]> Pileus Git - ~andy/gtk/commitdiff
Put it into CVS.
authorElliot Lee <sopwith@src.gnome.org>
Wed, 31 May 2000 21:50:38 +0000 (21:50 +0000)
committerElliot Lee <sopwith@src.gnome.org>
Wed, 31 May 2000 21:50:38 +0000 (21:50 +0000)
Put it into CVS.

51 files changed:
gdk/linux-fb/.cvsignore [new file with mode: 0644]
gdk/linux-fb/Makefile.am [new file with mode: 0644]
gdk/linux-fb/TODO [new file with mode: 0644]
gdk/linux-fb/gdkcolor-fb.c [new file with mode: 0644]
gdk/linux-fb/gdkcursor-fb.c [new file with mode: 0644]
gdk/linux-fb/gdkdnd-fb.c [new file with mode: 0644]
gdk/linux-fb/gdkdrawable-fb2.c [new file with mode: 0644]
gdk/linux-fb/gdkevents-fb.c [new file with mode: 0644]
gdk/linux-fb/gdkfb.h [new file with mode: 0644]
gdk/linux-fb/gdkfont-fb.c [new file with mode: 0644]
gdk/linux-fb/gdkgc-fb.c [new file with mode: 0644]
gdk/linux-fb/gdkgeometry-fb.c [new file with mode: 0644]
gdk/linux-fb/gdkglobals-fb.c [new file with mode: 0644]
gdk/linux-fb/gdkim-fb.c [new file with mode: 0644]
gdk/linux-fb/gdkimage-fb.c [new file with mode: 0644]
gdk/linux-fb/gdkinput-none.c [new file with mode: 0644]
gdk/linux-fb/gdkinput-ps2.c [new file with mode: 0644]
gdk/linux-fb/gdkinput.c [new file with mode: 0644]
gdk/linux-fb/gdkinputprivate.h [new file with mode: 0644]
gdk/linux-fb/gdkmain-fb.c [new file with mode: 0644]
gdk/linux-fb/gdkpixmap-fb.c [new file with mode: 0644]
gdk/linux-fb/gdkpoly-generic.h [new file with mode: 0644]
gdk/linux-fb/gdkpolyreg-generic.c [new file with mode: 0644]
gdk/linux-fb/gdkprivate-fb.h [new file with mode: 0644]
gdk/linux-fb/gdkproperty-fb.c [new file with mode: 0644]
gdk/linux-fb/gdkregion-generic.c [new file with mode: 0644]
gdk/linux-fb/gdkregion-generic.h [new file with mode: 0644]
gdk/linux-fb/gdkselection-fb.c [new file with mode: 0644]
gdk/linux-fb/gdkvisual-fb.c [new file with mode: 0644]
gdk/linux-fb/gdkwindow-fb.c [new file with mode: 0644]
gdk/linux-fb/mi.h [new file with mode: 0644]
gdk/linux-fb/miarc.c [new file with mode: 0644]
gdk/linux-fb/midash.c [new file with mode: 0644]
gdk/linux-fb/mifillarc.c [new file with mode: 0644]
gdk/linux-fb/mifillarc.h [new file with mode: 0644]
gdk/linux-fb/mifpoly.h [new file with mode: 0644]
gdk/linux-fb/mifpolycon.c [new file with mode: 0644]
gdk/linux-fb/miline.h [new file with mode: 0644]
gdk/linux-fb/mipoly.c [new file with mode: 0644]
gdk/linux-fb/mipoly.h [new file with mode: 0644]
gdk/linux-fb/mipolygen.c [new file with mode: 0644]
gdk/linux-fb/mipolyutil.c [new file with mode: 0644]
gdk/linux-fb/miscanfill.h [new file with mode: 0644]
gdk/linux-fb/mispans.c [new file with mode: 0644]
gdk/linux-fb/mispans.h [new file with mode: 0644]
gdk/linux-fb/mistruct.h [new file with mode: 0644]
gdk/linux-fb/mitypes.h [new file with mode: 0644]
gdk/linux-fb/miwideline.c [new file with mode: 0644]
gdk/linux-fb/miwideline.h [new file with mode: 0644]
gdk/linux-fb/mizerclip.c [new file with mode: 0644]
gdk/linux-fb/mizerline.c [new file with mode: 0644]

diff --git a/gdk/linux-fb/.cvsignore b/gdk/linux-fb/.cvsignore
new file mode 100644 (file)
index 0000000..10f8f3e
--- /dev/null
@@ -0,0 +1,8 @@
+*.lo
+Makefile
+Makefile.in
+.deps
+_libs
+.libs
+libgdk-x11.la
+gxid
diff --git a/gdk/linux-fb/Makefile.am b/gdk/linux-fb/Makefile.am
new file mode 100644 (file)
index 0000000..bdaeb24
--- /dev/null
@@ -0,0 +1,61 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = @STRIP_BEGIN@       \
+       -DG_LOG_DOMAIN=\"Gdk\"  \
+       -I$(top_srcdir)         \
+       -I$(top_srcdir)/gdk     \
+       -I$(top_builddir)/gdk   \
+       @GTK_DEBUG_FLAGS@       \
+       @GTK_XIM_FLAGS@         \
+       @GTK_LOCALE_FLAGS@      \
+       @GLIB_CFLAGS@           \
+@STRIP_END@
+
+LDFLAGS = @STRIP_BEGIN@ \
+       @GLIB_LIBS@     \
+       -L/gnome2/lib   \
+       -lt1            \
+       -lm             \
+@STRIP_END@
+
+lib_LTLIBRARIES = libgdk-fb.la
+noinst_PROGRAMS=test-fb
+
+test_fb_LDFLAGS=../libgdk.la libgdk-fb.la
+
+libgdk_fb_la_SOURCES =         \
+       gdkcolor-fb.c           \
+       gdkcursor-fb.c          \
+       gdkdnd-fb.c             \
+       gdkdrawable-fb2.c       \
+       gdkfont-fb.c            \
+       gdkgc-fb.c              \
+       gdkgeometry-fb.c        \
+       gdkglobals-fb.c         \
+       gdkim-fb.c              \
+       gdkimage-fb.c           \
+       gdkinput.c              \
+       gdkmain-fb.c            \
+       gdkpixmap-fb.c          \
+       gdkproperty-fb.c        \
+       gdkpolyreg-generic.c    \
+       gdkregion-generic.c     \
+       gdkselection-fb.c       \
+       gdkvisual-fb.c          \
+       gdkwindow-fb.c          \
+       gdkx.h                  \
+       gdkprivate-fb.h         \
+       gdkinputprivate.h       \
+       gdkinput-ps2.c          \
+       gdkevents-fb.c          \
+       miarc.c                 \
+       midash.c                \
+       mifillarc.c             \
+       mifpolycon.c            \
+       mipoly.c                \
+       mipolygen.c             \
+       mipolyutil.c            \
+       miwideline.c            \
+       mizerclip.c             \
+       mizerline.c             \
+       mispans.c
diff --git a/gdk/linux-fb/TODO b/gdk/linux-fb/TODO
new file mode 100644 (file)
index 0000000..fd308a5
--- /dev/null
@@ -0,0 +1,3 @@
+. Fix CTree
+. DnD?
+. All the standard X cursors
diff --git a/gdk/linux-fb/gdkcolor-fb.c b/gdk/linux-fb/gdkcolor-fb.c
new file mode 100644 (file)
index 0000000..684dec4
--- /dev/null
@@ -0,0 +1,759 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include <time.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "gdkcolor.h"
+#include "gdkprivate-fb.h"
+
+static gint  gdk_colormap_match_color (GdkColormap *cmap,
+                                      GdkColor    *color,
+                                      const gchar *available);
+GdkColormap*
+gdk_colormap_new (GdkVisual *visual,
+                 gint       private_cmap)
+{
+  GdkColormap *colormap;
+  GdkColormapPrivateFB *private;
+  GdkFBDisplay *fbd;
+  int i;
+
+  g_return_val_if_fail (visual != NULL, NULL);
+
+  private = g_new (GdkColormapPrivateFB, 1);
+  colormap = (GdkColormap*) private;
+
+  private->base.visual = visual;
+  private->base.ref_count = 1;
+  fbd = gdk_display;
+
+  private->hash = NULL;
+  
+  colormap->size = visual->colormap_size;
+  colormap->colors = NULL;
+
+  switch (visual->type)
+    {
+    case GDK_VISUAL_STATIC_GRAY:
+    case GDK_VISUAL_STATIC_COLOR:
+    case GDK_VISUAL_GRAYSCALE:
+    case GDK_VISUAL_PSEUDO_COLOR:
+      private->info = g_new0 (GdkColorInfo, colormap->size);
+      colormap->colors = g_new (GdkColor, colormap->size);
+      
+      private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
+                                       (GCompareFunc) gdk_color_equal);
+      
+      if (private_cmap)
+       {
+         guint16 red[256], green[256], blue[256];
+         struct fb_cmap fbc = {0, 256};
+
+         fbc.red = red;
+         fbc.green = green;
+         fbc.blue = blue;
+
+         if(ioctl(fbd->fd, FBIOGETCMAP, &fbc))
+           g_error("ioctl(FBIOGETCMAP) failed");
+
+         for (i = 0; i < colormap->size; i++)
+           {
+             colormap->colors[i].pixel = i;
+             colormap->colors[i].red = red[i];
+             colormap->colors[i].green = green[i];
+             colormap->colors[i].blue = blue[i];
+           }
+
+         gdk_colormap_change (colormap, colormap->size);
+       }
+      break;
+
+    case GDK_VISUAL_DIRECT_COLOR:
+      g_error("NYI");
+#if 0
+      colormap->colors = g_new (GdkColor, colormap->size);
+
+      size = 1 << visual->red_prec;
+      for (i = 0; i < size; i++)
+       colormap->colors[i].red = i * 65535 / (size - 1);
+
+      size = 1 << visual->green_prec;
+      for (i = 0; i < size; i++)
+       colormap->colors[i].green = i * 65535 / (size - 1);
+
+      size = 1 << visual->blue_prec;
+      for (i = 0; i < size; i++)
+       colormap->colors[i].blue = i * 65535 / (size - 1);
+
+      gdk_colormap_change (colormap, colormap->size);
+#endif
+      break;
+
+    default:
+      g_assert_not_reached();
+
+    case GDK_VISUAL_TRUE_COLOR:
+      break;
+    }
+
+  return colormap;
+}
+
+void
+_gdk_colormap_real_destroy (GdkColormap *colormap)
+{
+  GdkColormapPrivateFB *private = (GdkColormapPrivateFB*) colormap;
+
+  if (private->hash)
+    g_hash_table_destroy (private->hash);
+  
+  g_free (private->info);
+  g_free (colormap->colors);
+  g_free (colormap);
+}
+
+#define MIN_SYNC_TIME 2
+
+void
+gdk_colormap_sync (GdkColormap *colormap,
+                  gboolean     force)
+{
+  
+}                 
+
+GdkColormap*
+gdk_colormap_get_system (void)
+{
+  static GdkColormap *colormap = NULL;
+
+  if (!colormap)
+    {
+      guint16 red[256], green[256], blue[256];
+      struct fb_cmap fbc = {0, 256};
+      int i, r, g, b;
+      GdkVisual *visual = gdk_visual_get_system();
+
+      if(visual->type == GDK_VISUAL_GRAYSCALE
+        || visual->type ==  GDK_VISUAL_PSEUDO_COLOR)
+       {
+         fbc.red = red;
+         fbc.green = green;
+         fbc.blue = blue;
+         switch(visual->type)
+           {
+           case GDK_VISUAL_GRAYSCALE:
+             for(i = 0; i < 256; i++)
+               red[i] = green[i] = blue[i] = i << 8;
+             i--;
+             red[i] = green[i] = blue[i] = 65535; /* Make it a true white */
+             break;
+           case GDK_VISUAL_PSEUDO_COLOR:
+             /* Color cube stolen from gdkrgb upon advice from Owen */
+             for(i = r = 0; r < 6; r++)
+               for(g = 0; g < 6; g++)
+                 for(b = 0; b < 6; b++)
+                   {
+                     red[i] = r * 65535 / 5;
+                     green[i] = g * 65535 / 5;
+                     blue[i] = b * 65535 / 5;
+                     i++;
+                   }
+             g_assert(i == 216);
+
+         /* Fill in remaining space with grays */
+             for(i = 216; i < 256; i++)
+               {
+                 red[i] = green[i] = blue[i] =
+                   (i - 216) * 40;
+               }
+             /* Real white */
+             red[255] = green[255] = blue[255] = 65535;
+             break;
+           default:
+             break;
+           }
+
+         ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
+       }
+
+      colormap = gdk_colormap_new(visual, TRUE);
+    }
+
+  return colormap;
+}
+
+gint
+gdk_colormap_get_system_size (void)
+{
+  return 1 << (gdk_display->modeinfo.bits_per_pixel);
+}
+
+void
+gdk_colormap_change (GdkColormap *colormap,
+                    gint         ncolors)
+{
+  guint16 red[256], green[256], blue[256];
+  struct fb_cmap fbc = {0,256};
+  GdkColormapPrivateFB *private;
+  int i;
+
+  g_return_if_fail (colormap != NULL);
+
+  fbc.red = red;
+  fbc.green = green;
+  fbc.blue = blue;
+
+  private = (GdkColormapPrivateFB*) colormap;
+  switch (private->base.visual->type)
+    {
+    case GDK_VISUAL_GRAYSCALE:
+      for(i = 0; i < ncolors; i++)
+       {
+         red[i] = green[i] = blue[i] =
+           (colormap->colors[i].red +
+            colormap->colors[i].green +
+            colormap->colors[i].blue)/3;
+       }
+      ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
+      break;
+
+    case GDK_VISUAL_PSEUDO_COLOR:
+      for (i = 0; i < ncolors; i++)
+       {
+         red[i] = colormap->colors[i].red;
+         green[i] = colormap->colors[i].green;
+         blue[i] = colormap->colors[i].blue;
+       }
+      ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
+      break;
+
+    default:
+      break;
+    }
+}
+
+gboolean
+gdk_color_parse (const gchar *spec,
+                GdkColor *color)
+{
+  char aline[512];
+  FILE *fh;
+
+  g_return_val_if_fail(spec, FALSE);
+  g_return_val_if_fail(color, FALSE);
+
+  if(spec[0] == '#')
+    {
+      if(strlen(spec) == 7)
+       {
+         guint num;
+
+         sscanf(spec + 1, "%x", &num);
+         color->red = (num & 0xFF0000) >> 8;
+         color->green = (num & 0xFF00);
+         color->blue = (num & 0xFF) << 8;
+       }
+      else if(strlen(spec) == 13)
+       {
+         char s1[5], s2[5], s3[5];
+         g_snprintf(s1, sizeof(s1), spec + 1);
+         g_snprintf(s2, sizeof(s2), spec + 5);
+         g_snprintf(s3, sizeof(s3), spec + 9);
+
+         if(!sscanf(s1, "%hx", &color->red))
+           g_error("sscanf failed");
+         if(!sscanf(s2, "%hx", &color->green))
+           g_error("sscanf failed");
+         if(!sscanf(s3, "%hx", &color->blue))
+           g_error("sscanf failed");
+       }
+      else
+       {
+         g_warning("Couldn't parse color specifier `%s'", spec);
+         return FALSE;
+       }
+
+      return TRUE;
+    }
+  else
+    {
+      fh = fopen("/usr/lib/X11/rgb.txt", "r");
+      if(!fh)
+       return FALSE;
+
+      while(fgets(aline, sizeof(aline), fh))
+       {
+         int red, green, blue;
+         char *ctmp;
+
+         g_strstrip(aline);
+         if(!aline[0] || aline[0] == '#' || aline[0] == '!')
+           continue;
+
+         ctmp = strtok(aline, " \t");
+         if(!ctmp)
+           continue;
+         red = atoi(ctmp);
+
+         ctmp = strtok(NULL, " \t");
+         if(!ctmp)
+           continue;
+         green = atoi(ctmp);
+
+         ctmp = strtok(NULL, " \t");
+         if(!ctmp)
+           continue;
+         blue = atoi(ctmp);
+
+         ctmp = strtok(NULL, " \t");
+         if(!ctmp || strcmp(ctmp, spec))
+           continue;
+
+         color->red = red << 8;
+         color->green = green << 8;
+         color->blue = blue << 8;
+         return TRUE;
+       }
+      fclose(fh);
+    }
+
+  return FALSE;
+}
+
+void
+gdk_colormap_free_colors (GdkColormap *colormap,
+                         GdkColor    *colors,
+                         gint         ncolors)
+{
+  GdkColormapPrivateFB *private;
+  gint i;
+
+  g_return_if_fail (colormap != NULL);
+  g_return_if_fail (colors != NULL);
+
+  private = (GdkColormapPrivateFB*) colormap;
+
+  if ((private->base.visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
+      (private->base.visual->type != GDK_VISUAL_GRAYSCALE))
+    return;
+
+  for (i=0; i<ncolors; i++)
+    {
+      gulong pixel = colors[i].pixel;
+      
+      if (private->info[pixel].ref_count)
+       {
+         private->info[pixel].ref_count--;
+
+         if (private->info[pixel].ref_count == 0)
+           {
+             if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
+               g_hash_table_remove (private->hash, &colormap->colors[pixel]);
+             private->info[pixel].flags = 0;
+           }
+       }
+    }
+}
+
+/********************
+ * Color allocation *
+ ********************/
+
+/* Try to allocate a single color using XAllocColor. If it succeeds,
+ * cache the result in our colormap, and store in ret.
+ */
+static gboolean 
+gdk_colormap_alloc1 (GdkColormap *colormap,
+                    GdkColor    *color,
+                    GdkColor    *ret)
+{
+  GdkColormapPrivateFB *private;
+  int i;
+
+  private = (GdkColormapPrivateFB*) colormap;
+
+  if(private->base.visual->type != GDK_VISUAL_GRAYSCALE
+     && private->base.visual->type != GDK_VISUAL_PSEUDO_COLOR)
+    return FALSE;
+
+  *ret = *color;
+  if(!color->red && !color->green && !color->blue) /* black */
+    {
+      ret->pixel = 0;
+      private->info[ret->pixel].ref_count++;
+      return TRUE;
+    }
+
+  if(color->red == 65535 && color->green == 65535 && color->blue == 65535) /* white */
+    {
+      ret->pixel = 255;
+      private->info[ret->pixel].ref_count++;
+      return TRUE;
+    }
+
+  for(i = 1; i < (colormap->size - 1); i++)
+    {
+      if(!private->info[i].ref_count)
+       {
+         guint16 red = color->red, green = color->green, blue = color->blue;
+         struct fb_cmap fbc;
+         fbc.len = 1;
+         fbc.start = i;
+         fbc.red = &red;
+         fbc.green = &green;
+         fbc.blue = &blue;
+
+         ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
+
+         ret->pixel = i;
+         colormap->colors[ret->pixel] = *ret;
+         private->info[ret->pixel].ref_count = 1;
+         g_hash_table_insert (private->hash,
+                              &colormap->colors[ret->pixel],
+                              &colormap->colors[ret->pixel]);
+         return TRUE;
+       }
+    }
+
+  return FALSE;
+}
+
+static gint
+gdk_colormap_alloc_colors_shared (GdkColormap *colormap,
+                                 GdkColor    *colors,
+                                 gint         ncolors,
+                                 gboolean     writeable,
+                                 gboolean     best_match,
+                                 gboolean    *success)
+{
+  GdkColormapPrivateFB *private;
+  gint i, index;
+  gint nremaining = 0;
+  gint nfailed = 0;
+
+  private = (GdkColormapPrivateFB*) colormap;
+  index = -1;
+
+  for (i=0; i<ncolors; i++)
+    {
+      if (!success[i])
+       {
+         if (gdk_colormap_alloc1 (colormap, &colors[i], &colors[i]))
+           success[i] = TRUE;
+         else
+           nremaining++;
+       }
+    }
+
+
+  if (nremaining > 0 && best_match)
+    {
+      gchar *available = g_new (gchar, colormap->size);
+
+      for (i = 0; i < colormap->size; i++)
+       available[i] = ((private->info[i].ref_count == 0) ||
+                       !(private->info[i].flags && GDK_COLOR_WRITEABLE));
+      
+      while (nremaining > 0)
+       {
+         for (i=0; i<ncolors; i++)
+           {
+             if (!success[i])
+               {
+                 index = gdk_colormap_match_color (colormap, &colors[i], available);
+                 if (index != -1)
+                   {
+                     if (private->info[index].ref_count)
+                       {
+                         private->info[index].ref_count++;
+                         colors[i] = colormap->colors[index];
+                         success[i] = TRUE;
+                         nremaining--;
+                       }
+                     else
+                       {
+                         if (gdk_colormap_alloc1 (colormap, 
+                                                  &colormap->colors[index],
+                                                  &colors[i]))
+                           {
+                             success[i] = TRUE;
+                             nremaining--;
+                             break;
+                           }
+                         else
+                           {
+                             available[index] = FALSE;
+                           }
+                       }
+                   }
+                 else
+                   {
+                     nfailed++;
+                     nremaining--;
+                     success[i] = 2; /* flag as permanent failure */
+                   }
+               }
+           }
+       }
+      g_free (available);
+    }
+
+  /* Change back the values we flagged as permanent failures */
+  if (nfailed > 0)
+    {
+      for (i=0; i<ncolors; i++)
+       if (success[i] == 2)
+         success[i] = FALSE;
+      nremaining = nfailed;
+    }
+  
+  return (ncolors - nremaining);
+}
+
+static gint
+gdk_colormap_alloc_colors_pseudocolor (GdkColormap *colormap,
+                                      GdkColor    *colors,
+                                      gint         ncolors,
+                                      gboolean     writeable,
+                                      gboolean     best_match,
+                                      gboolean    *success)
+{
+  GdkColormapPrivateFB *private;
+  GdkColor *lookup_color;
+  gint i;
+  gint nremaining = 0;
+
+  private = (GdkColormapPrivateFB*) colormap;
+
+  /* Check for an exact match among previously allocated colors */
+
+  for (i=0; i<ncolors; i++)
+    {
+      if (!success[i])
+       {
+         lookup_color = g_hash_table_lookup (private->hash, &colors[i]);
+         if (lookup_color)
+           {
+             private->info[lookup_color->pixel].ref_count++;
+             colors[i].pixel = lookup_color->pixel;
+             success[i] = TRUE;
+           }
+         else
+           nremaining++;
+       }
+    }
+
+  /* If that failed, we try to allocate a new color, or approxmiate
+   * with what we can get if best_match is TRUE.
+   */
+  if (nremaining > 0)
+    return gdk_colormap_alloc_colors_shared (colormap, colors, ncolors, writeable, best_match, success);
+  else
+    return 0;
+}
+
+gint
+gdk_colormap_alloc_colors (GdkColormap *colormap,
+                          GdkColor    *colors,
+                          gint         ncolors,
+                          gboolean     writeable,
+                          gboolean     best_match,
+                          gboolean    *success)
+{
+  GdkColormapPrivateFB *private;
+  GdkVisual *visual;
+  gint i;
+  gint nremaining = 0;
+
+  g_return_val_if_fail (colormap != NULL, FALSE);
+  g_return_val_if_fail (colors != NULL, FALSE);
+
+  private = (GdkColormapPrivateFB*) colormap;
+
+  for (i=0; i<ncolors; i++)
+    success[i] = FALSE;
+
+  switch (private->base.visual->type)
+    {
+    case GDK_VISUAL_PSEUDO_COLOR:
+    case GDK_VISUAL_GRAYSCALE:
+    case GDK_VISUAL_STATIC_GRAY:
+    case GDK_VISUAL_STATIC_COLOR:
+      return gdk_colormap_alloc_colors_pseudocolor (colormap, colors, ncolors,
+                                                   writeable, best_match, success);
+      break;
+
+    case GDK_VISUAL_DIRECT_COLOR:
+    case GDK_VISUAL_TRUE_COLOR:
+      visual = private->base.visual;
+
+      for (i=0; i<ncolors; i++)
+       {
+         colors[i].pixel = (((colors[i].red >> (16 - visual->red_prec)) << visual->red_shift) +
+                            ((colors[i].green >> (16 - visual->green_prec)) << visual->green_shift) +
+                            ((colors[i].blue >> (16 - visual->blue_prec)) << visual->blue_shift));
+         success[i] = TRUE;
+       }
+      break;
+    }
+  return nremaining;
+}
+
+gboolean
+gdk_color_change (GdkColormap *colormap,
+                 GdkColor    *color)
+{
+  GdkColormapPrivateFB *private;
+  struct fb_cmap fbc = {0, 1};
+
+  g_return_val_if_fail (colormap != NULL, FALSE);
+  g_return_val_if_fail (color != NULL, FALSE);
+
+  private = (GdkColormapPrivateFB*) colormap;
+
+  switch(private->base.visual->type)
+    {
+    case GDK_VISUAL_GRAYSCALE:
+      color->red = color->green = color->blue = (color->red + color->green + color->blue)/3;
+
+    case GDK_VISUAL_PSEUDO_COLOR:
+      fbc.start = color->pixel;
+      fbc.red = &color->red;
+      fbc.green = &color->green;
+      fbc.blue = &color->blue;
+      ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
+      break;
+
+    default:
+      break;
+    }
+
+  return TRUE;
+}
+
+static gint
+gdk_colormap_match_color (GdkColormap *cmap,
+                         GdkColor    *color,
+                         const gchar *available)
+{
+  GdkColor *colors;
+  guint sum, max;
+  gint rdiff, gdiff, bdiff;
+  gint i, index;
+
+  g_return_val_if_fail (cmap != NULL, 0);
+  g_return_val_if_fail (color != NULL, 0);
+
+  colors = cmap->colors;
+  max = 3 * (65536);
+  index = -1;
+
+  for (i = 0; i < cmap->size; i++)
+    {
+      if ((!available) || (available && available[i]))
+       {
+         rdiff = (color->red - colors[i].red);
+         gdiff = (color->green - colors[i].green);
+         bdiff = (color->blue - colors[i].blue);
+
+         sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
+
+         if (sum < max)
+           {
+             index = i;
+             max = sum;
+           }
+       }
+    }
+
+  return index;
+}
+
+gint gdk_colors_alloc   (GdkColormap   *colormap,
+                         gboolean       contiguous,
+                         gulong        *planes,
+                         gint           nplanes,
+                         gulong        *pixels,
+                         gint           npixels)
+{
+  return 0;
+}
+
+void
+gdk_colors_free         (GdkColormap   *colormap,
+                 gulong        *pixels,
+                 gint           npixels,
+                 gulong         planes)
+{
+}
+
+gulong
+gdk_color_context_get_pixel(GdkColorContext *cc,
+                           gushort         red,
+                           gushort         green,
+                           gushort         blue,
+                           gint           *failed)
+{
+  g_error("NYI");
+
+  return 0;
+}
+
+GdkColorContext *
+gdk_color_context_new(GdkVisual   *visual,
+                     GdkColormap *colormap)
+{
+  g_error("NYI");
+
+  return NULL;
+}
+
+GdkColorContext *
+gdk_color_context_new_mono(GdkVisual   *visual,
+                          GdkColormap *colormap)
+{
+  g_error("NYI");
+
+  return NULL;
+}
+
+void
+gdk_color_context_free(GdkColorContext *cc)
+{
+  g_error("NYI");
+}
+
+gint
+gdk_color_context_query_color(GdkColorContext *cc,
+                             GdkColor     *color)
+{
+  g_error("NYI");
+
+  return 0;
+}
diff --git a/gdk/linux-fb/gdkcursor-fb.c b/gdk/linux-fb/gdkcursor-fb.c
new file mode 100644 (file)
index 0000000..8a883f9
--- /dev/null
@@ -0,0 +1,81 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "gdkfb.h"
+#include "gdkprivate-fb.h"
+#include "gdkcursor.h"
+
+GdkCursor*
+gdk_cursor_new (GdkCursorType cursor_type)
+{
+  GdkCursorPrivateFB *private;
+  GdkCursor *cursor;
+
+  return NULL;
+
+  private = g_new0(GdkCursorPrivateFB, 1);
+  cursor = (GdkCursor*) private;
+  cursor->type = cursor_type;
+  cursor->ref_count = 1;
+  
+  return cursor;
+}
+
+GdkCursor*
+gdk_cursor_new_from_pixmap (GdkPixmap *source,
+                           GdkPixmap *mask,
+                           GdkColor  *fg,
+                           GdkColor  *bg,
+                           gint       x,
+                           gint       y)
+{
+  GdkCursorPrivateFB *private;
+  GdkCursor *cursor;
+
+  g_return_val_if_fail (source != NULL, NULL);
+
+  private = g_new (GdkCursorPrivateFB, 1);
+  cursor = (GdkCursor *) private;
+  cursor->type = GDK_CURSOR_IS_PIXMAP;
+  cursor->ref_count = 1;
+  private->cursor = gdk_pixmap_ref(source);
+  private->mask = gdk_pixmap_ref(mask);
+  
+  return cursor;
+}
+
+void
+_gdk_cursor_destroy (GdkCursor *cursor)
+{
+  GdkCursorPrivateFB *private;
+
+  g_return_if_fail (cursor != NULL);
+  g_return_if_fail (cursor->ref_count == 0);
+
+  private = (GdkCursorPrivateFB *) cursor;
+
+  g_free (private);
+}
diff --git a/gdk/linux-fb/gdkdnd-fb.c b/gdk/linux-fb/gdkdnd-fb.c
new file mode 100644 (file)
index 0000000..b65c55a
--- /dev/null
@@ -0,0 +1,264 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include <string.h>
+
+#include "gdk.h"          /* For gdk_flush() */
+#include "gdkdnd.h"
+#include "gdkproperty.h"
+#include "gdkinternals.h"
+#include "gdkprivate-fb.h"
+
+typedef struct _GdkDragContextPrivate GdkDragContextPrivate;
+
+typedef enum {
+  GDK_DRAG_STATUS_DRAG,
+  GDK_DRAG_STATUS_MOTION_WAIT,
+  GDK_DRAG_STATUS_ACTION_WAIT,
+  GDK_DRAG_STATUS_DROP
+} GtkDragStatus;
+
+/* Structure that holds information about a drag in progress.
+ * this is used on both source and destination sides.
+ */
+struct _GdkDragContextPrivate {
+  GdkDragContext context;
+
+  guint   ref_count;
+};
+
+/* Drag Contexts */
+
+static GList *contexts;
+
+GdkDragContext *
+gdk_drag_context_new        (void)
+{
+  GdkDragContextPrivate *result;
+
+  result = g_new0 (GdkDragContextPrivate, 1);
+
+  result->ref_count = 1;
+
+  contexts = g_list_prepend (contexts, result);
+
+  return (GdkDragContext *)result;
+}
+
+void            
+gdk_drag_context_ref (GdkDragContext *context)
+{
+  g_return_if_fail (context != NULL);
+
+  ((GdkDragContextPrivate *)context)->ref_count++;
+}
+
+void            
+gdk_drag_context_unref (GdkDragContext *context)
+{
+  GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
+
+  g_return_if_fail (context != NULL);
+  g_return_if_fail (private->ref_count > 0);
+
+  private->ref_count--;
+  
+  if (private->ref_count == 0)
+    {
+      g_dataset_destroy (private);
+      
+      g_list_free (context->targets);
+
+      if (context->source_window)
+       {
+#if 0
+         if ((context->protocol == GDK_DRAG_PROTO_XDND) &&
+             !context->is_source)
+           xdnd_manage_source_filter (context, context->source_window, FALSE);
+#endif
+
+         gdk_window_unref (context->source_window);
+       }
+
+      if (context->dest_window)
+       gdk_window_unref (context->dest_window);
+
+#if 0
+      if (private->window_cache)
+       gdk_window_cache_destroy (private->window_cache);
+#endif
+
+      contexts = g_list_remove (contexts, private);
+      g_free (private);
+    }
+}
+
+/*************************************************************
+ ************************** Public API ***********************
+ *************************************************************/
+
+void
+gdk_dnd_init (void)
+{
+}                    
+
+/* Source side */
+
+static void
+gdk_drag_do_leave (GdkDragContext *context, guint32 time) G_GNUC_UNUSED;
+
+static void
+gdk_drag_do_leave (GdkDragContext *context, guint32 time)
+{
+}
+
+GdkDragContext * 
+gdk_drag_begin (GdkWindow     *window,
+               GList         *targets)
+{
+  GList *tmp_list;
+  GdkDragContext *new_context;
+  
+  g_return_val_if_fail (window != NULL, NULL);
+
+  new_context = gdk_drag_context_new ();
+  new_context->is_source = TRUE;
+  new_context->source_window = window;
+  gdk_window_ref (window);
+
+  tmp_list = g_list_last (targets);
+  new_context->targets = NULL;
+  while (tmp_list)
+    {
+      new_context->targets = g_list_prepend (new_context->targets,
+                                            tmp_list->data);
+      tmp_list = tmp_list->prev;
+    }
+
+  new_context->actions = 0;
+
+  return new_context;
+}
+
+guint32
+gdk_drag_get_protocol (guint32          xid,
+                      GdkDragProtocol *protocol)
+{
+  *protocol = GDK_DRAG_PROTO_NONE;
+  return GDK_NONE;
+}
+
+void
+gdk_drag_find_window (GdkDragContext  *context,
+                     GdkWindow       *drag_window,
+                     gint             x_root,
+                     gint             y_root,
+                     GdkWindow      **dest_window,
+                     GdkDragProtocol *protocol)
+{
+  g_return_if_fail (context != NULL);
+
+  *dest_window = gdk_window_get_pointer(NULL, &x_root, &y_root, NULL);
+}
+
+gboolean        
+gdk_drag_motion (GdkDragContext *context,
+                GdkWindow      *dest_window,
+                GdkDragProtocol protocol,
+                gint            x_root, 
+                gint            y_root,
+                GdkDragAction   suggested_action,
+                GdkDragAction   possible_actions,
+                guint32         time)
+{
+  g_return_val_if_fail (context != NULL, FALSE);
+
+  return FALSE;
+}
+
+void
+gdk_drag_drop (GdkDragContext *context,
+              guint32         time)
+{
+  g_return_if_fail (context != NULL);
+}
+
+void
+gdk_drag_abort (GdkDragContext *context,
+               guint32         time)
+{
+  g_return_if_fail (context != NULL);
+}
+
+/* Destination side */
+
+void             
+gdk_drag_status (GdkDragContext   *context,
+                GdkDragAction     action,
+                guint32           time)
+{
+  g_return_if_fail (context != NULL);
+}
+
+void 
+gdk_drop_reply (GdkDragContext   *context,
+               gboolean          ok,
+               guint32           time)
+{
+  g_return_if_fail (context != NULL);
+}
+
+void             
+gdk_drop_finish (GdkDragContext   *context,
+                gboolean          success,
+                guint32           time)
+{
+  g_return_if_fail (context != NULL);
+}
+
+
+void            
+gdk_window_register_dnd (GdkWindow      *window)
+{
+  g_return_if_fail (window != NULL);
+}
+
+/*************************************************************
+ * gdk_drag_get_selection:
+ *     Returns the selection atom for the current source window
+ *   arguments:
+ *     
+ *   results:
+ *************************************************************/
+
+GdkAtom       
+gdk_drag_get_selection (GdkDragContext *context)
+{
+  g_return_val_if_fail (context != NULL, GDK_NONE);
+
+  return GDK_NONE;
+}
+
diff --git a/gdk/linux-fb/gdkdrawable-fb2.c b/gdk/linux-fb/gdkdrawable-fb2.c
new file mode 100644 (file)
index 0000000..f5c7b8c
--- /dev/null
@@ -0,0 +1,959 @@
+#include "gdkprivate-fb.h"
+#include "mi.h"
+#include <t1lib.h>
+
+#ifndef g_alloca
+#define g_alloca alloca
+#endif
+
+static void gdk_fb_drawable_destroy   (GdkDrawable     *drawable);
+void gdk_fb_draw_rectangle (GdkDrawable    *drawable,
+                           GdkGC          *gc,
+                           gint            filled,
+                           gint            x,
+                           gint            y,
+                           gint            width,
+                           gint            height);
+static void gdk_fb_draw_arc       (GdkDrawable    *drawable,
+                                  GdkGC          *gc,
+                                  gint            filled,
+                                  gint            x,
+                                  gint            y,
+                                  gint            width,
+                                  gint            height,
+                                  gint            angle1,
+                                  gint            angle2);
+static void gdk_fb_draw_polygon   (GdkDrawable    *drawable,
+                                  GdkGC          *gc,
+                                  gint            filled,
+                                  GdkPoint       *points,
+                                  gint            npoints);
+static void gdk_fb_draw_text      (GdkDrawable    *drawable,
+                                  GdkFont        *font,
+                                  GdkGC          *gc,
+                                  gint            x,
+                                  gint            y,
+                                  const gchar    *text,
+                                  gint            text_length);
+static void gdk_fb_draw_text_wc   (GdkDrawable    *drawable,
+                                  GdkFont        *font,
+                                  GdkGC          *gc,
+                                  gint            x,
+                                  gint            y,
+                                  const GdkWChar *text,
+                                  gint            text_length);
+void gdk_fb_draw_drawable  (GdkDrawable    *drawable,
+                           GdkGC          *gc,
+                           GdkPixmap      *src,
+                           gint            xsrc,
+                           gint            ysrc,
+                           gint            xdest,
+                           gint            ydest,
+                           gint            width,
+                           gint            height);
+static void gdk_fb_draw_points    (GdkDrawable    *drawable,
+                                  GdkGC          *gc,
+                                  GdkPoint       *points,
+                                  gint            npoints);
+static void gdk_fb_draw_segments  (GdkDrawable    *drawable,
+                                  GdkGC          *gc,
+                                  GdkSegment     *segs,
+                                  gint            nsegs);
+static void gdk_fb_draw_lines     (GdkDrawable    *drawable,
+                                  GdkGC          *gc,
+                                  GdkPoint       *points,
+                                  gint            npoints);
+
+GdkDrawableClass _gdk_fb_drawable_class = {
+  gdk_fb_drawable_destroy,
+  (gpointer)_gdk_fb_gc_new,
+  gdk_fb_draw_rectangle,
+  gdk_fb_draw_arc,
+  gdk_fb_draw_polygon,
+  gdk_fb_draw_text,
+  gdk_fb_draw_text_wc,
+  gdk_fb_draw_drawable,
+  gdk_fb_draw_points,
+  gdk_fb_draw_segments,
+  gdk_fb_draw_lines
+};
+
+/*****************************************************
+ * FB specific implementations of generic functions *
+ *****************************************************/
+
+GdkColormap*
+gdk_drawable_get_colormap (GdkDrawable *drawable)
+{
+  GdkColormap *retval = GDK_DRAWABLE_P(drawable)->colormap;
+
+  if(!retval)
+    retval = gdk_colormap_get_system();
+
+  return retval;
+}
+
+void
+gdk_drawable_set_colormap (GdkDrawable *drawable,
+                          GdkColormap *colormap)
+{
+  GdkColormap *old_cmap;
+  old_cmap = GDK_DRAWABLE_P(drawable)->colormap;
+  GDK_DRAWABLE_P(drawable)->colormap = gdk_colormap_ref(colormap);
+  gdk_colormap_unref(old_cmap);
+}
+
+/* Drawing
+ */
+static void 
+gdk_fb_drawable_destroy (GdkDrawable *drawable)
+{
+}
+
+static GdkRegion *
+gdk_fb_clip_region(GdkDrawable *drawable, GdkGC *gc, gboolean do_clipping)
+{
+  GdkRectangle draw_rect;
+  GdkRegion *real_clip_region, *tmpreg;
+
+  g_assert(!GDK_IS_WINDOW(drawable) || !GDK_WINDOW_P(drawable)->input_only);
+
+  draw_rect.x = GDK_DRAWABLE_FBDATA(drawable)->llim_x;
+  draw_rect.y = GDK_DRAWABLE_FBDATA(drawable)->llim_y;
+  draw_rect.width = GDK_DRAWABLE_FBDATA(drawable)->lim_x - draw_rect.x;
+  draw_rect.height = GDK_DRAWABLE_FBDATA(drawable)->lim_y - draw_rect.y;
+  real_clip_region = gdk_region_rectangle(&draw_rect);
+
+  if(do_clipping && GDK_IS_WINDOW(drawable) && GDK_WINDOW_P(drawable)->mapped && !GDK_WINDOW_P(drawable)->input_only)
+    {
+      GdkWindow *parentwin, *lastwin;
+
+      for(parentwin = lastwin = ((GdkWindow *)drawable);
+         parentwin; lastwin = parentwin, parentwin = GDK_WINDOW_P(parentwin)->parent)
+       {
+         GList *cur;
+
+         for(cur = GDK_WINDOW_P(parentwin)->children; cur && cur->data != lastwin; cur = cur->next)
+           {
+             if(!GDK_WINDOW_P(cur->data)->mapped || GDK_WINDOW_P(cur->data)->input_only)
+               continue;
+
+             draw_rect.x = GDK_DRAWABLE_FBDATA(cur->data)->llim_x;
+             draw_rect.y = GDK_DRAWABLE_FBDATA(cur->data)->llim_y;
+             draw_rect.width = GDK_DRAWABLE_FBDATA(cur->data)->lim_x - draw_rect.x;
+             draw_rect.height = GDK_DRAWABLE_FBDATA(cur->data)->lim_y - draw_rect.y;
+
+             tmpreg = gdk_region_rectangle(&draw_rect);
+             gdk_region_subtract(real_clip_region, tmpreg);
+             gdk_region_destroy(tmpreg);
+           }
+       }
+    }
+
+  if(gc)
+    {
+      if(GDK_GC_FBDATA(gc)->clip_region)
+       {
+         tmpreg = gdk_region_copy(GDK_GC_FBDATA(gc)->clip_region);
+         gdk_region_offset(tmpreg, GDK_DRAWABLE_FBDATA(drawable)->abs_x + GDK_GC_P(gc)->clip_x_origin,
+                           GDK_DRAWABLE_FBDATA(drawable)->abs_y + GDK_GC_P(gc)->clip_y_origin);
+         gdk_region_intersect(real_clip_region, tmpreg);
+         gdk_region_destroy(tmpreg);
+       }
+
+      if(GDK_GC_FBDATA(gc)->values.clip_mask)
+       {
+         GdkDrawable *cmask = GDK_GC_FBDATA(gc)->values.clip_mask;
+
+         g_assert(GDK_DRAWABLE_P(cmask)->depth == 1);
+         g_assert(GDK_DRAWABLE_FBDATA(cmask)->abs_x == 0
+                  && GDK_DRAWABLE_FBDATA(cmask)->abs_y == 0);
+
+         draw_rect.x = GDK_DRAWABLE_FBDATA(drawable)->abs_x + GDK_DRAWABLE_FBDATA(cmask)->llim_x + GDK_GC_FBDATA(gc)->values.clip_x_origin;
+         draw_rect.y = GDK_DRAWABLE_FBDATA(drawable)->abs_y + GDK_DRAWABLE_FBDATA(cmask)->llim_y + GDK_GC_FBDATA(gc)->values.clip_y_origin;
+         draw_rect.width = GDK_DRAWABLE_P(cmask)->width;
+         draw_rect.height = GDK_DRAWABLE_P(cmask)->height;
+
+         tmpreg = gdk_region_rectangle(&draw_rect);
+         gdk_region_intersect(real_clip_region, tmpreg);
+         gdk_region_destroy(tmpreg);
+       }
+    }
+
+  return real_clip_region;
+}
+
+static void
+gdk_fb_fill_span(GdkDrawable *drawable, GdkGC *gc, GdkSegment *cur, guint pixel, GdkVisual *visual)
+{
+  int curx, cury;
+  guchar *mem = GDK_DRAWABLE_FBDATA(drawable)->mem;
+  guint rowstride = GDK_DRAWABLE_FBDATA(drawable)->rowstride;
+  guint depth = GDK_DRAWABLE_P(drawable)->depth;
+
+  if(gc
+     && (GDK_GC_FBDATA(gc)->values.clip_mask
+        || GDK_GC_FBDATA(gc)->values.tile
+        || GDK_GC_FBDATA(gc)->values.stipple))
+    {
+      int clipxoff, clipyoff; /* Amounts to add to curx & cury to get x & y in clip mask */
+      int tsxoff, tsyoff;
+      GdkDrawable *cmask;
+      guchar *clipmem;
+      guint mask_rowstride;
+      GdkPixmap *ts = NULL;
+      gboolean solid_stipple;
+
+      cmask = GDK_GC_FBDATA(gc)->values.clip_mask;
+      if(cmask)
+       {
+         clipmem = GDK_DRAWABLE_FBDATA(cmask)->mem;
+         clipxoff = GDK_DRAWABLE_FBDATA(cmask)->abs_x - GDK_GC_FBDATA(gc)->values.clip_x_origin - GDK_DRAWABLE_FBDATA(drawable)->abs_x;
+         clipyoff = GDK_DRAWABLE_FBDATA(cmask)->abs_y - GDK_GC_FBDATA(gc)->values.clip_y_origin - GDK_DRAWABLE_FBDATA(drawable)->abs_y;
+         mask_rowstride = GDK_DRAWABLE_FBDATA(cmask)->rowstride;
+       }
+
+      if(GDK_GC_FBDATA(gc)->values.fill == GDK_TILED
+        && GDK_GC_FBDATA(gc)->values.tile)
+       {
+         gint xstep, ystep;
+         gint relx, rely;
+
+         ts = GDK_GC_FBDATA(gc)->values.tile;
+         for(cury = cur->y1; cury < cur->y2; cury += ystep)
+           {
+             int drawh;
+             
+             rely = cury - GDK_DRAWABLE_FBDATA(drawable)->abs_y;
+             drawh = (rely + GDK_GC_FBDATA(gc)->values.ts_y_origin) % GDK_DRAWABLE_P(ts)->height;
+             if(drawh < 0)
+               drawh += GDK_DRAWABLE_P(ts)->height;
+
+             ystep = MIN(GDK_DRAWABLE_P(ts)->height - drawh, cur->y2 - rely);
+
+             for(curx = cur->x1; curx < cur->x2; curx += xstep)
+               {
+                 int draww;
+
+                 relx = curx - GDK_DRAWABLE_FBDATA(drawable)->abs_x;
+
+                 draww = (relx + GDK_GC_FBDATA(gc)->values.ts_x_origin) % GDK_DRAWABLE_P(ts)->width;
+                 if(draww < 0)
+                   draww += GDK_DRAWABLE_P(ts)->width;
+
+                 xstep = MIN(GDK_DRAWABLE_P(ts)->width - draww, cur->x2 - relx);
+
+                 gdk_fb_draw_drawable_2(drawable, gc, ts,
+                                        draww, drawh,
+                                        relx, rely,
+                                        xstep, ystep, FALSE, TRUE);
+               }
+           }
+
+         return;
+       }
+      else if((GDK_GC_FBDATA(gc)->values.fill == GDK_STIPPLED
+             || GDK_GC_FBDATA(gc)->values.fill == GDK_OPAQUE_STIPPLED)
+             && GDK_GC_FBDATA(gc)->values.stipple)
+       {
+         ts = GDK_GC_FBDATA(gc)->values.stipple;
+         tsxoff = GDK_DRAWABLE_FBDATA(ts)->abs_x - GDK_GC_FBDATA(gc)->values.ts_x_origin - GDK_DRAWABLE_FBDATA(drawable)->abs_x;
+         tsyoff = GDK_DRAWABLE_FBDATA(ts)->abs_y - GDK_GC_FBDATA(gc)->values.ts_y_origin - GDK_DRAWABLE_FBDATA(drawable)->abs_y;
+         solid_stipple = (GDK_GC_FBDATA(gc)->values.fill == GDK_OPAQUE_STIPPLED);
+       }
+
+      switch(depth)
+       {
+       case 1:
+         g_assert(!ts);
+         for(cury = cur->y1; cury < cur->y2; cury++)
+           {
+             for(curx = cur->x1; curx < cur->x2; curx++)
+               {
+                 guchar *ptr = mem + (cury * rowstride) + (curx >> 3);
+                 int maskx = curx+clipxoff, masky = cury + clipyoff;
+                 guchar foo;
+
+                 if(cmask)
+                   {
+                     foo = clipmem[masky*mask_rowstride + (maskx >> 3)];
+
+                     if(!(foo & (1 << (maskx % 8))))
+                       continue;
+                   }
+
+                 *ptr |= (1 << (curx % 8));
+               }
+           }
+         break;
+       case 8:
+         for(cury = cur->y1; cury < cur->y2; cury++)
+           {
+             for(curx = cur->x1; curx < cur->x2; curx++)
+               {
+                 guchar *ptr = mem + (cury * rowstride) + curx;
+                 int maskx = curx+clipxoff, masky = cury + clipyoff;
+                 guchar foo;
+
+                 if(cmask)
+                   {
+                     foo = clipmem[masky*mask_rowstride + (maskx >> 3)];
+
+                     if(!(foo & (1 << (maskx % 8))))
+                       continue;
+                   }
+
+                 if(ts)
+                   {
+                     int wid = GDK_DRAWABLE_P(ts)->width, hih = GDK_DRAWABLE_P(ts)->height;
+                     maskx = (curx+tsxoff)%wid;
+                     masky = (cury+tsyoff)%hih;
+                     if(maskx < 0)
+                       maskx += wid;
+                     if(masky < 0)
+                       masky += hih;
+
+                     foo = GDK_DRAWABLE_FBDATA(ts)->mem[(maskx >> 3) + GDK_DRAWABLE_FBDATA(ts)->rowstride*masky];
+                     if(foo & (1 << (maskx % 8)))
+                       {
+                         pixel = GDK_GC_FBDATA(gc)->values.foreground.pixel;
+                       }
+                     else if(solid_stipple)
+                       {
+                         pixel = GDK_GC_FBDATA(gc)->values.background.pixel;
+                       }
+                     else
+                       continue;
+                   }
+
+                 *ptr = pixel;
+               }
+           }
+         break;
+
+       case 16:
+       case 24:
+       case 32:
+         for(cury = cur->y1; cury < cur->y2; cury++)
+           {
+             for(curx = cur->x1; curx < cur->x2; curx++)
+               {
+                 guint *ptr2 = (guint *)(mem + (cury * rowstride) + (curx * (depth >> 3)));
+                 int maskx = curx+clipxoff, masky = cury + clipyoff;
+                 guchar foo;
+
+                 if(cmask)
+                   {
+                     foo = clipmem[masky*mask_rowstride + (maskx >> 3)];
+
+                     if(!(foo & (1 << (maskx % 8))))
+                       continue;
+                   }
+
+                 if(ts)
+                   {
+                     int wid = GDK_DRAWABLE_P(ts)->width, hih = GDK_DRAWABLE_P(ts)->height;
+
+                     maskx = (curx+tsxoff)%wid;
+                     masky = (cury+tsyoff)%hih;
+                     if(maskx < 0)
+                       maskx += wid;
+                     if(masky < 0)
+                       masky += hih;
+
+                     foo = GDK_DRAWABLE_FBDATA(ts)->mem[(maskx >> 3) + GDK_DRAWABLE_FBDATA(ts)->rowstride*masky];
+                     if(foo & (1 << (maskx % 8)))
+                       {
+                         pixel = GDK_GC_FBDATA(gc)->values.foreground.pixel;
+                       }
+                     else if(solid_stipple)
+                       {
+                         pixel = GDK_GC_FBDATA(gc)->values.background.pixel;
+                       }
+                     else
+                       continue;
+                   }
+
+                 *ptr2 = (*ptr2 & ~(visual->red_mask|visual->green_mask|visual->blue_mask)) | pixel;
+               }
+           }
+         break;
+       }
+    }
+  else
+    {
+      switch(depth)
+       {
+       case 1:
+         for(cury = cur->y1; cury < cur->y2; cury++)
+           {
+             for(curx = cur->x1; curx < cur->x2; curx++)
+               {
+                 guchar *ptr = mem + (cury * rowstride) + (curx >> 3);
+
+                 if(pixel)
+                   *ptr |= (1 << (curx % 8));
+                 else
+                   *ptr &= ~(1 << (curx % 8));
+               }
+           }
+         break;
+
+       case 8:
+         for(cury = cur->y1; cury < cur->y2; cury++)
+           {
+             guchar *ptr = mem + (cury * rowstride) + cur->x1;
+             memset(ptr, pixel, cur->x2 - cur->x1);
+           }
+         break;
+
+       case 16:
+       case 24:
+       case 32:
+         for(cury = cur->y1; cury < cur->y2; cury++)
+           {
+             for(curx = cur->x1; curx < cur->x2; curx++)
+               {
+                 guint *ptr2 = (guint *)(mem + (cury * rowstride) + (curx * (depth >> 3)));
+
+                 *ptr2 = (*ptr2 & ~(visual->red_mask|visual->green_mask|visual->blue_mask)) | pixel;
+               }
+           }
+         break;
+       }
+    }
+}
+
+void
+gdk_fb_fill_spans(GdkDrawable *drawable,
+                 GdkGC *gc,
+                 GdkRectangle *rects, int nrects)
+{
+  int i;
+  guint pixel;
+  GdkRegion *real_clip_region, *tmpreg;
+  GdkRectangle draw_rect, cursor_rect;
+  GdkVisual *visual = gdk_visual_get_system();
+  gboolean handle_cursor = FALSE;
+
+  if(GDK_IS_WINDOW(drawable) && !GDK_WINDOW_P(drawable)->mapped)
+    return;
+  if(GDK_IS_WINDOW(drawable) && GDK_WINDOW_P(drawable)->input_only)
+    g_error("Drawing on the evil input-only!");
+
+  if(gc)
+    pixel = GDK_GC_FBDATA(gc)->values.foreground.pixel;
+  else if(GDK_IS_WINDOW(drawable))
+    pixel = GDK_WINDOW_P(drawable)->bg_color.pixel;
+  else
+    pixel = 0;
+
+  real_clip_region = gdk_fb_clip_region(drawable, gc, TRUE);
+
+  gdk_fb_get_cursor_rect(&cursor_rect);
+  if(GDK_DRAWABLE_FBDATA(drawable)->mem == GDK_DRAWABLE_FBDATA(gdk_parent_root)->mem
+     && cursor_rect.x >= 0
+     && gdk_region_rect_in(real_clip_region, &cursor_rect) != GDK_OVERLAP_RECTANGLE_OUT)
+    {
+      handle_cursor = TRUE;
+      gdk_fb_cursor_hide();
+    }
+    
+  for(i = 0; i < nrects; i++)
+    {
+      GdkSegment cur;
+      int j;
+
+      cur.x1 = rects[i].x;
+      cur.y1 = rects[i].y;
+      cur.x2 = cur.x1 + rects[i].width;
+      cur.y2 = cur.y1 + rects[i].height;
+      g_assert(cur.x2 >= cur.x1);
+      g_assert(cur.y2 >= cur.y1);
+
+      cur.x1 += GDK_DRAWABLE_FBDATA(drawable)->abs_x;
+      cur.x1 = MAX(cur.x1, GDK_DRAWABLE_FBDATA(drawable)->llim_x);
+
+      cur.x2 += GDK_DRAWABLE_FBDATA(drawable)->abs_x;
+      cur.x2 = MIN(cur.x2, GDK_DRAWABLE_FBDATA(drawable)->lim_x);
+      cur.x1 = MIN(cur.x1, cur.x2);
+
+      cur.y1 += GDK_DRAWABLE_FBDATA(drawable)->abs_y;
+      cur.y1 = MAX(cur.y1, GDK_DRAWABLE_FBDATA(drawable)->llim_y);
+
+      cur.y2 += GDK_DRAWABLE_FBDATA(drawable)->abs_y;
+      cur.y2 = MIN(cur.y2, GDK_DRAWABLE_FBDATA(drawable)->lim_y);
+      cur.y1 = MIN(cur.y1, cur.y2);
+
+      draw_rect.x = cur.x1;
+      draw_rect.y = cur.y1;
+      draw_rect.width = cur.x2 - cur.x1;
+      draw_rect.height = cur.y2 - cur.y1;
+
+      switch(gdk_region_rect_in(real_clip_region, &draw_rect))
+       {
+       case GDK_OVERLAP_RECTANGLE_PART:
+         tmpreg = gdk_region_rectangle(&draw_rect);
+         gdk_region_intersect(tmpreg, real_clip_region);
+         for(j = 0; j < tmpreg->numRects; j++)
+           gdk_fb_fill_span(drawable, gc, &tmpreg->rects[j], pixel, visual);
+         gdk_region_destroy(tmpreg);
+         break;
+       case GDK_OVERLAP_RECTANGLE_IN:
+         gdk_fb_fill_span(drawable, gc, &cur, pixel, visual);
+         break;
+       default:
+         break;
+       }
+    }
+
+  gdk_region_destroy(real_clip_region);
+  if(handle_cursor)
+    gdk_fb_cursor_unhide();
+}
+
+void
+gdk_fb_draw_drawable_2 (GdkDrawable *drawable,
+                       GdkGC       *gc,
+                       GdkPixmap   *src,
+                       gint         xsrc,
+                       gint         ysrc,
+                       gint         xdest,
+                       gint         ydest,
+                       gint         width,
+                       gint         height,
+                       gboolean     draw_bg,
+                       gboolean     do_clipping)
+{
+  GdkRegion *real_clip_region, *tmpreg;
+  GdkRectangle rect, cursor_rect;
+  int i;
+  int src_x_off, src_y_off;
+  int clipxoff, clipyoff;
+  guchar *mem = GDK_DRAWABLE_FBDATA(drawable)->mem, *srcmem = GDK_DRAWABLE_FBDATA(src)->mem;
+  guchar *clipmem;
+  guint rowstride = GDK_DRAWABLE_FBDATA(drawable)->rowstride, src_rowstride = GDK_DRAWABLE_FBDATA(src)->rowstride;
+  guint clip_rowstride;
+  GdkDrawableFBData *fbd;
+  gboolean handle_cursor = FALSE;
+  GdkPixmap *bgpm = NULL;
+  GdkWindow *bg_relto = drawable;
+
+  if(GDK_IS_WINDOW(drawable) && !GDK_WINDOW_P(drawable)->mapped)
+    return;
+  if(GDK_IS_WINDOW(drawable) && GDK_WINDOW_P(drawable)->input_only)
+    g_error("Drawing on the evil input-only!");
+
+  if(GDK_IS_WINDOW(drawable))
+    {
+      bgpm = GDK_WINDOW_P(drawable)->bg_pixmap;
+      if(bgpm == GDK_PARENT_RELATIVE_BG)
+       {
+         for(; bgpm == GDK_PARENT_RELATIVE_BG && bg_relto; bg_relto = GDK_WINDOW_P(bg_relto)->parent)
+           bgpm = GDK_WINDOW_P(bg_relto)->bg_pixmap;
+       }
+
+      if(bgpm == GDK_NO_BG)
+       bgpm = NULL;
+
+      if(bgpm)
+       g_assert(GDK_DRAWABLE_P(bgpm)->depth == 8);
+    }
+
+  if(drawable == src)
+    {
+      GdkDrawableFBData *fbd = GDK_DRAWABLE_FBDATA(src);
+      /* One lame hack deserves another ;-) */
+      srcmem = g_alloca(fbd->rowstride * fbd->lim_y);
+      memcpy(srcmem, mem, fbd->rowstride * fbd->lim_y);
+    }
+
+  real_clip_region = gdk_fb_clip_region(drawable, gc, do_clipping);
+  rect.x = xdest + GDK_DRAWABLE_FBDATA(drawable)->abs_x;
+  rect.y = ydest + GDK_DRAWABLE_FBDATA(drawable)->abs_y;
+  rect.width = width;
+  rect.height = height;
+  tmpreg = gdk_region_rectangle(&rect);
+  gdk_region_intersect(real_clip_region, tmpreg);
+  gdk_region_destroy(tmpreg);
+
+  rect.x = xdest + GDK_DRAWABLE_FBDATA(drawable)->abs_x;
+  rect.y = ydest + GDK_DRAWABLE_FBDATA(drawable)->abs_y;
+  rect.width = MAX(GDK_DRAWABLE_P(src)->width - xsrc, 0);
+  rect.height = MAX(GDK_DRAWABLE_P(src)->height - ysrc, 0);
+  if(!rect.width || !rect.height)
+    goto out;
+  tmpreg = gdk_region_rectangle(&rect);
+  gdk_region_intersect(real_clip_region, tmpreg);
+  gdk_region_destroy(tmpreg);
+
+  src_x_off = (GDK_DRAWABLE_FBDATA(src)->abs_x + xsrc) - (GDK_DRAWABLE_FBDATA(drawable)->abs_x + xdest);
+  src_y_off = (GDK_DRAWABLE_FBDATA(src)->abs_y + ysrc) - (GDK_DRAWABLE_FBDATA(drawable)->abs_y + ydest);
+  clipxoff = - GDK_DRAWABLE_FBDATA(drawable)->abs_x;
+  clipyoff = - GDK_DRAWABLE_FBDATA(drawable)->abs_y;
+  if(gc)
+    {
+      clipxoff -= GDK_GC_FBDATA(gc)->values.clip_x_origin;
+      clipyoff -= GDK_GC_FBDATA(gc)->values.clip_y_origin;
+
+      if(GDK_GC_FBDATA(gc)->values.clip_mask)
+       {
+         fbd = GDK_DRAWABLE_FBDATA(GDK_GC_FBDATA(gc)->values.clip_mask);
+         clipmem = GDK_DRAWABLE_FBDATA(GDK_GC_FBDATA(gc)->values.clip_mask)->mem;
+         clip_rowstride = GDK_DRAWABLE_FBDATA(GDK_GC_FBDATA(gc)->values.clip_mask)->rowstride;
+       }
+    }
+
+  gdk_fb_get_cursor_rect(&cursor_rect);
+  if(do_clipping
+     && GDK_DRAWABLE_FBDATA(drawable)->mem == GDK_DRAWABLE_FBDATA(gdk_parent_root)->mem
+     && cursor_rect.x >= 0
+     && gdk_region_rect_in(real_clip_region, &cursor_rect) != GDK_OVERLAP_RECTANGLE_OUT)
+    {
+      handle_cursor = TRUE;
+      gdk_fb_cursor_hide();
+    }
+
+  for(i = 0; i < real_clip_region->numRects; i++)
+    {
+      GdkRegionBox *cur = &real_clip_region->rects[i];
+      int cur_y;
+
+      if(GDK_DRAWABLE_P(src)->depth == GDK_DRAWABLE_P(drawable)->depth
+        && GDK_DRAWABLE_P(src)->depth > 1
+        && (!gc || !GDK_GC_FBDATA(gc)->values.clip_mask))
+       {
+         guint depth = GDK_DRAWABLE_P(src)->depth;
+
+         for(cur_y = cur->y1; cur_y < cur->y2; cur_y++)
+           {
+             memcpy(mem + (cur_y * rowstride) + cur->x1*(depth>>3),
+                    srcmem + ((cur_y + src_y_off)*src_rowstride) + (cur->x1 + src_x_off)*(depth>>3),
+                    (cur->x2 - cur->x1)*(depth>>3));
+           }
+       }
+      else
+       {
+         int cur_x;
+
+         for(cur_y = cur->y1; cur_y < cur->y2; cur_y++)
+           {
+             for(cur_x = cur->x1; cur_x < cur->x2; cur_x++)
+               {
+                 guint pixel;
+                 guint16 *p16;
+                 guint32 *p32;
+
+                 if(gc && GDK_GC_FBDATA(gc)->values.clip_mask)
+                   {
+                     int maskx = cur_x+clipxoff, masky = cur_y + clipyoff;
+                     guchar foo;
+
+                     if(maskx < 0 || masky < 0)
+                       continue;
+
+                     foo = clipmem[masky*clip_rowstride + (maskx >> 3)];
+
+                     if(!(foo & (1 << (maskx % 8))))
+                       continue;
+                   }
+
+                 switch(GDK_DRAWABLE_P(src)->depth)
+                   {
+                   case 1:
+                     {
+                       guchar foo = srcmem[((cur_x + src_x_off) >> 3) + ((cur_y + src_y_off)*src_rowstride)];
+
+                       if(foo & (1 << ((cur_x + src_x_off) % 8))) {
+                         pixel = GDK_GC_FBDATA(gc)->values.foreground.pixel;
+                       } else if(draw_bg) {
+                         if(bgpm)
+                           {
+                             int bgx, bgy;
+
+                             bgx = (cur_x - GDK_DRAWABLE_FBDATA(bg_relto)->abs_x) % GDK_DRAWABLE_P(bgpm)->width;
+                             bgy = (cur_y - GDK_DRAWABLE_FBDATA(bg_relto)->abs_y) % GDK_DRAWABLE_P(bgpm)->height;
+
+                             pixel = GDK_DRAWABLE_FBDATA(bgpm)->mem[bgx + bgy * GDK_DRAWABLE_FBDATA(bgpm)->rowstride];
+                           }
+                         else
+                           pixel = GDK_GC_FBDATA(gc)->values.background.pixel;
+                       } else
+                         continue;
+                     }
+                     break;
+                   case 8:
+                     pixel = srcmem[(cur_x + src_x_off) + ((cur_y + src_y_off)*src_rowstride)];
+                     break;
+                   case 16:
+                     pixel = *(guint16 *)(srcmem + (cur_x + src_x_off)*2 + ((cur_y + src_y_off)*src_rowstride));
+                     break;
+                   case 24:
+                     pixel = 0x00FFFFFF & *(guint32 *)(srcmem + (cur_x + src_x_off)*3 + ((cur_y + src_y_off)*src_rowstride));
+                     break;
+                   case 32:
+                     pixel = *(guint32 *)(srcmem + (cur_x + src_x_off)*4 + ((cur_y + src_y_off)*src_rowstride));
+                     break;
+                   default:
+                     g_assert_not_reached();
+                     break;
+                   }
+
+                 switch(GDK_DRAWABLE_P(drawable)->depth)
+                   {
+                   case 1:
+                     {
+                       guchar *foo = mem + (cur_y*src_rowstride) + (cur_x >> 3);
+
+                       if(pixel == GDK_GC_FBDATA(gc)->values.foreground.pixel)
+                         *foo |= (1 << (cur_x % 8));
+                       else
+                         *foo &= ~(1 << (cur_x % 8));
+                     }
+                     break;
+                   case 8:
+                     mem[cur_x + cur_y*rowstride] = pixel;
+                     break;
+                   case 16:
+                     p16 = (guint16 *)&mem[cur_x*2 + cur_y*rowstride];
+                     *p16 = pixel;
+                     break;
+                   case 24:
+                     p32 = (guint32 *)&mem[cur_x*3 + cur_y*rowstride];
+                     *p32 = (*p32 & 0xFF000000) | pixel;
+                     break;
+                   case 32:
+                     p32 = (guint32 *)&mem[cur_x*4 + cur_y*rowstride];
+                     *p32 = pixel;
+                     break;
+                   default:
+                     g_assert_not_reached();
+                     break;
+                   }
+               }
+           }
+       }
+    }
+
+ out:
+  gdk_region_destroy(real_clip_region);
+
+  if(handle_cursor)
+    gdk_fb_cursor_unhide();
+}
+
+void
+gdk_fb_draw_drawable (GdkDrawable *drawable,
+                     GdkGC       *gc,
+                     GdkPixmap   *src,
+                     gint         xsrc,
+                     gint         ysrc,
+                     gint         xdest,
+                     gint         ydest,
+                     gint         width,
+                     gint         height)
+{
+  gdk_fb_draw_drawable_2(drawable, gc, src, xsrc, ysrc, xdest, ydest, width, height, TRUE, TRUE);
+}
+
+static void
+gdk_fb_draw_text(GdkDrawable    *drawable,
+                GdkFont        *font,
+                GdkGC          *gc,
+                gint            x,
+                gint            y,
+                const gchar    *text,
+                gint            text_length)
+{
+  GLYPH *g;
+  GdkDrawablePrivate tmp_pixmap;
+  GdkDrawableFBData fbd;
+
+  if(GDK_IS_WINDOW(drawable) && !GDK_WINDOW_P(drawable)->mapped)
+    return;
+
+  y -= font->ascent; /* y is relative to baseline, we want it relative to top left corner */
+
+  g = T1_SetString(GDK_FONT_FB(font)->t1_font_id, (char *)text, text_length, 0, T1_KERNING, GDK_FONT_FB(font)->size,
+                  NULL);
+  g_assert(g);
+
+  tmp_pixmap.window_type = GDK_DRAWABLE_PIXMAP;
+  tmp_pixmap.width = (g->metrics.rightSideBearing - g->metrics.leftSideBearing);
+  tmp_pixmap.height = (g->metrics.ascent - g->metrics.descent);
+  tmp_pixmap.depth = 1;
+
+  fbd.mem = g->bits;
+  fbd.abs_x = fbd.abs_y = fbd.llim_x = fbd.llim_y = 0;
+  fbd.lim_x = tmp_pixmap.width;
+  fbd.lim_y = tmp_pixmap.height;
+  fbd.rowstride = (tmp_pixmap.width + 7) / 8;
+  tmp_pixmap.klass_data = &fbd;
+  tmp_pixmap.klass = &_gdk_fb_drawable_class;
+
+  gdk_fb_draw_drawable_2(drawable, gc, (GdkPixmap *)&tmp_pixmap, 0, 0, x, y, tmp_pixmap.width, tmp_pixmap.height, FALSE, TRUE);
+}
+
+static void
+gdk_fb_draw_text_wc (GdkDrawable    *drawable,
+                    GdkFont         *font,
+                    GdkGC           *gc,
+                    gint             x,
+                    gint             y,
+                    const GdkWChar *text,
+                    gint             text_length)
+{
+  char *realbuf;
+  int i;
+
+  if(GDK_IS_WINDOW(drawable) && (!GDK_WINDOW_P(drawable)->mapped || GDK_WINDOW_P(drawable)->input_only))
+    return;
+
+  /* A hack, a hack, a pretty little hack */
+  realbuf = alloca(text_length + 1);
+  for(i = 0; i < text_length; i++)
+    realbuf[i] = text[i];
+  realbuf[i] = 0;
+
+  gdk_fb_draw_text(drawable, font, gc, x, y, realbuf, text_length);
+}
+
+void
+gdk_fb_draw_rectangle (GdkDrawable    *drawable,
+                      GdkGC          *gc,
+                      gint            filled,
+                      gint            x,
+                      gint            y,
+                      gint            width,
+                      gint            height)
+{
+  GdkRectangle rect;
+
+  if(filled)
+    {
+      static volatile int print_rect = 0;
+
+      if(print_rect)
+       {
+         fprintf(debug_out, "[%d, %d] +[%d, %d]\n", x, y, width, height);
+         if(y < 0)
+           G_BREAKPOINT();
+       }
+
+      rect.x = x;
+      rect.y = y;
+      rect.width = width;
+      rect.height = height;
+      gdk_fb_fill_spans(drawable, gc, &rect, 1);
+    }
+  else
+    {
+      GdkPoint pts[5];
+      pts[0].x = pts[4].x = x;
+      pts[0].y = pts[4].y = y;
+      pts[1].x = x + width;
+      pts[1].y = y;
+      pts[2].x = x + width;
+      pts[2].y = y + height;
+      pts[3].x = x;
+      pts[3].y = y + height;
+      gdk_fb_draw_lines(drawable, gc, pts, 5);
+    }
+}
+
+static void gdk_fb_draw_points    (GdkDrawable    *drawable,
+                                  GdkGC          *gc,
+                                  GdkPoint       *points,
+                                  gint            npoints)
+{
+  GdkRectangle *rects = alloca(npoints * sizeof(GdkRectangle));
+  int i;
+
+  for(i = 0; i < npoints; i++)
+    {
+      rects[i].x = points[i].x;
+      rects[i].y = points[i].y;
+      rects[i].width = rects[i].height = 1;
+    }
+
+  gdk_fb_fill_spans(drawable, gc, rects, npoints);
+}
+
+static void gdk_fb_draw_arc       (GdkDrawable    *drawable,
+                                  GdkGC          *gc,
+                                  gint            filled,
+                                  gint            x,
+                                  gint            y,
+                                  gint            width,
+                                  gint            height,
+                                  gint            angle1,
+                                  gint            angle2)
+{
+  miArc arc;
+
+  arc.x = x;
+  arc.y = y;
+  arc.width = width;
+  arc.height = height;
+  arc.angle1 = angle1;
+  arc.angle2 = angle2;
+
+  if(filled)
+    miPolyFillArc(drawable, gc, 1, &arc);
+  else
+    miPolyArc(drawable, gc, 1, &arc);
+}
+
+static void gdk_fb_draw_polygon   (GdkDrawable    *drawable,
+                                  GdkGC          *gc,
+                                  gint            filled,
+                                  GdkPoint       *points,
+                                  gint            npoints)
+{
+  if(filled)
+    miFillPolygon(drawable, gc, 0, 0, npoints, points);
+  else
+    {
+      GdkPoint *realpts = alloca(sizeof(GdkPoint) * (npoints + 1));
+
+      memcpy(realpts, points, sizeof(GdkPoint) * npoints);
+      realpts[npoints] = points[0];
+      gdk_fb_draw_lines(drawable, gc, points, npoints);
+    }
+}
+
+static void gdk_fb_draw_lines     (GdkDrawable    *drawable,
+                                  GdkGC          *gc,
+                                  GdkPoint       *points,
+                                  gint            npoints)
+{
+  if(GDK_GC_FBDATA(gc)->values.line_width > 0)
+    miWideLine(drawable, gc, 0, npoints, points);
+  else
+    miZeroLine(drawable, gc, 0, npoints, points);
+}
+
+static void gdk_fb_draw_segments  (GdkDrawable    *drawable,
+                                  GdkGC          *gc,
+                                  GdkSegment     *segs,
+                                  gint            nsegs)
+{
+  GdkPoint pts[2];
+  int i;
+
+  for(i = 0; i < nsegs; i++)
+    {
+      pts[0].x = segs[i].x1;
+      pts[0].y = segs[i].y1;
+      pts[1].x = segs[i].x2;
+      pts[1].y = segs[i].y2;
+
+      gdk_fb_draw_lines(drawable, gc, pts, 2);
+    }
+}
+
+void
+gdk_fb_drawable_clear(GdkDrawable *d)
+{
+  _gdk_windowing_window_clear_area(d, 0, 0, GDK_DRAWABLE_P(d)->width, GDK_DRAWABLE_P(d)->height);
+}
diff --git a/gdk/linux-fb/gdkevents-fb.c b/gdk/linux-fb/gdkevents-fb.c
new file mode 100644 (file)
index 0000000..7b80aa3
--- /dev/null
@@ -0,0 +1,209 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "gdk.h"
+#include "gdkprivate-fb.h"
+#include "gdkinternals.h"
+#include "gdkfb.h"
+
+#include "gdkkeysyms.h"
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#  if STDC_HEADERS
+#    include <string.h>
+#  endif
+#endif
+
+typedef struct _GdkIOClosure GdkIOClosure;
+typedef struct _GdkEventPrivate GdkEventPrivate;
+
+#define DOUBLE_CLICK_TIME      250
+#define TRIPLE_CLICK_TIME      500
+#define DOUBLE_CLICK_DIST      5
+#define TRIPLE_CLICK_DIST      5
+
+typedef enum
+{
+  /* Following flag is set for events on the event queue during
+   * translation and cleared afterwards.
+   */
+  GDK_EVENT_PENDING = 1 << 0
+} GdkEventFlags;
+
+struct _GdkIOClosure
+{
+  GdkInputFunction function;
+  GdkInputCondition condition;
+  GdkDestroyNotify notify;
+  gpointer data;
+};
+
+struct _GdkEventPrivate
+{
+  GdkEvent event;
+  guint    flags;
+};
+
+/* 
+ * Private function declarations
+ */
+
+/* Private variable declarations
+ */
+
+#if 0
+static GList *client_filters;              /* Filters for client messages */
+
+static GSourceFuncs event_funcs = {
+  gdk_event_prepare,
+  gdk_event_check,
+  gdk_event_dispatch,
+  (GDestroyNotify)g_free
+};
+#endif
+
+/*********************************************
+ * Functions for maintaining the event queue *
+ *********************************************/
+
+void 
+gdk_events_init (void)
+{
+  
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_events_pending
+ *
+ *   Returns if events are pending on the queue.
+ *
+ * Arguments:
+ *
+ * Results:
+ *   Returns TRUE if events are pending
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gboolean
+gdk_events_pending (void)
+{
+  return gdk_event_queue_find_first()?TRUE:FALSE;
+}
+
+GdkEvent*
+gdk_event_get_graphics_expose (GdkWindow *window)
+{
+  g_return_val_if_fail (window != NULL, NULL);
+  
+  return NULL; 
+}
+
+void
+gdk_events_queue (void)
+{
+  
+}
+
+static gint handler_tag = 0;
+
+static gboolean
+dispatch_events(gpointer data)
+{
+  GdkEvent *event;
+
+  GDK_THREADS_ENTER();
+
+  while((event = gdk_event_unqueue()))
+    {
+      if(event->type == GDK_EXPOSE
+        && event->expose.window == gdk_parent_root)
+       gdk_fb_drawable_clear(event->expose.window);
+      else if(gdk_event_func)
+       (*gdk_event_func)(event, gdk_event_data);
+      gdk_event_free(event);
+    }
+
+  GDK_THREADS_LEAVE();
+  if(event && !handler_tag)
+    handler_tag = g_idle_add_full(G_PRIORITY_HIGH_IDLE, dispatch_events, NULL, NULL);
+  else if(!event && handler_tag)
+    {
+      g_source_remove(handler_tag);
+      handler_tag = 0;
+    }
+
+  return handler_tag?TRUE:FALSE;
+}
+
+void
+_gdk_event_queue_changed(GList *queue)
+{
+  if(queue && !handler_tag)
+    handler_tag = g_idle_add_full(G_PRIORITY_HIGH_IDLE, dispatch_events, NULL, NULL);
+  else if(!queue && handler_tag)
+    {
+      g_source_remove(handler_tag);
+      handler_tag = 0;
+    }
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_flush
+ *
+ *   Flushes the Xlib output buffer and then waits
+ *   until all requests have been received and processed
+ *   by the X server. The only real use for this function
+ *   is in dealing with XShm.
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+gdk_flush (void)
+{
+}
+
+gboolean
+gdk_event_send_client_message (GdkEvent *event, guint32 xid)
+{
+  return FALSE;
+}
+
+void gdk_event_send_clientmessage_toall (GdkEvent *sev)
+{
+}
diff --git a/gdk/linux-fb/gdkfb.h b/gdk/linux-fb/gdkfb.h
new file mode 100644 (file)
index 0000000..7cb6f6d
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef GDKFB_H
+#define GDKFB_H 1
+
+#include "gdk/gdkprivate.h"
+
+typedef struct _GdkFBDisplay GdkFBDisplay;
+typedef struct _GdkFBWindow GdkFBWindow;
+
+extern GdkFBWindow *gdk_root_window;
+extern GdkFBDisplay *gdk_display;
+
+#define GDK_ROOT_WINDOW()             gdk_root_window
+#define GDK_ROOT_PARENT()             ((GdkWindow *)gdk_parent_root)
+#define GDK_DISPLAY()                 gdk_display
+
+extern const char *gdk_progclass;
+
+#endif /* GDKFB_H */
diff --git a/gdk/linux-fb/gdkfont-fb.c b/gdk/linux-fb/gdkfont-fb.c
new file mode 100644 (file)
index 0000000..c22b840
--- /dev/null
@@ -0,0 +1,328 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include <t1lib.h>
+#include <math.h>
+#include <stdlib.h>
+#include "gdkfont.h"
+#include "gdkprivate-fb.h"
+
+static GHashTable *font_name_hash = NULL;
+static GHashTable *fontset_name_hash = NULL;
+
+static void
+gdk_font_hash_insert (GdkFontType type, GdkFont *font, const gchar *font_name)
+{
+  GdkFontPrivateFB *private = (GdkFontPrivateFB *)font;
+  GHashTable **hashp = (type == GDK_FONT_FONT) ?
+    &font_name_hash : &fontset_name_hash;
+
+  if (!*hashp)
+    *hashp = g_hash_table_new (g_str_hash, g_str_equal);
+
+  private->names = g_slist_prepend (private->names, g_strdup (font_name));
+  g_hash_table_insert (*hashp, private->names->data, font);
+}
+
+static void
+gdk_font_hash_remove (GdkFontType type, GdkFont *font)
+{
+  GdkFontPrivateFB *private = (GdkFontPrivateFB *)font;
+  GSList *tmp_list;
+  GHashTable *hash = (type == GDK_FONT_FONT) ?
+    font_name_hash : fontset_name_hash;
+
+  tmp_list = private->names;
+  while (tmp_list)
+    {
+      g_hash_table_remove (hash, tmp_list->data);
+      g_free (tmp_list->data);
+      
+      tmp_list = tmp_list->next;
+    }
+
+  g_slist_free (private->names);
+  private->names = NULL;
+}
+
+static GdkFont *
+gdk_font_hash_lookup (GdkFontType type, const gchar *font_name)
+{
+  GdkFont *result;
+  GHashTable *hash = (type == GDK_FONT_FONT) ?
+    font_name_hash : fontset_name_hash;
+
+  if (!hash)
+    return NULL;
+  else
+    {
+      result = g_hash_table_lookup (hash, font_name);
+      if (result)
+       gdk_font_ref (result);
+      
+      return result;
+    }
+}
+
+GdkFont*
+gdk_font_load (const gchar *font_name)
+{
+  GdkFont *font;
+  GdkFontPrivateFB *private;
+
+  g_return_val_if_fail (font_name != NULL, NULL);
+
+  font = gdk_font_hash_lookup (GDK_FONT_FONTSET, font_name);
+  if (font)
+    return font;
+
+  {
+    char **pieces;
+    BBox bb;
+    
+    private = g_new0 (GdkFontPrivateFB, 1);
+    private->base.ref_count = 1;
+    private->names = NULL;
+
+    pieces = g_strsplit(font_name, "-", 2);
+    if(pieces[1])
+      {
+       private->size = atof(pieces[1]);
+       private->t1_font_id = T1_AddFont(pieces[0]);
+      }
+    else
+      private->t1_font_id = T1_AddFont((char *)font_name);
+    g_strfreev(pieces);
+
+    T1_LoadFont(private->t1_font_id);
+    CreateNewFontSize(private->t1_font_id, private->size, FALSE);
+
+    font = (GdkFont*) private;
+    font->type = GDK_FONT_FONTSET;
+
+    bb = T1_GetFontBBox(private->t1_font_id);
+
+    font->ascent = ((double)bb.ury) / 1000.0 * private->size;
+    font->descent = ((double)bb.lly) / -1000.0 * private->size;
+  }
+
+  gdk_font_hash_insert (GDK_FONT_FONTSET, font, font_name);
+
+  return font;
+}
+
+GdkFont*
+gdk_fontset_load (const gchar *fontset_name)
+{
+  return gdk_font_load(fontset_name);
+}
+
+void
+_gdk_font_destroy (GdkFont *font)
+{
+  gdk_font_hash_remove (font->type, font);
+      
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      break;
+    case GDK_FONT_FONTSET:
+      break;
+    default:
+      g_error ("unknown font type.");
+      break;
+    }
+  g_free (font);
+}
+
+gint
+_gdk_font_strlen (GdkFont     *font,
+                 const gchar *str)
+{
+  GdkFontPrivateFB *font_private;
+  gint length = 0;
+
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (str != NULL, -1);
+
+  font_private = (GdkFontPrivateFB*) font;
+
+  if (font->type == GDK_FONT_FONT)
+    {
+      guint16 *string_2b = (guint16 *)str;
+           
+      while (*(string_2b++))
+       length++;
+    }
+  else if (font->type == GDK_FONT_FONTSET)
+    {
+      length = strlen (str);
+    }
+  else
+    g_error("undefined font type\n");
+
+  return length;
+}
+
+gint
+gdk_font_id (const GdkFont *font)
+{
+  const GdkFontPrivateFB *font_private;
+
+  g_return_val_if_fail (font != NULL, 0);
+
+  font_private = (const GdkFontPrivateFB*) font;
+
+  if (font->type == GDK_FONT_FONT)
+    {
+      return -1;
+    }
+  else
+    {
+      return 0;
+    }
+}
+
+gint
+gdk_font_equal (const GdkFont *fonta,
+                const GdkFont *fontb)
+{
+  const GdkFontPrivateFB *privatea;
+  const GdkFontPrivateFB *privateb;
+
+  g_return_val_if_fail (fonta != NULL, FALSE);
+  g_return_val_if_fail (fontb != NULL, FALSE);
+
+  privatea = (const GdkFontPrivateFB*) fonta;
+  privateb = (const GdkFontPrivateFB*) fontb;
+
+  if(fonta == fontb)
+    return TRUE;
+  if(privatea->t1_font_id == privateb->t1_font_id
+     && privatea->size == privateb->size)
+    return TRUE;
+
+  return FALSE;
+}
+
+gint
+gdk_text_width (GdkFont      *font,
+               const gchar  *text,
+               gint          text_length)
+{
+  GdkFontPrivateFB *private;
+  gint width;
+  double n;
+
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (text != NULL, -1);
+
+  private = (GdkFontPrivateFB*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+    case GDK_FONT_FONTSET:
+      n = private->size / 1000.0;
+      n *= T1_GetStringWidth(private->t1_font_id, (char *)text, text_length, 0, T1_KERNING);
+      width = ceil(n);
+      break;
+    default:
+      width = 0;
+      break;
+    }
+
+  return width;
+}
+
+gint
+gdk_text_width_wc (GdkFont       *font,
+                  const GdkWChar *text,
+                  gint            text_length)
+{
+  char *realstr;
+  int i;
+
+  realstr = alloca(text_length + 1);
+  for(i = 0; i < text_length; i++)
+    realstr[i] = text[i];
+  realstr[i] = '\0';
+
+  return gdk_text_width(font, realstr, text_length);
+}
+
+void
+gdk_text_extents (GdkFont     *font,
+                  const gchar *text,
+                  gint         text_length,
+                 gint        *lbearing,
+                 gint        *rbearing,
+                 gint        *width,
+                 gint        *ascent,
+                 gint        *descent)
+{
+  GdkFontPrivateFB *private;
+  METRICSINFO mi;
+
+  g_return_if_fail (font != NULL);
+  g_return_if_fail (text != NULL);
+
+  private = (GdkFontPrivateFB*) font;
+
+  mi = T1_GetMetricsInfo(private->t1_font_id, (char *)text, text_length, 0, T1_KERNING);
+
+  if(ascent)
+    *ascent = ((double)mi.bbox.ury) / 1000.0 * private->size;
+  if(descent)
+    *descent = ((double)mi.bbox.lly) / -1000.0 * private->size;
+  if(width)
+    *width = ((double)mi.width) / 1000.0 * private->size;
+  if(lbearing)
+    *lbearing = ((double)mi.bbox.llx) / 1000.0 * private->size;
+  if(rbearing)
+    *rbearing = ((double)mi.bbox.urx) / 1000.0 * private->size;
+}
+
+void
+gdk_text_extents_wc (GdkFont        *font,
+                    const GdkWChar *text,
+                    gint            text_length,
+                    gint           *lbearing,
+                    gint           *rbearing,
+                    gint           *width,
+                    gint           *ascent,
+                    gint           *descent)
+{
+  char *realstr;
+  int i;
+
+  realstr = alloca(text_length + 1);
+  for(i = 0; i < text_length; i++)
+    realstr[i] = text[i];
+  realstr[i] = '\0';
+
+  return gdk_text_extents(font, realstr, text_length, lbearing, rbearing, width, ascent, descent);
+}
diff --git a/gdk/linux-fb/gdkgc-fb.c b/gdk/linux-fb/gdkgc-fb.c
new file mode 100644 (file)
index 0000000..02bf5d0
--- /dev/null
@@ -0,0 +1,308 @@
+#include "gdkprivate-fb.h"
+#include "gdkgc.h"
+#include "gdkfb.h"
+#include "gdkregion-generic.h"
+
+typedef enum {
+  GDK_GC_DIRTY_CLIP = 1 << 0,
+  GDK_GC_DIRTY_TS = 1 << 1
+} GdkGCDirtyValues;
+
+static void gdk_fb_gc_destroy    (GdkGC           *gc);
+static void gdk_fb_gc_get_values (GdkGC           *gc,
+                                  GdkGCValues     *values);
+static void gdk_fb_gc_set_values (GdkGC           *gc,
+                                  GdkGCValues     *values,
+                                  GdkGCValuesMask  values_mask);
+static void gdk_fb_gc_set_dashes (GdkGC          *gc,
+                                 gint            dash_offset,
+                                 gchar           dash_list[],
+                                 gint            n);
+
+static GdkGCClass gdk_fb_gc_class = {
+  gdk_fb_gc_destroy,
+  gdk_fb_gc_get_values,
+  gdk_fb_gc_set_values,
+  gdk_fb_gc_set_dashes
+};
+
+GdkGC *
+_gdk_fb_gc_new (GdkDrawable      *drawable,
+               GdkGCValues      *values,
+               GdkGCValuesMask   values_mask)
+{
+  GdkGC *gc;
+  GdkGCPrivate *private;
+  GdkGCFBData *data;
+  
+  gc = gdk_gc_alloc ();
+  private = (GdkGCPrivate *)gc;
+
+  private->klass = &gdk_fb_gc_class;
+  private->klass_data = data = g_new0 (GdkGCFBData, 1);
+  data->values.foreground.pixel = 255;
+  data->values.foreground.red = data->values.foreground.green = data->values.foreground.blue = 65535;
+
+  gdk_fb_gc_set_values(gc, values, values_mask);
+
+  return gc;
+}
+
+static void
+gdk_fb_gc_destroy (GdkGC *gc)
+{
+  if (GDK_GC_FBDATA (gc)->clip_region)
+    gdk_region_destroy (GDK_GC_FBDATA (gc)->clip_region);
+  
+  g_free (GDK_GC_FBDATA (gc));
+}
+
+static void
+gdk_fb_gc_get_values (GdkGC       *gc,
+                     GdkGCValues *values)
+{
+  *values = GDK_GC_FBDATA(gc)->values;
+}
+
+
+static void
+gdk_fb_gc_set_values (GdkGC           *gc,
+                     GdkGCValues     *values,
+                     GdkGCValuesMask  values_mask)
+{
+  GdkPixmap *oldpm;
+  GdkFont *oldf;
+
+  if(values_mask & GDK_GC_FOREGROUND)
+    {
+      GDK_GC_FBDATA(gc)->values.foreground = values->foreground;
+      GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_FOREGROUND;
+    }
+
+  if(values_mask & GDK_GC_BACKGROUND)
+    {
+      GDK_GC_FBDATA(gc)->values.background = values->background;
+      GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_BACKGROUND;
+    }
+
+  if(values_mask & GDK_GC_FONT)
+    {
+      oldf = GDK_GC_FBDATA(gc)->values.font;
+      GDK_GC_FBDATA(gc)->values.font = gdk_font_ref(values->font);
+      GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_FONT;
+      if(oldf)
+       gdk_font_unref(oldf);
+    }
+
+  if(values_mask & GDK_GC_FUNCTION)
+    {
+      GDK_GC_FBDATA(gc)->values.function = values->function;
+      GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_FUNCTION;
+    }
+
+  if(values_mask & GDK_GC_FILL)
+    {
+      GDK_GC_FBDATA(gc)->values.fill = values->fill;
+      GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_FILL;
+    }
+
+  if(values_mask & GDK_GC_TILE)
+    {
+      oldpm = GDK_GC_FBDATA(gc)->values.tile;
+      if(values->tile)
+       g_assert(GDK_DRAWABLE_P(values->tile)->depth == 8);
+
+      GDK_GC_FBDATA(gc)->values.tile = values->tile?gdk_pixmap_ref(values->tile):NULL;
+      GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_TILE;
+      if(oldpm)
+       gdk_pixmap_unref(oldpm);
+    }
+
+  if(values_mask & GDK_GC_STIPPLE)
+    {
+      oldpm = GDK_GC_FBDATA(gc)->values.stipple;
+      if(values->stipple)
+       g_assert(GDK_DRAWABLE_P(values->stipple)->depth == 1);
+      GDK_GC_FBDATA(gc)->values.stipple = values->stipple?gdk_pixmap_ref(values->stipple):NULL;
+      GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_STIPPLE;
+      if(oldpm)
+       gdk_pixmap_unref(oldpm);
+    }
+
+  if(values_mask & GDK_GC_CLIP_MASK)
+    {
+      oldpm = GDK_GC_FBDATA(gc)->values.clip_mask;
+
+      GDK_GC_FBDATA(gc)->values.clip_mask = values->clip_mask?gdk_pixmap_ref(values->clip_mask):NULL;
+      GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_CLIP_MASK;
+      if(oldpm)
+       gdk_pixmap_unref(oldpm);
+    }
+
+  if(values_mask & GDK_GC_SUBWINDOW)
+    {
+      GDK_GC_FBDATA(gc)->values.subwindow_mode = values->subwindow_mode;
+      GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_SUBWINDOW;
+    }
+
+  if(values_mask & GDK_GC_TS_X_ORIGIN)
+    {
+      GDK_GC_FBDATA(gc)->values.ts_x_origin = values->ts_x_origin;
+      GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_TS_X_ORIGIN;
+    }
+
+  if(values_mask & GDK_GC_TS_Y_ORIGIN)
+    {
+      GDK_GC_FBDATA(gc)->values.ts_y_origin = values->ts_y_origin;
+      GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_TS_Y_ORIGIN;
+    }
+
+  if(values_mask & GDK_GC_CLIP_X_ORIGIN)
+    {
+      GDK_GC_FBDATA(gc)->values.clip_x_origin = GDK_GC_P(gc)->clip_x_origin = values->clip_x_origin;
+      GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_CLIP_X_ORIGIN;
+    }
+
+  if(values_mask & GDK_GC_CLIP_Y_ORIGIN)
+    {
+      GDK_GC_FBDATA(gc)->values.clip_y_origin = GDK_GC_P(gc)->clip_y_origin = values->clip_y_origin;
+      GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_CLIP_Y_ORIGIN;
+    }
+
+  if(values_mask & GDK_GC_EXPOSURES)
+    {
+      GDK_GC_FBDATA(gc)->values.graphics_exposures = values->graphics_exposures;
+      GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_EXPOSURES;
+    }
+
+  if(values_mask & GDK_GC_LINE_WIDTH)
+    {
+      GDK_GC_FBDATA(gc)->values.line_width = values->line_width;
+      GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_LINE_WIDTH;
+    }
+
+  if(values_mask & GDK_GC_LINE_STYLE)
+    {
+      GDK_GC_FBDATA(gc)->values.line_style = values->line_style;
+      GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_LINE_STYLE;
+    }
+
+  if(values_mask & GDK_GC_CAP_STYLE)
+    {
+      GDK_GC_FBDATA(gc)->values.cap_style = values->cap_style;
+      GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_CAP_STYLE;
+    }
+
+  if(values_mask & GDK_GC_JOIN_STYLE)
+    {
+      GDK_GC_FBDATA(gc)->values.join_style = values->join_style;
+      GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_JOIN_STYLE;
+    }
+}
+
+static void
+gdk_fb_gc_set_dashes (GdkGC *gc,
+                     gint dash_offset,
+                     gchar dash_list[],
+                     gint n)
+{
+  GDK_GC_FBDATA(gc)->dash_offset = dash_offset;
+  GDK_GC_FBDATA(gc)->dash_list_len = n;
+  if(n)
+    {
+      GDK_GC_FBDATA(gc)->dash_list = g_realloc(GDK_GC_FBDATA(gc)->dash_list, n);
+      memcpy(GDK_GC_FBDATA(gc)->dash_list, dash_list, n);
+    }
+  else
+    {
+      g_free(GDK_GC_FBDATA(gc)->dash_list);
+      GDK_GC_FBDATA(gc)->dash_list = NULL;
+    }
+}
+
+void
+gdk_gc_set_clip_rectangle (GdkGC       *gc,
+                          GdkRectangle *rectangle)
+{
+  GdkGCPrivate *private = (GdkGCPrivate *)gc;
+  GdkGCFBData *data;
+
+  g_return_if_fail (gc != NULL);
+
+  data = GDK_GC_FBDATA (gc);
+
+  if (data->clip_region)
+    {
+      gdk_region_destroy (data->clip_region);
+      data->clip_region = NULL;
+    }
+
+  if (rectangle)
+    data->clip_region = gdk_region_rectangle (rectangle);
+
+  private->clip_x_origin = 0;
+  private->clip_y_origin = 0;
+  data->values.clip_x_origin = 0;
+  data->values.clip_y_origin = 0;
+} 
+
+void
+gdk_gc_set_clip_region (GdkGC    *gc,
+                       GdkRegion *region)
+{
+  GdkGCPrivate *private = (GdkGCPrivate *)gc;
+  GdkGCFBData *data;
+
+  g_return_if_fail (gc != NULL);
+
+  data = GDK_GC_FBDATA (gc);
+
+  if(region == data->clip_region)
+    return;
+
+  if (data->clip_region)
+    {
+      gdk_region_destroy (data->clip_region);
+      data->clip_region = NULL;
+    }
+
+  if (region)
+    data->clip_region = gdk_region_copy (region);
+  
+  private->clip_x_origin = 0;
+  private->clip_y_origin = 0;
+  data->values.clip_x_origin = 0;
+  data->values.clip_y_origin = 0;
+}
+
+
+void
+gdk_gc_copy (GdkGC *dst_gc, GdkGC *src_gc)
+{
+  g_return_if_fail (dst_gc != NULL);
+  g_return_if_fail (src_gc != NULL);
+
+  if(GDK_GC_FBDATA(dst_gc)->clip_region)
+    gdk_region_destroy(GDK_GC_FBDATA(dst_gc)->clip_region);
+
+  if(GDK_GC_FBDATA(dst_gc)->values_mask & GDK_GC_FONT)
+    gdk_font_unref(GDK_GC_FBDATA(dst_gc)->values.font);
+  if(GDK_GC_FBDATA(dst_gc)->values_mask & GDK_GC_TILE)
+    gdk_pixmap_unref(GDK_GC_FBDATA(dst_gc)->values.tile);
+  if(GDK_GC_FBDATA(dst_gc)->values_mask & GDK_GC_STIPPLE)
+    gdk_pixmap_unref(GDK_GC_FBDATA(dst_gc)->values.stipple);
+  if(GDK_GC_FBDATA(dst_gc)->values_mask & GDK_GC_CLIP_MASK)
+    gdk_pixmap_unref(GDK_GC_FBDATA(dst_gc)->values.clip_mask);
+
+  *dst_gc = *src_gc;
+  if(GDK_GC_FBDATA(dst_gc)->values_mask & GDK_GC_FONT)
+    gdk_font_ref(GDK_GC_FBDATA(dst_gc)->values.font);
+  if(GDK_GC_FBDATA(dst_gc)->values_mask & GDK_GC_TILE)
+    gdk_pixmap_ref(GDK_GC_FBDATA(dst_gc)->values.tile);
+  if(GDK_GC_FBDATA(dst_gc)->values_mask & GDK_GC_STIPPLE)
+    gdk_pixmap_ref(GDK_GC_FBDATA(dst_gc)->values.stipple);
+  if(GDK_GC_FBDATA(dst_gc)->values_mask & GDK_GC_CLIP_MASK)
+    gdk_pixmap_ref(GDK_GC_FBDATA(dst_gc)->values.clip_mask);
+  if(GDK_GC_FBDATA(dst_gc)->clip_region)
+    GDK_GC_FBDATA(dst_gc)->clip_region = gdk_region_copy(GDK_GC_FBDATA(dst_gc)->clip_region);
+}
diff --git a/gdk/linux-fb/gdkgeometry-fb.c b/gdk/linux-fb/gdkgeometry-fb.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gdk/linux-fb/gdkglobals-fb.c b/gdk/linux-fb/gdkglobals-fb.c
new file mode 100644 (file)
index 0000000..220a4f6
--- /dev/null
@@ -0,0 +1,41 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include <stdio.h>
+
+#include "gdktypes.h"
+#include "gdkprivate-fb.h"
+#include "config.h"
+
+const gchar            *gdk_progclass = "none";
+gboolean          gdk_null_window_warnings = TRUE;
+
+GdkWindow *_gdk_fb_pointer_grab_window, *_gdk_fb_keyboard_grab_window, *_gdk_fb_pointer_grab_confine = NULL;
+GdkEventMask _gdk_fb_pointer_grab_events, _gdk_fb_keyboard_grab_events;
+
+GdkFBWindow *gdk_root_window = NULL;
+GdkFBDisplay *gdk_display = NULL;
+GdkCursor *_gdk_fb_pointer_grab_cursor;
diff --git a/gdk/linux-fb/gdkim-fb.c b/gdk/linux-fb/gdkim-fb.c
new file mode 100644 (file)
index 0000000..05da53f
--- /dev/null
@@ -0,0 +1,242 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "gdki18n.h"
+#include "gdkinternals.h"
+#include "gdkprivate-fb.h"
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#  if STDC_HEADERS
+#    include <string.h>
+#  endif
+#endif
+
+#include <locale.h>
+
+/* If this variable is FALSE, it indicates that we should
+ * avoid trying to use multibyte conversion functions and
+ * assume everything is 1-byte per character
+ */
+static gboolean gdk_use_mb;
+
+/*
+ *--------------------------------------------------------------
+ * gdk_set_locale
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gchar*
+gdk_set_locale (void)
+{
+  wchar_t result;
+  gchar *current_locale;
+
+  gdk_use_mb = FALSE;
+
+  if (!setlocale (LC_ALL,""))
+    g_warning ("locale not supported by C library");
+  
+  current_locale = setlocale (LC_ALL, NULL);
+
+  if ((strcmp (current_locale, "C")) && (strcmp (current_locale, "POSIX")))
+    {
+      gdk_use_mb = TRUE;
+
+#ifndef X_LOCALE
+      /* Detect GNU libc, where mb == UTF8. Not useful unless it's
+       * really a UTF8 locale. The below still probably will
+       * screw up on Greek, Cyrillic, etc, encoded as UTF8.
+       */
+      
+      if ((MB_CUR_MAX == 2) &&
+         (mbstowcs (&result, "\xdd\xa5", 1) > 0) &&
+         result == 0x765)
+       {
+         if ((strlen (current_locale) < 4) ||
+             g_strcasecmp (current_locale + strlen(current_locale) - 4, "utf8"))
+           gdk_use_mb = FALSE;
+       }
+#endif /* X_LOCALE */
+    }
+
+  GDK_NOTE (MISC,
+           g_message ("%s multi-byte string functions.", 
+                      gdk_use_mb ? "Using" : "Not using"));
+  
+  return current_locale;
+}
+
+void 
+gdk_im_begin (GdkIC *ic, GdkWindow* window)
+{
+}
+
+void 
+gdk_im_end (void)
+{
+}
+
+GdkIMStyle
+gdk_im_decide_style (GdkIMStyle supported_style)
+{
+  return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE;
+}
+
+GdkIMStyle
+gdk_im_set_best_style (GdkIMStyle style)
+{
+  return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE;
+}
+
+gint 
+gdk_im_ready (void)
+{
+  return FALSE;
+}
+
+gint
+gdk_im_open(void)
+{
+  return TRUE;
+}
+
+void
+gdk_im_close(void)
+{
+}
+
+GdkIC * 
+gdk_ic_new (GdkICAttr *attr, GdkICAttributesType mask)
+{
+  return NULL;
+}
+
+void 
+gdk_ic_destroy (GdkIC *ic)
+{
+}
+
+GdkIMStyle
+gdk_ic_get_style (GdkIC *ic)
+{
+  return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE;
+}
+
+void 
+gdk_ic_set_values (GdkIC *ic, ...)
+{
+}
+
+void 
+gdk_ic_get_values (GdkIC *ic, ...)
+{
+}
+
+GdkICAttributesType 
+gdk_ic_set_attr (GdkIC *ic, GdkICAttr *attr, GdkICAttributesType mask)
+{
+  return 0;
+}
+
+GdkICAttributesType 
+gdk_ic_get_attr (GdkIC *ic, GdkICAttr *attr, GdkICAttributesType mask)
+{
+  return 0;
+}
+
+GdkEventMask 
+gdk_ic_get_events (GdkIC *ic)
+{
+  return 0;
+}
+
+/*
+ * gdk_wcstombs 
+ *
+ * Returns a multi-byte string converted from the specified array
+ * of wide characters. The string is newly allocated. The array of
+ * wide characters must be null-terminated. If the conversion is
+ * failed, it returns NULL.
+ */
+gchar *
+gdk_wcstombs (const GdkWChar *src)
+{
+  gchar *mbstr;
+
+  gint length = 0;
+  gint i;
+
+  while (src[length] != 0)
+    length++;
+  
+  mbstr = g_new (gchar, length + 1);
+  
+  for (i=0; i<length+1; i++)
+    mbstr[i] = src[i];
+
+  return mbstr;
+}
+  
+/*
+ * gdk_mbstowcs
+ *
+ * Converts the specified string into wide characters, and, returns the
+ * number of wide characters written. The string 'src' must be
+ * null-terminated. If the conversion is failed, it returns -1.
+ */
+gint
+gdk_mbstowcs (GdkWChar *dest, const gchar *src, gint dest_max)
+{
+  gint i;
+  
+  for (i=0; i<dest_max && src[i]; i++)
+    dest[i] = src[i];
+
+  return i;
+}
+
+void
+gdk_ic_cleanup(void)
+{
+}
+
+GdkICAttr*   gdk_ic_attr_new       (void)
+{
+  return NULL;
+}
+
+void
+gdk_ic_attr_destroy   (GdkICAttr *attr)
+{
+}
diff --git a/gdk/linux-fb/gdkimage-fb.c b/gdk/linux-fb/gdkimage-fb.c
new file mode 100644 (file)
index 0000000..d47f287
--- /dev/null
@@ -0,0 +1,268 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include <config.h>
+
+
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include "gdk.h"
+#include "gdkimage.h"
+#include "gdkprivate.h"
+#include "gdkprivate-fb.h"
+
+struct _GdkImagePrivateFB
+{
+  GdkImagePrivate base;
+};
+
+static void gdk_fb_image_destroy (GdkImage    *image);
+static void gdk_image_put_normal  (GdkImage    *image,
+                                  GdkDrawable *drawable,
+                                  GdkGC       *gc,
+                                  gint         xsrc,
+                                  gint         ysrc,
+                                  gint         xdest,
+                                  gint         ydest,
+                                  gint         width,
+                                  gint         height);
+
+static GdkImageClass image_class_normal = {
+  gdk_fb_image_destroy,
+  gdk_image_put_normal
+};
+
+GdkImage *
+gdk_image_new_bitmap(GdkVisual *visual, gpointer data, gint w, gint h)
+{
+  GdkImage *image;
+  GdkImagePrivateFB *private;
+  
+  private = g_new(GdkImagePrivateFB, 1);
+  image = (GdkImage *) private;
+  private->base.ref_count = 1;
+  private->base.klass = &image_class_normal;
+  image->type = GDK_IMAGE_NORMAL;
+  image->visual = visual;
+  image->width = w;
+  image->height = h;
+  image->depth = 1;
+
+  image->byte_order = 1 /* MSBFirst */;
+  image->mem = g_malloc(w * h / 8);
+  image->bpp = 1;
+  image->bpl = (w+7)/8;
+
+  return image;
+}
+
+void
+gdk_image_init (void)
+{
+}
+
+GdkImage*
+gdk_image_new (GdkImageType  type,
+              GdkVisual    *visual,
+              gint          width,
+              gint          height)
+{
+  GdkImage *image;
+  GdkImagePrivateFB *private;
+
+  private = g_new (GdkImagePrivateFB, 1);
+  image = (GdkImage*) private;
+
+  private->base.ref_count = 1;
+  
+  image->type = 0;
+  image->visual = visual;
+  image->width = width;
+  image->height = height;
+  image->depth = visual->depth;
+  
+  private->base.klass = &image_class_normal;
+
+  if (image)
+    {
+      image->byte_order = 0;
+      image->mem = g_malloc(width * height * (image->depth >> 3));
+      image->bpp = image->depth;
+      image->bpl = (width * image->depth + 7)/8;
+    }
+
+  return image;
+}
+
+GdkImage*
+gdk_image_get (GdkWindow *window,
+              gint       x,
+              gint       y,
+              gint       width,
+              gint       height)
+{
+  GdkImage *image;
+  GdkImagePrivateFB *private;
+  gint bits_per_pixel = GDK_DRAWABLE_P(gdk_parent_root)->depth;
+  GdkDrawableFBData fbd;
+  GdkDrawablePrivate tmp_foo;
+
+  g_return_val_if_fail (window != NULL, NULL);
+
+  if (GDK_DRAWABLE_DESTROYED (window))
+    return NULL;
+
+  private = g_new (GdkImagePrivateFB, 1);
+  image = (GdkImage*) private;
+
+  private->base.ref_count = 1;
+  private->base.klass = &image_class_normal;
+
+  image->type = GDK_IMAGE_NORMAL;
+  image->visual = gdk_window_get_visual (window);
+  image->width = width;
+  image->height = height;
+  image->depth = bits_per_pixel;
+
+  if (bits_per_pixel <= 8)
+    image->bpp = 1;
+  else if (bits_per_pixel <= 16)
+    image->bpp = 2;
+  else if (bits_per_pixel <= 24)
+    image->bpp = 3;
+  else
+    image->bpp = 4;
+  image->byte_order = 1;
+  image->bpl = (image->width * image->bpp + 7)/8;
+  image->mem = g_malloc(image->bpl * image->height);
+  
+  /* Fake its existence as a pixmap */
+  memset(&tmp_foo, 0, sizeof(tmp_foo));
+  memset(&fbd, 0, sizeof(fbd));
+  tmp_foo.klass = &_gdk_fb_drawable_class;
+  tmp_foo.klass_data = &fbd;
+  fbd.mem = image->mem;
+  fbd.rowstride = image->bpl;
+  tmp_foo.width = fbd.lim_x = image->width;
+  tmp_foo.height = fbd.lim_y = image->height;
+  tmp_foo.depth = image->depth;
+
+  gdk_fb_draw_drawable((GdkPixmap *)&tmp_foo, NULL, window, x, y, 0, 0, width, height);
+
+  return image;
+}
+
+guint32
+gdk_image_get_pixel (GdkImage *image,
+                    gint x,
+                    gint y)
+{
+  GdkImagePrivateFB *private;
+
+  g_return_val_if_fail (image != NULL, 0);
+
+  private = (GdkImagePrivateFB *) image;
+
+  g_assert(image->depth == 8);
+
+  return ((guchar *)image->mem)[x + y * image->bpl];
+}
+
+void
+gdk_image_put_pixel (GdkImage *image,
+                    gint x,
+                    gint y,
+                    guint32 pixel)
+{
+  GdkImagePrivateFB *private;
+
+  g_return_if_fail (image != NULL);
+
+  private = (GdkImagePrivateFB *) image;
+  g_assert(image->depth == 8);
+
+  ((guchar *)image->mem)[x + y * image->bpl] = pixel;
+}
+
+static void
+gdk_fb_image_destroy (GdkImage *image)
+{
+  GdkImagePrivateFB *private;
+
+  g_return_if_fail (image != NULL);
+
+  private = (GdkImagePrivateFB*) image;
+
+  g_free(image->mem); image->mem = NULL;
+
+  g_free (image);
+}
+
+static void
+gdk_image_put_normal (GdkImage    *image,
+                     GdkDrawable *drawable,
+                     GdkGC       *gc,
+                     gint         xsrc,
+                     gint         ysrc,
+                     gint         xdest,
+                     gint         ydest,
+                     gint         width,
+                     gint         height)
+{
+  GdkImagePrivateFB *image_private;
+  GdkDrawableFBData fbd;
+  GdkDrawablePrivate tmp_foo;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (image != NULL);
+  g_return_if_fail (gc != NULL);
+
+  if (GDK_DRAWABLE_DESTROYED (drawable))
+    return;
+
+  image_private = (GdkImagePrivateFB*) image;
+
+  g_return_if_fail (image->type == GDK_IMAGE_NORMAL);
+
+  /* Fake its existence as a pixmap */
+  memset(&tmp_foo, 0, sizeof(tmp_foo));
+  memset(&fbd, 0, sizeof(fbd));
+  tmp_foo.klass = &_gdk_fb_drawable_class;
+  tmp_foo.klass_data = &fbd;
+  fbd.mem = image->mem;
+  fbd.rowstride = image->bpl;
+  tmp_foo.width = fbd.lim_x = image->width;
+  tmp_foo.height = fbd.lim_y = image->height;
+  tmp_foo.depth = image->depth;
+
+  gdk_fb_draw_drawable(drawable, gc, (GdkPixmap *)&tmp_foo, xsrc, ysrc, xdest, ydest, width, height);
+}
+
+void
+gdk_image_exit(void)
+{
+}
diff --git a/gdk/linux-fb/gdkinput-none.c b/gdk/linux-fb/gdkinput-none.c
new file mode 100644 (file)
index 0000000..d3aba3d
--- /dev/null
@@ -0,0 +1,79 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gdkinputprivate.h"
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+static void gdk_input_none_get_pointer (GdkWindow       *window,
+                                       guint32   deviceid,
+                                       gdouble         *x,
+                                       gdouble         *y,
+                                       gdouble         *pressure,
+                                       gdouble         *xtilt,
+                                       gdouble         *ytilt,
+                                       GdkModifierType *mask);
+
+void
+gdk_input_init (void)
+{
+  gdk_input_vtable.set_mode           = NULL;
+  gdk_input_vtable.set_axes           = NULL;
+  gdk_input_vtable.set_key            = NULL;
+  gdk_input_vtable.motion_events      = NULL;
+  gdk_input_vtable.get_pointer        = gdk_input_none_get_pointer;
+  gdk_input_vtable.grab_pointer       = NULL;
+  gdk_input_vtable.ungrab_pointer     = NULL;
+  gdk_input_vtable.configure_event    = NULL;
+  gdk_input_vtable.enter_event        = NULL;
+  gdk_input_vtable.other_event        = NULL;
+  gdk_input_vtable.window_none_event  = NULL;
+  gdk_input_vtable.enable_window      = NULL;
+  gdk_input_vtable.disable_window     = NULL;
+
+  gdk_input_devices = g_list_append (NULL, (GdkDeviceInfo *) &gdk_input_core_info);
+
+  gdk_input_ignore_core = FALSE;
+}
+
+static void
+gdk_input_none_get_pointer (GdkWindow       *window,
+                           guint32          deviceid,
+                           gdouble         *x,
+                           gdouble         *y,
+                           gdouble         *pressure,
+                           gdouble         *xtilt,
+                           gdouble         *ytilt,
+                           GdkModifierType *mask)
+{
+  gint x_int, y_int;
+
+  gdk_window_get_pointer (window, &x_int, &y_int, mask);
+
+  if (x) *x = x_int;
+  if (y) *y = y_int;
+  if (pressure) *pressure = 0.5;
+  if (xtilt) *xtilt = 0;
+  if (ytilt) *ytilt = 0;
+}
diff --git a/gdk/linux-fb/gdkinput-ps2.c b/gdk/linux-fb/gdkinput-ps2.c
new file mode 100644 (file)
index 0000000..0db7456
--- /dev/null
@@ -0,0 +1,1096 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gdk/gdk.h>
+#include <gdk/gdkinternals.h>
+#include "gdkinputprivate.h"
+#include "gdkkeysyms.h"
+#include "gdkprivate-fb.h"
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <time.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/vt.h>
+#include <sys/kd.h>
+#include <ctype.h>
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+typedef struct {
+  gint fd, fd_tag;
+
+  gint x, y;
+  GdkWindow *prev_window;
+  gboolean button1_pressed, button2_pressed, button3_pressed;
+  gboolean click_grab;
+} PS2Mouse;
+
+typedef struct {
+  gint fd, fd_tag, consfd;
+
+  int vtnum, prev_vtnum;
+  guchar states[256];
+  gboolean is_ext : 1;
+  gboolean caps_lock : 1;
+} Keyboard;
+
+static void gdk_input_ps2_get_pointer (GdkWindow       *window,
+                                      guint32    deviceid,
+                                      gdouble         *x,
+                                      gdouble         *y,
+                                      gdouble         *pressure,
+                                      gdouble         *xtilt,
+                                      gdouble         *ytilt,
+                                      GdkModifierType *mask);
+static Keyboard * tty_keyboard_open(void);
+static guint keyboard_get_state(Keyboard *k);
+
+static PS2Mouse *ps2mouse = NULL;
+static Keyboard *keyboard = NULL;
+FILE *debug_out;
+
+static guint multiclick_tag;
+static GdkEvent *multiclick_event = NULL;
+
+static gboolean
+click_event_timeout(gpointer x)
+{
+  switch(multiclick_event->type)
+    {
+    case GDK_BUTTON_RELEASE:
+      gdk_event_free(multiclick_event);
+      break;
+    case GDK_2BUTTON_PRESS:
+    case GDK_3BUTTON_PRESS:
+      gdk_event_queue_append(multiclick_event);
+      break;
+    default:
+      break;
+    }
+
+  multiclick_event = NULL;
+  multiclick_tag = 0;
+
+  return FALSE;
+}
+
+static void
+send_button_event(PS2Mouse *mouse, guint button, gboolean press_event, time_t the_time)
+{
+  GdkEvent *event;
+  gint x, y;
+  GdkWindow *window;
+  int nbuttons = 0;
+
+  if(_gdk_fb_pointer_grab_window)
+    window = _gdk_fb_pointer_grab_window;
+  else
+    window = gdk_window_get_pointer(NULL, NULL, NULL, NULL);
+
+  gdk_window_get_origin(window, &x, &y);
+  x = mouse->x - x;
+  y = mouse->y - y;
+
+  if(!press_event
+     && multiclick_event
+     && multiclick_event->button.button == button
+     && multiclick_event->button.window == window
+     && ABS(multiclick_event->button.x - x) < 3
+     && ABS(multiclick_event->button.y - y) < 3)
+    {
+      multiclick_event->button.time = the_time;
+
+      /* Just change multiclick_event into a different event */
+      switch(multiclick_event->button.type)
+       {
+       default:
+         g_assert_not_reached();
+
+       case GDK_BUTTON_RELEASE:
+         multiclick_event->button.type = GDK_2BUTTON_PRESS;
+         return;
+
+       case GDK_2BUTTON_PRESS:
+         multiclick_event->button.type = GDK_3BUTTON_PRESS;
+         return;
+
+       case GDK_3BUTTON_PRESS:
+         gdk_event_queue_append(multiclick_event); multiclick_event = NULL;
+         g_source_remove(multiclick_tag); multiclick_tag = 0;
+       }
+    }
+
+  event = gdk_event_make(window, press_event?GDK_BUTTON_PRESS:GDK_BUTTON_RELEASE, FALSE);
+
+  if(!event)
+    return;
+
+  event->button.x = x;
+  event->button.y = y;
+  event->button.button = button;
+  event->button.pressure = 0.5;
+  event->button.xtilt = event->button.ytilt = 0;
+  event->button.state = (mouse->button1_pressed?GDK_BUTTON1_MASK:0)
+    | (mouse->button2_pressed?GDK_BUTTON2_MASK:0)
+    | (mouse->button3_pressed?GDK_BUTTON3_MASK:0)
+    | (1 << (button + 8)) /* badhack */
+    | keyboard_get_state(keyboard);
+  event->button.source = GDK_SOURCE_MOUSE;
+  event->button.deviceid = 0;
+  event->button.x_root = mouse->x;
+  event->button.y_root = mouse->y;
+
+  if(mouse->button1_pressed)
+    nbuttons++;
+  if(mouse->button2_pressed)
+    nbuttons++;
+  if(mouse->button3_pressed)
+    nbuttons++;
+
+  if(press_event && nbuttons == 1 && !_gdk_fb_pointer_grab_window)
+    {
+      gdk_pointer_grab(window, FALSE, gdk_window_get_events(window), NULL, NULL, GDK_CURRENT_TIME);
+      mouse->click_grab = TRUE;
+    }
+  else if(!press_event && nbuttons == 0 && mouse->click_grab)
+    {
+      gdk_pointer_ungrab(GDK_CURRENT_TIME);
+      mouse->click_grab = FALSE;
+    }
+
+#if 0
+  g_message("Button #%d %s [%d, %d] in %p", button, press_event?"pressed":"released",
+           x, y, window);
+
+  /* Debugging aid */
+  if(window && window != gdk_parent_root)
+    {
+      GdkGC *tmp_gc;
+
+      tmp_gc = gdk_gc_new(window);
+      GDK_GC_FBDATA(tmp_gc)->values.foreground.pixel = 0;
+      gdk_fb_draw_rectangle(window, tmp_gc, TRUE, 0, 0,
+                           GDK_DRAWABLE_P(window)->width, GDK_DRAWABLE_P(window)->height);
+      gdk_gc_unref(tmp_gc);
+    }
+#endif
+
+  if(!press_event && !multiclick_tag)
+    {
+      multiclick_tag = g_timeout_add(250, click_event_timeout, NULL);
+      multiclick_event = gdk_event_copy(event);
+    }
+
+  gdk_event_queue_append(event);
+}
+
+static GdkPixmap *last_contents = NULL;
+static GdkPoint last_location;
+static GdkCursor *last_cursor = NULL;
+static GdkGC *cursor_gc;
+
+void
+gdk_fb_cursor_hide(void)
+{
+  if(last_contents)
+    {
+      gdk_gc_set_clip_mask(cursor_gc, NULL);
+      /* Restore old picture */
+      gdk_fb_draw_drawable_2(gdk_parent_root, cursor_gc, last_contents, 0, 0, last_location.x, last_location.y,
+                            GDK_DRAWABLE_P(last_contents)->width,
+                            GDK_DRAWABLE_P(last_contents)->height, TRUE, FALSE);
+    }
+}
+
+void
+gdk_fb_cursor_invalidate(void)
+{
+  gdk_pixmap_unref(last_contents);
+  last_contents = NULL;
+}
+
+void
+gdk_fb_cursor_unhide(void)
+{
+  if(last_cursor)
+    {
+      if(!last_contents
+        || GDK_DRAWABLE_P(GDK_CURSOR_FB(last_cursor)->cursor)->width != GDK_DRAWABLE_P(last_contents)->width
+        || GDK_DRAWABLE_P(GDK_CURSOR_FB(last_cursor)->cursor)->height != GDK_DRAWABLE_P(last_contents)->height)
+       {
+         if(last_contents)
+           gdk_pixmap_unref(last_contents);
+
+         last_contents = gdk_pixmap_new(gdk_parent_root,
+                                        GDK_DRAWABLE_P(GDK_CURSOR_FB(last_cursor)->cursor)->width,
+                                        GDK_DRAWABLE_P(GDK_CURSOR_FB(last_cursor)->cursor)->height,
+                                        GDK_DRAWABLE_P(gdk_parent_root)->depth);
+       }
+
+      gdk_gc_set_clip_mask(cursor_gc, NULL);
+      gdk_fb_draw_drawable_2(last_contents, cursor_gc, gdk_parent_root, last_location.x, last_location.y, 0, 0,
+                            GDK_DRAWABLE_P(GDK_CURSOR_FB(last_cursor)->cursor)->width,
+                            GDK_DRAWABLE_P(GDK_CURSOR_FB(last_cursor)->cursor)->height, TRUE, FALSE);
+      gdk_gc_set_clip_mask(cursor_gc, GDK_CURSOR_FB(last_cursor)->mask);
+      gdk_gc_set_clip_origin(cursor_gc, last_location.x, last_location.y);
+      gdk_fb_draw_drawable_2(gdk_parent_root, cursor_gc, GDK_CURSOR_FB(last_cursor)->cursor,
+                            0, 0, last_location.x, last_location.y,
+                            GDK_DRAWABLE_P(GDK_CURSOR_FB(last_cursor)->cursor)->width,
+                            GDK_DRAWABLE_P(GDK_CURSOR_FB(last_cursor)->cursor)->height, TRUE, FALSE);
+    }
+  else
+    gdk_fb_cursor_invalidate();
+}
+
+void
+gdk_fb_get_cursor_rect(GdkRectangle *rect)
+{
+  if(last_cursor)
+    {
+      rect->x = last_location.x;
+      rect->y = last_location.y;
+      rect->width = GDK_DRAWABLE_P(GDK_CURSOR_FB(last_cursor)->cursor)->width;
+      rect->height = GDK_DRAWABLE_P(GDK_CURSOR_FB(last_cursor)->cursor)->height;
+    }
+  else
+    {
+      rect->x = rect->y = -1;
+      rect->width = rect->height = 0;
+    }
+}
+
+static void
+move_pointer(PS2Mouse *mouse, GdkWindow *in_window)
+{
+  GdkCursor *the_cursor;
+
+  if(!cursor_gc)
+    {
+      GdkColor white, black;
+      cursor_gc = gdk_gc_new(gdk_parent_root);
+      gdk_color_black(gdk_colormap_get_system(), &black);
+      gdk_color_white(gdk_colormap_get_system(), &white);
+      gdk_gc_set_foreground(cursor_gc, &black);
+      gdk_gc_set_background(cursor_gc, &white);
+    }
+
+  gdk_fb_cursor_hide();
+
+  last_location.x = mouse->x;
+  last_location.y = mouse->y;
+
+  if(_gdk_fb_pointer_grab_cursor)
+    the_cursor = _gdk_fb_pointer_grab_cursor;
+  else
+    {
+      while(!GDK_WINDOW_FBDATA(in_window)->cursor && GDK_WINDOW_P(in_window)->parent)
+       in_window = GDK_WINDOW_P(in_window)->parent;
+      the_cursor = GDK_WINDOW_FBDATA(in_window)->cursor;
+    }
+
+  if(the_cursor)
+    gdk_cursor_ref(the_cursor);
+  if(last_cursor)
+    gdk_cursor_unref(last_cursor);
+  last_cursor = the_cursor;
+
+  gdk_fb_cursor_unhide();
+}
+
+static gboolean
+handle_input(GIOChannel *gioc, GIOCondition cond, gpointer data)
+{
+  guchar buf[3];
+  int n, left, dx=0, dy=0;
+  PS2Mouse *mouse = data;
+  gboolean new_button1, new_button2, new_button3;
+  time_t the_time = g_latest_time.tv_sec;
+  GdkWindow *mousewin;
+
+  for(left = sizeof(buf); left > 0; )
+    {
+      n = read(mouse->fd, buf+sizeof(buf)-left, left);
+      g_assert(n > 0);
+      left -= n;
+    }
+
+  new_button1 = (buf[0] & 1) && 1;
+  new_button3 = (buf[0] & 2) && 1;
+  new_button2 = (buf[0] & 4) && 1;
+
+  if(new_button1 != mouse->button1_pressed)
+    {
+      mouse->button1_pressed = new_button1; 
+      send_button_event(mouse, 1, new_button1, the_time);
+    }
+
+  if(new_button2 != mouse->button2_pressed)
+    {
+      mouse->button2_pressed = new_button2;
+      send_button_event(mouse, 2, new_button2, the_time);
+    }
+
+  if(new_button3 != mouse->button3_pressed)
+    {
+      mouse->button3_pressed = new_button3; 
+      send_button_event(mouse, 3, new_button3, the_time);
+    }
+
+  if(buf[1] != 0)
+    dx =  ((buf[0] & 0x10) ? ((gint)buf[1])-256 : buf[1]);
+  else
+    dx = 0;
+  if(buf[2] != 0)
+    dy = -((buf[0] & 0x20) ? ((gint)buf[2])-256 : buf[2]);
+  else
+    dy = 0;
+
+  mouse->x += dx;
+  mouse->y += dy;
+  if(_gdk_fb_pointer_grab_confine)
+    mousewin = _gdk_fb_pointer_grab_confine;
+  else
+    mousewin = gdk_parent_root;
+
+  if(mouse->x < 0)
+    mouse->x = 0;
+  else if(mouse->x > (GDK_DRAWABLE_FBDATA(mousewin)->lim_x - 1))
+    mouse->x = GDK_DRAWABLE_FBDATA(mousewin)->lim_x - 1;
+  if(mouse->y < 0)
+    mouse->y = 0;
+  else if(mouse->y > (GDK_DRAWABLE_FBDATA(mousewin)->lim_y - 1))
+    mouse->y = GDK_DRAWABLE_FBDATA(mousewin)->lim_y - 1;
+
+  if(dx || dy) {
+    GdkEvent *event;
+    gint x, y, rx, ry;
+    GdkWindow *win;
+    guint state;
+
+    win = gdk_window_get_pointer(NULL, NULL, NULL, NULL);
+    move_pointer(mouse, win);
+    if(_gdk_fb_pointer_grab_window)
+      win = _gdk_fb_pointer_grab_window;
+
+    gdk_window_get_origin(win, &x, &y);
+    x = mouse->x - x;
+    y = mouse->y - y;
+
+
+    state = (mouse->button1_pressed?GDK_BUTTON1_MASK:0)
+      | (mouse->button2_pressed?GDK_BUTTON2_MASK:0)
+      | (mouse->button3_pressed?GDK_BUTTON3_MASK:0)
+      | keyboard_get_state(keyboard);
+
+    event = gdk_event_make (win, GDK_MOTION_NOTIFY, TRUE);
+    if(event)
+      {
+       event->motion.x = x;
+       event->motion.y = y;
+       event->motion.pressure = 0.5;
+       event->motion.xtilt = event->motion.ytilt = 0;
+       event->motion.state = state;
+       event->motion.is_hint = FALSE;
+       event->motion.source = GDK_SOURCE_MOUSE;
+       event->motion.deviceid = 0;
+       event->motion.x_root = mouse->x;
+       event->motion.y_root = mouse->y;
+      }
+
+    if(win != mouse->prev_window)
+      {
+       GdkEvent *evel;
+
+       if(mouse->prev_window && (evel = gdk_event_make(mouse->prev_window, GDK_LEAVE_NOTIFY, TRUE)))
+         {
+           evel->crossing.subwindow = gdk_window_ref(win);
+           evel->crossing.x = x;
+           evel->crossing.y = y;
+           evel->crossing.x_root = mouse->x;
+           evel->crossing.y_root = mouse->y;
+           evel->crossing.mode = GDK_CROSSING_NORMAL;
+           evel->crossing.detail = GDK_NOTIFY_UNKNOWN;
+           evel->crossing.focus = FALSE;
+           evel->crossing.state = state;
+         }
+
+       evel = gdk_event_make(win, GDK_ENTER_NOTIFY, TRUE);
+       if(evel)
+         {
+           evel->crossing.subwindow = gdk_window_ref(mouse->prev_window?mouse->prev_window:gdk_parent_root);
+           evel->crossing.x = x;
+           evel->crossing.y = y;
+           evel->crossing.x_root = mouse->x;
+           evel->crossing.y_root = mouse->y;
+           evel->crossing.mode = GDK_CROSSING_NORMAL;
+           evel->crossing.detail = GDK_NOTIFY_UNKNOWN;
+           evel->crossing.focus = FALSE;
+           evel->crossing.state = state;
+         }
+
+       if(mouse->prev_window)
+         gdk_window_unref(mouse->prev_window);
+       mouse->prev_window = gdk_window_ref(win);
+      }
+  }
+
+  return TRUE;
+}
+
+static PS2Mouse *
+mouse_open(void)
+{
+  PS2Mouse *retval = g_new0(PS2Mouse, 1);
+  guchar buf[7];
+  int i = 0;
+  GIOChannel *gioc;
+
+  retval->fd = open("/dev/psaux", O_RDWR);
+  if(retval->fd < 0)
+    {
+      g_free(retval);
+      return NULL;
+    }
+
+  /* From xf86_Mouse.c */
+  buf[i++] = 230; /* 1:1 scaling */
+  buf[i++] = 244; /* enable mouse */
+  buf[i++] = 243; /* Sample rate */
+  buf[i++] = 200;
+  buf[i++] = 232; /* device resolution */
+  buf[i++] = 1;
+  write(retval->fd, buf, i);
+  read(retval->fd, buf, 3); /* Get rid of misc garbage whatever stuff from mouse */
+
+  gioc = g_io_channel_unix_new(retval->fd);
+  retval->fd_tag = g_io_add_watch(gioc, G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL, handle_input, retval);
+
+  retval->x = gdk_display->modeinfo.xres >> 1;
+  retval->y = gdk_display->modeinfo.yres >> 1;
+
+  return retval;
+}
+
+void
+gdk_input_init (void)
+{
+  gdk_input_vtable.set_mode           = NULL;
+  gdk_input_vtable.set_axes           = NULL;
+  gdk_input_vtable.set_key            = NULL;
+  gdk_input_vtable.motion_events      = NULL;
+  gdk_input_vtable.get_pointer        = gdk_input_ps2_get_pointer;
+  gdk_input_vtable.grab_pointer       = NULL;
+  gdk_input_vtable.ungrab_pointer     = NULL;
+  gdk_input_vtable.configure_event    = NULL;
+  gdk_input_vtable.enter_event        = NULL;
+  gdk_input_vtable.other_event        = NULL;
+  gdk_input_vtable.window_none_event  = NULL;
+  gdk_input_vtable.enable_window      = NULL;
+  gdk_input_vtable.disable_window     = NULL;
+
+  gdk_input_devices = g_list_append (NULL, (GdkDeviceInfo *) &gdk_input_core_info);
+
+  gdk_input_ignore_core = FALSE;
+
+  ps2mouse = mouse_open();
+}
+
+void
+gdk_input_ps2_get_mouseinfo(gint *x, gint *y, GdkModifierType *mask)
+{
+  *x = ps2mouse->x;
+  *y = ps2mouse->y;
+  *mask =
+    (ps2mouse->button1_pressed?GDK_BUTTON1_MASK:0)
+    | (ps2mouse->button2_pressed?GDK_BUTTON2_MASK:0)
+    | (ps2mouse->button3_pressed?GDK_BUTTON3_MASK:0)
+    | keyboard_get_state(keyboard);
+}
+
+static void
+gdk_input_ps2_get_pointer (GdkWindow       *window,
+                          guint32          deviceid,
+                          gdouble         *x,
+                          gdouble         *y,
+                          gdouble         *pressure,
+                          gdouble         *xtilt,
+                          gdouble         *ytilt,
+                          GdkModifierType *mask)
+{
+  gint x_int, y_int;
+
+  gdk_window_get_root_origin(window, &x_int, &y_int);
+
+  if (x) *x = ps2mouse->x - x_int;
+  if (y) *y = ps2mouse->y - y_int;
+  if (pressure) *pressure = 0.5;
+  if (xtilt) *xtilt = 0;
+  if (ytilt) *ytilt = 0;
+}
+
+/* Returns the modifier mask for the keyboard */
+static guint
+keyboard_get_state(Keyboard *k)
+{
+  guint retval = 0;
+  struct {
+    guchar from;
+    guint to;
+  } statetrans[] = {
+    {0x1D, GDK_CONTROL_MASK},
+    {0x9D, GDK_CONTROL_MASK},
+    {0x38, GDK_MOD1_MASK},
+    {0xB8, GDK_MOD1_MASK},
+    {0x2A, GDK_SHIFT_MASK},
+    {0x36, GDK_SHIFT_MASK}
+  };
+  int i;
+
+  for(i = 0; i < sizeof(statetrans)/sizeof(statetrans[0]); i++)
+    if(k->states[statetrans[i].from])
+      retval |= statetrans[i].to;
+
+  return retval;
+}
+
+static GdkWindow *
+gdk_window_find_focus(void)
+{
+  if(_gdk_fb_keyboard_grab_window)
+    return _gdk_fb_keyboard_grab_window;
+  else if(GDK_WINDOW_P(gdk_parent_root)->children)
+    return GDK_WINDOW_P(gdk_parent_root)->children->data;
+  else
+    return gdk_parent_root;
+}
+
+static gboolean
+handle_keyboard_input(GIOChannel *gioc, GIOCondition cond, gpointer data)
+{
+  guchar buf[128];
+  int i, n;
+  Keyboard *k = data;
+  time_t now;
+
+  n = read(k->fd, buf, sizeof(buf));
+  if(n <= 0)
+    g_error("Nothing from keyboard!");
+
+  /* Now turn this into a keyboard event */
+  now = g_latest_time.tv_sec;
+
+  for(i = 0; i < n; i++)
+    {
+      guchar base_char;
+      static const guint trans_table[256][3] = {
+       /* 0x00 */
+       {0, 0, 0},
+       {GDK_Escape, 0, 0},
+       {'1', '!', 0},
+       {'2', '@', 0},
+       {'3', '#', 0},
+       {'4', '$', 0},
+       {'5', '%', 0},
+       {'6', '^', 0},
+       {'7', '&', 0},
+       {'8', '*', 0},
+       {'9', '(', 0},
+       {'0', ')', 0},
+       {'-', '_', 0},
+       {'=', '+', 0},
+       {GDK_BackSpace, 0, 0},
+       {GDK_Tab, 0, 0},
+       /* 0x10 */
+       {'q', 'Q', 0},
+       {'w', 'W', 0},
+       {'e', 'E', 0},
+       {'r', 'R', 0},
+       {'t', 'T', 0},
+       {'y', 'Y', 0},
+       {'u', 'U', 0},
+       {'i', 'I', 0},
+       {'o', 'O', 0},
+       {'p', 'P', 0},
+       {'[', '{', 0},
+       {']', '}', 0},
+       {GDK_Return, 0, 0},
+       {GDK_Control_L, 0, 0}, /* mod */
+       {'a', 'A', 0},
+       {'s', 'S', 0},
+
+       /* 0x20 */
+       {'d', 'D', 0},
+       {'f', 'F', 0},
+       {'g', 'G', 0},
+       {'h', 'H', 0},
+       {'j', 'J', 0},
+       {'k', 'K', 0},
+       {'l', 'L', 0},
+       {';', ':', 0},
+       {'\'', '"', 0},
+       {'`', '~', 0},
+       {0, 0, 0},
+       {GDK_Shift_L, 0, 0}, /* mod */
+       {'\\', 0, 0},
+       {'z', 0, 0},
+       {'x', 0, 0},
+       {'c', 0, 0},
+
+       /* 0x30 */
+       {'v', 'V', 0},
+       {'b', 'B', 0},
+       {'n', 'N', 0},
+       {'m', 'M', 0},
+       {',', 0, 0},
+       {'.', 0, 0},
+       {'/', 0, 0},
+       {GDK_Shift_R, 0, 0}, /* mod */
+       {GDK_KP_Multiply, 0, 0},
+       {' ', 0, 0},
+       {0, 0, 0},
+       {GDK_F1, 0, 0},
+       {GDK_F2, 0, 0},
+       {GDK_F3, 0, 0},
+       {GDK_F4, 0, 0},
+       {GDK_F5, 0, 0},
+
+       /* 0x40 */
+       {GDK_F6, 0, 0},
+       {GDK_F7, 0, 0},
+       {GDK_F8, 0, 0},
+       {GDK_F9, 0, 0},
+       {GDK_F10, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+
+       /* 0x50 */
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {GDK_F11, 0, 0},
+       {GDK_F12, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+
+       /* 0x60 */
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+
+       /* 0x70 */
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+
+       /* 0x80 */
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+
+       /* 0x90 */
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+
+       /* 0xA0 */
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+
+       /* 0xB0 */
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+
+       /* 0xC0 */
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {GDK_Up, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {GDK_Left, 0, 0},
+       {GDK_Right, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+
+       /* 0xD0 */
+       {GDK_Down, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+
+       /* 0xE0 */
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+
+       /* 0xF0 */
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+       {0, 0, 0},
+      };
+      GdkEvent *event;
+      GdkWindow *win;
+      char dummy[2];
+      int mod;
+      guint keyval, state;
+
+      if(buf[i] == 0xE0 || k->is_ext) /* extended char */
+       {
+         int l;
+
+         l = k->is_ext?0:1;
+         k->is_ext = TRUE;
+
+         if((i+l) >= n)
+           continue;
+
+         if(buf[i+l] == 0x2A
+            || buf[i+l] == 0xAA)
+           {
+             i++;
+             continue;
+           }
+
+         base_char = 0x80 + (buf[i+l] & 0x7F);
+         k->is_ext = FALSE;
+         i += l;
+       }
+      else
+       base_char = buf[i] & 0x7F;
+
+      if(base_char > sizeof(trans_table)/sizeof(trans_table[0]))
+       continue;
+
+      {
+       gboolean new_state = (buf[i] & 0x80)?FALSE:TRUE;
+
+       k->states[base_char] = new_state;
+      }
+
+      if((base_char == 0x1D) /* left Ctrl */
+        || (base_char == 0x9D) /* right Ctrl */
+        || (base_char == 0x38) /* left Alt */
+        || (base_char == 0xB8) /* right Alt */
+        || (base_char == 0x2A) /* left Shift */
+        || (base_char == 0x36) /* right Shift */)
+       {
+         continue; /* Don't generate events for modifiers */
+       }
+
+      if(base_char == 0x3A /* Caps lock */)
+       {
+         if(k->states[base_char])
+           k->caps_lock = !k->caps_lock;
+         ioctl(k->fd, KDSETLED, k->caps_lock?LED_CAP:0);
+
+         continue;
+       }
+
+      if(trans_table[base_char][0] >= GDK_F1
+        && trans_table[base_char][0] <= GDK_F35
+        && (keyboard_get_state(k) & GDK_MOD1_MASK))
+       {
+         if(!k->states[base_char]) /* Only switch on release */
+           {
+             gint vtnum = trans_table[base_char][0] - GDK_F1 + 1;
+
+             fprintf(debug_out, "Switching VTs\n");
+
+             /* Do the whole funky VT switch thing */
+             ioctl(k->consfd, VT_ACTIVATE, vtnum);
+             ioctl(k->consfd, VT_WAITACTIVE, k->vtnum);
+             gdk_fb_redraw_all();
+           }
+
+         continue;
+       }
+
+      keyval = 0;
+      state = keyboard_get_state(k);
+      mod = 0;
+      if(state & GDK_CONTROL_MASK)
+       mod = 2;
+      else if(state & GDK_SHIFT_MASK)
+       mod = 1;
+      do {
+       keyval = trans_table[base_char][mod--];
+      } while(!keyval && (mod > 0));
+
+      if(k->caps_lock && (keyval >= 'a')
+        && (keyval <= 'z'))
+       keyval = toupper(keyval);
+
+      win = gdk_window_find_focus();
+      event = gdk_event_make(win, k->states[base_char]?GDK_KEY_PRESS:GDK_KEY_RELEASE, TRUE);
+      if(event)
+       {
+         /* Find focused window */
+         event->key.time = now;
+         event->key.state = state;
+         event->key.keyval = keyval;
+         event->key.length = isprint(event->key.keyval)?1:0;
+         dummy[0] = event->key.keyval;
+         dummy[1] = 0;
+         event->key.string = event->key.length?g_strdup(dummy):NULL;
+       }
+    }
+
+  return TRUE;
+}
+
+static Keyboard *
+tty_keyboard_open(void)
+{
+  Keyboard *retval = g_new0(Keyboard, 1);
+  GIOChannel *gioc;
+  const char cursoroff_str[] = "\033[?1;0;0c";
+  int n;
+  struct vt_stat vs;
+  char buf[32];
+  struct termios ts;
+
+  setsid();
+  retval->consfd = open("/dev/console", O_RDWR);
+  ioctl(retval->consfd, VT_GETSTATE, &vs);
+  retval->prev_vtnum = vs.v_active;
+  g_snprintf(buf, sizeof(buf), "/dev/tty%d", retval->prev_vtnum);
+  ioctl(retval->consfd, KDSKBMODE, K_XLATE);
+
+  n = ioctl(retval->consfd, VT_OPENQRY, &retval->vtnum);
+  if(n < 0 || retval->vtnum == -1)
+    g_error("Cannot allocate VT");
+
+  ioctl(retval->consfd, VT_ACTIVATE, retval->vtnum);
+  ioctl(retval->consfd, VT_WAITACTIVE, retval->vtnum);
+
+  debug_out = fdopen(dup(2), "w");
+
+#if 0
+  close(0);
+  close(1);
+  close(2);
+#endif
+  g_snprintf(buf, sizeof(buf), "/dev/tty%d", retval->vtnum);
+  retval->fd = open(buf, O_RDWR|O_NONBLOCK);
+  if(retval->fd < 0)
+    return NULL;
+  if(ioctl(retval->fd, KDSKBMODE, K_RAW) < 0)
+    g_warning("K_RAW failed");
+
+  ioctl(0, TIOCNOTTY, 0);
+  ioctl(retval->fd, TIOCSCTTY, 0);
+  tcgetattr(retval->fd, &ts);
+  ts.c_cc[VTIME] = 0;
+  ts.c_cc[VMIN] = 1;
+  ts.c_lflag &= ~(ICANON|ECHO|ISIG);
+  ts.c_iflag = 0;
+  tcsetattr(retval->fd, TCSAFLUSH, &ts);
+
+  tcsetpgrp(retval->fd, getpgrp());
+
+  write(retval->fd, cursoroff_str, strlen(cursoroff_str));
+
+#if 0
+  if(retval->fd != 0)
+    dup2(retval->fd, 0);
+  if(retval->fd != 1)
+    dup2(retval->fd, 1);
+  if(retval->fd != 2)
+    dup2(retval->fd, 2);
+#endif
+
+  gioc = g_io_channel_unix_new(retval->fd);
+  retval->fd_tag = g_io_add_watch(gioc, G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL, handle_keyboard_input, retval);
+
+  return retval;
+}
+
+void
+keyboard_init(void)
+{
+  keyboard = tty_keyboard_open();
+}
+
+void
+keyboard_shutdown(void)
+{
+  int tmpfd;
+
+  ioctl(keyboard->fd, KDSKBMODE, K_XLATE);
+  close(keyboard->fd);
+  g_source_remove(keyboard->fd_tag);
+
+  tmpfd = keyboard->consfd;
+  ioctl(tmpfd, VT_ACTIVATE, keyboard->prev_vtnum);
+  ioctl(tmpfd, VT_WAITACTIVE, keyboard->prev_vtnum);
+  ioctl(tmpfd, VT_DISALLOCATE, keyboard->vtnum);
+  close(tmpfd);
+
+  g_free(keyboard);
+  keyboard = NULL;
+}
diff --git a/gdk/linux-fb/gdkinput.c b/gdk/linux-fb/gdkinput.c
new file mode 100644 (file)
index 0000000..2013ea0
--- /dev/null
@@ -0,0 +1,290 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include <stdlib.h>
+#include "config.h"
+
+#include "gdkfb.h"
+#include "gdkinput.h"
+#include "gdkprivate.h"
+#include "gdkinputprivate.h"
+
+static const GdkAxisUse gdk_input_core_axes[] = { GDK_AXIS_X, GDK_AXIS_Y };
+
+const GdkDeviceInfo gdk_input_core_info =
+{
+  GDK_CORE_POINTER,
+  "Core Pointer",
+  GDK_SOURCE_MOUSE,
+  GDK_MODE_SCREEN,
+  TRUE,
+  2,
+  gdk_input_core_axes
+};
+
+/* Global variables  */
+
+GdkInputVTable    gdk_input_vtable;
+/* information about network port and host for gxid daemon */
+gchar            *gdk_input_gxid_host;
+gint              gdk_input_gxid_port;
+gint              gdk_input_ignore_core;
+
+GList            *gdk_input_devices;
+GList            *gdk_input_windows;
+
+GList *
+gdk_input_list_devices (void)
+{
+  return gdk_input_devices;
+}
+
+void
+gdk_input_set_source (guint32 deviceid, GdkInputSource source)
+{
+  GdkDevicePrivate *gdkdev = gdk_input_find_device(deviceid);
+  g_return_if_fail (gdkdev != NULL);
+
+  gdkdev->info.source = source;
+}
+
+gint
+gdk_input_set_mode (guint32 deviceid, GdkInputMode mode)
+{
+  if (deviceid == GDK_CORE_POINTER)
+    return FALSE;
+
+  if (gdk_input_vtable.set_mode)
+    return gdk_input_vtable.set_mode(deviceid,mode);
+  else
+    return FALSE;
+}
+
+void
+gdk_input_set_axes (guint32 deviceid, GdkAxisUse *axes)
+{
+  if (deviceid != GDK_CORE_POINTER && gdk_input_vtable.set_axes)
+    gdk_input_vtable.set_axes (deviceid, axes);
+}
+
+void gdk_input_set_key (guint32 deviceid,
+                       guint   index,
+                       guint   keyval,
+                       GdkModifierType modifiers)
+{
+  if (deviceid != GDK_CORE_POINTER && gdk_input_vtable.set_key)
+    gdk_input_vtable.set_key (deviceid, index, keyval, modifiers);
+}
+
+GdkTimeCoord *
+gdk_input_motion_events (GdkWindow *window,
+                        guint32 deviceid,
+                        guint32 start,
+                        guint32 stop,
+                        gint *nevents_return)
+{
+  g_return_val_if_fail (window != NULL, NULL);
+  g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
+
+  *nevents_return = 0;
+  return NULL;
+}
+
+gint
+gdk_input_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev)
+{
+  if (gdk_input_vtable.enable_window)
+    return gdk_input_vtable.enable_window (window, gdkdev);
+  else
+    return TRUE;
+}
+
+gint
+gdk_input_disable_window (GdkWindow *window, GdkDevicePrivate *gdkdev)
+{
+  if (gdk_input_vtable.disable_window)
+    return gdk_input_vtable.disable_window(window,gdkdev);
+  else
+    return TRUE;
+}
+
+
+GdkInputWindow *
+gdk_input_window_find(GdkWindow *window)
+{
+  GList *tmp_list;
+
+  for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next)
+    if (((GdkInputWindow *)(tmp_list->data))->window == window)
+      return (GdkInputWindow *)(tmp_list->data);
+
+  return NULL;      /* Not found */
+}
+
+/* FIXME: this routine currently needs to be called between creation
+   and the corresponding configure event (because it doesn't get the
+   root_relative_geometry).  This should work with
+   gtk_window_set_extension_events, but will likely fail in other
+   cases */
+
+void
+gdk_input_set_extension_events (GdkWindow *window, gint mask,
+                               GdkExtensionMode mode)
+{
+  GdkWindowPrivate *window_private;
+  GList *tmp_list;
+  GdkInputWindow *iw;
+
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  window_private = (GdkWindowPrivate*) window;
+  if (GDK_DRAWABLE_DESTROYED (window))
+    return;
+
+  if (mode == GDK_EXTENSION_EVENTS_NONE)
+    mask = 0;
+
+  if (mask != 0)
+    {
+      iw = g_new(GdkInputWindow,1);
+
+      iw->window = window;
+      iw->mode = mode;
+
+      iw->obscuring = NULL;
+      iw->num_obscuring = 0;
+      iw->grabbed = FALSE;
+
+      gdk_input_windows = g_list_append(gdk_input_windows,iw);
+      window_private->extension_events = mask;
+
+      /* Add enter window events to the event mask */
+      /* FIXME, this is not needed for XINPUT_NONE */
+      gdk_window_set_events (window,
+                            gdk_window_get_events (window) | 
+                            GDK_ENTER_NOTIFY_MASK);
+    }
+  else
+    {
+      iw = gdk_input_window_find (window);
+      if (iw)
+       {
+         gdk_input_windows = g_list_remove(gdk_input_windows,iw);
+         g_free(iw);
+       }
+
+      window_private->extension_events = 0;
+    }
+
+  for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
+    {
+      GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data);
+
+      if (gdkdev->info.deviceid != GDK_CORE_POINTER)
+       {
+         if (mask != 0 && gdkdev->info.mode != GDK_MODE_DISABLED
+             && (gdkdev->info.has_cursor || mode == GDK_EXTENSION_EVENTS_ALL))
+           gdk_input_enable_window(window,gdkdev);
+         else
+           gdk_input_disable_window(window,gdkdev);
+       }
+    }
+}
+
+void
+gdk_input_window_destroy (GdkWindow *window)
+{
+  GdkInputWindow *input_window;
+
+  input_window = gdk_input_window_find (window);
+  g_return_if_fail (input_window != NULL);
+
+  gdk_input_windows = g_list_remove (gdk_input_windows,input_window);
+  g_free(input_window);
+}
+
+void
+gdk_input_exit (void)
+{
+  GList *tmp_list;
+  GdkDevicePrivate *gdkdev;
+
+  for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
+    {
+      gdkdev = (GdkDevicePrivate *)(tmp_list->data);
+      if (gdkdev->info.deviceid != GDK_CORE_POINTER)
+       {
+         gdk_input_set_mode(gdkdev->info.deviceid,GDK_MODE_DISABLED);
+
+         g_free(gdkdev->info.name);
+#ifndef XINPUT_NONE      
+         g_free(gdkdev->axes);
+#endif   
+         g_free(gdkdev->info.axes);
+         g_free(gdkdev->info.keys);
+         g_free(gdkdev);
+       }
+    }
+
+  g_list_free(gdk_input_devices);
+
+  for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
+    {
+      g_free(tmp_list->data);
+    }
+  g_list_free(gdk_input_windows);
+}
+
+GdkDevicePrivate *
+gdk_input_find_device(guint32 id)
+{
+  GList *tmp_list = gdk_input_devices;
+  GdkDevicePrivate *gdkdev;
+  while (tmp_list)
+    {
+      gdkdev = (GdkDevicePrivate *)(tmp_list->data);
+      if (gdkdev->info.deviceid == id)
+       return gdkdev;
+      tmp_list = tmp_list->next;
+    }
+  return NULL;
+}
+
+void
+gdk_input_window_get_pointer (GdkWindow       *window,
+                             guint32     deviceid,
+                             gdouble         *x,
+                             gdouble         *y,
+                             gdouble         *pressure,
+                             gdouble         *xtilt,
+                             gdouble         *ytilt,
+                             GdkModifierType *mask)
+{
+  if (gdk_input_vtable.get_pointer)
+    gdk_input_vtable.get_pointer (window, deviceid, x, y, pressure,
+                                 xtilt, ytilt, mask);
+}
diff --git a/gdk/linux-fb/gdkinputprivate.h b/gdk/linux-fb/gdkinputprivate.h
new file mode 100644 (file)
index 0000000..d9ce74f
--- /dev/null
@@ -0,0 +1,222 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#ifndef __GDK_INPUTPRIVATE_H__
+#define __GDK_INPUTPRIVATE_H__
+
+#include "config.h"
+#include "gdkinput.h"
+#include "gdkevents.h"
+#include "gdkfb.h"
+
+typedef struct _GdkAxisInfo    GdkAxisInfo;
+typedef struct _GdkInputVTable GdkInputVTable;
+typedef struct _GdkDevicePrivate GdkDevicePrivate;
+typedef struct _GdkInputWindow GdkInputWindow;
+
+struct _GdkInputVTable {
+  gint (*set_mode) (guint32 deviceid, GdkInputMode mode);
+  void (*set_axes) (guint32 deviceid, GdkAxisUse *axes);
+  void (*set_key)  (guint32 deviceid,
+                   guint   index,
+                   guint   keyval,
+                   GdkModifierType modifiers);
+       
+  GdkTimeCoord* (*motion_events) (GdkWindow *window,
+                                 guint32 deviceid,
+                                 guint32 start,
+                                 guint32 stop,
+                                 gint *nevents_return);
+  void (*get_pointer)   (GdkWindow       *window,
+                        guint32          deviceid,
+                        gdouble         *x,
+                        gdouble         *y,
+                        gdouble         *pressure,
+                        gdouble         *xtilt,
+                        gdouble         *ytilt,
+                        GdkModifierType *mask);
+  gint (*grab_pointer) (GdkWindow *     window,
+                       gint            owner_events,
+                       GdkEventMask    event_mask,
+                       GdkWindow *     confine_to,
+                       guint32         time);
+  void (*ungrab_pointer) (guint32 time);
+
+  void (*configure_event) (GdkEventConfigure *event, GdkWindow *window);
+  void (*enter_event) (GdkEventCrossing *event, GdkWindow *window);
+  gint (*other_event) (GdkEvent *event, GdkWindow *window);
+  /* Handle an unidentified event. Returns TRUE if handled, FALSE
+     otherwise */
+  gint (*window_none_event) (GdkEvent *event);
+  gint (*enable_window) (GdkWindow *window, GdkDevicePrivate *gdkdev);
+  gint (*disable_window) (GdkWindow *window, GdkDevicePrivate *gdkdev);
+};
+
+/* information about a device axis */
+struct _GdkAxisInfo
+{
+  /* reported x resolution */
+  gint xresolution;
+
+  /* reported x minimum/maximum values */
+  gint xmin_value, xmax_value;
+
+  /* calibrated resolution (for aspect ration) - only relative values
+     between axes used */
+  gint resolution;
+  
+  /* calibrated minimum/maximum values */
+  gint min_value, max_value;
+};
+
+#define GDK_INPUT_NUM_EVENTC 6
+
+struct _GdkDevicePrivate {
+  GdkDeviceInfo  info;
+
+#ifndef XINPUT_NONE
+  /* information about the axes */
+  GdkAxisInfo *axes;
+
+  /* reverse lookup on axis use type */
+  gint axis_for_use[GDK_AXIS_LAST];
+  
+  /* Information about XInput device */
+  XDevice       *xdevice;
+
+  /* minimum key code for device */
+  gint min_keycode;           
+
+  int buttonpress_type, buttonrelease_type, keypress_type,
+      keyrelease_type, motionnotify_type, proximityin_type, 
+      proximityout_type, changenotify_type;
+
+  /* true if we need to select a different set of events, but
+     can't because this is the core pointer */
+  gint needs_update;
+
+  /* Mask of buttons (used for button grabs) */
+  gint button_state;
+
+  /* true if we've claimed the device as active. (used only for XINPUT_GXI) */
+  gint claimed;
+#endif /* !XINPUT_NONE */
+};
+
+struct _GdkInputWindow
+{
+  /* gdk window */
+  GdkWindow *window;
+
+  /* Extension mode (GDK_EXTENSION_EVENTS_ALL/CURSOR) */
+  GdkExtensionMode mode;
+
+  /* position relative to root window */
+  gint root_x;
+  gint root_y;
+
+  /* rectangles relative to window of windows obscuring this one */
+  GdkRectangle *obscuring;
+  gint num_obscuring;
+
+  /* Is there a pointer grab for this window ? */
+  gint grabbed;
+};
+
+/* Global data */
+
+extern const GdkDeviceInfo gdk_input_core_info;
+extern GList *gdk_input_devices;
+extern GList *gdk_input_windows;
+
+extern GdkInputVTable gdk_input_vtable;
+/* information about network port and host for gxid daemon */
+extern gchar           *gdk_input_gxid_host;
+extern gint             gdk_input_gxid_port;
+extern gint             gdk_input_ignore_core;
+
+/* Function declarations */
+
+GdkDevicePrivate * gdk_input_find_device    (guint32           id);
+GdkInputWindow *   gdk_input_window_find    (GdkWindow        *window);
+void               gdk_input_window_destroy (GdkWindow        *window);
+void               gdk_input_init           (void);
+void               gdk_input_exit           (void);
+gint               gdk_input_enable_window  (GdkWindow        *window,
+                                            GdkDevicePrivate *gdkdev);
+gint               gdk_input_disable_window (GdkWindow        *window,
+                                            GdkDevicePrivate *gdkdev);
+
+#ifndef XINPUT_NONE
+
+#define GDK_MAX_DEVICE_CLASSES 13
+
+gint           gdk_input_common_init                (gint              include_core);
+void           gdk_input_get_root_relative_geometry (Display          *dpy,
+                                                    Window            w,
+                                                    int              *x_ret,
+                                                    int              *y_ret,
+                                                    int              *width_ret,
+                                                    int              *height_ret);
+void           gdk_input_common_find_events         (GdkWindow        *window,
+                                                    GdkDevicePrivate *gdkdev,
+                                                    gint              mask,
+                                                    XEventClass      *classes,
+                                                    int              *num_classes);
+void           gdk_input_common_select_events       (GdkWindow        *window,
+                                                    GdkDevicePrivate *gdkdev);
+gint           gdk_input_common_other_event         (GdkEvent         *event,
+                                                    XEvent           *xevent,
+                                                    GdkInputWindow   *input_window,
+                                                    GdkDevicePrivate *gdkdev);
+void           gdk_input_common_get_pointer         (GdkWindow        *window,
+                                                    guint32           deviceid,
+                                                    gdouble          *x,
+                                                    gdouble          *y,
+                                                    gdouble          *pressure,
+                                                    gdouble          *xtilt,
+                                                    gdouble          *ytilt,
+                                                    GdkModifierType  *mask);
+void           gdk_input_common_set_key             (guint32           deviceid,
+                                                    guint             index,
+                                                    guint             keyval,
+                                                    GdkModifierType   modifiers);
+void           gdk_input_common_set_axes            (guint32           deviceid,
+                                                    GdkAxisUse       *axes);
+GdkTimeCoord * gdk_input_common_motion_events       (GdkWindow        *window,
+                                                    guint32           deviceid,
+                                                    guint32           start,
+                                                    guint32           stop,
+                                                    gint             *nevents_return);
+
+#endif /* !XINPUT_NONE */
+
+GdkDevicePrivate *gdk_input_find_device (guint32 id);
+GdkInputWindow *gdk_input_window_find (GdkWindow *window);
+void gdk_input_window_destroy (GdkWindow *window);
+void gdk_input_exit           (void);
+
+#endif /* __GDK_INPUTPRIVATE_H__ */
diff --git a/gdk/linux-fb/gdkmain-fb.c b/gdk/linux-fb/gdkmain-fb.c
new file mode 100644 (file)
index 0000000..5fd7bb8
--- /dev/null
@@ -0,0 +1,575 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <t1lib.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "gdk.h"
+
+#include "gdkprivate-fb.h"
+#include "gdkinternals.h"
+
+/* 
+ * Private function declarations
+ */
+
+#ifndef HAVE_XCONVERTCASE
+static void     gdkx_XConvertCase      (KeySym        symbol,
+                                        KeySym       *lower,
+                                        KeySym       *upper);
+#define XConvertCase gdkx_XConvertCase
+#endif
+
+/* Private variable declarations
+ */
+static int gdk_initialized = 0;                            /* 1 if the library is initialized,
+                                                    * 0 otherwise.
+                                                    */
+
+#ifdef G_ENABLE_DEBUG
+static const GDebugKey gdk_debug_keys[] = {
+  {"misc",         GDK_DEBUG_MISC},
+  {"events",       GDK_DEBUG_EVENTS},
+};
+
+static const int gdk_ndebug_keys = sizeof(gdk_debug_keys)/sizeof(GDebugKey);
+
+#endif /* G_ENABLE_DEBUG */
+
+GdkArgDesc _gdk_windowing_args[] = {
+  { NULL }
+};
+
+static GdkFBDisplay *
+gdk_fb_display_new(const char *filename)
+{
+  int fd, n;
+  GdkFBDisplay *retval;
+  guint16 red[256], green[256], blue[256];
+  struct fb_cmap cmap;
+
+  fd = open(filename, O_RDWR);
+  if(fd < 0)
+    return NULL;
+
+  retval = g_new0(GdkFBDisplay, 1);
+  retval->fd = fd;
+  n = ioctl(fd, FBIOGET_FSCREENINFO, &retval->sinfo);
+  n |= ioctl(fd, FBIOGET_VSCREENINFO, &retval->modeinfo);
+  g_assert(!n);
+
+  retval->fbmem = mmap(NULL, retval->sinfo.smem_len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+  g_assert(retval->fbmem != MAP_FAILED);
+
+  for(n = 0; n < 16; n++)
+    red[n] = green[n] = blue[n] = n << 12;
+  for(n = 16; n < 256; n++)
+    red[n] = green[n] = blue[n] = n << 8;
+  cmap.red = red; cmap.green = green; cmap.blue = blue; cmap.len = 256; cmap.start = 0;
+  ioctl(fd, FBIOPUTCMAP, &cmap);
+
+  return retval;
+}
+
+static void
+gdk_fb_display_destroy(GdkFBDisplay *fbd)
+{
+  munmap(fbd->fbmem, fbd->sinfo.smem_len);
+  g_free(fbd);
+}
+
+extern void keyboard_init(void);
+
+gboolean
+_gdk_windowing_init_check (int argc, char **argv)
+{
+  if(gdk_initialized)
+    return TRUE;
+
+  keyboard_init();
+  gdk_display = gdk_fb_display_new("/dev/fb");
+
+  if(!gdk_display)
+    return FALSE;
+
+  T1_InitLib(NO_LOGFILE|IGNORE_FONTDATABASE);
+  T1_AASetBitsPerPixel(gdk_display->modeinfo.bits_per_pixel);
+
+  gdk_initialized = TRUE;
+
+  return TRUE;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_pointer_grab
+ *
+ *   Grabs the pointer to a specific window
+ *
+ * Arguments:
+ *   "window" is the window which will receive the grab
+ *   "owner_events" specifies whether events will be reported as is,
+ *     or relative to "window"
+ *   "event_mask" masks only interesting events
+ *   "confine_to" limits the cursor movement to the specified window
+ *   "cursor" changes the cursor for the duration of the grab
+ *   "time" specifies the time
+ *
+ * Results:
+ *
+ * Side effects:
+ *   requires a corresponding call to gdk_pointer_ungrab
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_pointer_grab (GdkWindow *    window,
+                 gint            owner_events,
+                 GdkEventMask    event_mask,
+                 GdkWindow *     confine_to,
+                 GdkCursor *     cursor,
+                 guint32         time)
+{
+  g_return_val_if_fail (window != NULL, 0);
+  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
+  g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
+
+  if(_gdk_fb_pointer_grab_window)
+    return 1;
+
+  if(!owner_events)
+    _gdk_fb_pointer_grab_window = gdk_window_ref(window);
+
+  _gdk_fb_pointer_grab_confine = confine_to?gdk_window_ref(confine_to):NULL;
+  _gdk_fb_pointer_grab_events = event_mask;
+  _gdk_fb_pointer_grab_cursor = cursor?gdk_cursor_ref(cursor):NULL;
+  
+  return 0;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_pointer_ungrab
+ *
+ *   Releases any pointer grab
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+gdk_pointer_ungrab (guint32 time)
+{
+  if(_gdk_fb_pointer_grab_window)
+    gdk_window_unref(_gdk_fb_pointer_grab_window);
+  _gdk_fb_pointer_grab_window = NULL;
+
+  if(_gdk_fb_pointer_grab_confine)
+    gdk_window_unref(_gdk_fb_pointer_grab_confine);
+  _gdk_fb_pointer_grab_confine = NULL;
+
+  if(_gdk_fb_pointer_grab_cursor)
+    gdk_cursor_unref(_gdk_fb_pointer_grab_cursor);
+  _gdk_fb_pointer_grab_cursor = NULL;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_pointer_is_grabbed
+ *
+ *   Tell wether there is an active x pointer grab in effect
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_pointer_is_grabbed (void)
+{
+  return _gdk_fb_pointer_grab_window != NULL;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_keyboard_grab
+ *
+ *   Grabs the keyboard to a specific window
+ *
+ * Arguments:
+ *   "window" is the window which will receive the grab
+ *   "owner_events" specifies whether events will be reported as is,
+ *     or relative to "window"
+ *   "time" specifies the time
+ *
+ * Results:
+ *
+ * Side effects:
+ *   requires a corresponding call to gdk_keyboard_ungrab
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_keyboard_grab (GdkWindow *    window,
+                  gint            owner_events,
+                  guint32         time)
+{
+  g_return_val_if_fail (window != NULL, 0);
+  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
+
+  if(_gdk_fb_pointer_grab_window)
+    gdk_keyboard_ungrab(time);
+
+  if(!owner_events)
+    _gdk_fb_keyboard_grab_window = gdk_window_ref(window);
+  
+  return 0;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_keyboard_ungrab
+ *
+ *   Releases any keyboard grab
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+gdk_keyboard_ungrab (guint32 time)
+{
+  if(_gdk_fb_keyboard_grab_window)
+    gdk_window_unref(_gdk_fb_keyboard_grab_window);
+  _gdk_fb_keyboard_grab_window = NULL;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_screen_width
+ *
+ *   Return the width of the screen.
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_screen_width (void)
+{
+  return gdk_display->modeinfo.xres;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_screen_height
+ *
+ *   Return the height of the screen.
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_screen_height (void)
+{
+  return gdk_display->modeinfo.yres;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_screen_width_mm
+ *
+ *   Return the width of the screen in millimeters.
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_screen_width_mm (void)
+{
+  return 0.5 + gdk_screen_width () * (25.4 / 72.);
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_screen_height
+ *
+ *   Return the height of the screen in millimeters.
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_screen_height_mm (void)
+{
+  return 0.5 + gdk_screen_height () * (25.4 / 72.);
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_set_sm_client_id
+ *
+ *   Set the SM_CLIENT_ID property on the WM_CLIENT_LEADER window
+ *   so that the window manager can save our state using the
+ *   X11R6 ICCCM session management protocol. A NULL value should 
+ *   be set following disconnection from the session manager to
+ *   remove the SM_CLIENT_ID property.
+ *
+ * Arguments:
+ * 
+ *   "sm_client_id" specifies the client id assigned to us by the
+ *   session manager or NULL to remove the property.
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+gdk_set_sm_client_id (const gchar* sm_client_id)
+{
+}
+
+void
+gdk_key_repeat_disable (void)
+{
+}
+
+void
+gdk_key_repeat_restore (void)
+{
+}
+
+
+void
+gdk_beep (void)
+{
+}
+
+extern void keyboard_shutdown(void);
+
+void
+gdk_windowing_exit (void)
+{
+  gdk_fb_display_destroy(gdk_display); gdk_display = NULL;
+
+  T1_CloseLib();
+
+  keyboard_shutdown();
+}
+
+gchar*
+gdk_keyval_name (guint       keyval)
+{
+  return NULL;
+}
+
+guint
+gdk_keyval_from_name (const gchar *keyval_name)
+{
+  return 0;
+}
+
+void     gdk_keyval_convert_case (guint        symbol,
+                                  guint       *lower,
+                                  guint       *upper)
+{
+  if(symbol >= 'a' && symbol <= 'z')
+    symbol = toupper(symbol);
+
+  if(upper)
+    *upper = symbol;
+
+  if(lower)
+    *lower = symbol;
+}
+
+gchar *
+gdk_get_display(void)
+{
+  return g_strdup("/dev/fb0");
+}
+
+/* utils */
+GdkEvent *
+gdk_event_make(GdkWindow *window, GdkEventType type, gboolean append_to_queue)
+{
+  static const guint type_masks[] = {
+    GDK_SUBSTRUCTURE_MASK, /* GDK_DELETE               = 0, */
+    GDK_STRUCTURE_MASK, /* GDK_DESTROY         = 1, */
+    GDK_EXPOSURE_MASK, /* GDK_EXPOSE           = 2, */
+    GDK_POINTER_MOTION_MASK|GDK_BUTTON_MOTION_MASK, /* GDK_MOTION_NOTIFY       = 3, */
+    GDK_BUTTON_PRESS_MASK, /* GDK_BUTTON_PRESS = 4, */
+    GDK_BUTTON_PRESS_MASK, /* GDK_2BUTTON_PRESS        = 5, */
+    GDK_BUTTON_PRESS_MASK, /* GDK_3BUTTON_PRESS        = 6, */
+    GDK_BUTTON_RELEASE_MASK, /* GDK_BUTTON_RELEASE     = 7, */
+    GDK_KEY_PRESS_MASK, /* GDK_KEY_PRESS       = 8, */
+    GDK_KEY_RELEASE_MASK, /* GDK_KEY_RELEASE   = 9, */
+    GDK_ENTER_NOTIFY_MASK, /* GDK_ENTER_NOTIFY = 10, */
+    GDK_LEAVE_NOTIFY_MASK, /* GDK_LEAVE_NOTIFY = 11, */
+    GDK_FOCUS_CHANGE_MASK, /* GDK_FOCUS_CHANGE = 12, */
+    GDK_STRUCTURE_MASK, /* GDK_CONFIGURE               = 13, */
+    GDK_VISIBILITY_NOTIFY_MASK, /* GDK_MAP             = 14, */
+    GDK_VISIBILITY_NOTIFY_MASK, /* GDK_UNMAP           = 15, */
+    GDK_PROPERTY_CHANGE_MASK, /* GDK_PROPERTY_NOTIFY   = 16, */
+    GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_CLEAR   = 17, */
+    GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_REQUEST = 18, */
+    GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_NOTIFY  = 19, */
+    GDK_PROXIMITY_IN_MASK, /* GDK_PROXIMITY_IN = 20, */
+    GDK_PROXIMITY_OUT_MASK, /* GDK_PROXIMITY_OUT       = 21, */
+    GDK_ALL_EVENTS_MASK, /* GDK_DRAG_ENTER        = 22, */
+    GDK_ALL_EVENTS_MASK, /* GDK_DRAG_LEAVE        = 23, */
+    GDK_ALL_EVENTS_MASK, /* GDK_DRAG_MOTION       = 24, */
+    GDK_ALL_EVENTS_MASK, /* GDK_DRAG_STATUS       = 25, */
+    GDK_ALL_EVENTS_MASK, /* GDK_DROP_START        = 26, */
+    GDK_ALL_EVENTS_MASK, /* GDK_DROP_FINISHED     = 27, */
+    GDK_ALL_EVENTS_MASK, /* GDK_CLIENT_EVENT   = 28, */
+    GDK_VISIBILITY_NOTIFY_MASK, /* GDK_VISIBILITY_NOTIFY = 29, */
+    GDK_EXPOSURE_MASK, /* GDK_NO_EXPOSE                = 30, */
+    GDK_SCROLL_MASK /* GDK_SCROLL            = 31 */
+  };
+
+  if(GDK_WINDOW_FBDATA(window)->event_mask & type_masks[type])
+    {
+      GdkEvent *event = gdk_event_new();
+      guint32 the_time = g_latest_time.tv_sec;
+
+      event->any.type = type;
+      event->any.window = gdk_window_ref(window);
+      switch(type)
+       {
+       case GDK_MOTION_NOTIFY:
+         event->motion.time = the_time;
+         break;
+       case GDK_BUTTON_PRESS:
+       case GDK_2BUTTON_PRESS:
+       case GDK_3BUTTON_PRESS:
+       case GDK_BUTTON_RELEASE:
+         event->button.time = the_time;
+         break;
+       case GDK_KEY_PRESS:
+       case GDK_KEY_RELEASE:
+         event->key.time = the_time;
+         break;
+       case GDK_ENTER_NOTIFY:
+       case GDK_LEAVE_NOTIFY:
+         event->crossing.time = the_time;
+         break;
+
+       case GDK_PROPERTY_NOTIFY:
+         event->property.time = the_time;
+         break;
+
+       case GDK_SELECTION_CLEAR:
+       case GDK_SELECTION_REQUEST:
+       case GDK_SELECTION_NOTIFY:
+         event->selection.time = the_time;
+         break;
+       case GDK_PROXIMITY_IN:
+       case GDK_PROXIMITY_OUT:
+         event->proximity.time = the_time;
+         break;
+       case GDK_DRAG_ENTER:
+       case GDK_DRAG_LEAVE:
+       case GDK_DRAG_MOTION:
+       case GDK_DRAG_STATUS:
+       case GDK_DROP_START:
+       case GDK_DROP_FINISHED:
+         event->dnd.time = the_time;
+         break;
+
+       case GDK_FOCUS_CHANGE:
+       case GDK_CONFIGURE:
+       case GDK_MAP:
+       case GDK_UNMAP:
+       case GDK_CLIENT_EVENT:
+       case GDK_VISIBILITY_NOTIFY:
+       case GDK_NO_EXPOSE:
+       case GDK_SCROLL:
+       case GDK_DELETE:
+       case GDK_DESTROY:
+       case GDK_EXPOSE:
+       default:
+         break;
+       }
+
+      if(append_to_queue)
+       gdk_event_queue_append(event);
+
+      return event;
+    }
+
+  return NULL;
+}
diff --git a/gdk/linux-fb/gdkpixmap-fb.c b/gdk/linux-fb/gdkpixmap-fb.c
new file mode 100644 (file)
index 0000000..30c6d2b
--- /dev/null
@@ -0,0 +1,768 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+/* Needed for SEEK_END in SunOS */
+#include <unistd.h>
+
+#include "gdkpixmap.h"
+#include "gdkfb.h"
+#include "gdkprivate-fb.h"
+
+typedef struct
+{
+  gchar *color_string;
+  GdkColor color;
+  gint transparent;
+} _GdkPixmapColor;
+
+typedef struct
+{
+  guint ncolors;
+  GdkColormap *colormap;
+  gulong pixels[1];
+} _GdkPixmapInfo;
+
+static void
+gdk_fb_pixmap_destroy (GdkPixmap *pixmap)
+{
+  g_free (GDK_DRAWABLE_FBDATA(pixmap)->mem);
+  g_free (GDK_DRAWABLE_FBDATA (pixmap));
+}
+
+static GdkDrawable *
+gdk_fb_pixmap_alloc (void)
+{
+  GdkDrawable *drawable;
+  GdkDrawablePrivate *private;
+  
+  static GdkDrawableClass klass;
+  static gboolean initialized = FALSE;
+
+  if (!initialized)
+    {
+      initialized = TRUE;
+      
+      klass = _gdk_fb_drawable_class;
+      klass.destroy = gdk_fb_pixmap_destroy;
+    }
+
+  drawable = gdk_drawable_alloc ();
+  private = (GdkDrawablePrivate *)drawable;
+
+  private->klass = &klass;
+  private->klass_data = g_new0 (GdkDrawableFBData, 1);
+  private->window_type = GDK_DRAWABLE_PIXMAP;
+  private->colormap = gdk_colormap_ref(gdk_colormap_get_system());
+
+  return drawable;
+}
+
+GdkPixmap*
+gdk_pixmap_new (GdkWindow *window,
+               gint       width,
+               gint       height,
+               gint       depth)
+{
+  GdkPixmap *pixmap;
+  GdkDrawablePrivate *private;
+
+  g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
+  g_return_val_if_fail ((window != NULL) || (depth != -1), NULL);
+  g_return_val_if_fail ((width != 0) && (height != 0), NULL);
+  
+  if (!window)
+    window = gdk_parent_root;
+
+  if (GDK_DRAWABLE_DESTROYED (window))
+    return NULL;
+
+  if (depth == -1)
+    depth = gdk_drawable_get_visual (window)->depth;
+
+  pixmap = gdk_fb_pixmap_alloc ();
+  private = (GdkDrawablePrivate *)pixmap;
+
+  GDK_DRAWABLE_FBDATA(pixmap)->mem = g_malloc(((width * depth + 7) / 8) * height);
+  GDK_DRAWABLE_FBDATA(pixmap)->rowstride = (width * depth + 7) / 8; /* Round up to nearest whole byte */
+  GDK_DRAWABLE_FBDATA(pixmap)->lim_x = width;
+  GDK_DRAWABLE_FBDATA(pixmap)->lim_y = height;
+  private->width = width;
+  private->height = height;
+  private->depth = depth;
+
+  return pixmap;
+}
+
+GdkPixmap *
+gdk_bitmap_create_from_data (GdkWindow   *window,
+                            const gchar *data,
+                            gint         width,
+                            gint         height)
+{
+  GdkPixmap *pixmap;
+
+  g_return_val_if_fail (data != NULL, NULL);
+  g_return_val_if_fail ((width != 0) && (height != 0), NULL);
+  g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
+
+  if (!window)
+    window = gdk_parent_root;
+
+  if (GDK_DRAWABLE_DESTROYED (window))
+    return NULL;
+
+  pixmap = gdk_pixmap_new(window, width, height, 1);
+
+  memcpy(GDK_DRAWABLE_FBDATA(pixmap)->mem, data, ((width + 7) / 8) * height);
+
+  return pixmap;
+}
+
+GdkPixmap*
+gdk_pixmap_create_from_data (GdkWindow   *window,
+                            const gchar *data,
+                            gint         width,
+                            gint         height,
+                            gint         depth,
+                            GdkColor    *fg,
+                            GdkColor    *bg)
+{
+  GdkPixmap *pixmap;
+  GdkDrawablePrivate *private;
+
+  g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
+  g_return_val_if_fail (data != NULL, NULL);
+  g_return_val_if_fail (fg != NULL, NULL);
+  g_return_val_if_fail (bg != NULL, NULL);
+  g_return_val_if_fail ((window != NULL) || (depth != -1), NULL);
+  g_return_val_if_fail ((width != 0) && (height != 0), NULL);
+
+  if (!window)
+    window = gdk_parent_root;
+
+  if (GDK_DRAWABLE_DESTROYED (window))
+    return NULL;
+
+  if (depth == -1)
+    depth = gdk_drawable_get_visual (window)->depth;
+
+  pixmap = gdk_pixmap_new(window, width, height, depth);
+
+  private = (GdkDrawablePrivate *)pixmap;
+
+
+  return pixmap;
+}
+
+static gint
+gdk_pixmap_seek_string (FILE  *infile,
+                        const gchar *str,
+                        gint   skip_comments)
+{
+  char instr[1024];
+
+  while (!feof (infile))
+    {
+      fscanf (infile, "%1023s", instr);
+      if (skip_comments == TRUE && strcmp (instr, "/*") == 0)
+        {
+          fscanf (infile, "%1023s", instr);
+          while (!feof (infile) && strcmp (instr, "*/") != 0)
+            fscanf (infile, "%1023s", instr);
+          fscanf(infile, "%1023s", instr);
+        }
+      if (strcmp (instr, str)==0)
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gint
+gdk_pixmap_seek_char (FILE  *infile,
+                      gchar  c)
+{
+  gint b, oldb;
+
+  while ((b = getc(infile)) != EOF)
+    {
+      if (c != b && b == '/')
+       {
+         b = getc (infile);
+         if (b == EOF)
+           return FALSE;
+         else if (b == '*')    /* we have a comment */
+           {
+             b = -1;
+             do
+               {
+                 oldb = b;
+                 b = getc (infile);
+                 if (b == EOF)
+                   return FALSE;
+               }
+             while (!(oldb == '*' && b == '/'));
+           }
+        }
+      else if (c == b)
+       return TRUE;
+    }
+  return FALSE;
+}
+
+static gint
+gdk_pixmap_read_string (FILE  *infile,
+                        gchar **buffer,
+                       guint *buffer_size)
+{
+  gint c;
+  guint cnt = 0, bufsiz, ret = FALSE;
+  gchar *buf;
+
+  buf = *buffer;
+  bufsiz = *buffer_size;
+  if (buf == NULL)
+    {
+      bufsiz = 10 * sizeof (gchar);
+      buf = g_new(gchar, bufsiz);
+    }
+
+  do
+    c = getc (infile);
+  while (c != EOF && c != '"');
+
+  if (c != '"')
+    goto out;
+
+  while ((c = getc(infile)) != EOF)
+    {
+      if (cnt == bufsiz)
+       {
+         guint new_size = bufsiz * 2;
+         if (new_size > bufsiz)
+           bufsiz = new_size;
+         else
+           goto out;
+         
+         buf = (gchar *) g_realloc (buf, bufsiz);
+         buf[bufsiz-1] = '\0';
+       }
+
+      if (c != '"')
+        buf[cnt++] = c;
+      else
+        {
+          buf[cnt] = 0;
+         ret = TRUE;
+         break;
+        }
+    }
+
+ out:
+  buf[bufsiz-1] = '\0';                /* ensure null termination for errors */
+  *buffer = buf;
+  *buffer_size = bufsiz;
+  return ret;
+}
+
+static gchar*
+gdk_pixmap_skip_whitespaces (gchar *buffer)
+{
+  gint32 index = 0;
+
+  while (buffer[index] != 0 && (buffer[index] == 0x20 || buffer[index] == 0x09))
+    index++;
+
+  return &buffer[index];
+}
+
+static gchar*
+gdk_pixmap_skip_string (gchar *buffer)
+{
+  gint32 index = 0;
+
+  while (buffer[index] != 0 && buffer[index] != 0x20 && buffer[index] != 0x09)
+    index++;
+
+  return &buffer[index];
+}
+
+/* Xlib crashed once at a color name lengths around 125 */
+#define MAX_COLOR_LEN 120
+
+static gchar*
+gdk_pixmap_extract_color (gchar *buffer)
+{
+  gint counter, numnames;
+  gchar *ptr = NULL, ch, temp[128];
+  gchar color[MAX_COLOR_LEN], *retcol;
+  gint space;
+
+  counter = 0;
+  while (ptr == NULL)
+    {
+      if (buffer[counter] == 'c')
+        {
+          ch = buffer[counter + 1];
+          if (ch == 0x20 || ch == 0x09)
+            ptr = &buffer[counter + 1];
+        }
+      else if (buffer[counter] == 0)
+        return NULL;
+
+      counter++;
+    }
+
+  ptr = gdk_pixmap_skip_whitespaces (ptr);
+
+  if (ptr[0] == 0)
+    return NULL;
+  else if (ptr[0] == '#')
+    {
+      counter = 1;
+      while (ptr[counter] != 0 && 
+             ((ptr[counter] >= '0' && ptr[counter] <= '9') ||
+              (ptr[counter] >= 'a' && ptr[counter] <= 'f') ||
+              (ptr[counter] >= 'A' && ptr[counter] <= 'F')))
+        counter++;
+
+      retcol = g_new (gchar, counter+1);
+      strncpy (retcol, ptr, counter);
+
+      retcol[counter] = 0;
+      
+      return retcol;
+    }
+
+  color[0] = 0;
+  numnames = 0;
+
+  space = MAX_COLOR_LEN - 1;
+  while (space > 0)
+    {
+      sscanf (ptr, "%127s", temp);
+
+      if (((gint)ptr[0] == 0) ||
+         (strcmp ("s", temp) == 0) || (strcmp ("m", temp) == 0) ||
+          (strcmp ("g", temp) == 0) || (strcmp ("g4", temp) == 0))
+       {
+         break;
+       }
+      else
+        {
+          if (numnames > 0)
+           {
+             space -= 1;
+             strcat (color, " ");
+           }
+         strncat (color, temp, space);
+         space -= MIN (space, strlen (temp));
+          ptr = gdk_pixmap_skip_string (ptr);
+          ptr = gdk_pixmap_skip_whitespaces (ptr);
+          numnames++;
+        }
+    }
+
+  retcol = g_strdup (color);
+  return retcol;
+}
+
+
+enum buffer_op
+{
+  op_header,
+  op_cmap,
+  op_body
+};
+  
+
+static void 
+gdk_xpm_destroy_notify (gpointer data)
+{
+  _GdkPixmapInfo *info = (_GdkPixmapInfo *)data;
+  GdkColor color;
+  int i;
+
+  for (i=0; i<info->ncolors; i++)
+    {
+      color.pixel = info->pixels[i];
+      gdk_colormap_free_colors (info->colormap, &color, 1);
+    }
+
+  gdk_colormap_unref (info->colormap);
+  g_free (info);
+}
+  
+static GdkPixmap *
+_gdk_pixmap_create_from_xpm (GdkWindow  *window,
+                            GdkColormap *colormap,
+                            GdkBitmap **mask,
+                            GdkColor   *transparent_color,
+                            gchar *   (*get_buf) (enum buffer_op op,
+                                                  gpointer       handle),
+                            gpointer    handle)
+{
+  GdkPixmap *pixmap = NULL;
+  GdkImage *image = NULL;
+  GdkVisual *visual;
+  GdkGC *gc = NULL;
+  GdkColor tmp_color;
+  gint width, height, num_cols, cpp, n, ns, cnt, xcnt, ycnt, wbytes;
+  gchar *buffer, pixel_str[32];
+  gchar *name_buf;
+  _GdkPixmapColor *color = NULL, *fallbackcolor = NULL;
+  _GdkPixmapColor *colors = NULL;
+  gulong index;
+  GHashTable *color_hash = NULL;
+  _GdkPixmapInfo *color_info = NULL;
+  
+  if ((window == NULL) && (colormap == NULL))
+    g_warning ("Creating pixmap from xpm with NULL window and colormap");
+  
+  if (window == NULL)
+    window = gdk_parent_root;
+  
+  if (colormap == NULL)
+    {
+      colormap = gdk_drawable_get_colormap (window);
+      visual = gdk_drawable_get_visual (window);
+    }
+  else
+    visual = ((GdkColormapPrivate *)colormap)->visual;
+  
+  buffer = (*get_buf) (op_header, handle);
+  if (buffer == NULL)
+    return NULL;
+  
+  sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp);
+  if (cpp >= 32)
+    {
+      g_warning ("Pixmap has more than 31 characters per color\n");
+      return NULL;
+    }
+  
+  color_hash = g_hash_table_new (g_str_hash, g_str_equal);
+  
+  if (transparent_color == NULL)
+    {
+      gdk_color_white (colormap, &tmp_color);
+      transparent_color = &tmp_color;
+    }
+
+  /* For pseudo-color and grayscale visuals, we have to remember
+   * the colors we allocated, so we can free them later.
+   */
+  if ((visual->type == GDK_VISUAL_PSEUDO_COLOR) ||
+      (visual->type == GDK_VISUAL_GRAYSCALE))
+    {
+      color_info = g_malloc (sizeof (_GdkPixmapInfo) + 
+                            sizeof(gulong) * (num_cols - 1));
+      color_info->ncolors = num_cols;
+      color_info->colormap = colormap;
+      gdk_colormap_ref (colormap);
+    }
+
+  name_buf = g_new (gchar, num_cols * (cpp+1));
+  colors = g_new (_GdkPixmapColor, num_cols);
+
+  for (cnt = 0; cnt < num_cols; cnt++)
+    {
+      gchar *color_name;
+      
+      buffer = (*get_buf) (op_cmap, handle);
+      if (buffer == NULL)
+       goto error;
+      
+      color = &colors[cnt];
+      color->color_string = &name_buf [cnt * (cpp + 1)];
+      strncpy (color->color_string, buffer, cpp);
+      color->color_string[cpp] = 0;
+      buffer += strlen (color->color_string);
+      color->transparent = FALSE;
+      
+      color_name = gdk_pixmap_extract_color (buffer);
+      
+      if (color_name == NULL || g_strcasecmp (color_name, "None") == 0 ||
+         gdk_color_parse (color_name, &color->color) == FALSE)
+       {
+         color->color = *transparent_color;
+         color->transparent = TRUE;
+       }
+      
+      g_free (color_name);
+      
+      /* FIXME: The remaining slowness appears to happen in this
+         function. */
+      gdk_color_alloc (colormap, &color->color);
+
+      if (color_info)
+       color_info->pixels[cnt] = color->color.pixel;
+      
+      g_hash_table_insert (color_hash, color->color_string, color);
+      if (cnt == 0)
+       fallbackcolor = color;
+    }
+  
+  index = 0;
+  image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height);
+  
+  if (mask)
+    {
+      /* The pixmap mask is just a bits pattern.
+       * Color 0 is used for background and 1 for foreground.
+       * We don't care about the colormap, we just need 0 and 1.
+       */
+      GdkColor mask_pattern;
+      
+      *mask = gdk_pixmap_new (window, width, height, 1);
+      gc = gdk_gc_new (*mask);
+      
+      mask_pattern.pixel = 0;
+      gdk_gc_set_foreground (gc, &mask_pattern);
+      gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, width, height);
+
+      mask_pattern.pixel = 255;
+      gdk_gc_set_foreground (gc, &mask_pattern);
+    }
+  
+  wbytes = width * cpp;
+  for (ycnt = 0; ycnt < height; ycnt++)
+    {
+      buffer = (*get_buf) (op_body, handle);
+      
+      /* FIXME: this slows things down a little - it could be
+       * integrated into the strncpy below, perhaps. OTOH, strlen
+       * is fast.
+       */
+      if ((buffer == NULL) || strlen (buffer) < wbytes)
+       continue;
+      
+      for (n = 0, cnt = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++)
+       {
+         strncpy (pixel_str, &buffer[n], cpp);
+         pixel_str[cpp] = 0;
+         ns = 0;
+         
+         color = g_hash_table_lookup (color_hash, pixel_str);
+         
+         if (!color) /* screwed up XPM file */
+           color = fallbackcolor;
+         
+         gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel);
+         
+         if (mask && color->transparent)
+           {
+             if (cnt < xcnt)
+               gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
+             cnt = xcnt + 1;
+           }
+       }
+      
+      if (mask && (cnt < xcnt))
+       gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
+    }
+  
+ error:
+  
+  if (mask)
+    gdk_gc_unref (gc);
+  
+  if (image != NULL)
+    {
+      pixmap = gdk_pixmap_new (window, width, height, visual->depth);
+
+      if (color_info)
+       gdk_drawable_set_data (pixmap, "gdk-xpm", color_info, 
+                              gdk_xpm_destroy_notify);
+      
+      gc = gdk_gc_new (pixmap);
+      gdk_gc_set_foreground (gc, transparent_color);
+      gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height);
+      gdk_gc_unref (gc);
+      gdk_image_unref (image);
+
+#if 0
+      g_print("%dx%d\n", width, height);
+      for(y = 0; y < height; y++)
+       {
+         for(x = 0; x < width; x++)
+           {
+             guchar foo = GDK_DRAWABLE_FBDATA(pixmap)->mem[(x + GDK_DRAWABLE_FBDATA(pixmap)->rowstride * y];
+             if(foo == 0)
+               g_print("o");
+             else if(foo == 255)
+               g_print("w");
+             else if(foo == transparent_color->pixel)
+               g_print(" ");
+             else
+               g_print(".");
+           }
+         g_print("\n");
+       }
+#endif
+    }
+  else if (color_info)
+    gdk_xpm_destroy_notify (color_info);
+  
+  if (color_hash != NULL)
+    g_hash_table_destroy (color_hash);
+
+  if (colors != NULL)
+    g_free (colors);
+
+  if (name_buf != NULL)
+    g_free (name_buf);
+
+  return pixmap;
+}
+
+
+struct file_handle
+{
+  FILE *infile;
+  gchar *buffer;
+  guint buffer_size;
+};
+
+
+static gchar *
+file_buffer (enum buffer_op op, gpointer handle)
+{
+  struct file_handle *h = handle;
+
+  switch (op)
+    {
+    case op_header:
+      if (gdk_pixmap_seek_string (h->infile, "XPM", FALSE) != TRUE)
+       break;
+
+      if (gdk_pixmap_seek_char (h->infile,'{') != TRUE)
+       break;
+      /* Fall through to the next gdk_pixmap_seek_char. */
+
+    case op_cmap:
+      gdk_pixmap_seek_char (h->infile, '"');
+      fseek (h->infile, -1, SEEK_CUR);
+      /* Fall through to the gdk_pixmap_read_string. */
+
+    case op_body:
+      gdk_pixmap_read_string (h->infile, &h->buffer, &h->buffer_size);
+      return h->buffer;
+    }
+  return 0;
+}
+
+
+GdkPixmap*
+gdk_pixmap_colormap_create_from_xpm (GdkWindow   *window,
+                                    GdkColormap *colormap,
+                                    GdkBitmap  **mask,
+                                    GdkColor    *transparent_color,
+                                    const gchar *filename)
+{
+  struct file_handle h;
+  GdkPixmap *pixmap = NULL;
+
+  memset (&h, 0, sizeof (h));
+  h.infile = fopen (filename, "rb");
+  if (h.infile != NULL)
+    {
+      pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask,
+                                           transparent_color,
+                                           file_buffer, &h);
+      fclose (h.infile);
+      g_free (h.buffer);
+    }
+
+  return pixmap;
+}
+
+GdkPixmap*
+gdk_pixmap_create_from_xpm (GdkWindow  *window,
+                           GdkBitmap **mask,
+                           GdkColor   *transparent_color,
+                           const gchar *filename)
+{
+  return gdk_pixmap_colormap_create_from_xpm (window, NULL, mask,
+                                      transparent_color, filename);
+}
+
+
+struct mem_handle
+{
+  gchar **data;
+  int offset;
+};
+
+
+static gchar *
+mem_buffer (enum buffer_op op, gpointer handle)
+{
+  struct mem_handle *h = handle;
+  switch (op)
+    {
+    case op_header:
+    case op_cmap:
+    case op_body:
+      if (h->data[h->offset])
+       return h->data[h->offset ++];
+    }
+  return 0;
+}
+
+
+GdkPixmap*
+gdk_pixmap_colormap_create_from_xpm_d (GdkWindow  *window,
+                                      GdkColormap *colormap,
+                                      GdkBitmap **mask,
+                                      GdkColor   *transparent_color,
+                                      gchar     **data)
+{
+  struct mem_handle h;
+  GdkPixmap *pixmap = NULL;
+
+  memset (&h, 0, sizeof (h));
+  h.data = data;
+  pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask,
+                                       transparent_color,
+                                       mem_buffer, &h);
+  return pixmap;
+}
+
+
+GdkPixmap*
+gdk_pixmap_create_from_xpm_d (GdkWindow  *window,
+                             GdkBitmap **mask,
+                             GdkColor   *transparent_color,
+                             gchar     **data)
+{
+  return gdk_pixmap_colormap_create_from_xpm_d (window, NULL, mask,
+                                               transparent_color, data);
+}
diff --git a/gdk/linux-fb/gdkpoly-generic.h b/gdk/linux-fb/gdkpoly-generic.h
new file mode 100644 (file)
index 0000000..660c689
--- /dev/null
@@ -0,0 +1,291 @@
+/* $TOG: poly.h /main/5 1998/02/06 17:47:27 kaleb $ */
+/************************************************************************
+
+Copyright 1987, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+************************************************************************/
+
+/*
+ *     This file contains a few macros to help track
+ *     the edge of a filled object.  The object is assumed
+ *     to be filled in scanline order, and thus the
+ *     algorithm used is an extension of Bresenham's line
+ *     drawing algorithm which assumes that y is always the
+ *     major axis.
+ *     Since these pieces of code are the same for any filled shape,
+ *     it is more convenient to gather the library in one
+ *     place, but since these pieces of code are also in
+ *     the inner loops of output primitives, procedure call
+ *     overhead is out of the question.
+ *     See the author for a derivation if needed.
+ */
+\f
+
+/*
+ *  In scan converting polygons, we want to choose those pixels
+ *  which are inside the polygon.  Thus, we add .5 to the starting
+ *  x coordinate for both left and right edges.  Now we choose the
+ *  first pixel which is inside the pgon for the left edge and the
+ *  first pixel which is outside the pgon for the right edge.
+ *  Draw the left pixel, but not the right.
+ *
+ *  How to add .5 to the starting x coordinate:
+ *      If the edge is moving to the right, then subtract dy from the
+ *  error term from the general form of the algorithm.
+ *      If the edge is moving to the left, then add dy to the error term.
+ *
+ *  The reason for the difference between edges moving to the left
+ *  and edges moving to the right is simple:  If an edge is moving
+ *  to the right, then we want the algorithm to flip immediately.
+ *  If it is moving to the left, then we don't want it to flip until
+ *  we traverse an entire pixel.
+ */
+#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
+    int dx;      /* local storage */ \
+\
+    /* \
+     *  if the edge is horizontal, then it is ignored \
+     *  and assumed not to be processed.  Otherwise, do this stuff. \
+     */ \
+    if ((dy) != 0) { \
+        xStart = (x1); \
+        dx = (x2) - xStart; \
+        if (dx < 0) { \
+            m = dx / (dy); \
+            m1 = m - 1; \
+            incr1 = -2 * dx + 2 * (dy) * m1; \
+            incr2 = -2 * dx + 2 * (dy) * m; \
+            d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
+        } else { \
+            m = dx / (dy); \
+            m1 = m + 1; \
+            incr1 = 2 * dx - 2 * (dy) * m1; \
+            incr2 = 2 * dx - 2 * (dy) * m; \
+            d = -2 * m * (dy) + 2 * dx; \
+        } \
+    } \
+}
+\f
+#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
+    if (m1 > 0) { \
+        if (d > 0) { \
+            minval += m1; \
+            d += incr1; \
+        } \
+        else { \
+            minval += m; \
+            d += incr2; \
+        } \
+    } else {\
+        if (d >= 0) { \
+            minval += m1; \
+            d += incr1; \
+        } \
+        else { \
+            minval += m; \
+            d += incr2; \
+        } \
+    } \
+}
+
+\f
+/*
+ *     This structure contains all of the information needed
+ *     to run the bresenham algorithm.
+ *     The variables may be hardcoded into the declarations
+ *     instead of using this structure to make use of
+ *     register declarations.
+ */
+typedef struct {
+    int minor_axis;    /* minor axis        */
+    int d;             /* decision variable */
+    int m, m1;         /* slope and slope+1 */
+    int incr1, incr2;  /* error increments */
+} BRESINFO;
+
+
+#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
+       BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
+                     bres.m, bres.m1, bres.incr1, bres.incr2)
+
+#define BRESINCRPGONSTRUCT(bres) \
+        BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
+
+
+
+/*
+ *     These are the data structures needed to scan
+ *     convert regions.  Two different scan conversion
+ *     methods are available -- the even-odd method, and
+ *     the winding number method.
+ *     The even-odd rule states that a point is inside
+ *     the polygon if a ray drawn from that point in any
+ *     direction will pass through an odd number of
+ *     path segments.
+ *     By the winding number rule, a point is decided
+ *     to be inside the polygon if a ray drawn from that
+ *     point in any direction passes through a different
+ *     number of clockwise and counter-clockwise path
+ *     segments.
+ *
+ *     These data structures are adapted somewhat from
+ *     the algorithm in (Foley/Van Dam) for scan converting
+ *     polygons.
+ *     The basic algorithm is to start at the top (smallest y)
+ *     of the polygon, stepping down to the bottom of
+ *     the polygon by incrementing the y coordinate.  We
+ *     keep a list of edges which the current scanline crosses,
+ *     sorted by x.  This list is called the Active Edge Table (AET)
+ *     As we change the y-coordinate, we update each entry in 
+ *     in the active edge table to reflect the edges new xcoord.
+ *     This list must be sorted at each scanline in case
+ *     two edges intersect.
+ *     We also keep a data structure known as the Edge Table (ET),
+ *     which keeps track of all the edges which the current
+ *     scanline has not yet reached.  The ET is basically a
+ *     list of ScanLineList structures containing a list of
+ *     edges which are entered at a given scanline.  There is one
+ *     ScanLineList per scanline at which an edge is entered.
+ *     When we enter a new edge, we move it from the ET to the AET.
+ *
+ *     From the AET, we can implement the even-odd rule as in
+ *     (Foley/Van Dam).
+ *     The winding number rule is a little trickier.  We also
+ *     keep the EdgeTableEntries in the AET linked by the
+ *     nextWETE (winding EdgeTableEntry) link.  This allows
+ *     the edges to be linked just as before for updating
+ *     purposes, but only uses the edges linked by the nextWETE
+ *     link as edges representing spans of the polygon to
+ *     drawn (as with the even-odd rule).
+ */
+
+/*
+ * for the winding number rule
+ */
+#define CLOCKWISE          1
+#define COUNTERCLOCKWISE  -1 
+
+typedef struct _EdgeTableEntry {
+     int ymax;             /* ycoord at which we exit this edge. */
+     BRESINFO bres;        /* Bresenham info to run the edge     */
+     struct _EdgeTableEntry *next;       /* next in the list     */
+     struct _EdgeTableEntry *back;       /* for insertion sort   */
+     struct _EdgeTableEntry *nextWETE;   /* for winding num rule */
+     int ClockWise;        /* flag for winding number rule       */
+} EdgeTableEntry;
+
+
+typedef struct _ScanLineList{
+     int scanline;              /* the scanline represented */
+     EdgeTableEntry *edgelist;  /* header node              */
+     struct _ScanLineList *next;  /* next in the list       */
+} ScanLineList;
+
+
+typedef struct {
+     int ymax;                 /* ymax for the polygon     */
+     int ymin;                 /* ymin for the polygon     */
+     ScanLineList scanlines;   /* header node              */
+} EdgeTable;
+
+
+/*
+ * Here is a struct to help with storage allocation
+ * so we can allocate a big chunk at a time, and then take
+ * pieces from this heap when we need to.
+ */
+#define SLLSPERBLOCK 25
+
+typedef struct _ScanLineListBlock {
+     ScanLineList SLLs[SLLSPERBLOCK];
+     struct _ScanLineListBlock *next;
+} ScanLineListBlock;
+
+
+\f
+/*
+ *
+ *     a few macros for the inner loops of the fill code where
+ *     performance considerations don't allow a procedure call.
+ *
+ *     Evaluate the given edge at the given scanline.
+ *     If the edge has expired, then we leave it and fix up
+ *     the active edge table; otherwise, we increment the
+ *     x value to be ready for the next scanline.
+ *     The winding number rule is in effect, so we must notify
+ *     the caller when the edge has been removed so he
+ *     can reorder the Winding Active Edge Table.
+ */
+#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
+   if (pAET->ymax == y) {          /* leaving this edge */ \
+      pPrevAET->next = pAET->next; \
+      pAET = pPrevAET->next; \
+      fixWAET = 1; \
+      if (pAET) \
+         pAET->back = pPrevAET; \
+   } \
+   else { \
+      BRESINCRPGONSTRUCT(pAET->bres); \
+      pPrevAET = pAET; \
+      pAET = pAET->next; \
+   } \
+}
+
+
+/*
+ *     Evaluate the given edge at the given scanline.
+ *     If the edge has expired, then we leave it and fix up
+ *     the active edge table; otherwise, we increment the
+ *     x value to be ready for the next scanline.
+ *     The even-odd rule is in effect.
+ */
+#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
+   if (pAET->ymax == y) {          /* leaving this edge */ \
+      pPrevAET->next = pAET->next; \
+      pAET = pPrevAET->next; \
+      if (pAET) \
+         pAET->back = pPrevAET; \
+   } \
+   else { \
+      BRESINCRPGONSTRUCT(pAET->bres); \
+      pPrevAET = pAET; \
+      pAET = pAET->next; \
+   } \
+}
diff --git a/gdk/linux-fb/gdkpolyreg-generic.c b/gdk/linux-fb/gdkpolyreg-generic.c
new file mode 100644 (file)
index 0000000..b98bd56
--- /dev/null
@@ -0,0 +1,616 @@
+/* $TOG: PolyReg.c /main/15 1998/02/06 17:47:08 kaleb $ */
+/************************************************************************
+
+Copyright 1987, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+************************************************************************/
+/* $XFree86: xc/lib/X11/PolyReg.c,v 1.4 1998/10/03 08:41:21 dawes Exp $ */
+
+#define LARGE_COORDINATE 1000000
+#define SMALL_COORDINATE -LARGE_COORDINATE
+
+#include <gdkregion.h>
+#include "gdkregion-generic.h"
+#include "gdkpoly-generic.h"
+
+/*
+ *     InsertEdgeInET
+ *
+ *     Insert the given edge into the edge table.
+ *     First we must find the correct bucket in the
+ *     Edge table, then find the right slot in the
+ *     bucket.  Finally, we can insert it.
+ *
+ */
+static void
+InsertEdgeInET(ET, ETE, scanline, SLLBlock, iSLLBlock)
+    EdgeTable *ET;
+    EdgeTableEntry *ETE;
+    int scanline;
+    ScanLineListBlock **SLLBlock;
+    int *iSLLBlock;
+{
+    EdgeTableEntry *start, *prev;
+    ScanLineList *pSLL, *pPrevSLL;
+    ScanLineListBlock *tmpSLLBlock;
+
+    /*
+     * find the right bucket to put the edge into
+     */
+    pPrevSLL = &ET->scanlines;
+    pSLL = pPrevSLL->next;
+    while (pSLL && (pSLL->scanline < scanline)) 
+    {
+        pPrevSLL = pSLL;
+        pSLL = pSLL->next;
+    }
+
+    /*
+     * reassign pSLL (pointer to ScanLineList) if necessary
+     */
+    if ((!pSLL) || (pSLL->scanline > scanline)) 
+    {
+        if (*iSLLBlock > SLLSPERBLOCK-1) 
+        {
+            tmpSLLBlock = 
+                 (ScanLineListBlock *)g_malloc(sizeof(ScanLineListBlock));
+            (*SLLBlock)->next = tmpSLLBlock;
+            tmpSLLBlock->next = (ScanLineListBlock *)NULL;
+            *SLLBlock = tmpSLLBlock;
+            *iSLLBlock = 0;
+        }
+        pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
+
+        pSLL->next = pPrevSLL->next;
+        pSLL->edgelist = (EdgeTableEntry *)NULL;
+        pPrevSLL->next = pSLL;
+    }
+    pSLL->scanline = scanline;
+
+    /*
+     * now insert the edge in the right bucket
+     */
+    prev = (EdgeTableEntry *)NULL;
+    start = pSLL->edgelist;
+    while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) 
+    {
+        prev = start;
+        start = start->next;
+    }
+    ETE->next = start;
+
+    if (prev)
+        prev->next = ETE;
+    else
+        pSLL->edgelist = ETE;
+}
+\f
+/*
+ *     CreateEdgeTable
+ *
+ *     This routine creates the edge table for
+ *     scan converting polygons. 
+ *     The Edge Table (ET) looks like:
+ *
+ *    EdgeTable
+ *     --------
+ *    |  ymax  |        ScanLineLists
+ *    |scanline|-->------------>-------------->...
+ *     --------   |scanline|   |scanline|
+ *                |edgelist|   |edgelist|
+ *                ---------    ---------
+ *                    |             |
+ *                    |             |
+ *                    V             V
+ *              list of ETEs   list of ETEs
+ *
+ *     where ETE is an EdgeTableEntry data structure,
+ *     and there is one ScanLineList per scanline at
+ *     which an edge is initially entered.
+ *
+ */
+
+static void
+CreateETandAET(count, pts, ET, AET, pETEs, pSLLBlock)
+    int count;
+    GdkPoint *pts;
+    EdgeTable *ET;
+    EdgeTableEntry *AET;
+    EdgeTableEntry *pETEs;
+    ScanLineListBlock   *pSLLBlock;
+{
+    GdkPoint *top, *bottom;
+    GdkPoint *PrevPt, *CurrPt;
+    int iSLLBlock = 0;
+    int dy;
+
+    if (count < 2)  return;
+
+    /*
+     *  initialize the Active Edge Table
+     */
+    AET->next = (EdgeTableEntry *)NULL;
+    AET->back = (EdgeTableEntry *)NULL;
+    AET->nextWETE = (EdgeTableEntry *)NULL;
+    AET->bres.minor_axis = SMALL_COORDINATE;
+
+    /*
+     *  initialize the Edge Table.
+     */
+    ET->scanlines.next = (ScanLineList *)NULL;
+    ET->ymax = SMALL_COORDINATE;
+    ET->ymin = LARGE_COORDINATE;
+    pSLLBlock->next = (ScanLineListBlock *)NULL;
+
+    PrevPt = &pts[count-1];
+
+    /*
+     *  for each vertex in the array of points.
+     *  In this loop we are dealing with two vertices at
+     *  a time -- these make up one edge of the polygon.
+     */
+    while (count--) 
+    {
+        CurrPt = pts++;
+
+        /*
+         *  find out which point is above and which is below.
+         */
+        if (PrevPt->y > CurrPt->y) 
+        {
+            bottom = PrevPt, top = CurrPt;
+            pETEs->ClockWise = 0;
+        }
+        else 
+        {
+            bottom = CurrPt, top = PrevPt;
+            pETEs->ClockWise = 1;
+        }
+
+        /*
+         * don't add horizontal edges to the Edge table.
+         */
+        if (bottom->y != top->y) 
+        {
+            pETEs->ymax = bottom->y-1;  /* -1 so we don't get last scanline */
+
+            /*
+             *  initialize integer edge algorithm
+             */
+            dy = bottom->y - top->y;
+            BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
+
+            InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock);
+
+           if (PrevPt->y > ET->ymax)
+               ET->ymax = PrevPt->y;
+           if (PrevPt->y < ET->ymin)
+               ET->ymin = PrevPt->y;
+            pETEs++;
+        }
+
+        PrevPt = CurrPt;
+    }
+}
+\f
+/*
+ *     loadAET
+ *
+ *     This routine moves EdgeTableEntries from the
+ *     EdgeTable into the Active Edge Table,
+ *     leaving them sorted by smaller x coordinate.
+ *
+ */
+
+static void
+loadAET(AET, ETEs)
+    EdgeTableEntry *AET, *ETEs;
+{
+    EdgeTableEntry *pPrevAET;
+    EdgeTableEntry *tmp;
+
+    pPrevAET = AET;
+    AET = AET->next;
+    while (ETEs) 
+    {
+        while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis)) 
+        {
+            pPrevAET = AET;
+            AET = AET->next;
+        }
+        tmp = ETEs->next;
+        ETEs->next = AET;
+        if (AET)
+            AET->back = ETEs;
+        ETEs->back = pPrevAET;
+        pPrevAET->next = ETEs;
+        pPrevAET = ETEs;
+
+        ETEs = tmp;
+    }
+}
+\f
+/*
+ *     computeWAET
+ *
+ *     This routine links the AET by the
+ *     nextWETE (winding EdgeTableEntry) link for
+ *     use by the winding number rule.  The final 
+ *     Active Edge Table (AET) might look something
+ *     like:
+ *
+ *     AET
+ *     ----------  ---------   ---------
+ *     |ymax    |  |ymax    |  |ymax    | 
+ *     | ...    |  |...     |  |...     |
+ *     |next    |->|next    |->|next    |->...
+ *     |nextWETE|  |nextWETE|  |nextWETE|
+ *     ---------   ---------   ^--------
+ *         |                   |       |
+ *         V------------------->       V---> ...
+ *
+ */
+static void
+computeWAET(AET)
+    EdgeTableEntry *AET;
+{
+    EdgeTableEntry *pWETE;
+    int inside = 1;
+    int isInside = 0;
+
+    AET->nextWETE = (EdgeTableEntry *)NULL;
+    pWETE = AET;
+    AET = AET->next;
+    while (AET) 
+    {
+        if (AET->ClockWise)
+            isInside++;
+        else
+            isInside--;
+
+        if ((!inside && !isInside) ||
+            ( inside &&  isInside)) 
+        {
+            pWETE->nextWETE = AET;
+            pWETE = AET;
+            inside = !inside;
+        }
+        AET = AET->next;
+    }
+    pWETE->nextWETE = (EdgeTableEntry *)NULL;
+}
+\f
+/*
+ *     InsertionSort
+ *
+ *     Just a simple insertion sort using
+ *     pointers and back pointers to sort the Active
+ *     Edge Table.
+ *
+ */
+
+static int
+InsertionSort(AET)
+    EdgeTableEntry *AET;
+{
+    EdgeTableEntry *pETEchase;
+    EdgeTableEntry *pETEinsert;
+    EdgeTableEntry *pETEchaseBackTMP;
+    int changed = 0;
+
+    AET = AET->next;
+    while (AET) 
+    {
+        pETEinsert = AET;
+        pETEchase = AET;
+        while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
+            pETEchase = pETEchase->back;
+
+        AET = AET->next;
+        if (pETEchase != pETEinsert) 
+        {
+            pETEchaseBackTMP = pETEchase->back;
+            pETEinsert->back->next = AET;
+            if (AET)
+                AET->back = pETEinsert->back;
+            pETEinsert->next = pETEchase;
+            pETEchase->back->next = pETEinsert;
+            pETEchase->back = pETEinsert;
+            pETEinsert->back = pETEchaseBackTMP;
+            changed = 1;
+        }
+    }
+    return(changed);
+}
+\f
+/*
+ *     Clean up our act.
+ */
+static void
+FreeStorage(pSLLBlock)
+    ScanLineListBlock   *pSLLBlock;
+{
+    ScanLineListBlock   *tmpSLLBlock;
+
+    while (pSLLBlock) 
+    {
+        tmpSLLBlock = pSLLBlock->next;
+        g_free (pSLLBlock);
+        pSLLBlock = tmpSLLBlock;
+    }
+}
+
+/*
+ *     Create an array of rectangles from a list of points.
+ *     If indeed these things (POINTS, RECTS) are the same,
+ *     then this proc is still needed, because it allocates
+ *     storage for the array, which was allocated on the
+ *     stack by the calling procedure.
+ *
+ */
+static int PtsToRegion(numFullPtBlocks, iCurPtBlock, FirstPtBlock, reg)
+    int  numFullPtBlocks, iCurPtBlock;
+    POINTBLOCK *FirstPtBlock;
+    GdkRegion *reg;
+{
+    GdkRegionBox *rects;
+    GdkPoint *pts;
+    POINTBLOCK *CurPtBlock;
+    int i;
+    GdkRegionBox *extents;
+    int numRects;
+
+    extents = &reg->extents;
+    numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
+    reg->rects = g_renew (GdkRegionBox, reg->rects, numRects);
+    reg->size = numRects;
+    CurPtBlock = FirstPtBlock;
+    rects = reg->rects - 1;
+    numRects = 0;
+    extents->x1 = G_MAXSHORT,  extents->x2 = G_MINSHORT;
+    for ( ; numFullPtBlocks >= 0; numFullPtBlocks--) {
+       /* the loop uses 2 points per iteration */
+       i = NUMPTSTOBUFFER >> 1;
+       if (!numFullPtBlocks)
+           i = iCurPtBlock >> 1;
+       for (pts = CurPtBlock->pts; i--; pts += 2) {
+           if (pts->x == pts[1].x)
+               continue;
+           if (numRects && pts->x == rects->x1 && pts->y == rects->y2 &&
+               pts[1].x == rects->x2 &&
+               (numRects == 1 || rects[-1].y1 != rects->y1) &&
+               (i && pts[2].y > pts[1].y)) {
+               rects->y2 = pts[1].y + 1;
+               continue;
+           }
+           numRects++;
+           rects++;
+           rects->x1 = pts->x;  rects->y1 = pts->y;
+           rects->x2 = pts[1].x;  rects->y2 = pts[1].y + 1;
+           if (rects->x1 < extents->x1)
+               extents->x1 = rects->x1;
+           if (rects->x2 > extents->x2)
+               extents->x2 = rects->x2;
+        }
+       CurPtBlock = CurPtBlock->next;
+    }
+
+    if (numRects) {
+       extents->y1 = reg->rects->y1;
+       extents->y2 = rects->y2;
+    } else {
+       extents->x1 = 0;
+       extents->y1 = 0;
+       extents->x2 = 0;
+       extents->y2 = 0;
+    }
+    reg->numRects = numRects;
+    return(TRUE);
+}
+
+/*
+ *     polytoregion
+ *
+ *     Scan converts a polygon by returning a run-length
+ *     encoding of the resultant bitmap -- the run-length
+ *     encoding is in the form of an array of rectangles.
+ */
+GdkRegion *
+gdk_region_polygon(GdkPoint *Pts, gint Count, GdkFillRule rule)
+{
+    GdkRegion *region;
+    EdgeTableEntry *pAET;   /* Active Edge Table       */
+    int y;                  /* current scanline        */
+    int iPts = 0;           /* number of pts in buffer */
+    EdgeTableEntry *pWETE;  /* Winding Edge Table Entry*/
+    ScanLineList *pSLL;     /* current scanLineList    */
+    GdkPoint *pts;             /* output buffer           */
+    EdgeTableEntry *pPrevAET;        /* ptr to previous AET     */
+    EdgeTable ET;                    /* header node for ET      */
+    EdgeTableEntry AET;              /* header node for AET     */
+    EdgeTableEntry *pETEs;           /* EdgeTableEntries pool   */
+    ScanLineListBlock SLLBlock;      /* header for scanlinelist */
+    int fixWAET = FALSE;
+    POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers    */
+    POINTBLOCK *tmpPtBlock;
+    int numFullPtBlocks = 0;
+    region = gdk_region_new ();
+
+    /* special case a rectangle */
+    pts = Pts;
+    if (((Count == 4) ||
+        ((Count == 5) && (pts[4].x == pts[0].x) && (pts[4].y == pts[0].y))) &&
+       (((pts[0].y == pts[1].y) &&
+         (pts[1].x == pts[2].x) &&
+         (pts[2].y == pts[3].y) &&
+         (pts[3].x == pts[0].x)) ||
+        ((pts[0].x == pts[1].x) &&
+         (pts[1].y == pts[2].y) &&
+         (pts[2].x == pts[3].x) &&
+         (pts[3].y == pts[0].y)))) {
+       region->extents.x1 = MIN(pts[0].x, pts[2].x);
+       region->extents.y1 = MIN(pts[0].y, pts[2].y);
+       region->extents.x2 = MAX(pts[0].x, pts[2].x);
+       region->extents.y2 = MAX(pts[0].y, pts[2].y);
+       if ((region->extents.x1 != region->extents.x2) &&
+           (region->extents.y1 != region->extents.y2)) {
+           region->numRects = 1;
+           *(region->rects) = region->extents;
+       }
+       return(region);
+    }
+
+    pETEs = g_new (EdgeTableEntry, Count);
+
+    pts = FirstPtBlock.pts;
+    CreateETandAET(Count, Pts, &ET, &AET, pETEs, &SLLBlock);
+    pSLL = ET.scanlines.next;
+    curPtBlock = &FirstPtBlock;
+    if (rule == GDK_EVEN_ODD_RULE) {
+        /*
+         *  for each scanline
+         */
+        for (y = ET.ymin; y < ET.ymax; y++) {
+            /*
+             *  Add a new edge to the active edge table when we
+             *  get to the next edge.
+             */
+            if (pSLL != NULL && y == pSLL->scanline) {
+                loadAET(&AET, pSLL->edgelist);
+                pSLL = pSLL->next;
+            }
+            pPrevAET = &AET;
+            pAET = AET.next;
+            /*
+             *  for each active edge
+             */
+            while (pAET) {
+                pts->x = pAET->bres.minor_axis,  pts->y = y;
+                pts++, iPts++;
+                /*
+                 *  send out the buffer
+                 */
+                if (iPts == NUMPTSTOBUFFER) {
+                    tmpPtBlock = (POINTBLOCK *)g_malloc(sizeof(POINTBLOCK));
+                    curPtBlock->next = tmpPtBlock;
+                    curPtBlock = tmpPtBlock;
+                    pts = curPtBlock->pts;
+                    numFullPtBlocks++;
+                    iPts = 0;
+                }
+                EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
+            }
+            (void) InsertionSort(&AET);
+        }
+    }
+    else {
+        /*
+         *  for each scanline
+         */
+        for (y = ET.ymin; y < ET.ymax; y++) {
+            /*
+             *  Add a new edge to the active edge table when we
+             *  get to the next edge.
+             */
+            if (pSLL != NULL && y == pSLL->scanline) {
+                loadAET(&AET, pSLL->edgelist);
+                computeWAET(&AET);
+                pSLL = pSLL->next;
+            }
+            pPrevAET = &AET;
+            pAET = AET.next;
+            pWETE = pAET;
+            /*
+             *  for each active edge
+             */
+            while (pAET) {
+                /*
+                 *  add to the buffer only those edges that
+                 *  are in the Winding active edge table.
+                 */
+                if (pWETE == pAET) {
+                    pts->x = pAET->bres.minor_axis,  pts->y = y;
+                    pts++, iPts++;
+                    /*
+                     *  send out the buffer
+                     */
+                    if (iPts == NUMPTSTOBUFFER) {
+                        tmpPtBlock = (POINTBLOCK *)g_malloc(sizeof(POINTBLOCK));
+                        curPtBlock->next = tmpPtBlock;
+                        curPtBlock = tmpPtBlock;
+                        pts = curPtBlock->pts;
+                        numFullPtBlocks++;    iPts = 0;
+                    }
+                    pWETE = pWETE->nextWETE;
+                }
+                EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
+            }
+            /*
+             *  recompute the winding active edge table if
+             *  we just resorted or have exited an edge.
+             */
+            if (InsertionSort(&AET) || fixWAET) {
+                computeWAET(&AET);
+                fixWAET = FALSE;
+            }
+        }
+    }
+    FreeStorage(SLLBlock.next);        
+    (void) PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
+    for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
+       tmpPtBlock = curPtBlock->next;
+       g_free (curPtBlock);
+       curPtBlock = tmpPtBlock;
+    }
+    g_free (pETEs);
+    return(region);
+}
diff --git a/gdk/linux-fb/gdkprivate-fb.h b/gdk/linux-fb/gdkprivate-fb.h
new file mode 100644 (file)
index 0000000..2ad3a04
--- /dev/null
@@ -0,0 +1,194 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+/*
+ * Private uninstalled header defining things local to X windowing code
+ */
+
+#ifndef __GDK_PRIVATE_FB_H__
+#define __GDK_PRIVATE_FB_H__
+
+#include <gdk/gdkprivate.h>
+#include <gdk/gdk.h>
+#include "gdkfb.h"
+#include "gdkregion-generic.h"
+#include <linux/fb.h>
+#include <stdio.h>
+
+#define GDK_DRAWABLE_FBDATA(win) ((GdkDrawableFBData *)(((GdkDrawablePrivate*)(win))->klass_data))
+#define GDK_PIXMAP_FBDATA(win) ((GdkPixmapFBData *)(((GdkDrawablePrivate*)(win))->klass_data))
+#define GDK_WINDOW_FBDATA(win) ((GdkWindowFBData *)(((GdkDrawablePrivate*)(win))->klass_data))
+#define GDK_FONT_FB(f) ((GdkFontPrivateFB *)(f))
+#define GDK_CURSOR_FB(c) ((GdkCursorPrivateFB *)(c))
+
+typedef struct _GdkDrawableFBData GdkDrawableFBData;
+typedef struct _GdkWindowFBData GdkWindowFBData;
+
+struct _GdkDrawableFBData
+{
+  guchar *mem;
+
+  gint abs_x, abs_y, lim_x, lim_y, llim_x, llim_y; /* computed values */
+
+  guint rowstride;
+};
+
+struct _GdkPixmapFBData
+{
+  GdkDrawableFBData drawable_data;
+};
+
+typedef struct {
+  gulong length;
+  GdkAtom type;
+  gint format;
+  guchar data[1];
+} GdkWindowProperty;
+
+struct _GdkWindowFBData
+{
+  GdkDrawableFBData drawable_data;
+  GdkCursor *cursor;
+  GHashTable *properties;
+
+  GdkEventMask event_mask;
+  gint level;
+  gboolean realized : 1;
+};
+
+struct _GdkFBDisplay
+{
+  int fd;
+  guchar *fbmem;
+  gpointer active_cmap;
+  gulong mem_len;
+  struct fb_fix_screeninfo sinfo;
+  struct fb_var_screeninfo modeinfo;
+};
+
+typedef struct {
+  GdkVisual base;
+} GdkVisualPrivateFB;
+
+typedef struct {
+  GdkColormapPrivate base;
+
+  GHashTable *hash;
+  GdkColorInfo *info;
+  guint sync_tag;
+} GdkColormapPrivateFB;
+
+typedef struct {
+  GdkCursor base;
+  GdkPixmap *cursor, *mask;
+} GdkCursorPrivateFB;
+
+typedef struct {
+  GdkFontPrivate base;
+
+  int t1_font_id;
+  double size;
+  GSList *names;
+} GdkFontPrivateFB;
+
+typedef struct {
+  GdkImagePrivate base;
+} GdkImagePrivateFB;
+
+#define GDK_GC_FBDATA(x) ((GdkGCFBData *)((GdkGCPrivate *)x)->klass_data)
+typedef struct {
+  GdkRegion *clip_region;
+  gchar *dash_list;
+  GdkGCValuesMask values_mask;
+  GdkGCValues values;
+  gint dash_offset;
+  gushort dash_list_len;
+  guchar depth, alu;
+} GdkGCFBData;
+
+GdkGC *       _gdk_fb_gc_new          (GdkDrawable     *drawable,
+                                      GdkGCValues     *values,
+                                      GdkGCValuesMask  values_mask);
+
+/* Routines from gdkgeometry-fb.c */
+
+void _gdk_window_init_position     (GdkWindow    *window);
+void _gdk_window_move_resize_child (GdkWindow    *window,
+                                   gint          x,
+                                   gint          y,
+                                   gint          width,
+                                   gint          height);
+void _gdk_window_process_expose    (GdkWindow    *window,
+                                   gulong        serial,
+                                   GdkRectangle *area);
+GdkGC *_gdk_fb_gc_new(GdkDrawable *drawable, GdkGCValues *values, GdkGCValuesMask values_mask);
+
+void gdk_fb_drawable_clear(GdkDrawable *drawable);
+void gdk_fb_draw_drawable  (GdkDrawable    *drawable,
+                           GdkGC          *gc,
+                           GdkPixmap      *src,
+                           gint            xsrc,
+                           gint            ysrc,
+                           gint            xdest,
+                           gint            ydest,
+                           gint            width,
+                           gint            height);
+void gdk_fb_draw_drawable_2 (GdkDrawable *drawable,
+                            GdkGC       *gc,
+                            GdkPixmap   *src,
+                            gint         xsrc,
+                            gint         ysrc,
+                            gint         xdest,
+                            gint         ydest,
+                            gint         width,
+                            gint         height,
+                            gboolean     draw_bg,
+                            gboolean     do_clipping);
+void gdk_fb_draw_rectangle (GdkDrawable    *drawable,
+                           GdkGC          *gc,
+                           gint            filled,
+                           gint            x,
+                           gint            y,
+                           gint            width,
+                           gint            height);
+void gdk_fb_fill_spans(GdkDrawable *drawable, GdkGC *gc, GdkRectangle *rects, int nrects);
+
+extern GdkWindow *_gdk_fb_pointer_grab_window, *_gdk_fb_keyboard_grab_window, *_gdk_fb_pointer_grab_confine;
+extern GdkEventMask _gdk_fb_pointer_grab_events, _gdk_fb_keyboard_grab_events;
+extern GdkCursor *_gdk_fb_pointer_grab_cursor;
+extern GdkFBDisplay *gdk_display;
+extern GdkDrawableClass _gdk_fb_drawable_class;
+extern FILE *debug_out;
+GdkEvent *gdk_event_make(GdkWindow *window, GdkEventType type, gboolean append_to_queue);
+
+void gdk_fb_get_cursor_rect(GdkRectangle *rect);
+void gdk_fb_cursor_unhide(void);
+void gdk_fb_cursor_hide(void);
+void gdk_fb_redraw_all(void);
+
+void gdk_input_ps2_get_mouseinfo(gint *x, gint *y, GdkModifierType *mask);
+
+#endif /* __GDK_PRIVATE_FB_H__ */
diff --git a/gdk/linux-fb/gdkproperty-fb.c b/gdk/linux-fb/gdkproperty-fb.c
new file mode 100644 (file)
index 0000000..e251e71
--- /dev/null
@@ -0,0 +1,204 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include <string.h>
+#include <time.h>
+
+#include "gdkfb.h"
+#include "gdkproperty.h"
+#include "gdkprivate.h"
+#include "gdkprivate-fb.h"
+
+GdkAtom
+gdk_atom_intern (const gchar *atom_name,
+                gboolean     only_if_exists)
+{
+  g_return_val_if_fail (atom_name != NULL, GDK_NONE);
+
+  return g_quark_from_string(atom_name);
+}
+
+gchar*
+gdk_atom_name (GdkAtom atom)
+{
+  return g_quark_to_string(atom);
+}
+
+static void
+gdk_property_delete_2 (GdkWindow *window,
+                      GdkAtom property,
+                      GdkWindowProperty *prop)
+{
+  GdkWindowFBData *fbd = GDK_WINDOW_FBDATA(window);
+  GdkEvent *event;
+  
+  g_hash_table_remove(fbd->properties, GUINT_TO_POINTER(property));
+  g_free(prop);
+
+  event = gdk_event_make(window, GDK_PROPERTY_NOTIFY, TRUE);
+  if(event)
+    {
+      event->property.atom = property;
+      event->property.state = GDK_PROPERTY_DELETE;
+    }
+}
+
+void
+gdk_property_delete (GdkWindow *window,
+                    GdkAtom    property)
+{
+  GdkWindowFBData *fbd = GDK_WINDOW_FBDATA(window);
+  GdkWindowProperty *prop;
+
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  if(!fbd->properties)
+    return;
+
+  prop = g_hash_table_lookup(fbd->properties, GUINT_TO_POINTER(property));
+  if(!prop)
+    return;
+
+  gdk_property_delete_2(window, property, prop);
+}
+
+gint
+gdk_property_get (GdkWindow   *window,
+                 GdkAtom      property,
+                 GdkAtom      type,
+                 gulong       offset,
+                 gulong       length,
+                 gint         pdelete,
+                 GdkAtom     *actual_property_type,
+                 gint        *actual_format_type,
+                 gint        *actual_length,
+                 guchar     **data)
+{
+  GdkWindowFBData *fbd = GDK_WINDOW_FBDATA(window);
+  GdkWindowProperty *prop;
+  int nbytes;
+
+  g_return_val_if_fail (window != NULL, FALSE);
+  g_return_val_if_fail (data != NULL, FALSE);
+  g_return_val_if_fail (actual_length != NULL, FALSE);
+  g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
+
+  if(!fbd->properties)
+    return FALSE;
+
+  prop = g_hash_table_lookup(fbd->properties, GUINT_TO_POINTER(property));
+  if(!prop)
+    return FALSE;
+
+  nbytes = (offset + length * (prop->format >> 3)) - prop->length;
+  nbytes = MAX(nbytes, 0);
+  if(nbytes > 0)
+    {
+      *data = g_malloc(nbytes+1);
+      memcpy(data, prop->data + offset, nbytes);
+      (*data)[nbytes] = 0;
+    }
+  else
+    *data = NULL;
+  *actual_length = nbytes / (prop->format >> 3);
+  *actual_property_type = prop->type;
+  *actual_format_type = prop->format;
+
+  if(pdelete)
+    gdk_property_delete_2(window, property, prop);
+
+  return TRUE;
+}
+
+void
+gdk_property_change (GdkWindow   *window,
+                    GdkAtom      property,
+                    GdkAtom      type,
+                    gint         format,
+                    GdkPropMode  mode,
+                    const guchar *data,
+                    gint         nelements)
+{
+  GdkWindowFBData *fbd = GDK_WINDOW_FBDATA(window);
+  GdkWindowProperty *prop, *new_prop;
+  int new_size;
+  GdkEvent *event;
+
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  if(!fbd->properties)
+    fbd->properties = g_hash_table_new(NULL, NULL);
+
+  prop = g_hash_table_lookup(fbd->properties, GUINT_TO_POINTER(property));
+
+  switch(mode)
+    {
+    case GDK_PROP_MODE_REPLACE:
+      new_size = nelements * (format >> 3);
+      break;
+    case GDK_PROP_MODE_PREPEND:
+    case GDK_PROP_MODE_APPEND:
+      new_size = nelements * (format >> 3);
+      if(prop)
+       new_size += prop->length;
+    default:
+      break;
+    }
+
+  new_prop = g_malloc(G_STRUCT_OFFSET(GdkWindowProperty, data) + new_size);
+  new_prop->length = new_size;
+  new_prop->type = type;
+  new_prop->format = format;
+
+  switch(mode)
+    {
+    case GDK_PROP_MODE_REPLACE:
+      memcpy(new_prop->data, data, new_size);
+      break;
+    case GDK_PROP_MODE_APPEND:
+      if(prop)
+       memcpy(new_prop->data, prop->data, prop->length);
+      memcpy(new_prop->data + prop->length, data, (nelements * (format >> 3)));
+      break;
+    case GDK_PROP_MODE_PREPEND:
+      memcpy(new_prop->data, data, (nelements * (format >> 3)));
+      if(prop)
+       memcpy(new_prop->data + (nelements * (format >> 3)), prop->data, prop->length);
+      break;
+    }
+
+  g_hash_table_insert(fbd->properties, GUINT_TO_POINTER(property), new_prop);
+  g_free(prop);
+
+  event = gdk_event_make(window, GDK_PROPERTY_NOTIFY, TRUE);
+  if(event)
+    {
+      event->property.atom = property;
+      event->property.state = GDK_PROPERTY_NEW_VALUE;
+    }
+}
diff --git a/gdk/linux-fb/gdkregion-generic.c b/gdk/linux-fb/gdkregion-generic.c
new file mode 100644 (file)
index 0000000..1140ce0
--- /dev/null
@@ -0,0 +1,1505 @@
+/* $TOG: Region.c /main/31 1998/02/06 17:50:22 kaleb $ */
+/************************************************************************
+
+Copyright 1987, 1988, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+************************************************************************/
+/* $XFree86: xc/lib/X11/Region.c,v 1.5 1999/05/09 10:50:01 dawes Exp $ */
+/*
+ * The functions in this file implement the Region abstraction, similar to one
+ * used in the X11 sample server. A Region is simply an area, as the name
+ * implies, and is implemented as a "y-x-banded" array of rectangles. To
+ * explain: Each Region is made up of a certain number of rectangles sorted
+ * by y coordinate first, and then by x coordinate.
+ *
+ * Furthermore, the rectangles are banded such that every rectangle with a
+ * given upper-left y coordinate (y1) will have the same lower-right y
+ * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
+ * will span the entire vertical distance of the band. This means that some
+ * areas that could be merged into a taller rectangle will be represented as
+ * several shorter rectangles to account for shorter rectangles to its left
+ * or right but within its "vertical scope".
+ *
+ * An added constraint on the rectangles is that they must cover as much
+ * horizontal area as possible. E.g. no two rectangles in a band are allowed
+ * to touch.
+ *
+ * Whenever possible, bands will be merged together to cover a greater vertical
+ * distance (and thus reduce the number of rectangles). Two bands can be merged
+ * only if the bottom of one touches the top of the other and they have
+ * rectangles in the same places (of the same width, of course). This maintains
+ * the y-x-banding that's so nice to have...
+ */
+
+#include <gdkregion.h>
+#include "gdkregion-generic.h"
+
+#ifdef DEBUG
+#include <stdio.h>
+#define assert(expr) {if (!(expr)) fprintf(stderr,\
+"Assertion failed file %s, line %d: expr\n", __FILE__, __LINE__); }
+#else
+#define assert(expr)
+#endif
+
+typedef void (*overlapFunc) (GdkRegion    *pReg,
+                            GdkRegionBox *r1,
+                            GdkRegionBox *r1End,
+                            GdkRegionBox *r2,
+                            GdkRegionBox *r2End,
+                            gint          y1,
+                            gint          y2);
+typedef void (*nonOverlapFunc) (GdkRegion    *pReg,
+                               GdkRegionBox *r,
+                               GdkRegionBox *rEnd,
+                               gint          y1,
+                               gint          y2);
+
+static void miRegionCopy (GdkRegion      *dstrgn,
+                         GdkRegion      *rgn);
+static void miRegionOp   (GdkRegion      *newReg,
+                         GdkRegion      *reg1,
+                         GdkRegion      *reg2,
+                         overlapFunc     overlapFn,
+                         nonOverlapFunc  nonOverlap1Fn,
+                         nonOverlapFunc  nonOverlap2Fn);
+
+/*     Create a new empty region       */
+
+GdkRegion *
+gdk_region_new ()
+{
+  GdkRegion *temp;
+
+  temp = g_new (GdkRegion, 1);
+  temp->rects = g_new (GdkRegionBox, 1);
+
+  temp->numRects = 0;
+  temp->extents.x1 = 0;
+  temp->extents.y1 = 0;
+  temp->extents.x2 = 0;
+  temp->extents.y2 = 0;
+  temp->size = 1;
+  
+  return temp;
+}
+
+GdkRegion *
+gdk_region_rectangle (GdkRectangle *rectangle)
+{
+  GdkRegion *temp;
+
+  if (rectangle->width <= 0 || rectangle->height <= 0)
+    return gdk_region_new();
+
+  temp = g_new (GdkRegion, 1);
+  temp->rects = g_new (GdkRegionBox, 1);
+
+  temp->numRects = 1;
+  temp->extents.x1 = temp->rects[0].x1 = rectangle->x;
+  temp->extents.y1 = temp->rects[0].y1 = rectangle->y;
+  temp->extents.x2 = temp->rects[0].x2 = rectangle->x + rectangle->width;
+  temp->extents.y2 = temp->rects[0].y2 = rectangle->y + rectangle->height;
+  temp->size = 1;
+  
+  return temp;
+}
+
+GdkRegion *
+gdk_region_copy (GdkRegion *region)
+{
+  GdkRegion *temp;
+
+  temp = g_new (GdkRegion, 1);
+  temp->rects = g_new (GdkRegionBox, region->numRects);
+
+  temp->numRects = region->numRects;
+  temp->extents = region->extents;
+  temp->size = region->numRects;
+  
+  memcpy (temp->rects, region->rects, region->numRects * sizeof (GdkRegionBox));
+
+  return temp;
+}
+
+void
+gdk_region_get_clipbox (GdkRegion *r, GdkRectangle *rect)
+{
+  rect->x = r->extents.x1;
+  rect->y = r->extents.y1;
+  rect->width = r->extents.x2 - r->extents.x1;
+  rect->height = r->extents.y2 - r->extents.y1;
+}
+
+void
+gdk_region_union_with_rect (GdkRegion    *region,
+                           GdkRectangle *rect)
+{
+  GdkRegion tmp_region;
+
+  if (!rect->width || !rect->height)
+    return;
+    
+  tmp_region.rects = &tmp_region.extents;
+  tmp_region.numRects = 1;
+  tmp_region.extents.x1 = rect->x;
+  tmp_region.extents.y1 = rect->y;
+  tmp_region.extents.x2 = rect->x + rect->width;
+  tmp_region.extents.y2 = rect->y + rect->height;
+  tmp_region.size = 1;
+
+  gdk_region_union (region, &tmp_region);
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * miSetExtents --
+ *     Reset the extents of a region to what they should be. Called by
+ *     miSubtract and miIntersect b/c they can't figure it out along the
+ *     way or do so easily, as miUnion can.
+ *
+ * Results:
+ *     None.
+ *
+ * Side Effects:
+ *     The region's 'extents' structure is overwritten.
+ *
+ *-----------------------------------------------------------------------
+ */
+static void
+miSetExtents (GdkRegion *pReg)
+{
+  GdkRegionBox *pBox, *pBoxEnd, *pExtents;
+
+  if (pReg->numRects == 0)
+    {
+      pReg->extents.x1 = 0;
+      pReg->extents.y1 = 0;
+      pReg->extents.x2 = 0;
+      pReg->extents.y2 = 0;
+      return;
+    }
+
+  pExtents = &pReg->extents;
+  pBox = pReg->rects;
+  pBoxEnd = &pBox[pReg->numRects - 1];
+
+    /*
+     * Since pBox is the first rectangle in the region, it must have the
+     * smallest y1 and since pBoxEnd is the last rectangle in the region,
+     * it must have the largest y2, because of banding. Initialize x1 and
+     * x2 from  pBox and pBoxEnd, resp., as good things to initialize them
+     * to...
+     */
+  pExtents->x1 = pBox->x1;
+  pExtents->y1 = pBox->y1;
+  pExtents->x2 = pBoxEnd->x2;
+  pExtents->y2 = pBoxEnd->y2;
+
+  assert(pExtents->y1 < pExtents->y2);
+  while (pBox <= pBoxEnd)
+    {
+      if (pBox->x1 < pExtents->x1)
+       {
+         pExtents->x1 = pBox->x1;
+       }
+      if (pBox->x2 > pExtents->x2)
+       {
+         pExtents->x2 = pBox->x2;
+       }
+      pBox++;
+    }
+  assert(pExtents->x1 < pExtents->x2);
+}
+
+void
+gdk_region_destroy (GdkRegion *r)
+{
+    g_free (r->rects);
+    g_free (r);
+}
+
+
+/* TranslateRegion(pRegion, x, y)
+   translates in place
+   added by raymond
+*/
+
+void
+gdk_region_offset (GdkRegion *region,
+                  gint       x,
+                  gint       y)
+{
+  int nbox;
+  GdkRegionBox *pbox;
+
+  pbox = region->rects;
+  nbox = region->numRects;
+
+  while(nbox--)
+    {
+      pbox->x1 += x;
+      pbox->x2 += x;
+      pbox->y1 += y;
+      pbox->y2 += y;
+      pbox++;
+    }
+  region->extents.x1 += x;
+  region->extents.x2 += x;
+  region->extents.y1 += y;
+  region->extents.y2 += y;
+}
+
+/* 
+   Utility procedure Compress:
+   Replace r by the region r', where 
+     p in r' iff (Quantifer m <= dx) (p + m in r), and
+     Quantifier is Exists if grow is TRUE, For all if grow is FALSE, and
+     (x,y) + m = (x+m,y) if xdir is TRUE; (x,y+m) if xdir is FALSE.
+
+   Thus, if xdir is TRUE and grow is FALSE, r is replaced by the region
+   of all points p such that p and the next dx points on the same
+   horizontal scan line are all in r.  We do this using by noting
+   that p is the head of a run of length 2^i + k iff p is the head
+   of a run of length 2^i and p+2^i is the head of a run of length
+   k. Thus, the loop invariant: s contains the region corresponding
+   to the runs of length shift.  r contains the region corresponding
+   to the runs of length 1 + dxo & (shift-1), where dxo is the original
+   value of dx.  dx = dxo & ~(shift-1).  As parameters, s and t are
+   scratch regions, so that we don't have to allocate them on every
+   call.
+*/
+
+#define ZOpRegion(a,b) if (grow) gdk_region_union (a, b); \
+                        else gdk_region_intersect (a,b)
+#define ZShiftRegion(a,b) if (xdir) gdk_region_offset (a,b,0); \
+                         else gdk_region_offset (a,0,b)
+
+static void
+Compress(GdkRegion *r,
+        GdkRegion *s,
+        GdkRegion *t,
+        guint      dx,
+        int        xdir,
+        int        grow)
+{
+  guint shift = 1;
+
+  miRegionCopy (s, r);
+  while (dx)
+    {
+      if (dx & shift)
+       {
+         ZShiftRegion(r, -(int)shift);
+         ZOpRegion(r, s);
+         dx -= shift;
+         if (!dx) break;
+        }
+      miRegionCopy (t, s);
+      ZShiftRegion(s, -(int)shift);
+      ZOpRegion(s, t);
+      shift <<= 1;
+    }
+}
+
+#undef ZOpRegion
+#undef ZShiftRegion
+#undef ZCopyRegion
+
+void
+gdk_region_shrink (GdkRegion *r,
+                  int        dx,
+                  int        dy)
+{
+  GdkRegion *s, *t;
+  int grow;
+
+  if (!dx && !dy)
+    return;
+
+  s = gdk_region_new ();
+  t = gdk_region_new ();
+
+  grow = (dx < 0);
+  if (grow)
+    dx = -dx;
+  if (dx)
+     Compress(r, s, t, (unsigned) 2*dx, TRUE, grow);
+     
+  grow = (dy < 0);
+  if (grow)
+    dy = -dy;
+  if (dy)
+     Compress(r, s, t, (unsigned) 2*dy, FALSE, grow);
+  
+  gdk_region_offset (r, dx, dy);
+  gdk_region_destroy (s);
+  gdk_region_destroy (t);
+}
+
+\f
+/*======================================================================
+ *         Region Intersection
+ *====================================================================*/
+/*-
+ *-----------------------------------------------------------------------
+ * miIntersectO --
+ *     Handle an overlapping band for miIntersect.
+ *
+ * Results:
+ *     None.
+ *
+ * Side Effects:
+ *     Rectangles may be added to the region.
+ *
+ *-----------------------------------------------------------------------
+ */
+/* static void*/
+static void
+miIntersectO (GdkRegion    *pReg,
+             GdkRegionBox *r1,
+             GdkRegionBox *r1End,
+             GdkRegionBox *r2,
+             GdkRegionBox *r2End,
+             gint          y1,
+             gint          y2)
+{
+  int          x1;
+  int          x2;
+  GdkRegionBox *pNextRect;
+
+  pNextRect = &pReg->rects[pReg->numRects];
+
+  while ((r1 != r1End) && (r2 != r2End))
+    {
+      x1 = MAX (r1->x1,r2->x1);
+      x2 = MIN (r1->x2,r2->x2);
+
+      /*
+       * If there's any overlap between the two rectangles, add that
+       * overlap to the new region.
+       * There's no need to check for subsumption because the only way
+       * such a need could arise is if some region has two rectangles
+       * right next to each other. Since that should never happen...
+       */
+      if (x1 < x2)
+       {
+         assert (y1<y2);
+
+         MEMCHECK (pReg, pNextRect, pReg->rects);
+         pNextRect->x1 = x1;
+         pNextRect->y1 = y1;
+         pNextRect->x2 = x2;
+         pNextRect->y2 = y2;
+         pReg->numRects += 1;
+         pNextRect++;
+         assert (pReg->numRects <= pReg->size);
+       }
+
+      /*
+       * Need to advance the pointers. Shift the one that extends
+       * to the right the least, since the other still has a chance to
+       * overlap with that region's next rectangle, if you see what I mean.
+       */
+      if (r1->x2 < r2->x2)
+       {
+         r1++;
+       }
+      else if (r2->x2 < r1->x2)
+       {
+         r2++;
+       }
+      else
+       {
+         r1++;
+         r2++;
+       }
+    }
+}
+
+void
+gdk_region_intersect (GdkRegion *region,
+                     GdkRegion *other)
+{
+  /* check for trivial reject */
+  if ((!(region->numRects)) || (!(other->numRects))  ||
+      (!EXTENTCHECK(&region->extents, &other->extents)))
+    region->numRects = 0;
+  else
+    miRegionOp (region, region, other, 
+               miIntersectO, (nonOverlapFunc) NULL, (nonOverlapFunc) NULL);
+    
+  /*
+   * Can't alter region's extents before miRegionOp depends on the
+   * extents of the regions being unchanged. Besides, this way there's
+   * no checking against rectangles that will be nuked due to
+   * coalescing, so we have to examine fewer rectangles.
+   */
+  miSetExtents(region);
+}
+
+static void
+miRegionCopy(GdkRegion *dstrgn, GdkRegion *rgn)
+{
+  if (dstrgn != rgn) /*  don't want to copy to itself */
+    {  
+      if (dstrgn->size < rgn->numRects)
+        {
+         dstrgn->rects = g_renew (GdkRegionBox, dstrgn->rects, rgn->numRects);
+         dstrgn->size = rgn->numRects;
+       }
+      dstrgn->numRects = rgn->numRects;
+      dstrgn->extents.x1 = rgn->extents.x1;
+      dstrgn->extents.y1 = rgn->extents.y1;
+      dstrgn->extents.x2 = rgn->extents.x2;
+      dstrgn->extents.y2 = rgn->extents.y2;
+
+      memcpy (dstrgn->rects, rgn->rects, rgn->numRects * sizeof (GdkRegionBox));
+    }
+}
+
+
+/*======================================================================
+ *         Generic Region Operator
+ *====================================================================*/
+
+/*-
+ *-----------------------------------------------------------------------
+ * miCoalesce --
+ *     Attempt to merge the boxes in the current band with those in the
+ *     previous one. Used only by miRegionOp.
+ *
+ * Results:
+ *     The new index for the previous band.
+ *
+ * Side Effects:
+ *     If coalescing takes place:
+ *         - rectangles in the previous band will have their y2 fields
+ *           altered.
+ *         - pReg->numRects will be decreased.
+ *
+ *-----------------------------------------------------------------------
+ */
+/* static int*/
+static int
+miCoalesce (GdkRegion *pReg,         /* Region to coalesce */
+           gint       prevStart,    /* Index of start of previous band */
+           gint       curStart)     /* Index of start of current band */
+{
+  GdkRegionBox *pPrevBox;      /* Current box in previous band */
+  GdkRegionBox *pCurBox;       /* Current box in current band */
+  GdkRegionBox *pRegEnd;       /* End of region */
+  int          curNumRects;    /* Number of rectangles in current
+                                * band */
+  int          prevNumRects;   /* Number of rectangles in previous
+                                * band */
+  int          bandY1;         /* Y1 coordinate for current band */
+
+  pRegEnd = &pReg->rects[pReg->numRects];
+
+  pPrevBox = &pReg->rects[prevStart];
+  prevNumRects = curStart - prevStart;
+
+    /*
+     * Figure out how many rectangles are in the current band. Have to do
+     * this because multiple bands could have been added in miRegionOp
+     * at the end when one region has been exhausted.
+     */
+  pCurBox = &pReg->rects[curStart];
+  bandY1 = pCurBox->y1;
+  for (curNumRects = 0;
+       (pCurBox != pRegEnd) && (pCurBox->y1 == bandY1);
+       curNumRects++)
+    {
+      pCurBox++;
+    }
+    
+  if (pCurBox != pRegEnd)
+    {
+      /*
+       * If more than one band was added, we have to find the start
+       * of the last band added so the next coalescing job can start
+       * at the right place... (given when multiple bands are added,
+       * this may be pointless -- see above).
+       */
+      pRegEnd--;
+      while (pRegEnd[-1].y1 == pRegEnd->y1)
+       {
+         pRegEnd--;
+       }
+      curStart = pRegEnd - pReg->rects;
+      pRegEnd = pReg->rects + pReg->numRects;
+    }
+       
+  if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
+    pCurBox -= curNumRects;
+    /*
+     * The bands may only be coalesced if the bottom of the previous
+     * matches the top scanline of the current.
+     */
+    if (pPrevBox->y2 == pCurBox->y1)
+      {
+       /*
+        * Make sure the bands have boxes in the same places. This
+        * assumes that boxes have been added in such a way that they
+        * cover the most area possible. I.e. two boxes in a band must
+        * have some horizontal space between them.
+        */
+       do
+         {
+           if ((pPrevBox->x1 != pCurBox->x1) ||
+               (pPrevBox->x2 != pCurBox->x2))
+             {
+               /*
+                * The bands don't line up so they can't be coalesced.
+                */
+               return (curStart);
+             }
+           pPrevBox++;
+           pCurBox++;
+           prevNumRects -= 1;
+         } while (prevNumRects != 0);
+
+       pReg->numRects -= curNumRects;
+       pCurBox -= curNumRects;
+       pPrevBox -= curNumRects;
+
+       /*
+        * The bands may be merged, so set the bottom y of each box
+        * in the previous band to that of the corresponding box in
+        * the current band.
+        */
+       do
+         {
+           pPrevBox->y2 = pCurBox->y2;
+           pPrevBox++;
+           pCurBox++;
+           curNumRects -= 1;
+         }
+       while (curNumRects != 0);
+
+       /*
+        * If only one band was added to the region, we have to backup
+        * curStart to the start of the previous band.
+        *
+        * If more than one band was added to the region, copy the
+        * other bands down. The assumption here is that the other bands
+        * came from the same region as the current one and no further
+        * coalescing can be done on them since it's all been done
+        * already... curStart is already in the right place.
+        */
+       if (pCurBox == pRegEnd)
+         {
+           curStart = prevStart;
+         }
+       else
+         {
+           do
+             {
+               *pPrevBox++ = *pCurBox++;
+             }
+           while (pCurBox != pRegEnd);
+         }
+           
+      }
+  }
+  return curStart;
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * miRegionOp --
+ *     Apply an operation to two regions. Called by miUnion, miInverse,
+ *     miSubtract, miIntersect...
+ *
+ * Results:
+ *     None.
+ *
+ * Side Effects:
+ *     The new region is overwritten.
+ *
+ * Notes:
+ *     The idea behind this function is to view the two regions as sets.
+ *     Together they cover a rectangle of area that this function divides
+ *     into horizontal bands where points are covered only by one region
+ *     or by both. For the first case, the nonOverlapFunc is called with
+ *     each the band and the band's upper and lower extents. For the
+ *     second, the overlapFunc is called to process the entire band. It
+ *     is responsible for clipping the rectangles in the band, though
+ *     this function provides the boundaries.
+ *     At the end of each band, the new region is coalesced, if possible,
+ *     to reduce the number of rectangles in the region.
+ *
+ *-----------------------------------------------------------------------
+ */
+/* static void*/
+static void
+miRegionOp(GdkRegion *newReg,
+          GdkRegion *reg1,
+          GdkRegion *reg2,
+          overlapFunc    overlapFn,            /* Function to call for over-
+                                                * lapping bands */
+          nonOverlapFunc nonOverlap1Fn,        /* Function to call for non-
+                                                * overlapping bands in region
+                                                * 1 */
+          nonOverlapFunc nonOverlap2Fn)        /* Function to call for non-
+                                                * overlapping bands in region
+                                                * 2 */
+{
+    GdkRegionBox *r1;                  /* Pointer into first region */
+    GdkRegionBox *r2;                  /* Pointer into 2d region */
+    GdkRegionBox *r1End;               /* End of 1st region */
+    GdkRegionBox *r2End;               /* End of 2d region */
+    int          ybot;                 /* Bottom of intersection */
+    int          ytop;                 /* Top of intersection */
+    GdkRegionBox *oldRects;            /* Old rects for newReg */
+    int                  prevBand;             /* Index of start of
+                                        * previous band in newReg */
+    int                  curBand;              /* Index of start of current
+                                        * band in newReg */
+    GdkRegionBox *r1BandEnd;           /* End of current band in r1 */
+    GdkRegionBox *r2BandEnd;           /* End of current band in r2 */
+    int          top;                  /* Top of non-overlapping
+                                        * band */
+    int          bot;                  /* Bottom of non-overlapping
+                                        * band */
+    
+    /*
+     * Initialization:
+     * set r1, r2, r1End and r2End appropriately, preserve the important
+     * parts of the destination region until the end in case it's one of
+     * the two source regions, then mark the "new" region empty, allocating
+     * another array of rectangles for it to use.
+     */
+    r1 = reg1->rects;
+    r2 = reg2->rects;
+    r1End = r1 + reg1->numRects;
+    r2End = r2 + reg2->numRects;
+    
+    oldRects = newReg->rects;
+    
+    EMPTY_REGION(newReg);
+
+    /*
+     * Allocate a reasonable number of rectangles for the new region. The idea
+     * is to allocate enough so the individual functions don't need to
+     * reallocate and copy the array, which is time consuming, yet we don't
+     * have to worry about using too much memory. I hope to be able to
+     * nuke the Xrealloc() at the end of this function eventually.
+     */
+    newReg->size = MAX (reg1->numRects, reg2->numRects) * 2;
+    newReg->rects = g_new (GdkRegionBox, newReg->size);
+    
+    /*
+     * Initialize ybot and ytop.
+     * In the upcoming loop, ybot and ytop serve different functions depending
+     * on whether the band being handled is an overlapping or non-overlapping
+     * band.
+     *         In the case of a non-overlapping band (only one of the regions
+     * has points in the band), ybot is the bottom of the most recent
+     * intersection and thus clips the top of the rectangles in that band.
+     * ytop is the top of the next intersection between the two regions and
+     * serves to clip the bottom of the rectangles in the current band.
+     * For an overlapping band (where the two regions intersect), ytop clips
+     * the top of the rectangles of both regions and ybot clips the bottoms.
+     */
+    if (reg1->extents.y1 < reg2->extents.y1)
+      ybot = reg1->extents.y1;
+    else
+      ybot = reg2->extents.y1;
+    
+    /*
+     * prevBand serves to mark the start of the previous band so rectangles
+     * can be coalesced into larger rectangles. qv. miCoalesce, above.
+     * In the beginning, there is no previous band, so prevBand == curBand
+     * (curBand is set later on, of course, but the first band will always
+     * start at index 0). prevBand and curBand must be indices because of
+     * the possible expansion, and resultant moving, of the new region's
+     * array of rectangles.
+     */
+    prevBand = 0;
+    
+    do
+      {
+       curBand = newReg->numRects;
+
+       /*
+        * This algorithm proceeds one source-band (as opposed to a
+        * destination band, which is determined by where the two regions
+        * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
+        * rectangle after the last one in the current band for their
+        * respective regions.
+        */
+       r1BandEnd = r1;
+       while ((r1BandEnd != r1End) && (r1BandEnd->y1 == r1->y1))
+         {
+           r1BandEnd++;
+         }
+       
+       r2BandEnd = r2;
+       while ((r2BandEnd != r2End) && (r2BandEnd->y1 == r2->y1))
+         {
+           r2BandEnd++;
+         }
+       
+       /*
+        * First handle the band that doesn't intersect, if any.
+        *
+        * Note that attention is restricted to one band in the
+        * non-intersecting region at once, so if a region has n
+        * bands between the current position and the next place it overlaps
+        * the other, this entire loop will be passed through n times.
+        */
+       if (r1->y1 < r2->y1)
+         {
+           top = MAX (r1->y1,ybot);
+           bot = MIN (r1->y2,r2->y1);
+
+           if ((top != bot) && (nonOverlap1Fn != (void (*)())NULL))
+             {
+               (* nonOverlap1Fn) (newReg, r1, r1BandEnd, top, bot);
+             }
+
+           ytop = r2->y1;
+         }
+       else if (r2->y1 < r1->y1)
+         {
+           top = MAX (r2->y1,ybot);
+           bot = MIN (r2->y2,r1->y1);
+
+           if ((top != bot) && (nonOverlap2Fn != (void (*)())NULL))
+             {
+               (* nonOverlap2Fn) (newReg, r2, r2BandEnd, top, bot);
+             }
+
+           ytop = r1->y1;
+         }
+       else
+         {
+           ytop = r1->y1;
+         }
+
+       /*
+        * If any rectangles got added to the region, try and coalesce them
+        * with rectangles from the previous band. Note we could just do
+        * this test in miCoalesce, but some machines incur a not
+        * inconsiderable cost for function calls, so...
+        */
+       if (newReg->numRects != curBand)
+         {
+           prevBand = miCoalesce (newReg, prevBand, curBand);
+         }
+
+       /*
+        * Now see if we've hit an intersecting band. The two bands only
+        * intersect if ybot > ytop
+        */
+       ybot = MIN (r1->y2, r2->y2);
+       curBand = newReg->numRects;
+       if (ybot > ytop)
+         {
+           (* overlapFn) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
+
+         }
+       
+       if (newReg->numRects != curBand)
+         {
+           prevBand = miCoalesce (newReg, prevBand, curBand);
+         }
+
+       /*
+        * If we've finished with a band (y2 == ybot) we skip forward
+        * in the region to the next band.
+        */
+       if (r1->y2 == ybot)
+         {
+           r1 = r1BandEnd;
+         }
+       if (r2->y2 == ybot)
+         {
+           r2 = r2BandEnd;
+         }
+      } while ((r1 != r1End) && (r2 != r2End));
+
+    /*
+     * Deal with whichever region still has rectangles left.
+     */
+    curBand = newReg->numRects;
+    if (r1 != r1End)
+      {
+       if (nonOverlap1Fn != (nonOverlapFunc )NULL)
+         {
+           do
+             {
+               r1BandEnd = r1;
+               while ((r1BandEnd < r1End) && (r1BandEnd->y1 == r1->y1))
+                 {
+                   r1BandEnd++;
+                 }
+               (* nonOverlap1Fn) (newReg, r1, r1BandEnd,
+                                    MAX (r1->y1,ybot), r1->y2);
+               r1 = r1BandEnd;
+             } while (r1 != r1End);
+         }
+      }
+    else if ((r2 != r2End) && (nonOverlap2Fn != (nonOverlapFunc) NULL))
+      {
+       do
+         {
+           r2BandEnd = r2;
+           while ((r2BandEnd < r2End) && (r2BandEnd->y1 == r2->y1))
+             {
+               r2BandEnd++;
+             }
+           (* nonOverlap2Fn) (newReg, r2, r2BandEnd,
+                              MAX (r2->y1,ybot), r2->y2);
+           r2 = r2BandEnd;
+         } while (r2 != r2End);
+      }
+
+    if (newReg->numRects != curBand)
+    {
+      (void) miCoalesce (newReg, prevBand, curBand);
+    }
+
+    /*
+     * A bit of cleanup. To keep regions from growing without bound,
+     * we shrink the array of rectangles to match the new number of
+     * rectangles in the region. This never goes to 0, however...
+     *
+     * Only do this stuff if the number of rectangles allocated is more than
+     * twice the number of rectangles in the region (a simple optimization...).
+     */
+    if (newReg->numRects < (newReg->size >> 1))
+      {
+       if (REGION_NOT_EMPTY (newReg))
+         {
+           newReg->size = newReg->numRects;
+           newReg->rects = g_renew (GdkRegionBox, newReg->rects, newReg->size);
+         }
+       else
+         {
+           /*
+            * No point in doing the extra work involved in an Xrealloc if
+            * the region is empty
+            */
+           newReg->size = 1;
+           g_free (newReg->rects);
+           newReg->rects = g_new (GdkRegionBox, 1);
+         }
+      }
+    g_free (oldRects);
+}
+
+\f
+/*======================================================================
+ *         Region Union
+ *====================================================================*/
+
+/*-
+ *-----------------------------------------------------------------------
+ * miUnionNonO --
+ *     Handle a non-overlapping band for the union operation. Just
+ *     Adds the rectangles into the region. Doesn't have to check for
+ *     subsumption or anything.
+ *
+ * Results:
+ *     None.
+ *
+ * Side Effects:
+ *     pReg->numRects is incremented and the final rectangles overwritten
+ *     with the rectangles we're passed.
+ *
+ *-----------------------------------------------------------------------
+ */
+static void
+miUnionNonO (GdkRegion    *pReg,
+            GdkRegionBox *r,
+            GdkRegionBox *rEnd,
+            gint          y1,
+            gint          y2)
+{
+  GdkRegionBox *pNextRect;
+
+  pNextRect = &pReg->rects[pReg->numRects];
+
+  assert(y1 < y2);
+
+  while (r != rEnd)
+    {
+      assert(r->x1 < r->x2);
+      MEMCHECK(pReg, pNextRect, pReg->rects);
+      pNextRect->x1 = r->x1;
+      pNextRect->y1 = y1;
+      pNextRect->x2 = r->x2;
+      pNextRect->y2 = y2;
+      pReg->numRects += 1;
+      pNextRect++;
+
+      assert(pReg->numRects<=pReg->size);
+      r++;
+    }
+}
+
+
+/*-
+ *-----------------------------------------------------------------------
+ * miUnionO --
+ *     Handle an overlapping band for the union operation. Picks the
+ *     left-most rectangle each time and merges it into the region.
+ *
+ * Results:
+ *     None.
+ *
+ * Side Effects:
+ *     Rectangles are overwritten in pReg->rects and pReg->numRects will
+ *     be changed.
+ *
+ *-----------------------------------------------------------------------
+ */
+
+/* static void*/
+static void
+miUnionO (GdkRegion *pReg,
+         GdkRegionBox *r1,
+         GdkRegionBox *r1End,
+         GdkRegionBox *r2,
+         GdkRegionBox *r2End,
+         gint          y1,
+         gint          y2)
+{
+  GdkRegionBox *       pNextRect;
+    
+  pNextRect = &pReg->rects[pReg->numRects];
+
+#define MERGERECT(r)                                   \
+    if ((pReg->numRects != 0) &&                       \
+       (pNextRect[-1].y1 == y1) &&                     \
+       (pNextRect[-1].y2 == y2) &&                     \
+       (pNextRect[-1].x2 >= r->x1))                    \
+      {                                                \
+       if (pNextRect[-1].x2 < r->x2)                   \
+         {                                             \
+           pNextRect[-1].x2 = r->x2;                   \
+           assert(pNextRect[-1].x1<pNextRect[-1].x2);  \
+         }                                             \
+      }                                                \
+    else                                               \
+      {                                                \
+       MEMCHECK(pReg, pNextRect, pReg->rects);         \
+       pNextRect->y1 = y1;                             \
+       pNextRect->y2 = y2;                             \
+       pNextRect->x1 = r->x1;                          \
+       pNextRect->x2 = r->x2;                          \
+       pReg->numRects += 1;                            \
+        pNextRect += 1;                                \
+      }                                                \
+    assert(pReg->numRects<=pReg->size);                        \
+    r++;
+    
+    assert (y1<y2);
+    while ((r1 != r1End) && (r2 != r2End))
+    {
+       if (r1->x1 < r2->x1)
+       {
+           MERGERECT(r1);
+       }
+       else
+       {
+           MERGERECT(r2);
+       }
+    }
+    
+    if (r1 != r1End)
+    {
+       do
+       {
+           MERGERECT(r1);
+       } while (r1 != r1End);
+    }
+    else while (r2 != r2End)
+    {
+       MERGERECT(r2);
+    }
+}
+
+void
+gdk_region_union (GdkRegion *region,
+                 GdkRegion *other)
+{
+  /*  checks all the simple cases */
+
+    /*
+     * region and other are the same or other is empty
+     */
+  if ((region == other) || (!(other->numRects)))
+    return;
+
+    /* 
+     * region is empty
+     */
+  if (!(region->numRects))
+    {
+      miRegionCopy (region, other);
+      return;
+    }
+
+  /*
+     * region completely subsumes otehr
+     */
+  if ((region->numRects == 1) && 
+      (region->extents.x1 <= other->extents.x1) &&
+      (region->extents.y1 <= other->extents.y1) &&
+      (region->extents.x2 >= other->extents.x2) &&
+      (region->extents.y2 >= other->extents.y2))
+    return;
+
+  /*
+     * other completely subsumes region
+     */
+  if ((other->numRects == 1) && 
+      (other->extents.x1 <= region->extents.x1) &&
+      (other->extents.y1 <= region->extents.y1) &&
+      (other->extents.x2 >= region->extents.x2) &&
+      (other->extents.y2 >= region->extents.y2))
+    {
+      miRegionCopy(region, other);
+      return;
+    }
+
+  miRegionOp (region, region, other, miUnionO, 
+             miUnionNonO, miUnionNonO);
+
+  region->extents.x1 = MIN (region->extents.x1, other->extents.x1);
+  region->extents.y1 = MIN (region->extents.y1, other->extents.y1);
+  region->extents.x2 = MAX (region->extents.x2, other->extents.x2);
+  region->extents.y2 = MAX (region->extents.y2, other->extents.y2);
+}
+
+\f
+/*======================================================================
+ *               Region Subtraction
+ *====================================================================*/
+
+/*-
+ *-----------------------------------------------------------------------
+ * miSubtractNonO --
+ *     Deal with non-overlapping band for subtraction. Any parts from
+ *     region 2 we discard. Anything from region 1 we add to the region.
+ *
+ * Results:
+ *     None.
+ *
+ * Side Effects:
+ *     pReg may be affected.
+ *
+ *-----------------------------------------------------------------------
+ */
+/* static void*/
+static void
+miSubtractNonO1 (GdkRegion    *pReg,
+                GdkRegionBox *r,
+                GdkRegionBox *rEnd,
+                gint          y1,
+                gint          y2)
+{
+  GdkRegionBox *       pNextRect;
+       
+  pNextRect = &pReg->rects[pReg->numRects];
+       
+  assert(y1<y2);
+
+  while (r != rEnd)
+    {
+      assert (r->x1<r->x2);
+      MEMCHECK (pReg, pNextRect, pReg->rects);
+      pNextRect->x1 = r->x1;
+      pNextRect->y1 = y1;
+      pNextRect->x2 = r->x2;
+      pNextRect->y2 = y2;
+      pReg->numRects += 1;
+      pNextRect++;
+
+      assert (pReg->numRects <= pReg->size);
+
+      r++;
+    }
+}
+
+/*-
+ *-----------------------------------------------------------------------
+ * miSubtractO --
+ *     Overlapping band subtraction. x1 is the left-most point not yet
+ *     checked.
+ *
+ * Results:
+ *     None.
+ *
+ * Side Effects:
+ *     pReg may have rectangles added to it.
+ *
+ *-----------------------------------------------------------------------
+ */
+/* static void*/
+static void
+miSubtractO (GdkRegion    *pReg,
+            GdkRegionBox *r1,
+            GdkRegionBox *r1End,
+            GdkRegionBox *r2,
+            GdkRegionBox *r2End,
+            gint          y1,
+            gint          y2)
+{
+  GdkRegionBox *       pNextRect;
+  int          x1;
+    
+  x1 = r1->x1;
+    
+  assert(y1<y2);
+  pNextRect = &pReg->rects[pReg->numRects];
+
+  while ((r1 != r1End) && (r2 != r2End))
+    {
+      if (r2->x2 <= x1)
+       {
+         /*
+          * Subtrahend missed the boat: go to next subtrahend.
+          */
+         r2++;
+       }
+      else if (r2->x1 <= x1)
+       {
+         /*
+          * Subtrahend preceeds minuend: nuke left edge of minuend.
+          */
+         x1 = r2->x2;
+         if (x1 >= r1->x2)
+           {
+             /*
+              * Minuend completely covered: advance to next minuend and
+              * reset left fence to edge of new minuend.
+              */
+             r1++;
+             if (r1 != r1End)
+               x1 = r1->x1;
+           }
+         else
+           {
+             /*
+              * Subtrahend now used up since it doesn't extend beyond
+              * minuend
+              */
+             r2++;
+           }
+       }
+      else if (r2->x1 < r1->x2)
+       {
+         /*
+          * Left part of subtrahend covers part of minuend: add uncovered
+          * part of minuend to region and skip to next subtrahend.
+          */
+         assert(x1<r2->x1);
+         MEMCHECK(pReg, pNextRect, pReg->rects);
+         pNextRect->x1 = x1;
+         pNextRect->y1 = y1;
+         pNextRect->x2 = r2->x1;
+         pNextRect->y2 = y2;
+         pReg->numRects += 1;
+         pNextRect++;
+
+         assert(pReg->numRects<=pReg->size);
+
+         x1 = r2->x2;
+         if (x1 >= r1->x2)
+           {
+             /*
+              * Minuend used up: advance to new...
+              */
+             r1++;
+             if (r1 != r1End)
+               x1 = r1->x1;
+           }
+         else
+           {
+             /*
+              * Subtrahend used up
+              */
+             r2++;
+           }
+       }
+      else
+       {
+         /*
+          * Minuend used up: add any remaining piece before advancing.
+          */
+         if (r1->x2 > x1)
+           {
+             MEMCHECK(pReg, pNextRect, pReg->rects);
+             pNextRect->x1 = x1;
+             pNextRect->y1 = y1;
+             pNextRect->x2 = r1->x2;
+             pNextRect->y2 = y2;
+             pReg->numRects += 1;
+             pNextRect++;
+             assert(pReg->numRects<=pReg->size);
+           }
+         r1++;
+         x1 = r1->x1;
+       }
+    }
+
+  /*
+     * Add remaining minuend rectangles to region.
+     */
+  while (r1 != r1End)
+    {
+      assert(x1<r1->x2);
+      MEMCHECK(pReg, pNextRect, pReg->rects);
+      pNextRect->x1 = x1;
+      pNextRect->y1 = y1;
+      pNextRect->x2 = r1->x2;
+      pNextRect->y2 = y2;
+      pReg->numRects += 1;
+      pNextRect++;
+
+      assert(pReg->numRects<=pReg->size);
+
+      r1++;
+      if (r1 != r1End)
+       {
+         x1 = r1->x1;
+       }
+    }
+}
+       
+/*-
+ *-----------------------------------------------------------------------
+ * gdk_region_subtract --
+ *     Subtract other from region and leave the result in region.
+ *
+ * Results:
+ *     TRUE.
+ *
+ * Side Effects:
+ *     region is overwritten.
+ *
+ *-----------------------------------------------------------------------
+ */
+
+void
+gdk_region_subtract (GdkRegion *region,
+                    GdkRegion *other)
+{
+  /* check for trivial reject */
+  if ((!(region->numRects)) || (!(other->numRects)) ||
+      (!EXTENTCHECK(&region->extents, &other->extents)))
+    return;
+  miRegionOp (region, region, other, miSubtractO,
+             miSubtractNonO1, (nonOverlapFunc) NULL);
+
+  /*
+   * Can't alter region's extents before we call miRegionOp because miRegionOp
+   * depends on the extents of those regions being the unaltered. Besides, this
+   * way there's no checking against rectangles that will be nuked
+   * due to coalescing, so we have to examine fewer rectangles.
+   */
+  miSetExtents (region);
+}
+
+void
+gdk_region_xor (GdkRegion *sra,
+               GdkRegion *srb)
+{
+  GdkRegion *trb;
+
+  trb = gdk_region_copy (srb);
+
+  gdk_region_subtract (trb, sra);
+  gdk_region_subtract (sra, srb);
+
+  gdk_region_union (sra,trb);
+  
+  gdk_region_destroy (trb);
+}
+
+/*
+ * Check to see if the region is empty.  Assumes a region is passed 
+ * as a parameter
+ */
+gboolean
+gdk_region_empty (GdkRegion *r)
+{
+  if (r->numRects == 0)
+    return TRUE;
+  else
+    return FALSE;
+}
+
+/*
+ *     Check to see if two regions are equal   
+ */
+gboolean
+gdk_region_equal (GdkRegion *r1,
+                 GdkRegion *r2)
+{
+  int i;
+
+  if (r1->numRects != r2->numRects) return FALSE;
+  else if (r1->numRects == 0) return TRUE;
+  else if (r1->extents.x1 != r2->extents.x1) return FALSE;
+  else if (r1->extents.x2 != r2->extents.x2) return FALSE;
+  else if (r1->extents.y1 != r2->extents.y1) return FALSE;
+  else if (r1->extents.y2 != r2->extents.y2) return FALSE;
+  else
+    for(i=0; i < r1->numRects; i++ )
+      {
+       if (r1->rects[i].x1 != r2->rects[i].x1) return FALSE;
+       else if (r1->rects[i].x2 != r2->rects[i].x2) return FALSE;
+       else if (r1->rects[i].y1 != r2->rects[i].y1) return FALSE;
+       else if (r1->rects[i].y2 != r2->rects[i].y2) return FALSE;
+      }
+  return TRUE;
+}
+
+gboolean
+gdk_region_point_in (GdkRegion *region,
+                    int        x,
+                    int        y)
+{
+  int i;
+
+  if (region->numRects == 0)
+    return FALSE;
+  if (!INBOX(region->extents, x, y))
+    return FALSE;
+  for (i=0; i<region->numRects; i++)
+    {
+      if (INBOX (region->rects[i], x, y))
+       return TRUE;
+    }
+  return FALSE;
+}
+
+GdkOverlapType
+gdk_region_rect_in (GdkRegion    *region,
+                   GdkRectangle *rectangle)
+{
+  GdkRegionBox *pbox;
+  GdkRegionBox *pboxEnd;
+  GdkRegionBox  rect;
+  GdkRegionBox *prect = &rect;
+  gboolean      partIn, partOut;
+
+  gint rx = rectangle->x;
+  gint ry = rectangle->y;
+  
+  prect->x1 = rx;
+  prect->y1 = ry;
+  prect->x2 = rx + rectangle->width;
+  prect->y2 = ry + rectangle->height;
+    
+    /* this is (just) a useful optimization */
+  if ((region->numRects == 0) || !EXTENTCHECK (&region->extents, prect))
+    return GDK_OVERLAP_RECTANGLE_OUT;
+
+  partOut = FALSE;
+  partIn = FALSE;
+
+    /* can stop when both partOut and partIn are TRUE, or we reach prect->y2 */
+  for (pbox = region->rects, pboxEnd = pbox + region->numRects;
+       pbox < pboxEnd;
+       pbox++)
+    {
+
+      if (pbox->y2 <= ry)
+       continue;       /* getting up to speed or skipping remainder of band */
+
+      if (pbox->y1 > ry)
+       {
+         partOut = TRUE;       /* missed part of rectangle above */
+         if (partIn || (pbox->y1 >= prect->y2))
+           break;
+         ry = pbox->y1;        /* x guaranteed to be == prect->x1 */
+       }
+
+      if (pbox->x2 <= rx)
+       continue;               /* not far enough over yet */
+
+      if (pbox->x1 > rx)
+       {
+         partOut = TRUE;       /* missed part of rectangle to left */
+         if (partIn)
+           break;
+       }
+
+      if (pbox->x1 < prect->x2)
+       {
+         partIn = TRUE;        /* definitely overlap */
+         if (partOut)
+           break;
+       }
+
+      if (pbox->x2 >= prect->x2)
+       {
+         ry = pbox->y2;        /* finished with this band */
+         if (ry >= prect->y2)
+           break;
+         rx = prect->x1;       /* reset x out to left again */
+       }
+      else
+       {
+         /*
+          * Because boxes in a band are maximal width, if the first box
+          * to overlap the rectangle doesn't completely cover it in that
+          * band, the rectangle must be partially out, since some of it
+          * will be uncovered in that band. partIn will have been set true
+          * by now...
+          */
+         break;
+       }
+
+    }
+
+  return (partIn ?
+            ((ry < prect->y2) ?
+             GDK_OVERLAP_RECTANGLE_PART : GDK_OVERLAP_RECTANGLE_IN) : 
+         GDK_OVERLAP_RECTANGLE_OUT);
+}
diff --git a/gdk/linux-fb/gdkregion-generic.h b/gdk/linux-fb/gdkregion-generic.h
new file mode 100644 (file)
index 0000000..33d0683
--- /dev/null
@@ -0,0 +1,162 @@
+/* $TOG: region.h /main/9 1998/02/06 17:50:30 kaleb $ */
+/************************************************************************
+
+Copyright 1987, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+************************************************************************/
+
+#ifndef __GDK_REGION_GENERIC_H__
+#define __GDK_REGION_GENERIC_H__
+
+typedef GdkSegment GdkRegionBox;
+
+/* 
+ *   clip region
+ */
+
+struct _GdkRegion
+{
+  long size;
+  long numRects;
+  GdkRegionBox *rects;
+  GdkRegionBox extents;
+};
+
+/*  1 if two BOXs overlap.
+ *  0 if two BOXs do not overlap.
+ *  Remember, x2 and y2 are not in the region 
+ */
+#define EXTENTCHECK(r1, r2) \
+       ((r1)->x2 > (r2)->x1 && \
+        (r1)->x1 < (r2)->x2 && \
+        (r1)->y2 > (r2)->y1 && \
+        (r1)->y1 < (r2)->y2)
+
+/*
+ *  update region extents
+ */
+#define EXTENTS(r,idRect){\
+            if((r)->x1 < (idRect)->extents.x1)\
+              (idRect)->extents.x1 = (r)->x1;\
+            if((r)->y1 < (idRect)->extents.y1)\
+              (idRect)->extents.y1 = (r)->y1;\
+            if((r)->x2 > (idRect)->extents.x2)\
+              (idRect)->extents.x2 = (r)->x2;\
+            if((r)->y2 > (idRect)->extents.y2)\
+              (idRect)->extents.y2 = (r)->y2;\
+        }
+
+/*
+ *   Check to see if there is enough memory in the present region.
+ */
+#define MEMCHECK(reg, rect, firstrect){                                                 \
+        if ((reg)->numRects >= ((reg)->size - 1)) {                             \
+          (firstrect) = g_renew (GdkRegionBox, (firstrect), 2 * (reg)->size);    \
+          (reg)->size *= 2;                                                     \
+          (rect) = &(firstrect)[(reg)->numRects];                               \
+         }                                                                      \
+       }
+
+/*  this routine checks to see if the previous rectangle is the same
+ *  or subsumes the new rectangle to add.
+ */
+
+#define CHECK_PREVIOUS(Reg, R, Rx1, Ry1, Rx2, Ry2)\
+               (!(((Reg)->numRects > 0)&&\
+                  ((R-1)->y1 == (Ry1)) &&\
+                  ((R-1)->y2 == (Ry2)) &&\
+                  ((R-1)->x1 <= (Rx1)) &&\
+                  ((R-1)->x2 >= (Rx2))))
+
+/*  add a rectangle to the given Region */
+#define ADDRECT(reg, r, rx1, ry1, rx2, ry2){\
+    if (((rx1) < (rx2)) && ((ry1) < (ry2)) &&\
+        CHECK_PREVIOUS((reg), (r), (rx1), (ry1), (rx2), (ry2))){\
+              (r)->x1 = (rx1);\
+              (r)->y1 = (ry1);\
+              (r)->x2 = (rx2);\
+              (r)->y2 = (ry2);\
+              EXTENTS((r), (reg));\
+              (reg)->numRects++;\
+              (r)++;\
+            }\
+        }
+
+
+
+/*  add a rectangle to the given Region */
+#define ADDRECTNOX(reg, r, rx1, ry1, rx2, ry2){\
+            if ((rx1 < rx2) && (ry1 < ry2) &&\
+                CHECK_PREVIOUS((reg), (r), (rx1), (ry1), (rx2), (ry2))){\
+              (r)->x1 = (rx1);\
+              (r)->y1 = (ry1);\
+              (r)->x2 = (rx2);\
+              (r)->y2 = (ry2);\
+              (reg)->numRects++;\
+              (r)++;\
+            }\
+        }
+
+#define EMPTY_REGION(pReg) pReg->numRects = 0
+
+#define REGION_NOT_EMPTY(pReg) pReg->numRects
+
+#define INBOX(r, x, y) \
+      ( ( ((r).x2 >  x)) && \
+        ( ((r).x1 <= x)) && \
+        ( ((r).y2 >  y)) && \
+        ( ((r).y1 <= y)) )
+
+/*
+ * number of points to buffer before sending them off
+ * to scanlines() :  Must be an even number
+ */
+#define NUMPTSTOBUFFER 200
+
+/*
+ * used to allocate buffers for points and link
+ * the buffers together
+ */
+typedef struct _POINTBLOCK {
+  GdkPoint pts[NUMPTSTOBUFFER];
+  struct _POINTBLOCK *next;
+} POINTBLOCK;
+
+#endif /* __GDK_REGION_GENERIC_H__ */
diff --git a/gdk/linux-fb/gdkselection-fb.c b/gdk/linux-fb/gdkselection-fb.c
new file mode 100644 (file)
index 0000000..1b154b0
--- /dev/null
@@ -0,0 +1,104 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include <string.h>
+
+#include "gdkproperty.h"
+#include "gdkselection.h"
+#include "gdkprivate.h"
+#include "gdkprivate-fb.h"
+
+
+gint
+gdk_selection_owner_set (GdkWindow *owner,
+                        GdkAtom    selection,
+                        guint32    time,
+                        gint       send_event)
+{
+  return FALSE;
+}
+
+GdkWindow*
+gdk_selection_owner_get (GdkAtom selection)
+{
+  return NULL;
+}
+
+void
+gdk_selection_convert (GdkWindow *requestor,
+                      GdkAtom    selection,
+                      GdkAtom    target,
+                      guint32    time)
+{
+}
+
+gint
+gdk_selection_property_get (GdkWindow  *requestor,
+                           guchar    **data,
+                           GdkAtom    *ret_type,
+                           gint       *ret_format)
+{
+  g_return_val_if_fail (requestor != NULL, 0);
+  g_return_val_if_fail (GDK_IS_WINDOW (requestor), 0);
+
+  return 0;
+}
+
+
+void
+gdk_selection_send_notify (guint32  requestor,
+                          GdkAtom  selection,
+                          GdkAtom  target,
+                          GdkAtom  property,
+                          guint32  time)
+{
+}
+
+gint
+gdk_text_property_to_text_list (GdkAtom encoding, gint format, 
+                               const guchar *text, gint length,
+                               gchar ***list)
+{
+  return 0;
+}
+
+void
+gdk_free_text_list (gchar **list)
+{
+  g_return_if_fail (list != NULL);
+}
+
+gint
+gdk_string_to_compound_text (const gchar *str,
+                            GdkAtom *encoding, gint *format,
+                            guchar **ctext, gint *length)
+{
+  return 0;
+}
+
+void gdk_free_compound_text (guchar *ctext)
+{
+}
diff --git a/gdk/linux-fb/gdkvisual-fb.c b/gdk/linux-fb/gdkvisual-fb.c
new file mode 100644 (file)
index 0000000..24468aa
--- /dev/null
@@ -0,0 +1,180 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "gdkvisual.h"
+#include "gdkprivate-fb.h"
+#include "gdkinternals.h"
+#include <endian.h>
+
+static GdkVisual *system_visual = NULL;
+
+#ifdef G_ENABLE_DEBUG
+
+#if 0
+static const gchar* visual_names[] =
+{
+  "static gray",
+  "grayscale",
+  "static color",
+  "pseudo color",
+  "true color",
+  "direct color",
+};
+#endif
+
+#endif /* G_ENABLE_DEBUG */
+
+void
+gdk_visual_init (void)
+{
+  system_visual = g_new0(GdkVisual, 1);
+
+  system_visual->depth = system_visual->bits_per_rgb = gdk_display->modeinfo.bits_per_pixel;
+  system_visual->byte_order = GDK_LSB_FIRST;
+  system_visual->colormap_size = 0;
+
+  switch(gdk_display->sinfo.visual)
+    {
+    case FB_VISUAL_PSEUDOCOLOR:
+      system_visual->colormap_size = 1 << gdk_display->modeinfo.bits_per_pixel;
+      system_visual->type = GDK_VISUAL_PSEUDO_COLOR;
+      break;
+    case FB_VISUAL_DIRECTCOLOR:
+      system_visual->colormap_size = 1 << gdk_display->modeinfo.bits_per_pixel;
+      system_visual->type = GDK_VISUAL_DIRECT_COLOR;
+    case FB_VISUAL_TRUECOLOR:
+      if(gdk_display->sinfo.visual == GDK_VISUAL_TRUE_COLOR)
+       system_visual->type = GDK_VISUAL_TRUE_COLOR;
+
+      system_visual->red_prec = MIN(system_visual->depth / 3, 8);
+      system_visual->red_shift = 0;
+      system_visual->red_mask = ((1 << (system_visual->red_prec + 1)) - 1) << system_visual->red_shift;
+
+      system_visual->green_shift = system_visual->red_prec;
+      system_visual->green_prec = MIN(system_visual->depth / 3, 8);
+      system_visual->green_mask = ((1 << (system_visual->green_prec + 1)) - 1) << system_visual->green_shift;
+
+      system_visual->blue_shift = system_visual->green_prec + system_visual->green_shift;
+      system_visual->blue_prec = MIN(system_visual->depth / 3, 8);
+      system_visual->blue_mask = ((1 << (system_visual->blue_prec + 1)) - 1) << system_visual->blue_shift;
+      break;
+    case FB_VISUAL_STATIC_PSEUDOCOLOR:
+      system_visual->type = GDK_VISUAL_STATIC_COLOR;
+      system_visual->colormap_size = 1 << gdk_display->modeinfo.bits_per_pixel;
+      break;
+    default:
+      g_assert_not_reached();
+      break;
+    }
+}
+
+GdkVisual*
+gdk_visual_ref (GdkVisual *visual)
+{
+  return visual;
+}
+
+void
+gdk_visual_unref (GdkVisual *visual)
+{
+}
+
+gint
+gdk_visual_get_best_depth (void)
+{
+  return system_visual->depth;
+}
+
+GdkVisualType
+gdk_visual_get_best_type (void)
+{
+  return system_visual->type;
+}
+
+GdkVisual*
+gdk_visual_get_system (void)
+{
+  return system_visual;
+}
+
+GdkVisual*
+gdk_visual_get_best (void)
+{
+  return system_visual;
+}
+
+GdkVisual*
+gdk_visual_get_best_with_depth (gint depth)
+{
+  if(system_visual->depth != depth)
+    return NULL;
+
+  return system_visual;
+}
+
+GdkVisual*
+gdk_visual_get_best_with_type (GdkVisualType visual_type)
+{
+  if(system_visual->type != visual_type)
+    return NULL;
+
+  return system_visual;
+}
+
+GdkVisual*
+gdk_visual_get_best_with_both (gint          depth,
+                              GdkVisualType visual_type)
+{
+  if(system_visual->depth != depth)
+    return NULL;
+
+  if(system_visual->type != visual_type)
+    return NULL;
+
+  return system_visual;
+}
+
+void
+gdk_query_depths  (gint **depths,
+                  gint  *count)
+{
+  *count = 1;
+  *depths = &system_visual->depth;
+}
+
+void
+gdk_query_visual_types (GdkVisualType **visual_types,
+                       gint           *count)
+{
+  *count = 1;
+  *visual_types = &system_visual->type;
+}
+
+GList*
+gdk_list_visuals (void)
+{
+  return g_list_append(NULL, gdk_visual_get_system());
+}
diff --git a/gdk/linux-fb/gdkwindow-fb.c b/gdk/linux-fb/gdkwindow-fb.c
new file mode 100644 (file)
index 0000000..dad9ff3
--- /dev/null
@@ -0,0 +1,1372 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "gdk.h"
+#include "config.h"
+
+#include "gdkwindow.h"
+#include "gdkinputprivate.h"
+#include "gdkprivate-fb.h"
+#include "gdkinternals.h"
+
+#include <limits.h>
+
+GdkDrawableClass _gdk_windowing_window_class;
+
+static void recompute_drawable(GdkDrawable *drawable);
+
+static void
+g_free_2nd(gpointer a, gpointer b, gpointer data)
+{
+  g_free(b);
+}
+
+static void
+gdk_fb_window_destroy (GdkDrawable *drawable)
+{
+  GdkWindowFBData *fbd = GDK_WINDOW_FBDATA(drawable);
+
+  if (!GDK_DRAWABLE_DESTROYED (drawable))
+    g_warning ("losing last reference to undestroyed window\n");
+
+  if(GDK_WINDOW_P(drawable)->mapped)
+    gdk_window_hide(drawable);
+
+  if(fbd->cursor)
+    gdk_cursor_unref(fbd->cursor);
+
+  if(fbd->properties)
+    {
+      g_hash_table_foreach(fbd->properties, g_free_2nd, NULL);
+      g_hash_table_destroy(fbd->properties);
+    }
+
+  g_free (GDK_DRAWABLE_FBDATA (drawable));
+}
+
+static GdkWindow *
+gdk_fb_window_alloc (void)
+{
+  GdkWindow *window;
+  GdkWindowPrivate *private;
+  
+  static gboolean initialized = FALSE;
+
+  if (!initialized)
+    {
+      initialized = TRUE;
+
+      _gdk_windowing_window_class = _gdk_fb_drawable_class;
+      _gdk_windowing_window_class.destroy = gdk_fb_window_destroy;
+    }
+
+  window = _gdk_window_alloc ();
+  private = (GdkWindowPrivate *)window;
+
+  private->drawable.klass = &_gdk_window_class;
+  private->drawable.klass_data = g_new0 (GdkWindowFBData, 1);
+  private->drawable.depth = gdk_display->modeinfo.bits_per_pixel;
+  private->drawable.colormap = gdk_colormap_get_system ();
+  GDK_WINDOW_FBDATA(private)->event_mask = GDK_STRUCTURE_MASK;
+
+  return window;
+}
+
+#include "/usr/include/X11/bitmaps/left_ptr"
+#include "/usr/include/X11/bitmaps/left_ptrmsk"
+
+void
+gdk_window_init (void)
+{
+  GdkBitmap *ptr, *mask;
+  GdkCursor *cursor;
+  GdkWindowPrivate *private;
+
+  gdk_parent_root = gdk_fb_window_alloc ();
+  private = (GdkWindowPrivate *)gdk_parent_root;
+
+  private->drawable.window_type = GDK_WINDOW_ROOT;
+  private->drawable.width = gdk_screen_width ();
+  private->drawable.height = gdk_screen_height ();
+  private->mapped = TRUE;
+  private->x = 0;
+  private->y = 0;
+
+  GDK_DRAWABLE_FBDATA(private)->mem = gdk_display->fbmem;
+  GDK_DRAWABLE_FBDATA(private)->rowstride = gdk_display->modeinfo.xres * (gdk_display->modeinfo.bits_per_pixel >> 3);
+  GDK_DRAWABLE_FBDATA(private)->lim_x = gdk_display->modeinfo.xres;
+  GDK_DRAWABLE_FBDATA(private)->lim_y = gdk_display->modeinfo.yres;
+  GDK_WINDOW_FBDATA(private)->event_mask = GDK_EXPOSURE_MASK;
+
+  gdk_fb_drawable_clear(gdk_parent_root);
+
+  ptr = gdk_bitmap_create_from_data(gdk_parent_root, left_ptr_bits, left_ptr_width, left_ptr_height);
+  mask = gdk_bitmap_create_from_data(gdk_parent_root, left_ptrmsk_bits, left_ptrmsk_width, left_ptrmsk_height);
+  cursor = gdk_cursor_new_from_pixmap(ptr, mask, NULL, NULL, left_ptr_x_hot, left_ptr_y_hot);
+
+  gdk_window_set_cursor(gdk_parent_root, cursor);
+}
+
+GdkWindow*
+gdk_window_new (GdkWindow     *parent,
+               GdkWindowAttr *attributes,
+               gint           attributes_mask)
+{
+  GdkWindow *window;
+  GdkWindowPrivate *private;
+  GdkWindowPrivate *parent_private;
+  GdkVisual *visual;
+
+  int x, y, depth;
+  
+  g_return_val_if_fail (attributes != NULL, NULL);
+  
+  if (!parent || attributes->window_type != GDK_WINDOW_CHILD)
+    parent = gdk_parent_root;
+  
+  parent_private = (GdkWindowPrivate*) parent;
+  if (GDK_DRAWABLE_DESTROYED (parent))
+    return NULL;
+  
+  window = gdk_fb_window_alloc ();
+  private = (GdkWindowPrivate *)window;
+
+  private->parent = parent;
+
+  if (attributes_mask & GDK_WA_X)
+    x = attributes->x;
+  else
+    x = 0;
+
+  if (attributes_mask & GDK_WA_Y)
+    y = attributes->y;
+  else
+    y = 0;
+
+  gdk_window_set_events(window, attributes->event_mask);
+
+  if (attributes_mask & GDK_WA_VISUAL)
+    visual = attributes->visual;
+
+  private->x = x;
+  private->y = y;
+  private->drawable.width = (attributes->width > 1) ? (attributes->width) : (1);
+  private->drawable.height = (attributes->height > 1) ? (attributes->height) : (1);
+  private->drawable.window_type = attributes->window_type;
+  GDK_DRAWABLE_FBDATA(private)->mem = gdk_display->fbmem;
+  GDK_DRAWABLE_FBDATA(private)->rowstride = gdk_display->modeinfo.xres * (gdk_display->modeinfo.bits_per_pixel >> 3);
+  gdk_window_move_resize (window, x, y,
+                         private->drawable.width, private->drawable.height);
+
+  if (attributes->wclass == GDK_INPUT_OUTPUT)
+    {
+      depth = visual->depth;
+
+      private->input_only = FALSE;
+      private->drawable.depth = depth;
+      
+      if ((attributes_mask & GDK_WA_COLORMAP)
+         && attributes->colormap)
+       private->drawable.colormap = attributes->colormap;
+      
+      switch (private->drawable.window_type)
+       {
+       case GDK_WINDOW_TOPLEVEL:
+       case GDK_WINDOW_CHILD:
+       case GDK_WINDOW_DIALOG:
+       case GDK_WINDOW_TEMP:
+         break;
+         
+       case GDK_WINDOW_ROOT:
+         g_error ("cannot make windows of type GDK_WINDOW_ROOT");
+         break;
+       case GDK_WINDOW_PIXMAP:
+         g_error ("cannot make windows of type GDK_WINDOW_PIXMAP (use gdk_pixmap_new)");
+         break;
+       }
+    }
+  else
+    {
+      depth = 0;
+      private->input_only = TRUE;
+      GDK_WINDOW_FBDATA(private)->level = 10000;
+      private->drawable.colormap = NULL;
+    }
+
+  gdk_drawable_ref (window);
+  
+  if (private->drawable.colormap)
+    gdk_colormap_ref (private->drawable.colormap);
+  
+  gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ?
+                                 (attributes->cursor) :
+                                 NULL));
+  
+  if (parent_private)
+    parent_private->children = g_list_prepend (parent_private->children, window);
+  if(parent_private && parent_private->children->next)
+    GDK_WINDOW_FBDATA(private)->level = GDK_WINDOW_FBDATA(parent_private->children->next->data)->level + 1;
+  
+  return window;
+}
+
+/* Call this function when you want a window and all its children to
+ * disappear.  When xdestroy is true, a request to destroy the XWindow
+ * is sent out.  When it is false, it is assumed that the XWindow has
+ * been or will be destroyed by destroying some ancestor of this
+ * window.
+ */
+void
+_gdk_windowing_window_destroy(GdkWindow *window,
+                             gboolean   recursing,
+                             gboolean   foreign_destroy)
+{
+  GdkWindowPrivate *private;
+  GdkWindowPrivate *temp_private;
+  GdkWindow *temp_window;
+  GList *children;
+  GList *tmp;
+  gboolean our_destroy = !foreign_destroy;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  
+  switch (private->drawable.window_type)
+    {
+    case GDK_WINDOW_TOPLEVEL:
+    case GDK_WINDOW_CHILD:
+    case GDK_WINDOW_DIALOG:
+    case GDK_WINDOW_TEMP:
+    case GDK_WINDOW_FOREIGN:
+      if (!private->drawable.destroyed)
+       {
+         if (private->parent)
+           {
+             GdkWindowPrivate *parent_private = (GdkWindowPrivate *)private->parent;
+             if (parent_private->children)
+               parent_private->children = g_list_remove (parent_private->children, window);
+           }
+
+         if (private->bg_pixmap && private->bg_pixmap != GDK_PARENT_RELATIVE_BG)
+           {
+             gdk_pixmap_unref (private->bg_pixmap);
+             private->bg_pixmap = NULL;
+           }
+         
+         if (GDK_DRAWABLE_TYPE (window) != GDK_WINDOW_FOREIGN)
+           {
+             children = tmp = private->children;
+             private->children = NULL;
+             
+             while (tmp)
+               {
+                 temp_window = tmp->data;
+                 tmp = tmp->next;
+                 
+                 temp_private = (GdkWindowPrivate*) temp_window;
+                 if (temp_private)
+                   _gdk_windowing_window_destroy (temp_window, !FALSE,
+                                                  !our_destroy);
+               }
+             
+             g_list_free (children);
+           }
+         
+         if (private->extension_events != 0)
+           gdk_input_window_destroy (window);
+         
+         if (private->filters)
+           {
+             tmp = private->filters;
+             
+             while (tmp)
+               {
+                 g_free (tmp->data);
+                 tmp = tmp->next;
+               }
+             
+             g_list_free (private->filters);
+             private->filters = NULL;
+           }
+         
+         if (private->drawable.window_type == GDK_WINDOW_FOREIGN)
+           {
+             if (our_destroy && (private->parent != NULL))
+               {
+                 /* It's somebody elses window, but in our heirarchy,
+                  * so reparent it to the root window, and then send
+                  * it a delete event, as if we were a WM
+                  */
+                 gdk_error_trap_push ();
+                 gdk_window_hide (window);
+                 gdk_window_reparent (window, NULL, 0, 0);
+                 
+                 gdk_flush ();
+                 gdk_error_trap_pop ();
+               }
+           }
+         
+         if (private->drawable.colormap)
+           gdk_colormap_unref (private->drawable.colormap);
+         
+         private->mapped = FALSE;
+         private->drawable.destroyed = TRUE;
+       }
+      break;
+      
+    case GDK_WINDOW_ROOT:
+      g_error ("attempted to destroy root window");
+      break;
+      
+    case GDK_WINDOW_PIXMAP:
+      g_error ("called gdk_window_destroy on a pixmap (use gdk_pixmap_unref)");
+      break;
+    }
+}
+
+/* This function is called when the XWindow is really gone.  */
+
+void
+gdk_window_destroy_notify (GdkWindow *window)
+{
+  g_return_if_fail (window != NULL);
+  
+  if (!GDK_DRAWABLE_DESTROYED (window))
+    {
+      if (GDK_DRAWABLE_TYPE(window) != GDK_WINDOW_FOREIGN)
+       g_warning ("GdkWindow %#x unexpectedly destroyed", GPOINTER_TO_UINT(window));
+
+      _gdk_windowing_window_destroy (window, TRUE, TRUE);
+    }
+  
+  gdk_drawable_unref (window);
+}
+
+static gboolean all_parents_shown(GdkWindowPrivate *private)
+{
+  while(private->mapped)
+    {
+      if(private->parent)
+       private = (GdkWindowPrivate *)private->parent;
+      else
+       return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+send_map_events(GdkWindowPrivate *private, gboolean is_map)
+{
+  GdkEvent *event;
+  GList *l;
+  GdkWindow *parent = private->parent;
+
+  if(!private->mapped || GDK_DRAWABLE_DESTROYED(private))
+    return;
+
+  if(is_map)
+    gdk_event_make((GdkWindow *)private, GDK_MAP, TRUE);
+
+  if(private->input_only)
+    return;
+
+  if(!parent)
+    parent = (GdkWindow *)private;
+
+  if(((GDK_DRAWABLE_FBDATA(private)->abs_x > GDK_DRAWABLE_FBDATA(parent)->lim_x)
+      || (GDK_DRAWABLE_FBDATA(private)->abs_y > GDK_DRAWABLE_FBDATA(parent)->lim_y)
+      || (GDK_DRAWABLE_FBDATA(private)->lim_x < GDK_DRAWABLE_FBDATA(parent)->llim_x)
+      || (GDK_DRAWABLE_FBDATA(private)->lim_y < GDK_DRAWABLE_FBDATA(parent)->llim_y)))
+     return;
+
+  if(is_map)
+    gdk_window_clear((GdkWindow *)private);
+
+  event = gdk_event_new();
+  event->expose.type = GDK_EXPOSE;
+  event->expose.window = gdk_window_ref((GdkWindow *)private);
+  if(GDK_DRAWABLE_FBDATA(private)->abs_x > GDK_DRAWABLE_FBDATA(parent)->llim_x)
+    event->expose.area.x = 0;
+  else
+    event->expose.area.x = GDK_DRAWABLE_FBDATA(parent)->llim_x - GDK_DRAWABLE_FBDATA(private)->abs_x;
+
+  if(GDK_DRAWABLE_FBDATA(private)->abs_y > GDK_DRAWABLE_FBDATA(parent)->llim_y)
+    event->expose.area.y = 0;
+  else
+    event->expose.area.y = GDK_DRAWABLE_FBDATA(parent)->llim_y - GDK_DRAWABLE_FBDATA(private)->abs_y;
+
+  event->expose.area.width = MIN(private->drawable.width,
+                                GDK_DRAWABLE_FBDATA(private)->lim_x - GDK_DRAWABLE_FBDATA(private)->abs_x);
+  event->expose.area.height = MIN(private->drawable.height,
+                                 GDK_DRAWABLE_FBDATA(private)->lim_y - GDK_DRAWABLE_FBDATA(private)->abs_y);
+  if(event->expose.area.width > 0
+     && event->expose.area.height > 0)
+    {
+      gdk_event_queue_append(event);
+      for(l = private->children; l; l = l->next)
+       send_map_events(l->data, is_map);
+    }
+  else
+    gdk_event_free(event);
+
+}
+
+void
+gdk_fb_redraw_all(void)
+{
+  send_map_events((GdkWindowPrivate *)gdk_parent_root, FALSE);
+}
+
+static
+void gdk_fb_window_visibility_crossing(GdkWindow *window, gboolean is_show)
+{
+  gint winx, winy;
+  GdkModifierType my_mask;
+
+  gdk_input_ps2_get_mouseinfo(&winx, &winy, &my_mask);
+
+  if(winx >= GDK_DRAWABLE_FBDATA(window)->llim_x
+     && winx < GDK_DRAWABLE_FBDATA(window)->lim_x
+     && winy >= GDK_DRAWABLE_FBDATA(window)->llim_y
+     && winy < GDK_DRAWABLE_FBDATA(window)->lim_y && 0)
+    {
+      GdkWindow *oldwin, *newwin, *curwin;
+      GdkEvent *event;
+
+      curwin = gdk_window_get_pointer(NULL, NULL, NULL, NULL);
+
+      if(is_show)
+       {
+         /* Window is about to be shown */
+         oldwin = curwin;
+         newwin = window;
+       }
+      else
+       {
+         /* Window is about to be hidden */
+         oldwin = window;
+         newwin = curwin;
+       }
+      event = gdk_event_make(oldwin, GDK_LEAVE_NOTIFY, TRUE);
+      if(event)
+       {
+         guint x_int, y_int;
+         event->crossing.subwindow = gdk_window_ref(newwin);
+         gdk_window_get_root_origin(oldwin, &x_int, &y_int);
+         event->crossing.x = winx - x_int;
+         event->crossing.y = winy - y_int;
+         event->crossing.x_root = winx;
+         event->crossing.y_root = winy;
+         event->crossing.mode = GDK_CROSSING_NORMAL;
+         event->crossing.detail = GDK_NOTIFY_UNKNOWN;
+         event->crossing.focus = FALSE;
+         event->crossing.state = my_mask;
+       }
+
+      event = gdk_event_make(newwin, GDK_ENTER_NOTIFY, TRUE);
+      if(event)
+       {
+         guint x_int, y_int;
+         event->crossing.subwindow = gdk_window_ref(oldwin);
+         gdk_window_get_root_origin(newwin, &x_int, &y_int);
+         event->crossing.x = winx - x_int;
+         event->crossing.y = winy - y_int;
+         event->crossing.x_root = winx;
+         event->crossing.y_root = winy;
+         event->crossing.mode = GDK_CROSSING_NORMAL;
+         event->crossing.detail = GDK_NOTIFY_UNKNOWN;
+         event->crossing.focus = FALSE;
+         event->crossing.state = my_mask;
+       }
+    }
+}
+
+void
+gdk_window_show (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+
+  if (!private->drawable.destroyed && !private->mapped)
+    {
+      private->mapped = TRUE;
+
+      if(all_parents_shown((GdkWindowPrivate *)private->parent))
+       {
+         recompute_drawable((GdkDrawable *)window);
+         send_map_events(private, TRUE);
+
+         private->mapped = FALSE; /* a hack, ayup, to make gdk_window_get_pointer get the other window */
+         gdk_fb_window_visibility_crossing(window, TRUE);
+         private->mapped = TRUE;
+       }
+    }
+}
+
+static gboolean
+rects_overlap(GdkRectangle *r1, GdkRectangle *r2)
+{
+  if(r1->x > (r2->x + r2->width))
+    return FALSE;
+  if(r2->x > (r1->x + r1->width))
+    return FALSE;
+  if(r1->y > (r2->y + r2->height))
+    return FALSE;
+  if(r2->y > (r1->y + r1->height))
+    return FALSE;
+  
+  return TRUE;
+}
+
+static void
+gdk_window_on_hide(GdkWindow *window, GdkRectangle *in_rect, GdkWindow *ignore)
+{
+  GdkEvent *event;
+  GdkRectangle this_rect, test_rect;
+
+  if(!GDK_WINDOW_P(window)->mapped || window == ignore || GDK_WINDOW_P(window)->input_only)
+    return;
+
+  this_rect.x = MAX(GDK_DRAWABLE_FBDATA(window)->llim_x - GDK_DRAWABLE_FBDATA(window)->abs_x, 0);
+
+  this_rect.y = MAX(GDK_DRAWABLE_FBDATA(window)->llim_y - GDK_DRAWABLE_FBDATA(window)->abs_y, 0);
+
+  this_rect.width = MIN(GDK_DRAWABLE_P(window)->width,
+                       GDK_DRAWABLE_FBDATA(window)->lim_x - GDK_DRAWABLE_FBDATA(window)->abs_x);
+  this_rect.height = MIN(GDK_DRAWABLE_P(window)->height,
+                        GDK_DRAWABLE_FBDATA(window)->lim_y - GDK_DRAWABLE_FBDATA(window)->abs_y);
+
+  test_rect = this_rect;
+  test_rect.x += GDK_DRAWABLE_FBDATA(window)->abs_x;
+  test_rect.y += GDK_DRAWABLE_FBDATA(window)->abs_y;
+  if(this_rect.width > 0
+     && this_rect.height > 0
+     && rects_overlap(&test_rect, in_rect))
+    {
+      GList *l;
+
+      event = gdk_event_make(window, GDK_EXPOSE, TRUE);
+      if(event)
+       event->expose.area = this_rect;
+
+      for(l = GDK_WINDOW_P(window)->children; l; l = l->next)
+       gdk_window_on_hide(l->data, in_rect, ignore);
+    }
+}
+
+void
+gdk_window_hide (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+
+  if (!private->drawable.destroyed && private->mapped)
+    {
+      GdkEvent *event;
+      GdkRectangle r;
+
+      event = gdk_event_make(window, GDK_UNMAP, TRUE);
+
+      r.x = GDK_DRAWABLE_FBDATA(window)->llim_x;
+      r.y = GDK_DRAWABLE_FBDATA(window)->llim_y;
+      r.width = GDK_DRAWABLE_FBDATA(window)->lim_x - r.x;
+      r.height = GDK_DRAWABLE_FBDATA(window)->lim_y - r.y;
+
+      private->mapped = FALSE;
+      gdk_window_on_hide(private->parent, &r, NULL);
+
+      if(private->parent == gdk_parent_root)
+       gdk_fb_drawable_clear((GdkDrawable *)gdk_parent_root);
+
+      if(all_parents_shown((GdkWindowPrivate *)private->parent))
+       gdk_fb_window_visibility_crossing(window, FALSE);
+    }
+}
+
+void
+gdk_window_withdraw (GdkWindow *window)
+{
+  gdk_window_hide(window);
+}
+
+void
+gdk_window_move (GdkWindow *window,
+                gint       x,
+                gint       y)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+  
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  gdk_window_move_resize (window, x, y,
+                         private->drawable.width, private->drawable.height);
+}
+
+void
+gdk_window_resize (GdkWindow *window,
+                  gint       width,
+                  gint       height)
+{
+  GdkWindowPrivate *private;
+  
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  
+  private = (GdkWindowPrivate*) window;
+  
+  if (width < 1)
+    width = 1;
+  if (height < 1)
+    height = 1;
+  gdk_window_move_resize(window, private->x, private->y, width, height);
+}
+
+static void
+recompute_abs_positions(GdkDrawable *drawable, gint parent_x, gint parent_y,
+                       gint parent_llim_x, gint parent_llim_y,
+                       gint parent_lim_x, gint parent_lim_y)
+{
+  GList *l;
+
+  if(GDK_IS_WINDOW(drawable))
+    {
+      GdkWindowPrivate *private = GDK_WINDOW_P(drawable);
+
+      if(!private->mapped)
+       return;
+
+      GDK_DRAWABLE_FBDATA(private)->abs_x = parent_x + private->x;
+      GDK_DRAWABLE_FBDATA(private)->abs_y = parent_y + private->y;
+      GDK_DRAWABLE_FBDATA(private)->llim_x = MIN(MAX(parent_llim_x, GDK_DRAWABLE_FBDATA(private)->abs_x),
+                                                parent_lim_x);
+      GDK_DRAWABLE_FBDATA(private)->llim_y = MIN(MAX(parent_llim_y, GDK_DRAWABLE_FBDATA(private)->abs_y),
+                                                parent_lim_y);
+      GDK_DRAWABLE_FBDATA(private)->lim_x = MAX(MIN(parent_lim_x, GDK_DRAWABLE_FBDATA(private)->abs_x + GDK_DRAWABLE_P(private)->width),
+                                               GDK_DRAWABLE_FBDATA(private)->llim_x);
+      GDK_DRAWABLE_FBDATA(private)->lim_y = MAX(MIN(parent_lim_y,
+                                               GDK_DRAWABLE_FBDATA(private)->abs_y + GDK_DRAWABLE_P(private)->height),
+                                               GDK_DRAWABLE_FBDATA(private)->llim_y);
+
+      g_assert(GDK_DRAWABLE_FBDATA(private)->llim_x <= GDK_DRAWABLE_FBDATA(private)->lim_x);
+      g_assert(GDK_DRAWABLE_FBDATA(private)->llim_y <= GDK_DRAWABLE_FBDATA(private)->lim_y);
+
+      for(l = private->children; l; l = l->next)
+       recompute_abs_positions(l->data, GDK_DRAWABLE_FBDATA(private)->abs_x, GDK_DRAWABLE_FBDATA(private)->abs_y,
+                               GDK_DRAWABLE_FBDATA(private)->llim_x, GDK_DRAWABLE_FBDATA(private)->llim_y,
+                               GDK_DRAWABLE_FBDATA(private)->lim_x, GDK_DRAWABLE_FBDATA(private)->lim_y);
+    }
+  else
+    {
+      GDK_DRAWABLE_FBDATA(drawable)->abs_x = 0;
+      GDK_DRAWABLE_FBDATA(drawable)->abs_y = 0;
+      GDK_DRAWABLE_FBDATA(drawable)->llim_x = 0;
+      GDK_DRAWABLE_FBDATA(drawable)->llim_y = 0;
+      GDK_DRAWABLE_FBDATA(drawable)->lim_x = GDK_DRAWABLE_P(drawable)->width;
+      GDK_DRAWABLE_FBDATA(drawable)->lim_y = GDK_DRAWABLE_P(drawable)->height;
+    }
+}
+
+static void
+recompute_drawable(GdkDrawable *drawable)
+{
+  if(GDK_IS_WINDOW(drawable))
+    {
+      GdkWindowPrivate *private = GDK_WINDOW_P(drawable);
+      GdkWindow *parent;
+
+      parent = private->parent;
+      if(!parent)
+       parent = gdk_parent_root;
+
+      recompute_abs_positions(drawable, GDK_DRAWABLE_FBDATA(parent)->abs_x,
+                             GDK_DRAWABLE_FBDATA(parent)->abs_y,
+                             GDK_DRAWABLE_FBDATA(parent)->llim_x,
+                             GDK_DRAWABLE_FBDATA(parent)->llim_y,
+                             GDK_DRAWABLE_FBDATA(parent)->lim_x,
+                             GDK_DRAWABLE_FBDATA(parent)->lim_y);
+    }
+  else
+    recompute_abs_positions(drawable, 0, 0, 0, 0, INT_MAX, INT_MAX);
+}
+
+void
+gdk_window_move_resize (GdkWindow *window,
+                       gint       x,
+                       gint       y,
+                       gint       width,
+                       gint       height)
+{
+  GdkWindowPrivate *private;
+  
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  if (width < 1)
+    width = 1;
+  if (height < 1)
+    height = 1;
+  
+  private = (GdkWindowPrivate*) window;
+
+  if (!GDK_DRAWABLE_DESTROYED (window))
+    {
+      private->x = x;
+      private->y = y;
+      GDK_DRAWABLE_P(private)->width = width;
+      GDK_DRAWABLE_P(private)->height = height;
+
+      if(private->mapped)
+       {
+         GdkRectangle r;
+
+         r.x = GDK_DRAWABLE_FBDATA(window)->llim_x;
+         r.y = GDK_DRAWABLE_FBDATA(window)->llim_y;
+         r.width = GDK_DRAWABLE_FBDATA(window)->lim_x - r.x;
+         r.height = GDK_DRAWABLE_FBDATA(window)->lim_y - r.y;
+
+         recompute_drawable((GdkDrawable *)window);
+         send_map_events(private, FALSE);
+
+         gdk_window_on_hide(private->parent, &r, window);
+       }
+    }
+}
+
+void
+gdk_window_reparent (GdkWindow *window,
+                    GdkWindow *new_parent,
+                    gint       x,
+                    gint       y)
+{
+  GdkWindowPrivate *window_private;
+  GdkWindowPrivate *parent_private;
+  GdkWindowPrivate *old_parent_private;
+  
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (new_parent != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (new_parent));
+  
+  if (!new_parent)
+    new_parent = gdk_parent_root;
+
+  window_private = (GdkWindowPrivate*) window;
+  old_parent_private = (GdkWindowPrivate*)window_private->parent;
+  parent_private = (GdkWindowPrivate*) new_parent;
+  
+  g_assert(window_private->drawable.colormap);
+
+  window_private->parent = new_parent;
+  
+  if (old_parent_private)
+    old_parent_private->children = g_list_remove (old_parent_private->children, window);
+
+  parent_private->children = g_list_prepend (parent_private->children, window);
+
+  if(window_private->mapped)
+    recompute_drawable((GdkDrawable *)window);
+}
+
+
+void
+_gdk_windowing_window_clear_area (GdkWindow *window,
+                                 gint       x,
+                                 gint       y,
+                                 gint       width,
+                                 gint       height)
+{
+  GdkPixmap *bgpm;
+  GdkWindow *relto;
+
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  if(GDK_WINDOW_P(window)->input_only)
+    return;
+
+  bgpm = GDK_WINDOW_P(window)->bg_pixmap;
+  for(relto = window; bgpm == GDK_PARENT_RELATIVE_BG && relto; relto = GDK_WINDOW_P(relto)->parent)
+    bgpm = GDK_WINDOW_P(relto)->bg_pixmap;
+
+  if(bgpm && bgpm != GDK_NO_BG)
+    {
+      int curx, cury;
+      int xtrans, ytrans;
+      int xstep, ystep;
+
+      return; /* Don't bother doing this - gtk+ will do it itself using GC tiles */
+
+      xtrans = GDK_DRAWABLE_FBDATA(relto)->abs_x - GDK_DRAWABLE_FBDATA(window)->abs_x;
+      ytrans = GDK_DRAWABLE_FBDATA(relto)->abs_y - GDK_DRAWABLE_FBDATA(window)->abs_y;
+
+      for(cury = y - ytrans; cury < (y - ytrans + height); cury += ystep)
+       {
+         int drawh = cury % GDK_DRAWABLE_P(bgpm)->height;
+         ystep = GDK_DRAWABLE_P(bgpm)->height - drawh;
+
+         for(curx = x - xtrans; curx < (x - xtrans + width); curx += xstep)
+           {
+             int draww = curx % GDK_DRAWABLE_P(bgpm)->width;
+             xstep = GDK_DRAWABLE_P(bgpm)->width - draww;
+
+             gdk_fb_draw_drawable_2(window, NULL, bgpm,
+                                    draww, drawh, curx + xtrans, cury + ytrans,
+                                    xstep, ystep, FALSE, TRUE);
+           }
+       }
+    }
+  else if(!bgpm)
+    gdk_fb_draw_rectangle(window, NULL, TRUE, x, y, width, height);
+}
+
+/* What's the diff? */
+void
+_gdk_windowing_window_clear_area_e (GdkWindow *window,
+                                   gint       x,
+                                   gint       y,
+                                   gint       width,
+                                   gint       height)
+{
+  _gdk_windowing_window_clear_area(window, x, y, width, height);
+}
+
+static gint
+compare_window_levels(gconstpointer a, gconstpointer b)
+{
+  return (GDK_WINDOW_FBDATA(b)->level - GDK_WINDOW_FBDATA(a)->level);
+}
+
+/* Child list is sorted bottom-to-top */
+static void
+gdk_window_resort_children(GdkWindow *win)
+{
+  GdkWindowPrivate *private = GDK_WINDOW_P(win);
+
+  private->children = g_list_sort(private->children, compare_window_levels);
+
+  /* Now the fun part - redraw */
+  if(GDK_WINDOW_P(win)->parent)
+    send_map_events(private, FALSE);
+}
+
+void
+gdk_window_raise (GdkWindow *window)
+{
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  GDK_WINDOW_FBDATA(window)->level++;
+
+  if(GDK_WINDOW_P(window)->parent)
+    gdk_window_resort_children(GDK_WINDOW_P(window)->parent);
+}
+
+void
+gdk_window_lower (GdkWindow *window)
+{
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  
+  GDK_WINDOW_FBDATA(window)->level--;
+
+  if(GDK_WINDOW_P(window)->parent)
+    gdk_window_resort_children(GDK_WINDOW_P(window)->parent);
+}
+
+void
+gdk_window_set_hints (GdkWindow *window,
+                     gint       x,
+                     gint       y,
+                     gint       min_width,
+                     gint       min_height,
+                     gint       max_width,
+                     gint       max_height,
+                     gint       flags)
+{
+}
+
+void 
+gdk_window_set_geometry_hints (GdkWindow      *window,
+                              GdkGeometry    *geometry,
+                              GdkWindowHints  geom_mask)
+{
+}
+
+void
+gdk_window_set_title (GdkWindow   *window,
+                     const gchar *title)
+{
+}
+
+void          
+gdk_window_set_role (GdkWindow   *window,
+                    const gchar *role)
+{
+}
+
+void          
+gdk_window_set_transient_for (GdkWindow *window, 
+                             GdkWindow *parent)
+{
+  GDK_WINDOW_FBDATA(window)->level = GDK_WINDOW_FBDATA(parent)->level + 1;
+}
+
+void
+gdk_window_set_background (GdkWindow *window,
+                          GdkColor  *color)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+  
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  
+  private->bg_color = *color;
+
+  if (private->bg_pixmap &&
+      private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
+      private->bg_pixmap != GDK_NO_BG)
+    {
+      gdk_pixmap_unref (private->bg_pixmap);
+      private->bg_pixmap = NULL;
+    }
+}
+
+void
+gdk_window_set_back_pixmap (GdkWindow *window,
+                           GdkPixmap *pixmap,
+                           gboolean   parent_relative)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+  GdkPixmap *old_pixmap;
+
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (pixmap == NULL || !parent_relative);
+
+  old_pixmap = private->bg_pixmap;
+
+  if (parent_relative)
+    {
+      private->bg_pixmap = GDK_PARENT_RELATIVE_BG;
+    }
+  else
+    {
+      if (pixmap)
+       {
+         gdk_pixmap_ref (pixmap);
+         private->bg_pixmap = pixmap;
+       }
+      else
+       {
+         private->bg_pixmap = GDK_NO_BG;
+       }
+    }
+
+  if (old_pixmap &&
+      old_pixmap != GDK_PARENT_RELATIVE_BG &&
+      old_pixmap != GDK_NO_BG)
+    gdk_pixmap_unref (old_pixmap);
+}
+
+void
+gdk_window_set_cursor (GdkWindow *window,
+                      GdkCursor *cursor)
+{
+  GdkCursor *old_cursor = GDK_WINDOW_FBDATA(window)->cursor;
+
+  GDK_WINDOW_FBDATA(window)->cursor = cursor?gdk_cursor_ref(cursor):NULL;
+
+  if(old_cursor)
+    gdk_cursor_unref(old_cursor);
+}
+
+void
+gdk_window_get_geometry (GdkWindow *window,
+                        gint      *x,
+                        gint      *y,
+                        gint      *width,
+                        gint      *height,
+                        gint      *depth)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+  
+  g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
+  
+  if (!window)
+    window = gdk_parent_root;
+  
+  if (!GDK_DRAWABLE_DESTROYED (window))
+    {
+
+      if (x)
+       *x = private->x;
+      if (y)
+       *y = private->y;
+      if (width)
+       *width = GDK_DRAWABLE_P(window)->width;
+      if (height)
+       *height = GDK_DRAWABLE_P(window)->height;
+      if (depth)
+       *depth = gdk_display->modeinfo.bits_per_pixel;
+    }
+}
+
+gboolean
+gdk_window_get_origin (GdkWindow *window,
+                      gint      *x,
+                      gint      *y)
+{
+  g_return_val_if_fail (window != NULL, 0);
+  
+  if (x)
+    *x = GDK_DRAWABLE_FBDATA(window)->abs_x;
+  if (y)
+    *y = GDK_DRAWABLE_FBDATA(window)->abs_y;
+
+  return TRUE;
+}
+
+gboolean
+gdk_window_get_deskrelative_origin (GdkWindow *window,
+                                   gint      *x,
+                                   gint      *y)
+{
+  gint tx = 0;
+  gint ty = 0;
+  gboolean return_val;
+
+  g_return_val_if_fail (window != NULL, 0);
+  
+  if (!GDK_DRAWABLE_DESTROYED (window))
+    {
+      tx = GDK_DRAWABLE_FBDATA(window)->abs_x;
+      ty = GDK_DRAWABLE_FBDATA(window)->abs_y;
+
+      return_val = TRUE;
+    }
+  else
+    return_val = FALSE;
+  
+  if (x)
+    *x = tx;
+  if (y)
+    *y = ty;
+
+  return return_val;
+}
+
+void
+gdk_window_get_root_origin (GdkWindow *window,
+                           gint      *x,
+                           gint      *y)
+{
+  gdk_window_get_deskrelative_origin(window, x, y);
+}
+
+GdkWindow*
+gdk_window_get_pointer (GdkWindow       *window,
+                       gint            *x,
+                       gint            *y,
+                       GdkModifierType *mask)
+{
+  GdkWindow *return_val;
+  int winx = 0;
+  int winy = 0;
+  int x_int, y_int;
+  GdkModifierType my_mask;
+
+  g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
+  
+  if (!window)
+    window = gdk_parent_root;
+  
+  gdk_window_get_root_origin(window, &x_int, &y_int);
+  gdk_input_ps2_get_mouseinfo(&winx, &winy, &my_mask);
+
+  winx -= x_int;
+  winy -= y_int;
+
+  if (x)
+    *x = winx;
+  if (y)
+    *y = winy;
+  if (mask)
+    *mask = my_mask;
+  
+  return_val = NULL;
+  
+  if((winx >= 0) && (winx < GDK_DRAWABLE_P(window)->width)
+     && (winy >= 0) && (winy < GDK_DRAWABLE_P(window)->height))
+    {
+      GdkWindowPrivate *private;
+      GdkWindowPrivate *sub;
+      int subx = winx, suby = winy;
+
+      for(private = sub = (GdkWindowPrivate *)window; sub; private = sub)
+       {
+         GList *ltmp;
+
+         for(ltmp = private->children; ltmp; ltmp = ltmp->next)
+           {
+             sub = ltmp->data;
+
+             if(!sub->mapped)
+               continue;
+
+             if(subx >= sub->x
+                && (subx < (GDK_DRAWABLE_P(sub)->width + sub->x))
+                && (suby >= sub->y)
+                && (suby < (GDK_DRAWABLE_P(sub)->height + sub->y)))
+               {
+                 subx -= sub->x;
+                 suby -= sub->y;
+                 break;
+               }
+           }
+
+         if(!ltmp)
+           {
+             sub = NULL;
+             break;
+           }
+       }
+
+      return_val = (GdkWindow *)private;
+    }
+
+  if(!return_val)
+    return_val = gdk_parent_root;
+
+  return return_val;
+}
+
+GdkWindow*
+gdk_window_at_pointer (gint *win_x,
+                      gint *win_y)
+{
+  gint rx, ry;
+  GdkWindow *retval = gdk_window_get_pointer(NULL, win_x, win_y, NULL);
+
+  if(retval)
+    {
+      gdk_window_get_origin(retval, &ry, &rx);
+      if(win_x)
+       (*win_x) -= rx;
+      if(win_y)
+       (*win_y) -= ry;
+    }
+
+  return retval;
+}
+
+GList*
+gdk_window_get_children (GdkWindow *window)
+{
+  GList *children;
+  
+  g_return_val_if_fail (window != NULL, NULL);
+  g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
+
+  if (GDK_DRAWABLE_DESTROYED (window))
+    return NULL;
+  
+  children = NULL;
+
+  return ((GdkWindowPrivate *)window)->children; /* Need to copy this list? */
+}
+
+GdkEventMask  
+gdk_window_get_events (GdkWindow *window)
+{
+  g_return_val_if_fail (window != NULL, 0);
+  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
+
+  if (GDK_DRAWABLE_DESTROYED (window))
+    return 0;
+  else
+    return GDK_WINDOW_FBDATA(window)->event_mask;
+}
+
+void          
+gdk_window_set_events (GdkWindow       *window,
+                      GdkEventMask     event_mask)
+{
+  
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  
+  if (!GDK_DRAWABLE_DESTROYED (window))
+    GDK_WINDOW_FBDATA(window)->event_mask = event_mask;
+}
+
+void
+gdk_window_add_colormap_windows (GdkWindow *window)
+{
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  
+  /* N/A */
+}
+
+/*
+ * This needs the X11 shape extension.
+ * If not available, shaped windows will look
+ * ugly, but programs still work.    Stefan Wille
+ */
+void
+gdk_window_shape_combine_mask (GdkWindow *window,
+                              GdkBitmap *mask,
+                              gint x, gint y)
+{
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+}
+
+void
+gdk_window_set_override_redirect (GdkWindow *window,
+                                 gboolean override_redirect)
+{
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  /* N/A */
+}
+
+void          
+gdk_window_set_icon (GdkWindow *window, 
+                    GdkWindow *icon_window,
+                    GdkPixmap *pixmap,
+                    GdkBitmap *mask)
+{
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  /* N/A */
+}
+
+void          
+gdk_window_set_icon_name (GdkWindow *window, 
+                         const gchar *    name)
+{
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  /* N/A */
+}
+
+void          
+gdk_window_set_group (GdkWindow *window, 
+                     GdkWindow *leader)
+{
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (leader != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (leader));
+
+  /* N/A */
+}
+
+void
+gdk_window_set_decorations (GdkWindow      *window,
+                           GdkWMDecoration decorations)
+{
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  /* N/A */
+}
+
+void
+gdk_window_set_functions (GdkWindow    *window,
+                         GdkWMFunction functions)
+{
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  /* N/A */
+}
+
+void
+gdk_window_set_child_shapes (GdkWindow *window)
+{
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  
+}
+
+void
+gdk_window_merge_child_shapes (GdkWindow *window)
+{
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  
+}
+
+/*************************************************************
+ * gdk_window_set_static_gravities:
+ *     Set the bit gravity of the given window to static,
+ *     and flag it so all children get static subwindow
+ *     gravity.
+ *   arguments:
+ *     window: window for which to set static gravity
+ *     use_static: Whether to turn static gravity on or off.
+ *   results:
+ *     Does the XServer support static gravity?
+ *************************************************************/
+
+gboolean 
+gdk_window_set_static_gravities (GdkWindow *window,
+                                gboolean   use_static)
+{
+  g_return_val_if_fail (window != NULL, FALSE);
+  g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
+  
+  return TRUE;
+}
+
+void
+_gdk_windowing_window_get_offsets      (GdkWindow  *window,
+                                       gint       *x_offset,
+                                       gint       *y_offset)
+{
+  *x_offset = *y_offset = 0;
+}
+
+gboolean
+_gdk_windowing_window_queue_antiexpose (GdkWindow  *window,
+                                       GdkRegion  *area)
+{
+  return FALSE;
+}
diff --git a/gdk/linux-fb/mi.h b/gdk/linux-fb/mi.h
new file mode 100644 (file)
index 0000000..b651797
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef MI_H
+#define MI_H 1
+
+#include "mitypes.h"
+#include "mistruct.h"
+#include "mifpoly.h"
+#include "mifillarc.h"
+#include "mipoly.h"
+
+void miPolyArc(GdkDrawable *pDraw, GdkGC *pGC, int narcs, miArc *parcs);
+void miPolyFillArc(GdkDrawable *pDraw, GdkGC *pGC, int narcs, miArc *parcs);
+void miFillPolygon(GdkDrawable *dst, GdkGC *pgc, int shape, int mode, int count, GdkPoint *pPts);
+
+miDashPtr miDashLine(int npt, GdkPoint *ppt, unsigned int nDash, unsigned char *pDash, unsigned int offset, int *pnseg);
+void miZeroLine(GdkDrawable *pDraw, GdkGC *pGC, int mode, int npt, GdkPoint *pptInit);
+void miZeroDashLine(GdkDrawable *dst, GdkGC *pgc, int mode, int nptInit, GdkPoint *pptInit);
+void miStepDash (int dist, int *pDashIndex, unsigned char *pDash, int numInDashList, int *pDashOffset);
+void miWideDash (GdkDrawable *pDrawable, GdkGC *pGC, int mode, int npt, GdkPoint *pPts);
+void miWideLine (GdkDrawable *pDrawable, GdkGC *pGC, int mode, int npt, GdkPoint *pPts);
+
+#endif
diff --git a/gdk/linux-fb/miarc.c b/gdk/linux-fb/miarc.c
new file mode 100644 (file)
index 0000000..a3d7395
--- /dev/null
@@ -0,0 +1,3569 @@
+/* $XFree86: xc/programs/Xserver/mi/miarc.c,v 3.7 1999/12/27 00:39:56 robin Exp $ */
+/***********************************************************
+
+Copyright 1987, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+/* $TOG: miarc.c /main/91 1998/02/09 14:45:57 kaleb $ */
+/* Author: Keith Packard and Bob Scheifler */
+/* Warning: this code is toxic, do not dally very long here. */
+
+#define _XOPEN_SOURCE_EXTENDED /* to get prototype for cbrt on some systems */
+#define _XOPEN_SOURCE          /* to get prototype for hypot on some systems */
+
+#include <string.h>            /* memmove */
+#include <limits.h>
+
+#include <math.h>
+
+#include "mi.h"
+#include "gdkprivate-fb.h"
+
+static double miDsin(double a), miDcos(double a), miDasin(double a), miDatan2(double x, double y);
+
+#ifdef ICEILTEMPDECL
+ICEILTEMPDECL
+#endif
+
+/*
+ * some interesting sematic interpretation of the protocol:
+ *
+ * Self intersecting arcs (i.e. those spanning 360 degrees) 
+ *  never join with other arcs, and are drawn without caps
+ *  (unless on/off dashed, in which case each dash segment
+ *  is capped, except when the last segment meets the
+ *  first segment, when no caps are drawn)
+ *
+ * double dash arcs are drawn in two parts, first the
+ *  odd dashes (drawn in background) then the even dashes
+ *  (drawn in foreground).  This means that overlapping
+ *  sections of foreground/background are drawn twice,
+ *  first in background then in foreground.  The double-draw
+ *  occurs even when the function uses the destination values
+ *  (e.g. xor mode).  This is the same way the wide-line
+ *  code works and should be "fixed".
+ *
+ */
+
+#undef max
+#undef min
+
+#if defined (__GNUC__) && defined (__STDC__) && !defined (__STRICT_ANSI__)
+#define USE_INLINE
+#endif
+
+struct bound {
+       double  min, max;
+};
+
+struct ibound {
+       int     min, max;
+};
+
+#define boundedLe(value, bounds)\
+       ((bounds).min <= (value) && (value) <= (bounds).max)
+
+struct line {
+       double  m, b;
+       int     valid;
+};
+
+#define intersectLine(y,line) (line.m * (y) + line.b)
+
+/*
+ * these are all y value bounds
+ */
+
+struct arc_bound {
+       struct bound    ellipse;
+       struct bound    inner;
+       struct bound    outer;
+       struct bound    right;
+       struct bound    left;
+       struct ibound   inneri;
+       struct ibound   outeri;
+};
+
+struct accelerators {
+       double          tail_y;
+       double          h2;
+       double          w2;
+       double          h4;
+       double          w4;
+       double          h2mw2;
+       double          h2l;
+       double          w2l;
+       double          fromIntX;
+       double          fromIntY;
+       struct line     left, right;
+       int             yorgu;
+       int             yorgl;
+       int             xorg;
+};
+
+struct arc_def {
+       double  w, h, l;
+       double  a0, a1;
+};
+
+# define todeg(xAngle) (((double) (xAngle)) / 64.0)
+
+# define RIGHT_END     0
+# define LEFT_END      1
+
+typedef struct _miArcJoin {
+       int     arcIndex0, arcIndex1;
+       int     phase0, phase1;
+       int     end0, end1;
+} miArcJoinRec, *miArcJoinPtr;
+
+typedef struct _miArcCap {
+       int             arcIndex;
+       int             end;            
+} miArcCapRec, *miArcCapPtr;
+
+typedef struct _miArcFace {
+       SppPointRec     clock;
+       SppPointRec     center;
+       SppPointRec     counterClock;
+} miArcFaceRec, *miArcFacePtr;
+
+typedef struct _miArcData {
+       miArc           arc;
+       int             render;         /* non-zero means render after drawing */
+       int             join;           /* related join */
+       int             cap;            /* related cap */
+       int             selfJoin;       /* final dash meets first dash */
+       miArcFaceRec    bounds[2];
+       double          x0, y0, x1, y1;
+} miArcDataRec, *miArcDataPtr;
+
+/*
+ * This is an entire sequence of arcs, computed and categorized according
+ * to operation.  miDashArcs generates either one or two of these.
+ */
+
+typedef struct _miPolyArc {
+       int             narcs;
+       miArcDataPtr    arcs;
+       int             ncaps;
+       miArcCapPtr     caps;
+       int             njoins;
+       miArcJoinPtr    joins;
+} miPolyArcRec, *miPolyArcPtr;
+
+typedef struct {
+    short lx, lw, rx, rw;
+} miArcSpan;
+
+typedef struct {
+    miArcSpan *spans;
+    int count1, count2, k;
+    char top, bot, hole;
+} miArcSpanData;
+
+typedef struct {
+    unsigned long lrustamp;
+    unsigned short lw;
+    unsigned short width, height;
+    miArcSpanData *spdata;
+} arcCacheRec;
+
+# define DASH_MAP_SIZE 91
+
+typedef struct {
+       double  map[DASH_MAP_SIZE];
+} dashMap;
+
+static void fillSpans(GdkDrawable *pDrawable, GdkGC *pGC);
+static void newFinalSpan(int y, int xmin, int xmax);
+static void drawArc (miArc *tarc, int l, int a0, int a1, miArcFacePtr right, miArcFacePtr left);
+static void drawQuadrant(struct arc_def *def, struct accelerators *acc,
+                        int a0, int a1, int mask, miArcFacePtr right, miArcFacePtr left,
+                        miArcSpanData *spdata);
+static void drawZeroArc(GdkDrawable *pDraw, GdkGC *pGC, miArc *tarc, int lw, miArcFacePtr right, miArcFacePtr left);
+static void miArcJoin(GdkDrawable *pDraw, GdkGC *pGC, miArcFacePtr pRight, miArcFacePtr pLeft, int xOrgRight, int yOrgRight,
+                     double xFtransRight, double yFtransRight,
+                     int xOrgLeft, int yOrgLeft,
+                     double xFtransLeft, double yFtransLeft);
+static void miArcCap(GdkDrawable *pDraw, GdkGC *pGC, miArcFacePtr pFace, int end, int xOrg, int yOrg,
+                    double xFtrans, double yFtrans);
+static void miRoundCap(GdkDrawable *pDraw, GdkGC *pGC, SppPointRec pCenter, SppPointRec pEnd, SppPointRec pCorner,
+                      SppPointRec pOtherCorner, int fLineEnd, int xOrg, int yOrg,
+                      double xFtrans, double yFtrans);
+static void miFreeArcs(miPolyArcPtr arcs, GdkGC *pGC);
+static int computeAngleFromPath(int startAngle, int endAngle, dashMap *map, int *lenp, int backwards);
+static miPolyArcPtr miComputeArcs (miArc *parcs, int narcs, GdkGC *gc);
+static int miGetArcPts(SppArcPtr parc, int cpt, SppPointPtr *ppPts);
+
+# define CUBED_ROOT_2  1.2599210498948732038115849718451499938964
+# define CUBED_ROOT_4  1.5874010519681993173435330390930175781250
+
+/*
+ * draw one segment of the arc using the arc spans generation routines
+ */
+
+static void
+miArcSegment(GdkDrawable *pDraw, GdkGC *pGC, miArc tarc, miArcFacePtr right, miArcFacePtr left)
+{
+    int l = GDK_GC_FBDATA(pGC)->values.line_width;
+    int a0, a1, startAngle, endAngle;
+    miArcFacePtr       temp;
+
+    if (!l)
+       l = 1;
+
+    if (tarc.width == 0 || tarc.height == 0) {
+       drawZeroArc (pDraw, pGC, &tarc, l, left, right);
+       return;
+    }
+
+    a0 = tarc.angle1;
+    a1 = tarc.angle2;
+    if (a1 > FULLCIRCLE)
+       a1 = FULLCIRCLE;
+    else if (a1 < -FULLCIRCLE)
+       a1 = -FULLCIRCLE;
+    if (a1 < 0) {
+       startAngle = a0 + a1;
+       endAngle = a0;
+       temp = right;
+       right = left;
+       left = temp;
+    } else {
+       startAngle = a0;
+       endAngle = a0 + a1;
+    }
+    /*
+     * bounds check the two angles
+     */
+    if (startAngle < 0)
+       startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
+    if (startAngle >= FULLCIRCLE)
+       startAngle = startAngle % FULLCIRCLE;
+    if (endAngle < 0)
+       endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE;
+    if (endAngle > FULLCIRCLE)
+       endAngle = (endAngle-1) % FULLCIRCLE + 1;
+    if ((startAngle == endAngle) && a1) {
+       startAngle = 0;
+       endAngle = FULLCIRCLE;
+    }
+
+    drawArc (&tarc, l, startAngle, endAngle, right, left);
+}
+
+/*
+
+Three equations combine to describe the boundaries of the arc
+
+x^2/w^2 + y^2/h^2 = 1                  ellipse itself
+(X-x)^2 + (Y-y)^2 = r^2                        circle at (x, y) on the ellipse
+(Y-y) = (X-x)*w^2*y/(h^2*x)            normal at (x, y) on the ellipse
+
+These lead to a quartic relating Y and y
+
+y^4 - (2Y)y^3 + (Y^2 + (h^4 - w^2*r^2)/(w^2 - h^2))y^2
+    - (2Y*h^4/(w^2 - h^2))y + (Y^2*h^4)/(w^2 - h^2) = 0
+
+The reducible cubic obtained from this quartic is
+
+z^3 - (3N)z^2 - 2V = 0
+
+where
+
+N = (Y^2 + (h^4 - w^2*r^2/(w^2 - h^2)))/6
+V = w^2*r^2*Y^2*h^4/(4 *(w^2 - h^2)^2)
+
+Let
+
+t = z - N
+p = -N^2
+q = -N^3 - V
+
+Then we get
+
+t^3 + 3pt + 2q = 0
+
+The discriminant of this cubic is
+
+D = q^2 + p^3
+
+When D > 0, a real root is obtained as
+
+z = N + cbrt(-q+sqrt(D)) + cbrt(-q-sqrt(D))
+
+When D < 0, a real root is obtained as
+
+z = N - 2m*cos(acos(-q/m^3)/3)
+
+where
+
+m = sqrt(|p|) * sign(q)
+
+Given a real root Z of the cubic, the roots of the quartic are the roots
+of the two quadratics
+
+y^2 + ((b+A)/2)y + (Z + (bZ - d)/A) = 0
+
+where 
+
+A = +/- sqrt(8Z + b^2 - 4c)
+b, c, d are the cubic, quadratic, and linear coefficients of the quartic
+
+Some experimentation is then required to determine which solutions
+correspond to the inner and outer boundaries.
+
+*/
+
+#define CACHESIZE 25
+
+static arcCacheRec arcCache[CACHESIZE];
+static unsigned long lrustamp;
+static arcCacheRec *lastCacheHit = &arcCache[0];
+
+#if 0
+static RESTYPE cacheType;
+
+/*
+ * External so it can be called when low on memory.
+ * Call with a zero ID in that case.
+ */
+/*ARGSUSED*/
+int
+miFreeArcCache (data, id)
+    gpointer       data;
+    guint                  id;
+{
+    int k;
+    arcCacheRec *cent;
+
+    if (id)
+       cacheType = 0;
+
+    for (k = CACHESIZE, cent = &arcCache[0]; --k >= 0; cent++)
+    {
+       if (cent->spdata)
+       {
+           cent->lrustamp = 0;
+           cent->lw = 0;
+           g_free(cent->spdata);
+           cent->spdata = NULL;
+       }
+    }
+    lrustamp = 0;
+    return TRUE;
+}
+#endif
+
+static void
+miComputeCircleSpans(int lw, miArc *parc, miArcSpanData *spdata)
+{
+    register miArcSpan *span;
+    int doinner;
+    register int x, y, e;
+    int xk, yk, xm, ym, dx, dy;
+    register int slw, inslw;
+    int inx, iny, ine;
+    int inxk, inyk, inxm, inym;
+
+    doinner = -lw;
+    slw = parc->width - doinner;
+    y = parc->height >> 1;
+    dy = parc->height & 1;
+    dx = 1 - dy;
+    MIWIDEARCSETUP(x, y, dy, slw, e, xk, xm, yk, ym);
+    inslw = parc->width + doinner;
+    if (inslw > 0)
+    {
+       spdata->hole = spdata->top;
+       MIWIDEARCSETUP(inx, iny, dy, inslw, ine, inxk, inxm, inyk, inym);
+    }
+    else
+    {
+       spdata->hole = FALSE;
+       doinner = -y;
+    }
+    spdata->count1 = -doinner - spdata->top;
+    spdata->count2 = y + doinner;
+    span = spdata->spans;
+    while (y)
+    {
+       MIFILLARCSTEP(slw);
+       span->lx = dy - x;
+       if (++doinner <= 0)
+       {
+           span->lw = slw;
+           span->rx = 0;
+           span->rw = span->lx + slw;
+       }
+       else
+       {
+           MIFILLINARCSTEP(inslw);
+           span->lw = x - inx;
+           span->rx = dy - inx + inslw;
+           span->rw = inx - x + slw - inslw;
+       }
+       span++;
+    }
+    if (spdata->bot)
+    {
+       if (spdata->count2)
+           spdata->count2--;
+       else
+       {
+           if (lw > (int)parc->height)
+               span[-1].rx = span[-1].rw = -((lw - (int)parc->height) >> 1);
+           else
+               span[-1].rw = 0;
+           spdata->count1--;
+       }
+    }
+}
+
+static void
+miComputeEllipseSpans(int lw, miArc *parc, miArcSpanData *spdata)
+{
+    register miArcSpan *span;
+    double w, h, r, xorg;
+    double Hs, Hf, WH, K, Vk, Nk, Fk, Vr, N, Nc, Z, rs;
+    double A, T, b, d, x, y, t, inx, outx, hepp, hepm;
+    int flip, solution;
+
+    w = (double)parc->width / 2.0;
+    h = (double)parc->height / 2.0;
+    r = lw / 2.0;
+    rs = r * r;
+    Hs = h * h;
+    WH = w * w - Hs;
+    Nk = w * r;
+    Vk = (Nk * Hs) / (WH + WH);
+    Hf = Hs * Hs;
+    Nk = (Hf - Nk * Nk) / WH;
+    Fk = Hf / WH;
+    hepp = h + EPSILON;
+    hepm = h - EPSILON;
+    K = h + ((lw - 1) >> 1);
+    span = spdata->spans;
+    if (parc->width & 1)
+       xorg = .5;
+    else
+       xorg = 0.0;
+    if (spdata->top)
+    {
+       span->lx = 0;
+       span->lw = 1;
+       span++;
+    }
+    spdata->count1 = 0;
+    spdata->count2 = 0;
+    spdata->hole = (spdata->top &&
+                (int)parc->height * lw <= (int)(parc->width * parc->width) &&
+                   lw < (int)parc->height);
+    for (; K > 0.0; K -= 1.0)
+    {
+       N = (K * K + Nk) / 6.0;
+       Nc = N * N * N;
+       Vr = Vk * K;
+       t = Nc + Vr * Vr;
+       d = Nc + t;
+       if (d < 0.0) {
+           d = Nc;
+           b = N;
+           if ( (b < 0.0) == (t < 0.0) )
+           {
+               b = -b;
+               d = -d;
+           }
+           Z = N - 2.0 * b * cos(acos(-t / d) / 3.0);
+           if ( (Z < 0.0) == (Vr < 0.0) )
+               flip = 2;
+           else
+               flip = 1;
+       }
+       else
+       {
+           d = Vr * sqrt(d);
+           Z = N + cbrt(t + d) + cbrt(t - d);
+           flip = 0;
+       }
+       A = sqrt((Z + Z) - Nk);
+       T = (Fk - Z) * K / A;
+       inx = 0.0;
+       solution = FALSE;
+       b = -A + K;
+       d = b * b - 4 * (Z + T);
+       if (d >= 0)
+       {
+           d = sqrt(d);
+           y = (b + d) / 2;
+           if ((y >= 0.0) && (y < hepp))
+           {
+               solution = TRUE;
+               if (y > hepm)
+                   y = h;
+               t = y / h;
+               x = w * sqrt(1 - (t * t));
+               t = K - y;
+               if (rs - (t * t) >= 0)
+                  t = sqrt(rs - (t * t));
+               else
+                  t = 0;
+               if (flip == 2)
+                   inx = x - t;
+               else
+                   outx = x + t;
+           }
+       }
+       b = A + K;
+       d = b * b - 4 * (Z - T);
+       /* Because of the large magnitudes involved, we lose enough precision
+        * that sometimes we end up with a negative value near the axis, when
+        * it should be positive.  This is a workaround.
+        */
+       if (d < 0 && !solution)
+           d = 0.0;
+       if (d >= 0) {
+           d = sqrt(d);
+           y = (b + d) / 2;
+           if (y < hepp)
+           {
+               if (y > hepm)
+                   y = h;
+               t = y / h;
+               x = w * sqrt(1 - (t * t));
+               t = K - y;
+               if (rs - (t * t) >= 0)
+                  inx = x - sqrt(rs - (t * t));
+               else
+                  inx = x;
+           }
+           y = (b - d) / 2;
+           if (y >= 0.0)
+           {
+               if (y > hepm)
+                   y = h;
+               t = y / h;
+               x = w * sqrt(1 - (t * t));
+               t = K - y;
+               if (rs - (t * t) >= 0)
+                  t = sqrt(rs - (t * t));
+               else 
+                  t = 0;
+               if (flip == 1)
+                   inx = x - t;
+               else
+                   outx = x + t;
+           }
+       }
+       span->lx = ICEIL(xorg - outx);
+       if (inx <= 0.0)
+       {
+           spdata->count1++;
+           span->lw = ICEIL(xorg + outx) - span->lx;
+           span->rx = ICEIL(xorg + inx);
+           span->rw = -ICEIL(xorg - inx);
+       }
+       else
+       {
+           spdata->count2++;
+           span->lw = ICEIL(xorg - inx) - span->lx;
+           span->rx = ICEIL(xorg + inx);
+           span->rw = ICEIL(xorg + outx) - span->rx;
+       }
+       span++;
+    }
+    if (spdata->bot)
+    {
+       outx = w + r;
+       if (r >= h && r <= w)
+           inx = 0.0;
+       else if (Nk < 0.0 && -Nk < Hs)
+       {
+           inx = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk);
+           if (inx > w - r)
+               inx = w - r;
+       }
+       else
+           inx = w - r;
+       span->lx = ICEIL(xorg - outx);
+       if (inx <= 0.0)
+       {
+           span->lw = ICEIL(xorg + outx) - span->lx;
+           span->rx = ICEIL(xorg + inx);
+           span->rw = -ICEIL(xorg - inx);
+       }
+       else
+       {
+           span->lw = ICEIL(xorg - inx) - span->lx;
+           span->rx = ICEIL(xorg + inx);
+           span->rw = ICEIL(xorg + outx) - span->rx;
+       }
+    }
+    if (spdata->hole)
+    {
+       span = &spdata->spans[spdata->count1];
+       span->lw = -span->lx;
+       span->rx = 1;
+       span->rw = span->lw;
+       spdata->count1--;
+       spdata->count2++;
+    }
+}
+
+static double
+tailX(double K, struct arc_def *def, struct arc_bound *bounds, struct accelerators *acc)
+{
+    double w, h, r;
+    double Hs, Hf, WH, Vk, Nk, Fk, Vr, N, Nc, Z, rs;
+    double A, T, b, d, x, y, t, hepp, hepm;
+    int flip, solution;
+    double xs[2];
+    double *xp;
+
+    w = def->w;
+    h = def->h;
+    r = def->l;
+    rs = r * r;
+    Hs = acc->h2;
+    WH = -acc->h2mw2;
+    Nk = def->w * r;
+    Vk = (Nk * Hs) / (WH + WH);
+    Hf = acc->h4;
+    Nk = (Hf - Nk * Nk) / WH;
+    if (K == 0.0) {
+       if (Nk < 0.0 && -Nk < Hs) {
+           xs[0] = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk);
+           xs[1] = w - r;
+           if (acc->left.valid && boundedLe(K, bounds->left) &&
+               !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0)
+               return xs[1];
+           if (acc->right.valid && boundedLe(K, bounds->right) &&
+               !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0)
+               return xs[1];
+           return xs[0];
+       }
+       return w - r;
+    }
+    Fk = Hf / WH;
+    hepp = h + EPSILON;
+    hepm = h - EPSILON;
+    N = (K * K + Nk) / 6.0;
+    Nc = N * N * N;
+    Vr = Vk * K;
+    xp = xs;
+    xs[0] = 0.0;
+    t = Nc + Vr * Vr;
+    d = Nc + t;
+    if (d < 0.0) {
+       d = Nc;
+       b = N;
+       if ( (b < 0.0) == (t < 0.0) )
+       {
+           b = -b;
+           d = -d;
+       }
+       Z = N - 2.0 * b * cos(acos(-t / d) / 3.0);
+       if ( (Z < 0.0) == (Vr < 0.0) )
+           flip = 2;
+       else
+           flip = 1;
+    }
+    else
+    {
+       d = Vr * sqrt(d);
+       Z = N + cbrt(t + d) + cbrt(t - d);
+       flip = 0;
+    }
+    A = sqrt((Z + Z) - Nk);
+    T = (Fk - Z) * K / A;
+    solution = FALSE;
+    b = -A + K;
+    d = b * b - 4 * (Z + T);
+    if (d >= 0 && flip == 2)
+    {
+       d = sqrt(d);
+       y = (b + d) / 2;
+       if ((y >= 0.0) && (y < hepp))
+       {
+           solution = TRUE;
+           if (y > hepm)
+               y = h;
+           t = y / h;
+           x = w * sqrt(1 - (t * t));
+           t = K - y;
+           if (rs - (t * t) >= 0)
+              t = sqrt(rs - (t * t));
+           else
+              t = 0;
+           *xp++ = x - t;
+       }
+    }
+    b = A + K;
+    d = b * b - 4 * (Z - T);
+    /* Because of the large magnitudes involved, we lose enough precision
+     * that sometimes we end up with a negative value near the axis, when
+     * it should be positive.  This is a workaround.
+     */
+    if (d < 0 && !solution)
+       d = 0.0;
+    if (d >= 0) {
+       d = sqrt(d);
+       y = (b + d) / 2;
+       if (y < hepp)
+       {
+           if (y > hepm)
+               y = h;
+           t = y / h;
+           x = w * sqrt(1 - (t * t));
+           t = K - y;
+           if (rs - (t * t) >= 0)
+              *xp++ = x - sqrt(rs - (t * t));
+           else
+              *xp++ = x;
+       }
+       y = (b - d) / 2;
+       if (y >= 0.0 && flip == 1)
+       {
+           if (y > hepm)
+               y = h;
+           t = y / h;
+           x = w * sqrt(1 - (t * t));
+           t = K - y;
+           if (rs - (t * t) >= 0)
+              t = sqrt(rs - (t * t));
+           else
+              t = 0;
+           *xp++ = x - t;
+       }
+    }
+    if (xp > &xs[1]) {
+       if (acc->left.valid && boundedLe(K, bounds->left) &&
+           !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0)
+           return xs[1];
+       if (acc->right.valid && boundedLe(K, bounds->right) &&
+           !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0)
+           return xs[1];
+    }
+    return xs[0];
+}
+
+static miArcSpanData *
+miComputeWideEllipse(int lw, miArc *parc, gboolean *mustFree)
+{
+    register miArcSpanData *spdata;
+    register arcCacheRec *cent, *lruent;
+    register int k;
+    arcCacheRec fakeent;
+
+    if (!lw)
+       lw = 1;
+    if (parc->height <= 1500)
+    {
+       *mustFree = FALSE;
+       cent = lastCacheHit;
+       if (cent->lw == lw &&
+           cent->width == parc->width && cent->height == parc->height)
+       {
+           cent->lrustamp = ++lrustamp;
+           return cent->spdata;
+       }
+       lruent = &arcCache[0];
+       for (k = CACHESIZE, cent = lruent; --k >= 0; cent++)
+       {
+           if (cent->lw == lw &&
+               cent->width == parc->width && cent->height == parc->height)
+           {
+               cent->lrustamp = ++lrustamp;
+               lastCacheHit = cent;
+               return cent->spdata;
+           }
+           if (cent->lrustamp < lruent->lrustamp)
+               lruent = cent;
+       }
+#if 0
+       if (!cacheType)
+       {
+           cacheType = CreateNewResourceType(miFreeArcCache);
+           (void) AddResource(FakeClientID(0), cacheType, NULL);
+       }
+#endif 
+    } else {
+       lruent = &fakeent;
+       lruent->spdata = NULL;
+       *mustFree = TRUE;
+    }
+    k = (parc->height >> 1) + ((lw - 1) >> 1);
+    spdata = lruent->spdata;
+    if (!spdata || spdata->k != k)
+    {
+       if (spdata)
+           g_free(spdata);
+       spdata = (miArcSpanData *)g_malloc(sizeof(miArcSpanData) +
+                                        sizeof(miArcSpan) * (k + 2));
+       lruent->spdata = spdata;
+       if (!spdata)
+       {
+           lruent->lrustamp = 0;
+           lruent->lw = 0;
+           return spdata;
+       }
+       spdata->spans = (miArcSpan *)(spdata + 1);
+       spdata->k = k;
+    }
+    spdata->top = !(lw & 1) && !(parc->width & 1);
+    spdata->bot = !(parc->height & 1);
+    lruent->lrustamp = ++lrustamp;
+    lruent->lw = lw;
+    lruent->width = parc->width;
+    lruent->height = parc->height;
+    if (lruent != &fakeent)
+       lastCacheHit = lruent;
+    if (parc->width == parc->height)
+       miComputeCircleSpans(lw, parc, spdata);
+    else
+       miComputeEllipseSpans(lw, parc, spdata);
+    return spdata;
+}
+
+static void
+miFillWideEllipse(GdkDrawable *pDraw, GdkGC *pGC, miArc *parc)
+{
+    GdkRectangle* points;
+    register GdkRectangle* pts;
+    miArcSpanData *spdata;
+    gboolean mustFree;
+    register miArcSpan *span;
+    register int xorg, yorgu, yorgl;
+    register int n;
+
+    yorgu = parc->height + GDK_GC_FBDATA(pGC)->values.line_width;
+    points = ALLOCATE_LOCAL(sizeof(GdkRectangle) * yorgu * 2);
+    spdata = miComputeWideEllipse(GDK_GC_FBDATA(pGC)->values.line_width, parc, &mustFree);
+    if (!spdata)
+    {
+       DEALLOCATE_LOCAL(points);
+       return;
+    }
+    pts = points;
+    span = spdata->spans;
+    xorg = parc->x + (parc->width >> 1);
+    yorgu = parc->y + (parc->height >> 1);
+    yorgl = yorgu + (parc->height & 1);
+    yorgu -= spdata->k;
+    yorgl += spdata->k;
+    if (spdata->top)
+    {
+       pts->x = xorg;
+       pts->y = yorgu - 1;
+       pts->width = pts->height = 1;
+       pts++;
+       span++;
+    }
+    for (n = spdata->count1; --n >= 0; )
+    {
+       pts[0].x = xorg + span->lx;
+       pts[0].y = yorgu;
+       pts[0].height = 1;
+       pts[0].width = span->lw;
+       pts[1] = pts[0];
+       pts[1].y = yorgl;
+       yorgu++;
+       yorgl--;
+       pts += 2;
+       span++;
+    }
+    if (spdata->hole)
+    {
+       pts[0].x = xorg;
+       pts[0].y = yorgl;
+       pts[0].width = pts[0].height = 1;
+       pts++;
+    }
+    for (n = spdata->count2; --n >= 0; )
+    {
+       pts[0].x = xorg + span->lx;
+       pts[0].y = yorgu;
+       pts[0].width = span->lw;
+       pts[0].height = 1;
+
+       pts[1].x = xorg + span->rx;
+       pts[1].y = pts[0].y;
+       pts[1].width = span->rw;
+       pts[1].height = 1;
+
+       pts[2].x = pts[0].x;
+       pts[2].y = yorgl;
+       pts[2].height = 1;
+       pts[2].width = pts[0].width;
+
+       pts[3].x = pts[1].x;
+       pts[3].y = pts[2].y;
+       pts[3].width = pts[1].width;
+       pts[3].height = 1;
+
+       yorgu++;
+       yorgl--;
+       pts += 4;
+       span++;
+    }
+    if (spdata->bot)
+    {
+       if (span->rw <= 0)
+       {
+           pts[0].x = xorg + span->lx;
+           pts[0].y = yorgu;
+           pts[0].width = span->lw;
+           pts[0].height = 1;
+           pts++;
+       }
+       else
+       {
+           pts[0].x = xorg + span->lx;
+           pts[0].y = yorgu;
+           pts[0].width = span->lw;
+           pts[0].height = 1;
+           pts[1].x = xorg + span->rx;
+           pts[1].y = pts[0].y;
+           pts[1].width = span->rw;
+           pts[1].height = 1;
+           pts += 2;
+       }
+    }
+    if (mustFree)
+       g_free(spdata);
+
+    gdk_fb_fill_spans(pDraw, pGC, points, pts - points);
+
+    DEALLOCATE_LOCAL(points);
+}
+
+/*
+ * miPolyArc strategy:
+ *
+ * If arc is zero width and solid, we don't have to worry about the rasterop
+ * or join styles.  For wide solid circles, we use a fast integer algorithm.
+ * For wide solid ellipses, we use special case floating point code.
+ * Otherwise, we set up pDrawTo and pGCTo according to the rasterop, then
+ * draw using pGCTo and pDrawTo.  If the raster-op was "tricky," that is,
+ * if it involves the destination, then we use PushPixels to move the bits
+ * from the scratch drawable to pDraw. (See the wide line code for a
+ * fuller explanation of this.)
+ */
+
+void
+miPolyArc(GdkDrawable *pDraw, GdkGC *pGC, int narcs, miArc *parcs)
+{
+    register int               i;
+    miArc                      *parc;
+    int                                xMin, xMax, yMin, yMax;
+    int                                pixmapWidth, pixmapHeight;
+    int                                xOrg, yOrg;
+    int                                width;
+    gboolean                   fTricky;
+    GdkDrawable*               pDrawTo;
+    GdkColor                   fg, bg;
+    GdkGC*                     pGCTo;
+    miPolyArcPtr               polyArcs;
+    int                                cap[2], join[2];
+    int                                iphase;
+    int                                halfWidth;
+    GdkGCValues gcv;
+
+    width = GDK_GC_FBDATA(pGC)->values.line_width;
+    if(width == 0 && GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_SOLID)
+    {
+       for(i = narcs, parc = parcs; --i >= 0; parc++)
+           miArcSegment( pDraw, pGC, *parc,
+           (miArcFacePtr) 0, (miArcFacePtr) 0 );
+       fillSpans (pDraw, pGC);
+    }
+    else 
+    {
+       if ((GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_SOLID) && narcs)
+       {
+           while (parcs->width && parcs->height &&
+                  (parcs->angle2 >= FULLCIRCLE ||
+                   parcs->angle2 <= -FULLCIRCLE))
+           {
+               miFillWideEllipse(pDraw, pGC, parcs);
+               if (!--narcs)
+                   return;
+               parcs++;
+           }
+       }
+
+       /* Set up pDrawTo and pGCTo based on the rasterop */
+       switch(GDK_GC_FBDATA(pGC)->alu)
+       {
+         case GDK_CLEAR:               /* 0 */
+         case GDK_COPY:                /* src */
+         case GDK_COPY_INVERT: /* NOT src */
+         case GDK_SET:         /* 1 */
+           fTricky = FALSE;
+           pDrawTo = pDraw;
+           pGCTo = pGC;
+           break;
+         default:
+           fTricky = TRUE;
+
+           /* find bounding box around arcs */
+           xMin = yMin = SHRT_MAX;
+           xMax = yMax = SHRT_MIN;
+
+           for(i = narcs, parc = parcs; --i >= 0; parc++)
+           {
+               xMin = MIN (xMin, parc->x);
+               yMin = MIN (yMin, parc->y);
+               xMax = MAX (xMax, (parc->x + (int) parc->width));
+               yMax = MAX (yMax, (parc->y + (int) parc->height));
+           }
+
+           /* expand box to deal with line widths */
+           halfWidth = (width + 1)/2;
+           xMin -= halfWidth;
+           yMin -= halfWidth;
+           xMax += halfWidth;
+           yMax += halfWidth;
+
+           /* compute pixmap size; limit it to size of drawable */
+           xOrg = MAX(xMin, 0);
+           yOrg = MAX(yMin, 0);
+           pixmapWidth = MIN(xMax, GDK_DRAWABLE_P(pDraw)->width) - xOrg;
+           pixmapHeight = MIN(yMax, GDK_DRAWABLE_P(pDraw)->height) - yOrg;
+
+           /* if nothing left, return */
+           if ( (pixmapWidth <= 0) || (pixmapHeight <= 0) ) return;
+
+           for(i = narcs, parc = parcs; --i >= 0; parc++)
+           {
+               parc->x -= xOrg;
+               parc->y -= yOrg;
+           }
+
+           /* set up scratch GC */
+           /* allocate a 1 bit deep pixmap of the appropriate size, and
+            * validate it */
+           pDrawTo = gdk_pixmap_new(NULL, pixmapWidth, pixmapHeight, 1);
+           if (!pDrawTo)
+             return;
+
+           pGCTo = gdk_gc_new(pDrawTo);
+           if (!pGCTo)
+             {
+               gdk_pixmap_unref(pDrawTo);
+               return;
+             }
+           gdk_gc_set_function(pGCTo, GDK_COPY);
+           memset(&gcv.background, 0, sizeof(GdkColor));
+           gcv.foreground.pixel = 1;
+           gcv.foreground.red = gcv.foreground.green = gcv.foreground.blue = 1;
+           gdk_gc_set_foreground(pGCTo, &gcv.foreground);
+           gdk_gc_set_background(pGCTo, &gcv.background);
+           gdk_gc_set_line_attributes(pGCTo,
+                                      GDK_GC_FBDATA(pGC)->values.line_width,
+                                      GDK_GC_FBDATA(pGC)->values.line_style,
+                                      GDK_GC_FBDATA(pGC)->values.cap_style,
+                                      GDK_GC_FBDATA(pGC)->values.join_style);
+           gdk_fb_drawable_clear(pDrawTo);
+       }
+
+       fg = GDK_GC_FBDATA(pGC)->values.foreground;
+       bg = GDK_GC_FBDATA(pGC)->values.background;
+       if ((GDK_GC_FBDATA(pGC)->values.fill == GDK_TILED) ||
+           (GDK_GC_FBDATA(pGC)->values.fill == GDK_OPAQUE_STIPPLED))
+           bg = fg; /* the protocol sez these don't cause color changes */
+
+       polyArcs = miComputeArcs (parcs, narcs, pGC);
+
+       if (!polyArcs)
+       {
+           if (fTricky) {
+             gdk_pixmap_unref(pDrawTo);
+             gdk_gc_unref(pGCTo);
+           }
+           return;
+       }
+
+       cap[0] = cap[1] = 0;
+       join[0] = join[1] = 0;
+       for (iphase = ((GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH) ? 1 : 0);
+            iphase >= 0;
+            iphase--)
+       {
+           if (iphase == 1)
+             gdk_gc_set_foreground(pGC, &bg);
+           else if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH)
+             gdk_gc_set_foreground(pGC, &fg);
+           for (i = 0; i < polyArcs[iphase].narcs; i++) {
+               miArcDataPtr    arcData;
+
+               arcData = &polyArcs[iphase].arcs[i];
+               miArcSegment(pDrawTo, pGCTo, arcData->arc,
+                            &arcData->bounds[RIGHT_END],
+                            &arcData->bounds[LEFT_END]);
+               if (polyArcs[iphase].arcs[i].render) {
+                   fillSpans (pDrawTo, pGCTo);
+                   /*
+                    * don't cap self-joining arcs
+                    */
+                   if (polyArcs[iphase].arcs[i].selfJoin &&
+                       cap[iphase] < polyArcs[iphase].arcs[i].cap)
+                       cap[iphase]++;
+                   while (cap[iphase] < polyArcs[iphase].arcs[i].cap) {
+                       int     arcIndex, end;
+                       miArcDataPtr    arcData0;
+
+                       arcIndex = polyArcs[iphase].caps[cap[iphase]].arcIndex;
+                       end = polyArcs[iphase].caps[cap[iphase]].end;
+                       arcData0 = &polyArcs[iphase].arcs[arcIndex];
+                       miArcCap (pDrawTo, pGCTo,
+                                 &arcData0->bounds[end], end,
+                                 arcData0->arc.x, arcData0->arc.y,
+                                 (double) arcData0->arc.width / 2.0,
+                                 (double) arcData0->arc.height / 2.0);
+                       ++cap[iphase];
+                   }
+                   while (join[iphase] < polyArcs[iphase].arcs[i].join) {
+                       int     arcIndex0, arcIndex1, end0, end1;
+                       int     phase0, phase1;
+                       miArcDataPtr    arcData0, arcData1;
+                       miArcJoinPtr    joinp;
+
+                       joinp = &polyArcs[iphase].joins[join[iphase]];
+                       arcIndex0 = joinp->arcIndex0;
+                       end0 = joinp->end0;
+                       arcIndex1 = joinp->arcIndex1;
+                       end1 = joinp->end1;
+                       phase0 = joinp->phase0;
+                       phase1 = joinp->phase1;
+                       arcData0 = &polyArcs[phase0].arcs[arcIndex0];
+                       arcData1 = &polyArcs[phase1].arcs[arcIndex1];
+                       miArcJoin (pDrawTo, pGCTo,
+                                 &arcData0->bounds[end0],
+                                 &arcData1->bounds[end1],
+                                 arcData0->arc.x, arcData0->arc.y,
+                                 (double) arcData0->arc.width / 2.0,
+                                 (double) arcData0->arc.height / 2.0,
+                                 arcData1->arc.x, arcData1->arc.y,
+                                 (double) arcData1->arc.width / 2.0,
+                                 (double) arcData1->arc.height / 2.0);
+                       ++join[iphase];
+                   }
+                   if (fTricky) {
+                     gdk_fb_draw_drawable(pDraw, pGC, pDrawTo, 0, 0, xOrg, yOrg, pixmapWidth, pixmapHeight);
+                     gdk_fb_drawable_clear(pDrawTo);
+                   }
+               }
+           }
+       }
+       miFreeArcs(polyArcs, pGC);
+
+       if(fTricky)
+       {
+         gdk_pixmap_unref(pDrawTo);
+         gdk_gc_unref(pGCTo);
+       }
+    }
+}
+
+static double
+angleBetween (center, point1, point2)
+       SppPointRec     center, point1, point2;
+{
+       double  a1, a2, a;
+       
+       /*
+        * reflect from X coordinates back to ellipse
+        * coordinates -- y increasing upwards
+        */
+       a1 = miDatan2 (- (point1.y - center.y), point1.x - center.x);
+       a2 = miDatan2 (- (point2.y - center.y), point2.x - center.x);
+       a = a2 - a1;
+       if (a <= -180.0)
+               a += 360.0;
+       else if (a > 180.0)
+               a -= 360.0;
+       return a;
+}
+
+static void
+translateBounds (b, x, y, fx, fy)
+miArcFacePtr   b;
+int            x, y;
+double         fx, fy;
+{
+       fx += x;
+       fy += y;
+       b->clock.x -= fx;
+       b->clock.y -= fy;
+       b->center.x -= fx;
+       b->center.y -= fy;
+       b->counterClock.x -= fx;
+       b->counterClock.y -= fy;
+}
+
+static void
+miArcJoin (GdkDrawable *pDraw, GdkGC *pGC, miArcFacePtr pLeft, miArcFacePtr pRight,
+          int xOrgLeft, int yOrgLeft, double xFtransLeft, double yFtransLeft,
+          int xOrgRight, int yOrgRight, double xFtransRight, double yFtransRight)
+{
+       SppPointRec     center, corner, otherCorner;
+       SppPointRec     poly[5], e;
+       SppPointPtr     pArcPts;
+       int             cpt;
+       SppArcRec       arc;
+       miArcFaceRec    Right, Left;
+       int             polyLen;
+       int             xOrg, yOrg;
+       double          xFtrans, yFtrans;
+       double          a;
+       double          ae, ac2, ec2, bc2, de;
+       double          width;
+       
+       xOrg = (xOrgRight + xOrgLeft) / 2;
+       yOrg = (yOrgRight + yOrgLeft) / 2;
+       xFtrans = (xFtransLeft + xFtransRight) / 2;
+       yFtrans = (yFtransLeft + yFtransRight) / 2;
+       Right = *pRight;
+       translateBounds (&Right, xOrg - xOrgRight, yOrg - yOrgRight,
+                                xFtrans - xFtransRight, yFtrans - yFtransRight);
+       Left = *pLeft;
+       translateBounds (&Left, xOrg - xOrgLeft, yOrg - yOrgLeft,
+                                xFtrans - xFtransLeft, yFtrans - yFtransLeft);
+       pRight = &Right;
+       pLeft = &Left;
+
+       if (pRight->clock.x == pLeft->counterClock.x &&
+           pRight->clock.y == pLeft->counterClock.y)
+               return;
+       center = pRight->center;
+       if (0 <= (a = angleBetween (center, pRight->clock, pLeft->counterClock))
+           && a <= 180.0)
+       {
+               corner = pRight->clock;
+               otherCorner = pLeft->counterClock;
+       } else {
+               a = angleBetween (center, pLeft->clock, pRight->counterClock);
+               corner = pLeft->clock;
+               otherCorner = pRight->counterClock;
+       }
+       switch (GDK_GC_FBDATA(pGC)->values.join_style) {
+       case GDK_JOIN_ROUND:
+               width = (GDK_GC_FBDATA(pGC)->values.line_width ? (double)GDK_GC_FBDATA(pGC)->values.line_width : (double)1);
+
+               arc.x = center.x - width/2;
+               arc.y = center.y - width/2;
+               arc.width = width;
+               arc.height = width;
+               arc.angle1 = -miDatan2 (corner.y - center.y, corner.x - center.x);
+               arc.angle2 = a;
+               pArcPts = (SppPointPtr) g_malloc (3 * sizeof (SppPointRec));
+               if (!pArcPts)
+                   return;
+               pArcPts[0].x = otherCorner.x;
+               pArcPts[0].y = otherCorner.y;
+               pArcPts[1].x = center.x;
+               pArcPts[1].y = center.y;
+               pArcPts[2].x = corner.x;
+               pArcPts[2].y = corner.y;
+               if( (cpt = miGetArcPts(&arc, 3, &pArcPts)) )
+               {
+                       /* by drawing with miFillSppPoly and setting the endpoints of the arc
+                        * to be the corners, we assure that the cap will meet up with the
+                        * rest of the line */
+                       miFillSppPoly(pDraw, pGC, cpt, pArcPts, xOrg, yOrg, xFtrans, yFtrans);
+               }
+               g_free(pArcPts);
+               return;
+       case GDK_JOIN_MITER:
+               /*
+                * don't miter arcs with less than 11 degrees between them
+                */
+               if (a < 169.0) {
+                       poly[0] = corner;
+                       poly[1] = center;
+                       poly[2] = otherCorner;
+                       bc2 = (corner.x - otherCorner.x) * (corner.x - otherCorner.x) +
+                             (corner.y - otherCorner.y) * (corner.y - otherCorner.y);
+                       ec2 = bc2 / 4;
+                       ac2 = (corner.x - center.x) * (corner.x - center.x) +
+                             (corner.y - center.y) * (corner.y - center.y);
+                       ae = sqrt (ac2 - ec2);
+                       de = ec2 / ae;
+                       e.x = (corner.x + otherCorner.x) / 2;
+                       e.y = (corner.y + otherCorner.y) / 2;
+                       poly[3].x = e.x + de * (e.x - center.x) / ae;
+                       poly[3].y = e.y + de * (e.y - center.y) / ae;
+                       poly[4] = corner;
+                       polyLen = 5;
+                       break;
+               }
+       case GDK_JOIN_BEVEL:
+               poly[0] = corner;
+               poly[1] = center;
+               poly[2] = otherCorner;
+               poly[3] = corner;
+               polyLen = 4;
+               break;
+       }
+       miFillSppPoly (pDraw, pGC, polyLen, poly, xOrg, yOrg, xFtrans, yFtrans);
+}
+
+/*ARGSUSED*/
+static void
+miArcCap (pDraw, pGC, pFace, end, xOrg, yOrg, xFtrans, yFtrans)
+       GdkDrawable*    pDraw;
+       GdkGC*          pGC;
+       miArcFacePtr    pFace;
+       int             end;
+       int             xOrg, yOrg;
+       double          xFtrans, yFtrans;
+{
+       SppPointRec     corner, otherCorner, center, endPoint, poly[5];
+
+       corner = pFace->clock;
+       otherCorner = pFace->counterClock;
+       center = pFace->center;
+       switch (GDK_GC_FBDATA(pGC)->values.cap_style) {
+       case GDK_CAP_PROJECTING:
+               poly[0].x = otherCorner.x;
+               poly[0].y = otherCorner.y;
+               poly[1].x = corner.x;
+               poly[1].y = corner.y;
+               poly[2].x = corner.x -
+                               (center.y - corner.y);
+               poly[2].y = corner.y +
+                               (center.x - corner.x);
+               poly[3].x = otherCorner.x -
+                               (otherCorner.y - center.y);
+               poly[3].y = otherCorner.y +
+                               (otherCorner.x - center.x);
+               poly[4].x = otherCorner.x;
+               poly[4].y = otherCorner.y;
+               miFillSppPoly (pDraw, pGC, 5, poly, xOrg, yOrg, xFtrans, yFtrans);
+               break;
+       case GDK_CAP_ROUND:
+               /*
+                * miRoundCap just needs these to be unequal.
+                */
+               endPoint = center;
+               endPoint.x = endPoint.x + 100;
+               miRoundCap (pDraw, pGC, center, endPoint, corner, otherCorner, 0,
+                           -xOrg, -yOrg, xFtrans, yFtrans);
+               break;
+       default:
+         break;
+       }
+}
+
+/* MIROUNDCAP -- a private helper function
+ * Put Rounded cap on end. pCenter is the center of this end of the line
+ * pEnd is the center of the other end of the line. pCorner is one of the
+ * two corners at this end of the line.  
+ * NOTE:  pOtherCorner must be counter-clockwise from pCorner.
+ */
+/*ARGSUSED*/
+static void miRoundCap(GdkDrawable *pDraw, GdkGC *pGC, SppPointRec pCenter, SppPointRec pEnd, SppPointRec pCorner,
+                      SppPointRec pOtherCorner, int fLineEnd, int xOrg, int yOrg,
+                      double xFtrans, double yFtrans)
+{
+    int                cpt;
+    double     width;
+    double     miDatan2 ();
+    SppArcRec  arc;
+    SppPointPtr        pArcPts;
+
+    width = (GDK_GC_FBDATA(pGC)->values.line_width ? (double)GDK_GC_FBDATA(pGC)->values.line_width : (double)1);
+
+    arc.x = pCenter.x - width/2;
+    arc.y = pCenter.y - width/2;
+    arc.width = width;
+    arc.height = width;
+    arc.angle1 = -miDatan2 (pCorner.y - pCenter.y, pCorner.x - pCenter.x);
+    if(PTISEQUAL(pCenter, pEnd))
+       arc.angle2 = - 180.0;
+    else {
+       arc.angle2 = -miDatan2 (pOtherCorner.y - pCenter.y, pOtherCorner.x - pCenter.x) - arc.angle1;
+       if (arc.angle2 < 0)
+           arc.angle2 += 360.0;
+    }
+    pArcPts = (SppPointPtr) NULL;
+    if( (cpt = miGetArcPts(&arc, 0, &pArcPts)) )
+    {
+       /* by drawing with miFillSppPoly and setting the endpoints of the arc
+        * to be the corners, we assure that the cap will meet up with the
+        * rest of the line */
+       miFillSppPoly(pDraw, pGC, cpt, pArcPts, -xOrg, -yOrg, xFtrans, yFtrans);
+    }
+    g_free(pArcPts);
+}
+
+/*
+ * To avoid inaccuracy at the cardinal points, use trig functions
+ * which are exact for those angles
+ */
+
+#ifndef M_PI
+#define M_PI   3.14159265358979323846
+#endif
+#ifndef M_PI_2
+#define M_PI_2 1.57079632679489661923
+#endif
+
+# define Dsin(d)       ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
+# define Dcos(d)       ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
+# define mod(a,b)      ((a) >= 0 ? (a) % (b) : (b) - (-a) % (b))
+
+static double
+miDcos (a)
+double a;
+{
+       int     i;
+
+       if (floor (a/90) == a/90) {
+               i = (int) (a/90.0);
+               switch (mod (i, 4)) {
+               case 0: return 1;
+               case 1: return 0;
+               case 2: return -1;
+               case 3: return 0;
+               }
+       }
+       return cos (a * M_PI / 180.0);
+}
+
+static double
+miDsin (a)
+double a;
+{
+       int     i;
+
+       if (floor (a/90) == a/90) {
+               i = (int) (a/90.0);
+               switch (mod (i, 4)) {
+               case 0: return 0;
+               case 1: return 1;
+               case 2: return 0;
+               case 3: return -1;
+               }
+       }
+       return sin (a * M_PI / 180.0);
+}
+
+static double
+miDasin (v)
+double v;
+{
+    if (v == 0)
+       return 0.0;
+    if (v == 1.0)
+       return 90.0;
+    if (v == -1.0)
+       return -90.0;
+    return asin(v) * (180.0 / M_PI);
+}
+
+static double
+miDatan2 (dy, dx)
+double dy, dx;
+{
+    if (dy == 0) {
+       if (dx >= 0)
+           return 0.0;
+       return 180.0;
+    } else if (dx == 0) {
+       if (dy > 0)
+           return 90.0;
+       return -90.0;
+    } else if (fabs (dy) == fabs (dx)) {
+       if (dy > 0) {
+           if (dx > 0)
+               return 45.0;
+           return 135.0;
+       } else {
+           if (dx > 0)
+               return 315.0;
+           return 225.0;
+       }
+    } else {
+       return atan2 (dy, dx) * (180.0 / M_PI);
+    }
+}
+
+/* MIGETARCPTS -- Converts an arc into a set of line segments -- a helper
+ * routine for filled arc and line (round cap) code.
+ * Returns the number of points in the arc.  Note that it takes a pointer
+ * to a pointer to where it should put the points and an index (cpt).
+ * This procedure allocates the space necessary to fit the arc points.
+ * Sometimes it's convenient for those points to be at the end of an existing
+ * array. (For example, if we want to leave a spare point to make sectors
+ * instead of segments.)  So we pass in the g_malloc()ed chunk that contains the
+ * array and an index saying where we should start stashing the points.
+ * If there isn't an array already, we just pass in a null pointer and 
+ * count on g_realloc() to handle the null pointer correctly.
+ */
+static int
+miGetArcPts(SppArcPtr parc, int cpt, SppPointPtr *ppPts)
+#if 0
+    SppArcPtr  parc;   /* points to an arc */
+    int                cpt;    /* number of points already in arc list */
+    SppPointPtr        *ppPts; /* pointer to pointer to arc-list -- modified */
+#endif
+{
+    double     st,     /* Start Theta, start angle */
+                et,    /* End Theta, offset from start theta */
+               dt,     /* Delta Theta, angle to sweep ellipse */
+               cdt,    /* Cos Delta Theta, actually 2 cos(dt) */
+               x0, y0, /* the recurrence formula needs two points to start */
+               x1, y1,
+               x2, y2, /* this will be the new point generated */
+               xc, yc; /* the center point */
+    int                count, i;
+    SppPointPtr        poly;
+    GdkPoint last;             /* last point on integer boundaries */
+
+    /* The spec says that positive angles indicate counterclockwise motion.
+     * Given our coordinate system (with 0,0 in the upper left corner), 
+     * the screen appears flipped in Y.  The easiest fix is to negate the
+     * angles given */
+    
+    st = - parc->angle1;
+
+    et = - parc->angle2;
+
+    /* Try to get a delta theta that is within 1/2 pixel.  Then adjust it
+     * so that it divides evenly into the total.
+     * I'm just using cdt 'cause I'm lazy.
+     */
+    cdt = parc->width;
+    if (parc->height > cdt)
+       cdt = parc->height;
+    cdt /= 2.0;
+    if(cdt <= 0)
+       return 0;
+    if (cdt < 1.0)
+       cdt = 1.0;
+    dt = miDasin ( 1.0 / cdt ); /* minimum step necessary */
+    count = et/dt;
+    count = abs(count) + 1;
+    dt = et/count;     
+    count++;
+
+    cdt = 2 * miDcos(dt);
+    if (!(poly = (SppPointPtr) g_realloc((gpointer)*ppPts,
+                                       (cpt + count) * sizeof(SppPointRec))))
+       return(0);
+    *ppPts = poly;
+
+    xc = parc->width/2.0;              /* store half width and half height */
+    yc = parc->height/2.0;
+    
+    x0 = xc * miDcos(st);
+    y0 = yc * miDsin(st);
+    x1 = xc * miDcos(st + dt);
+    y1 = yc * miDsin(st + dt);
+    xc += parc->x;             /* by adding initial point, these become */
+    yc += parc->y;             /* the center point */
+
+    poly[cpt].x = (xc + x0);
+    poly[cpt].y = (yc + y0);
+    last.x = ROUNDTOINT( poly[cpt + 1].x = (xc + x1) );
+    last.y = ROUNDTOINT( poly[cpt + 1].y = (yc + y1) );
+
+    for(i = 2; i < count; i++)
+    {
+       x2 = cdt * x1 - x0;
+       y2 = cdt * y1 - y0;
+
+       poly[cpt + i].x = (xc + x2);
+       poly[cpt + i].y = (yc + y2);
+
+       x0 = x1; y0 = y1;
+       x1 = x2; y1 = y2;
+    }
+    /* adjust the last point */
+    if (abs(parc->angle2) >= 360.0)
+       poly[cpt +i -1] = poly[0];
+    else {
+       poly[cpt +i -1].x = (miDcos(st + et) * parc->width/2.0 + xc);
+       poly[cpt +i -1].y = (miDsin(st + et) * parc->height/2.0 + yc);
+    }
+
+    return(count);
+}
+
+struct arcData {
+       double  x0, y0, x1, y1;
+       int     selfJoin;
+};
+
+# define ADD_REALLOC_STEP      20
+
+static void
+addCap (capsp, ncapsp, sizep, end, arcIndex)
+       miArcCapPtr     *capsp;
+       int             *ncapsp, *sizep;
+       int             end, arcIndex;
+{
+       int newsize;
+       miArcCapPtr     cap;
+
+       if (*ncapsp == *sizep)
+       {
+           newsize = *sizep + ADD_REALLOC_STEP;
+           cap = (miArcCapPtr) g_realloc (*capsp,
+                                         newsize * sizeof (**capsp));
+           if (!cap)
+               return;
+           *sizep = newsize;
+           *capsp = cap;
+       }
+       cap = &(*capsp)[*ncapsp];
+       cap->end = end;
+       cap->arcIndex = arcIndex;
+       ++*ncapsp;
+}
+
+static void
+addJoin (joinsp, njoinsp, sizep, end0, index0, phase0, end1, index1, phase1)
+       miArcJoinPtr    *joinsp;
+       int             *njoinsp, *sizep;
+       int             end0, index0, phase0, end1, index1, phase1;
+{
+       int newsize;
+       miArcJoinPtr    join;
+
+       if (*njoinsp == *sizep)
+       {
+           newsize = *sizep + ADD_REALLOC_STEP;
+           join = (miArcJoinPtr) g_realloc (*joinsp,
+                                           newsize * sizeof (**joinsp));
+           if (!join)
+               return;
+           *sizep = newsize;
+           *joinsp = join;
+       }
+       join = &(*joinsp)[*njoinsp];
+       join->end0 = end0;
+       join->arcIndex0 = index0;
+       join->phase0 = phase0;
+       join->end1 = end1;
+       join->arcIndex1 = index1;
+       join->phase1 = phase1;
+       ++*njoinsp;
+}
+
+static miArcDataPtr
+addArc (arcsp, narcsp, sizep, xarc)
+       miArcDataPtr    *arcsp;
+       int             *narcsp, *sizep;
+       miArc           *xarc;
+{
+       int newsize;
+       miArcDataPtr    arc;
+
+       if (*narcsp == *sizep)
+       {
+           newsize = *sizep + ADD_REALLOC_STEP;
+           arc = (miArcDataPtr) g_realloc (*arcsp,
+                                          newsize * sizeof (**arcsp));
+           if (!arc)
+               return (miArcDataPtr)NULL;
+           *sizep = newsize;
+           *arcsp = arc;
+       }
+       arc = &(*arcsp)[*narcsp];
+       arc->arc = *xarc;
+       ++*narcsp;
+       return arc;
+}
+
+static void
+miFreeArcs(miPolyArcPtr arcs, GdkGC *pGC)
+{
+       int iphase;
+
+       for (iphase = ((GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH) ? 1 : 0);
+            iphase >= 0;
+            iphase--)
+       {
+           if (arcs[iphase].narcs > 0)
+               g_free(arcs[iphase].arcs);
+           if (arcs[iphase].njoins > 0)
+               g_free(arcs[iphase].joins);
+           if (arcs[iphase].ncaps > 0)
+               g_free(arcs[iphase].caps);
+       }
+       g_free(arcs);
+}
+
+/*
+ * map angles to radial distance.  This only deals with the first quadrant
+ */
+
+/*
+ * a polygonal approximation to the arc for computing arc lengths
+ */
+
+# define dashIndexToAngle(di)  ((((double) (di)) * 90.0) / ((double) DASH_MAP_SIZE - 1))
+# define xAngleToDashIndex(xa) ((((long) (xa)) * (DASH_MAP_SIZE - 1)) / (90 * 64))
+# define dashIndexToXAngle(di) ((((long) (di)) * (90 * 64)) / (DASH_MAP_SIZE - 1))
+# define dashXAngleStep        (((double) (90 * 64)) / ((double) (DASH_MAP_SIZE - 1)))
+
+static void
+computeDashMap (arcp, map)
+       miArc   *arcp;
+       dashMap *map;
+{
+       int     di;
+       double  a, x, y, prevx, prevy, dist;
+
+       for (di = 0; di < DASH_MAP_SIZE; di++) {
+               a = dashIndexToAngle (di);
+               x = ((double) arcp->width / 2.0) * miDcos (a);
+               y = ((double) arcp->height / 2.0) * miDsin (a);
+               if (di == 0) {
+                       map->map[di] = 0.0;
+               } else {
+                       dist = hypot (x - prevx, y - prevy);
+                       map->map[di] = map->map[di - 1] + dist;
+               }
+               prevx = x;
+               prevy = y;
+       }
+}
+
+typedef enum {HORIZONTAL, VERTICAL, OTHER} arcTypes;
+
+/* this routine is a bit gory */
+
+static miPolyArcPtr
+miComputeArcs (miArc *parcs, int narcs, GdkGC *pGC)
+{
+       int             isDashed, isDoubleDash;
+       int             dashOffset;
+       miPolyArcPtr    arcs;
+       int             start, i, j, k, nexti, nextk;
+       int             joinSize[2];
+       int             capSize[2];
+       int             arcSize[2];
+       int             angle2;
+       double          a0, a1;
+       struct arcData  *data;
+       miArcDataPtr    arc;
+       miArc           xarc;
+       int             iphase, prevphase, joinphase;
+       int             arcsJoin;
+       int             selfJoin;
+
+       int             iDash, dashRemaining;
+       int             iDashStart, dashRemainingStart, iphaseStart;
+       int             startAngle, spanAngle, endAngle, backwards;
+       int             prevDashAngle, dashAngle;
+       dashMap         map;
+
+       isDashed = !(GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_SOLID);
+       isDoubleDash = (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH);
+       dashOffset = GDK_GC_FBDATA(pGC)->dash_offset;
+
+       data = (struct arcData *) ALLOCATE_LOCAL (narcs * sizeof (struct arcData));
+       if (!data)
+           return (miPolyArcPtr)NULL;
+       arcs = (miPolyArcPtr) g_malloc (sizeof (*arcs) * (isDoubleDash ? 2 : 1));
+       if (!arcs)
+       {
+           DEALLOCATE_LOCAL(data);
+           return (miPolyArcPtr)NULL;
+       }
+       for (i = 0; i < narcs; i++) {
+               a0 = todeg (parcs[i].angle1);
+               angle2 = parcs[i].angle2;
+               if (angle2 > FULLCIRCLE)
+                       angle2 = FULLCIRCLE;
+               else if (angle2 < -FULLCIRCLE)
+                       angle2 = -FULLCIRCLE;
+               data[i].selfJoin = angle2 == FULLCIRCLE || angle2 == -FULLCIRCLE;
+               a1 = todeg (parcs[i].angle1 + angle2);
+               data[i].x0 = parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos (a0));
+               data[i].y0 = parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin (a0));
+               data[i].x1 = parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos (a1));
+               data[i].y1 = parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin (a1));
+       }
+
+       for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++) {
+               arcs[iphase].njoins = 0;
+               arcs[iphase].joins = 0;
+               joinSize[iphase] = 0;
+               
+               arcs[iphase].ncaps = 0;
+               arcs[iphase].caps = 0;
+               capSize[iphase] = 0;
+               
+               arcs[iphase].narcs = 0;
+               arcs[iphase].arcs = 0;
+               arcSize[iphase] = 0;
+       }
+
+       iphase = 0;
+       if (isDashed) {
+               iDash = 0;
+               dashRemaining = GDK_GC_FBDATA(pGC)->dash_list[0];
+               while (dashOffset > 0) {
+                       if (dashOffset >= dashRemaining) {
+                               dashOffset -= dashRemaining;
+                               iphase = iphase ? 0 : 1;
+                               iDash++;
+                               if (iDash == GDK_GC_FBDATA(pGC)->dash_list_len)
+                                   iDash = 0;
+                               dashRemaining = GDK_GC_FBDATA(pGC)->dash_list[iDash];
+                       } else {
+                               dashRemaining -= dashOffset;
+                               dashOffset = 0;
+                       }
+               }
+               iDashStart = iDash;
+               dashRemainingStart = dashRemaining;
+       }
+       iphaseStart = iphase;
+
+       for (i = narcs - 1; i >= 0; i--) {
+               j = i + 1;
+               if (j == narcs)
+                       j = 0;
+               if (data[i].selfJoin || i == j ||
+                    (UNEQUAL (data[i].x1, data[j].x0) ||
+                     UNEQUAL (data[i].y1, data[j].y0)))
+               {
+                       if (iphase == 0 || isDoubleDash)
+                               addCap (&arcs[iphase].caps, &arcs[iphase].ncaps,
+                                       &capSize[iphase], RIGHT_END, 0);
+                       break;
+               }
+       }
+       start = i + 1;
+       if (start == narcs)
+               start = 0;
+       i = start;
+       for (;;) {
+               j = i + 1;
+               if (j == narcs)
+                       j = 0;
+               nexti = i+1;
+               if (nexti == narcs)
+                       nexti = 0;
+               if (isDashed) {
+                       /*
+                       ** deal with dashed arcs.  Use special rules for certain 0 area arcs.
+                       ** Presumably, the other 0 area arcs still aren't done right.
+                       */
+                       arcTypes        arcType = OTHER;
+                       guint16         thisLength;
+
+                       if (parcs[i].height == 0
+                           && (parcs[i].angle1 % FULLCIRCLE) == 0x2d00
+                           && parcs[i].angle2 == 0x2d00) 
+                               arcType = HORIZONTAL;
+                       else if (parcs[i].width == 0
+                           && (parcs[i].angle1 % FULLCIRCLE) == 0x1680
+                           && parcs[i].angle2 == 0x2d00)
+                               arcType = VERTICAL;
+                       if (arcType == OTHER) {
+                               /*
+                                * precompute an approximation map
+                                */
+                               computeDashMap (&parcs[i], &map);
+                               /*
+                                * compute each individual dash segment using the path
+                                * length function
+                                */
+                               startAngle = parcs[i].angle1;
+                               spanAngle = parcs[i].angle2;
+                               if (spanAngle > FULLCIRCLE)
+                                       spanAngle = FULLCIRCLE;
+                               else if (spanAngle < -FULLCIRCLE)
+                                       spanAngle = -FULLCIRCLE;
+                               if (startAngle < 0)
+                                       startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
+                               if (startAngle >= FULLCIRCLE)
+                                       startAngle = startAngle % FULLCIRCLE;
+                               endAngle = startAngle + spanAngle;
+                               backwards = spanAngle < 0;
+                       } else {
+                               xarc = parcs[i];
+                               if (arcType == VERTICAL) {
+                                       xarc.angle1 = 0x1680;
+                                       startAngle = parcs[i].y;
+                                       endAngle = startAngle + parcs[i].height;
+                               } else {
+                                       xarc.angle1 = 0x2d00;
+                                       startAngle = parcs[i].x;
+                                       endAngle = startAngle + parcs[i].width;
+                               }
+                       }
+                       dashAngle = startAngle;
+                       selfJoin = data[i].selfJoin &&
+                                   (iphase == 0 || isDoubleDash);
+                       /*
+                        * add dashed arcs to each bucket
+                        */
+                       arc = 0;
+                       while (dashAngle != endAngle) {
+                               prevDashAngle = dashAngle;
+                               if (arcType == OTHER) {
+                                       dashAngle = computeAngleFromPath (prevDashAngle, endAngle,
+                                                               &map, &dashRemaining, backwards);
+                                       /* avoid troubles with huge arcs and small dashes */
+                                       if (dashAngle == prevDashAngle) {
+                                               if (backwards)
+                                                       dashAngle--;
+                                               else
+                                                       dashAngle++;
+                                       }
+                               } else {
+                                       thisLength = (dashAngle + dashRemaining <= endAngle) ? 
+                                           dashRemaining : endAngle - dashAngle;
+                                       if (arcType == VERTICAL) {
+                                               xarc.y = dashAngle;
+                                               xarc.height = thisLength;
+                                       } else {
+                                               xarc.x = dashAngle;
+                                               xarc.width = thisLength;
+                                       }
+                                       dashAngle += thisLength;
+                                       dashRemaining -= thisLength;
+                               }
+                               if (iphase == 0 || isDoubleDash) {
+                                       if (arcType == OTHER) {
+                                               xarc = parcs[i];
+                                               spanAngle = prevDashAngle;
+                                               if (spanAngle < 0)
+                                                   spanAngle = FULLCIRCLE - (-spanAngle) % FULLCIRCLE;
+                                               if (spanAngle >= FULLCIRCLE)
+                                                   spanAngle = spanAngle % FULLCIRCLE;
+                                               xarc.angle1 = spanAngle;
+                                               spanAngle = dashAngle - prevDashAngle;
+                                               if (backwards) {
+                                                       if (dashAngle > prevDashAngle)
+                                                               spanAngle = - FULLCIRCLE + spanAngle;
+                                               } else {
+                                                       if (dashAngle < prevDashAngle)
+                                                               spanAngle = FULLCIRCLE + spanAngle;
+                                               }
+                                               if (spanAngle > FULLCIRCLE)
+                                                   spanAngle = FULLCIRCLE;
+                                               if (spanAngle < -FULLCIRCLE)
+                                                   spanAngle = -FULLCIRCLE;
+                                               xarc.angle2 = spanAngle;
+                                       }
+                                       arc = addArc (&arcs[iphase].arcs, &arcs[iphase].narcs,
+                                                       &arcSize[iphase], &xarc);
+                                       if (!arc)
+                                           goto arcfail;
+                                       /*
+                                        * cap each end of an on/off dash
+                                        */
+                                       if (!isDoubleDash) {
+                                               if (prevDashAngle != startAngle) {
+                                                       addCap (&arcs[iphase].caps,
+                                                               &arcs[iphase].ncaps,
+                                                               &capSize[iphase], RIGHT_END,
+                                                               arc - arcs[iphase].arcs);
+                                                       
+                                               }
+                                               if (dashAngle != endAngle) {
+                                                       addCap (&arcs[iphase].caps,
+                                                               &arcs[iphase].ncaps,
+                                                               &capSize[iphase], LEFT_END,
+                                                               arc - arcs[iphase].arcs);
+                                               }
+                                       }
+                                       arc->cap = arcs[iphase].ncaps;
+                                       arc->join = arcs[iphase].njoins;
+                                       arc->render = 0;
+                                       arc->selfJoin = 0;
+                                       if (dashAngle == endAngle)
+                                               arc->selfJoin = selfJoin;
+                               }
+                               prevphase = iphase;
+                               if (dashRemaining <= 0) {
+                                       ++iDash;
+                                       if (iDash == GDK_GC_FBDATA(pGC)->dash_list_len)
+                                               iDash = 0;
+                                       iphase = iphase ? 0:1;
+                                       dashRemaining = GDK_GC_FBDATA(pGC)->dash_list[iDash];
+                               }
+                       }
+                       /*
+                        * make sure a place exists for the position data when
+                        * drawing a zero-length arc
+                        */
+                       if (startAngle == endAngle) {
+                               prevphase = iphase;
+                               if (!isDoubleDash && iphase == 1)
+                                       prevphase = 0;
+                               arc = addArc (&arcs[prevphase].arcs, &arcs[prevphase].narcs,
+                                             &arcSize[prevphase], &parcs[i]);
+                               if (!arc)
+                                   goto arcfail;
+                               arc->join = arcs[prevphase].njoins;
+                               arc->cap = arcs[prevphase].ncaps;
+                               arc->selfJoin = data[i].selfJoin;
+                       }
+               } else {
+                       arc = addArc (&arcs[iphase].arcs, &arcs[iphase].narcs,
+                                     &arcSize[iphase], &parcs[i]);
+                       if (!arc)
+                           goto arcfail;
+                       arc->join = arcs[iphase].njoins;
+                       arc->cap = arcs[iphase].ncaps;
+                       arc->selfJoin = data[i].selfJoin;
+                       prevphase = iphase;
+               }
+               if (prevphase == 0 || isDoubleDash)
+                       k = arcs[prevphase].narcs - 1;
+               if (iphase == 0 || isDoubleDash)
+                       nextk = arcs[iphase].narcs;
+               if (nexti == start) {
+                       nextk = 0;
+                       if (isDashed) {
+                               iDash = iDashStart;
+                               iphase = iphaseStart;
+                               dashRemaining = dashRemainingStart;
+                       }
+               }
+               arcsJoin = narcs > 1 && i != j &&
+                           ISEQUAL (data[i].x1, data[j].x0) &&
+                           ISEQUAL (data[i].y1, data[j].y0) &&
+                           !data[i].selfJoin && !data[j].selfJoin;
+               if (arc)
+               {
+                       if (arcsJoin)
+                               arc->render = 0;
+                       else
+                               arc->render = 1;
+               }
+               if (arcsJoin &&
+                   (prevphase == 0 || isDoubleDash) &&
+                   (iphase == 0 || isDoubleDash))
+               {
+                       joinphase = iphase;
+                       if (isDoubleDash) {
+                               if (nexti == start)
+                                       joinphase = iphaseStart;
+                               /*
+                                * if the join is right at the dash,
+                                * draw the join in foreground
+                                * This is because the foreground
+                                * arcs are computed second, the results
+                                * of which are needed to draw the join
+                                */
+                               if (joinphase != prevphase)
+                                       joinphase = 0;
+                       }
+                       if (joinphase == 0 || isDoubleDash) {
+                               addJoin (&arcs[joinphase].joins,
+                                        &arcs[joinphase].njoins,
+                                        &joinSize[joinphase],
+                                        LEFT_END, k, prevphase,
+                                        RIGHT_END, nextk, iphase);
+                               arc->join = arcs[prevphase].njoins;
+                       }
+               } else {
+                       /*
+                        * cap the left end of this arc
+                        * unless it joins itself
+                        */
+                       if ((prevphase == 0 || isDoubleDash) &&
+                           !arc->selfJoin)
+                       {
+                               addCap (&arcs[prevphase].caps, &arcs[prevphase].ncaps,
+                                       &capSize[prevphase], LEFT_END, k);
+                               arc->cap = arcs[prevphase].ncaps;
+                       }
+                       if (isDashed && !arcsJoin) {
+                               iDash = iDashStart;
+                               iphase = iphaseStart;
+                               dashRemaining = dashRemainingStart;
+                       }
+                       nextk = arcs[iphase].narcs;
+                       if (nexti == start) {
+                               nextk = 0;
+                               iDash = iDashStart;
+                               iphase = iphaseStart;
+                               dashRemaining = dashRemainingStart;
+                       }
+                       /*
+                        * cap the right end of the next arc.  If the
+                        * next arc is actually the first arc, only
+                        * cap it if it joins with this arc.  This
+                        * case will occur when the final dash segment
+                        * of an on/off dash is off.  Of course, this
+                        * cap will be drawn at a strange time, but that
+                        * hardly matters...
+                        */
+                       if ((iphase == 0 || isDoubleDash) &&
+                           (nexti != start || (arcsJoin && isDashed)))
+                               addCap (&arcs[iphase].caps, &arcs[iphase].ncaps,
+                                       &capSize[iphase], RIGHT_END, nextk);
+               }
+               i = nexti;
+               if (i == start)
+                       break;
+       }
+       /*
+        * make sure the last section is rendered
+        */
+       for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++)
+               if (arcs[iphase].narcs > 0) {
+                       arcs[iphase].arcs[arcs[iphase].narcs-1].render = 1;
+                       arcs[iphase].arcs[arcs[iphase].narcs-1].join =
+                                arcs[iphase].njoins;
+                       arcs[iphase].arcs[arcs[iphase].narcs-1].cap =
+                                arcs[iphase].ncaps;
+               }
+       DEALLOCATE_LOCAL(data);
+       return arcs;
+arcfail:
+       miFreeArcs(arcs, pGC);
+       DEALLOCATE_LOCAL(data);
+       return (miPolyArcPtr)NULL;
+}
+
+static double
+angleToLength (angle, map)
+       int     angle;
+       dashMap *map;
+{
+       double  len, excesslen, sidelen = map->map[DASH_MAP_SIZE - 1], totallen;
+       int     di;
+       int     excess;
+       gboolean        oddSide = FALSE;
+
+       totallen = 0;
+       if (angle >= 0) {
+               while (angle >= 90 * 64) {
+                       angle -= 90 * 64;
+                       totallen += sidelen;
+                       oddSide = !oddSide;
+               }
+       } else {
+               while (angle < 0) {
+                       angle += 90 * 64;
+                       totallen -= sidelen;
+                       oddSide = !oddSide;
+               }
+       }
+       if (oddSide)
+               angle = 90 * 64 - angle;
+               
+       di = xAngleToDashIndex (angle);
+       excess = angle - dashIndexToXAngle (di);
+
+       len = map->map[di];
+       /*
+        * linearly interpolate between this point and the next
+        */
+       if (excess > 0) {
+               excesslen = (map->map[di + 1] - map->map[di]) *
+                               ((double) excess) / dashXAngleStep;
+               len += excesslen;
+       }
+       if (oddSide)
+               totallen += (sidelen - len);
+       else
+               totallen += len;
+       return totallen;
+}
+
+/*
+ * len is along the arc, but may be more than one rotation
+ */
+
+static int
+lengthToAngle (len, map)
+       double  len;
+       dashMap *map;
+{
+       double  sidelen = map->map[DASH_MAP_SIZE - 1];
+       int     angle, angleexcess;
+       gboolean        oddSide = FALSE;
+       int     a0, a1, a;
+
+       angle = 0;
+       /*
+        * step around the ellipse, subtracting sidelens and
+        * adding 90 degrees.  oddSide will tell if the
+        * map should be interpolated in reverse
+        */
+       if (len >= 0) {
+               if (sidelen == 0)
+                       return 2 * FULLCIRCLE;  /* infinity */
+               while (len >= sidelen) {
+                       angle += 90 * 64;
+                       len -= sidelen;
+                       oddSide = !oddSide;
+               }
+       } else {
+               if (sidelen == 0)
+                       return -2 * FULLCIRCLE; /* infinity */
+               while (len < 0) {
+                       angle -= 90 * 64;
+                       len += sidelen;
+                       oddSide = !oddSide;
+               }
+       }
+       if (oddSide)
+               len = sidelen - len;
+       a0 = 0;
+       a1 = DASH_MAP_SIZE - 1;
+       /*
+        * binary search for the closest pre-computed length
+        */
+       while (a1 - a0 > 1) {
+               a = (a0 + a1) / 2;
+               if (len > map->map[a])
+                       a0 = a;
+               else
+                       a1 = a;
+       }
+       angleexcess = dashIndexToXAngle (a0);
+       /*
+        * linearly interpolate to the next point
+        */
+       angleexcess += (len - map->map[a0]) /
+                       (map->map[a0+1] - map->map[a0]) * dashXAngleStep;
+       if (oddSide)
+               angle += (90 * 64) - angleexcess;
+       else
+               angle += angleexcess;
+       return angle;
+}
+
+/*
+ * compute the angle of an ellipse which cooresponds to
+ * the given path length.  Note that the correct solution
+ * to this problem is an eliptic integral, we'll punt and
+ * approximate (it's only for dashes anyway).  This
+ * approximation uses a polygon.
+ *
+ * The remaining portion of len is stored in *lenp -
+ * this will be negative if the arc extends beyond
+ * len and positive if len extends beyond the arc.
+ */
+
+static int computeAngleFromPath(int startAngle, int endAngle, dashMap *map, int *lenp, int backwards)
+/*     int     startAngle, endAngle;   *//* normalized absolute angles in *64 degrees */
+{
+       int     a0, a1, a;
+       double  len0;
+       int     len;
+
+       a0 = startAngle;
+       a1 = endAngle;
+       len = *lenp;
+       if (backwards) {
+               /*
+                * flip the problem around to always be
+                * forwards
+                */
+               a0 = FULLCIRCLE - a0;
+               a1 = FULLCIRCLE - a1;
+       }
+       if (a1 < a0)
+               a1 += FULLCIRCLE;
+       len0 = angleToLength (a0, map);
+       a = lengthToAngle (len0 + len, map);
+       if (a > a1) {
+               a = a1;
+               len -= angleToLength (a1, map) - len0;
+       } else
+               len = 0;
+       if (backwards)
+               a = FULLCIRCLE - a;
+       *lenp = len;
+       return a;
+}
+
+/*
+ * scan convert wide arcs.
+ */
+
+/*
+ * draw zero width/height arcs
+ */
+
+static void
+drawZeroArc (pDraw, pGC, tarc, lw, left, right)
+    GdkDrawable*   pDraw;
+    GdkGC*         pGC;
+    miArc          *tarc;
+    int                  lw;
+    miArcFacePtr       right, left;
+{
+       double  x0, y0, x1, y1, w, h, x, y;
+       double  xmax, ymax, xmin, ymin;
+       int     a0, a1;
+       double  a, startAngle, endAngle;
+       double  l, lx, ly;
+
+       l = lw / 2.0;
+       a0 = tarc->angle1;
+       a1 = tarc->angle2;
+       if (a1 > FULLCIRCLE)
+               a1 = FULLCIRCLE;
+       else if (a1 < -FULLCIRCLE)
+               a1 = -FULLCIRCLE;
+       w = (double)tarc->width / 2.0;
+       h = (double)tarc->height / 2.0;
+       /*
+        * play in X coordinates right away
+        */
+       startAngle = - ((double) a0 / 64.0);
+       endAngle = - ((double) (a0 + a1) / 64.0);
+       
+       xmax = -w;
+       xmin = w;
+       ymax = -h;
+       ymin = h;
+       a = startAngle;
+       for (;;)
+       {
+               x = w * miDcos(a);
+               y = h * miDsin(a);
+               if (a == startAngle)
+               {
+                       x0 = x;
+                       y0 = y;
+               }
+               if (a == endAngle)
+               {
+                       x1 = x;
+                       y1 = y;
+               }
+               if (x > xmax)
+                       xmax = x;
+               if (x < xmin)
+                       xmin = x;
+               if (y > ymax)
+                       ymax = y;
+               if (y < ymin)
+                       ymin = y;
+               if (a == endAngle)
+                       break;
+               if (a1 < 0)     /* clockwise */
+               {
+                       if (floor (a / 90.0) == floor (endAngle / 90.0))
+                               a = endAngle;
+                       else
+                               a = 90 * (floor (a/90.0) + 1);
+               }
+               else
+               {
+                       if (ceil (a / 90.0) == ceil (endAngle / 90.0))
+                               a = endAngle;
+                       else
+                               a = 90 * (ceil (a/90.0) - 1);
+               }
+       }
+       lx = ly = l;
+       if ((x1 - x0) + (y1 - y0) < 0)
+           lx = ly = -l;
+       if (h)
+       {
+           ly = 0.0;
+           lx = -lx;
+       }
+       else
+           lx = 0.0;
+       if (right)
+       {
+           right->center.x = x0;
+           right->center.y = y0;
+           right->clock.x = x0 - lx;
+           right->clock.y = y0 - ly;
+           right->counterClock.x = x0 + lx;
+           right->counterClock.y = y0 + ly;
+       }
+       if (left)
+       {
+           left->center.x = x1;
+           left->center.y = y1;
+           left->clock.x = x1 + lx;
+           left->clock.y = y1 + ly;
+           left->counterClock.x = x1 - lx;
+           left->counterClock.y = y1 - ly;
+       }
+       
+       x0 = xmin;
+       x1 = xmax;
+       y0 = ymin;
+       y1 = ymax;
+       if (ymin != y1) {
+               xmin = -l;
+               xmax = l;
+       } else {
+               ymin = -l;
+               ymax = l;
+       }
+       if (xmax != xmin && ymax != ymin) {
+               int     minx, maxx, miny, maxy;
+
+               minx = ICEIL (xmin + w) + tarc->x;
+               maxx = ICEIL (xmax + w) + tarc->x;
+               miny = ICEIL (ymin + h) + tarc->y;
+               maxy = ICEIL (ymax + h) + tarc->y;
+
+               gdk_fb_draw_rectangle(pDraw, pGC, TRUE, minx, miny, maxx - minx, maxy - miny);
+       }
+}
+
+/*
+ * this computes the ellipse y value associated with the
+ * bottom of the tail.
+ */
+
+static void
+tailEllipseY (def, acc)
+       struct arc_def          *def;
+       struct accelerators     *acc;
+{
+       double          t;
+
+       acc->tail_y = 0.0;
+       if (def->w == def->h)
+           return;
+       t = def->l * def->w;
+       if (def->w > def->h) {
+           if (t < acc->h2)
+               return;
+       } else {
+           if (t > acc->h2)
+               return;
+       }
+       t = 2.0 * def->h * t;
+       t = (CUBED_ROOT_4 * acc->h2 - cbrt(t * t)) / acc->h2mw2;
+       if (t > 0.0)
+           acc->tail_y = def->h / CUBED_ROOT_2 * sqrt(t);
+}
+
+/*
+ * inverse functions -- compute edge coordinates
+ * from the ellipse
+ */
+
+static double
+outerXfromXY (x, y, def, acc)
+       double                  x, y;
+       struct arc_def          *def;
+       struct accelerators     *acc;
+{
+       return x + (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
+}
+
+static double
+outerYfromXY (x, y, def, acc)
+       double          x, y;
+       struct arc_def          *def;
+       struct accelerators     *acc;
+{
+       return y + (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
+}
+
+static double
+innerXfromXY (x, y, def, acc)
+       double                  x, y;
+       struct arc_def          *def;
+       struct accelerators     *acc;
+{
+       return x - (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
+}
+
+static double
+innerYfromXY (x, y, def, acc)
+       double                  x, y;
+       struct arc_def          *def;
+       struct accelerators     *acc;
+{
+       return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
+}
+
+static double
+innerYfromY (y, def, acc)
+       double  y;
+       struct arc_def          *def;
+       struct accelerators     *acc;
+{
+       double  x;
+
+       x = (def->w / def->h) * sqrt (acc->h2 - y*y);
+
+       return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
+}
+
+static void
+computeLine (x1, y1, x2, y2, line)
+       double          x1, y1, x2, y2;
+       struct line     *line;
+{
+       if (y1 == y2)
+               line->valid = 0;
+       else {
+               line->m = (x1 - x2) / (y1 - y2);
+               line->b = x1  - y1 * line->m;
+               line->valid = 1;
+       }
+}
+
+/*
+ * compute various accelerators for an ellipse.  These
+ * are simply values that are used repeatedly in
+ * the computations
+ */
+
+static void
+computeAcc (tarc, lw, def, acc)
+       miArc                   *tarc;
+       int                     lw;
+       struct arc_def          *def;
+       struct accelerators     *acc;
+{
+       def->w = ((double) tarc->width) / 2.0;
+       def->h = ((double) tarc->height) / 2.0;
+       def->l = ((double) lw) / 2.0;
+       acc->h2 = def->h * def->h;
+       acc->w2 = def->w * def->w;
+       acc->h4 = acc->h2 * acc->h2;
+       acc->w4 = acc->w2 * acc->w2;
+       acc->h2l = acc->h2 * def->l;
+       acc->w2l = acc->w2 * def->l;
+       acc->h2mw2 = acc->h2 - acc->w2;
+       acc->fromIntX = (tarc->width & 1) ? 0.5 : 0.0;
+       acc->fromIntY = (tarc->height & 1) ? 0.5 : 0.0;
+       acc->xorg = tarc->x + (tarc->width >> 1);
+       acc->yorgu = tarc->y + (tarc->height >> 1);
+       acc->yorgl = acc->yorgu + (tarc->height & 1);
+       tailEllipseY (def, acc);
+}
+               
+/*
+ * compute y value bounds of various portions of the arc,
+ * the outer edge, the ellipse and the inner edge.
+ */
+
+static void
+computeBound (def, bound, acc, right, left)
+       struct arc_def          *def;
+       struct arc_bound        *bound;
+       struct accelerators     *acc;
+       miArcFacePtr            right, left;
+{
+       double          t;
+       double          innerTaily;
+       double          tail_y;
+       struct bound    innerx, outerx;
+       struct bound    ellipsex;
+
+       bound->ellipse.min = Dsin (def->a0) * def->h;
+       bound->ellipse.max = Dsin (def->a1) * def->h;
+       if (def->a0 == 45 && def->w == def->h)
+               ellipsex.min = bound->ellipse.min;
+       else
+               ellipsex.min = Dcos (def->a0) * def->w;
+       if (def->a1 == 45 && def->w == def->h)
+               ellipsex.max = bound->ellipse.max;
+       else
+               ellipsex.max = Dcos (def->a1) * def->w;
+       bound->outer.min = outerYfromXY (ellipsex.min, bound->ellipse.min, def, acc);
+       bound->outer.max = outerYfromXY (ellipsex.max, bound->ellipse.max, def, acc);
+       bound->inner.min = innerYfromXY (ellipsex.min, bound->ellipse.min, def, acc);
+       bound->inner.max = innerYfromXY (ellipsex.max, bound->ellipse.max, def, acc);
+
+       outerx.min = outerXfromXY (ellipsex.min, bound->ellipse.min, def, acc);
+       outerx.max = outerXfromXY (ellipsex.max, bound->ellipse.max, def, acc);
+       innerx.min = innerXfromXY (ellipsex.min, bound->ellipse.min, def, acc);
+       innerx.max = innerXfromXY (ellipsex.max, bound->ellipse.max, def, acc);
+       
+       /*
+        * save the line end points for the
+        * cap code to use.  Careful here, these are
+        * in cartesean coordinates (y increasing upwards)
+        * while the cap code uses inverted coordinates
+        * (y increasing downwards)
+        */
+
+       if (right) {
+               right->counterClock.y = bound->outer.min;
+               right->counterClock.x = outerx.min;
+               right->center.y = bound->ellipse.min;
+               right->center.x = ellipsex.min;
+               right->clock.y = bound->inner.min;
+               right->clock.x = innerx.min;
+       }
+
+       if (left) {
+               left->clock.y = bound->outer.max;
+               left->clock.x = outerx.max;
+               left->center.y = bound->ellipse.max;
+               left->center.x = ellipsex.max;
+               left->counterClock.y = bound->inner.max;
+               left->counterClock.x = innerx.max;
+       }
+
+       bound->left.min = bound->inner.max;
+       bound->left.max = bound->outer.max;
+       bound->right.min = bound->inner.min;
+       bound->right.max = bound->outer.min;
+
+       computeLine (innerx.min, bound->inner.min, outerx.min, bound->outer.min,
+                     &acc->right);
+       computeLine (innerx.max, bound->inner.max, outerx.max, bound->outer.max,
+                    &acc->left);
+
+       if (bound->inner.min > bound->inner.max) {
+               t = bound->inner.min;
+               bound->inner.min = bound->inner.max;
+               bound->inner.max = t;
+       }
+       tail_y = acc->tail_y;
+       if (tail_y > bound->ellipse.max)
+               tail_y = bound->ellipse.max;
+       else if (tail_y < bound->ellipse.min)
+               tail_y = bound->ellipse.min;
+       innerTaily = innerYfromY (tail_y, def, acc);
+       if (bound->inner.min > innerTaily)
+               bound->inner.min = innerTaily;
+       if (bound->inner.max < innerTaily)
+               bound->inner.max = innerTaily;
+       bound->inneri.min = ICEIL(bound->inner.min - acc->fromIntY);
+       bound->inneri.max = floor(bound->inner.max - acc->fromIntY);
+       bound->outeri.min = ICEIL(bound->outer.min - acc->fromIntY);
+       bound->outeri.max = floor(bound->outer.max - acc->fromIntY);
+}
+
+/*
+ * this section computes the x value of the span at y 
+ * intersected with the specified face of the ellipse.
+ *
+ * this is the min/max X value over the set of normal
+ * lines to the entire ellipse,  the equation of the
+ * normal lines is:
+ *
+ *     ellipse_x h^2                   h^2
+ * x = ------------ y + ellipse_x (1 - --- )
+ *     ellipse_y w^2                   w^2
+ *
+ * compute the derivative with-respect-to ellipse_y and solve
+ * for zero:
+ *    
+ *       (w^2 - h^2) ellipse_y^3 + h^4 y
+ * 0 = - ----------------------------------
+ *       h w ellipse_y^2 sqrt (h^2 - ellipse_y^2)
+ *
+ *             (   h^4 y     )
+ * ellipse_y = ( ----------  ) ^ (1/3)
+ *             ( (h^2 - w^2) )
+ *
+ * The other two solutions to the equation are imaginary.
+ *
+ * This gives the position on the ellipse which generates
+ * the normal with the largest/smallest x intersection point.
+ *
+ * Now compute the second derivative to check whether
+ * the intersection is a minimum or maximum:
+ *
+ *    h (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2))
+ * -  -------------------------------------------
+ *          w y0^3 (sqrt (h^2 - y^2)) ^ 3
+ *
+ * as we only care about the sign,
+ *
+ * - (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2))
+ *
+ * or (to use accelerators),
+ *
+ * y0^3 (h^2 - w^2) - h^2 y (3y0^2 - 2h^2) 
+ *
+ */
+
+/*
+ * computes the position on the ellipse whose normal line
+ * intersects the given scan line maximally
+ */
+
+static double
+hookEllipseY (scan_y, bound, acc, left)
+       double                  scan_y;
+       struct arc_bound        *bound;
+       struct accelerators     *acc;
+       int                     left;
+{
+       double  ret;
+
+       if (acc->h2mw2 == 0) {
+               if ( (scan_y > 0 && !left) || (scan_y < 0 && left) )
+                       return bound->ellipse.min;
+               return bound->ellipse.max;
+       }
+       ret = (acc->h4 * scan_y) / (acc->h2mw2);
+       if (ret >= 0)
+               return cbrt (ret);
+       else
+               return -cbrt (-ret);
+}
+
+/*
+ * computes the X value of the intersection of the
+ * given scan line with the right side of the lower hook
+ */
+
+static double
+hookX (scan_y, def, bound, acc, left)
+       double                  scan_y;
+       struct arc_def          *def;
+       struct arc_bound        *bound;
+       struct accelerators     *acc;
+       int                     left;
+{
+       double  ellipse_y, x;
+       double  maxMin;
+
+       if (def->w != def->h) {
+               ellipse_y = hookEllipseY (scan_y, bound, acc, left);
+               if (boundedLe (ellipse_y, bound->ellipse)) {
+                       /*
+                        * compute the value of the second
+                        * derivative
+                        */
+                       maxMin = ellipse_y*ellipse_y*ellipse_y * acc->h2mw2 -
+                        acc->h2 * scan_y * (3 * ellipse_y*ellipse_y - 2*acc->h2);
+                       if ((left && maxMin > 0) || (!left && maxMin < 0)) {
+                               if (ellipse_y == 0)
+                                       return def->w + left ? -def->l : def->l;
+                               x = (acc->h2 * scan_y - ellipse_y * acc->h2mw2) *
+                                       sqrt (acc->h2 - ellipse_y * ellipse_y) /
+                                       (def->h * def->w * ellipse_y);
+                               return x;
+                       }
+               }
+       }
+       if (left) {
+               if (acc->left.valid && boundedLe (scan_y, bound->left)) {
+                       x = intersectLine (scan_y, acc->left);
+               } else {
+                       if (acc->right.valid)
+                               x = intersectLine (scan_y, acc->right);
+                       else
+                               x = def->w - def->l;
+               }
+       } else {
+               if (acc->right.valid && boundedLe (scan_y, bound->right)) {
+                       x = intersectLine (scan_y, acc->right);
+               } else {
+                       if (acc->left.valid)
+                               x = intersectLine (scan_y, acc->left);
+                       else
+                               x = def->w - def->l;
+               }
+       }
+       return x;
+}
+
+/*
+ * generate the set of spans with
+ * the given y coordinate
+ */
+
+static void
+arcSpan (y, lx, lw, rx, rw, def, bounds, acc, mask)
+       int                     y;
+       int                     lx;
+       int                     lw;
+       int                     rx;
+       int                     rw;
+       struct arc_def          *def;
+       struct arc_bound        *bounds;
+       struct accelerators     *acc;
+       int                     mask;
+{
+       int linx, loutx, rinx, routx;
+       double x, altx;
+
+       if (boundedLe (y, bounds->inneri)) {
+           linx = -(lx + lw);
+           rinx = rx;
+       } else {
+           /*
+            * intersection with left face
+            */
+           x = hookX (y + acc->fromIntY, def, bounds, acc, 1);
+           if (acc->right.valid &&
+               boundedLe (y + acc->fromIntY, bounds->right))
+           {
+               altx = intersectLine (y + acc->fromIntY, acc->right);
+               if (altx < x)
+                   x = altx;
+           }
+           linx = -ICEIL(acc->fromIntX - x);
+           rinx = ICEIL(acc->fromIntX + x);
+       }
+       if (boundedLe (y, bounds->outeri)) {
+           loutx = -lx;
+           routx = rx + rw;
+       } else {
+           /*
+            * intersection with right face
+            */
+           x = hookX (y + acc->fromIntY, def, bounds, acc, 0);
+           if (acc->left.valid &&
+               boundedLe (y + acc->fromIntY, bounds->left))
+           {
+               altx = x;
+               x = intersectLine (y + acc->fromIntY, acc->left);
+               if (x < altx)
+                   x = altx;
+           }
+           loutx = -ICEIL(acc->fromIntX - x);
+           routx = ICEIL(acc->fromIntX + x);
+       }
+       if (routx > rinx) {
+           if (mask & 1)
+               newFinalSpan (acc->yorgu - y,
+                             acc->xorg + rinx, acc->xorg + routx);
+           if (mask & 8)
+               newFinalSpan (acc->yorgl + y,
+                             acc->xorg + rinx, acc->xorg + routx);
+       }
+       if (loutx > linx) {
+           if (mask & 2)
+               newFinalSpan (acc->yorgu - y,
+                             acc->xorg - loutx, acc->xorg - linx);
+           if (mask & 4)
+               newFinalSpan (acc->yorgl + y,
+                             acc->xorg - loutx, acc->xorg - linx);
+       }
+}
+
+static void
+arcSpan0 (lx, lw, rx, rw, def, bounds, acc, mask)
+       int                     lx;
+       int                     lw;
+       int                     rx;
+       int                     rw;
+       struct arc_def          *def;
+       struct arc_bound        *bounds;
+       struct accelerators     *acc;
+       int                     mask;
+{
+    double x;
+
+    if (boundedLe (0, bounds->inneri) &&
+       acc->left.valid && boundedLe (0, bounds->left) &&
+       acc->left.b > 0)
+    {
+       x = def->w - def->l;
+       if (acc->left.b < x)
+           x = acc->left.b;
+       lw = ICEIL(acc->fromIntX - x) - lx;
+       rw += rx;
+       rx = ICEIL(acc->fromIntX + x);
+       rw -= rx;
+    }
+    arcSpan (0, lx, lw, rx, rw, def, bounds, acc, mask);
+}
+
+static void
+tailSpan (y, lw, rw, def, bounds, acc, mask)
+       int                     y;
+       int                     lw;
+       int                     rw;
+       struct arc_def          *def;
+       struct arc_bound        *bounds;
+       struct accelerators     *acc;
+       int                     mask;
+{
+    double yy, xalt, x, lx, rx;
+    int n;
+
+    if (boundedLe(y, bounds->outeri))
+       arcSpan (y, 0, lw, -rw, rw, def, bounds, acc, mask);
+    else if (def->w != def->h) {
+       yy = y + acc->fromIntY;
+       x = tailX(yy, def, bounds, acc);
+       if (yy == 0.0 && x == -rw - acc->fromIntX)
+           return;
+       if (acc->right.valid && boundedLe (yy, bounds->right)) {
+           rx = x;
+           lx = -x;
+           xalt = intersectLine (yy, acc->right);
+           if (xalt >= -rw - acc->fromIntX && xalt <= rx)
+               rx = xalt;
+           n = ICEIL(acc->fromIntX + lx);
+           if (lw > n) {
+               if (mask & 2)
+                   newFinalSpan (acc->yorgu - y,
+                                 acc->xorg + n, acc->xorg + lw);
+               if (mask & 4)
+                   newFinalSpan (acc->yorgl + y,
+                                 acc->xorg + n, acc->xorg + lw);
+           }
+           n = ICEIL(acc->fromIntX + rx);
+           if (n > -rw) {
+               if (mask & 1)
+                   newFinalSpan (acc->yorgu - y,
+                                 acc->xorg - rw, acc->xorg + n);
+               if (mask & 8)
+                   newFinalSpan (acc->yorgl + y,
+                                 acc->xorg - rw, acc->xorg + n);
+           }
+       }
+       arcSpan (y,
+                ICEIL(acc->fromIntX - x), 0,
+                ICEIL(acc->fromIntX + x), 0,
+                def, bounds, acc, mask);
+    }
+}
+
+/*
+ * create whole arcs out of pieces.  This code is
+ * very bad.
+ */
+
+static struct finalSpan        **finalSpans = NULL;
+static int             finalMiny = 0, finalMaxy = -1;
+static int             finalSize = 0;
+
+static int             nspans = 0;     /* total spans, not just y coords */
+
+struct finalSpan {
+       struct finalSpan        *next;
+       int                     min, max;       /* x values */
+};
+
+static struct finalSpan    *freeFinalSpans, *tmpFinalSpan;
+
+# define allocFinalSpan()   (freeFinalSpans ?\
+                               ((tmpFinalSpan = freeFinalSpans), \
+                                (freeFinalSpans = freeFinalSpans->next), \
+                                (tmpFinalSpan->next = 0), \
+                                tmpFinalSpan) : \
+                            realAllocSpan ())
+
+# define SPAN_CHUNK_SIZE    128
+
+struct finalSpanChunk {
+       struct finalSpan        data[SPAN_CHUNK_SIZE];
+       struct finalSpanChunk   *next;
+};
+
+static struct finalSpanChunk   *chunks;
+
+struct finalSpan *
+realAllocSpan ()
+{
+       register struct finalSpanChunk  *newChunk;
+       register struct finalSpan       *span;
+       register int                    i;
+
+       newChunk = (struct finalSpanChunk *) g_malloc (sizeof (struct finalSpanChunk));
+       if (!newChunk)
+               return (struct finalSpan *) NULL;
+       newChunk->next = chunks;
+       chunks = newChunk;
+       freeFinalSpans = span = newChunk->data + 1;
+       for (i = 1; i < SPAN_CHUNK_SIZE-1; i++) {
+               span->next = span+1;
+               span++;
+       }
+       span->next = 0;
+       span = newChunk->data;
+       span->next = 0;
+       return span;
+}
+
+static void
+disposeFinalSpans ()
+{
+       struct finalSpanChunk   *chunk, *next;
+
+       for (chunk = chunks; chunk; chunk = next) {
+               next = chunk->next;
+               g_free (chunk);
+       }
+       chunks = 0;
+       freeFinalSpans = 0;
+       g_free(finalSpans);
+       finalSpans = 0;
+}
+
+static void
+fillSpans (pDrawable, pGC)
+    GdkDrawable*       pDrawable;
+    GdkGC*     pGC;
+{
+       register struct finalSpan       *span;
+       register GdkRectangle*          xSpan;
+       register int                    i;
+       register struct finalSpan       **f;
+       register int                    spany;
+       GdkRectangle*                   xSpans;
+
+       if (nspans == 0)
+               return;
+       xSpan = xSpans = (GdkRectangle*) ALLOCATE_LOCAL (nspans * sizeof (GdkRectangle));
+       if (xSpans)
+       {
+           i = 0;
+           f = finalSpans;
+           for (spany = finalMiny; spany <= finalMaxy; spany++, f++) {
+                   for (span = *f; span; span=span->next) {
+                           if (span->max <= span->min)
+                                   continue;
+                           xSpan->x = span->min;
+                           xSpan->y = spany;
+                           xSpan->width = span->max - span->min;
+                           xSpan->height = 1;
+                           ++xSpan;
+                           ++i;
+                   }
+           }
+
+           gdk_fb_fill_spans(pDrawable, pGC, xSpans, i);
+       }
+       disposeFinalSpans ();
+       if (xSpans)
+           DEALLOCATE_LOCAL (xSpans);
+       finalMiny = 0;
+       finalMaxy = -1;
+       finalSize = 0;
+       nspans = 0;
+}
+
+# define SPAN_REALLOC  100
+
+# define findSpan(y) ((finalMiny <= (y) && (y) <= finalMaxy) ? \
+                         &finalSpans[(y) - finalMiny] : \
+                         realFindSpan (y))
+
+static struct finalSpan **
+realFindSpan (y)
+    int y;
+{
+       struct finalSpan        **newSpans;
+       int                     newSize, newMiny, newMaxy;
+       int                     change;
+       int                     i;
+
+       if (y < finalMiny || y > finalMaxy) {
+               if (!finalSize) {
+                       finalMiny = y;
+                       finalMaxy = y - 1;
+               }
+               if (y < finalMiny)
+                       change = finalMiny - y;
+               else
+                       change = y - finalMaxy;
+               if (change >= SPAN_REALLOC)
+                       change += SPAN_REALLOC;
+               else
+                       change = SPAN_REALLOC;
+               newSize = finalSize + change;
+               newSpans = (struct finalSpan **) g_malloc
+                                       (newSize * sizeof (struct finalSpan *));
+               if (!newSpans)
+                   return (struct finalSpan **)NULL;
+               newMiny = finalMiny;
+               newMaxy = finalMaxy;
+               if (y < finalMiny)
+                       newMiny = finalMiny - change;
+               else
+                       newMaxy = finalMaxy + change;
+               if (finalSpans) {
+                       g_memmove(((char *) newSpans) + (finalMiny-newMiny) * sizeof (struct finalSpan *),
+                                 (char *) finalSpans,
+                              finalSize * sizeof (struct finalSpan *));
+                       g_free (finalSpans);
+               }
+               if ((i = finalMiny - newMiny) > 0)
+                       memset ((char *)newSpans, 0, i * sizeof (struct finalSpan *));
+               if ((i = newMaxy - finalMaxy) > 0)
+                       memset ((char *)(newSpans + newSize - i), 0,
+                              i * sizeof (struct finalSpan *));
+               finalSpans = newSpans;
+               finalMaxy = newMaxy;
+               finalMiny = newMiny;
+               finalSize = newSize;
+       }
+       return &finalSpans[y - finalMiny];
+}
+
+static void
+newFinalSpan (y, xmin, xmax)
+    int                y;
+    register int       xmin, xmax;
+{
+       register struct finalSpan       *x;
+       register struct finalSpan       **f;
+       struct finalSpan                *oldx;
+       struct finalSpan                *prev;
+
+       f = findSpan (y);
+       if (!f)
+           return;
+       oldx = 0;
+       for (;;) {
+               prev = 0;
+               for (x = *f; x; x=x->next) {
+                       if (x == oldx) {
+                               prev = x;
+                               continue;
+                       }
+                       if (x->min <= xmax && xmin <= x->max) {
+                               if (oldx) {
+                                       oldx->min = MIN (x->min, xmin);
+                                       oldx->max = MAX (x->max, xmax);
+                                       if (prev)
+                                               prev->next = x->next;
+                                       else
+                                               *f = x->next;
+                                       --nspans;
+                               } else {
+                                       x->min = MIN (x->min, xmin);
+                                       x->max = MAX (x->max, xmax);
+                                       oldx = x;
+                               }
+                               xmin = oldx->min;
+                               xmax = oldx->max;
+                               break;
+                       }
+                       prev = x;
+               }
+               if (!x)
+                       break;
+       }
+       if (!oldx) {
+               x = allocFinalSpan ();
+               if (x)
+               {
+                   x->min = xmin;
+                   x->max = xmax;
+                   x->next = *f;
+                   *f = x;
+                   ++nspans;
+               }
+       }
+}
+
+static void
+mirrorSppPoint (quadrant, sppPoint)
+       int             quadrant;
+       SppPointPtr     sppPoint;
+{
+       switch (quadrant) {
+       case 0:
+               break;
+       case 1:
+               sppPoint->x = -sppPoint->x;
+               break;
+       case 2:
+               sppPoint->x = -sppPoint->x;
+               sppPoint->y = -sppPoint->y;
+               break;
+       case 3:
+               sppPoint->y = -sppPoint->y;
+               break;
+       }
+       /*
+        * and translate to X coordinate system
+        */
+       sppPoint->y = -sppPoint->y;
+}
+
+/*
+ * split an arc into pieces which are scan-converted
+ * in the first-quadrant and mirrored into position.
+ * This is necessary as the scan-conversion code can
+ * only deal with arcs completely contained in the
+ * first quadrant.
+ */
+
+static void
+drawArc (miArc *tarc, int l, int a0, int a1, miArcFacePtr right, miArcFacePtr left)
+     /*        miArcFacePtr    right, left;    */ /* save end line points */
+{
+       struct arc_def          def;
+       struct accelerators     acc;
+       int                     startq, endq, curq;
+       int                     rightq, leftq, righta, lefta;
+       miArcFacePtr            passRight, passLeft;
+       int                     q0, q1, mask;
+       struct band {
+               int     a0, a1;
+               int     mask;
+       }       band[5], sweep[20];
+       int                     bandno, sweepno;
+       int                     i, j;
+       int                     flipRight = 0, flipLeft = 0;                    
+       int                     copyEnd = 0;
+       miArcSpanData           *spdata;
+       gboolean                        mustFree;
+
+       spdata = miComputeWideEllipse(l, tarc, &mustFree);
+       if (!spdata)
+           return;
+
+       if (a1 < a0)
+               a1 += 360 * 64;
+       startq = a0 / (90 * 64);
+       if (a0 == a1)
+           endq = startq;
+       else
+           endq = (a1-1) / (90 * 64);
+       bandno = 0;
+       curq = startq;
+       rightq = -1;
+       for (;;) {
+               switch (curq) {
+               case 0:
+                       if (a0 > 90 * 64)
+                               q0 = 0;
+                       else
+                               q0 = a0;
+                       if (a1 < 360 * 64)
+                               q1 = MIN (a1, 90 * 64);
+                       else
+                               q1 = 90 * 64;
+                       if (curq == startq && a0 == q0 && rightq < 0) {
+                               righta = q0;
+                               rightq = curq;
+                       }
+                       if (curq == endq && a1 == q1) {
+                               lefta = q1;
+                               leftq = curq;
+                       }
+                       break;
+               case 1:
+                       if (a1 < 90 * 64)
+                               q0 = 0;
+                       else
+                               q0 = 180 * 64 - MIN (a1, 180 * 64);
+                       if (a0 > 180 * 64)
+                               q1 = 90 * 64;
+                       else
+                               q1 = 180 * 64 - MAX (a0, 90 * 64);
+                       if (curq == startq && 180 * 64 - a0 == q1) {
+                               righta = q1;
+                               rightq = curq;
+                       }
+                       if (curq == endq && 180 * 64 - a1 == q0) {
+                               lefta = q0;
+                               leftq = curq;
+                       }
+                       break;
+               case 2:
+                       if (a0 > 270 * 64)
+                               q0 = 0;
+                       else
+                               q0 = MAX (a0, 180 * 64) - 180 * 64;
+                       if (a1 < 180 * 64)
+                               q1 = 90 * 64;
+                       else
+                               q1 = MIN (a1, 270 * 64) - 180 * 64;
+                       if (curq == startq && a0 - 180*64 == q0) {
+                               righta = q0;
+                               rightq = curq;
+                       }
+                       if (curq == endq && a1 - 180 * 64 == q1) {
+                               lefta = q1;
+                               leftq = curq;
+                       }
+                       break;
+               case 3:
+                       if (a1 < 270 * 64)
+                               q0 = 0;
+                       else
+                               q0 = 360 * 64 - MIN (a1, 360 * 64);
+                       q1 = 360 * 64 - MAX (a0, 270 * 64);
+                       if (curq == startq && 360 * 64 - a0 == q1) {
+                               righta = q1;
+                               rightq = curq;
+                       }
+                       if (curq == endq && 360 * 64 - a1 == q0) {
+                               lefta = q0;
+                               leftq = curq;
+                       }
+                       break;
+               }
+               band[bandno].a0 = q0;
+               band[bandno].a1 = q1;
+               band[bandno].mask = 1 << curq;
+               bandno++;
+               if (curq == endq)
+                       break;
+               curq++;
+               if (curq == 4) {
+                       a0 = 0;
+                       a1 -= 360 * 64;
+                       curq = 0;
+                       endq -= 4;
+               }
+       }
+       sweepno = 0;
+       for (;;) {
+               q0 = 90 * 64;
+               mask = 0;
+               /*
+                * find left-most point
+                */
+               for (i = 0; i < bandno; i++)
+                       if (band[i].a0 <= q0) {
+                               q0 = band[i].a0;
+                               q1 = band[i].a1;
+                               mask = band[i].mask;
+                       }
+               if (!mask)
+                       break;
+               /*
+                * locate next point of change
+                */
+               for (i = 0; i < bandno; i++)
+                       if (!(mask & band[i].mask)) {
+                               if (band[i].a0 == q0) {
+                                       if (band[i].a1 < q1)
+                                               q1 = band[i].a1;
+                                       mask |= band[i].mask;
+                               } else if (band[i].a0 < q1)
+                                       q1 = band[i].a0;
+                       }
+               /*
+                * create a new sweep
+                */
+               sweep[sweepno].a0 = q0;
+               sweep[sweepno].a1 = q1;
+               sweep[sweepno].mask = mask;
+               sweepno++;
+               /*
+                * subtract the sweep from the affected bands
+                */
+               for (i = 0; i < bandno; i++)
+                       if (band[i].a0 == q0) {
+                               band[i].a0 = q1;
+                               /*
+                                * check if this band is empty
+                                */
+                               if (band[i].a0 == band[i].a1)
+                                       band[i].a1 = band[i].a0 = 90 * 64 + 1;
+                       }
+       }
+       computeAcc (tarc, l, &def, &acc);
+       for (j = 0; j < sweepno; j++) {
+               mask = sweep[j].mask;
+               passRight = passLeft = 0;
+               if (mask & (1 << rightq)) {
+                       if (sweep[j].a0 == righta)
+                               passRight = right;
+                       else if (sweep[j].a1 == righta) {
+                               passLeft = right;
+                               flipRight = 1;
+                       }
+               }
+               if (mask & (1 << leftq)) {
+                       if (sweep[j].a1 == lefta)
+                       {
+                               if (passLeft)
+                                       copyEnd = 1;
+                               passLeft = left;
+                       }
+                       else if (sweep[j].a0 == lefta) {
+                               if (passRight)
+                                       copyEnd = 1;
+                               passRight = left;
+                               flipLeft = 1;
+                       }
+               }
+               drawQuadrant (&def, &acc, sweep[j].a0, sweep[j].a1, mask, 
+                             passRight, passLeft, spdata);
+       }
+       /*
+        * when copyEnd is set, both ends of the arc were computed
+        * at the same time; drawQuadrant only takes one end though,
+        * so the left end will be the only one holding the data.  Copy
+        * it from there.
+        */
+       if (copyEnd)
+               *right = *left;
+       /*
+        * mirror the coordinates generated for the
+        * faces of the arc
+        */
+       if (right) {
+               mirrorSppPoint (rightq, &right->clock);
+               mirrorSppPoint (rightq, &right->center);
+               mirrorSppPoint (rightq, &right->counterClock);
+               if (flipRight) {
+                       SppPointRec     temp;
+
+                       temp = right->clock;
+                       right->clock = right->counterClock;
+                       right->counterClock = temp;
+               }
+       }
+       if (left) {
+               mirrorSppPoint (leftq,  &left->counterClock);
+               mirrorSppPoint (leftq,  &left->center);
+               mirrorSppPoint (leftq,  &left->clock);
+               if (flipLeft) {
+                       SppPointRec     temp;
+
+                       temp = left->clock;
+                       left->clock = left->counterClock;
+                       left->counterClock = temp;
+               }
+       }
+       if (mustFree)
+           g_free(spdata);
+}
+
+static void
+drawQuadrant (def, acc, a0, a1, mask, right, left, spdata)
+       struct arc_def          *def;
+       struct accelerators     *acc;
+       int                     a0, a1;
+       int                     mask;
+       miArcFacePtr            right, left;
+       miArcSpanData           *spdata;
+{
+       struct arc_bound        bound;
+       double                  yy, x, xalt;
+       int                     y, miny, maxy;
+       int                     n;
+       miArcSpan               *span;
+
+       def->a0 = ((double) a0) / 64.0;
+       def->a1 = ((double) a1) / 64.0;
+       computeBound (def, &bound, acc, right, left);
+       yy = bound.inner.min;
+       if (bound.outer.min < yy)
+           yy = bound.outer.min;
+       miny = ICEIL(yy - acc->fromIntY);
+       yy = bound.inner.max;
+       if (bound.outer.max > yy)
+           yy = bound.outer.max;
+       maxy = floor(yy - acc->fromIntY);
+       y = spdata->k;
+       span = spdata->spans;
+       if (spdata->top)
+       {
+           if (a1 == 90 * 64 && (mask & 1))
+               newFinalSpan (acc->yorgu - y - 1, acc->xorg, acc->xorg + 1);
+           span++;
+       }
+       for (n = spdata->count1; --n >= 0; )
+       {
+           if (y < miny)
+               return;
+           if (y <= maxy) {
+               arcSpan (y,
+                        span->lx, -span->lx, 0, span->lx + span->lw,
+                        def, &bound, acc, mask);
+               if (span->rw + span->rx)
+                   tailSpan (y, -span->rw, -span->rx, def, &bound, acc, mask);
+           }
+           y--;
+           span++;
+       }
+       if (y < miny)
+           return;
+       if (spdata->hole)
+       {
+           if (y <= maxy)
+               arcSpan (y, 0, 0, 0, 1, def, &bound, acc, mask & 0xc);
+       }
+       for (n = spdata->count2; --n >= 0; )
+       {
+           if (y < miny)
+               return;
+           if (y <= maxy)
+               arcSpan (y, span->lx, span->lw, span->rx, span->rw,
+                        def, &bound, acc, mask);
+           y--;
+           span++;
+       }
+       if (spdata->bot && miny <= y && y <= maxy)
+       {
+           n = mask;
+           if (y == miny)
+               n &= 0xc;
+           if (span->rw <= 0) {
+               arcSpan0 (span->lx, -span->lx, 0, span->lx + span->lw,
+                         def, &bound, acc, n);
+               if (span->rw + span->rx)
+                   tailSpan (y, -span->rw, -span->rx, def, &bound, acc, n);
+           }
+           else
+               arcSpan0 (span->lx, span->lw, span->rx, span->rw,
+                         def, &bound, acc, n);
+           y--;
+       }
+       while (y >= miny) {
+           yy = y + acc->fromIntY;
+           if (def->w == def->h) {
+               xalt = def->w - def->l;
+               x = -sqrt(xalt * xalt - yy * yy);
+           } else {
+               x = tailX(yy, def, &bound, acc);
+               if (acc->left.valid && boundedLe (yy, bound.left)) {
+                   xalt = intersectLine (yy, acc->left);
+                   if (xalt < x)
+                       x = xalt;
+               }
+               if (acc->right.valid && boundedLe (yy, bound.right)) {
+                   xalt = intersectLine (yy, acc->right);
+                   if (xalt < x)
+                       x = xalt;
+               }
+           }
+           arcSpan (y,
+                    ICEIL(acc->fromIntX - x), 0,
+                    ICEIL(acc->fromIntX + x), 0,
+                    def, &bound, acc, mask);
+           y--;
+       }
+}
diff --git a/gdk/linux-fb/midash.c b/gdk/linux-fb/midash.c
new file mode 100644 (file)
index 0000000..c939976
--- /dev/null
@@ -0,0 +1,309 @@
+/***********************************************************
+
+Copyright 1987, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+/* $TOG: midash.c /main/14 1998/02/09 14:46:34 kaleb $ */
+
+#include "mi.h"
+
+static miDashPtr CheckDashStorage();
+
+/* return a list of DashRec.  there will be an extra
+entry at the end holding the last point of the polyline.
+   this means that the code that actually draws dashes can
+get a pair of points for every dash.  only the point in the last
+dash record is useful; the other fields are not used.
+   nseg is the number of segments, not the number of points.
+
+example:
+
+   dash1.start
+   dash2.start
+   dash3.start
+   last-point
+
+defines a list of segments
+   (dash1.pt, dash2.pt)
+   (dash2.pt, dash3.pt)
+   (dash3.pt, last-point)
+and nseg == 3.
+
+NOTE:
+    EVEN_DASH == ~ODD_DASH
+
+NOTE ALSO:
+    miDashLines may return 0 segments, going from pt[0] to pt[0] with one dash.
+*/
+
+enum { EVEN_DASH=0, ODD_DASH=1 };
+
+#define sign(x) ((x)>0)?1:( ((x)<0)?-1:0 )
+
+miDashPtr
+miDashLine(npt, ppt, nDash, pDash, offset, pnseg)
+int npt;
+GdkPoint* ppt;
+unsigned int nDash;
+unsigned char *pDash;
+unsigned int offset;
+int *pnseg;
+{
+    GdkPoint pt1, pt2;
+    int lenCur;                /* npt used from this dash */
+    int lenMax;                /* npt in this dash */
+    int iDash = 0;     /* index of current dash */
+    int which;         /* EVEN_DASH or ODD_DASH */
+    miDashPtr pseg;    /* list of dash segments */
+    miDashPtr psegBase;        /* start of list */
+    int nseg = 0;      /* number of dashes so far */
+    int nsegMax = 0;   /* num segs we can fit in this list */
+
+    int x, y, len;
+    int adx, ady, signdx, signdy;
+    int du, dv, e1, e2, e, base_e = 0;
+
+    lenCur = offset;
+    which = EVEN_DASH;
+    while(lenCur >= pDash[iDash])
+    {
+       lenCur -= pDash[iDash];
+       iDash++;
+       if (iDash >= nDash)
+           iDash = 0;
+       which = ~which;
+    }
+    lenMax = pDash[iDash];
+
+    psegBase = (miDashPtr)NULL;
+    pt2 = ppt[0];              /* just in case there is only one point */
+
+    while(--npt)
+    {
+       if (PtEqual(ppt[0], ppt[1]))
+       {
+           ppt++;
+           continue;           /* no duplicated points in polyline */
+       }
+       pt1 = *ppt++;
+       pt2 = *ppt;
+
+       adx = pt2.x - pt1.x;
+       ady = pt2.y - pt1.y;
+       signdx = sign(adx);
+       signdy = sign(ady);
+       adx = abs(adx);
+       ady = abs(ady);
+
+       if (adx > ady)
+       {
+           du = adx;
+           dv = ady;
+           len = adx;
+       }
+       else
+       {
+           du = ady;
+           dv = adx;
+           len = ady;
+       }
+
+       e1 = dv * 2;
+       e2 = e1 - 2*du;
+       e = e1 - du;
+       x = pt1.x;
+       y = pt1.y;
+
+       nseg++;
+       pseg = CheckDashStorage(&psegBase, nseg, &nsegMax);
+       if (!pseg)
+           return (miDashPtr)NULL;
+       pseg->pt = pt1;
+       pseg->e1 = e1;
+       pseg->e2 = e2;
+       base_e = pseg->e = e;
+       pseg->which = which;
+       pseg->newLine = 1;
+
+       while (len--)
+       {
+           if (adx > ady)
+           {
+               /* X_AXIS */
+               if (((signdx > 0) && (e < 0)) ||
+                   ((signdx <=0) && (e <=0))
+                  )
+               {
+                   e += e1;
+               }
+               else
+               {
+                   y += signdy;
+                   e += e2;
+               }
+               x += signdx;
+           }
+           else
+           {
+               /* Y_AXIS */
+               if (((signdx > 0) && (e < 0)) ||
+                   ((signdx <=0) && (e <=0))
+                  )
+               {
+                   e +=e1;
+               }
+               else
+               {
+                   x += signdx;
+                   e += e2;
+               }
+               y += signdy;
+           }
+
+           lenCur++;
+           if (lenCur >= lenMax && (len || npt <= 1))
+           {
+               nseg++;
+               pseg = CheckDashStorage(&psegBase, nseg, &nsegMax);
+               if (!pseg)
+                   return (miDashPtr)NULL;
+               pseg->pt.x = x;
+               pseg->pt.y = y;
+               pseg->e1 = e1;
+               pseg->e2 = e2;
+               pseg->e = e;
+               which = ~which;
+               pseg->which = which;
+               pseg->newLine = 0;
+
+               /* move on to next dash */
+               iDash++;
+               if (iDash >= nDash)
+                   iDash = 0;
+               lenMax = pDash[iDash];
+               lenCur = 0;
+           }
+       } /* while len-- */
+    } /* while --npt */
+
+    if (lenCur == 0 && nseg != 0)
+    {
+       nseg--;
+       which = ~which;
+    }
+    *pnseg = nseg;
+    pseg = CheckDashStorage(&psegBase, nseg+1, &nsegMax);
+    if (!pseg)
+       return (miDashPtr)NULL;
+    pseg->pt = pt2;
+    pseg->e = base_e;
+    pseg->which = which;
+    pseg->newLine = 0;
+    return psegBase;
+} 
+
+
+#define NSEGDELTA 16
+
+/* returns a pointer to the pseg[nseg-1], growing the storage as
+necessary.  this interface seems unnecessarily cumbersome.
+
+*/
+
+static
+miDashPtr
+CheckDashStorage(ppseg, nseg, pnsegMax)
+miDashPtr *ppseg;              /* base pointer */
+int nseg;                      /* number of segment we want to write to */
+int *pnsegMax;                 /* size (in segments) of list so far */
+{
+    if (nseg > *pnsegMax)
+    {
+       miDashPtr newppseg;
+
+       *pnsegMax += NSEGDELTA;
+       newppseg = (miDashPtr)g_realloc(*ppseg,
+                                      (*pnsegMax)*sizeof(miDashRec));
+       if (!newppseg)
+       {
+           g_free(*ppseg);
+           return (miDashPtr)NULL;
+       }
+       *ppseg = newppseg;
+    }
+    return(*ppseg+(nseg-1));
+}
+
+void
+miStepDash (dist, pDashIndex, pDash, numInDashList, pDashOffset)
+    int dist;                  /* distance to step */
+    int *pDashIndex;           /* current dash */
+    unsigned char *pDash;      /* dash list */
+    int numInDashList;         /* total length of dash list */
+    int *pDashOffset;          /* offset into current dash */
+{
+    int        dashIndex, dashOffset;
+    int totallen;
+    int        i;
+    
+    dashIndex = *pDashIndex;
+    dashOffset = *pDashOffset;
+    if (dist < pDash[dashIndex] - dashOffset)
+    {
+       *pDashOffset = dashOffset + dist;
+       return;
+    }
+    dist -= pDash[dashIndex] - dashOffset;
+    if (++dashIndex == numInDashList)
+       dashIndex = 0;
+    totallen = 0;
+    for (i = 0; i < numInDashList; i++)
+       totallen += pDash[i];
+    if (totallen <= dist)
+       dist = dist % totallen;
+    while (dist >= pDash[dashIndex])
+    {
+       dist -= pDash[dashIndex];
+       if (++dashIndex == numInDashList)
+           dashIndex = 0;
+    }
+    *pDashIndex = dashIndex;
+    *pDashOffset = dist;
+}
diff --git a/gdk/linux-fb/mifillarc.c b/gdk/linux-fb/mifillarc.c
new file mode 100644 (file)
index 0000000..115be21
--- /dev/null
@@ -0,0 +1,743 @@
+/* $XFree86: xc/programs/Xserver/mi/mifillarc.c,v 3.4 1999/04/11 13:11:20 dawes Exp $ */
+/************************************************************
+
+Copyright 1989, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+Author:  Bob Scheifler, MIT X Consortium
+
+********************************************************/
+
+/* $TOG: mifillarc.c /main/20 1998/02/09 14:46:52 kaleb $ */
+
+#include <math.h>
+#include "mi.h"
+#include "mifillarc.h"
+#include "gdkprivate-fb.h"
+
+#define QUADRANT (90 * 64)
+#define HALFCIRCLE (180 * 64)
+#define QUADRANT3 (270 * 64)
+
+#ifndef M_PI
+#define M_PI   3.14159265358979323846
+#endif
+
+#define Dsin(d)        sin((double)d*(M_PI/11520.0))
+#define Dcos(d)        cos((double)d*(M_PI/11520.0))
+
+void
+miFillArcSetup(arc, info)
+    register miArc *arc;
+    register miFillArcRec *info;
+{
+    info->y = arc->height >> 1;
+    info->dy = arc->height & 1;
+    info->yorg = arc->y + info->y;
+    info->dx = arc->width & 1;
+    info->xorg = arc->x + (arc->width >> 1) + info->dx;
+    info->dx = 1 - info->dx;
+    if (arc->width == arc->height)
+    {
+       /* (2x - 2xorg)^2 = d^2 - (2y - 2yorg)^2 */
+       /* even: xorg = yorg = 0   odd:  xorg = .5, yorg = -.5 */
+       info->ym = 8;
+       info->xm = 8;
+       info->yk = info->y << 3;
+       if (!info->dx)
+       {
+           info->xk = 0;
+           info->e = -1;
+       }
+       else
+       {
+           info->y++;
+           info->yk += 4;
+           info->xk = -4;
+           info->e = - (info->y << 3);
+       }
+    }
+    else
+    {
+       /* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */
+       /* even: xorg = yorg = 0   odd:  xorg = .5, yorg = -.5 */
+       info->ym = (arc->width * arc->width) << 3;
+       info->xm = (arc->height * arc->height) << 3;
+       info->yk = info->y * info->ym;
+       if (!info->dy)
+           info->yk -= info->ym >> 1;
+       if (!info->dx)
+       {
+           info->xk = 0;
+           info->e = - (info->xm >> 3);
+       }
+       else
+       {
+           info->y++;
+           info->yk += info->ym;
+           info->xk = -(info->xm >> 1);
+           info->e = info->xk - info->yk;
+       }
+    }
+}
+
+void
+miFillArcDSetup(arc, info)
+    register miArc *arc;
+    register miFillArcDRec *info;
+{
+    /* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */
+    /* even: xorg = yorg = 0   odd:  xorg = .5, yorg = -.5 */
+    info->y = arc->height >> 1;
+    info->dy = arc->height & 1;
+    info->yorg = arc->y + info->y;
+    info->dx = arc->width & 1;
+    info->xorg = arc->x + (arc->width >> 1) + info->dx;
+    info->dx = 1 - info->dx;
+    info->ym = ((double)arc->width) * (arc->width * 8);
+    info->xm = ((double)arc->height) * (arc->height * 8);
+    info->yk = info->y * info->ym;
+    if (!info->dy)
+       info->yk -= info->ym / 2.0;
+    if (!info->dx)
+    {
+       info->xk = 0;
+       info->e = - (info->xm / 8.0);
+    }
+    else
+    {
+       info->y++;
+       info->yk += info->ym;
+       info->xk = -info->xm / 2.0;
+       info->e = info->xk - info->yk;
+    }
+}
+
+static void
+miGetArcEdge(arc, edge, k, top, left)
+    register miArc *arc;
+    register miSliceEdgePtr edge;
+    int k;
+    gboolean top, left;
+{
+    register int xady, y;
+
+    y = arc->height >> 1;
+    if (!(arc->width & 1))
+       y++;
+    if (!top)
+    {
+       y = -y;
+       if (arc->height & 1)
+           y--;
+    }
+    xady = k + y * edge->dx;
+    if (xady <= 0)
+       edge->x = - ((-xady) / edge->dy + 1);
+    else
+       edge->x = (xady - 1) / edge->dy;
+    edge->e = xady - edge->x * edge->dy;
+    if ((top && (edge->dx < 0)) || (!top && (edge->dx > 0)))
+       edge->e = edge->dy - edge->e + 1;
+    if (left)
+       edge->x++;
+    edge->x += arc->x + (arc->width >> 1);
+    if (edge->dx > 0)
+    {
+       edge->deltax = 1;
+       edge->stepx = edge->dx / edge->dy;
+       edge->dx = edge->dx % edge->dy;
+    }
+    else
+    {
+       edge->deltax = -1;
+       edge->stepx = - ((-edge->dx) / edge->dy);
+       edge->dx = (-edge->dx) % edge->dy;
+    }
+    if (!top)
+    {
+       edge->deltax = -edge->deltax;
+       edge->stepx = -edge->stepx;
+    }
+}
+
+void
+miEllipseAngleToSlope (angle, width, height, dxp, dyp, d_dxp, d_dyp)
+    int            angle;
+    int            width;
+    int            height;
+    int            *dxp;
+    int            *dyp;
+    double  *d_dxp;
+    double  *d_dyp;
+{
+    int            dx, dy;
+    double  d_dx, d_dy, scale;
+    gboolean    negative_dx, negative_dy;
+
+    switch (angle) {
+    case 0:
+       *dxp = -1;
+       *dyp = 0;
+       if (d_dxp) {
+           *d_dxp = width / 2.0;
+           *d_dyp = 0;
+       }
+       break;
+    case QUADRANT:
+       *dxp = 0;
+       *dyp = 1;
+       if (d_dxp) {
+           *d_dxp = 0;
+           *d_dyp = - height / 2.0;
+       }
+       break;
+    case HALFCIRCLE:
+       *dxp = 1;
+       *dyp = 0;
+       if (d_dxp) {
+           *d_dxp = - width / 2.0;
+           *d_dyp = 0;
+       }
+       break;
+    case QUADRANT3:
+       *dxp = 0;
+       *dyp = -1;
+       if (d_dxp) {
+           *d_dxp = 0;
+           *d_dyp = height / 2.0;
+       }
+       break;
+    default:
+       d_dx = Dcos(angle) * width;
+       d_dy = Dsin(angle) * height;
+       if (d_dxp) {
+           *d_dxp = d_dx / 2.0;
+           *d_dyp = - d_dy / 2.0;
+       }
+       negative_dx = FALSE;
+       if (d_dx < 0.0)
+       {
+           d_dx = -d_dx;
+           negative_dx = TRUE;
+       }
+       negative_dy = FALSE;
+       if (d_dy < 0.0)
+       {
+           d_dy = -d_dy;
+           negative_dy = TRUE;
+       }
+       scale = d_dx;
+       if (d_dy > d_dx)
+           scale = d_dy;
+       dx = floor ((d_dx * 32768) / scale + 0.5);
+       if (negative_dx)
+           dx = -dx;
+       *dxp = dx;
+       dy = floor ((d_dy * 32768) / scale + 0.5);
+       if (negative_dy)
+           dy = -dy;
+       *dyp = dy;
+       break;
+    }
+}
+
+static void
+miGetPieEdge(arc, angle, edge, top, left)
+    register miArc *arc;
+    register int angle;
+    register miSliceEdgePtr edge;
+    gboolean top, left;
+{
+    register int k;
+    int        dx, dy;
+
+    miEllipseAngleToSlope (angle, arc->width, arc->height, &dx, &dy, 0, 0);
+
+    if (dy == 0)
+    {
+       edge->x = left ? -65536 : 65536;
+       edge->stepx = 0;
+       edge->e = 0;
+       edge->dx = -1;
+       return;
+    }
+    if (dx == 0)
+    {
+       edge->x = arc->x + (arc->width >> 1);
+       if (left && (arc->width & 1))
+           edge->x++;
+       else if (!left && !(arc->width & 1))
+           edge->x--;
+       edge->stepx = 0;
+       edge->e = 0;
+       edge->dx = -1;
+       return;
+    }
+    if (dy < 0) {
+       dx = -dx;
+       dy = -dy;
+    }
+    k = (arc->height & 1) ? dx : 0;
+    if (arc->width & 1)
+       k += dy;
+    edge->dx = dx << 1;
+    edge->dy = dy << 1;
+    miGetArcEdge(arc, edge, k, top, left);
+}
+
+void
+miFillArcSliceSetup(arc, slice, pGC)
+    register miArc *arc;
+    register miArcSliceRec *slice;
+    GdkGC* pGC;
+{
+    register int angle1, angle2;
+
+    angle1 = arc->angle1;
+    if (arc->angle2 < 0)
+    {
+       angle2 = angle1;
+       angle1 += arc->angle2;
+    }
+    else
+       angle2 = angle1 + arc->angle2;
+    while (angle1 < 0)
+       angle1 += FULLCIRCLE;
+    while (angle1 >= FULLCIRCLE)
+       angle1 -= FULLCIRCLE;
+    while (angle2 < 0)
+       angle2 += FULLCIRCLE;
+    while (angle2 >= FULLCIRCLE)
+       angle2 -= FULLCIRCLE;
+    slice->min_top_y = 0;
+    slice->max_top_y = arc->height >> 1;
+    slice->min_bot_y = 1 - (arc->height & 1);
+    slice->max_bot_y = slice->max_top_y - 1;
+    slice->flip_top = FALSE;
+    slice->flip_bot = FALSE;
+    if (0 /* pGC->arcMode == ArcPieSlice */)
+    {
+       slice->edge1_top = (angle1 < HALFCIRCLE);
+       slice->edge2_top = (angle2 <= HALFCIRCLE);
+       if ((angle2 == 0) || (angle1 == HALFCIRCLE))
+       {
+           if (angle2 ? slice->edge2_top : slice->edge1_top)
+               slice->min_top_y = slice->min_bot_y;
+           else
+               slice->min_top_y = arc->height;
+           slice->min_bot_y = 0;
+       }
+       else if ((angle1 == 0) || (angle2 == HALFCIRCLE))
+       {
+           slice->min_top_y = slice->min_bot_y;
+           if (angle1 ? slice->edge1_top : slice->edge2_top)
+               slice->min_bot_y = arc->height;
+           else
+               slice->min_bot_y = 0;
+       }
+       else if (slice->edge1_top == slice->edge2_top)
+       {
+           if (angle2 < angle1)
+           {
+               slice->flip_top = slice->edge1_top;
+               slice->flip_bot = !slice->edge1_top;
+           }
+           else if (slice->edge1_top)
+           {
+               slice->min_top_y = 1;
+               slice->min_bot_y = arc->height;
+           }
+           else
+           {
+               slice->min_bot_y = 0;
+               slice->min_top_y = arc->height;
+           }
+       }
+       miGetPieEdge(arc, angle1, &slice->edge1,
+                    slice->edge1_top, !slice->edge1_top);
+       miGetPieEdge(arc, angle2, &slice->edge2,
+                    slice->edge2_top, slice->edge2_top);
+    }
+    else
+    {
+       double w2, h2, x1, y1, x2, y2, dx, dy, scale;
+       int signdx, signdy, y, k;
+       gboolean isInt1 = TRUE, isInt2 = TRUE;
+
+       w2 = (double)arc->width / 2.0;
+       h2 = (double)arc->height / 2.0;
+       if ((angle1 == 0) || (angle1 == HALFCIRCLE))
+       {
+           x1 = angle1 ? -w2 : w2;
+           y1 = 0.0;
+       }
+       else if ((angle1 == QUADRANT) || (angle1 == QUADRANT3))
+       {
+           x1 = 0.0;
+           y1 = (angle1 == QUADRANT) ? h2 : -h2;
+       }
+       else
+       {
+           isInt1 = FALSE;
+           x1 = Dcos(angle1) * w2;
+           y1 = Dsin(angle1) * h2;
+       }
+       if ((angle2 == 0) || (angle2 == HALFCIRCLE))
+       {
+           x2 = angle2 ? -w2 : w2;
+           y2 = 0.0;
+       }
+       else if ((angle2 == QUADRANT) || (angle2 == QUADRANT3))
+       {
+           x2 = 0.0;
+           y2 = (angle2 == QUADRANT) ? h2 : -h2;
+       }
+       else
+       {
+           isInt2 = FALSE;
+           x2 = Dcos(angle2) * w2;
+           y2 = Dsin(angle2) * h2;
+       }
+       dx = x2 - x1;
+       dy = y2 - y1;
+       if (arc->height & 1)
+       {
+           y1 -= 0.5;
+           y2 -= 0.5;
+       }
+       if (arc->width & 1)
+       {
+           x1 += 0.5;
+           x2 += 0.5;
+       }
+       if (dy < 0.0)
+       {
+           dy = -dy;
+           signdy = -1;
+       }
+       else
+           signdy = 1;
+       if (dx < 0.0)
+       {
+           dx = -dx;
+           signdx = -1;
+       }
+       else
+           signdx = 1;
+       if (isInt1 && isInt2)
+       {
+           slice->edge1.dx = dx * 2;
+           slice->edge1.dy = dy * 2;
+       }
+       else
+       {
+           scale = (dx > dy) ? dx : dy;
+           slice->edge1.dx = floor((dx * 32768) / scale + .5);
+           slice->edge1.dy = floor((dy * 32768) / scale + .5);
+       }
+       if (!slice->edge1.dy)
+       {
+           if (signdx < 0)
+           {
+               y = floor(y1 + 1.0);
+               if (y >= 0)
+               {
+                   slice->min_top_y = y;
+                   slice->min_bot_y = arc->height;
+               }
+               else
+               {
+                   slice->max_bot_y = -y - (arc->height & 1);
+               }
+           }
+           else
+           {
+               y = floor(y1);
+               if (y >= 0)
+                   slice->max_top_y = y;
+               else
+               {
+                   slice->min_top_y = arc->height;
+                   slice->min_bot_y = -y - (arc->height & 1);
+               }
+           }
+           slice->edge1_top = TRUE;
+           slice->edge1.x = 65536;
+           slice->edge1.stepx = 0;
+           slice->edge1.e = 0;
+           slice->edge1.dx = -1;
+           slice->edge2 = slice->edge1;
+           slice->edge2_top = FALSE;
+       }
+       else if (!slice->edge1.dx)
+       {
+           if (signdy < 0)
+               x1 -= 1.0;
+           slice->edge1.x = ceil(x1);
+           slice->edge1_top = signdy < 0;
+           slice->edge1.x += arc->x + (arc->width >> 1);
+           slice->edge1.stepx = 0;
+           slice->edge1.e = 0;
+           slice->edge1.dx = -1;
+           slice->edge2_top = !slice->edge1_top;
+           slice->edge2 = slice->edge1;
+       }
+       else
+       {
+           if (signdx < 0)
+               slice->edge1.dx = -slice->edge1.dx;
+           if (signdy < 0)
+               slice->edge1.dx = -slice->edge1.dx;
+           k = ceil(((x1 + x2) * slice->edge1.dy - (y1 + y2) * slice->edge1.dx) / 2.0);
+           slice->edge2.dx = slice->edge1.dx;
+           slice->edge2.dy = slice->edge1.dy;
+           slice->edge1_top = signdy < 0;
+           slice->edge2_top = !slice->edge1_top;
+           miGetArcEdge(arc, &slice->edge1, k,
+                        slice->edge1_top, !slice->edge1_top);
+           miGetArcEdge(arc, &slice->edge2, k,
+                        slice->edge2_top, slice->edge2_top);
+       }
+    }
+}
+
+#define ADDSPANS() \
+    pts->x = xorg - x; \
+    pts->y = yorg - y; \
+    pts->width = slw; \
+    pts->height = 1; \
+    pts++; \
+    if (miFillArcLower(slw)) \
+    { \
+       pts->x = xorg - x; \
+       pts->y = yorg + y + dy; \
+        pts->width = slw; \
+        pts->height = 1; \
+       pts++; \
+    }
+
+static void
+miFillEllipseI(pDraw, pGC, arc)
+    GdkDrawable* pDraw;
+    GdkGC* pGC;
+    miArc *arc;
+{
+    register int x, y, e;
+    int yk, xk, ym, xm, dx, dy, xorg, yorg;
+    int slw;
+    miFillArcRec info;
+    GdkRectangle* points;
+    register GdkRectangle* pts;
+
+    points = (GdkRectangle*)ALLOCATE_LOCAL(sizeof(GdkRectangle) * arc->height);
+    if (!points)
+       return;
+    miFillArcSetup(arc, &info);
+    MIFILLARCSETUP();
+    pts = points;
+    while (y > 0)
+    {
+       MIFILLARCSTEP(slw);
+       ADDSPANS();
+    }
+    gdk_fb_fill_spans(pDraw, pGC, points, pts - points);
+
+    DEALLOCATE_LOCAL(points);
+}
+
+static void
+miFillEllipseD(pDraw, pGC, arc)
+    GdkDrawable* pDraw;
+    GdkGC* pGC;
+    miArc *arc;
+{
+    register int x, y;
+    int xorg, yorg, dx, dy, slw;
+    double e, yk, xk, ym, xm;
+    miFillArcDRec info;
+    GdkRectangle* points;
+    register GdkRectangle* pts;
+
+    points = (GdkRectangle*)ALLOCATE_LOCAL(sizeof(GdkRectangle) * arc->height);
+    if (!points)
+       return;
+    miFillArcDSetup(arc, &info);
+    MIFILLARCSETUP();
+    pts = points;
+    while (y > 0)
+    {
+       MIFILLARCSTEP(slw);
+       ADDSPANS();
+    }
+    gdk_fb_fill_spans(pDraw, pGC, points, pts - points);
+    DEALLOCATE_LOCAL(points);
+}
+
+#define ADDSPAN(l,r) \
+    if (r >= l) \
+    { \
+       pts->x = l; \
+       pts->y = ya; \
+        pts->width = r - l + 1; \
+        pts->height = 1; \
+       pts++; \
+    }
+
+#define ADDSLICESPANS(flip) \
+    if (!flip) \
+    { \
+       ADDSPAN(xl, xr); \
+    } \
+    else \
+    { \
+       xc = xorg - x; \
+       ADDSPAN(xc, xr); \
+       xc += slw - 1; \
+       ADDSPAN(xl, xc); \
+    }
+
+static void
+miFillArcSliceI(pDraw, pGC, arc)
+    GdkDrawable* pDraw;
+    GdkGC* pGC;
+    miArc *arc;
+{
+    int yk, xk, ym, xm, dx, dy, xorg, yorg, slw;
+    register int x, y, e;
+    miFillArcRec info;
+    miArcSliceRec slice;
+    int ya, xl, xr, xc;
+    GdkRectangle* points;
+    register GdkRectangle* pts;
+
+    miFillArcSetup(arc, &info);
+    miFillArcSliceSetup(arc, &slice, pGC);
+    MIFILLARCSETUP();
+    slw = arc->height;
+    if (slice.flip_top || slice.flip_bot)
+       slw += (arc->height >> 1) + 1;
+    points = (GdkRectangle*)ALLOCATE_LOCAL(sizeof(GdkRectangle) * slw);
+    if (!points)
+       return;
+    pts = points;
+    while (y > 0)
+    {
+       MIFILLARCSTEP(slw);
+       MIARCSLICESTEP(slice.edge1);
+       MIARCSLICESTEP(slice.edge2);
+       if (miFillSliceUpper(slice))
+       {
+           ya = yorg - y;
+           MIARCSLICEUPPER(xl, xr, slice, slw);
+           ADDSLICESPANS(slice.flip_top);
+       }
+       if (miFillSliceLower(slice))
+       {
+           ya = yorg + y + dy;
+           MIARCSLICELOWER(xl, xr, slice, slw);
+           ADDSLICESPANS(slice.flip_bot);
+       }
+    }
+    
+    gdk_fb_fill_spans(pDraw, pGC, points, pts - points);
+    DEALLOCATE_LOCAL(points);
+}
+
+static void
+miFillArcSliceD(pDraw, pGC, arc)
+    GdkDrawable* pDraw;
+    GdkGC* pGC;
+    miArc *arc;
+{
+    register int x, y;
+    int dx, dy, xorg, yorg, slw;
+    double e, yk, xk, ym, xm;
+    miFillArcDRec info;
+    miArcSliceRec slice;
+    int ya, xl, xr, xc;
+    GdkRectangle* points;
+    register GdkRectangle* pts;
+
+    miFillArcDSetup(arc, &info);
+    miFillArcSliceSetup(arc, &slice, pGC);
+    MIFILLARCSETUP();
+    slw = arc->height;
+    if (slice.flip_top || slice.flip_bot)
+       slw += (arc->height >> 1) + 1;
+    points = (GdkRectangle*)ALLOCATE_LOCAL(sizeof(GdkRectangle) * slw);
+    if (!points)
+       return;
+    pts = points;
+    while (y > 0)
+    {
+       MIFILLARCSTEP(slw);
+       MIARCSLICESTEP(slice.edge1);
+       MIARCSLICESTEP(slice.edge2);
+       if (miFillSliceUpper(slice))
+       {
+           ya = yorg - y;
+           MIARCSLICEUPPER(xl, xr, slice, slw);
+           ADDSLICESPANS(slice.flip_top);
+       }
+       if (miFillSliceLower(slice))
+       {
+           ya = yorg + y + dy;
+           MIARCSLICELOWER(xl, xr, slice, slw);
+           ADDSLICESPANS(slice.flip_bot);
+       }
+    }
+    gdk_fb_fill_spans(pDraw, pGC, points, pts - points);
+
+    DEALLOCATE_LOCAL(points);
+}
+
+/* MIPOLYFILLARC -- The public entry for the PolyFillArc request.
+ * Since we don't have to worry about overlapping segments, we can just
+ * fill each arc as it comes.
+ */
+void
+miPolyFillArc(pDraw, pGC, narcs, parcs)
+    GdkDrawable*       pDraw;
+    GdkGC*     pGC;
+    int                narcs;
+    miArc      *parcs;
+{
+    register int i;
+    register miArc *arc;
+
+    for(i = narcs, arc = parcs; --i >= 0; arc++)
+    {
+       if (miFillArcEmpty(arc))
+           continue;;
+       if ((arc->angle2 >= FULLCIRCLE) || (arc->angle2 <= -FULLCIRCLE))
+       {
+           if (miCanFillArc(arc))
+               miFillEllipseI(pDraw, pGC, arc);
+           else
+               miFillEllipseD(pDraw, pGC, arc);
+       }
+       else
+       {
+           if (miCanFillArc(arc))
+               miFillArcSliceI(pDraw, pGC, arc);
+           else
+               miFillArcSliceD(pDraw, pGC, arc);
+       }
+    }
+}
diff --git a/gdk/linux-fb/mifillarc.h b/gdk/linux-fb/mifillarc.h
new file mode 100644 (file)
index 0000000..99a75d6
--- /dev/null
@@ -0,0 +1,224 @@
+/* $XFree86: xc/programs/Xserver/mi/mifillarc.h,v 3.3 1998/10/04 09:39:27 dawes Exp $ */
+/************************************************************
+
+Copyright 1989, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+********************************************************/
+
+/* $TOG: mifillarc.h /main/11 1998/02/09 14:46:57 kaleb $ */
+
+#ifndef MIFILLARC_H
+#define MIFILLARC_H 1
+
+#define FULLCIRCLE (360 * 64)
+
+typedef struct _miFillArc {
+    int xorg, yorg;
+    int y;
+    int dx, dy;
+    int e;
+    int ym, yk, xm, xk;
+} miFillArcRec;
+
+/* could use 64-bit integers */
+typedef struct _miFillArcD {
+    int xorg, yorg;
+    int y;
+    int dx, dy;
+    double e;
+    double ym, yk, xm, xk;
+} miFillArcDRec;
+
+#define miFillArcEmpty(arc) (!(arc)->angle2 || \
+                            !(arc)->width || !(arc)->height || \
+                            (((arc)->width == 1) && ((arc)->height & 1)))
+
+#define miCanFillArc(arc) (((arc)->width == (arc)->height) || \
+                          (((arc)->width <= 800) && ((arc)->height <= 800)))
+
+#define MIFILLARCSETUP() \
+    x = 0; \
+    y = info.y; \
+    e = info.e; \
+    xk = info.xk; \
+    xm = info.xm; \
+    yk = info.yk; \
+    ym = info.ym; \
+    dx = info.dx; \
+    dy = info.dy; \
+    xorg = info.xorg; \
+    yorg = info.yorg
+
+#define MIFILLARCSTEP(slw) \
+    e += yk; \
+    while (e >= 0) \
+    { \
+       x++; \
+       xk -= xm; \
+       e += xk; \
+    } \
+    y--; \
+    yk -= ym; \
+    slw = (x << 1) + dx; \
+    if ((e == xk) && (slw > 1)) \
+       slw--
+
+#define MIFILLCIRCSTEP(slw) MIFILLARCSTEP(slw)
+#define MIFILLELLSTEP(slw) MIFILLARCSTEP(slw)
+
+#define miFillArcLower(slw) (((y + dy) != 0) && ((slw > 1) || (e != xk)))
+
+typedef struct _miSliceEdge {
+    int            x;
+    int     stepx;
+    int            deltax;
+    int            e;
+    int            dy;
+    int            dx;
+} miSliceEdgeRec, *miSliceEdgePtr;
+
+typedef struct _miArcSlice {
+    miSliceEdgeRec edge1, edge2;
+    int min_top_y, max_top_y;
+    int min_bot_y, max_bot_y;
+    gboolean edge1_top, edge2_top;
+    gboolean flip_top, flip_bot;
+} miArcSliceRec;
+
+#define MIARCSLICESTEP(edge) \
+    edge.x -= edge.stepx; \
+    edge.e -= edge.dx; \
+    if (edge.e <= 0) \
+    { \
+       edge.x -= edge.deltax; \
+       edge.e += edge.dy; \
+    }
+
+#define miFillSliceUpper(slice) \
+               ((y >= slice.min_top_y) && (y <= slice.max_top_y))
+
+#define miFillSliceLower(slice) \
+               ((y >= slice.min_bot_y) && (y <= slice.max_bot_y))
+
+#define MIARCSLICEUPPER(xl,xr,slice,slw) \
+    xl = xorg - x; \
+    xr = xl + slw - 1; \
+    if (slice.edge1_top && (slice.edge1.x < xr)) \
+       xr = slice.edge1.x; \
+    if (slice.edge2_top && (slice.edge2.x > xl)) \
+       xl = slice.edge2.x;
+
+#define MIARCSLICELOWER(xl,xr,slice,slw) \
+    xl = xorg - x; \
+    xr = xl + slw - 1; \
+    if (!slice.edge1_top && (slice.edge1.x > xl)) \
+       xl = slice.edge1.x; \
+    if (!slice.edge2_top && (slice.edge2.x < xr)) \
+       xr = slice.edge2.x;
+
+#define MIWIDEARCSETUP(x,y,dy,slw,e,xk,xm,yk,ym) \
+    x = 0; \
+    y = slw >> 1; \
+    yk = y << 3; \
+    xm = 8; \
+    ym = 8; \
+    if (dy) \
+    { \
+       xk = 0; \
+       if (slw & 1) \
+           e = -1; \
+       else \
+           e = -(y << 2) - 2; \
+    } \
+    else \
+    { \
+       y++; \
+       yk += 4; \
+       xk = -4; \
+       if (slw & 1) \
+           e = -(y << 2) - 3; \
+       else \
+           e = - (y << 3); \
+    }
+
+#define MIFILLINARCSTEP(slw) \
+    ine += inyk; \
+    while (ine >= 0) \
+    { \
+       inx++; \
+       inxk -= inxm; \
+       ine += inxk; \
+    } \
+    iny--; \
+    inyk -= inym; \
+    slw = (inx << 1) + dx; \
+    if ((ine == inxk) && (slw > 1)) \
+       slw--
+
+#define miFillInArcLower(slw) (((iny + dy) != 0) && \
+                              ((slw > 1) || (ine != inxk)))
+
+extern int miFreeArcCache(
+#if NeedFunctionPrototypes
+    gpointer /*data*/,
+    guint /*id*/
+#endif
+);
+
+extern struct finalSpan *realAllocSpan(
+#if NeedFunctionPrototypes
+    void
+#endif
+);
+
+extern void miFillArcSetup(
+#if NeedFunctionPrototypes
+    miArc * /*arc*/,
+    miFillArcRec * /*info*/
+#endif
+);
+
+extern void miFillArcDSetup(
+#if NeedFunctionPrototypes
+    miArc * /*arc*/,
+    miFillArcDRec * /*info*/
+#endif
+);
+
+extern void miEllipseAngleToSlope(
+#if NeedFunctionPrototypes
+    int /*angle*/,
+    int /*width*/,
+    int /*height*/,
+    int * /*dxp*/,
+    int * /*dyp*/,
+    double * /*d_dxp*/,
+    double * /*d_dyp*/
+#endif
+);
+
+extern void miFillArcSliceSetup(
+#if NeedFunctionPrototypes
+    miArc * /*arc*/,
+    miArcSliceRec * /*slice*/,
+    GdkGC* /*pGC*/
+#endif
+);
+
+#endif
diff --git a/gdk/linux-fb/mifpoly.h b/gdk/linux-fb/mifpoly.h
new file mode 100644 (file)
index 0000000..fd56f57
--- /dev/null
@@ -0,0 +1,112 @@
+/* $TOG: mifpoly.h /main/10 1998/02/09 14:47:09 kaleb $ */
+/***********************************************************
+
+Copyright 1987, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef MIFPOLY_H
+#define MIFPOLY_H 1
+
+#define EPSILON        0.000001
+#define ISEQUAL(a,b) (fabs((a) - (b)) <= EPSILON)
+#define UNEQUAL(a,b) (fabs((a) - (b)) > EPSILON)
+#define WITHINHALF(a, b) (((a) - (b) > 0.0) ? (a) - (b) < 0.5 : \
+                                            (b) - (a) <= 0.5)
+#define ROUNDTOINT(x)   ((int) (((x) > 0.0) ? ((x) + 0.5) : ((x) - 0.5)))
+#define ISZERO(x)      (fabs((x)) <= EPSILON)
+#define PTISEQUAL(a,b) (ISEQUAL(a.x,b.x) && ISEQUAL(a.y,b.y))
+#define PTUNEQUAL(a,b) (UNEQUAL(a.x,b.x) || UNEQUAL(a.y,b.y))
+#define PtEqual(a, b) (((a).x == (b).x) && ((a).y == (b).y))
+
+#define NotEnd         0
+#define FirstEnd       1
+#define SecondEnd      2
+
+#define SQSECANT 108.856472512142 /* 1/sin^2(11/2) - for 11o miter cutoff */
+#define D2SECANT 5.21671526231167 /* 1/2*sin(11/2) - max extension per width */
+
+#ifndef ICIEL
+#ifdef NOINLINEICEIL
+#define ICEIL(x) ((int)ceil(x))
+#else
+#ifdef __GNUC__
+#define ICEIL ICIEL
+static __inline int ICEIL(x)
+    double x;
+{
+    int _cTmp = x;
+    return ((x == _cTmp) || (x < 0.0)) ? _cTmp : _cTmp+1;
+}
+#else
+#define ICEIL(x) ((((x) == (_cTmp = (x))) || ((x) < 0.0)) ? _cTmp : _cTmp+1)
+#define ICEILTEMPDECL static int _cTmp;
+#endif
+#endif
+#endif
+
+/* Point with sub-pixel positioning.  In this case we use doubles, but
+ * see mifpolycon.c for other suggestions 
+ */
+typedef struct _SppPoint {
+       double  x, y;
+} SppPointRec, *SppPointPtr;
+
+typedef struct _SppArc {
+       double  x, y, width, height;
+       double  angle1, angle2;
+} SppArcRec, *SppArcPtr;
+
+/* mifpolycon.c */
+
+extern void miFillSppPoly(
+#if NeedFunctionPrototypes
+    GdkDrawable* /*dst*/,
+    GdkGC* /*pgc*/,
+    int /*count*/,
+    SppPointPtr /*ptsIn*/,
+    int /*xTrans*/,
+    int /*yTrans*/,
+    double /*xFtrans*/,
+    double /*yFtrans*/
+#endif
+);
+
+#endif /* MIFPOLY_H */
diff --git a/gdk/linux-fb/mifpolycon.c b/gdk/linux-fb/mifpolycon.c
new file mode 100644 (file)
index 0000000..341512f
--- /dev/null
@@ -0,0 +1,261 @@
+/***********************************************************
+
+Copyright 1987, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+/* $TOG: mifpolycon.c /main/13 1998/02/09 14:47:05 kaleb $ */
+#include <math.h>
+#include "mi.h"
+#include "mifpoly.h"
+
+static int GetFPolyYBounds();
+
+#ifdef ICEILTEMPDECL
+ICEILTEMPDECL
+#endif
+
+/*
+ *     Written by Todd Newman; April. 1987.
+ *
+ *     Fill a convex polygon.  If the given polygon
+ *     is not convex, then the result is undefined.
+ *     The algorithm is to order the edges from smallest
+ *     y to largest by partitioning the array into a left
+ *     edge list and a right edge list.  The algorithm used
+ *     to traverse each edge is digital differencing analyzer
+ *     line algorithm with y as the major axis. There's some funny linear
+ *     interpolation involved because of the subpixel postioning.
+ */
+void
+miFillSppPoly(GdkDrawable *dst, GdkGC *pgc, int count, SppPointPtr ptsIn, int xTrans, int yTrans, double xFtrans, double yFtrans)
+#if 0
+    GdkDrawable*       dst;
+    GdkGC*             pgc;
+    int                        count;          /* number of points */
+    SppPointPtr        ptsIn;          /* the points */
+    int                        xTrans, yTrans; /* Translate each point by this */
+    double             xFtrans, yFtrans;       /* translate before conversion
+                                                  by this amount.  This provides
+                                                  a mechanism to match rounding
+                                                  errors with any shape that must
+                                                  meet the polygon exactly.
+                                                */
+#endif
+{
+    double             xl, xr,         /* x vals of left and right edges */
+                       ml,             /* left edge slope */
+                       mr,             /* right edge slope */
+                       dy,             /* delta y */
+                       i;              /* loop counter */
+    int                        y,              /* current scanline */
+                       j,
+                       imin,           /* index of vertex with smallest y */
+                       ymin,           /* y-extents of polygon */
+                       ymax,
+                       *Marked;        /* set if this vertex has been used */
+    register int       left, right,    /* indices to first endpoints */
+                       nextleft,
+                       nextright;      /* indices to second endpoints */
+    GdkRectangle*      ptsOut,
+      *FirstPoint;     /* output buffer */
+
+    imin = GetFPolyYBounds(ptsIn, count, yFtrans, &ymin, &ymax);
+
+    y = ymax - ymin + 1;
+    if ((count < 3) || (y <= 0))
+       return;
+    ptsOut = FirstPoint = (GdkRectangle*)ALLOCATE_LOCAL(sizeof(GdkRectangle) * y);
+    Marked = (int *) ALLOCATE_LOCAL(sizeof(int) * count);
+
+    if(!ptsOut || !Marked)
+    {
+       if (Marked) DEALLOCATE_LOCAL(Marked);
+       if (ptsOut) DEALLOCATE_LOCAL(ptsOut);
+       return;
+    }
+
+    for(j = 0; j < count; j++)
+       Marked[j] = 0;
+    nextleft = nextright = imin;
+    Marked[imin] = -1;
+    y = ICEIL(ptsIn[nextleft].y + yFtrans);
+
+    /*
+     *  loop through all edges of the polygon
+     */
+    do
+    {
+        /* add a left edge if we need to */
+        if ((y > (ptsIn[nextleft].y + yFtrans) ||
+            ISEQUAL(y, ptsIn[nextleft].y + yFtrans)) &&
+            Marked[nextleft] != 1)
+       {
+           Marked[nextleft]++;
+            left = nextleft++;
+
+            /* find the next edge, considering the end conditions */
+            if (nextleft >= count)
+                nextleft = 0;
+
+            /* now compute the starting point and slope */
+           dy = ptsIn[nextleft].y - ptsIn[left].y;
+           if (dy != 0.0)
+           { 
+               ml = (ptsIn[nextleft].x - ptsIn[left].x) / dy;
+               dy = y - (ptsIn[left].y + yFtrans);
+               xl = (ptsIn[left].x + xFtrans) + ml * MAX(dy, 0); 
+           }
+        }
+
+        /* add a right edge if we need to */
+        if ((y > ptsIn[nextright].y + yFtrans) ||
+            (ISEQUAL(y, ptsIn[nextright].y + yFtrans)
+             && Marked[nextright] != 1))
+       {
+           Marked[nextright]++;
+            right = nextright--;
+
+            /* find the next edge, considering the end conditions */
+            if (nextright < 0)
+                nextright = count - 1;
+
+            /* now compute the starting point and slope */
+           dy = ptsIn[nextright].y - ptsIn[right].y;
+           if (dy != 0.0) 
+           { 
+               mr = (ptsIn[nextright].x - ptsIn[right].x) / dy;
+               dy = y - (ptsIn[right].y + yFtrans); 
+               xr = (ptsIn[right].x + xFtrans) + mr * MAX(dy, 0);
+           }
+        }
+
+
+        /*
+         *  generate scans to fill while we still have
+         *  a right edge as well as a left edge.
+         */
+        i = (MIN(ptsIn[nextleft].y, ptsIn[nextright].y) + yFtrans) - y;
+
+       if (i < EPSILON)
+       {
+           if(Marked[nextleft] && Marked[nextright])
+           {
+               /* Arrgh, we're trapped! (no more points) 
+                * Out, we've got to get out of here before this decadence saps
+                * our will completely! */
+               break;
+           }
+           continue;
+       }
+       else
+       {
+               j = (int) i;
+               if(!j)
+                   j++;
+       }
+        while (j > 0) 
+        {
+           int cxl, cxr;
+
+            ptsOut->y = (y) + yTrans;
+
+           cxl = ICEIL(xl);
+           cxr = ICEIL(xr);
+           ptsOut->height = 1;
+            /* reverse the edges if necessary */
+            if (xl < xr) 
+            {
+             ptsOut->width = cxr - cxl;
+             (ptsOut++)->x = cxl + xTrans;
+            }
+            else 
+            {
+             ptsOut->width = cxl - cxr;
+             (ptsOut++)->x = cxr + xTrans;
+            }
+            y++;
+
+            /* increment down the edges */
+           xl += ml;
+           xr += mr;
+           j--;
+        }
+    }  while (y <= ymax);
+
+    /* Finally, fill the spans we've collected */
+    gdk_fb_fill_spans(dst, pgc, FirstPoint, ptsOut-FirstPoint);
+    DEALLOCATE_LOCAL(Marked);
+    DEALLOCATE_LOCAL(FirstPoint);
+}
+
+\f
+/* Find the index of the point with the smallest y.also return the
+ * smallest and largest y */
+static
+int
+GetFPolyYBounds(pts, n, yFtrans, by, ty)
+    register SppPointPtr       pts;
+    int                        n;
+    double                     yFtrans;
+    int                        *by, *ty;
+{
+    register SppPointPtr       ptMin;
+    double                     ymin, ymax;
+    SppPointPtr                        ptsStart = pts;
+
+    ptMin = pts;
+    ymin = ymax = (pts++)->y;
+
+    while (--n > 0) {
+        if (pts->y < ymin)
+       {
+            ptMin = pts;
+            ymin = pts->y;
+        }
+       if(pts->y > ymax)
+            ymax = pts->y;
+
+        pts++;
+    }
+
+    *by = ICEIL(ymin + yFtrans);
+    *ty = ICEIL(ymax + yFtrans - 1);
+    return(ptMin-ptsStart);
+}
diff --git a/gdk/linux-fb/miline.h b/gdk/linux-fb/miline.h
new file mode 100644 (file)
index 0000000..a4ccf2c
--- /dev/null
@@ -0,0 +1,177 @@
+/* $TOG: miline.h /main/7 1998/02/09 14:47:30 kaleb $ */
+
+/*
+
+Copyright 1994, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/* $XFree86: xc/programs/Xserver/mi/miline.h,v 1.4 1999/10/13 22:33:11 dawes Exp $ */
+
+#ifndef MILINE_H
+
+/*
+ * Public definitions used for configuring basic pixelization aspects
+ * of the sample implementation line-drawing routines provided in
+ * {mfb,mi,cfb*} at run-time.
+ */
+
+#define XDECREASING    4
+#define YDECREASING    2
+#define YMAJOR         1
+
+#define OCTANT1                (1 << (YDECREASING))
+#define OCTANT2                (1 << (YDECREASING|YMAJOR))
+#define OCTANT3                (1 << (XDECREASING|YDECREASING|YMAJOR))
+#define OCTANT4                (1 << (XDECREASING|YDECREASING))
+#define OCTANT5                (1 << (XDECREASING))
+#define OCTANT6                (1 << (XDECREASING|YMAJOR))
+#define OCTANT7                (1 << (YMAJOR))
+#define OCTANT8                (1 << (0))
+
+#define XMAJOROCTANTS          (OCTANT1 | OCTANT4 | OCTANT5 | OCTANT8)
+
+#define DEFAULTZEROLINEBIAS    (OCTANT2 | OCTANT3 | OCTANT4 | OCTANT5)
+
+/*
+ * Devices can configure the rendering of routines in mi, mfb, and cfb*
+ * by specifying a thin line bias to be applied to a particular screen
+ * using the following function.  The bias parameter is an OR'ing of
+ * the appropriate OCTANT constants defined above to indicate which
+ * octants to bias a line to prefer an axial step when the Bresenham
+ * error term is exactly zero.  The octants are mapped as follows:
+ *
+ *   \    |    /
+ *    \ 3 | 2 /
+ *     \  |  /
+ *    4 \ | / 1
+ *       \|/
+ *   -----------
+ *       /|\
+ *    5 / | \ 8
+ *     /  |  \
+ *    / 6 | 7 \
+ *   /    |    \
+ *
+ * For more information, see "Ambiguities in Incremental Line Rastering,"
+ * Jack E. Bresenham, IEEE CG&A, May 1987.
+ */
+
+#if 0
+extern void miSetZeroLineBias(
+#if NeedFunctionPrototypes
+    ScreenPtr /* pScreen */,
+    unsigned int /* bias */
+#endif
+);
+#endif
+
+/*
+ * Private definitions needed for drawing thin (zero width) lines
+ * Used by the mi, mfb, and all cfb* components.
+ */
+
+#define X_AXIS 0
+#define Y_AXIS 1
+
+#define OUT_LEFT  0x08
+#define OUT_RIGHT 0x04
+#define OUT_ABOVE 0x02
+#define OUT_BELOW 0x01
+
+#define OUTCODES(_result, _x, _y, _pbox) \
+    if     ( (_x) <  (_pbox)->x1) (_result) |= OUT_LEFT; \
+    else if ( (_x) >= (_pbox)->x2) (_result) |= OUT_RIGHT; \
+    if     ( (_y) <  (_pbox)->y1) (_result) |= OUT_ABOVE; \
+    else if ( (_y) >= (_pbox)->y2) (_result) |= OUT_BELOW;
+
+#define MIOUTCODES(outcode, x, y, xmin, ymin, xmax, ymax) \
+{\
+     if (x < xmin) outcode |= OUT_LEFT;\
+     if (x > xmax) outcode |= OUT_RIGHT;\
+     if (y < ymin) outcode |= OUT_ABOVE;\
+     if (y > ymax) outcode |= OUT_BELOW;\
+}
+  
+#define SWAPINT(i, j) \
+{  register int _t = i;  i = j;  j = _t; }
+
+#define SWAPPT(i, j) \
+{  GdkPoint _t; _t = i;  i = j; j = _t; }
+
+#define SWAPINT_PAIR(x1, y1, x2, y2)\
+{   int t = x1;  x1 = x2;  x2 = t;\
+        t = y1;  y1 = y2;  y2 = t;\
+}
+
+#if 0
+#define miGetZeroLineBias(_pScreen) \
+    ((miZeroLineScreenIndex < 0) ? \
+               0 : ((_pScreen)->devPrivates[miZeroLineScreenIndex].uval))
+#endif
+#define miGetZeroLineBias() DEFAULTZEROLINEBIAS
+
+#define CalcLineDeltas(_x1,_y1,_x2,_y2,_adx,_ady,_sx,_sy,_SX,_SY,_octant) \
+    (_octant) = 0;                             \
+    (_sx) = (_SX);                             \
+    if (((_adx) = (_x2) - (_x1)) < 0) {                \
+       (_adx) = -(_adx);                       \
+       (_sx = -(_sx));                         \
+       (_octant) |= XDECREASING;               \
+    }                                          \
+    (_sy) = (_SY);                             \
+    if (((_ady) = (_y2) - (_y1)) < 0) {                \
+       (_ady) = -(_ady);                       \
+       (_sy = -(_sy));                         \
+       (_octant) |= YDECREASING;               \
+    }
+
+#define SetYMajorOctant(_octant)       ((_octant) |= YMAJOR)
+
+#define FIXUP_ERROR(_e, _octant, _bias) \
+    (_e) -= (((_bias) >> (_octant)) & 1)
+
+#define IsXMajorOctant(_octant)                (!((_octant) & YMAJOR))
+#define IsYMajorOctant(_octant)                ((_octant) & YMAJOR)
+#define IsXDecreasingOctant(_octant)   ((_octant) & XDECREASING)
+#define IsYDecreasingOctant(_octant)   ((_octant) & YDECREASING)
+
+extern int miZeroLineScreenIndex;
+
+extern int miZeroClipLine(
+#if NeedFunctionPrototypes
+    int /*xmin*/,
+    int /*ymin*/,
+    int /*xmax*/,
+    int /*ymax*/,
+    int * /*new_x1*/,
+    int * /*new_y1*/,
+    int * /*new_x2*/,
+    int * /*new_y2*/,
+    unsigned int /*adx*/,
+    unsigned int /*ady*/,
+    int * /*pt1_clipped*/,
+    int * /*pt2_clipped*/,
+    int /*octant*/,
+    unsigned int /*bias*/,
+    int /*oc1*/,
+    int /*oc2*/
+#endif
+);
+
+#endif /* MILINE_H */
diff --git a/gdk/linux-fb/mipoly.c b/gdk/linux-fb/mipoly.c
new file mode 100644 (file)
index 0000000..de1d740
--- /dev/null
@@ -0,0 +1,77 @@
+/***********************************************************
+
+Copyright 1987, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+/* $TOG: mipoly.c /main/5 1998/02/09 14:48:16 kaleb $ */
+/*
+ *  mipoly.c
+ *
+ *  Written by Brian Kelleher; June 1986
+ *
+ *  Draw polygons.  This routine translates the point by the
+ *  origin if pGC->miTranslate is non-zero, and calls
+ *  to the appropriate routine to actually scan convert the
+ *  polygon.
+ */
+#include "mi.h"
+
+extern gboolean miFillGeneralPoly(
+#if NeedFunctionPrototypes
+    GdkDrawable* /*dst*/,
+    GdkGC* /*pgc*/,
+    int /*count*/,
+    GdkPoint* /*ptsIn*/
+#endif
+);
+
+void
+miFillPolygon(dst, pgc, shape, mode, count, pPts)
+    GdkDrawable*               dst;
+    register GdkGC*    pgc;
+    int                        shape, mode;
+    register int       count;
+    GdkPoint*          pPts;
+{
+    if (count == 0)
+       return;
+
+    miFillGeneralPoly(dst, pgc, count, pPts);
+}
diff --git a/gdk/linux-fb/mipoly.h b/gdk/linux-fb/mipoly.h
new file mode 100644 (file)
index 0000000..d8dfe19
--- /dev/null
@@ -0,0 +1,230 @@
+/* $TOG: mipoly.h /main/6 1998/02/09 14:48:20 kaleb $ */
+/*
+
+Copyright 1987, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+*/
+
+#ifndef MIPOLY_H
+#define MIPOLY_H
+
+#include "miscanfill.h"
+
+/*
+ *     fill.h
+ *
+ *     Created by Brian Kelleher; Oct 1985
+ *
+ *     Include file for filled polygon routines.
+ *
+ *     These are the data structures needed to scan
+ *     convert regions.  Two different scan conversion
+ *     methods are available -- the even-odd method, and
+ *     the winding number method.
+ *     The even-odd rule states that a point is inside
+ *     the polygon if a ray drawn from that point in any
+ *     direction will pass through an odd number of
+ *     path segments.
+ *     By the winding number rule, a point is decided
+ *     to be inside the polygon if a ray drawn from that
+ *     point in any direction passes through a different
+ *     number of clockwise and counter-clockwise path
+ *     segments.
+ *
+ *     These data structures are adapted somewhat from
+ *     the algorithm in (Foley/Van Dam) for scan converting
+ *     polygons.
+ *     The basic algorithm is to start at the top (smallest y)
+ *     of the polygon, stepping down to the bottom of
+ *     the polygon by incrementing the y coordinate.  We
+ *     keep a list of edges which the current scanline crosses,
+ *     sorted by x.  This list is called the Active Edge Table (AET)
+ *     As we change the y-coordinate, we update each entry in 
+ *     in the active edge table to reflect the edges new xcoord.
+ *     This list must be sorted at each scanline in case
+ *     two edges intersect.
+ *     We also keep a data structure known as the Edge Table (ET),
+ *     which keeps track of all the edges which the current
+ *     scanline has not yet reached.  The ET is basically a
+ *     list of ScanLineList structures containing a list of
+ *     edges which are entered at a given scanline.  There is one
+ *     ScanLineList per scanline at which an edge is entered.
+ *     When we enter a new edge, we move it from the ET to the AET.
+ *
+ *     From the AET, we can implement the even-odd rule as in
+ *     (Foley/Van Dam).
+ *     The winding number rule is a little trickier.  We also
+ *     keep the EdgeTableEntries in the AET linked by the
+ *     nextWETE (winding EdgeTableEntry) link.  This allows
+ *     the edges to be linked just as before for updating
+ *     purposes, but only uses the edges linked by the nextWETE
+ *     link as edges representing spans of the polygon to
+ *     drawn (as with the even-odd rule).
+ */
+
+/*
+ * for the winding number rule
+ */
+#define CLOCKWISE          1
+#define COUNTERCLOCKWISE  -1 
+
+typedef struct _EdgeTableEntry {
+     int ymax;             /* ycoord at which we exit this edge. */
+     BRESINFO bres;        /* Bresenham info to run the edge     */
+     struct _EdgeTableEntry *next;       /* next in the list     */
+     struct _EdgeTableEntry *back;       /* for insertion sort   */
+     struct _EdgeTableEntry *nextWETE;   /* for winding num rule */
+     int ClockWise;        /* flag for winding number rule       */
+} EdgeTableEntry;
+
+
+typedef struct _ScanLineList{
+     int scanline;              /* the scanline represented */
+     EdgeTableEntry *edgelist;  /* header node              */
+     struct _ScanLineList *next;  /* next in the list       */
+} ScanLineList;
+
+
+typedef struct {
+     int ymax;                 /* ymax for the polygon     */
+     int ymin;                 /* ymin for the polygon     */
+     ScanLineList scanlines;   /* header node              */
+} EdgeTable;
+
+
+/*
+ * Here is a struct to help with storage allocation
+ * so we can allocate a big chunk at a time, and then take
+ * pieces from this heap when we need to.
+ */
+#define SLLSPERBLOCK 25
+
+typedef struct _ScanLineListBlock {
+     ScanLineList SLLs[SLLSPERBLOCK];
+     struct _ScanLineListBlock *next;
+} ScanLineListBlock;
+
+/*
+ * number of points to buffer before sending them off
+ * to scanlines() :  Must be an even number
+ */
+#define NUMPTSTOBUFFER 200
+
+\f
+/*
+ *
+ *     a few macros for the inner loops of the fill code where
+ *     performance considerations don't allow a procedure call.
+ *
+ *     Evaluate the given edge at the given scanline.
+ *     If the edge has expired, then we leave it and fix up
+ *     the active edge table; otherwise, we increment the
+ *     x value to be ready for the next scanline.
+ *     The winding number rule is in effect, so we must notify
+ *     the caller when the edge has been removed so he
+ *     can reorder the Winding Active Edge Table.
+ */
+#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
+   if (pAET->ymax == y) {          /* leaving this edge */ \
+      pPrevAET->next = pAET->next; \
+      pAET = pPrevAET->next; \
+      fixWAET = 1; \
+      if (pAET) \
+         pAET->back = pPrevAET; \
+   } \
+   else { \
+      BRESINCRPGONSTRUCT(pAET->bres); \
+      pPrevAET = pAET; \
+      pAET = pAET->next; \
+   } \
+}
+
+
+/*
+ *     Evaluate the given edge at the given scanline.
+ *     If the edge has expired, then we leave it and fix up
+ *     the active edge table; otherwise, we increment the
+ *     x value to be ready for the next scanline.
+ *     The even-odd rule is in effect.
+ */
+#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
+   if (pAET->ymax == y) {          /* leaving this edge */ \
+      pPrevAET->next = pAET->next; \
+      pAET = pPrevAET->next; \
+      if (pAET) \
+         pAET->back = pPrevAET; \
+   } \
+   else { \
+      BRESINCRPGONSTRUCT(pAET->bres); \
+      pPrevAET = pAET; \
+      pAET = pAET->next; \
+   } \
+}
+
+/* mipolyutil.c */
+
+extern gboolean miInsertEdgeInET(
+#if NeedFunctionPrototypes
+    EdgeTable * /*ET*/,
+    EdgeTableEntry * /*ETE*/,
+    int /*scanline*/,
+    ScanLineListBlock ** /*SLLBlock*/,
+    int * /*iSLLBlock*/
+#endif
+);
+
+extern gboolean miCreateETandAET(
+#if NeedFunctionPrototypes
+    int /*count*/,
+    GdkPoint* /*pts*/,
+    EdgeTable * /*ET*/,
+    EdgeTableEntry * /*AET*/,
+    EdgeTableEntry * /*pETEs*/,
+    ScanLineListBlock * /*pSLLBlock*/
+#endif
+);
+
+extern void miloadAET(
+#if NeedFunctionPrototypes
+    EdgeTableEntry * /*AET*/,
+    EdgeTableEntry * /*ETEs*/
+#endif
+);
+
+extern void micomputeWAET(
+#if NeedFunctionPrototypes
+    EdgeTableEntry * /*AET*/
+#endif
+);
+
+extern int miInsertionSort(
+#if NeedFunctionPrototypes
+    EdgeTableEntry * /*AET*/
+#endif
+);
+
+extern void miFreeStorage(
+#if NeedFunctionPrototypes
+    ScanLineListBlock * /*pSLLBlock*/
+#endif
+);
+
+#endif
diff --git a/gdk/linux-fb/mipolygen.c b/gdk/linux-fb/mipolygen.c
new file mode 100644 (file)
index 0000000..5068536
--- /dev/null
@@ -0,0 +1,214 @@
+/***********************************************************
+
+Copyright 1987, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+/* $TOG: mipolygen.c /main/9 1998/02/09 14:47:51 kaleb $ */
+#include "mi.h"
+#include "mipoly.h"
+
+/*
+ *
+ *     Written by Brian Kelleher;  Oct. 1985
+ *
+ *     Routine to fill a polygon.  Two fill rules are
+ *     supported: frWINDING and frEVENODD.
+ *
+ *     See fillpoly.h for a complete description of the algorithm.
+ */
+
+gboolean
+miFillGeneralPoly(dst, pgc, count, ptsIn)
+    GdkDrawable* dst;
+    GdkGC*     pgc;
+    int                count;              /* number of points        */
+    GdkPoint* ptsIn;              /* the points              */
+{
+    register EdgeTableEntry *pAET;  /* the Active Edge Table   */
+    register int y;                 /* the current scanline    */
+    register int nPts = 0;          /* number of pts in buffer */
+    register EdgeTableEntry *pWETE; /* Winding Edge Table      */
+    register ScanLineList *pSLL;    /* Current ScanLineList    */
+    register GdkRectangle* ptsOut;      /* ptr to output buffers   */
+    GdkRectangle FirstPoint[NUMPTSTOBUFFER]; /* the output buffers */
+    EdgeTableEntry *pPrevAET;       /* previous AET entry      */
+    EdgeTable ET;                   /* Edge Table header node  */
+    EdgeTableEntry AET;             /* Active ET header node   */
+    EdgeTableEntry *pETEs;          /* Edge Table Entries buff */
+    ScanLineListBlock SLLBlock;     /* header for ScanLineList */
+    int fixWAET = 0;
+
+    if (count < 3)
+       return(TRUE);
+
+    if(!(pETEs = (EdgeTableEntry *)
+        ALLOCATE_LOCAL(sizeof(EdgeTableEntry) * count)))
+       return(FALSE);
+    ptsOut = FirstPoint;
+    if (!miCreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock))
+    {
+       DEALLOCATE_LOCAL(pETEs);
+       return(FALSE);
+    }
+    pSLL = ET.scanlines.next;
+
+    if (0 /* pgc->fillRule == EvenOddRule */)
+    {
+        /*
+         *  for each scanline
+         */
+        for (y = ET.ymin; y < ET.ymax; y++) 
+        {
+            /*
+             *  Add a new edge to the active edge table when we
+             *  get to the next edge.
+             */
+            if (pSLL && y == pSLL->scanline) 
+            {
+                miloadAET(&AET, pSLL->edgelist);
+                pSLL = pSLL->next;
+            }
+            pPrevAET = &AET;
+            pAET = AET.next;
+
+            /*
+             *  for each active edge
+             */
+            while (pAET) 
+            {
+                ptsOut->x = pAET->bres.minor;
+               ptsOut->width = pAET->next->bres.minor - pAET->bres.minor;
+               ptsOut->height = 1;
+               ptsOut++->y = y;
+                nPts++;
+
+                /*
+                 *  send out the buffer when its full
+                 */
+                if (nPts == NUMPTSTOBUFFER) 
+               {
+                 gdk_fb_fill_spans(dst, pgc, FirstPoint, nPts);
+                 ptsOut = FirstPoint;
+                 nPts = 0;
+                }
+                EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
+                EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
+            }
+            miInsertionSort(&AET);
+        }
+    }
+    else      /* default to WindingNumber */
+    {
+        /*
+         *  for each scanline
+         */
+        for (y = ET.ymin; y < ET.ymax; y++) 
+        {
+            /*
+             *  Add a new edge to the active edge table when we
+             *  get to the next edge.
+             */
+            if (pSLL && y == pSLL->scanline) 
+            {
+                miloadAET(&AET, pSLL->edgelist);
+                micomputeWAET(&AET);
+                pSLL = pSLL->next;
+            }
+            pPrevAET = &AET;
+            pAET = AET.next;
+            pWETE = pAET;
+
+            /*
+             *  for each active edge
+             */
+            while (pAET) 
+            {
+                /*
+                 *  if the next edge in the active edge table is
+                 *  also the next edge in the winding active edge
+                 *  table.
+                 */
+                if (pWETE == pAET) 
+                {
+                    ptsOut->x = pAET->bres.minor;
+                   ptsOut->width = pAET->nextWETE->bres.minor - pAET->bres.minor;
+                   ptsOut->height = 1;
+                   ptsOut++->y = y;
+                    nPts++;
+
+                    /*
+                     *  send out the buffer
+                     */
+                    if (nPts == NUMPTSTOBUFFER) 
+                    {
+                     gdk_fb_fill_spans(dst, pgc, FirstPoint, nPts);
+                     ptsOut = FirstPoint;
+                     nPts = 0;
+                    }
+
+                    pWETE = pWETE->nextWETE;
+                    while (pWETE != pAET)
+                        EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
+                    pWETE = pWETE->nextWETE;
+                }
+                EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
+            }
+
+            /*
+             *  reevaluate the Winding active edge table if we
+             *  just had to resort it or if we just exited an edge.
+             */
+            if (miInsertionSort(&AET) || fixWAET) 
+            {
+                micomputeWAET(&AET);
+                fixWAET = 0;
+            }
+        }
+    }
+
+    /*
+     *     Get any spans that we missed by buffering
+     */
+    if(nPts > 0)
+      gdk_fb_fill_spans(dst, pgc, FirstPoint, nPts);
+    DEALLOCATE_LOCAL(pETEs);
+    miFreeStorage(SLLBlock.next);
+    return(TRUE);
+}
diff --git a/gdk/linux-fb/mipolyutil.c b/gdk/linux-fb/mipolyutil.c
new file mode 100644 (file)
index 0000000..3cf3f9f
--- /dev/null
@@ -0,0 +1,392 @@
+/* $XFree86: xc/programs/Xserver/mi/mipolyutil.c,v 1.7 1998/10/04 09:39:31 dawes Exp $ */
+/***********************************************************
+
+Copyright 1987, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+/* $TOG: mipolyutil.c /main/6 1998/02/09 14:48:12 kaleb $ */
+#include <limits.h>
+#include "mi.h"
+#include "miscanfill.h"
+#include "mipoly.h"
+
+/*
+ *     fillUtils.c
+ *
+ *     Written by Brian Kelleher;  Oct. 1985
+ *
+ *     This module contains all of the utility functions
+ *     needed to scan convert a polygon.
+ *
+ */
+\f
+/*
+ *     InsertEdgeInET
+ *
+ *     Insert the given edge into the edge table.
+ *     First we must find the correct bucket in the
+ *     Edge table, then find the right slot in the
+ *     bucket.  Finally, we can insert it.
+ *
+ */
+gboolean
+miInsertEdgeInET(ET, ETE, scanline, SLLBlock, iSLLBlock)
+    EdgeTable *ET;
+    EdgeTableEntry *ETE;
+    int scanline;
+    ScanLineListBlock **SLLBlock;
+    int *iSLLBlock;
+{
+    register EdgeTableEntry *start, *prev;
+    register ScanLineList *pSLL, *pPrevSLL;
+    ScanLineListBlock *tmpSLLBlock;
+
+    /*
+     * find the right bucket to put the edge into
+     */
+    pPrevSLL = &ET->scanlines;
+    pSLL = pPrevSLL->next;
+    while (pSLL && (pSLL->scanline < scanline)) 
+    {
+        pPrevSLL = pSLL;
+        pSLL = pSLL->next;
+    }
+
+    /*
+     * reassign pSLL (pointer to ScanLineList) if necessary
+     */
+    if ((!pSLL) || (pSLL->scanline > scanline)) 
+    {
+        if (*iSLLBlock > SLLSPERBLOCK-1) 
+        {
+            tmpSLLBlock = 
+                 (ScanLineListBlock *)g_malloc(sizeof(ScanLineListBlock));
+           if (!tmpSLLBlock)
+               return FALSE;
+            (*SLLBlock)->next = tmpSLLBlock;
+            tmpSLLBlock->next = (ScanLineListBlock *)NULL;
+            *SLLBlock = tmpSLLBlock;
+            *iSLLBlock = 0;
+        }
+        pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
+
+        pSLL->next = pPrevSLL->next;
+        pSLL->edgelist = (EdgeTableEntry *)NULL;
+        pPrevSLL->next = pSLL;
+    }
+    pSLL->scanline = scanline;
+
+    /*
+     * now insert the edge in the right bucket
+     */
+    prev = (EdgeTableEntry *)NULL;
+    start = pSLL->edgelist;
+    while (start && (start->bres.minor < ETE->bres.minor)) 
+    {
+        prev = start;
+        start = start->next;
+    }
+    ETE->next = start;
+
+    if (prev)
+        prev->next = ETE;
+    else
+        pSLL->edgelist = ETE;
+    return TRUE;
+}
+\f
+/*
+ *     CreateEdgeTable
+ *
+ *     This routine creates the edge table for
+ *     scan converting polygons. 
+ *     The Edge Table (ET) looks like:
+ *
+ *    EdgeTable
+ *     --------
+ *    |  ymax  |        ScanLineLists
+ *    |scanline|-->------------>-------------->...
+ *     --------   |scanline|   |scanline|
+ *                |edgelist|   |edgelist|
+ *                ---------    ---------
+ *                    |             |
+ *                    |             |
+ *                    V             V
+ *              list of ETEs   list of ETEs
+ *
+ *     where ETE is an EdgeTableEntry data structure,
+ *     and there is one ScanLineList per scanline at
+ *     which an edge is initially entered.
+ *
+ */
+
+gboolean
+miCreateETandAET(count, pts, ET, AET, pETEs, pSLLBlock)
+    register int count;
+    register GdkPoint* pts;
+    EdgeTable *ET;
+    EdgeTableEntry *AET;
+    register EdgeTableEntry *pETEs;
+    ScanLineListBlock   *pSLLBlock;
+{
+    register GdkPoint* top, *bottom;
+    register GdkPoint* PrevPt, *CurrPt;
+    int iSLLBlock = 0;
+
+    int dy;
+
+    if (count < 2)  return TRUE;
+
+    /*
+     *  initialize the Active Edge Table
+     */
+    AET->next = (EdgeTableEntry *)NULL;
+    AET->back = (EdgeTableEntry *)NULL;
+    AET->nextWETE = (EdgeTableEntry *)NULL;
+    AET->bres.minor = INT_MIN;
+
+    /*
+     *  initialize the Edge Table.
+     */
+    ET->scanlines.next = (ScanLineList *)NULL;
+    ET->ymax = INT_MIN;
+    ET->ymin = INT_MAX;
+    pSLLBlock->next = (ScanLineListBlock *)NULL;
+
+    PrevPt = &pts[count-1];
+
+    /*
+     *  for each vertex in the array of points.
+     *  In this loop we are dealing with two vertices at
+     *  a time -- these make up one edge of the polygon.
+     */
+    while (count--) 
+    {
+        CurrPt = pts++;
+
+        /*
+         *  find out which point is above and which is below.
+         */
+        if (PrevPt->y > CurrPt->y) 
+        {
+            bottom = PrevPt, top = CurrPt;
+            pETEs->ClockWise = 0;
+        }
+        else 
+        {
+            bottom = CurrPt, top = PrevPt;
+            pETEs->ClockWise = 1;
+        }
+
+        /*
+         * don't add horizontal edges to the Edge table.
+         */
+        if (bottom->y != top->y) 
+        {
+            pETEs->ymax = bottom->y-1;  /* -1 so we don't get last scanline */
+
+            /*
+             *  initialize integer edge algorithm
+             */
+            dy = bottom->y - top->y;
+            BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
+
+            if (!miInsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock))
+           {
+               miFreeStorage(pSLLBlock->next);
+               return FALSE;
+           }
+
+            ET->ymax = MAX(ET->ymax, PrevPt->y);
+            ET->ymin = MIN(ET->ymin, PrevPt->y);
+            pETEs++;
+        }
+
+        PrevPt = CurrPt;
+    }
+    return TRUE;
+}
+\f
+/*
+ *     loadAET
+ *
+ *     This routine moves EdgeTableEntries from the
+ *     EdgeTable into the Active Edge Table,
+ *     leaving them sorted by smaller x coordinate.
+ *
+ */
+
+void
+miloadAET(AET, ETEs)
+    register EdgeTableEntry *AET, *ETEs;
+{
+    register EdgeTableEntry *pPrevAET;
+    register EdgeTableEntry *tmp;
+
+    pPrevAET = AET;
+    AET = AET->next;
+    while (ETEs) 
+    {
+        while (AET && (AET->bres.minor < ETEs->bres.minor)) 
+        {
+            pPrevAET = AET;
+            AET = AET->next;
+        }
+        tmp = ETEs->next;
+        ETEs->next = AET;
+        if (AET)
+            AET->back = ETEs;
+        ETEs->back = pPrevAET;
+        pPrevAET->next = ETEs;
+        pPrevAET = ETEs;
+
+        ETEs = tmp;
+    }
+}
+\f
+/*
+ *     computeWAET
+ *
+ *     This routine links the AET by the
+ *     nextWETE (winding EdgeTableEntry) link for
+ *     use by the winding number rule.  The final 
+ *     Active Edge Table (AET) might look something
+ *     like:
+ *
+ *     AET
+ *     ----------  ---------   ---------
+ *     |ymax    |  |ymax    |  |ymax    | 
+ *     | ...    |  |...     |  |...     |
+ *     |next    |->|next    |->|next    |->...
+ *     |nextWETE|  |nextWETE|  |nextWETE|
+ *     ---------   ---------   ^--------
+ *         |                   |       |
+ *         V------------------->       V---> ...
+ *
+ */
+void
+micomputeWAET(AET)
+    register EdgeTableEntry *AET;
+{
+    register EdgeTableEntry *pWETE;
+    register int inside = 1;
+    register int isInside = 0;
+
+    AET->nextWETE = (EdgeTableEntry *)NULL;
+    pWETE = AET;
+    AET = AET->next;
+    while (AET) 
+    {
+        if (AET->ClockWise)
+            isInside++;
+        else
+            isInside--;
+
+        if ((!inside && !isInside) ||
+            ( inside &&  isInside)) 
+        {
+            pWETE->nextWETE = AET;
+            pWETE = AET;
+            inside = !inside;
+        }
+        AET = AET->next;
+    }
+    pWETE->nextWETE = (EdgeTableEntry *)NULL;
+}
+\f
+/*
+ *     InsertionSort
+ *
+ *     Just a simple insertion sort using
+ *     pointers and back pointers to sort the Active
+ *     Edge Table.
+ *
+ */
+
+int
+miInsertionSort(AET)
+    register EdgeTableEntry *AET;
+{
+    register EdgeTableEntry *pETEchase;
+    register EdgeTableEntry *pETEinsert;
+    register EdgeTableEntry *pETEchaseBackTMP;
+    register int changed = 0;
+
+    AET = AET->next;
+    while (AET) 
+    {
+        pETEinsert = AET;
+        pETEchase = AET;
+        while (pETEchase->back->bres.minor > AET->bres.minor)
+            pETEchase = pETEchase->back;
+
+        AET = AET->next;
+        if (pETEchase != pETEinsert) 
+        {
+            pETEchaseBackTMP = pETEchase->back;
+            pETEinsert->back->next = AET;
+            if (AET)
+                AET->back = pETEinsert->back;
+            pETEinsert->next = pETEchase;
+            pETEchase->back->next = pETEinsert;
+            pETEchase->back = pETEinsert;
+            pETEinsert->back = pETEchaseBackTMP;
+            changed = 1;
+        }
+    }
+    return(changed);
+}
+\f
+/*
+ *     Clean up our act.
+ */
+void
+miFreeStorage(pSLLBlock)
+    register ScanLineListBlock   *pSLLBlock;
+{
+    register ScanLineListBlock   *tmpSLLBlock;
+
+    while (pSLLBlock) 
+    {
+        tmpSLLBlock = pSLLBlock->next;
+        g_free(pSLLBlock);
+        pSLLBlock = tmpSLLBlock;
+    }
+}
diff --git a/gdk/linux-fb/miscanfill.h b/gdk/linux-fb/miscanfill.h
new file mode 100644 (file)
index 0000000..c9e1f50
--- /dev/null
@@ -0,0 +1,139 @@
+/* $TOG: miscanfill.h /main/6 1998/02/09 14:48:35 kaleb $ */
+/*
+
+Copyright 1987, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+*/
+
+#ifndef SCANFILLINCLUDED
+#define SCANFILLINCLUDED
+/*
+ *     scanfill.h
+ *
+ *     Written by Brian Kelleher; Jan 1985
+ *
+ *     This file contains a few macros to help track
+ *     the edge of a filled object.  The object is assumed
+ *     to be filled in scanline order, and thus the
+ *     algorithm used is an extension of Bresenham's line
+ *     drawing algorithm which assumes that y is always the
+ *     major axis.
+ *     Since these pieces of code are the same for any filled shape,
+ *     it is more convenient to gather the library in one
+ *     place, but since these pieces of code are also in
+ *     the inner loops of output primitives, procedure call
+ *     overhead is out of the question.
+ *     See the author for a derivation if needed.
+ */
+\f
+
+/*
+ *  In scan converting polygons, we want to choose those pixels
+ *  which are inside the polygon.  Thus, we add .5 to the starting
+ *  x coordinate for both left and right edges.  Now we choose the
+ *  first pixel which is inside the pgon for the left edge and the
+ *  first pixel which is outside the pgon for the right edge.
+ *  Draw the left pixel, but not the right.
+ *
+ *  How to add .5 to the starting x coordinate:
+ *      If the edge is moving to the right, then subtract dy from the
+ *  error term from the general form of the algorithm.
+ *      If the edge is moving to the left, then add dy to the error term.
+ *
+ *  The reason for the difference between edges moving to the left
+ *  and edges moving to the right is simple:  If an edge is moving
+ *  to the right, then we want the algorithm to flip immediately.
+ *  If it is moving to the left, then we don't want it to flip until
+ *  we traverse an entire pixel.
+ */
+#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
+    int dx;      /* local storage */ \
+\
+    /* \
+     *  if the edge is horizontal, then it is ignored \
+     *  and assumed not to be processed.  Otherwise, do this stuff. \
+     */ \
+    if ((dy) != 0) { \
+        xStart = (x1); \
+        dx = (x2) - xStart; \
+        if (dx < 0) { \
+            m = dx / (dy); \
+            m1 = m - 1; \
+            incr1 = -2 * dx + 2 * (dy) * m1; \
+            incr2 = -2 * dx + 2 * (dy) * m; \
+            d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
+        } else { \
+            m = dx / (dy); \
+            m1 = m + 1; \
+            incr1 = 2 * dx - 2 * (dy) * m1; \
+            incr2 = 2 * dx - 2 * (dy) * m; \
+            d = -2 * m * (dy) + 2 * dx; \
+        } \
+    } \
+}
+\f
+#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
+    if (m1 > 0) { \
+        if (d > 0) { \
+            minval += m1; \
+            d += incr1; \
+        } \
+        else { \
+            minval += m; \
+            d += incr2; \
+        } \
+    } else {\
+        if (d >= 0) { \
+            minval += m1; \
+            d += incr1; \
+        } \
+        else { \
+            minval += m; \
+            d += incr2; \
+        } \
+    } \
+}
+
+\f
+/*
+ *     This structure contains all of the information needed
+ *     to run the bresenham algorithm.
+ *     The variables may be hardcoded into the declarations
+ *     instead of using this structure to make use of
+ *     register declarations.
+ */
+typedef struct {
+    int minor;         /* minor axis        */
+    int d;           /* decision variable */
+    int m, m1;       /* slope and slope+1 */
+    int incr1, incr2; /* error increments */
+} BRESINFO;
+
+
+#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
+       BRESINITPGON(dmaj, min1, min2, bres.minor, bres.d, \
+                     bres.m, bres.m1, bres.incr1, bres.incr2)
+
+#define BRESINCRPGONSTRUCT(bres) \
+        BRESINCRPGON(bres.d, bres.minor, bres.m, bres.m1, bres.incr1, bres.incr2)
+
+
+#endif
diff --git a/gdk/linux-fb/mispans.c b/gdk/linux-fb/mispans.c
new file mode 100644 (file)
index 0000000..a8638dd
--- /dev/null
@@ -0,0 +1,507 @@
+/* $XFree86: xc/programs/Xserver/mi/mispans.c,v 3.1 1998/10/04 09:39:33 dawes Exp $ */
+/***********************************************************
+
+Copyright 1989, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/* $TOG: mispans.c /main/7 1998/02/09 14:48:44 kaleb $ */
+
+#include "mi.h"
+#include "mispans.h"
+#include <string.h>            /* for memmove */
+
+/*
+
+These routines maintain lists of Spans, in order to implement the
+``touch-each-pixel-once'' rules of wide lines and arcs.
+
+Written by Joel McCormack, Summer 1989.
+
+*/
+
+
+void miInitSpanGroup(spanGroup)
+    SpanGroup *spanGroup;
+{
+    spanGroup->size = 0;
+    spanGroup->count = 0;
+    spanGroup->group = NULL;
+    spanGroup->ymin = SHRT_MAX;
+    spanGroup->ymax = SHRT_MIN;
+} /* InitSpanGroup */
+
+#define YMIN(spans) (spans->points[0].y)
+#define YMAX(spans)  (spans->points[spans->count-1].y)
+
+void miSubtractSpans (spanGroup, sub)
+    SpanGroup  *spanGroup;
+    Spans      *sub;
+{
+    int                i, subCount, spansCount;
+    int                ymin, ymax, xmin, xmax;
+    Spans      *spans;
+    GdkRectangle*      subPt, *spansPt;
+    int                extra;
+
+    ymin = YMIN(sub);
+    ymax = YMAX(sub);
+    spans = spanGroup->group;
+    for (i = spanGroup->count; i; i--, spans++) {
+       if (YMIN(spans) <= ymax && ymin <= YMAX(spans)) {
+           subCount = sub->count;
+           subPt = sub->points;
+           spansCount = spans->count;
+           spansPt = spans->points;
+           extra = 0;
+           for (;;)
+           {
+               while (spansCount && spansPt->y < subPt->y)
+               {
+                   spansPt++; spansCount--;
+               }
+               if (!spansCount)
+                   break;
+               while (subCount && subPt->y < spansPt->y)
+               {
+                   subPt++; subCount--;
+               }
+               if (!subCount)
+                   break;
+               if (subPt->y == spansPt->y)
+               {
+                   xmin = subPt->x;
+                   xmax = xmin + subPt->width;
+                   if (xmin >= (spansPt->x + spansPt->width) || spansPt->x >= xmax)
+                   {
+                       ;
+                   }
+                   else if (xmin <= spansPt->x)
+                   {
+                       if (xmax >= (spansPt->x + spansPt->width))
+                       {
+                           g_memmove (spansPt, spansPt + 1, sizeof *spansPt * (spansCount - 1));
+                           spansPt--;
+                           spans->count--;
+                           extra++;
+                       }
+                       else 
+                       {
+                         spansPt->width -= xmax - spansPt->x;
+                         spansPt->x = xmax;
+                       }
+                   }
+                   else
+                   {
+                       if (xmax >= (spansPt->x + spansPt->width))
+                       {
+                         spansPt->width = xmin - spansPt->x;
+                       }
+                       else
+                       {
+                           if (!extra) {
+                               GdkRectangle* newPt;
+
+#define EXTRA 8
+                               newPt = (GdkRectangle*) g_realloc (spans->points, (spans->count + EXTRA) * sizeof (GdkRectangle));
+                               if (!newPt)
+                                   break;
+                               spansPt = newPt + (spansPt - spans->points);
+                               spans->points = newPt;
+                               extra = EXTRA;
+                           }
+                           g_memmove (spansPt + 1, spansPt, sizeof *spansPt * (spansCount));
+                           spans->count++;
+                           extra--;
+                           spansPt->width = xmin - spansPt->x;
+                           spansPt->height = 1;
+                           spansPt++;
+                           spansPt->width -= xmax - spansPt->x;
+                           spansPt->height = 1;
+                           spansPt->x = xmax;
+                       }
+                   }
+               }
+               spansPt++; spansCount--;
+           }
+       }
+    }
+}
+    
+void miAppendSpans(spanGroup, otherGroup, spans)
+    SpanGroup   *spanGroup;
+    SpanGroup  *otherGroup;
+    Spans       *spans;
+{
+    register    int ymin, ymax;
+    register    int spansCount;
+
+    spansCount = spans->count;
+    if (spansCount > 0) {
+       if (spanGroup->size == spanGroup->count) {
+           spanGroup->size = (spanGroup->size + 8) * 2;
+           spanGroup->group = (Spans *)
+               g_realloc(spanGroup->group, sizeof(Spans) * spanGroup->size);
+        }
+
+       spanGroup->group[spanGroup->count] = *spans;
+       (spanGroup->count)++;
+       ymin = spans->points[0].y;
+       if (ymin < spanGroup->ymin) spanGroup->ymin = ymin;
+       ymax = spans->points[spansCount - 1].y;
+       if (ymax > spanGroup->ymax) spanGroup->ymax = ymax;
+       if (otherGroup &&
+           otherGroup->ymin < ymax &&
+           ymin < otherGroup->ymax)
+       {
+           miSubtractSpans (otherGroup, spans);
+       }
+    }
+    else
+    {
+       g_free (spans->points);
+    }
+} /* AppendSpans */
+
+void miFreeSpanGroup(spanGroup)
+    SpanGroup   *spanGroup;
+{
+    if (spanGroup->group != NULL) g_free(spanGroup->group);
+}
+
+static void QuickSortSpansX(points, numSpans)
+    register GdkRectangle    points[];
+    register int           numSpans;
+{
+    register int           x;
+    register int           i, j, m;
+    register GdkRectangle*    r;
+
+/* Always called with numSpans > 1 */
+/* Sorts only by x, as all y should be the same */
+
+#define ExchangeSpans(a, b)                                \
+{                                                          \
+    GdkRectangle     tpt;                                  \
+                                                           \
+    tpt = points[a]; points[a] = points[b]; points[b] = tpt;    \
+}
+
+    do {
+       if (numSpans < 9) {
+           /* Do insertion sort */
+           register int xprev;
+
+           xprev = points[0].x;
+           i = 1;
+           do { /* while i != numSpans */
+               x = points[i].x;
+               if (xprev > x) {
+                   /* points[i] is out of order.  Move into proper location. */
+                   GdkRectangle tpt;
+                   int     k;
+
+                   for (j = 0; x >= points[j].x; j++) {}
+                   tpt = points[i];
+                   for (k = i; k != j; k--) {
+                       points[k] = points[k-1];
+                   }
+                   points[j] = tpt;
+                   x = points[i].x;
+               } /* if out of order */
+               xprev = x;
+               i++;
+           } while (i != numSpans);
+           return;
+       }
+
+       /* Choose partition element, stick in location 0 */
+       m = numSpans / 2;
+       if (points[m].x > points[0].x)          ExchangeSpans(m, 0);
+       if (points[m].x > points[numSpans-1].x) ExchangeSpans(m, numSpans-1);
+       if (points[m].x > points[0].x)          ExchangeSpans(m, 0);
+       x = points[0].x;
+
+        /* Partition array */
+        i = 0;
+        j = numSpans;
+        do {
+           r = &(points[i]);
+           do {
+               r++;
+               i++;
+            } while (i != numSpans && r->x < x);
+           r = &(points[j]);
+           do {
+               r--;
+               j--;
+            } while (x < r->x);
+            if (i < j) ExchangeSpans(i, j);
+        } while (i < j);
+
+        /* Move partition element back to middle */
+        ExchangeSpans(0, j);
+
+       /* Recurse */
+        if (numSpans-j-1 > 1)
+           QuickSortSpansX(&points[j+1], numSpans-j-1);
+        numSpans = j;
+    } while (numSpans > 1);
+} /* QuickSortSpans */
+
+
+static int UniquifySpansX(spans, newPoints, newWidths)
+    Spans                  *spans;
+    register GdkRectangle    *newPoints;
+{
+    register int newx1, newx2, oldpt, i, y;
+    GdkRectangle    *oldPoints, *startNewPoints = newPoints;
+
+/* Always called with numSpans > 1 */
+/* Uniquify the spans, and stash them into newPoints and newWidths.  Return the
+   number of unique spans. */
+
+
+    oldPoints = spans->points;
+
+    y = oldPoints->y;
+    newx1 = oldPoints->x;
+    newx2 = newx1 + oldPoints->width;
+
+    for (i = spans->count-1; i != 0; i--) {
+       oldPoints++;
+       oldpt = oldPoints->x;
+       if (oldpt > newx2) {
+           /* Write current span, start a new one */
+           newPoints->x = newx1;
+           newPoints->y = y;
+           newPoints->width = newx2 - newx1;
+           newPoints->height = 1;
+           newPoints++;
+           newx1 = oldpt;
+           newx2 = oldpt + oldPoints->width;
+       } else {
+           /* extend current span, if old extends beyond new */
+           oldpt = oldpt + oldPoints->width;
+           if (oldpt > newx2) newx2 = oldpt;
+       }
+    } /* for */
+
+    /* Write final span */
+    newPoints->x = newx1;
+    newPoints->width = newx2 - newx1;
+    newPoints->height = 1;
+    newPoints->y = y;
+
+    return (newPoints - startNewPoints) + 1;
+} /* UniquifySpansX */
+
+void
+miDisposeSpanGroup (spanGroup)
+    SpanGroup  *spanGroup;
+{
+    int            i;
+    Spans   *spans;
+
+    for (i = 0; i < spanGroup->count; i++)
+    {
+       spans = spanGroup->group + i;
+       g_free (spans->points);
+    }
+}
+
+void miFillUniqueSpanGroup(pDraw, pGC, spanGroup)
+    GdkDrawable* pDraw;
+    GdkGC*     pGC;
+    SpanGroup   *spanGroup;
+{
+    register int    i;
+    register Spans  *spans;
+    register Spans  *yspans;
+    register int    *ysizes;
+    register int    ymin, ylength;
+
+    /* Outgoing spans for one big call to FillSpans */
+    register GdkRectangle*    points;
+    register int           count;
+
+    if (spanGroup->count == 0) return;
+
+    if (spanGroup->count == 1) {
+       /* Already should be sorted, unique */
+       spans = spanGroup->group;
+       gdk_fb_fill_spans(pDraw, pGC, spans->points, spans->count);
+       g_free(spans->points);
+    }
+    else
+    {
+       /* Yuck.  Gross.  Radix sort into y buckets, then sort x and uniquify */
+       /* This seems to be the fastest thing to do.  I've tried sorting on
+          both x and y at the same time rather than creating into all those
+          y buckets, but it was somewhat slower. */
+
+       ymin    = spanGroup->ymin;
+       ylength = spanGroup->ymax - ymin + 1;
+
+       /* Allocate Spans for y buckets */
+       yspans = (Spans *) g_malloc(ylength * sizeof(Spans));
+       ysizes = (int *) g_malloc(ylength * sizeof (int));
+
+       if (!yspans || !ysizes)
+       {
+           if (yspans)
+               g_free (yspans);
+           if (ysizes)
+               g_free (ysizes);
+           miDisposeSpanGroup (spanGroup);
+           return;
+       }
+       
+       for (i = 0; i != ylength; i++) {
+           ysizes[i]        = 0;
+           yspans[i].count  = 0;
+           yspans[i].points = NULL;
+       }
+
+       /* Go through every single span and put it into the correct bucket */
+       count = 0;
+       for (i = 0, spans = spanGroup->group;
+               i != spanGroup->count;
+               i++, spans++) {
+           int         index;
+           int         j;
+
+           for (j = 0, points = spans->points;
+                j != spans->count;
+                j++, points++) {
+               index = points->y - ymin;
+               if (index >= 0 && index < ylength) {
+                   Spans *newspans = &(yspans[index]);
+                   if (newspans->count == ysizes[index]) {
+                       GdkRectangle* newpoints;
+                       ysizes[index] = (ysizes[index] + 8) * 2;
+                       newpoints = (GdkRectangle*) g_realloc(
+                           newspans->points,
+                           ysizes[index] * sizeof(GdkRectangle));
+                       if (!newpoints)
+                       {
+                           int i;
+
+                           for (i = 0; i < ylength; i++)
+                           {
+                               g_free (yspans[i].points);
+                           }
+                           g_free (yspans);
+                           g_free (ysizes);
+                           miDisposeSpanGroup (spanGroup);
+                           return;
+                       }
+                       newspans->points = newpoints;
+                   }
+                   newspans->points[newspans->count] = *points;
+                   (newspans->count)++;
+               } /* if y value of span in range */
+           } /* for j through spans */
+           count += spans->count;
+           g_free(spans->points);
+           spans->points = NULL;
+       } /* for i thorough Spans */
+
+       /* Now sort by x and uniquify each bucket into the final array */
+       points = (GdkRectangle*) g_malloc(count * sizeof(GdkRectangle));
+       if (!points)
+       {
+           int i;
+
+           for (i = 0; i < ylength; i++)
+           {
+               g_free (yspans[i].points);
+           }
+           g_free (yspans);
+           g_free (ysizes);
+           if (points)
+               g_free (points);
+           return;
+       }
+       count = 0;
+       for (i = 0; i != ylength; i++) {
+           int ycount = yspans[i].count;
+           if (ycount > 0) {
+               if (ycount > 1) {
+                   QuickSortSpansX(yspans[i].points, ycount);
+                   count += UniquifySpansX
+                       (&(yspans[i]), &(points[count]));
+               } else {
+                   points[count] = yspans[i].points[0];
+                   count++;
+               }
+               g_free(yspans[i].points);
+           }
+       }
+
+       gdk_fb_fill_spans(pDraw, pGC, points, count);
+       g_free(points);
+       g_free(yspans);
+       g_free(ysizes);         /* use (DE)ALLOCATE_LOCAL for these? */
+    }
+
+    spanGroup->count = 0;
+    spanGroup->ymin = SHRT_MAX;
+    spanGroup->ymax = SHRT_MIN;
+}
+
+
+void miFillSpanGroup(pDraw, pGC, spanGroup)
+    GdkDrawable* pDraw;
+    GdkGC*     pGC;
+    SpanGroup   *spanGroup;
+{
+    register int    i;
+    register Spans  *spans;
+
+    for (i = 0, spans = spanGroup->group; i != spanGroup->count; i++, spans++) {
+      gdk_fb_fill_spans(pDraw, pGC, spans->points, spans->count);
+      g_free(spans->points);
+    }
+
+    spanGroup->count = 0;
+    spanGroup->ymin = SHRT_MAX;
+    spanGroup->ymax = SHRT_MIN;
+} /* FillSpanGroup */
diff --git a/gdk/linux-fb/mispans.h b/gdk/linux-fb/mispans.h
new file mode 100644 (file)
index 0000000..4724e20
--- /dev/null
@@ -0,0 +1,127 @@
+/***********************************************************
+
+Copyright 1989, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/* $TOG: mispans.h /main/5 1998/02/09 14:48:48 kaleb $ */
+
+typedef struct {
+    int         count;         /* number of spans                  */
+    GdkRectangle* points;              /* pointer to list of start points  */
+} Spans;
+
+typedef struct {
+    int                size;           /* Total number of *Spans allocated     */
+    int                count;          /* Number of *Spans actually in group   */
+    Spans       *group;                /* List of Spans                        */
+    int                ymin, ymax;     /* Min, max y values encountered        */
+} SpanGroup;
+
+/* Initialize SpanGroup.  MUST BE DONE before use. */
+extern void miInitSpanGroup(
+#if NeedFunctionPrototypes
+    SpanGroup * /*spanGroup*/
+#endif
+);
+
+/* Add a Spans to a SpanGroup. The spans MUST BE in y-sorted order */
+extern void miAppendSpans(
+#if NeedFunctionPrototypes
+    SpanGroup * /*spanGroup*/,
+    SpanGroup * /*otherGroup*/,
+    Spans * /*spans*/
+#endif
+);
+
+/* Paint a span group, possibly with some overlap */
+extern void miFillSpanGroup(
+#if NeedFunctionPrototypes
+    GdkDrawable* /*pDraw*/,
+    GdkGC* /*pGC*/,
+    SpanGroup * /*spanGroup*/
+#endif
+);
+
+/* Paint a span group, insuring that each pixel is painted at most once */
+extern void miFillUniqueSpanGroup(
+#if NeedFunctionPrototypes
+    GdkDrawable* /*pDraw*/,
+    GdkGC* /*pGC*/,
+    SpanGroup * /*spanGroup*/
+#endif
+);
+
+/* Free up data in a span group.  MUST BE DONE or you'll suffer memory leaks */
+extern void miFreeSpanGroup(
+#if NeedFunctionPrototypes
+    SpanGroup * /*spanGroup*/
+#endif
+);
+
+extern void miSubtractSpans(
+#if NeedFunctionPrototypes
+    SpanGroup * /*spanGroup*/,
+    Spans * /*sub*/
+#endif
+);
+
+extern void miDisposeSpanGroup(
+#if NeedFunctionPrototypes
+    SpanGroup * /*spanGroup*/
+#endif
+);
+
+extern int miClipSpans(
+#if NeedFunctionPrototypes
+    GdkRegion* /*prgnDst*/,
+    GdkPoint* /*ppt*/,
+    int * /*pwidth*/,
+    int /*nspans*/,
+    GdkPoint* /*pptNew*/,
+    int * /*pwidthNew*/,
+    int /*fSorted*/
+#endif
+);
+
+/* Rops which must use span groups */
+#define miSpansCarefulRop(rop) (((rop) & 0xc) == 0x8 || ((rop) & 0x3) == 0x2)
+#define miSpansEasyRop(rop)    (!miSpansCarefulRop(rop))
+
diff --git a/gdk/linux-fb/mistruct.h b/gdk/linux-fb/mistruct.h
new file mode 100644 (file)
index 0000000..ff5d738
--- /dev/null
@@ -0,0 +1,58 @@
+/* $TOG: mistruct.h /main/4 1998/02/09 14:49:07 kaleb $ */
+/***********************************************************
+
+Copyright 1987, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+#ifndef MISTRUCT_H
+#define MISTRUCT_H
+
+#include "mitypes.h"
+
+/* information about dashes */
+typedef struct _miDash {
+    GdkPoint   pt;
+    int                e1, e2; /* keep these, so we don't have to do it again */
+    int                e;      /* bresenham error term for this point on line */
+    int                which;
+    int                newLine;/* 0 if part of same original line as previous dash */
+} miDashRec;
+
+#endif /* MISTRUCT_H */
diff --git a/gdk/linux-fb/mitypes.h b/gdk/linux-fb/mitypes.h
new file mode 100644 (file)
index 0000000..997ec8a
--- /dev/null
@@ -0,0 +1,486 @@
+#ifndef MITYPES_H
+#define MITYPES_H
+
+#include <alloca.h>
+
+#define ALLOCATE_LOCAL(size) alloca((int)(size))
+#define DEALLOCATE_LOCAL(ptr)  /* as nothing */
+
+#include <stdlib.h>
+#include <glib.h>
+#include <gdk/gdk.h>
+#include <gdkfb.h>
+#include <gdkprivate-fb.h>
+#include <gdkregion-generic.h>
+
+typedef struct _miDash *miDashPtr;
+
+#define CT_NONE                 0
+#define CT_PIXMAP               1
+#define CT_REGION               2
+#define CT_UNSORTED             6
+#define CT_YSORTED              10
+#define CT_YXSORTED             14
+#define CT_YXBANDED             18
+
+struct _GdkGCFuncs {
+  void        (* ValidateGC)(
+                            GdkGC* /*pGC*/,
+                            unsigned long /*stateChanges*/,
+                            GdkDrawable* /*pDrawable*/
+                            );
+
+  void        (* ChangeGC)(
+                          GdkGC* /*pGC*/,
+                          unsigned long /*mask*/
+                          );
+
+  void        (* CopyGC)(
+                        GdkGC* /*pGCSrc*/,
+                        unsigned long /*mask*/,
+                        GdkGC* /*pGCDst*/
+                        );
+
+  void        (* DestroyGC)(
+                           GdkGC* /*pGC*/
+                           );
+
+  void        (* ChangeClip)(
+                            GdkGC* /*pGC*/,
+                            int /*type*/,
+                            gpointer /*pvalue*/,
+                            int /*nrects*/
+                            );
+  void        (* DestroyClip)(
+                             GdkGC* /*pGC*/
+                             );
+
+  void        (* CopyClip)(
+                          GdkGC* /*pgcDst*/,
+                          GdkGC* /*pgcSrc*/
+                          );
+
+};
+
+typedef union {
+  guint32 val;
+  gpointer ptr;
+} ChangeGCVal, *ChangeGCValPtr;
+
+#define PixmapBytePad(w, d) (w)
+#define BitmapBytePad(w) (w)
+
+#if 0
+typedef struct _PaddingInfo {
+        int     padRoundUp;     /* pixels per pad unit - 1 */
+        int     padPixelsLog2;  /* log 2 (pixels per pad unit) */
+        int     padBytesLog2;   /* log 2 (bytes per pad unit) */
+        int     notPower2;      /* bitsPerPixel not a power of 2 */
+        int     bytesPerPixel;  /* only set when notPower2 is TRUE */
+} PaddingInfo;
+extern PaddingInfo PixmapWidthPaddingInfo[];
+
+#define PixmapWidthInPadUnits(w, d) \
+    (PixmapWidthPaddingInfo[d].notPower2 ? \
+    (((int)(w) * PixmapWidthPaddingInfo[d].bytesPerPixel +  \
+                 PixmapWidthPaddingInfo[d].bytesPerPixel) >> \
+        PixmapWidthPaddingInfo[d].padBytesLog2) : \
+    ((int)((w) + PixmapWidthPaddingInfo[d].padRoundUp) >> \
+        PixmapWidthPaddingInfo[d].padPixelsLog2))
+
+#define PixmapBytePad(w, d) \
+    (PixmapWidthInPadUnits(w, d) << PixmapWidthPaddingInfo[d].padBytesLog2)
+
+#define BitmapBytePad(w) \
+    (((int)((w) + BITMAP_SCANLINE_PAD - 1) >> LOG2_BITMAP_PAD) << LOG2_BYTES_PER_SCANLINE_PAD)
+
+typedef struct _GdkDrawable GdkPixmap, *GdkPixmap*;
+typedef struct _GdkDrawable GdkDrawable, *GdkDrawable*;
+typedef struct _GdkGCOps GdkGCOps;
+typedef struct _Region Region, *GdkRegion*;
+  
+#define EVEN_DASH      0
+#define ODD_DASH       ~0
+
+typedef struct _GdkPoint {
+    gint16             x, y;
+} GdkPoint, *GdkPoint*;
+
+typedef struct _GdkGC {
+    unsigned char       depth;    
+    unsigned char       alu;
+    unsigned short      line_width;          
+    unsigned short      dashOffset;
+    unsigned short      numInDashList;
+    unsigned char       *dash;
+    unsigned int        lineStyle : 2;
+    unsigned int        capStyle : 2;
+    unsigned int        joinStyle : 2;
+    unsigned int        fillStyle : 2;
+    unsigned int        fillRule : 1;
+    unsigned int        arcMode : 1;
+    unsigned int        subWindowMode : 1;
+    unsigned int        graphicsExposures : 1;
+    unsigned int        clientClipType : 2; /* CT_<kind> */
+    unsigned int        miTranslate:1; /* should mi things translate? */
+    unsigned int        tileIsPixel:1; /* tile is solid pixel */
+    unsigned int        fExpose:1;     /* Call exposure handling */
+    unsigned int        freeCompClip:1;  /* Free composite clip */
+    unsigned int        unused:14; /* see comment above */
+    unsigned long       planemask;
+    unsigned long       fgPixel;
+    unsigned long       bgPixel;
+    /*
+     * alas -- both tile and stipple must be here as they
+     * are independently specifiable
+     */
+  /*    PixUnion            tile;
+       GdkPixmap*           stipple;*/
+    GdkPoint             patOrg;         /* origin for (tile, stipple) */
+    struct _Font        *font;
+    GdkPoint             clipOrg;
+    GdkPoint             lastWinOrg;     /* position of window last validated */
+    gpointer            clientClip;
+    unsigned long       stateChanges;   /* masked with GC_<kind> */
+    unsigned long       serialNumber;
+  /*    GCFuncs             *funcs; */
+    GdkGCOps             *ops;
+} GdkGC, *GdkGC*;
+
+struct _GdkDrawable {
+    unsigned char      type;   /* DRAWABLE_<type> */
+    unsigned char      depth;
+    unsigned char      bitsPerPixel;
+    short              x;      /* window: screen absolute, pixmap: 0 */
+    short              y;      /* window: screen absolute, pixmap: 0 */
+    unsigned short     width;
+    unsigned short     height;
+    unsigned long      serialNumber;
+
+    guchar             *buffer;
+    int                 rowStride;                 
+};
+
+typedef struct _GdkSegment {
+    gint16 x1, y1, x2, y2;
+} GdkSegment;
+
+typedef struct _GdkRectangle {
+    gint16 x, y;
+    guint16  width, height;
+} GdkRectangle, *GdkRectangle*;
+
+typedef struct _Box {
+    short x1, y1, x2, y2;
+} BoxRec, *BoxPtr;
+
+/*
+ * graphics operations invoked through a GC
+ */
+
+/* graphics functions, as in GC.alu */
+
+#define GDK_CLEAR                 0x0             /* 0 */
+#define GDK_AND                   0x1             /* src AND dst */
+#define GDK_AND_REVERSE            0x2             /* src AND NOT dst */
+#define GDK_COPY                  0x3             /* src */
+#define GDK_AND_INVERT           0x4             /* NOT src AND dst */
+#define GDK_NOOP                  0x5             /* dst */
+#define GDK_XOR                   0x6             /* src XOR dst */
+#define GDK_OR                    0x7             /* src OR dst */
+#define GDK_NOR                   0x8             /* NOT src AND NOT dst */
+#define GDK_EQUIV                 0x9             /* NOT src XOR dst */
+#define GDK_INVERT                0xa             /* NOT dst */
+#define GDK_OR_REVERSE             0xb             /* src OR NOT dst */
+#define GDK_COPY_INVERT          0xc             /* NOT src */
+#define GDK_OR_INVERT            0xd             /* NOT src OR dst */
+#define GDK_NAND                  0xe             /* NOT src OR NOT dst */
+#define GDK_SET                   0xf             /* 1 */
+
+/* CoordinateMode for drawing routines */
+
+#define CoordModeOrigin         0       /* relative to the origin */
+#define CoordModePrevious       1       /* relative to previous point */
+
+/* Polygon shapes */
+
+#define Complex                 0       /* paths may intersect */
+#define Nonconvex               1       /* no paths intersect, but not convex */
+#define Convex                  2       /* wholly convex */
+
+/* LineStyle */
+
+#define GDK_LINE_SOLID               0
+#define GDK_LINE_ON_OFF_DASH           1
+#define GDK_LINE_DOUBLE_DASH          2
+
+/* capStyle */
+
+#define GDK_CAP_NOT_LAST              0
+#define GDK_CAP_BUTT                 1
+#define GDK_CAP_ROUND                2
+#define GDK_CAP_PROJECTING           3
+
+/* joinStyle */
+
+#define GDK_JOIN_MITER               0
+#define GDK_JOIN_ROUND               1
+#define GDK_JOIN_BEVEL               2
+
+/* Arc modes for PolyFillArc */
+
+#define ArcChord                0       /* join endpoints of arc */
+#define ArcPieSlice             1       /* join endpoints to center of arc */
+
+/* fillRule */
+
+#define EvenOddRule             0
+#define WindingRule             1
+
+/* fillStyle */
+
+#define GDK_SOLID               0
+#define GDK_TILED               1
+#define GDK_STIPPLED            2
+#define GDK_OPAQUE_STIPPLED      3
+
+typedef enum {  Linear8Bit, TwoD8Bit, Linear16Bit, TwoD16Bit }  FontEncoding;
+
+#define MININT G_MININT
+#define MAXINT G_MAXINT
+#define MINSHORT G_MINSHORT
+#define MAXSHORT G_MAXSHORT
+
+/* GC components: masks used in CreateGC, CopyGC, ChangeGC, OR'ed into
+   GC.stateChanges */
+
+#define GDK_GC_FUNCTION              (1L<<0)
+#define GCPlaneMask             (1L<<1)
+#define GDK_GC_FOREGROUND            (1L<<2)
+#define GDK_GC_BACKGROUND            (1L<<3)
+#define GDK_GC_LINE_WIDTH             (1L<<4)
+#define GCLineStyle             (1L<<5)
+#define GDK_GC_CAP_STYLE              (1L<<6)
+#define GDK_GC_JOIN_STYLE             (1L<<7)
+#define GDK_GC_FILL_STYLE             (1L<<8)
+#define GCFillRule              (1L<<9) 
+#define GCTile                  (1L<<10)
+#define GDK_GC_STIPPLE               (1L<<11)
+#define GDK_GC_TS_X_ORIGIN       (1L<<12)
+#define GDK_GC_TS_Y_ORIGIN       (1L<<13)
+#define GCFont                  (1L<<14)
+#define GCSubwindowMode         (1L<<15)
+#define GCGraphicsExposures     (1L<<16)
+#define GCClipXOrigin           (1L<<17)
+#define GCClipYOrigin           (1L<<18)
+#define GCClipMask              (1L<<19)
+#define GCDashOffset            (1L<<20)
+#define GCDashList              (1L<<21)
+#define GCArcMode               (1L<<22)
+
+/* types for Drawable */
+
+#define GDK_WINDOW_CHILD 0
+#define GDK_DRAWABLE_PIXMAP 1
+#define GDK_WINDOW_FOREIGN 2
+#define GDK_WINDOW_TEMP 3
+
+#endif
+
+typedef GdkSegment BoxRec, *BoxPtr;
+
+typedef struct _miArc {
+    gint16 x, y;
+    guint16   width, height;
+    gint16   angle1, angle2;
+} miArc;
+
+struct _GdkGCOps {
+    void       (* FillSpans)(
+               GdkDrawable* /*pDrawable*/,
+               GdkGC* /*pGC*/,
+               int /*nInit*/,
+               GdkPoint* /*pptInit*/,
+               int * /*pwidthInit*/,
+               int /*fSorted*/
+);
+
+    void       (* SetSpans)(
+               GdkDrawable* /*pDrawable*/,
+               GdkGC* /*pGC*/,
+               char * /*psrc*/,
+               GdkPoint* /*ppt*/,
+               int * /*pwidth*/,
+               int /*nspans*/,
+               int /*fSorted*/
+);
+
+    void       (* PutImage)(
+               GdkDrawable* /*pDrawable*/,
+               GdkGC* /*pGC*/,
+               int /*depth*/,
+               int /*x*/,
+               int /*y*/,
+               int /*w*/,
+               int /*h*/,
+               int /*leftPad*/,
+               int /*format*/,
+               char * /*pBits*/
+);
+
+    GdkRegion* (* CopyArea)(
+               GdkDrawable* /*pSrc*/,
+               GdkDrawable* /*pDst*/,
+               GdkGC* /*pGC*/,
+               int /*srcx*/,
+               int /*srcy*/,
+               int /*w*/,
+               int /*h*/,
+               int /*dstx*/,
+               int /*dsty*/
+);
+
+    GdkRegion* (* CopyPlane)(
+               GdkDrawable* /*pSrcDrawable*/,
+               GdkDrawable* /*pDstDrawable*/,
+               GdkGC* /*pGC*/,
+               int /*srcx*/,
+               int /*srcy*/,
+               int /*width*/,
+               int /*height*/,
+               int /*dstx*/,
+               int /*dsty*/,
+               unsigned long /*bitPlane*/
+);
+    void       (* PolyPoint)(
+               GdkDrawable* /*pDrawable*/,
+               GdkGC* /*pGC*/,
+               int /*mode*/,
+               int /*npt*/,
+               GdkPoint* /*pptInit*/
+);
+
+    void       (* Polylines)(
+               GdkDrawable* /*pDrawable*/,
+               GdkGC* /*pGC*/,
+               int /*mode*/,
+               int /*npt*/,
+               GdkPoint* /*pptInit*/
+);
+
+    void       (* PolySegment)(
+               GdkDrawable* /*pDrawable*/,
+               GdkGC* /*pGC*/,
+               int /*nseg*/,
+               GdkSegment * /*pSegs*/
+);
+
+    void       (* PolyRectangle)(
+               GdkDrawable* /*pDrawable*/,
+               GdkGC* /*pGC*/,
+               int /*nrects*/,
+               GdkRectangle * /*pRects*/
+);
+
+    void       (* PolyArc)(
+               GdkDrawable* /*pDrawable*/,
+               GdkGC* /*pGC*/,
+               int /*narcs*/,
+               miArc * /*parcs*/
+);
+
+    void       (* FillPolygon)(
+               GdkDrawable* /*pDrawable*/,
+               GdkGC* /*pGC*/,
+               int /*shape*/,
+               int /*mode*/,
+               int /*count*/,
+               GdkPoint* /*pPts*/
+);
+
+    void       (* PolyFillRect)(
+               GdkDrawable* /*pDrawable*/,
+               GdkGC* /*pGC*/,
+               int /*nrectFill*/,
+               GdkRectangle * /*prectInit*/
+);
+
+    void       (* PolyFillArc)(
+               GdkDrawable* /*pDrawable*/,
+               GdkGC* /*pGC*/,
+               int /*narcs*/,
+               miArc * /*parcs*/
+);
+
+#if 0  
+    int                (* PolyText8)(
+               GdkDrawable* /*pDrawable*/,
+               GdkGC* /*pGC*/,
+               int /*x*/,
+               int /*y*/,
+               int /*count*/,
+               char * /*chars*/
+);
+
+    int                (* PolyText16)(
+               GdkDrawable* /*pDrawable*/,
+               GdkGC* /*pGC*/,
+               int /*x*/,
+               int /*y*/,
+               int /*count*/,
+               unsigned short * /*chars*/
+);
+
+    void       (* ImageText8)(
+               GdkDrawable* /*pDrawable*/,
+               GdkGC* /*pGC*/,
+               int /*x*/,
+               int /*y*/,
+               int /*count*/,
+               char * /*chars*/
+);
+
+    void       (* ImageText16)(
+               GdkDrawable* /*pDrawable*/,
+               GdkGC* /*pGC*/,
+               int /*x*/,
+               int /*y*/,
+               int /*count*/,
+               unsigned short * /*chars*/
+);
+
+    void       (* ImageGlyphBlt)(
+               GdkDrawable* /*pDrawable*/,
+               GdkGC* /*pGC*/,
+               int /*x*/,
+               int /*y*/,
+               unsigned int /*nglyph*/,
+               CharInfoPtr * /*ppci*/,
+               pointer /*pglyphBase*/
+);
+
+    void       (* PolyGlyphBlt)(
+               GdkDrawable* /*pDrawable*/,
+               GdkGC* /*pGC*/,
+               int /*x*/,
+               int /*y*/,
+               unsigned int /*nglyph*/,
+               CharInfoPtr * /*ppci*/,
+               pointer /*pglyphBase*/
+);
+#endif
+  
+    void       (* PushPixels)(
+               GdkGC* /*pGC*/,
+               GdkPixmap* /*pBitMap*/,
+               GdkDrawable* /*pDst*/,
+               int /*w*/,
+               int /*h*/,
+               int /*x*/,
+               int /*y*/
+);
+};
+
+#define SCRRIGHT(x, n) ((x)>>(n))
+
+#endif /* MITYPES_H */
diff --git a/gdk/linux-fb/miwideline.c b/gdk/linux-fb/miwideline.c
new file mode 100644 (file)
index 0000000..d1e46b9
--- /dev/null
@@ -0,0 +1,2108 @@
+/* $TOG: miwideline.c /main/60 1998/03/07 17:40:23 kaleb $ */
+/*
+
+Copyright 1988, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+*/
+/* $XFree86: xc/programs/Xserver/mi/miwideline.c,v 1.7 1999/10/13 22:33:13 dawes Exp $ */
+
+/* Author:  Keith Packard, MIT X Consortium */
+
+/*
+ * Mostly integer wideline code.  Uses a technique similar to
+ * bresenham zero-width lines, except walks an X edge
+ */
+
+#include <stdio.h>
+#ifdef _XOPEN_SOURCE
+#include <math.h>
+#else
+#define _XOPEN_SOURCE  /* to get prototype for hypot on some systems */
+#include <math.h>
+#undef _XOPEN_SOURCE
+#endif
+
+#include "mi.h"
+#include "miwideline.h"
+
+#ifdef ICEILTEMPDECL
+ICEILTEMPDECL
+#endif
+
+static void miLineArc();
+
+/*
+ * spans-based polygon filler
+ */
+
+void
+miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, overall_height,
+                 left, right, left_count, right_count)
+    GdkDrawable*       pDrawable;
+    GdkGC*     pGC;
+    GdkColor *pixel;
+    SpanDataPtr        spanData;
+    int                y;                      /* start y coordinate */
+    int                overall_height;         /* height of entire segment */
+    PolyEdgePtr        left, right;
+    int                left_count, right_count;
+{
+    register int left_x = 0, left_e = 0;
+    int        left_stepx = 0;
+    int        left_signdx = 0;
+    int        left_dy = 0, left_dx = 0;
+
+    register int right_x = 0, right_e = 0;
+    int        right_stepx = 0;
+    int        right_signdx = 0;
+    int        right_dy = 0, right_dx = 0;
+
+    int        height = 0;
+    int        left_height = 0, right_height = 0;
+
+    register GdkRectangle* ppt;
+    GdkRectangle* pptInit;
+    GdkColor           oldPixel;
+    int                xorg;
+    Spans      spanRec;
+
+    left_height = 0;
+    right_height = 0;
+    
+    if (!spanData)
+    {
+       pptInit = (GdkRectangle*) ALLOCATE_LOCAL (overall_height * sizeof(*ppt));
+       if (!pptInit)
+           return;
+       ppt = pptInit;
+       oldPixel = GDK_GC_FBDATA(pGC)->values.foreground;
+       if (pixel->pixel != oldPixel.pixel)
+       {
+         gdk_gc_set_foreground(pGC, pixel);
+       }
+    }
+    else
+    {
+       spanRec.points = (GdkRectangle*) g_malloc (overall_height * sizeof (*ppt));
+       if (!spanRec.points)
+           return;
+       ppt = spanRec.points;
+    }
+
+    xorg = 0;
+    while ((left_count || left_height) &&
+          (right_count || right_height))
+    {
+       MIPOLYRELOADLEFT
+       MIPOLYRELOADRIGHT
+
+       height = left_height;
+       if (height > right_height)
+           height = right_height;
+
+       left_height -= height;
+       right_height -= height;
+
+       while (--height >= 0)
+       {
+           if (right_x >= left_x)
+           {
+               ppt->y = y;
+               ppt->x = left_x + xorg;
+               ppt->width = right_x - left_x + 1;
+               ppt->height = 1;
+               ppt++;
+           }
+           y++;
+       
+           MIPOLYSTEPLEFT
+
+           MIPOLYSTEPRIGHT
+       }
+    }
+    if (!spanData)
+    {
+      gdk_fb_fill_spans(pDrawable, pGC, pptInit, ppt - pptInit);
+      DEALLOCATE_LOCAL (pptInit);
+      if (pixel->pixel != oldPixel.pixel)
+       {
+         gdk_gc_set_foreground(pGC, &oldPixel);
+       }
+    }
+    else
+    {
+       spanRec.count = ppt - spanRec.points;
+       AppendSpanGroup (pGC, pixel, &spanRec, spanData)
+    }
+}
+
+static void
+miFillRectPolyHelper (pDrawable, pGC, pixel, spanData, x, y, w, h)
+    GdkDrawable*       pDrawable;
+    GdkGC*     pGC;
+    GdkColor*   pixel;
+    SpanDataPtr        spanData;
+    int                x, y, w, h;
+{
+    register GdkRectangle* ppt;
+    GdkColor           oldPixel;
+    Spans      spanRec;
+    GdkRectangle  rect;
+
+    if (!spanData)
+    {
+       rect.x = x;
+       rect.y = y;
+       rect.width = w;
+       rect.height = h;
+       oldPixel = GDK_GC_FBDATA(pGC)->values.foreground;
+       if (pixel->pixel != oldPixel.pixel)
+       {
+         gdk_gc_set_foreground(pGC, pixel);
+       }
+       gdk_fb_fill_spans(pDrawable, pGC, &rect, 1);
+       if (pixel->pixel != oldPixel.pixel)
+       {
+         gdk_gc_set_foreground(pGC, &oldPixel);
+       }
+    }
+    else
+    {
+       spanRec.points = (GdkRectangle*) g_malloc (h * sizeof (*ppt));
+       if (!spanRec.points)
+           return;
+       ppt = spanRec.points;
+
+       while (h--)
+       {
+           ppt->x = x;
+           ppt->y = y;
+           ppt->width = w;
+           ppt->height = 1;
+           ppt++;
+           y++;
+       }
+       spanRec.count = ppt - spanRec.points;
+       AppendSpanGroup (pGC, pixel, &spanRec, spanData)
+    }
+}
+
+/* static */ int
+miPolyBuildEdge (x0, y0, k, dx, dy, xi, yi, left, edge)
+    double     x0, y0;
+    double     k;  /* x0 * dy - y0 * dx */
+    register int dx, dy;
+    int                xi, yi;
+    int                left;
+    register PolyEdgePtr edge;
+{
+    int            x, y, e;
+    int            xady;
+
+    if (dy < 0)
+    {
+       dy = -dy;
+       dx = -dx;
+       k = -k;
+    }
+
+#ifdef NOTDEF
+    {
+       double  realk, kerror;
+       realk = x0 * dy - y0 * dx;
+       kerror = Fabs (realk - k);
+       if (kerror > .1)
+           printf ("realk: %g k: %g\n", realk, k);
+    }
+#endif
+    y = ICEIL (y0);
+    xady = ICEIL (k) + y * dx;
+
+    if (xady <= 0)
+       x = - (-xady / dy) - 1;
+    else
+       x = (xady - 1) / dy;
+
+    e = xady - x * dy;
+
+    if (dx >= 0)
+    {
+       edge->signdx = 1;
+       edge->stepx = dx / dy;
+       edge->dx = dx % dy;
+    }
+    else
+    {
+       edge->signdx = -1;
+       edge->stepx = - (-dx / dy);
+       edge->dx = -dx % dy;
+       e = dy - e + 1;
+    }
+    edge->dy = dy;
+    edge->x = x + left + xi;
+    edge->e = e - dy;  /* bias to compare against 0 instead of dy */
+    return y + yi;
+}
+
+#define StepAround(v, incr, max) (((v) + (incr) < 0) ? (max - 1) : ((v) + (incr) == max) ? 0 : ((v) + (incr)))
+
+/* static */ int
+miPolyBuildPoly (vertices, slopes, count, xi, yi, left, right, pnleft, pnright, h)
+    register PolyVertexPtr vertices;
+    register PolySlopePtr  slopes;
+    int                    count;
+    int                    xi, yi;
+    PolyEdgePtr            left, right;
+    int                    *pnleft, *pnright;
+    int                    *h;
+{
+    int            top, bottom;
+    double  miny, maxy;
+    register int i;
+    int            j;
+    int            clockwise;
+    int            slopeoff;
+    register int s;
+    register int nright, nleft;
+    int            y, lasty = 0, bottomy, topy = 0;
+
+    /* find the top of the polygon */
+    maxy = miny = vertices[0].y;
+    bottom = top = 0;
+    for (i = 1; i < count; i++)
+    {
+       if (vertices[i].y < miny)
+       {
+           top = i;
+           miny = vertices[i].y;
+       }
+       if (vertices[i].y >= maxy)
+       {
+           bottom = i;
+           maxy = vertices[i].y;
+       }
+    }
+    clockwise = 1;
+    slopeoff = 0;
+
+    i = top;
+    j = StepAround (top, -1, count);
+
+    if (slopes[j].dy * slopes[i].dx > slopes[i].dy * slopes[j].dx)
+    {
+       clockwise = -1;
+       slopeoff = -1;
+    }
+
+    bottomy = ICEIL (maxy) + yi;
+
+    nright = 0;
+
+    s = StepAround (top, slopeoff, count);
+    i = top;
+    while (i != bottom)
+    {
+       if (slopes[s].dy != 0)
+       {
+           y = miPolyBuildEdge (vertices[i].x, vertices[i].y,
+                       slopes[s].k,
+                       slopes[s].dx, slopes[s].dy,
+                       xi, yi, 0,
+                       &right[nright]);
+           if (nright != 0)
+               right[nright-1].height = y - lasty;
+           else
+               topy = y;
+           nright++;
+           lasty = y;
+       }
+
+       i = StepAround (i, clockwise, count);
+       s = StepAround (s, clockwise, count);
+    }
+    if (nright != 0)
+       right[nright-1].height = bottomy - lasty;
+
+    if (slopeoff == 0)
+       slopeoff = -1;
+    else
+       slopeoff = 0;
+
+    nleft = 0;
+    s = StepAround (top, slopeoff, count);
+    i = top;
+    while (i != bottom)
+    {
+       if (slopes[s].dy != 0)
+       {
+           y = miPolyBuildEdge (vertices[i].x, vertices[i].y,
+                          slopes[s].k,
+                          slopes[s].dx,  slopes[s].dy, xi, yi, 1,
+                          &left[nleft]);
+    
+           if (nleft != 0)
+               left[nleft-1].height = y - lasty;
+           nleft++;
+           lasty = y;
+       }
+       i = StepAround (i, -clockwise, count);
+       s = StepAround (s, -clockwise, count);
+    }
+    if (nleft != 0)
+       left[nleft-1].height = bottomy - lasty;
+    *pnleft = nleft;
+    *pnright = nright;
+    *h = bottomy - topy;
+    return topy;
+}
+
+static void
+miLineOnePoint (pDrawable, pGC, pixel, spanData, x, y)
+    GdkDrawable*           pDrawable;
+    GdkGC*         pGC;
+    GdkColor*   pixel;
+    SpanDataPtr            spanData;
+    int                    x, y;
+{
+    GdkColor   oldPixel;
+    GdkRectangle rect;
+
+    MILINESETPIXEL (pDrawable, pGC, pixel, oldPixel);
+    rect.width = 1;
+    rect.height = 1;
+
+    gdk_fb_fill_spans(pDrawable, pGC, &rect, 1);
+    MILINERESETPIXEL (pDrawable, pGC, pixel, oldPixel);
+}
+
+static void
+miLineJoin (pDrawable, pGC, pixel, spanData, pLeft, pRight)
+    GdkDrawable*           pDrawable;
+    GdkGC*         pGC;
+    GdkColor *pixel;
+    SpanDataPtr            spanData;
+    register LineFacePtr pLeft, pRight;
+{
+    double         mx, my;
+    double         denom = 0.0;
+    PolyVertexRec   vertices[4];
+    PolySlopeRec    slopes[4];
+    int                    edgecount;
+    PolyEdgeRec            left[4], right[4];
+    int                    nleft, nright;
+    int                    y, height;
+    int                    swapslopes;
+    int                    joinStyle = GDK_GC_FBDATA(pGC)->values.join_style;
+    int                    lw = GDK_GC_FBDATA(pGC)->values.line_width;
+
+    if (lw == 1 && !spanData) {
+       /* Lines going in the same direction have no join */
+       if (pLeft->dx >= 0 == pRight->dx <= 0)
+           return;
+       if (joinStyle != GDK_JOIN_ROUND) {
+           denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
+           if (denom == 0)
+               return; /* no join to draw */
+       }
+       if (joinStyle != GDK_JOIN_MITER) {
+           miLineOnePoint (pDrawable, pGC, pixel, spanData, pLeft->x, pLeft->y);
+           return;
+       }
+    } else {
+       if (joinStyle == GDK_JOIN_ROUND)
+       {
+           miLineArc(pDrawable, pGC, pixel, spanData,
+                     pLeft, pRight,
+                     (double)0.0, (double)0.0, TRUE);
+           return;
+       }
+       denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
+       if (denom == 0.0)
+           return;     /* no join to draw */
+    }
+
+    swapslopes = 0;
+    if (denom > 0)
+    {
+       pLeft->xa = -pLeft->xa;
+       pLeft->ya = -pLeft->ya;
+       pLeft->dx = -pLeft->dx;
+       pLeft->dy = -pLeft->dy;
+    }
+    else
+    {
+       swapslopes = 1;
+       pRight->xa = -pRight->xa;
+       pRight->ya = -pRight->ya;
+       pRight->dx = -pRight->dx;
+       pRight->dy = -pRight->dy;
+    }
+
+    vertices[0].x = pRight->xa;
+    vertices[0].y = pRight->ya;
+    slopes[0].dx = -pRight->dy;
+    slopes[0].dy =  pRight->dx;
+    slopes[0].k = 0;
+
+    vertices[1].x = 0;
+    vertices[1].y = 0;
+    slopes[1].dx =  pLeft->dy;
+    slopes[1].dy = -pLeft->dx;
+    slopes[1].k = 0;
+
+    vertices[2].x = pLeft->xa;
+    vertices[2].y = pLeft->ya;
+
+    if (joinStyle == GDK_JOIN_MITER)
+    {
+       my = (pLeft->dy  * (pRight->xa * pRight->dy - pRight->ya * pRight->dx) -
+              pRight->dy * (pLeft->xa  * pLeft->dy  - pLeft->ya  * pLeft->dx )) /
+             denom;
+       if (pLeft->dy != 0)
+       {
+           mx = pLeft->xa + (my - pLeft->ya) *
+                           (double) pLeft->dx / (double) pLeft->dy;
+       }
+       else
+       {
+           mx = pRight->xa + (my - pRight->ya) *
+                           (double) pRight->dx / (double) pRight->dy;
+       }
+       /* check miter limit */
+       if ((mx * mx + my * my) * 4 > SQSECANT * lw * lw)
+           joinStyle = GDK_JOIN_BEVEL;
+    }
+
+    if (joinStyle == GDK_JOIN_MITER)
+    {
+       slopes[2].dx = pLeft->dx;
+       slopes[2].dy = pLeft->dy;
+       slopes[2].k =  pLeft->k;
+       if (swapslopes)
+       {
+           slopes[2].dx = -slopes[2].dx;
+           slopes[2].dy = -slopes[2].dy;
+           slopes[2].k  = -slopes[2].k;
+       }
+       vertices[3].x = mx;
+       vertices[3].y = my;
+       slopes[3].dx = pRight->dx;
+       slopes[3].dy = pRight->dy;
+       slopes[3].k  = pRight->k;
+       if (swapslopes)
+       {
+           slopes[3].dx = -slopes[3].dx;
+           slopes[3].dy = -slopes[3].dy;
+           slopes[3].k  = -slopes[3].k;
+       }
+       edgecount = 4;
+    }
+    else
+    {
+       double  scale, dx, dy, adx, ady;
+
+       adx = dx = pRight->xa - pLeft->xa;
+       ady = dy = pRight->ya - pLeft->ya;
+       if (adx < 0)
+           adx = -adx;
+       if (ady < 0)
+           ady = -ady;
+       scale = ady;
+       if (adx > ady)
+           scale = adx;
+       slopes[2].dx = (dx * 65536) / scale;
+       slopes[2].dy = (dy * 65536) / scale;
+       slopes[2].k = ((pLeft->xa + pRight->xa) * slopes[2].dy -
+                      (pLeft->ya + pRight->ya) * slopes[2].dx) / 2.0;
+       edgecount = 3;
+    }
+
+    y = miPolyBuildPoly (vertices, slopes, edgecount, pLeft->x, pLeft->y,
+                  left, right, &nleft, &nright, &height);
+    miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, height, left, right, nleft, nright);
+}
+
+static int
+miLineArcI (pDraw, pGC, xorg, yorg, points, widths)
+    GdkDrawable*           pDraw;
+    GdkGC*         pGC;
+    int                    xorg, yorg;
+    GdkRectangle*          points;
+{
+    register GdkRectangle* tpts, *bpts;
+    register int x, y, e, ex, slw;
+
+    tpts = points;
+    slw = GDK_GC_FBDATA(pGC)->values.line_width;
+    if (slw == 1)
+    {
+       tpts->x = xorg;
+       tpts->y = yorg;
+       tpts->width = 1;
+       tpts->height = 1;
+       return 1;
+    }
+    bpts = tpts + slw;
+    y = (slw >> 1) + 1;
+    if (slw & 1)
+       e = - ((y << 2) + 3);
+    else
+       e = - (y << 3);
+    ex = -4;
+    x = 0;
+    while (y)
+    {
+       e += (y << 3) - 4;
+       while (e >= 0)
+       {
+           x++;
+           e += (ex = -((x << 3) + 4));
+       }
+       y--;
+       slw = (x << 1) + 1;
+       if ((e == ex) && (slw > 1))
+           slw--;
+       tpts->x = xorg - x;
+       tpts->y = yorg - y;
+       tpts->width = slw;
+       tpts->height = 1;
+       tpts++;
+       if ((y != 0) && ((slw > 1) || (e != ex)))
+       {
+           bpts--;
+           bpts->x = xorg - x;
+           bpts->y = yorg + y;
+           bpts->height = 1;
+           bpts->width = slw;
+       }
+    }
+    return (GDK_GC_FBDATA(pGC)->values.line_width);
+}
+
+#define CLIPSTEPEDGE(edgey,edge,edgeleft) \
+    if (ybase == edgey) \
+    { \
+       if (edgeleft) \
+       { \
+           if (edge->x > xcl) \
+               xcl = edge->x; \
+       } \
+       else \
+       { \
+           if (edge->x < xcr) \
+               xcr = edge->x; \
+       } \
+       edgey++; \
+       edge->x += edge->stepx; \
+       edge->e += edge->dx; \
+       if (edge->e > 0) \
+       { \
+           edge->x += edge->signdx; \
+           edge->e -= edge->dy; \
+       } \
+    }
+
+static int
+miLineArcD (pDraw, pGC, xorg, yorg, points, widths,
+           edge1, edgey1, edgeleft1, edge2, edgey2, edgeleft2)
+    GdkDrawable*           pDraw;
+    GdkGC*         pGC;
+    double         xorg, yorg;
+    GdkRectangle*   points;
+    PolyEdgePtr            edge1, edge2;
+    int                    edgey1, edgey2;
+    gboolean       edgeleft1, edgeleft2;
+{
+    register GdkRectangle* pts;
+    double radius, x0, y0, el, er, yk, xlk, xrk, k;
+    int xbase, ybase, y, boty, xl, xr, xcl, xcr;
+    int ymin, ymax;
+    gboolean edge1IsMin, edge2IsMin;
+    int ymin1, ymin2;
+
+    pts = points;
+    xbase = floor(xorg);
+    x0 = xorg - xbase;
+    ybase = ICEIL (yorg);
+    y0 = yorg - ybase;
+    xlk = x0 + x0 + 1.0;
+    xrk = x0 + x0 - 1.0;
+    yk = y0 + y0 - 1.0;
+    radius = ((double)GDK_GC_FBDATA(pGC)->values.line_width) / 2.0;
+    y = floor(radius - y0 + 1.0);
+    ybase -= y;
+    ymin = ybase;
+    ymax = 65536;
+    edge1IsMin = FALSE;
+    ymin1 = edgey1;
+    if (edge1->dy >= 0)
+    {
+       if (!edge1->dy)
+       {
+           if (edgeleft1)
+               edge1IsMin = TRUE;
+           else
+               ymax = edgey1;
+           edgey1 = 65536;
+       }
+       else
+       {
+           if ((edge1->signdx < 0) == edgeleft1)
+               edge1IsMin = TRUE;
+       }
+    }
+    edge2IsMin = FALSE;
+    ymin2 = edgey2;
+    if (edge2->dy >= 0)
+    {
+       if (!edge2->dy)
+       {
+           if (edgeleft2)
+               edge2IsMin = TRUE;
+           else
+               ymax = edgey2;
+           edgey2 = 65536;
+       }
+       else
+       {
+           if ((edge2->signdx < 0) == edgeleft2)
+               edge2IsMin = TRUE;
+       }
+    }
+    if (edge1IsMin)
+    {
+       ymin = ymin1;
+       if (edge2IsMin && ymin1 > ymin2)
+           ymin = ymin2;
+    } else if (edge2IsMin)
+       ymin = ymin2;
+    el = radius * radius - ((y + y0) * (y + y0)) - (x0 * x0);
+    er = el + xrk;
+    xl = 1;
+    xr = 0;
+    if (x0 < 0.5)
+    {
+       xl = 0;
+       el -= xlk;
+    }
+    boty = (y0 < -0.5) ? 1 : 0;
+    if (ybase + y - boty > ymax)
+       boty = ymax - ybase - y;
+    while (y > boty)
+    {
+       k = (y << 1) + yk;
+       er += k;
+       while (er > 0.0)
+       {
+           xr++;
+           er += xrk - (xr << 1);
+       }
+       el += k;
+       while (el >= 0.0)
+       {
+           xl--;
+           el += (xl << 1) - xlk;
+       }
+       y--;
+       ybase++;
+       if (ybase < ymin)
+           continue;
+       xcl = xl + xbase;
+       xcr = xr + xbase;
+       CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
+       CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
+       if (xcr >= xcl)
+       {
+           pts->x = xcl;
+           pts->y = ybase;
+           pts->width = xcr - xcl + 1;
+           pts->height = 1;
+           pts++;
+       }
+    }
+    er = xrk - (xr << 1) - er;
+    el = (xl << 1) - xlk - el;
+    boty = floor(-y0 - radius + 1.0);
+    if (ybase + y - boty > ymax)
+       boty = ymax - ybase - y;
+    while (y > boty)
+    {
+       k = (y << 1) + yk;
+       er -= k;
+       while ((er >= 0.0) && (xr >= 0))
+       {
+           xr--;
+           er += xrk - (xr << 1);
+       }
+       el -= k;
+       while ((el > 0.0) && (xl <= 0))
+       {
+           xl++;
+           el += (xl << 1) - xlk;
+       }
+       y--;
+       ybase++;
+       if (ybase < ymin)
+           continue;
+       xcl = xl + xbase;
+       xcr = xr + xbase;
+       CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
+       CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
+       if (xcr >= xcl)
+       {
+           pts->x = xcl;
+           pts->y = ybase;
+           pts->width = xcr - xcl + 1;
+           pts->height = 1;
+           pts++;
+       }
+    }
+    return (pts - points);
+}
+
+int
+miRoundJoinFace (face, edge, leftEdge)
+    register LineFacePtr face;
+    register PolyEdgePtr edge;
+    gboolean   *leftEdge;
+{
+    int            y;
+    int            dx, dy;
+    double  xa, ya;
+    gboolean   left;
+
+    dx = -face->dy;
+    dy = face->dx;
+    xa = face->xa;
+    ya = face->ya;
+    left = 1;
+    if (ya > 0)
+    {
+       ya = 0.0;
+       xa = 0.0;
+    }
+    if (dy < 0 || (dy == 0 && dx > 0))
+    {
+       dx = -dx;
+       dy = -dy;
+       left = !left;
+    }
+    if (dx == 0 && dy == 0)
+       dy = 1;
+    if (dy == 0)
+    {
+       y = ICEIL (face->ya) + face->y;
+       edge->x = -32767;
+       edge->stepx = 0;
+       edge->signdx = 0;
+       edge->e = -1;
+       edge->dy = 0;
+       edge->dx = 0;
+       edge->height = 0;
+    }
+    else
+    {
+       y = miPolyBuildEdge (xa, ya, 0.0, dx, dy, face->x, face->y, !left, edge);
+       edge->height = 32767;
+    }
+    *leftEdge = !left;
+    return y;
+}
+
+void
+miRoundJoinClip (pLeft, pRight, edge1, edge2, y1, y2, left1, left2)
+    register LineFacePtr pLeft, pRight;
+    PolyEdgePtr        edge1, edge2;
+    int                *y1, *y2;
+    gboolean   *left1, *left2;
+{
+    double     denom;
+
+    denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
+
+    if (denom >= 0)
+    {
+       pLeft->xa = -pLeft->xa;
+       pLeft->ya = -pLeft->ya;
+    }
+    else
+    {
+       pRight->xa = -pRight->xa;
+       pRight->ya = -pRight->ya;
+    }
+    *y1 = miRoundJoinFace (pLeft, edge1, left1);
+    *y2 = miRoundJoinFace (pRight, edge2, left2);
+}
+
+int
+miRoundCapClip (face, isInt, edge, leftEdge)
+    register LineFacePtr face;
+    gboolean   isInt;
+    register PolyEdgePtr edge;
+    gboolean   *leftEdge;
+{
+    int            y;
+    register int dx, dy;
+    double  xa, ya, k;
+    gboolean   left;
+
+    dx = -face->dy;
+    dy = face->dx;
+    xa = face->xa;
+    ya = face->ya;
+    k = 0.0;
+    if (!isInt)
+       k = face->k;
+    left = 1;
+    if (dy < 0 || (dy == 0 && dx > 0))
+    {
+       dx = -dx;
+       dy = -dy;
+       xa = -xa;
+       ya = -ya;
+       left = !left;
+    }
+    if (dx == 0 && dy == 0)
+       dy = 1;
+    if (dy == 0)
+    {
+       y = ICEIL (face->ya) + face->y;
+       edge->x = -32767;
+       edge->stepx = 0;
+       edge->signdx = 0;
+       edge->e = -1;
+       edge->dy = 0;
+       edge->dx = 0;
+       edge->height = 0;
+    }
+    else
+    {
+       y = miPolyBuildEdge (xa, ya, k, dx, dy, face->x, face->y, !left, edge);
+       edge->height = 32767;
+    }
+    *leftEdge = !left;
+    return y;
+}
+
+static void
+miLineArc (pDraw, pGC, pixel, spanData, leftFace, rightFace, xorg, yorg, isInt)
+    GdkDrawable*           pDraw;
+    register GdkGC*  pGC;
+    GdkColor* pixel;
+    SpanDataPtr            spanData;
+    register LineFacePtr leftFace, rightFace;
+    double         xorg, yorg;
+    gboolean       isInt;
+{
+    GdkRectangle* points;
+    int xorgi = 0, yorgi = 0;
+    GdkColor           oldPixel;
+    Spans spanRec;
+    int n;
+    PolyEdgeRec        edge1, edge2;
+    int                edgey1, edgey2;
+    gboolean   edgeleft1, edgeleft2;
+
+    if (isInt)
+    {
+       xorgi = leftFace ? leftFace->x : rightFace->x;
+       yorgi = leftFace ? leftFace->y : rightFace->y;
+    }
+    edgey1 = 65536;
+    edgey2 = 65536;
+    edge1.x = 0; /* not used, keep memory checkers happy */
+    edge1.dy = -1;
+    edge2.x = 0; /* not used, keep memory checkers happy */
+    edge2.dy = -1;
+    edgeleft1 = FALSE;
+    edgeleft2 = FALSE;
+    if (((GDK_GC_FBDATA(pGC)->values.line_style != GDK_LINE_SOLID || GDK_GC_FBDATA(pGC)->values.line_width > 2) &&
+        (GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_ROUND && GDK_GC_FBDATA(pGC)->values.join_style != GDK_JOIN_ROUND)) ||
+       (GDK_GC_FBDATA(pGC)->values.join_style == GDK_JOIN_ROUND && GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_BUTT))
+    {
+       if (isInt)
+       {
+           xorg = (double) xorgi;
+           yorg = (double) yorgi;
+       }
+       if (leftFace && rightFace)
+       {
+           miRoundJoinClip (leftFace, rightFace, &edge1, &edge2,
+                            &edgey1, &edgey2, &edgeleft1, &edgeleft2);
+       }
+       else if (leftFace)
+       {
+           edgey1 = miRoundCapClip (leftFace, isInt, &edge1, &edgeleft1);
+       }
+       else if (rightFace)
+       {
+           edgey2 = miRoundCapClip (rightFace, isInt, &edge2, &edgeleft2);
+       }
+       isInt = FALSE;
+    }
+    if (!spanData)
+    {
+       points = (GdkRectangle*)ALLOCATE_LOCAL(sizeof(GdkRectangle) * GDK_GC_FBDATA(pGC)->values.line_width);
+       if (!points)
+           return;
+       oldPixel = GDK_GC_FBDATA(pGC)->values.foreground;
+       if (pixel->pixel != oldPixel.pixel)
+       {
+         gdk_gc_set_foreground(pGC, pixel);
+       }
+    }
+    else
+    {
+       points = (GdkRectangle*) g_malloc (GDK_GC_FBDATA(pGC)->values.line_width * sizeof (GdkRectangle));
+       if (!points)
+           return;
+       spanRec.points = points;
+    }
+    if (isInt)
+       n = miLineArcI(pDraw, pGC, xorgi, yorgi, points);
+    else
+       n = miLineArcD(pDraw, pGC, xorg, yorg, points,
+                      &edge1, edgey1, edgeleft1,
+                      &edge2, edgey2, edgeleft2);
+
+    if (!spanData)
+    {
+      gdk_fb_fill_spans(pDraw, pGC, points, n);
+      DEALLOCATE_LOCAL(points);
+      if (pixel->pixel != oldPixel.pixel)
+       {
+         gdk_gc_set_foreground(pGC, &oldPixel);
+       }
+    }
+    else
+    {
+       spanRec.count = n;
+       AppendSpanGroup (pGC, pixel, &spanRec, spanData)
+    }
+}
+
+void
+miLineProjectingCap (pDrawable, pGC, pixel, spanData, face, isLeft, xorg, yorg, isInt)
+    GdkDrawable*           pDrawable;
+    register GdkGC*  pGC;
+    GdkColor *pixel;
+    SpanDataPtr            spanData;
+    register LineFacePtr face;
+    gboolean       isLeft;
+    double         xorg, yorg;
+    gboolean       isInt;
+{
+    int        xorgi = 0, yorgi = 0;
+    int        lw;
+    PolyEdgeRec        lefts[2], rights[2];
+    int                lefty, righty, topy, bottomy;
+    PolyEdgePtr left, right;
+    PolyEdgePtr        top, bottom;
+    double     xa,ya;
+    double     k;
+    double     xap, yap;
+    int                dx, dy;
+    double     projectXoff, projectYoff;
+    double     maxy;
+    int                finaly;
+    
+    if (isInt)
+    {
+       xorgi = face->x;
+       yorgi = face->y;
+    }
+    lw = GDK_GC_FBDATA(pGC)->values.line_width;
+    dx = face->dx;
+    dy = face->dy;
+    k = face->k;
+    if (dy == 0)
+    {
+       lefts[0].height = lw;
+       lefts[0].x = xorgi;
+       if (isLeft)
+           lefts[0].x -= (lw >> 1);
+       lefts[0].stepx = 0;
+       lefts[0].signdx = 1;
+       lefts[0].e = -lw;
+       lefts[0].dx = 0;
+       lefts[0].dy = lw;
+       rights[0].height = lw;
+       rights[0].x = xorgi;
+       if (!isLeft)
+           rights[0].x += ((lw + 1) >> 1);
+       rights[0].stepx = 0;
+       rights[0].signdx = 1;
+       rights[0].e = -lw;
+       rights[0].dx = 0;
+       rights[0].dy = lw;
+       miFillPolyHelper (pDrawable, pGC, pixel, spanData, yorgi - (lw >> 1), lw,
+                         lefts, rights, 1, 1);
+    }
+    else if (dx == 0)
+    {
+       topy = yorgi;
+       bottomy = yorgi + dy;
+       if (isLeft)
+           topy -= (lw >> 1);
+       else
+           bottomy += (lw >> 1);
+       lefts[0].height = bottomy - topy;
+       lefts[0].x = xorgi - (lw >> 1);
+       lefts[0].stepx = 0;
+       lefts[0].signdx = 1;
+       lefts[0].e = -dy;
+       lefts[0].dx = dx;
+       lefts[0].dy = dy;
+
+       rights[0].height = bottomy - topy;
+       rights[0].x = lefts[0].x + (lw-1);
+       rights[0].stepx = 0;
+       rights[0].signdx = 1;
+       rights[0].e = -dy;
+       rights[0].dx = dx;
+       rights[0].dy = dy;
+       miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy, bottomy - topy, lefts, rights, 1, 1);
+    }
+    else
+    {
+       xa = face->xa;
+       ya = face->ya;
+       projectXoff = -ya;
+       projectYoff = xa;
+       if (dx < 0)
+       {
+           right = &rights[1];
+           left = &lefts[0];
+           top = &rights[0];
+           bottom = &lefts[1];
+       }
+       else
+       {
+           right = &rights[0];
+           left = &lefts[1];
+           top = &lefts[0];
+           bottom = &rights[1];
+       }
+       if (isLeft)
+       {
+           righty = miPolyBuildEdge (xa, ya,
+                    k, dx, dy, xorgi, yorgi, 0, right);
+           
+           xa = -xa;
+           ya = -ya;
+           k = -k;
+           lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
+                                    k, dx, dy, xorgi, yorgi, 1, left);
+           if (dx > 0)
+           {
+               ya = -ya;
+               xa = -xa;
+           }
+           xap = xa - projectXoff;
+           yap = ya - projectYoff;
+           topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
+                                   -dy, dx, xorgi, yorgi, dx > 0, top);
+           bottomy = miPolyBuildEdge (xa, ya,
+                                      0.0, -dy, dx, xorgi, yorgi, dx < 0, bottom);
+           maxy = -ya;
+       }
+       else
+       {
+           righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
+                    k, dx, dy, xorgi, yorgi, 0, right);
+           
+           xa = -xa;
+           ya = -ya;
+           k = -k;
+           lefty = miPolyBuildEdge (xa, ya,
+                   k, dx, dy, xorgi, yorgi, 1, left);
+           if (dx > 0)
+           {
+               ya = -ya;
+               xa = -xa;
+           }
+           xap = xa - projectXoff;
+           yap = ya - projectYoff;
+           topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, xorgi, xorgi, dx > 0, top);
+           bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
+                                      -dy, dx, xorgi, xorgi, dx < 0, bottom);
+           maxy = -ya + projectYoff;
+       }
+       finaly = ICEIL(maxy) + yorgi;
+       if (dx < 0)
+       {
+           left->height = bottomy - lefty;
+           right->height = finaly - righty;
+           top->height = righty - topy;
+       }
+       else
+       {
+           right->height =  bottomy - righty;
+           left->height = finaly - lefty;
+           top->height = lefty - topy;
+       }
+       bottom->height = finaly - bottomy;
+       miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy,
+                    bottom->height + bottomy - topy, lefts, rights, 2, 2);
+    }
+}
+
+static void
+miWideSegment (GdkDrawable *pDrawable, GdkGC *pGC, GdkColor *pixel, SpanDataPtr spanData,
+              int x1, int y1, int x2, int y2, gboolean projectLeft, gboolean projectRight, LineFacePtr leftFace, LineFacePtr rightFace)
+{
+    double     l, L, r;
+    double     xa, ya;
+    double     projectXoff = 0.0, projectYoff = 0.0;
+    double     k;
+    double     maxy;
+    int                x, y;
+    int                dx, dy;
+    int                finaly;
+    PolyEdgePtr left, right;
+    PolyEdgePtr        top, bottom;
+    int                lefty, righty, topy, bottomy;
+    int                signdx;
+    PolyEdgeRec        lefts[2], rights[2];
+    LineFacePtr        tface;
+    int                lw = GDK_GC_FBDATA(pGC)->values.line_width;
+
+    g_assert(leftFace);
+    /* draw top-to-bottom always */
+    if (y2 < y1 || (y2 == y1 && x2 < x1))
+    {
+       x = x1;
+       x1 = x2;
+       x2 = x;
+
+       y = y1;
+       y1 = y2;
+       y2 = y;
+
+       x = projectLeft;
+       projectLeft = projectRight;
+       projectRight = x;
+
+       tface = leftFace;
+       leftFace = rightFace;
+       rightFace = tface;
+    }
+
+    dy = y2 - y1;
+    signdx = 1;
+    dx = x2 - x1;
+    if (dx < 0)
+       signdx = -1;
+
+    g_assert(leftFace);
+    leftFace->x = x1;
+    leftFace->y = y1;
+    leftFace->dx = dx;
+    leftFace->dy = dy;
+
+    rightFace->x = x2;
+    rightFace->y = y2;
+    rightFace->dx = -dx;
+    rightFace->dy = -dy;
+
+    if (dy == 0)
+    {
+       rightFace->xa = 0;
+       rightFace->ya = (double) lw / 2.0;
+       rightFace->k = -(double) (lw * dx) / 2.0;
+       leftFace->xa = 0;
+       leftFace->ya = -rightFace->ya;
+       leftFace->k = rightFace->k;
+       x = x1;
+       if (projectLeft)
+           x -= (lw >> 1);
+       y = y1 - (lw >> 1);
+       dx = x2 - x;
+       if (projectRight)
+           dx += ((lw + 1) >> 1);
+       dy = lw;
+       miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
+                             x, y, dx, dy);
+    }
+    else if (dx == 0)
+    {
+       leftFace->xa =  (double) lw / 2.0;
+       leftFace->ya = 0;
+       leftFace->k = (double) (lw * dy) / 2.0;
+       rightFace->xa = -leftFace->xa;
+       rightFace->ya = 0;
+       rightFace->k = leftFace->k;
+       y = y1;
+       if (projectLeft)
+           y -= lw >> 1;
+       x = x1 - (lw >> 1);
+       dy = y2 - y;
+       if (projectRight)
+           dy += ((lw + 1) >> 1);
+       dx = lw;
+       miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
+                             x, y, dx, dy);
+    }
+    else
+    {
+       l = ((double) lw) / 2.0;
+       L = hypot ((double) dx, (double) dy);
+
+       if (dx < 0)
+       {
+           right = &rights[1];
+           left = &lefts[0];
+           top = &rights[0];
+           bottom = &lefts[1];
+       }
+       else
+       {
+           right = &rights[0];
+           left = &lefts[1];
+           top = &lefts[0];
+           bottom = &rights[1];
+       }
+       r = l / L;
+
+       /* coord of upper bound at integral y */
+       ya = -r * dx;
+       xa = r * dy;
+
+       if (projectLeft | projectRight)
+       {
+           projectXoff = -ya;
+           projectYoff = xa;
+       }
+
+       /* xa * dy - ya * dx */
+       k = l * L;
+
+       leftFace->xa = xa;
+       leftFace->ya = ya;
+       leftFace->k = k;
+       rightFace->xa = -xa;
+       rightFace->ya = -ya;
+       rightFace->k = k;
+
+       if (projectLeft)
+           righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
+                                     k, dx, dy, x1, y1, 0, right);
+       else
+           righty = miPolyBuildEdge (xa, ya,
+                                     k, dx, dy, x1, y1, 0, right);
+
+       /* coord of lower bound at integral y */
+       ya = -ya;
+       xa = -xa;
+
+       /* xa * dy - ya * dx */
+       k = - k;
+
+       if (projectLeft)
+           lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
+                                    k, dx, dy, x1, y1, 1, left);
+       else
+           lefty = miPolyBuildEdge (xa, ya,
+                                    k, dx, dy, x1, y1, 1, left);
+
+       /* coord of top face at integral y */
+
+       if (signdx > 0)
+       {
+           ya = -ya;
+           xa = -xa;
+       }
+
+       if (projectLeft)
+       {
+           double xap = xa - projectXoff;
+           double yap = ya - projectYoff;
+           topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
+                                   -dy, dx, x1, y1, dx > 0, top);
+       }
+       else
+           topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, x1, y1, dx > 0, top);
+
+       /* coord of bottom face at integral y */
+
+       if (projectRight)
+       {
+           double xap = xa + projectXoff;
+           double yap = ya + projectYoff;
+           bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
+                                      -dy, dx, x2, y2, dx < 0, bottom);
+           maxy = -ya + projectYoff;
+       }
+       else
+       {
+           bottomy = miPolyBuildEdge (xa, ya,
+                                      0.0, -dy, dx, x2, y2, dx < 0, bottom);
+           maxy = -ya;
+       }
+
+       finaly = ICEIL (maxy) + y2;
+
+       if (dx < 0)
+       {
+           left->height = bottomy - lefty;
+           right->height = finaly - righty;
+           top->height = righty - topy;
+       }
+       else
+       {
+           right->height =  bottomy - righty;
+           left->height = finaly - lefty;
+           top->height = lefty - topy;
+       }
+       bottom->height = finaly - bottomy;
+       miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy,
+                         bottom->height + bottomy - topy, lefts, rights, 2, 2);
+    }
+}
+
+SpanDataPtr
+miSetupSpanData (pGC, spanData, npt)
+    register GdkGC* pGC;
+    SpanDataPtr        spanData;
+    int                npt;
+{
+    if ((npt < 3 && GDK_GC_FBDATA(pGC)->values.cap_style != GDK_CAP_ROUND) || miSpansEasyRop(GDK_GC_FBDATA(pGC)->alu))
+       return (SpanDataPtr) NULL;
+    if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH)
+       miInitSpanGroup (&spanData->bgGroup);
+    miInitSpanGroup (&spanData->fgGroup);
+    return spanData;
+}
+
+void
+miCleanupSpanData (pDrawable, pGC, spanData)
+    GdkDrawable*       pDrawable;
+    GdkGC*     pGC;
+    SpanDataPtr        spanData;
+{
+    if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH)
+    {
+       GdkColor oldPixel, pixel;
+       
+       pixel = GDK_GC_FBDATA(pGC)->values.background;
+       oldPixel = GDK_GC_FBDATA(pGC)->values.foreground;
+       if (pixel.pixel != oldPixel.pixel)
+         gdk_gc_set_foreground(pGC, &pixel);
+       miFillUniqueSpanGroup (pDrawable, pGC, &spanData->bgGroup);
+       miFreeSpanGroup (&spanData->bgGroup);
+       if (pixel.pixel != oldPixel.pixel)
+         gdk_gc_set_foreground(pGC, &oldPixel);
+    }
+    miFillUniqueSpanGroup (pDrawable, pGC, &spanData->fgGroup);
+    miFreeSpanGroup (&spanData->fgGroup);
+}
+
+void
+miWideLine (pDrawable, pGC, mode, npt, pPts)
+    GdkDrawable*       pDrawable;
+    register GdkGC* pGC;
+    int                mode;
+    register int npt;
+    register GdkPoint* pPts;
+{
+    int                    x1, y1, x2, y2;
+    SpanDataRec            spanDataRec;
+    SpanDataPtr            spanData;
+    GdkColor pixel;
+    gboolean       projectLeft, projectRight;
+    LineFaceRec            leftFace, rightFace, prevRightFace;
+    LineFaceRec            firstFace;
+    register int    first;
+    gboolean       somethingDrawn = FALSE;
+    gboolean       selfJoin;
+
+    spanData = miSetupSpanData (pGC, &spanDataRec, npt);
+    pixel = GDK_GC_FBDATA(pGC)->values.foreground;
+    x2 = pPts->x;
+    y2 = pPts->y;
+    first = TRUE;
+    selfJoin = FALSE;
+    if (npt > 1)
+    {
+      if (0 /* mode == CoordModePrevious*/)
+       {
+           int nptTmp;
+           GdkPoint* pPtsTmp;
+    
+           x1 = x2;
+           y1 = y2;
+           nptTmp = npt;
+           pPtsTmp = pPts + 1;
+           while (--nptTmp)
+           {
+               x1 += pPtsTmp->x;
+               y1 += pPtsTmp->y;
+               ++pPtsTmp;
+           }
+           if (x2 == x1 && y2 == y1)
+               selfJoin = TRUE;
+       }
+       else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y)
+       {
+           selfJoin = TRUE;
+       }
+    }
+    projectLeft = GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_PROJECTING && !selfJoin;
+    projectRight = FALSE;
+    while (--npt)
+    {
+       x1 = x2;
+       y1 = y2;
+       ++pPts;
+       x2 = pPts->x;
+       y2 = pPts->y;
+       if (0 /* mode == CoordModePrevious */)
+       {
+           x2 += x1;
+           y2 += y1;
+       }
+       if (x1 != x2 || y1 != y2)
+       {
+           somethingDrawn = TRUE;
+           if (npt == 1 && GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_PROJECTING && !selfJoin)
+               projectRight = TRUE;
+           miWideSegment (pDrawable, pGC, &pixel, spanData, x1, y1, x2, y2,
+                          projectLeft, projectRight, &leftFace, &rightFace);
+           if (first)
+           {
+               if (selfJoin)
+                   firstFace = leftFace;
+               else if (GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_ROUND)
+               {
+                   if (GDK_GC_FBDATA(pGC)->values.line_width == 1 && !spanData)
+                       miLineOnePoint (pDrawable, pGC, pixel, spanData, x1, y1);
+                   else
+                       miLineArc (pDrawable, pGC, pixel, spanData,
+                                  &leftFace, (LineFacePtr) NULL,
+                                  (double)0.0, (double)0.0,
+                                  TRUE);
+               }
+           }
+           else
+           {
+               miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace,
+                           &prevRightFace);
+           }
+           prevRightFace = rightFace;
+           first = FALSE;
+           projectLeft = FALSE;
+       }
+       if (npt == 1 && somethingDrawn)
+       {
+           if (selfJoin)
+               miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace,
+                           &rightFace);
+           else if (GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_ROUND)
+           {
+               if (GDK_GC_FBDATA(pGC)->values.line_width == 1 && !spanData)
+                   miLineOnePoint (pDrawable, pGC, pixel, spanData, x2, y2);
+               else
+                   miLineArc (pDrawable, pGC, pixel, spanData,
+                              (LineFacePtr) NULL, &rightFace,
+                              (double)0.0, (double)0.0,
+                              TRUE);
+           }
+       }
+    }
+    /* handle crock where all points are coincedent */
+    if (!somethingDrawn)
+    {
+       projectLeft = GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_PROJECTING;
+       miWideSegment (pDrawable, pGC, &pixel, spanData,
+                      x2, y2, x2, y2, projectLeft, projectLeft,
+                      &leftFace, &rightFace);
+       if (GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_ROUND)
+       {
+           miLineArc (pDrawable, pGC, pixel, spanData,
+                      &leftFace, (LineFacePtr) NULL,
+                      (double)0.0, (double)0.0,
+                      TRUE);
+           rightFace.dx = -1;  /* sleezy hack to make it work */
+           miLineArc (pDrawable, pGC, pixel, spanData,
+                      (LineFacePtr) NULL, &rightFace,
+                      (double)0.0, (double)0.0,
+                      TRUE);
+       }
+    }
+    if (spanData)
+       miCleanupSpanData (pDrawable, pGC, spanData);
+}
+
+#define V_TOP      0
+#define V_RIGHT            1
+#define V_BOTTOM    2
+#define V_LEFT     3
+
+static void
+miWideDashSegment (pDrawable, pGC, spanData, pDashOffset, pDashIndex,
+          x1, y1, x2, y2, projectLeft, projectRight, leftFace, rightFace)
+    GdkDrawable*           pDrawable;
+    register GdkGC*  pGC;
+    int                    *pDashOffset, *pDashIndex;
+    SpanDataPtr            spanData;
+    int                    x1, y1, x2, y2;
+    gboolean       projectLeft, projectRight;
+    LineFacePtr            leftFace, rightFace;
+{
+    int                    dashIndex, dashRemain;
+    unsigned char   *pDash;
+    double         L, l;
+    double         k;
+    PolyVertexRec   vertices[4];
+    PolyVertexRec   saveRight, saveBottom;
+    PolySlopeRec    slopes[4];
+    PolyEdgeRec            left[2], right[2];
+    LineFaceRec            lcapFace, rcapFace;
+    int                    nleft, nright;
+    int                    h;
+    int                    y;
+    int                    dy, dx;
+    GdkColor pixel;
+    double         LRemain;
+    double         r;
+    double         rdx, rdy;
+    double         dashDx, dashDy;
+    double         saveK = 0.0;
+    gboolean       first = TRUE;
+    double         lcenterx, lcentery, rcenterx = 0.0, rcentery = 0.0;
+    GdkColor fgPixel, bgPixel;
+    
+    dx = x2 - x1;
+    dy = y2 - y1;
+    dashIndex = *pDashIndex;
+    pDash = GDK_GC_FBDATA(pGC)->dash_list;
+    dashRemain = pDash[dashIndex] - *pDashOffset;
+    fgPixel = GDK_GC_FBDATA(pGC)->values.foreground;
+    bgPixel = GDK_GC_FBDATA(pGC)->values.background;
+    if (GDK_GC_FBDATA(pGC)->values.fill == GDK_OPAQUE_STIPPLED ||
+       GDK_GC_FBDATA(pGC)->values.fill == GDK_TILED)
+    {
+       bgPixel = fgPixel;
+    }
+
+    l = ((double) GDK_GC_FBDATA(pGC)->values.line_width) / 2.0;
+    if (dx == 0)
+    {
+       L = dy;
+       rdx = 0;
+       rdy = l;
+       if (dy < 0)
+       {
+           L = -dy;
+           rdy = -l;
+       }
+    }
+    else if (dy == 0)
+    {
+       L = dx;
+       rdx = l;
+       rdy = 0;
+       if (dx < 0)
+       {
+           L = -dx;
+           rdx = -l;
+       }
+    }
+    else
+    {
+       L = hypot ((double) dx, (double) dy);
+       r = l / L;
+
+       rdx = r * dx;
+       rdy = r * dy;
+    }
+    k = l * L;
+    LRemain = L;
+    /* All position comments are relative to a line with dx and dy > 0,
+     * but the code does not depend on this */
+    /* top */
+    slopes[V_TOP].dx = dx;
+    slopes[V_TOP].dy = dy;
+    slopes[V_TOP].k = k;
+    /* right */
+    slopes[V_RIGHT].dx = -dy;
+    slopes[V_RIGHT].dy = dx;
+    slopes[V_RIGHT].k = 0;
+    /* bottom */
+    slopes[V_BOTTOM].dx = -dx;
+    slopes[V_BOTTOM].dy = -dy;
+    slopes[V_BOTTOM].k = k;
+    /* left */
+    slopes[V_LEFT].dx = dy;
+    slopes[V_LEFT].dy = -dx;
+    slopes[V_LEFT].k = 0;
+
+    /* preload the start coordinates */
+    vertices[V_RIGHT].x = vertices[V_TOP].x = rdy;
+    vertices[V_RIGHT].y = vertices[V_TOP].y = -rdx;
+
+    vertices[V_BOTTOM].x = vertices[V_LEFT].x = -rdy;
+    vertices[V_BOTTOM].y = vertices[V_LEFT].y = rdx;
+
+    if (projectLeft)
+    {
+       vertices[V_TOP].x -= rdx;
+       vertices[V_TOP].y -= rdy;
+
+       vertices[V_LEFT].x -= rdx;
+       vertices[V_LEFT].y -= rdy;
+
+       slopes[V_LEFT].k = rdx * dx + rdy * dy;
+    }
+
+    lcenterx = x1;
+    lcentery = y1;
+
+    if (GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_ROUND)
+    {
+       lcapFace.dx = dx;
+       lcapFace.dy = dy;
+       lcapFace.x = x1;
+       lcapFace.y = y1;
+
+       rcapFace.dx = -dx;
+       rcapFace.dy = -dy;
+       rcapFace.x = x1;
+       rcapFace.y = y1;
+    }
+    while (LRemain > dashRemain)
+    {
+       dashDx = (dashRemain * dx) / L;
+       dashDy = (dashRemain * dy) / L;
+
+       rcenterx = lcenterx + dashDx;
+       rcentery = lcentery + dashDy;
+
+       vertices[V_RIGHT].x += dashDx;
+       vertices[V_RIGHT].y += dashDy;
+
+       vertices[V_BOTTOM].x += dashDx;
+       vertices[V_BOTTOM].y += dashDy;
+
+       slopes[V_RIGHT].k = vertices[V_RIGHT].x * dx + vertices[V_RIGHT].y * dy;
+
+       if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH || !(dashIndex & 1))
+       {
+           if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_ON_OFF_DASH &&
+               GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_PROJECTING)
+           {
+               saveRight = vertices[V_RIGHT];
+               saveBottom = vertices[V_BOTTOM];
+               saveK = slopes[V_RIGHT].k;
+               
+               if (!first)
+               {
+                   vertices[V_TOP].x -= rdx;
+                   vertices[V_TOP].y -= rdy;
+    
+                   vertices[V_LEFT].x -= rdx;
+                   vertices[V_LEFT].y -= rdy;
+
+                   slopes[V_LEFT].k = vertices[V_LEFT].x *
+                                      slopes[V_LEFT].dy -
+                                      vertices[V_LEFT].y *
+                                      slopes[V_LEFT].dx;
+               }
+               
+               vertices[V_RIGHT].x += rdx;
+               vertices[V_RIGHT].y += rdy;
+
+               vertices[V_BOTTOM].x += rdx;
+               vertices[V_BOTTOM].y += rdy;
+
+               slopes[V_RIGHT].k = vertices[V_RIGHT].x *
+                                  slopes[V_RIGHT].dy -
+                                  vertices[V_RIGHT].y *
+                                  slopes[V_RIGHT].dx;
+           }
+           y = miPolyBuildPoly (vertices, slopes, 4, x1, y1,
+                                left, right, &nleft, &nright, &h);
+           pixel = (dashIndex & 1) ? bgPixel : fgPixel;
+           miFillPolyHelper (pDrawable, pGC, &pixel, spanData, y, h, left, right, nleft, nright);
+
+           if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_ON_OFF_DASH)
+           {
+               switch (GDK_GC_FBDATA(pGC)->values.cap_style)
+               {
+               case GDK_CAP_PROJECTING:
+                   vertices[V_BOTTOM] = saveBottom;
+                   vertices[V_RIGHT] = saveRight;
+                   slopes[V_RIGHT].k = saveK;
+                   break;
+               case GDK_CAP_ROUND:
+                   if (!first)
+                   {
+                       if (dx < 0)
+                       {
+                           lcapFace.xa = -vertices[V_LEFT].x;
+                           lcapFace.ya = -vertices[V_LEFT].y;
+                           lcapFace.k = slopes[V_LEFT].k;
+                       }
+                       else
+                       {
+                           lcapFace.xa = vertices[V_TOP].x;
+                           lcapFace.ya = vertices[V_TOP].y;
+                           lcapFace.k = -slopes[V_LEFT].k;
+                       }
+                       miLineArc (pDrawable, pGC, pixel, spanData,
+                                  &lcapFace, (LineFacePtr) NULL,
+                                  lcenterx, lcentery, FALSE);
+                   }
+                   if (dx < 0)
+                   {
+                       rcapFace.xa = vertices[V_BOTTOM].x;
+                       rcapFace.ya = vertices[V_BOTTOM].y;
+                       rcapFace.k = slopes[V_RIGHT].k;
+                   }
+                   else
+                   {
+                       rcapFace.xa = -vertices[V_RIGHT].x;
+                       rcapFace.ya = -vertices[V_RIGHT].y;
+                       rcapFace.k = -slopes[V_RIGHT].k;
+                   }
+                   miLineArc (pDrawable, pGC, pixel, spanData,
+                              (LineFacePtr) NULL, &rcapFace,
+                              rcenterx, rcentery, FALSE);
+                   break;
+               default:
+                 break;
+               }
+           }
+       }
+       LRemain -= dashRemain;
+       ++dashIndex;
+       if (dashIndex == GDK_GC_FBDATA(pGC)->dash_list_len)
+           dashIndex = 0;
+       dashRemain = pDash[dashIndex];
+
+       lcenterx = rcenterx;
+       lcentery = rcentery;
+
+       vertices[V_TOP] = vertices[V_RIGHT];
+       vertices[V_LEFT] = vertices[V_BOTTOM];
+       slopes[V_LEFT].k = -slopes[V_RIGHT].k;
+       first = FALSE;
+    }
+
+    if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH || !(dashIndex & 1))
+    {
+       vertices[V_TOP].x -= dx;
+       vertices[V_TOP].y -= dy;
+
+       vertices[V_LEFT].x -= dx;
+       vertices[V_LEFT].y -= dy;
+
+       vertices[V_RIGHT].x = rdy;
+       vertices[V_RIGHT].y = -rdx;
+
+       vertices[V_BOTTOM].x = -rdy;
+       vertices[V_BOTTOM].y = rdx;
+
+       
+       if (projectRight)
+       {
+           vertices[V_RIGHT].x += rdx;
+           vertices[V_RIGHT].y += rdy;
+    
+           vertices[V_BOTTOM].x += rdx;
+           vertices[V_BOTTOM].y += rdy;
+           slopes[V_RIGHT].k = vertices[V_RIGHT].x *
+                               slopes[V_RIGHT].dy -
+                               vertices[V_RIGHT].y *
+                               slopes[V_RIGHT].dx;
+       }
+       else
+           slopes[V_RIGHT].k = 0;
+
+       if (!first && GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_ON_OFF_DASH &&
+           GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_PROJECTING)
+       {
+           vertices[V_TOP].x -= rdx;
+           vertices[V_TOP].y -= rdy;
+
+           vertices[V_LEFT].x -= rdx;
+           vertices[V_LEFT].y -= rdy;
+           slopes[V_LEFT].k = vertices[V_LEFT].x *
+                              slopes[V_LEFT].dy -
+                              vertices[V_LEFT].y *
+                              slopes[V_LEFT].dx;
+       }
+       else
+           slopes[V_LEFT].k += dx * dx + dy * dy;
+
+
+       y = miPolyBuildPoly (vertices, slopes, 4, x2, y2,
+                            left, right, &nleft, &nright, &h);
+
+       pixel = (dashIndex & 1) ? GDK_GC_FBDATA(pGC)->values.background : GDK_GC_FBDATA(pGC)->values.foreground;
+       miFillPolyHelper (pDrawable, pGC, &pixel, spanData, y, h, left, right, nleft, nright);
+       if (!first && GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_ON_OFF_DASH &&
+           GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_ROUND)
+       {
+           lcapFace.x = x2;
+           lcapFace.y = y2;
+           if (dx < 0)
+           {
+               lcapFace.xa = -vertices[V_LEFT].x;
+               lcapFace.ya = -vertices[V_LEFT].y;
+               lcapFace.k = slopes[V_LEFT].k;
+           }
+           else
+           {
+               lcapFace.xa = vertices[V_TOP].x;
+               lcapFace.ya = vertices[V_TOP].y;
+               lcapFace.k = -slopes[V_LEFT].k;
+           }
+           miLineArc (pDrawable, pGC, pixel, spanData,
+                      &lcapFace, (LineFacePtr) NULL,
+                      rcenterx, rcentery, FALSE);
+       }
+    }
+    dashRemain = ((double) dashRemain) - LRemain;
+    if (dashRemain == 0)
+    {
+       dashIndex++;
+       if (dashIndex == GDK_GC_FBDATA(pGC)->dash_list_len)
+           dashIndex = 0;
+       dashRemain = pDash[dashIndex];
+    }
+
+    leftFace->x = x1;
+    leftFace->y = y1;
+    leftFace->dx = dx;
+    leftFace->dy = dy;
+    leftFace->xa = rdy;
+    leftFace->ya = -rdx;
+    leftFace->k = k;
+
+    rightFace->x = x2;
+    rightFace->y = y2;
+    rightFace->dx = -dx;
+    rightFace->dy = -dy;
+    rightFace->xa = -rdy;
+    rightFace->ya = rdx;
+    rightFace->k = k;
+
+    *pDashIndex = dashIndex;
+    *pDashOffset = pDash[dashIndex] - dashRemain;
+}
+
+void
+miWideDash (pDrawable, pGC, mode, npt, pPts)
+    GdkDrawable*       pDrawable;
+    register GdkGC* pGC;
+    int                mode;
+    register int npt;
+    register GdkPoint* pPts;
+{
+    int                    x1, y1, x2, y2;
+    GdkColor pixel;
+    gboolean       projectLeft, projectRight;
+    LineFaceRec            leftFace, rightFace, prevRightFace;
+    LineFaceRec            firstFace;
+    int                    first;
+    int                    dashIndex, dashOffset;
+    register int    prevDashIndex;
+    SpanDataRec            spanDataRec;
+    SpanDataPtr            spanData;
+    gboolean       somethingDrawn = FALSE;
+    gboolean       selfJoin;
+    gboolean       endIsFg = FALSE, startIsFg = FALSE;
+    gboolean            firstIsFg = FALSE, prevIsFg = FALSE;
+
+#ifndef XFree86Server
+    /* XXX backward compatibility */
+    if (GDK_GC_FBDATA(pGC)->values.line_width == 0)
+    {
+       miZeroDashLine (pDrawable, pGC, mode, npt, pPts);
+       return;
+    }
+#endif
+    if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH && 
+       (GDK_GC_FBDATA(pGC)->values.fill == GDK_OPAQUE_STIPPLED || GDK_GC_FBDATA(pGC)->values.fill == GDK_TILED))
+    {
+       miWideLine (pDrawable, pGC, mode, npt, pPts);
+       return;
+    }
+    if (npt == 0)
+       return;
+    spanData = miSetupSpanData (pGC, &spanDataRec, npt);
+    x2 = pPts->x;
+    y2 = pPts->y;
+    first = TRUE;
+    selfJoin = FALSE;
+    if (0 /* mode == CoordModePrevious */)
+    {
+       int nptTmp;
+       GdkPoint* pPtsTmp;
+
+       x1 = x2;
+       y1 = y2;
+       nptTmp = npt;
+       pPtsTmp = pPts + 1;
+       while (--nptTmp)
+       {
+           x1 += pPtsTmp->x;
+           y1 += pPtsTmp->y;
+           ++pPtsTmp;
+       }
+       if (x2 == x1 && y2 == y1)
+           selfJoin = TRUE;
+    }
+    else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y)
+    {
+       selfJoin = TRUE;
+    }
+    projectLeft = GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_PROJECTING && !selfJoin;
+    projectRight = FALSE;
+    dashIndex = 0;
+    dashOffset = 0;
+    miStepDash (GDK_GC_FBDATA(pGC)->dash_offset, &dashIndex,
+               GDK_GC_FBDATA(pGC)->dash_list, (int)GDK_GC_FBDATA(pGC)->dash_list_len, &dashOffset);
+    while (--npt)
+    {
+       x1 = x2;
+       y1 = y2;
+       ++pPts;
+       x2 = pPts->x;
+       y2 = pPts->y;
+       if (0 /* mode == CoordModePrevious */)
+       {
+           x2 += x1;
+           y2 += y1;
+       }
+       if (x1 != x2 || y1 != y2)
+       {
+           somethingDrawn = TRUE;
+           if (npt == 1 && GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_PROJECTING && 
+               (!selfJoin || !firstIsFg))
+               projectRight = TRUE;
+           prevDashIndex = dashIndex;
+           miWideDashSegment (pDrawable, pGC, spanData, &dashOffset, &dashIndex,
+                               x1, y1, x2, y2,
+                               projectLeft, projectRight, &leftFace, &rightFace);
+           startIsFg = !(prevDashIndex & 1);
+           endIsFg = (dashIndex & 1) ^ (dashOffset != 0);
+           if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH || startIsFg)
+           {
+               pixel = startIsFg ? GDK_GC_FBDATA(pGC)->values.foreground : GDK_GC_FBDATA(pGC)->values.background;
+               if (first || (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_ON_OFF_DASH && !prevIsFg))
+               {
+                   if (first && selfJoin)
+                   {
+                       firstFace = leftFace;
+                       firstIsFg = startIsFg;
+                   }
+                   else if (GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_ROUND)
+                       miLineArc (pDrawable, pGC, pixel, spanData,
+                                  &leftFace, (LineFacePtr) NULL,
+                                  (double)0.0, (double)0.0, TRUE);
+               }
+               else
+               {
+                   miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace,
+                               &prevRightFace);
+               }
+           }
+           prevRightFace = rightFace;
+           prevIsFg = endIsFg;
+           first = FALSE;
+           projectLeft = FALSE;
+       }
+       if (npt == 1 && somethingDrawn)
+       {
+           if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH || endIsFg)
+           {
+               pixel = endIsFg ? GDK_GC_FBDATA(pGC)->values.foreground : GDK_GC_FBDATA(pGC)->values.background;
+               if (selfJoin && (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH || firstIsFg))
+               {
+                   miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace,
+                               &rightFace);
+               }
+               else 
+               {
+                   if (GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_ROUND)
+                       miLineArc (pDrawable, pGC, pixel, spanData,
+                                   (LineFacePtr) NULL, &rightFace,
+                                   (double)0.0, (double)0.0, TRUE);
+               }
+           }
+           else
+           {
+               /* glue a cap to the start of the line if
+                * we're OnOffDash and ended on odd dash
+                */
+               if (selfJoin && firstIsFg)
+               {
+                   pixel = GDK_GC_FBDATA(pGC)->values.foreground;
+                   if (GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_PROJECTING)
+                       miLineProjectingCap (pDrawable, pGC, &pixel, spanData,
+                                   &firstFace, TRUE,
+                                   (double)0.0, (double)0.0, TRUE);
+                   else if (GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_ROUND)
+                       miLineArc (pDrawable, pGC, &pixel, spanData,
+                                   &firstFace, (LineFacePtr) NULL,
+                                   (double)0.0, (double)0.0, TRUE);
+               }
+           }
+       }
+    }
+    /* handle crock where all points are coincident */
+    if (!somethingDrawn && (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH || !(dashIndex & 1)))
+    {
+       /* not the same as endIsFg computation above */
+       pixel = (dashIndex & 1) ? GDK_GC_FBDATA(pGC)->values.background : GDK_GC_FBDATA(pGC)->values.foreground;
+       switch (GDK_GC_FBDATA(pGC)->values.cap_style) {
+       case GDK_CAP_ROUND:
+           miLineArc (pDrawable, pGC, pixel, spanData,
+                      (LineFacePtr) NULL, (LineFacePtr) NULL,
+                      (double)x2, (double)y2,
+                      FALSE);
+           break;
+       case GDK_CAP_PROJECTING:
+           x1 = GDK_GC_FBDATA(pGC)->values.line_width;
+           miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
+                                 x2 - (x1 >> 1), y2 - (x1 >> 1), x1, x1);
+           break;
+       default:
+         break;
+       }
+    }
+    if (spanData)
+       miCleanupSpanData (pDrawable, pGC, spanData);
+}
+
+/* these are stubs to allow old ddx miValidateGCs to work without change */
+
+void
+miMiter()
+{
+}
+
+void
+miNotMiter()
+{
+}
diff --git a/gdk/linux-fb/miwideline.h b/gdk/linux-fb/miwideline.h
new file mode 100644 (file)
index 0000000..a39b6c1
--- /dev/null
@@ -0,0 +1,254 @@
+/* $TOG: miwideline.h /main/12 1998/02/09 14:49:26 kaleb $ */
+/*
+
+Copyright 1988, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+*/
+/* $XFree86: xc/programs/Xserver/mi/miwideline.h,v 1.7 1998/10/04 09:39:35 dawes Exp $ */
+
+/* Author:  Keith Packard, MIT X Consortium */
+
+#ifndef MI_WIDELINE_H
+#define MI_WIDELINE_H 1
+
+#include "mispans.h"
+
+/* 
+ * interface data to span-merging polygon filler
+ */
+
+typedef struct _SpanData {
+    SpanGroup  fgGroup, bgGroup;
+} SpanDataRec, *SpanDataPtr;
+
+#define AppendSpanGroup(pGC, pixel, spanPtr, spanData) { \
+       SpanGroup   *group, *othergroup = NULL; \
+       if (pixel->pixel == GDK_GC_FBDATA(pGC)->values.foreground.pixel) \
+       { \
+           group = &spanData->fgGroup; \
+           if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH) \
+               othergroup = &spanData->bgGroup; \
+       } \
+       else \
+       { \
+           group = &spanData->bgGroup; \
+           othergroup = &spanData->fgGroup; \
+       } \
+       miAppendSpans (group, othergroup, spanPtr); \
+}
+
+/*
+ * Polygon edge description for integer wide-line routines
+ */
+
+typedef struct _PolyEdge {
+    int            height;     /* number of scanlines to process */
+    int            x;          /* starting x coordinate */
+    int            stepx;      /* fixed integral dx */
+    int            signdx;     /* variable dx sign */
+    int            e;          /* initial error term */
+    int            dy;
+    int            dx;
+} PolyEdgeRec, *PolyEdgePtr;
+
+#define SQSECANT 108.856472512142 /* 1/sin^2(11/2) - miter limit constant */
+
+/*
+ * types for general polygon routines
+ */
+
+typedef struct _PolyVertex {
+    double  x, y;
+} PolyVertexRec, *PolyVertexPtr;
+
+typedef struct _PolySlope {
+    int            dx, dy;
+    double  k;     /* x0 * dy - y0 * dx */
+} PolySlopeRec, *PolySlopePtr;
+
+/*
+ * Line face description for caps/joins
+ */
+
+typedef struct _LineFace {
+    double  xa, ya;
+    int            dx, dy;
+    int            x, y;
+    double  k;
+} LineFaceRec, *LineFacePtr;
+
+/*
+ * macros for polygon fillers
+ */
+
+#define MIPOLYRELOADLEFT    if (!left_height && left_count) { \
+                               left_height = left->height; \
+                               left_x = left->x; \
+                               left_stepx = left->stepx; \
+                               left_signdx = left->signdx; \
+                               left_e = left->e; \
+                               left_dy = left->dy; \
+                               left_dx = left->dx; \
+                               --left_count; \
+                               ++left; \
+                           }
+
+#define MIPOLYRELOADRIGHT   if (!right_height && right_count) { \
+                               right_height = right->height; \
+                               right_x = right->x; \
+                               right_stepx = right->stepx; \
+                               right_signdx = right->signdx; \
+                               right_e = right->e; \
+                               right_dy = right->dy; \
+                               right_dx = right->dx; \
+                               --right_count; \
+                               ++right; \
+                       }
+
+#define MIPOLYSTEPLEFT  left_x += left_stepx; \
+                       left_e += left_dx; \
+                       if (left_e > 0) \
+                       { \
+                           left_x += left_signdx; \
+                           left_e -= left_dy; \
+                       }
+
+#define MIPOLYSTEPRIGHT right_x += right_stepx; \
+                       right_e += right_dx; \
+                       if (right_e > 0) \
+                       { \
+                           right_x += right_signdx; \
+                           right_e -= right_dy; \
+                       }
+
+#define MILINESETPIXEL(pDrawable, pGC, pixel, oldPixel) { \
+    oldPixel = GDK_GC_FBDATA(pGC)->values.foreground; \
+    if (pixel->pixel != oldPixel.pixel) { \
+        gdk_gc_set_foreground(pGC, pixel); \
+    } \
+}
+#define MILINERESETPIXEL(pDrawable, pGC, pixel, oldPixel) { \
+    if (pixel->pixel != oldPixel.pixel) { \
+        gdk_gc_set_foreground(pGC, &oldPixel); \
+    } \
+}
+
+#ifndef ICEIL
+#ifdef NOINLINEICEIL
+#define ICEIL(x) ((int)ceil(x))
+#else
+#ifdef __GNUC__
+#define ICEIL ICIEL
+static __inline int ICEIL(x)
+    double x;
+{
+    int _cTmp = x;
+    return ((x == _cTmp) || (x < 0.0)) ? _cTmp : _cTmp+1;
+}
+#else
+#define ICEIL(x) ((((x) == (_cTmp = (x))) || ((x) < 0.0)) ? _cTmp : _cTmp+1)
+#define ICEILTEMPDECL static int _cTmp;
+#endif
+#endif
+#endif
+
+extern void miFillPolyHelper(
+#if NeedFunctionPrototypes
+    GdkDrawable* /*pDrawable*/,
+    GdkGC* /*pGC*/,
+    GdkColor * /*pixel*/,
+    SpanDataPtr /*spanData*/,
+    int /*y*/,
+    int /*overall_height*/,
+    PolyEdgePtr /*left*/,
+    PolyEdgePtr /*right*/,
+    int /*left_count*/,
+    int /*right_count*/
+#endif
+);
+extern int miRoundJoinFace(
+#if NeedFunctionPrototypes
+    LineFacePtr /*face*/,
+    PolyEdgePtr /*edge*/,
+    gboolean * /*leftEdge*/
+#endif
+);
+
+extern void miRoundJoinClip(
+#if NeedFunctionPrototypes
+    LineFacePtr /*pLeft*/,
+    LineFacePtr /*pRight*/,
+    PolyEdgePtr /*edge1*/,
+    PolyEdgePtr /*edge2*/,
+    int * /*y1*/,
+    int * /*y2*/,
+    gboolean * /*left1*/,
+    gboolean * /*left2*/
+#endif
+);
+
+extern int miRoundCapClip(
+#if NeedFunctionPrototypes
+    LineFacePtr /*face*/,
+    gboolean /*isInt*/,
+    PolyEdgePtr /*edge*/,
+    gboolean * /*leftEdge*/
+#endif
+);
+
+extern void miLineProjectingCap(
+#if NeedFunctionPrototypes
+    GdkDrawable* /*pDrawable*/,
+    GdkGC* /*pGC*/,
+    GdkColor * /*pixel*/,
+    SpanDataPtr /*spanData*/,
+    LineFacePtr /*face*/,
+    gboolean /*isLeft*/,
+    double /*xorg*/,
+    double /*yorg*/,
+    gboolean /*isInt*/
+#endif
+);
+
+extern SpanDataPtr miSetupSpanData(
+#if NeedFunctionPrototypes
+    GdkGC* /*pGC*/,
+    SpanDataPtr /*spanData*/,
+    int /*npt*/
+#endif
+);
+
+extern void miCleanupSpanData(
+#if NeedFunctionPrototypes
+    GdkDrawable* /*pDrawable*/,
+    GdkGC* /*pGC*/,
+    SpanDataPtr /*spanData*/
+#endif
+);
+
+extern int miPolyBuildEdge(double x0, double y0, double k, int dx, int dy,
+                               int xi, int yi, int left, PolyEdgePtr edge);
+extern int miPolyBuildPoly(PolyVertexPtr vertices, PolySlopePtr slopes,
+                               int count, int xi, int yi, PolyEdgePtr left,
+                               PolyEdgePtr right, int *pnleft, int *pnright,
+                               int *h);
+
+#endif
diff --git a/gdk/linux-fb/mizerclip.c b/gdk/linux-fb/mizerclip.c
new file mode 100644 (file)
index 0000000..145ccd9
--- /dev/null
@@ -0,0 +1,622 @@
+/* $XFree86: xc/programs/Xserver/mi/mizerclip.c,v 1.1 1999/10/13 22:33:13 dawes Exp $ */
+/***********************************************************
+
+Copyright 1987, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#include "mi.h"
+#include "miline.h"
+
+/*
+
+The bresenham error equation used in the mi/mfb/cfb line routines is:
+
+       e = error
+       dx = difference in raw X coordinates
+       dy = difference in raw Y coordinates
+       M = # of steps in X direction
+       N = # of steps in Y direction
+       B = 0 to prefer diagonal steps in a given octant,
+           1 to prefer axial steps in a given octant
+
+       For X major lines:
+               e = 2Mdy - 2Ndx - dx - B
+               -2dx <= e < 0
+
+       For Y major lines:
+               e = 2Ndx - 2Mdy - dy - B
+               -2dy <= e < 0
+
+At the start of the line, we have taken 0 X steps and 0 Y steps,
+so M = 0 and N = 0:
+
+       X major e = 2Mdy - 2Ndx - dx - B
+                 = -dx - B
+
+       Y major e = 2Ndx - 2Mdy - dy - B
+                 = -dy - B
+
+At the end of the line, we have taken dx X steps and dy Y steps,
+so M = dx and N = dy:
+
+       X major e = 2Mdy - 2Ndx - dx - B
+                 = 2dxdy - 2dydx - dx - B
+                 = -dx - B
+       Y major e = 2Ndx - 2Mdy - dy - B
+                 = 2dydx - 2dxdy - dy - B
+                 = -dy - B
+
+Thus, the error term is the same at the start and end of the line.
+
+Let us consider clipping an X coordinate.  There are 4 cases which
+represent the two independent cases of clipping the start vs. the
+end of the line and an X major vs. a Y major line.  In any of these
+cases, we know the number of X steps (M) and we wish to find the
+number of Y steps (N).  Thus, we will solve our error term equation.
+If we are clipping the start of the line, we will find the smallest
+N that satisfies our error term inequality.  If we are clipping the
+end of the line, we will find the largest number of Y steps that
+satisfies the inequality.  In that case, since we are representing
+the Y steps as (dy - N), we will actually want to solve for the
+smallest N in that equation.
+\f
+Case 1:  X major, starting X coordinate moved by M steps
+
+               -2dx <= 2Mdy - 2Ndx - dx - B < 0
+       2Ndx <= 2Mdy - dx - B + 2dx     2Ndx > 2Mdy - dx - B
+       2Ndx <= 2Mdy + dx - B           N > (2Mdy - dx - B) / 2dx
+       N <= (2Mdy + dx - B) / 2dx
+
+Since we are trying to find the smallest N that satisfies these
+equations, we should use the > inequality to find the smallest:
+
+       N = floor((2Mdy - dx - B) / 2dx) + 1
+         = floor((2Mdy - dx - B + 2dx) / 2dx)
+         = floor((2Mdy + dx - B) / 2dx)
+
+Case 1b: X major, ending X coordinate moved to M steps
+
+Same derivations as Case 1, but we want the largest N that satisfies
+the equations, so we use the <= inequality:
+
+       N = floor((2Mdy + dx - B) / 2dx)
+
+Case 2: X major, ending X coordinate moved by M steps
+
+               -2dx <= 2(dx - M)dy - 2(dy - N)dx - dx - B < 0
+               -2dx <= 2dxdy - 2Mdy - 2dxdy + 2Ndx - dx - B < 0
+               -2dx <= 2Ndx - 2Mdy - dx - B < 0
+       2Ndx >= 2Mdy + dx + B - 2dx     2Ndx < 2Mdy + dx + B
+       2Ndx >= 2Mdy - dx + B           N < (2Mdy + dx + B) / 2dx
+       N >= (2Mdy - dx + B) / 2dx
+
+Since we are trying to find the highest number of Y steps that
+satisfies these equations, we need to find the smallest N, so
+we should use the >= inequality to find the smallest:
+
+       N = ceiling((2Mdy - dx + B) / 2dx)
+         = floor((2Mdy - dx + B + 2dx - 1) / 2dx)
+         = floor((2Mdy + dx + B - 1) / 2dx)
+
+Case 2b: X major, starting X coordinate moved to M steps from end
+
+Same derivations as Case 2, but we want the smallest number of Y
+steps, so we want the highest N, so we use the < inequality:
+
+       N = ceiling((2Mdy + dx + B) / 2dx) - 1
+         = floor((2Mdy + dx + B + 2dx - 1) / 2dx) - 1
+         = floor((2Mdy + dx + B + 2dx - 1 - 2dx) / 2dx)
+         = floor((2Mdy + dx + B - 1) / 2dx)
+\f
+Case 3: Y major, starting X coordinate moved by M steps
+
+               -2dy <= 2Ndx - 2Mdy - dy - B < 0
+       2Ndx >= 2Mdy + dy + B - 2dy     2Ndx < 2Mdy + dy + B
+       2Ndx >= 2Mdy - dy + B           N < (2Mdy + dy + B) / 2dx
+       N >= (2Mdy - dy + B) / 2dx
+
+Since we are trying to find the smallest N that satisfies these
+equations, we should use the >= inequality to find the smallest:
+
+       N = ceiling((2Mdy - dy + B) / 2dx)
+         = floor((2Mdy - dy + B + 2dx - 1) / 2dx)
+         = floor((2Mdy - dy + B - 1) / 2dx) + 1
+
+Case 3b: Y major, ending X coordinate moved to M steps
+
+Same derivations as Case 3, but we want the largest N that satisfies
+the equations, so we use the < inequality:
+
+       N = ceiling((2Mdy + dy + B) / 2dx) - 1
+         = floor((2Mdy + dy + B + 2dx - 1) / 2dx) - 1
+         = floor((2Mdy + dy + B + 2dx - 1 - 2dx) / 2dx)
+         = floor((2Mdy + dy + B - 1) / 2dx)
+
+Case 4: Y major, ending X coordinate moved by M steps
+
+               -2dy <= 2(dy - N)dx - 2(dx - M)dy - dy - B < 0
+               -2dy <= 2dxdy - 2Ndx - 2dxdy + 2Mdy - dy - B < 0
+               -2dy <= 2Mdy - 2Ndx - dy - B < 0
+       2Ndx <= 2Mdy - dy - B + 2dy     2Ndx > 2Mdy - dy - B
+       2Ndx <= 2Mdy + dy - B           N > (2Mdy - dy - B) / 2dx
+       N <= (2Mdy + dy - B) / 2dx
+
+Since we are trying to find the highest number of Y steps that
+satisfies these equations, we need to find the smallest N, so
+we should use the > inequality to find the smallest:
+
+       N = floor((2Mdy - dy - B) / 2dx) + 1
+
+Case 4b: Y major, starting X coordinate moved to M steps from end
+
+Same analysis as Case 4, but we want the smallest number of Y steps
+which means the largest N, so we use the <= inequality:
+
+       N = floor((2Mdy + dy - B) / 2dx)
+\f
+Now let's try the Y coordinates, we have the same 4 cases.
+
+Case 5: X major, starting Y coordinate moved by N steps
+
+               -2dx <= 2Mdy - 2Ndx - dx - B < 0
+       2Mdy >= 2Ndx + dx + B - 2dx     2Mdy < 2Ndx + dx + B
+       2Mdy >= 2Ndx - dx + B           M < (2Ndx + dx + B) / 2dy
+       M >= (2Ndx - dx + B) / 2dy
+
+Since we are trying to find the smallest M, we use the >= inequality:
+
+       M = ceiling((2Ndx - dx + B) / 2dy)
+         = floor((2Ndx - dx + B + 2dy - 1) / 2dy)
+         = floor((2Ndx - dx + B - 1) / 2dy) + 1
+
+Case 5b: X major, ending Y coordinate moved to N steps
+
+Same derivations as Case 5, but we want the largest M that satisfies
+the equations, so we use the < inequality:
+
+       M = ceiling((2Ndx + dx + B) / 2dy) - 1
+         = floor((2Ndx + dx + B + 2dy - 1) / 2dy) - 1
+         = floor((2Ndx + dx + B + 2dy - 1 - 2dy) / 2dy)
+         = floor((2Ndx + dx + B - 1) / 2dy)
+
+Case 6: X major, ending Y coordinate moved by N steps
+
+               -2dx <= 2(dx - M)dy - 2(dy - N)dx - dx - B < 0
+               -2dx <= 2dxdy - 2Mdy - 2dxdy + 2Ndx - dx - B < 0
+               -2dx <= 2Ndx - 2Mdy - dx - B < 0
+       2Mdy <= 2Ndx - dx - B + 2dx     2Mdy > 2Ndx - dx - B
+       2Mdy <= 2Ndx + dx - B           M > (2Ndx - dx - B) / 2dy
+       M <= (2Ndx + dx - B) / 2dy
+
+Largest # of X steps means smallest M, so use the > inequality:
+
+       M = floor((2Ndx - dx - B) / 2dy) + 1
+
+Case 6b: X major, starting Y coordinate moved to N steps from end
+
+Same derivations as Case 6, but we want the smallest # of X steps
+which means the largest M, so use the <= inequality:
+
+       M = floor((2Ndx + dx - B) / 2dy)
+\f
+Case 7: Y major, starting Y coordinate moved by N steps
+
+               -2dy <= 2Ndx - 2Mdy - dy - B < 0
+       2Mdy <= 2Ndx - dy - B + 2dy     2Mdy > 2Ndx - dy - B
+       2Mdy <= 2Ndx + dy - B           M > (2Ndx - dy - B) / 2dy
+       M <= (2Ndx + dy - B) / 2dy
+
+To find the smallest M, use the > inequality:
+
+       M = floor((2Ndx - dy - B) / 2dy) + 1
+         = floor((2Ndx - dy - B + 2dy) / 2dy)
+         = floor((2Ndx + dy - B) / 2dy)
+
+Case 7b: Y major, ending Y coordinate moved to N steps
+
+Same derivations as Case 7, but we want the largest M that satisfies
+the equations, so use the <= inequality:
+
+       M = floor((2Ndx + dy - B) / 2dy)
+
+Case 8: Y major, ending Y coordinate moved by N steps
+
+               -2dy <= 2(dy - N)dx - 2(dx - M)dy - dy - B < 0
+               -2dy <= 2dxdy - 2Ndx - 2dxdy + 2Mdy - dy - B < 0
+               -2dy <= 2Mdy - 2Ndx - dy - B < 0
+       2Mdy >= 2Ndx + dy + B - 2dy     2Mdy < 2Ndx + dy + B
+       2Mdy >= 2Ndx - dy + B           M < (2Ndx + dy + B) / 2dy
+       M >= (2Ndx - dy + B) / 2dy
+
+To find the highest X steps, find the smallest M, use the >= inequality:
+
+       M = ceiling((2Ndx - dy + B) / 2dy)
+         = floor((2Ndx - dy + B + 2dy - 1) / 2dy)
+         = floor((2Ndx + dy + B - 1) / 2dy)
+
+Case 8b: Y major, starting Y coordinate moved to N steps from the end
+
+Same derivations as Case 8, but we want to find the smallest # of X
+steps which means the largest M, so we use the < inequality:
+
+       M = ceiling((2Ndx + dy + B) / 2dy) - 1
+         = floor((2Ndx + dy + B + 2dy - 1) / 2dy) - 1
+         = floor((2Ndx + dy + B + 2dy - 1 - 2dy) / 2dy)
+         = floor((2Ndx + dy + B - 1) / 2dy)
+\f
+So, our equations are:
+
+       1:  X major move x1 to x1+M     floor((2Mdy + dx - B) / 2dx)
+       1b: X major move x2 to x1+M     floor((2Mdy + dx - B) / 2dx)
+       2:  X major move x2 to x2-M     floor((2Mdy + dx + B - 1) / 2dx)
+       2b: X major move x1 to x2-M     floor((2Mdy + dx + B - 1) / 2dx)
+
+       3:  Y major move x1 to x1+M     floor((2Mdy - dy + B - 1) / 2dx) + 1
+       3b: Y major move x2 to x1+M     floor((2Mdy + dy + B - 1) / 2dx)
+       4:  Y major move x2 to x2-M     floor((2Mdy - dy - B) / 2dx) + 1
+       4b: Y major move x1 to x2-M     floor((2Mdy + dy - B) / 2dx)
+
+       5:  X major move y1 to y1+N     floor((2Ndx - dx + B - 1) / 2dy) + 1
+       5b: X major move y2 to y1+N     floor((2Ndx + dx + B - 1) / 2dy)
+       6:  X major move y2 to y2-N     floor((2Ndx - dx - B) / 2dy) + 1
+       6b: X major move y1 to y2-N     floor((2Ndx + dx - B) / 2dy)
+
+       7:  Y major move y1 to y1+N     floor((2Ndx + dy - B) / 2dy)
+       7b: Y major move y2 to y1+N     floor((2Ndx + dy - B) / 2dy)
+       8:  Y major move y2 to y2-N     floor((2Ndx + dy + B - 1) / 2dy)
+       8b: Y major move y1 to y2-N     floor((2Ndx + dy + B - 1) / 2dy)
+
+We have the following constraints on all of the above terms:
+
+       0 < M,N <= 2^15          2^15 can be imposed by miZeroClipLine
+       0 <= dx/dy <= 2^16 - 1
+       0 <= B <= 1
+
+The floor in all of the above equations can be accomplished with a
+simple C divide operation provided that both numerator and denominator
+are positive.
+
+Since dx,dy >= 0 and since moving an X coordinate implies that dx != 0
+and moving a Y coordinate implies dy != 0, we know that the denominators
+are all > 0.
+
+For all lines, (-B) and (B-1) are both either 0 or -1, depending on the
+bias.  Thus, we have to show that the 2MNdxy +/- dxy terms are all >= 1
+or > 0 to prove that the numerators are positive (or zero).
+
+For X Major lines we know that dx > 0 and since 2Mdy is >= 0 due to the
+constraints, the first four equations all have numerators >= 0.
+
+For the second four equations, M > 0, so 2Mdy >= 2dy so (2Mdy - dy) >= dy
+So (2Mdy - dy) > 0, since they are Y major lines.  Also, (2Mdy + dy) >= 3dy
+or (2Mdy + dy) > 0.  So all of their numerators are >= 0.
+
+For the third set of four equations, N > 0, so 2Ndx >= 2dx so (2Ndx - dx)
+>= dx > 0.  Similarly (2Ndx + dx) >= 3dx > 0.  So all numerators >= 0.
+
+For the fourth set of equations, dy > 0 and 2Ndx >= 0, so all numerators
+are > 0.
+
+To consider overflow, consider the case of 2 * M,N * dx,dy + dx,dy.  This
+is bounded <= 2 * 2^15 * (2^16 - 1) + (2^16 - 1)
+          <= 2^16 * (2^16 - 1) + (2^16 - 1)
+          <= 2^32 - 2^16 + 2^16 - 1
+          <= 2^32 - 1
+Since the (-B) and (B-1) terms are all 0 or -1, the maximum value of
+the numerator is therefore (2^32 - 1), which does not overflow an unsigned
+32 bit variable.
+
+*/
+
+/* Bit codes for the terms of the 16 clipping equations defined below. */
+
+#define T_2NDX         (1 << 0)
+#define T_2MDY         (0)                             /* implicit term */
+#define T_DXNOTY       (1 << 1)
+#define T_DYNOTX       (0)                             /* implicit term */
+#define T_SUBDXORY     (1 << 2)
+#define T_ADDDX                (T_DXNOTY)                      /* composite term */
+#define T_SUBDX                (T_DXNOTY | T_SUBDXORY)         /* composite term */
+#define T_ADDDY                (T_DYNOTX)                      /* composite term */
+#define T_SUBDY                (T_DYNOTX | T_SUBDXORY)         /* composite term */
+#define T_BIASSUBONE   (1 << 3)
+#define T_SUBBIAS      (0)                             /* implicit term */
+#define T_DIV2DX       (1 << 4)
+#define T_DIV2DY       (0)                             /* implicit term */
+#define T_ADDONE       (1 << 5)
+
+/* Bit masks defining the 16 equations used in miZeroClipLine. */
+
+#define EQN1   (T_2MDY | T_ADDDX | T_SUBBIAS    | T_DIV2DX)
+#define EQN1B  (T_2MDY | T_ADDDX | T_SUBBIAS    | T_DIV2DX)
+#define EQN2   (T_2MDY | T_ADDDX | T_BIASSUBONE | T_DIV2DX)
+#define EQN2B  (T_2MDY | T_ADDDX | T_BIASSUBONE | T_DIV2DX)
+
+#define EQN3   (T_2MDY | T_SUBDY | T_BIASSUBONE | T_DIV2DX | T_ADDONE)
+#define EQN3B  (T_2MDY | T_ADDDY | T_BIASSUBONE | T_DIV2DX)
+#define EQN4   (T_2MDY | T_SUBDY | T_SUBBIAS    | T_DIV2DX | T_ADDONE)
+#define EQN4B  (T_2MDY | T_ADDDY | T_SUBBIAS    | T_DIV2DX)
+
+#define EQN5   (T_2NDX | T_SUBDX | T_BIASSUBONE | T_DIV2DY | T_ADDONE)
+#define EQN5B  (T_2NDX | T_ADDDX | T_BIASSUBONE | T_DIV2DY)
+#define EQN6   (T_2NDX | T_SUBDX | T_SUBBIAS    | T_DIV2DY | T_ADDONE)
+#define EQN6B  (T_2NDX | T_ADDDX | T_SUBBIAS    | T_DIV2DY)
+
+#define EQN7   (T_2NDX | T_ADDDY | T_SUBBIAS    | T_DIV2DY)
+#define EQN7B  (T_2NDX | T_ADDDY | T_SUBBIAS    | T_DIV2DY)
+#define EQN8   (T_2NDX | T_ADDDY | T_BIASSUBONE | T_DIV2DY)
+#define EQN8B  (T_2NDX | T_ADDDY | T_BIASSUBONE | T_DIV2DY)
+
+/* miZeroClipLine
+ *
+ * returns:  1 for partially clipped line
+ *          -1 for completely clipped line
+ *
+ */
+int
+miZeroClipLine(xmin, ymin, xmax, ymax,
+              new_x1, new_y1, new_x2, new_y2,
+              adx, ady,
+              pt1_clipped, pt2_clipped, octant, bias, oc1, oc2)
+    int xmin, ymin, xmax, ymax;
+    int *new_x1, *new_y1, *new_x2, *new_y2;
+    int *pt1_clipped, *pt2_clipped;
+    unsigned int adx, ady;
+    int octant;
+    unsigned int bias;
+    int oc1, oc2;
+{
+    int swapped = 0;
+    int clipDone = 0;
+    guint32 utmp;
+    int clip1, clip2;
+    int x1, y1, x2, y2;
+    int x1_orig, y1_orig, x2_orig, y2_orig;
+    int xmajor;
+    int negslope, anchorval;
+    unsigned int eqn;
+
+    x1 = x1_orig = *new_x1;
+    y1 = y1_orig = *new_y1;
+    x2 = x2_orig = *new_x2;
+    y2 = y2_orig = *new_y2;
+
+    clip1 = 0;
+    clip2 = 0;
+
+    xmajor = IsXMajorOctant(octant);
+    bias = ((bias >> octant) & 1);
+
+    while (1)
+    {
+        if ((oc1 & oc2) != 0)                  /* trivial reject */
+       {
+           clipDone = -1;
+           clip1 = oc1;
+           clip2 = oc2;
+           break;
+       }
+        else if ((oc1 | oc2) == 0)             /* trivial accept */
+        {
+           clipDone = 1;
+           if (swapped)
+           {
+               SWAPINT_PAIR(x1, y1, x2, y2);
+               SWAPINT(clip1, clip2);
+           }
+           break;
+        }
+        else                   /* have to clip */
+        {
+           /* only clip one point at a time */
+           if (oc1 == 0)
+           {
+               SWAPINT_PAIR(x1, y1, x2, y2);
+               SWAPINT_PAIR(x1_orig, y1_orig, x2_orig, y2_orig);
+               SWAPINT(oc1, oc2);
+               SWAPINT(clip1, clip2);
+               swapped = !swapped;
+           }
+    
+           clip1 |= oc1;
+           if (oc1 & OUT_LEFT)
+           {
+               negslope = IsYDecreasingOctant(octant);
+               utmp = xmin - x1_orig;
+               if (utmp <= 32767)              /* clip based on near endpt */
+               {
+                   if (xmajor)
+                       eqn = (swapped) ? EQN2 : EQN1;
+                   else
+                       eqn = (swapped) ? EQN4 : EQN3;
+                   anchorval = y1_orig;
+               }
+               else                            /* clip based on far endpt */
+               {
+                   utmp = x2_orig - xmin;
+                   if (xmajor)
+                       eqn = (swapped) ? EQN1B : EQN2B;
+                   else
+                       eqn = (swapped) ? EQN3B : EQN4B;
+                   anchorval = y2_orig;
+                   negslope = !negslope;
+               }
+               x1 = xmin;
+           }
+           else if (oc1 & OUT_ABOVE)
+           {
+               negslope = IsXDecreasingOctant(octant);
+               utmp = ymin - y1_orig;
+               if (utmp <= 32767)              /* clip based on near endpt */
+               {
+                   if (xmajor)
+                       eqn = (swapped) ? EQN6 : EQN5;
+                   else
+                       eqn = (swapped) ? EQN8 : EQN7;
+                   anchorval = x1_orig;
+               }
+               else                            /* clip based on far endpt */
+               {
+                   utmp = y2_orig - ymin;
+                   if (xmajor)
+                       eqn = (swapped) ? EQN5B : EQN6B;
+                   else
+                       eqn = (swapped) ? EQN7B : EQN8B;
+                   anchorval = x2_orig;
+                   negslope = !negslope;
+               }
+               y1 = ymin;
+           }
+           else if (oc1 & OUT_RIGHT)
+           {
+               negslope = IsYDecreasingOctant(octant);
+               utmp = x1_orig - xmax;
+               if (utmp <= 32767)              /* clip based on near endpt */
+               {
+                   if (xmajor)
+                       eqn = (swapped) ? EQN2 : EQN1;
+                   else
+                       eqn = (swapped) ? EQN4 : EQN3;
+                   anchorval = y1_orig;
+               }
+               else                            /* clip based on far endpt */
+               {
+                   /*
+                    * Technically since the equations can handle
+                    * utmp == 32768, this overflow code isn't
+                    * needed since X11 protocol can't generate
+                    * a line which goes more than 32768 pixels
+                    * to the right of a clip rectangle.
+                    */
+                   utmp = xmax - x2_orig;
+                   if (xmajor)
+                       eqn = (swapped) ? EQN1B : EQN2B;
+                   else
+                       eqn = (swapped) ? EQN3B : EQN4B;
+                   anchorval = y2_orig;
+                   negslope = !negslope;
+               }
+               x1 = xmax;
+           }
+           else if (oc1 & OUT_BELOW)
+           {
+               negslope = IsXDecreasingOctant(octant);
+               utmp = y1_orig - ymax;
+               if (utmp <= 32767)              /* clip based on near endpt */
+               {
+                   if (xmajor)
+                       eqn = (swapped) ? EQN6 : EQN5;
+                   else
+                       eqn = (swapped) ? EQN8 : EQN7;
+                   anchorval = x1_orig;
+               }
+               else                            /* clip based on far endpt */
+               {
+                   /*
+                    * Technically since the equations can handle
+                    * utmp == 32768, this overflow code isn't
+                    * needed since X11 protocol can't generate
+                    * a line which goes more than 32768 pixels
+                    * below the bottom of a clip rectangle.
+                    */
+                   utmp = ymax - y2_orig;
+                   if (xmajor)
+                       eqn = (swapped) ? EQN5B : EQN6B;
+                   else
+                       eqn = (swapped) ? EQN7B : EQN8B;
+                   anchorval = x2_orig;
+                   negslope = !negslope;
+               }
+               y1 = ymax;
+           }
+
+           if (swapped)
+               negslope = !negslope;
+
+           utmp <<= 1;                 /* utmp = 2N or 2M */
+           if (eqn & T_2NDX)
+               utmp = (utmp * adx);
+           else /* (eqn & T_2MDY) */
+               utmp = (utmp * ady);
+           if (eqn & T_DXNOTY)
+               if (eqn & T_SUBDXORY)
+                   utmp -= adx;
+               else
+                   utmp += adx;
+           else /* (eqn & T_DYNOTX) */
+               if (eqn & T_SUBDXORY)
+                   utmp -= ady;
+               else
+                   utmp += ady;
+           if (eqn & T_BIASSUBONE)
+               utmp += bias - 1;
+           else /* (eqn & T_SUBBIAS) */
+               utmp -= bias;
+           if (eqn & T_DIV2DX)
+               utmp /= (adx << 1);
+           else /* (eqn & T_DIV2DY) */
+               utmp /= (ady << 1);
+           if (eqn & T_ADDONE)
+               utmp++;
+
+           if (negslope)
+               utmp = -utmp;
+
+           if (eqn & T_2NDX)   /* We are calculating X steps */
+               x1 = anchorval + utmp;
+           else                /* else, Y steps */
+               y1 = anchorval + utmp;
+
+           oc1 = 0;
+           MIOUTCODES(oc1, x1, y1, xmin, ymin, xmax, ymax);
+        }
+    }
+
+    *new_x1 = x1;
+    *new_y1 = y1;
+    *new_x2 = x2;
+    *new_y2 = y2;
+    
+    *pt1_clipped = clip1;
+    *pt2_clipped = clip2;
+
+    return clipDone;
+}
diff --git a/gdk/linux-fb/mizerline.c b/gdk/linux-fb/mizerline.c
new file mode 100644 (file)
index 0000000..4ea91f3
--- /dev/null
@@ -0,0 +1,332 @@
+/* $XFree86: xc/programs/Xserver/mi/mizerline.c,v 3.4 1999/10/14 04:43:16 dawes Exp $ */
+/***********************************************************
+
+Copyright 1987, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+/* $TOG: mizerline.c /main/18 1998/02/09 14:49:45 kaleb $ */
+
+#include "mi.h"
+#include "miline.h"
+
+/* Draw lineSolid, fillStyle-independent zero width lines.
+ *
+ * Must keep X and Y coordinates in "ints" at least until after they're
+ * translated and clipped to accomodate CoordModePrevious lines with very
+ * large coordinates.
+ *
+ * Draws the same pixels regardless of sign(dx) or sign(dy).
+ *
+ * Ken Whaley
+ *
+ */
+
+/* largest positive value that can fit into a component of a point.
+ * Assumes that the point structure is {type x, y;} where type is
+ * a signed type.
+ */
+#define MAX_COORDINATE ((1 << (((sizeof(GdkPoint) >> 1) << 3) - 1)) - 1)
+
+#define MI_OUTPUT_POINT(xx, yy)\
+{\
+    if ( !new_span && yy == current_y)\
+    {\
+        if (xx < spans->x)\
+           spans->x = xx;\
+        spans->width++; \
+    }\
+    else\
+    {\
+        ++Nspans;\
+       ++spans;\
+       spans->x = xx;\
+       spans->y = yy;\
+        spans->width = 1; \
+        spans->height = 1; \
+       current_y = yy;\
+        new_span = FALSE;\
+    }\
+}
+
+void
+miZeroLine(pDraw, pGC, mode, npt, pptInit)
+    GdkDrawable* pDraw;
+    GdkGC*     pGC;
+    int                mode;           /* Origin or Previous */
+    int                npt;            /* number of points */
+    GdkPoint* pptInit;
+{
+    int Nspans, current_y;
+    GdkPoint* ppt; 
+    GdkRectangle* pspanInit, *spans;
+    int list_len;
+    int xleft, ytop, xright, ybottom;
+    int new_x1, new_y1, new_x2, new_y2;
+    int x, y, x1, y1, x2, y2, xstart, ystart;
+    int oc1, oc2;
+    int result;
+    int pt1_clipped, pt2_clipped = 0;
+    gboolean new_span;
+    int signdx, signdy;
+    int clipdx, clipdy;
+    int width, height;
+    int adx, ady;
+    int octant;
+    unsigned int bias = miGetZeroLineBias();
+    int e, e1, e2, e3; /* Bresenham error terms */
+    int length;                /* length of lines == # of pixels on major axis */
+
+    xleft   = 0;
+    ytop    = 0;
+    xright  = GDK_DRAWABLE_P(pDraw)->width - 1;
+    ybottom = GDK_DRAWABLE_P(pDraw)->height - 1;
+
+    /* it doesn't matter whether we're in drawable or screen coordinates,
+     * FillSpans simply cannot take starting coordinates outside of the
+     * range of a GdkPoint component.
+     */
+
+    /* since we're clipping to the drawable's boundaries & coordinate
+     * space boundaries, we're guaranteed that the larger of width/height
+     * is the longest span we'll need to output
+     */
+    width = xright - xleft + 1;
+    height = ybottom - ytop + 1;
+    list_len = (height >= width) ? height : width;
+    pspanInit = (GdkRectangle*)ALLOCATE_LOCAL(list_len * sizeof(GdkRectangle));
+    if (!pspanInit)
+       return;
+
+    Nspans = 0;
+    new_span = TRUE;
+    spans  = pspanInit - 1;
+    ppt = pptInit;
+
+    xstart = ppt->x;
+    ystart = ppt->y;
+    
+    /* x2, y2, oc2 copied to x1, y1, oc1 at top of loop to simplify
+     * iteration logic
+     */
+    x2 = xstart;
+    y2 = ystart;
+    oc2 = 0;
+    MIOUTCODES(oc2, x2, y2, xleft, ytop, xright, ybottom);
+
+    while (--npt > 0)
+    {
+       if (Nspans > 0)
+         gdk_fb_fill_spans(pDraw, pGC, pspanInit, Nspans);
+       Nspans = 0;
+       new_span = TRUE;
+       spans  = pspanInit - 1;
+
+       x1  = x2;
+       y1  = y2;
+       oc1 = oc2;
+       ++ppt;
+
+       x2 = ppt->x;
+       y2 = ppt->y;
+
+       oc2 = 0;
+       MIOUTCODES(oc2, x2, y2, xleft, ytop, xright, ybottom);
+
+       CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy, 1, 1, octant);
+
+       if (adx > ady)
+       {
+           e1 = ady << 1;
+           e2 = e1 - (adx << 1);
+           e  = e1 - adx;
+           length  = adx;      /* don't draw endpoint in main loop */
+
+           FIXUP_ERROR(e, octant, bias);
+
+           new_x1 = x1;
+           new_y1 = y1;
+           new_x2 = x2;
+           new_y2 = y2;
+           pt1_clipped = 0;
+           pt2_clipped = 0;
+
+           if ((oc1 | oc2) != 0)
+           {
+               result = miZeroClipLine(xleft, ytop, xright, ybottom,
+                                       &new_x1, &new_y1, &new_x2, &new_y2,
+                                       adx, ady,
+                                       &pt1_clipped, &pt2_clipped,
+                                       octant, bias, oc1, oc2);
+               if (result == -1)
+                   continue;
+
+               length = abs(new_x2 - new_x1);
+
+               /* if we've clipped the endpoint, always draw the full length
+                * of the segment, because then the capstyle doesn't matter 
+                */
+               if (pt2_clipped)
+                   length++;
+
+               if (pt1_clipped)
+               {
+                   /* must calculate new error terms */
+                   clipdx = abs(new_x1 - x1);
+                   clipdy = abs(new_y1 - y1);
+                   e += (clipdy * e2) + ((clipdx - clipdy) * e1);
+               }
+           }
+
+           /* draw the segment */
+
+           x = new_x1;
+           y = new_y1;
+           
+           e3 = e2 - e1;
+           e  = e - e1;
+
+           while (length--)
+           {
+               MI_OUTPUT_POINT(x, y);
+               e += e1;
+               if (e >= 0)
+               {
+                   y += signdy;
+                   e += e3;
+               }
+               x += signdx;
+           }
+       }
+       else    /* Y major line */
+       {
+           e1 = adx << 1;
+           e2 = e1 - (ady << 1);
+           e  = e1 - ady;
+           length  = ady;      /* don't draw endpoint in main loop */
+
+           SetYMajorOctant(octant);
+           FIXUP_ERROR(e, octant, bias);
+
+           new_x1 = x1;
+           new_y1 = y1;
+           new_x2 = x2;
+           new_y2 = y2;
+           pt1_clipped = 0;
+           pt2_clipped = 0;
+
+           if ((oc1 | oc2) != 0)
+           {
+               result = miZeroClipLine(xleft, ytop, xright, ybottom,
+                                       &new_x1, &new_y1, &new_x2, &new_y2,
+                                       adx, ady,
+                                       &pt1_clipped, &pt2_clipped,
+                                       octant, bias, oc1, oc2);
+               if (result == -1)
+                   continue;
+
+               length = abs(new_y2 - new_y1);
+
+               /* if we've clipped the endpoint, always draw the full length
+                * of the segment, because then the capstyle doesn't matter 
+                */
+               if (pt2_clipped)
+                   length++;
+
+               if (pt1_clipped)
+               {
+                   /* must calculate new error terms */
+                   clipdx = abs(new_x1 - x1);
+                   clipdy = abs(new_y1 - y1);
+                   e += (clipdx * e2) + ((clipdy - clipdx) * e1);
+               }
+           }
+
+           /* draw the segment */
+
+           x = new_x1;
+           y = new_y1;
+
+           e3 = e2 - e1;
+           e  = e - e1;
+
+           while (length--)
+           {
+               MI_OUTPUT_POINT(x, y);
+               e += e1;
+               if (e >= 0)
+               {
+                   x += signdx;
+                   e += e3;
+               }
+               y += signdy;
+           }
+       }
+    }
+
+    /* only do the capnotlast check on the last segment
+     * and only if the endpoint wasn't clipped.  And then, if the last
+     * point is the same as the first point, do not draw it, unless the
+     * line is degenerate
+     */
+    if ( (! pt2_clipped) && (GDK_GC_FBDATA(pGC)->values.cap_style != GDK_CAP_NOT_LAST) &&
+               (((xstart != x2) || (ystart != y2)) || (ppt == pptInit + 1)))
+    {
+       MI_OUTPUT_POINT(x, y);
+    }    
+
+    if (Nspans > 0)
+      gdk_fb_fill_spans(pDraw, pGC, pspanInit, Nspans);
+
+    DEALLOCATE_LOCAL(pspanInit);
+}
+
+void
+miZeroDashLine(dst, pgc, mode, nptInit, pptInit)
+GdkDrawable* dst;
+GdkGC* pgc;
+int mode;
+int nptInit;           /* number of points in polyline */
+GdkPoint *pptInit;     /* points in the polyline */
+{
+    /* XXX kludge until real zero-width dash code is written */
+    GDK_GC_FBDATA(pgc)->values.line_width = 1;
+    miWideDash (dst, pgc, mode, nptInit, pptInit);
+    GDK_GC_FBDATA(pgc)->values.line_width = 0;
+}