summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElliot Lee <sopwith@src.gnome.org>2000-05-31 21:50:38 +0000
committerElliot Lee <sopwith@src.gnome.org>2000-05-31 21:50:38 +0000
commitc4962116760783afa572f01ee532addecb359e98 (patch)
treecba684a9e2b38430e9493e1b44878ca455e4c1c3
parent85e7a89b132cf3bb299c876fc340ab0ce8fbd7d3 (diff)
downloadgtk+-c4962116760783afa572f01ee532addecb359e98.tar.gz
Put it into CVS.
Put it into CVS.
-rw-r--r--gdk/linux-fb/.cvsignore8
-rw-r--r--gdk/linux-fb/Makefile.am61
-rw-r--r--gdk/linux-fb/TODO3
-rw-r--r--gdk/linux-fb/gdkcolor-fb.c759
-rw-r--r--gdk/linux-fb/gdkcursor-fb.c81
-rw-r--r--gdk/linux-fb/gdkdnd-fb.c264
-rw-r--r--gdk/linux-fb/gdkdrawable-fb2.c959
-rw-r--r--gdk/linux-fb/gdkevents-fb.c209
-rw-r--r--gdk/linux-fb/gdkfb.h18
-rw-r--r--gdk/linux-fb/gdkfont-fb.c328
-rw-r--r--gdk/linux-fb/gdkgc-fb.c308
-rw-r--r--gdk/linux-fb/gdkgeometry-fb.c0
-rw-r--r--gdk/linux-fb/gdkglobals-fb.c41
-rw-r--r--gdk/linux-fb/gdkim-fb.c242
-rw-r--r--gdk/linux-fb/gdkimage-fb.c268
-rw-r--r--gdk/linux-fb/gdkinput-none.c79
-rw-r--r--gdk/linux-fb/gdkinput-ps2.c1096
-rw-r--r--gdk/linux-fb/gdkinput.c290
-rw-r--r--gdk/linux-fb/gdkinputprivate.h222
-rw-r--r--gdk/linux-fb/gdkmain-fb.c575
-rw-r--r--gdk/linux-fb/gdkpixmap-fb.c768
-rw-r--r--gdk/linux-fb/gdkpoly-generic.h291
-rw-r--r--gdk/linux-fb/gdkpolyreg-generic.c616
-rw-r--r--gdk/linux-fb/gdkprivate-fb.h194
-rw-r--r--gdk/linux-fb/gdkproperty-fb.c204
-rw-r--r--gdk/linux-fb/gdkregion-generic.c1505
-rw-r--r--gdk/linux-fb/gdkregion-generic.h162
-rw-r--r--gdk/linux-fb/gdkselection-fb.c104
-rw-r--r--gdk/linux-fb/gdkvisual-fb.c180
-rw-r--r--gdk/linux-fb/gdkwindow-fb.c1372
-rw-r--r--gdk/linux-fb/mi.h21
-rw-r--r--gdk/linux-fb/miarc.c3569
-rw-r--r--gdk/linux-fb/midash.c309
-rw-r--r--gdk/linux-fb/mifillarc.c743
-rw-r--r--gdk/linux-fb/mifillarc.h224
-rw-r--r--gdk/linux-fb/mifpoly.h112
-rw-r--r--gdk/linux-fb/mifpolycon.c261
-rw-r--r--gdk/linux-fb/miline.h177
-rw-r--r--gdk/linux-fb/mipoly.c77
-rw-r--r--gdk/linux-fb/mipoly.h230
-rw-r--r--gdk/linux-fb/mipolygen.c214
-rw-r--r--gdk/linux-fb/mipolyutil.c392
-rw-r--r--gdk/linux-fb/miscanfill.h139
-rw-r--r--gdk/linux-fb/mispans.c507
-rw-r--r--gdk/linux-fb/mispans.h127
-rw-r--r--gdk/linux-fb/mistruct.h58
-rw-r--r--gdk/linux-fb/mitypes.h486
-rw-r--r--gdk/linux-fb/miwideline.c2108
-rw-r--r--gdk/linux-fb/miwideline.h254
-rw-r--r--gdk/linux-fb/mizerclip.c622
-rw-r--r--gdk/linux-fb/mizerline.c332
51 files changed, 22169 insertions, 0 deletions
diff --git a/gdk/linux-fb/.cvsignore b/gdk/linux-fb/.cvsignore
new file mode 100644
index 0000000000..10f8f3eec3
--- /dev/null
+++ b/gdk/linux-fb/.cvsignore
@@ -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
index 0000000000..bdaeb24a5b
--- /dev/null
+++ b/gdk/linux-fb/Makefile.am
@@ -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
index 0000000000..fd308a5b33
--- /dev/null
+++ b/gdk/linux-fb/TODO
@@ -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
index 0000000000..684dec443b
--- /dev/null
+++ b/gdk/linux-fb/gdkcolor-fb.c
@@ -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
index 0000000000..8a883f9e87
--- /dev/null
+++ b/gdk/linux-fb/gdkcursor-fb.c
@@ -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
index 0000000000..b65c55a8e5
--- /dev/null
+++ b/gdk/linux-fb/gdkdnd-fb.c
@@ -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
index 0000000000..f5c7b8c122
--- /dev/null
+++ b/gdk/linux-fb/gdkdrawable-fb2.c
@@ -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
index 0000000000..7b80aa364a
--- /dev/null
+++ b/gdk/linux-fb/gdkevents-fb.c
@@ -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
index 0000000000..7cb6f6d3ad
--- /dev/null
+++ b/gdk/linux-fb/gdkfb.h
@@ -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
index 0000000000..c22b840177
--- /dev/null
+++ b/gdk/linux-fb/gdkfont-fb.c
@@ -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
index 0000000000..02bf5d0591
--- /dev/null
+++ b/gdk/linux-fb/gdkgc-fb.c
@@ -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
index 0000000000..e69de29bb2
--- /dev/null
+++ b/gdk/linux-fb/gdkgeometry-fb.c
diff --git a/gdk/linux-fb/gdkglobals-fb.c b/gdk/linux-fb/gdkglobals-fb.c
new file mode 100644
index 0000000000..220a4f6ab5
--- /dev/null
+++ b/gdk/linux-fb/gdkglobals-fb.c
@@ -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
index 0000000000..05da53fc48
--- /dev/null
+++ b/gdk/linux-fb/gdkim-fb.c
@@ -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
index 0000000000..d47f287d33
--- /dev/null
+++ b/gdk/linux-fb/gdkimage-fb.c
@@ -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
index 0000000000..d3aba3dd93
--- /dev/null
+++ b/gdk/linux-fb/gdkinput-none.c
@@ -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
index 0000000000..0db7456728
--- /dev/null
+++ b/gdk/linux-fb/gdkinput-ps2.c
@@ -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
index 0000000000..2013ea07c8
--- /dev/null
+++ b/gdk/linux-fb/gdkinput.c
@@ -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
index 0000000000..d9ce74fdf9
--- /dev/null
+++ b/gdk/linux-fb/gdkinputprivate.h
@@ -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
index 0000000000..5fd7bb8800
--- /dev/null
+++ b/gdk/linux-fb/gdkmain-fb.c
@@ -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
index 0000000000..30c6d2bdcb
--- /dev/null
+++ b/gdk/linux-fb/gdkpixmap-fb.c
@@ -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
index 0000000000..660c689adb
--- /dev/null
+++ b/gdk/linux-fb/gdkpoly-generic.h
@@ -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.
+ */
+
+
+/*
+ * 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; \
+ } \
+ } \
+}
+
+#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; \
+ } \
+ } \
+}
+
+
+/*
+ * 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;
+
+
+
+/*
+ *
+ * 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
index 0000000000..b98bd5641e
--- /dev/null
+++ b/gdk/linux-fb/gdkpolyreg-generic.c
@@ -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;
+}
+
+/*
+ * 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;
+ }
+}
+
+/*
+ * 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;
+ }
+}
+
+/*
+ * 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;
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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
index 0000000000..2ad3a04896
--- /dev/null
+++ b/gdk/linux-fb/gdkprivate-fb.h
@@ -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
index 0000000000..e251e71d3b
--- /dev/null
+++ b/gdk/linux-fb/gdkproperty-fb.c
@@ -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
index 0000000000..1140ce0421
--- /dev/null
+++ b/gdk/linux-fb/gdkregion-generic.c
@@ -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);
+}
+
+
+/*======================================================================
+ * 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);
+}
+
+
+/*======================================================================
+ * 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);
+}
+
+
+/*======================================================================
+ * 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
index 0000000000..33d0683dfb
--- /dev/null
+++ b/gdk/linux-fb/gdkregion-generic.h
@@ -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
index 0000000000..1b154b0045
--- /dev/null
+++ b/gdk/linux-fb/gdkselection-fb.c
@@ -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
index 0000000000..24468aafdc
--- /dev/null
+++ b/gdk/linux-fb/gdkvisual-fb.c
@@ -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
index 0000000000..dad9ff3f35
--- /dev/null
+++ b/gdk/linux-fb/gdkwindow-fb.c
@@ -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
index 0000000000..b65179700b
--- /dev/null
+++ b/gdk/linux-fb/mi.h
@@ -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
index 0000000000..a3d739513f
--- /dev/null
+++ b/gdk/linux-fb/miarc.c
@@ -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
index 0000000000..c939976e78
--- /dev/null
+++ b/gdk/linux-fb/midash.c
@@ -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
index 0000000000..115be216c3
--- /dev/null
+++ b/gdk/linux-fb/mifillarc.c
@@ -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
index 0000000000..99a75d6423
--- /dev/null
+++ b/gdk/linux-fb/mifillarc.h
@@ -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
index 0000000000..fd56f57ea1
--- /dev/null
+++ b/gdk/linux-fb/mifpoly.h
@@ -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
index 0000000000..341512f367
--- /dev/null
+++ b/gdk/linux-fb/mifpolycon.c
@@ -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);
+}
+
+
+/* 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
index 0000000000..a4ccf2c325
--- /dev/null
+++ b/gdk/linux-fb/miline.h
@@ -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
index 0000000000..de1d740a20
--- /dev/null
+++ b/gdk/linux-fb/mipoly.c
@@ -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
index 0000000000..d8dfe19664
--- /dev/null
+++ b/gdk/linux-fb/mipoly.h
@@ -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
+
+
+/*
+ *
+ * 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
index 0000000000..5068536c71
--- /dev/null
+++ b/gdk/linux-fb/mipolygen.c
@@ -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
index 0000000000..3cf3f9f9e8
--- /dev/null
+++ b/gdk/linux-fb/mipolyutil.c
@@ -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.
+ *
+ */
+
+/*
+ * 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;
+}
+
+/*
+ * 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;
+}
+
+/*
+ * 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;
+ }
+}
+
+/*
+ * 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;
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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
index 0000000000..c9e1f50276
--- /dev/null
+++ b/gdk/linux-fb/miscanfill.h
@@ -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.
+ */
+
+
+/*
+ * 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; \
+ } \
+ } \
+}
+
+#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; \
+ } \
+ } \
+}
+
+
+/*
+ * 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
index 0000000000..a8638dd858
--- /dev/null
+++ b/gdk/linux-fb/mispans.c
@@ -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
index 0000000000..4724e203ed
--- /dev/null
+++ b/gdk/linux-fb/mispans.h
@@ -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
index 0000000000..ff5d738219
--- /dev/null
+++ b/gdk/linux-fb/mistruct.h
@@ -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
index 0000000000..997ec8aa07
--- /dev/null
+++ b/gdk/linux-fb/mitypes.h
@@ -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
index 0000000000..d1e46b9468
--- /dev/null
+++ b/gdk/linux-fb/miwideline.c
@@ -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
index 0000000000..a39b6c13bf
--- /dev/null
+++ b/gdk/linux-fb/miwideline.h
@@ -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
index 0000000000..145ccd9551
--- /dev/null
+++ b/gdk/linux-fb/mizerclip.c
@@ -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.
+
+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)
+
+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)
+
+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)
+
+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)
+
+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
index 0000000000..4ea91f357c
--- /dev/null
+++ b/gdk/linux-fb/mizerline.c
@@ -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;
+}