diff options
Diffstat (limited to 'gdk/x11')
-rw-r--r-- | gdk/x11/Makefile.am | 67 | ||||
-rw-r--r-- | gdk/x11/gdkcc-x11.c | 1 | ||||
-rw-r--r-- | gdk/x11/gdkcolor-x11.c | 2 | ||||
-rw-r--r-- | gdk/x11/gdkdnd-x11.c | 4 | ||||
-rw-r--r-- | gdk/x11/gdkdrawable-x11.c | 170 | ||||
-rw-r--r-- | gdk/x11/gdkevents-x11.c | 296 | ||||
-rw-r--r-- | gdk/x11/gdkfont-x11.c | 2 | ||||
-rw-r--r-- | gdk/x11/gdkgc-x11.c | 152 | ||||
-rw-r--r-- | gdk/x11/gdkgeometry-x11.c | 698 | ||||
-rw-r--r-- | gdk/x11/gdkim-x11.c | 4 | ||||
-rw-r--r-- | gdk/x11/gdkimage-x11.c | 6 | ||||
-rw-r--r-- | gdk/x11/gdkinput-x11.c | 4 | ||||
-rw-r--r-- | gdk/x11/gdkinputprivate.h | 4 | ||||
-rw-r--r-- | gdk/x11/gdkmain-x11.c | 4 | ||||
-rw-r--r-- | gdk/x11/gdkpixmap-x11.c | 7 | ||||
-rw-r--r-- | gdk/x11/gdkpoly-generic.h | 291 | ||||
-rw-r--r-- | gdk/x11/gdkpolyreg-generic.c | 616 | ||||
-rw-r--r-- | gdk/x11/gdkprivate-x11.h | 150 | ||||
-rw-r--r-- | gdk/x11/gdkregion-generic.c | 1505 | ||||
-rw-r--r-- | gdk/x11/gdkregion-generic.h | 167 | ||||
-rw-r--r-- | gdk/x11/gdkregion-x11.c | 26 | ||||
-rw-r--r-- | gdk/x11/gdkselection-x11.c | 2 | ||||
-rw-r--r-- | gdk/x11/gdkvisual-x11.c | 1 | ||||
-rw-r--r-- | gdk/x11/gdkwindow-x11.c | 186 | ||||
-rw-r--r-- | gdk/x11/gdkx.h | 138 |
25 files changed, 3943 insertions, 560 deletions
diff --git a/gdk/x11/Makefile.am b/gdk/x11/Makefile.am index b1ac71906f..afa9db5f02 100644 --- a/gdk/x11/Makefile.am +++ b/gdk/x11/Makefile.am @@ -35,40 +35,49 @@ xinput_sources = \ endif endif -libgdk_x11_la_SOURCES = \ - MwmUtil.h \ - gdkcc-x11.c \ - gdkcolor-x11.c \ - gdkcursor-x11.c \ - gdkdnd-x11.c \ - gdkdrawable-x11.c \ - gdkevents-x11.c \ - gdkfont-x11.c \ - gdkgc-x11.c \ - gdkglobals-x11.c \ - gdkim-x11.c \ - gdkimage-x11.c \ - gdkinput.c \ - gdkmain-x11.c \ - gdkpixmap-x11.c \ - gdkproperty-x11.c \ - gdkregion-x11.c \ - gdkselection-x11.c \ - gdkvisual-x11.c \ - gdkwindow-x11.c \ - gdkxid.c \ - gxid_lib.c \ - gxid_lib.h \ - gxid_proto.h \ - gdkx.h \ - gdkprivate-x11.h \ - gdkinputprivate.h \ +libgdk_x11_la_SOURCES = \ + MwmUtil.h \ + gdkcc-x11.c \ + gdkcolor-x11.c \ + gdkcursor-x11.c \ + gdkdnd-x11.c \ + gdkdrawable-x11.c \ + gdkevents-x11.c \ + gdkfont-x11.c \ + gdkgc-x11.c \ + gdkgeometry-x11.c \ + gdkglobals-x11.c \ + gdkim-x11.c \ + gdkimage-x11.c \ + gdkinput.c \ + gdkmain-x11.c \ + gdkpixmap-x11.c \ + gdkproperty-x11.c \ + gdkpolyreg-generic.c \ + gdkregion-generic.c \ + gdkselection-x11.c \ + gdkvisual-x11.c \ + gdkwindow-x11.c \ + gdkxid.c \ + gxid_lib.c \ + gxid_lib.h \ + gxid_proto.h \ + gdkx.h \ + gdkprivate-x11.h \ + gdkinputprivate.h \ $(xinput_sources) +INCLUDE_HEADERS = \ + gdkx.h + EXTRA_PROGRAMS = gxid bin_PROGRAMS = @xinput_progs@ gxid_SOURCES = gxid.c gxid_LDADD = $(LDADDS) - +install-data-local: + ../../$(MKINSTALLDIRS) $(includedir)/gdk + $(INSTALL_DATA) $(srcdir)/gdkx.h $(includedir)/gdk + ../../$(MKINSTALLDIRS) $(includedir)/gdk/x11 + $(INSTALL_DATA) $(srcdir)/gdkprivate-x11.h $(includedir)/gdk/x11 diff --git a/gdk/x11/gdkcc-x11.c b/gdk/x11/gdkcc-x11.c index 91e873453b..5cce8aad32 100644 --- a/gdk/x11/gdkcc-x11.c +++ b/gdk/x11/gdkcc-x11.c @@ -68,6 +68,7 @@ #include "gdkcc.h" #include "gdkcolor.h" #include "gdkx.h" +#include "gdkinternals.h" #define MAX_IMAGE_COLORS 256 diff --git a/gdk/x11/gdkcolor-x11.c b/gdk/x11/gdkcolor-x11.c index 7759fb5f1b..156933cec4 100644 --- a/gdk/x11/gdkcolor-x11.c +++ b/gdk/x11/gdkcolor-x11.c @@ -27,7 +27,7 @@ #include <time.h> #include "gdkcolor.h" -#include "gdkx.h" +#include "gdkprivate-x11.h" static gint gdk_colormap_match_color (GdkColormap *cmap, GdkColor *color, diff --git a/gdk/x11/gdkdnd-x11.c b/gdk/x11/gdkdnd-x11.c index 590c4174d1..287a65dc58 100644 --- a/gdk/x11/gdkdnd-x11.c +++ b/gdk/x11/gdkdnd-x11.c @@ -31,8 +31,8 @@ #include "gdk.h" /* For gdk_flush() */ #include "gdkdnd.h" #include "gdkproperty.h" -#include "gdkprivate.h" -#include "gdkx.h" +#include "gdkinternals.h" +#include "gdkprivate-x11.h" typedef struct _GdkDragContextPrivate GdkDragContextPrivate; diff --git a/gdk/x11/gdkdrawable-x11.c b/gdk/x11/gdkdrawable-x11.c index c99de5bc23..5caa7a1351 100644 --- a/gdk/x11/gdkdrawable-x11.c +++ b/gdk/x11/gdkdrawable-x11.c @@ -1,4 +1,30 @@ -#include "gdkx.h" +/* 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 "gdkprivate-x11.h" static void gdk_x11_drawable_destroy (GdkDrawable *drawable); @@ -159,10 +185,10 @@ gdk_x11_draw_rectangle (GdkDrawable *drawable, { if (filled) XFillRectangle (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), - GDK_GC_XGC (gc), x, y, width, height); + GDK_GC_GET_XGC (gc), x, y, width, height); else XDrawRectangle (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), - GDK_GC_XGC (gc), x, y, width, height); + GDK_GC_GET_XGC (gc), x, y, width, height); } static void @@ -178,10 +204,10 @@ gdk_x11_draw_arc (GdkDrawable *drawable, { if (filled) XFillArc (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), - GDK_GC_XGC (gc), x, y, width, height, angle1, angle2); + GDK_GC_GET_XGC (gc), x, y, width, height, angle1, angle2); else XDrawArc (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), - GDK_GC_XGC (gc), x, y, width, height, angle1, angle2); + GDK_GC_GET_XGC (gc), x, y, width, height, angle1, angle2); } static void @@ -191,36 +217,37 @@ gdk_x11_draw_polygon (GdkDrawable *drawable, GdkPoint *points, gint npoints) { - if (filled) + XPoint *tmp_points; + gint tmp_npoints, i; + + if (!filled && + (points[0].x != points[npoints-1].x || points[0].y != points[npoints-1].y)) { - XFillPolygon (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), - GDK_GC_XGC (gc), (XPoint*) points, npoints, Complex, CoordModeOrigin); + tmp_npoints = npoints + 1; + tmp_points = g_new (XPoint, tmp_npoints); + tmp_points[npoints].x = points[0].x; + tmp_points[npoints].y = points[0].y; } else { - GdkPoint *local_points = points; - gint local_npoints = npoints; - gint local_alloc = 0; - - if ((points[0].x != points[npoints-1].x) || - (points[0].y != points[npoints-1].y)) - { - local_alloc = 1; - ++local_npoints; - local_points = (GdkPoint*) g_malloc (local_npoints * sizeof(GdkPoint)); - memcpy (local_points, points, npoints * sizeof(GdkPoint)); - local_points[npoints].x = points[0].x; - local_points[npoints].y = points[0].y; - } - - XDrawLines (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), - GDK_GC_XGC (gc), - (XPoint*) local_points, local_npoints, - CoordModeOrigin); - - if (local_alloc) - g_free (local_points); + tmp_npoints = npoints; + tmp_points = g_new (XPoint, tmp_npoints); + } + + for (i=0; i<npoints; i++) + { + tmp_points[i].x = points[i].x; + tmp_points[i].y = points[i].y; } + + if (filled) + XFillPolygon (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), + GDK_GC_GET_XGC (gc), tmp_points, tmp_npoints, Complex, CoordModeOrigin); + else + XDrawLines (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), + GDK_GC_GET_XGC (gc), tmp_points, tmp_npoints, CoordModeOrigin); + + g_free (tmp_points); } /* gdk_x11_draw_text @@ -241,23 +268,23 @@ gdk_x11_draw_text (GdkDrawable *drawable, if (font->type == GDK_FONT_FONT) { XFontStruct *xfont = (XFontStruct *) GDK_FONT_XFONT (font); - XSetFont(GDK_DRAWABLE_XDISPLAY (drawable), GDK_GC_XGC (gc), xfont->fid); + XSetFont(GDK_DRAWABLE_XDISPLAY (drawable), GDK_GC_GET_XGC (gc), xfont->fid); if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) { XDrawString (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), - GDK_GC_XGC (gc), x, y, text, text_length); + GDK_GC_GET_XGC (gc), x, y, text, text_length); } else { XDrawString16 (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), - GDK_GC_XGC (gc), x, y, (XChar2b *) text, text_length / 2); + GDK_GC_GET_XGC (gc), x, y, (XChar2b *) text, text_length / 2); } } else if (font->type == GDK_FONT_FONTSET) { XFontSet fontset = (XFontSet) GDK_FONT_XFONT (font); XmbDrawString (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), - fontset, GDK_GC_XGC (gc), x, y, text, text_length); + fontset, GDK_GC_GET_XGC (gc), x, y, text, text_length); } else g_error("undefined font type\n"); @@ -277,11 +304,11 @@ gdk_x11_draw_text_wc (GdkDrawable *drawable, XFontStruct *xfont = (XFontStruct *) GDK_FONT_XFONT (font); gchar *text_8bit; gint i; - XSetFont(GDK_DRAWABLE_XDISPLAY (drawable), GDK_GC_XGC (gc), xfont->fid); + XSetFont(GDK_DRAWABLE_XDISPLAY (drawable), GDK_GC_GET_XGC (gc), xfont->fid); text_8bit = g_new (gchar, text_length); for (i=0; i<text_length; i++) text_8bit[i] = text[i]; XDrawString (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), - GDK_GC_XGC (gc), x, y, text_8bit, text_length); + GDK_GC_GET_XGC (gc), x, y, text_8bit, text_length); g_free (text_8bit); } else if (font->type == GDK_FONT_FONTSET) @@ -290,7 +317,7 @@ gdk_x11_draw_text_wc (GdkDrawable *drawable, { XwcDrawString (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), (XFontSet) GDK_FONT_XFONT (font), - GDK_GC_XGC (gc), x, y, (wchar_t *)text, text_length); + GDK_GC_GET_XGC (gc), x, y, (wchar_t *)text, text_length); } else { @@ -300,7 +327,7 @@ gdk_x11_draw_text_wc (GdkDrawable *drawable, for (i=0; i<text_length; i++) text_wchar[i] = text[i]; XwcDrawString (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), (XFontSet) GDK_FONT_XFONT (font), - GDK_GC_XGC (gc), x, y, text_wchar, text_length); + GDK_GC_GET_XGC (gc), x, y, text_wchar, text_length); g_free (text_wchar); } } @@ -319,27 +346,31 @@ gdk_x11_draw_drawable (GdkDrawable *drawable, gint width, gint height) { - /* FIXME: this doesn't work because bitmaps don't have visuals */ - if (gdk_drawable_get_visual (src)->depth == 1) + int src_depth = gdk_drawable_get_depth (src); + int dest_depth = gdk_drawable_get_depth (drawable); + + if (src_depth == 1) { XCopyArea (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (src), GDK_DRAWABLE_XID (drawable), - GDK_GC_XGC (gc), + GDK_GC_GET_XGC (gc), xsrc, ysrc, width, height, xdest, ydest); } - else + else if (dest_depth != 0 && src_depth == dest_depth) { XCopyArea (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (src), GDK_DRAWABLE_XID (drawable), - GDK_GC_XGC (gc), + GDK_GC_GET_XGC (gc), xsrc, ysrc, width, height, xdest, ydest); } + else + g_warning ("Attempt to copy between drawables of mismatched depths!\n"); } static void @@ -355,17 +386,28 @@ gdk_x11_draw_points (GdkDrawable *drawable, { XDrawPoint (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), - GDK_GC_XGC (gc), + GDK_GC_GET_XGC (gc), points[0].x, points[0].y); } else { + gint i; + XPoint *tmp_points = g_new (XPoint, npoints); + + for (i=0; i<npoints; i++) + { + tmp_points[i].x = points[i].x; + tmp_points[i].y = points[i].y; + } + XDrawPoints (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), - GDK_GC_XGC (gc), - (XPoint *) points, + GDK_GC_GET_XGC (gc), + tmp_points, npoints, CoordModeOrigin); + + g_free (tmp_points); } } @@ -381,16 +423,28 @@ gdk_x11_draw_segments (GdkDrawable *drawable, if (nsegs == 1) { XDrawLine (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), - GDK_GC_XGC (gc), segs[0].x1, segs[0].y1, + GDK_GC_GET_XGC (gc), segs[0].x1, segs[0].y1, segs[0].x2, segs[0].y2); } else { + gint i; + XSegment *tmp_segs = g_new (XSegment, nsegs); + + for (i=0; i<nsegs; i++) + { + tmp_segs[i].x1 = segs[i].x1; + tmp_segs[i].x2 = segs[i].x2; + tmp_segs[i].y1 = segs[i].y1; + tmp_segs[i].y2 = segs[i].y2; + } + XDrawSegments (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), - GDK_GC_XGC (gc), - (XSegment *) segs, - nsegs); + GDK_GC_GET_XGC (gc), + tmp_segs, nsegs); + + g_free (tmp_segs); } } @@ -400,10 +454,20 @@ gdk_x11_draw_lines (GdkDrawable *drawable, GdkPoint *points, gint npoints) { + gint i; + XPoint *tmp_points = g_new (XPoint, npoints); + + for (i=0; i<npoints; i++) + { + tmp_points[i].x = points[i].x; + tmp_points[i].y = points[i].y; + } + XDrawLines (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), - GDK_GC_XGC (gc), - (XPoint *) points, - npoints, + GDK_GC_GET_XGC (gc), + tmp_points, npoints, CoordModeOrigin); + + g_free (tmp_points); } diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c index e2056add0e..9f29453178 100644 --- a/gdk/x11/gdkevents-x11.c +++ b/gdk/x11/gdkevents-x11.c @@ -25,7 +25,8 @@ */ #include "gdk.h" -#include "gdkprivate.h" +#include "gdkprivate-x11.h" +#include "gdkinternals.h" #include "gdkx.h" #include "gdkkeysyms.h" @@ -215,214 +216,6 @@ gdk_event_get_graphics_expose (GdkWindow *window) return NULL; } -/************************ - * Exposure compression * - ************************/ - -/* - * The following implements simple exposure compression. It is - * modelled after the way Xt does exposure compression - in - * particular compress_expose = XtExposeCompressMultiple. - * It compress consecutive sequences of exposure events, - * but not sequences that cross other events. (This is because - * if it crosses a ConfigureNotify, we could screw up and - * mistakenly compress the exposures generated for the new - * size - could we just check for ConfigureNotify?) - * - * Xt compresses to a region / bounding rectangle, we compress - * to two rectangles, and try find the two rectangles of minimal - * area for this - this is supposed to handle the typical - * L-shaped regions generated by OpaqueMove. - */ - -/* Given three rectangles, find the two rectangles that cover - * them with the smallest area. - */ -static void -gdk_add_rect_to_rects (GdkRectangle *rect1, - GdkRectangle *rect2, - GdkRectangle *new_rect) -{ - GdkRectangle t1, t2, t3; - gint size1, size2, size3; - - gdk_rectangle_union (rect1, rect2, &t1); - gdk_rectangle_union (rect1, new_rect, &t2); - gdk_rectangle_union (rect2, new_rect, &t3); - - size1 = t1.width * t1.height + new_rect->width * new_rect->height; - size2 = t2.width * t2.height + rect2->width * rect2->height; - size3 = t1.width * t1.height + rect1->width * rect1->height; - - if (size1 < size2) - { - if (size1 < size3) - { - *rect1 = t1; - *rect2 = *new_rect; - } - else - *rect2 = t3; - } - else - { - if (size2 < size3) - *rect1 = t2; - else - *rect2 = t3; - } -} - -typedef struct _GdkExposeInfo GdkExposeInfo; - -struct _GdkExposeInfo -{ - Window window; - gboolean seen_nonmatching; -}; - -static Bool -expose_predicate (Display *display, - XEvent *xevent, - XPointer arg) -{ - GdkExposeInfo *info = (GdkExposeInfo*) arg; - - /* Compressing across GravityNotify events is safe, because - * we completely ignore them, so they can't change what - * we are going to draw. Compressing across GravityNotify - * events is necessay because during window-unshading animation - * we'll get a whole bunch of them interspersed with - * expose events. - */ - if (xevent->xany.type != Expose && - xevent->xany.type != GravityNotify) - { - info->seen_nonmatching = TRUE; - } - - if (info->seen_nonmatching || - xevent->xany.type != Expose || - xevent->xany.window != info->window) - return FALSE; - else - return TRUE; -} - -void -gdk_compress_exposures (XEvent *xevent, - GdkWindow *window) -{ - gint nrects = 1; - gint count = 0; - GdkRectangle rect1; - GdkRectangle rect2; - GdkRectangle tmp_rect; - XEvent tmp_event; - GdkFilterReturn result; - GdkExposeInfo info; - GdkEvent event; - - info.window = xevent->xany.window; - info.seen_nonmatching = FALSE; - - rect1.x = xevent->xexpose.x; - rect1.y = xevent->xexpose.y; - rect1.width = xevent->xexpose.width; - rect1.height = xevent->xexpose.height; - - event.any.type = GDK_EXPOSE; - event.any.window = None; - event.any.send_event = FALSE; - - while (1) - { - if (count == 0) - { - if (!XCheckIfEvent (gdk_display, - &tmp_event, - expose_predicate, - (XPointer)&info)) - break; - } - else - XIfEvent (gdk_display, - &tmp_event, - expose_predicate, - (XPointer)&info); - - event.any.window = window; - - /* We apply filters here, and if it was filtered, completely - * ignore the return - */ - result = gdk_event_apply_filters (xevent, &event, - window ? - ((GdkWindowPrivate *)window)->filters - : gdk_default_filters); - - if (result != GDK_FILTER_CONTINUE) - { - if (result == GDK_FILTER_TRANSLATE) - gdk_event_put (&event); - continue; - } - - if (nrects == 1) - { - rect2.x = tmp_event.xexpose.x; - rect2.y = tmp_event.xexpose.y; - rect2.width = tmp_event.xexpose.width; - rect2.height = tmp_event.xexpose.height; - - nrects++; - } - else - { - tmp_rect.x = tmp_event.xexpose.x; - tmp_rect.y = tmp_event.xexpose.y; - tmp_rect.width = tmp_event.xexpose.width; - tmp_rect.height = tmp_event.xexpose.height; - - gdk_add_rect_to_rects (&rect1, &rect2, &tmp_rect); - } - - count = tmp_event.xexpose.count; - } - - if (nrects == 2) - { - gdk_rectangle_union (&rect1, &rect2, &tmp_rect); - - if ((tmp_rect.width * tmp_rect.height) < - 2 * (rect1.height * rect1.width + - rect2.height * rect2.width)) - { - rect1 = tmp_rect; - nrects = 1; - } - } - - if (nrects == 2) - { - event.expose.type = GDK_EXPOSE; - event.expose.window = window; - event.expose.area.x = rect2.x; - event.expose.area.y = rect2.y; - event.expose.area.width = rect2.width; - event.expose.area.height = rect2.height; - event.expose.count = 0; - - gdk_event_put (&event); - } - - xevent->xexpose.count = nrects - 1; - xevent->xexpose.x = rect1.x; - xevent->xexpose.y = rect1.y; - xevent->xexpose.width = rect1.width; - xevent->xexpose.height = rect1.height; -} - static gint gdk_event_apply_filters (XEvent *xevent, GdkEvent *event, @@ -477,6 +270,7 @@ gdk_event_translate (GdkEvent *event, char buf[16]; #endif gint return_val; + gint xoffset, yoffset; return_val = FALSE; @@ -571,6 +365,16 @@ gdk_event_translate (GdkEvent *event, return_val = TRUE; + if (window) + { + _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset); + } + else + { + xoffset = 0; + yoffset = 0; + } + switch (xevent->type) { case KeyPress: @@ -709,8 +513,8 @@ gdk_event_translate (GdkEvent *event, GDK_SCROLL_UP : GDK_SCROLL_DOWN; event->scroll.window = window; event->scroll.time = xevent->xbutton.x; - event->scroll.x = xevent->xbutton.x; - event->scroll.y = xevent->xbutton.y; + event->scroll.x = xevent->xbutton.x + xoffset; + event->scroll.y = xevent->xbutton.y + yoffset; event->scroll.x_root = (gfloat)xevent->xbutton.x_root; event->scroll.y_root = (gfloat)xevent->xbutton.y_root; event->scroll.pressure = 0.5; @@ -725,8 +529,8 @@ gdk_event_translate (GdkEvent *event, event->button.type = GDK_BUTTON_PRESS; event->button.window = window; event->button.time = xevent->xbutton.time; - event->button.x = xevent->xbutton.x; - event->button.y = xevent->xbutton.y; + event->button.x = xevent->xbutton.x + xoffset; + event->button.y = xevent->xbutton.y + yoffset; event->button.x_root = (gfloat)xevent->xbutton.x_root; event->button.y_root = (gfloat)xevent->xbutton.y_root; event->button.pressure = 0.5; @@ -769,8 +573,8 @@ gdk_event_translate (GdkEvent *event, event->button.type = GDK_BUTTON_RELEASE; event->button.window = window; event->button.time = xevent->xbutton.time; - event->button.x = xevent->xbutton.x; - event->button.y = xevent->xbutton.y; + event->button.x = xevent->xbutton.x + xoffset; + event->button.y = xevent->xbutton.y + yoffset; event->button.x_root = (gfloat)xevent->xbutton.x_root; event->button.y_root = (gfloat)xevent->xbutton.y_root; event->button.pressure = 0.5; @@ -803,8 +607,8 @@ gdk_event_translate (GdkEvent *event, event->motion.type = GDK_MOTION_NOTIFY; event->motion.window = window; event->motion.time = xevent->xmotion.time; - event->motion.x = xevent->xmotion.x; - event->motion.y = xevent->xmotion.y; + event->motion.x = xevent->xmotion.x + xoffset; + event->motion.y = xevent->xmotion.y + yoffset; event->motion.x_root = (gfloat)xevent->xmotion.x_root; event->motion.y_root = (gfloat)xevent->xmotion.y_root; event->motion.pressure = 0.5; @@ -845,8 +649,8 @@ gdk_event_translate (GdkEvent *event, event->crossing.subwindow = NULL; event->crossing.time = xevent->xcrossing.time; - event->crossing.x = xevent->xcrossing.x; - event->crossing.y = xevent->xcrossing.y; + event->crossing.x = xevent->xcrossing.x + xoffset; + event->crossing.y = xevent->xcrossing.y + yoffset; event->crossing.x_root = xevent->xcrossing.x_root; event->crossing.y_root = xevent->xcrossing.y_root; @@ -914,8 +718,8 @@ gdk_event_translate (GdkEvent *event, event->crossing.subwindow = NULL; event->crossing.time = xevent->xcrossing.time; - event->crossing.x = xevent->xcrossing.x; - event->crossing.y = xevent->xcrossing.y; + event->crossing.x = xevent->xcrossing.x + xoffset; + event->crossing.y = xevent->xcrossing.y + yoffset; event->crossing.x_root = xevent->xcrossing.x_root; event->crossing.y_root = xevent->xcrossing.y_root; @@ -1016,33 +820,41 @@ gdk_event_translate (GdkEvent *event, xevent->xexpose.x, xevent->xexpose.y, xevent->xexpose.width, xevent->xexpose.height, event->any.send_event ? " (send)" : "")); - gdk_compress_exposures (xevent, window); - - event->expose.type = GDK_EXPOSE; - event->expose.window = window; - event->expose.area.x = xevent->xexpose.x; - event->expose.area.y = xevent->xexpose.y; - event->expose.area.width = xevent->xexpose.width; - event->expose.area.height = xevent->xexpose.height; - event->expose.count = xevent->xexpose.count; - + { + GdkRectangle expose_rect; + + expose_rect.x = xevent->xexpose.x + xoffset; + expose_rect.y = xevent->xexpose.y + yoffset; + expose_rect.width = xevent->xexpose.width; + expose_rect.height = xevent->xexpose.height; + + _gdk_window_process_expose (window, xevent->xexpose.serial, &expose_rect); + + return_val = FALSE; + } + break; case GraphicsExpose: /* Print debugging info. */ - GDK_NOTE (EVENTS, - g_message ("graphics expose:\tdrawable: %ld", - xevent->xgraphicsexpose.drawable)); - - event->expose.type = GDK_EXPOSE; - event->expose.window = window; - event->expose.area.x = xevent->xgraphicsexpose.x; - event->expose.area.y = xevent->xgraphicsexpose.y; - event->expose.area.width = xevent->xgraphicsexpose.width; - event->expose.area.height = xevent->xgraphicsexpose.height; - event->expose.count = xevent->xexpose.count; + { + GdkRectangle expose_rect; + + GDK_NOTE (EVENTS, + g_message ("graphics expose:\tdrawable: %ld", + xevent->xgraphicsexpose.drawable)); + + expose_rect.x = xevent->xgraphicsexpose.x + xoffset; + expose_rect.y = xevent->xgraphicsexpose.y + yoffset; + expose_rect.width = xevent->xgraphicsexpose.width; + expose_rect.height = xevent->xgraphicsexpose.height; + + _gdk_window_process_expose (window, xevent->xgraphicsexpose.serial, &expose_rect); + + return_val = FALSE; + } break; case NoExpose: diff --git a/gdk/x11/gdkfont-x11.c b/gdk/x11/gdkfont-x11.c index b4e1020bca..4195a1f67d 100644 --- a/gdk/x11/gdkfont-x11.c +++ b/gdk/x11/gdkfont-x11.c @@ -27,7 +27,7 @@ #include <X11/Xlib.h> #include <X11/Xos.h> #include "gdkfont.h" -#include "gdkx.h" +#include "gdkprivate-x11.h" static GHashTable *font_name_hash = NULL; static GHashTable *fontset_name_hash = NULL; diff --git a/gdk/x11/gdkgc-x11.c b/gdk/x11/gdkgc-x11.c index bf3ff6617d..10d2d09245 100644 --- a/gdk/x11/gdkgc-x11.c +++ b/gdk/x11/gdkgc-x11.c @@ -1,5 +1,11 @@ #include "gdkgc.h" #include "gdkx.h" +#include "gdkregion-generic.h" + +typedef enum { + GDK_GC_DIRTY_CLIP = 1 << 0, + GDK_GC_DIRTY_TS = 1 << 1 +} GdkGCDirtyValues; static void gdk_x11_gc_values_to_xvalues (GdkGCValues *values, GdkGCValuesMask mask, @@ -31,6 +37,7 @@ _gdk_x11_gc_new (GdkDrawable *drawable, { GdkGC *gc; GdkGCPrivate *private; + GdkGCXData *data; XGCValues xvalues; unsigned long xvalues_mask; @@ -39,10 +46,25 @@ _gdk_x11_gc_new (GdkDrawable *drawable, private = (GdkGCPrivate *)gc; private->klass = &gdk_x11_gc_class; - private->klass_data = g_new (GdkGCXData, 1); + private->klass_data = data = g_new (GdkGCXData, 1); + + data->dirty_mask = 0; + data->clip_region = NULL; GDK_GC_XDATA (gc)->xdisplay = GDK_DRAWABLE_XDISPLAY (drawable); + if (values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN)) + { + values_mask &= ~(GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN); + data->dirty_mask |= GDK_GC_DIRTY_CLIP; + } + + if (values_mask & (GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN)) + { + values_mask &= ~(GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN); + data->dirty_mask |= GDK_GC_DIRTY_TS; + } + xvalues.function = GXcopy; xvalues.fill_style = FillSolid; xvalues.arc_mode = ArcPieSlice; @@ -52,7 +74,7 @@ _gdk_x11_gc_new (GdkDrawable *drawable, gdk_x11_gc_values_to_xvalues (values, values_mask, &xvalues, &xvalues_mask); - GDK_GC_XDATA (gc)->xgc = XCreateGC (GDK_GC_XDISPLAY (gc), + data->xgc = XCreateGC (GDK_GC_XDISPLAY (gc), GDK_DRAWABLE_XID (drawable), xvalues_mask, &xvalues); @@ -62,10 +84,55 @@ _gdk_x11_gc_new (GdkDrawable *drawable, static void gdk_x11_gc_destroy (GdkGC *gc) { + if (GDK_GC_XDATA (gc)->clip_region) + gdk_region_destroy (GDK_GC_XDATA (gc)->clip_region); + XFreeGC (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc)); g_free (GDK_GC_XDATA (gc)); } +GC +_gdk_x11_gc_flush (GdkGC *gc) +{ + GdkGCPrivate *private = (GdkGCPrivate *)gc; + GdkGCXData *data = GDK_GC_XDATA (gc); + + if (data->dirty_mask & GDK_GC_DIRTY_CLIP) + { + if (!data->clip_region) + XSetClipOrigin (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), + private->clip_x_origin, private->clip_y_origin); + else + { + XRectangle *rectangles = g_new (XRectangle, data->clip_region->numRects); + GdkRegionBox *boxes = data->clip_region->rects; + int i; + + for (i=0; i<data->clip_region->numRects; i++) + { + rectangles[i].x = CLAMP (boxes[i].x1 + private->clip_x_origin, G_MINSHORT, G_MAXSHORT); + rectangles[i].y = CLAMP (boxes[i].y1 + private->clip_y_origin, G_MINSHORT, G_MAXSHORT); + rectangles[i].width = CLAMP (boxes[i].x2 + private->clip_x_origin, G_MINSHORT, G_MAXSHORT) - rectangles[i].x; + rectangles[i].height = CLAMP (boxes[i].y2 + private->clip_y_origin, G_MINSHORT, G_MAXSHORT) - rectangles[i].y; + } + + XSetClipRectangles(GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), 0, 0, rectangles, + data->clip_region->numRects, YXBanded); + + g_free (rectangles); + } + } + + if (data->dirty_mask & GDK_GC_DIRTY_TS) + { + XSetTSOrigin (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), + private->ts_x_origin, private->ts_y_origin); + } + + data->dirty_mask = 0; + return GDK_GC_XGC (gc); +} + static void gdk_x11_gc_get_values (GdkGC *gc, GdkGCValues *values) @@ -215,9 +282,35 @@ gdk_x11_gc_set_values (GdkGC *gc, GdkGCValues *values, GdkGCValuesMask values_mask) { + GdkGCXData *data; XGCValues xvalues; unsigned long xvalues_mask = 0; + g_return_if_fail (gc != NULL); + + data = GDK_GC_XDATA (gc); + + if (values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN)) + { + values_mask &= ~(GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN); + data->dirty_mask |= GDK_GC_DIRTY_CLIP; + } + + if (values_mask & (GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN)) + { + values_mask &= ~(GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN); + data->dirty_mask |= GDK_GC_DIRTY_TS; + } + + if (values_mask & GDK_GC_CLIP_MASK) + { + if (data->clip_region) + { + gdk_region_destroy (data->clip_region); + data->clip_region = NULL; + } + } + gdk_x11_gc_values_to_xvalues (values, values_mask, &xvalues, &xvalues_mask); XChangeGC (GDK_GC_XDISPLAY (gc), @@ -454,43 +547,56 @@ void gdk_gc_set_clip_rectangle (GdkGC *gc, GdkRectangle *rectangle) { - XRectangle xrectangle; - + GdkGCPrivate *private = (GdkGCPrivate *)gc; + GdkGCXData *data; + g_return_if_fail (gc != NULL); + data = GDK_GC_XDATA (gc); + + if (data->clip_region) + gdk_region_destroy (data->clip_region); + if (rectangle) + data->clip_region = gdk_region_rectangle (rectangle); + else { - xrectangle.x = rectangle->x; - xrectangle.y = rectangle->y; - xrectangle.width = rectangle->width; - xrectangle.height = rectangle->height; - - XSetClipRectangles (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), 0, 0, - &xrectangle, 1, Unsorted); + data->clip_region = NULL; + XSetClipMask (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), None); } - else - XSetClipMask (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), None); + + private->clip_x_origin = 0; + private->clip_y_origin = 0; + + data->dirty_mask |= GDK_GC_DIRTY_CLIP; } void -gdk_gc_set_clip_region (GdkGC *gc, - GdkRegion *region) +gdk_gc_set_clip_region (GdkGC *gc, + GdkRegion *region) { - GdkGCPrivate *private; + GdkGCPrivate *private = (GdkGCPrivate *)gc; + GdkGCXData *data; g_return_if_fail (gc != NULL); - private = (GdkGCPrivate*) gc; + data = GDK_GC_XDATA (gc); + + if (data->clip_region) + gdk_region_destroy (data->clip_region); if (region) + data->clip_region = gdk_region_copy (region); + else { - GdkRegionPrivate *region_private; - - region_private = (GdkRegionPrivate*) region; - XSetRegion (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), region_private->xregion); + data->clip_region = NULL; + XSetClipMask (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), None); } - else - XSetClipMask (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), None); + + private->clip_x_origin = 0; + private->clip_y_origin = 0; + + data->dirty_mask |= GDK_GC_DIRTY_CLIP; } diff --git a/gdk/x11/gdkgeometry-x11.c b/gdk/x11/gdkgeometry-x11.c new file mode 100644 index 0000000000..40855e8abb --- /dev/null +++ b/gdk/x11/gdkgeometry-x11.c @@ -0,0 +1,698 @@ +/* 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. + */ + +/* gdkgeometry-x11.c: emulation of 32 bit coordinates within the + * limits of X. + * + * By Owen Taylor <otaylor@redhat.com> + * Copyright Red Hat, Inc. 2000 + */ + +#include "gdk.h" /* For gdk_rectangle_intersect */ +#include "gdkprivate-x11.h" +#include "gdkx.h" +#include "gdkregion.h" + +typedef struct _GdkWindowQueueItem GdkWindowQueueItem; +typedef struct _GdkWindowParentPos GdkWindowParentPos; + +typedef enum { + GDK_WINDOW_QUEUE_TRANSLATE, + GDK_WINDOW_QUEUE_ANTIEXPOSE +} GdkWindowQueueType; + +struct _GdkWindowQueueItem +{ + GdkWindow *window; + gulong serial; + GdkWindowQueueType type; + union { + struct { + gint dx; + gint dy; + } translate; + struct { + GdkRegion *area; + } antiexpose; + } u; +}; + +struct _GdkWindowParentPos +{ + gint x; + gint y; + gint x11_x; + gint x11_y; + GdkRectangle clip_rect; +}; + +static void gdk_window_compute_position (GdkWindow *window, + GdkWindowParentPos *parent_pos, + GdkXPositionInfo *info); +static void gdk_window_compute_parent_pos (GdkWindow *window, + GdkWindowParentPos *parent_pos); +static void gdk_window_premove (GdkWindow *window, + GdkWindowParentPos *parent_pos); +static void gdk_window_postmove (GdkWindow *window, + GdkWindowParentPos *parent_pos); +static void gdk_window_queue_translation (GdkWindow *window, + gint dx, + gint dy); +static void gdk_window_tmp_unset_bg (GdkWindow *window); +static void gdk_window_tmp_reset_bg (GdkWindow *window); +static void gdk_window_clip_changed (GdkWindow *window, + GdkRectangle *old_clip, + GdkRectangle *new_clip); + +static GSList *translate_queue = NULL; + +void +_gdk_windowing_window_get_offsets (GdkWindow *window, + gint *x_offset, + gint *y_offset) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + GdkWindowXData *data = (GdkWindowXData *)private->drawable.klass_data; + + *x_offset = data->position_info.x_offset; + *y_offset = data->position_info.y_offset; +} + +void +_gdk_window_init_position (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + GdkWindowXData *data; + GdkWindowParentPos parent_pos; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + data = (GdkWindowXData *)private->drawable.klass_data; + + gdk_window_compute_parent_pos (window, &parent_pos); + gdk_window_compute_position (window, &parent_pos, &data->position_info); +} + +void +_gdk_window_move_resize_child (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + GdkXPositionInfo new_info; + GdkWindowParentPos parent_pos; + GdkWindowXData *data; + GList *tmp_list; + + gint d_xoffset, d_yoffset; + gint dx, dy; + gboolean is_move; + gboolean is_resize; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + data = (GdkWindowXData *)private->drawable.klass_data; + + dx = x - private->x; + dy = y - private->y; + + is_move = dx != 0 || dy != 0; + is_resize = private->drawable.width != width || private->drawable.height != height; + + if (!is_move && !is_resize) + return; + + private->x = x; + private->y = y; + private->drawable.width = width; + private->drawable.height = height; + + gdk_window_compute_parent_pos (window, &parent_pos); + gdk_window_compute_position (window, &parent_pos, &new_info); + + gdk_window_clip_changed (window, &data->position_info.clip_rect, &new_info.clip_rect); + + parent_pos.x += private->x; + parent_pos.y += private->y; + parent_pos.x11_x += new_info.x; + parent_pos.x11_y += new_info.y; + parent_pos.clip_rect = new_info.clip_rect; + + d_xoffset = new_info.x_offset - data->position_info.x_offset; + d_yoffset = new_info.y_offset - data->position_info.y_offset; + + if (d_xoffset != 0 || d_yoffset != 0) + { + gint new_x0, new_y0, new_x1, new_y1; + + gdk_window_set_static_gravities (window, TRUE); + + if (d_xoffset < 0 || d_yoffset < 0) + gdk_window_queue_translation (window, MIN (d_xoffset, 0), MIN (d_yoffset, 0)); + + if (d_xoffset < 0) + { + new_x0 = data->position_info.x + d_xoffset; + new_x1 = data->position_info.x + data->position_info.width; + } + else + { + new_x0 = data->position_info.x; + new_x1 = data->position_info.x + new_info.width + d_xoffset; + } + + if (d_yoffset < 0) + { + new_y0 = data->position_info.y + d_yoffset; + new_y1 = data->position_info.y + data->position_info.height; + } + else + { + new_y0 = data->position_info.y; + new_y1 = data->position_info.y + new_info.height + d_yoffset; + } + + XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window), + GDK_DRAWABLE_XID (window), + new_x0, new_y0, new_x1 - new_x0, new_y1 - new_y0); + + tmp_list = private->children; + while (tmp_list) + { + gdk_window_premove (tmp_list->data, &parent_pos); + tmp_list = tmp_list->next; + } + + XMoveWindow (GDK_DRAWABLE_XDISPLAY (window), + GDK_DRAWABLE_XID (window), + new_x0 + dx, new_y0 + dy); + + if (d_xoffset > 0 || d_yoffset > 0) + gdk_window_queue_translation (window, MAX (d_xoffset, 0), MAX (d_yoffset, 0)); + + XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window), + GDK_DRAWABLE_XID (window), + new_info.x, new_info.y, new_info.width, new_info.height); + + if (data->position_info.no_bg) + gdk_window_tmp_reset_bg (window); + + if (!data->position_info.mapped && new_info.mapped && private->mapped) + XMapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window)); + + data->position_info = new_info; + + tmp_list = private->children; + while (tmp_list) + { + gdk_window_postmove (tmp_list->data, &parent_pos); + tmp_list = tmp_list->next; + } + } + else + { + if (is_move && is_resize) + gdk_window_set_static_gravities (window, FALSE); + + if (data->position_info.mapped && !new_info.mapped) + XUnmapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window)); + + tmp_list = private->children; + while (tmp_list) + { + gdk_window_premove (tmp_list->data, &parent_pos); + tmp_list = tmp_list->next; + } + + if (is_resize) + XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window), + GDK_DRAWABLE_XID (window), + new_info.x, new_info.y, new_info.width, new_info.height); + else + XMoveWindow (GDK_DRAWABLE_XDISPLAY (window), + GDK_DRAWABLE_XID (window), + new_info.x, new_info.y); + + tmp_list = private->children; + while (tmp_list) + { + gdk_window_postmove (tmp_list->data, &parent_pos); + tmp_list = tmp_list->next; + } + + if (data->position_info.no_bg) + gdk_window_tmp_reset_bg (window); + + if (!data->position_info.mapped && new_info.mapped && private->mapped) + XMapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window)); + + data->position_info = new_info; + } +} + +static void +gdk_window_compute_position (GdkWindow *window, + GdkWindowParentPos *parent_pos, + GdkXPositionInfo *info) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + int parent_x_offset; + int parent_y_offset; + + info->big = FALSE; + + if (private->drawable.width <= 32768) + { + info->width = private->drawable.width; + info->x = parent_pos->x + private->x - parent_pos->x11_x; + } + else + { + info->big = TRUE; + info->width = 32768; + if (parent_pos->x + private->x < -16384) + { + if (parent_pos->x + private->x + private->drawable.width < 16384) + info->x = parent_pos->x + private->x + private->drawable.width - 32768 - parent_pos->x11_x; + else + info->x = -16384 - parent_pos->x11_y; + } + else + info->x = parent_pos->x + private->x - parent_pos->x11_x; + } + + if (private->drawable.height <= 32768) + { + info->height = private->drawable.height; + info->y = parent_pos->y + private->y - parent_pos->x11_y; + } + else + { + info->big = TRUE; + info->height = 32768; + if (parent_pos->y + private->y < -16384) + { + if (parent_pos->y + private->y + private->drawable.height < 16384) + info->y = parent_pos->y + private->y + private->drawable.height - 32768 - parent_pos->x11_y; + else + info->y = -16384 - parent_pos->x11_y; + } + else + info->y = parent_pos->y + private->y - parent_pos->x11_y; + } + + parent_x_offset = parent_pos->x11_x - parent_pos->x; + parent_y_offset = parent_pos->x11_y - parent_pos->y; + + info->x_offset = parent_x_offset + info->x - private->x; + info->y_offset = parent_y_offset + info->y - private->y; + + /* We don't considering the clipping of toplevel windows and their immediate children + * by their parents, and simply always map those windows. + */ + if (parent_pos->clip_rect.width == G_MAXINT) + info->mapped = TRUE; + /* Check if the window would wrap around into the visible space in either direction */ + else if (info->x + parent_x_offset < parent_pos->clip_rect.x + parent_pos->clip_rect.width - 65536 || + info->x + info->width + parent_x_offset > parent_pos->clip_rect.x + 65536 || + info->y + parent_y_offset < parent_pos->clip_rect.y + parent_pos->clip_rect.height - 65536 || + info->y + info->width + parent_y_offset > parent_pos->clip_rect.y + 65536) + info->mapped = FALSE; + else + info->mapped = TRUE; + + info->no_bg = FALSE; + + if (GDK_DRAWABLE_TYPE (private) == GDK_WINDOW_CHILD) + { + info->clip_rect.x = private->x; + info->clip_rect.y = private->y; + info->clip_rect.width = private->drawable.width; + info->clip_rect.height = private->drawable.height; + + gdk_rectangle_intersect (&info->clip_rect, &parent_pos->clip_rect, &info->clip_rect); + + info->clip_rect.x -= private->x; + info->clip_rect.y -= private->y; + } + else + { + info->clip_rect.x = 0; + info->clip_rect.y = 0; + info->clip_rect.width = G_MAXINT; + info->clip_rect.height = G_MAXINT; + } +} + +static void +gdk_window_compute_parent_pos (GdkWindow *window, + GdkWindowParentPos *parent_pos) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + GdkWindowXData *data; + GdkRectangle tmp_clip; + + int clip_xoffset = 0; + int clip_yoffset = 0; + + parent_pos->x = 0; + parent_pos->y = 0; + parent_pos->x11_x = 0; + parent_pos->x11_y = 0; + + /* We take a simple approach here and simply consider toplevel + * windows not to clip their children on the right/bottom, since the + * size of toplevel windows is not directly under our + * control. Clipping only really matters when scrolling and + * generally we aren't going to be moving the immediate child of a + * toplevel beyond the bounds of that toplevel. + * + * We could go ahead and recompute the clips of toplevel windows and + * their descendents when we receive size notification, but it would + * probably not be an improvement in most cases. + */ + parent_pos->clip_rect.x = 0; + parent_pos->clip_rect.y = 0; + parent_pos->clip_rect.width = G_MAXINT; + parent_pos->clip_rect.height = G_MAXINT; + + private = (GdkWindowPrivate *)private->parent; + while (private && private->drawable.window_type == GDK_WINDOW_CHILD) + { + data = (GdkWindowXData *)private->drawable.klass_data; + + tmp_clip.x = - clip_xoffset; + tmp_clip.y = - clip_yoffset; + tmp_clip.width = private->drawable.width; + tmp_clip.height = private->drawable.height; + + gdk_rectangle_intersect (&parent_pos->clip_rect, &tmp_clip, &parent_pos->clip_rect); + + parent_pos->x += private->x; + parent_pos->y += private->y; + parent_pos->x11_x += data->position_info.x; + parent_pos->x11_y += data->position_info.y; + + clip_xoffset += private->x; + clip_yoffset += private->y; + + private = (GdkWindowPrivate *)private->parent; + } +} + +static void +gdk_window_premove (GdkWindow *window, + GdkWindowParentPos *parent_pos) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + GdkWindowXData *data = GDK_WINDOW_XDATA (window); + GdkXPositionInfo new_info; + GList *tmp_list; + gint d_xoffset, d_yoffset; + GdkWindowParentPos this_pos; + + gdk_window_compute_position (window, parent_pos, &new_info); + + gdk_window_clip_changed (window, &data->position_info.clip_rect, &new_info.clip_rect); + + this_pos.x = parent_pos->x + private->x; + this_pos.y = parent_pos->y + private->y; + this_pos.x11_x = parent_pos->x11_x + new_info.x; + this_pos.x11_y = parent_pos->x11_y + new_info.y; + this_pos.clip_rect = new_info.clip_rect; + + if (data->position_info.mapped && !new_info.mapped) + XUnmapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window)); + + d_xoffset = new_info.x_offset - data->position_info.x_offset; + d_yoffset = new_info.y_offset - data->position_info.y_offset; + + if (d_xoffset != 0 || d_yoffset != 0) + { + gint new_x0, new_y0, new_x1, new_y1; + + if (d_xoffset < 0 || d_yoffset < 0) + gdk_window_queue_translation (window, MIN (d_xoffset, 0), MIN (d_yoffset, 0)); + + if (d_xoffset < 0) + { + new_x0 = data->position_info.x + d_xoffset; + new_x1 = data->position_info.x + data->position_info.width; + } + else + { + new_x0 = data->position_info.x; + new_x1 = data->position_info.x + new_info.width + d_xoffset; + } + + if (d_yoffset < 0) + { + new_y0 = data->position_info.y + d_yoffset; + new_y1 = data->position_info.y + data->position_info.height; + } + else + { + new_y0 = data->position_info.y; + new_y1 = data->position_info.y + new_info.height + d_yoffset; + } + + XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window), + GDK_DRAWABLE_XID (window), + new_x0, new_y0, new_x1 - new_x0, new_y1 - new_y0); + } + + tmp_list = private->children; + while (tmp_list) + { + gdk_window_premove (tmp_list->data, &this_pos); + tmp_list = tmp_list->next; + } +} + +static void +gdk_window_postmove (GdkWindow *window, + GdkWindowParentPos *parent_pos) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + GdkWindowXData *data = (GdkWindowXData *)private->drawable.klass_data; + GdkXPositionInfo new_info; + GList *tmp_list; + gint d_xoffset, d_yoffset; + GdkWindowParentPos this_pos; + + gdk_window_compute_position (window, parent_pos, &new_info); + + this_pos.x = parent_pos->x + private->x; + this_pos.y = parent_pos->y + private->y; + this_pos.x11_x = parent_pos->x11_x + new_info.x; + this_pos.x11_y = parent_pos->x11_y + new_info.y; + this_pos.clip_rect = new_info.clip_rect; + + d_xoffset = new_info.x_offset - data->position_info.x_offset; + d_yoffset = new_info.y_offset - data->position_info.y_offset; + + if (d_xoffset != 0 || d_yoffset != 0) + { + if (d_xoffset > 0 || d_yoffset > 0) + gdk_window_queue_translation (window, MAX (d_xoffset, 0), MAX (d_yoffset, 0)); + + XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window), + GDK_DRAWABLE_XID (window), + new_info.x, new_info.y, new_info.width, new_info.height); + } + + if (!data->position_info.mapped && new_info.mapped && private->mapped) + XMapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window)); + + if (data->position_info.no_bg) + gdk_window_tmp_reset_bg (window); + + data->position_info = new_info; + + tmp_list = private->children; + while (tmp_list) + { + gdk_window_postmove (tmp_list->data, &this_pos); + tmp_list = tmp_list->next; + } +} + +static void +gdk_window_queue_translation (GdkWindow *window, + gint dx, + gint dy) +{ + GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1); + item->window = window; + item->serial = NextRequest (GDK_WINDOW_XDISPLAY (window)); + item->type = GDK_WINDOW_QUEUE_TRANSLATE; + item->u.translate.dx = dx; + item->u.translate.dy = dy; + + gdk_drawable_ref (window); + translate_queue = g_slist_append (translate_queue, item); +} + +gboolean +_gdk_windowing_window_queue_antiexpose (GdkWindow *window, + GdkRegion *area) +{ + GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1); + item->window = window; + item->serial = NextRequest (GDK_WINDOW_XDISPLAY (window)); + item->type = GDK_WINDOW_QUEUE_ANTIEXPOSE; + item->u.antiexpose.area = area; + + gdk_drawable_ref (window); + translate_queue = g_slist_append (translate_queue, item); + + return TRUE; +} + +void +_gdk_window_process_expose (GdkWindow *window, + gulong serial, + GdkRectangle *area) +{ + GdkWindowXData *data = GDK_WINDOW_XDATA (window); + GdkRegion *invalidate_region = gdk_region_rectangle (area); + GdkRegion *clip_region; + + GSList *tmp_list = translate_queue; + + while (tmp_list) + { + GdkWindowQueueItem *item = tmp_list->data; + tmp_list = tmp_list->next; + + if (serial < item->serial) + { + if (item->window == window) + { + if (item->type == GDK_WINDOW_QUEUE_TRANSLATE) + gdk_region_offset (invalidate_region, - item->u.translate.dx, - item->u.translate.dy); + else /* anti-expose */ + gdk_region_subtract (invalidate_region, item->u.antiexpose.area); + } + } + else + { + GSList *tmp_link = translate_queue; + + translate_queue = g_slist_remove_link (translate_queue, translate_queue); + gdk_drawable_unref (item->window); + + if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE) + gdk_region_destroy (item->u.antiexpose.area); + + g_free (item); + g_slist_free_1 (tmp_link); + } + } + + clip_region = gdk_region_rectangle (&data->position_info.clip_rect); + gdk_region_intersect (invalidate_region, clip_region); + + if (!gdk_region_empty (invalidate_region)) + gdk_window_invalidate_region (window, invalidate_region, FALSE); + + gdk_region_destroy (invalidate_region); + gdk_region_destroy (clip_region); +} + +static void +gdk_window_tmp_unset_bg (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + GdkWindowXData *data = GDK_WINDOW_XDATA (window); + + data->position_info.no_bg = TRUE; + + if (private->bg_pixmap != GDK_NO_BG) + XSetWindowBackgroundPixmap (GDK_DRAWABLE_XDISPLAY (window), + GDK_DRAWABLE_XID (window), None); +} + +static void +gdk_window_tmp_reset_bg (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + GdkWindowXData *data = GDK_WINDOW_XDATA (window); + + data->position_info.no_bg = FALSE; + + if (private->bg_pixmap == GDK_NO_BG) + return; + + if (private->bg_pixmap) + { + Pixmap xpixmap; + + if (private->bg_pixmap == GDK_PARENT_RELATIVE_BG) + xpixmap = ParentRelative; + else + xpixmap = GDK_DRAWABLE_XID (private->bg_pixmap); + + XSetWindowBackgroundPixmap (GDK_DRAWABLE_XDISPLAY (window), + GDK_DRAWABLE_XID (window), xpixmap); + } + else + { + XSetWindowBackground (GDK_DRAWABLE_XDISPLAY (window), + GDK_DRAWABLE_XID (window), + private->bg_color.pixel); + } +} + +static void +gdk_window_clip_changed (GdkWindow *window, GdkRectangle *old_clip, GdkRectangle *new_clip) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + + GdkRegion *old_clip_region; + GdkRegion *new_clip_region; + + if (private->input_only) + return; + + old_clip_region = gdk_region_rectangle (old_clip); + new_clip_region = gdk_region_rectangle (new_clip); + + /* Trim invalid region of window to new clip rectangle + */ + if (private->update_area) + gdk_region_intersect (private->update_area, new_clip_region); + + /* Invalidate newly exposed portion of window + */ + gdk_region_subtract (new_clip_region, old_clip_region); + if (!gdk_region_empty (new_clip_region)) + { + gdk_window_tmp_unset_bg (window); + gdk_window_invalidate_region (window, new_clip_region, FALSE); + } + + gdk_region_destroy (new_clip_region); + gdk_region_destroy (old_clip_region); +} + diff --git a/gdk/x11/gdkim-x11.c b/gdk/x11/gdkim-x11.c index 6ad29752e3..0d309a768d 100644 --- a/gdk/x11/gdkim-x11.c +++ b/gdk/x11/gdkim-x11.c @@ -29,9 +29,9 @@ #include "gdk.h" /* For gdk_flush() */ #include "gdkim.h" #include "gdkpixmap.h" -#include "gdkprivate.h" #include "gdki18n.h" -#include "gdkx.h" +#include "gdkinternals.h" +#include "gdkprivate-x11.h" #if HAVE_CONFIG_H # include <config.h> diff --git a/gdk/x11/gdkimage-x11.c b/gdk/x11/gdkimage-x11.c index cee55c7115..2972e7a4ee 100644 --- a/gdk/x11/gdkimage-x11.c +++ b/gdk/x11/gdkimage-x11.c @@ -56,7 +56,7 @@ #include "gdk.h" /* For gdk_error_trap_* / gdk_flush_* */ #include "gdkimage.h" #include "gdkprivate.h" -#include "gdkx.h" +#include "gdkprivate-x11.h" static void gdk_x11_image_destroy (GdkImage *image); static void gdk_image_put_normal (GdkImage *image, @@ -480,7 +480,7 @@ gdk_image_put_normal (GdkImage *image, g_return_if_fail (image->type == GDK_IMAGE_NORMAL); XPutImage (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), - GDK_GC_XGC (gc), image_private->ximage, + GDK_GC_GET_XGC (gc), image_private->ximage, xsrc, ysrc, xdest, ydest, width, height); } @@ -509,7 +509,7 @@ gdk_image_put_shared (GdkImage *image, g_return_if_fail (image->type == GDK_IMAGE_SHARED); XShmPutImage (GDK_DRAWABLE_XDISPLAY (drawable), GDK_DRAWABLE_XID (drawable), - GDK_GC_XGC (gc), image_private->ximage, + GDK_GC_GET_XGC (gc), image_private->ximage, xsrc, ysrc, xdest, ydest, width, height, False); #else /* USE_SHM */ g_error ("trying to draw shared memory image when gdk was compiled without shared memory support"); diff --git a/gdk/x11/gdkinput-x11.c b/gdk/x11/gdkinput-x11.c index eb6d57295b..04356378d8 100644 --- a/gdk/x11/gdkinput-x11.c +++ b/gdk/x11/gdkinput-x11.c @@ -25,6 +25,7 @@ */ #include "gdkinputprivate.h" +#include "gdkinternals.h" #include "gdkx.h" /* Forward declarations */ @@ -146,6 +147,7 @@ gdk_input_device_new(XDeviceInfo *device, gint include_core) gdkdev->info.num_axes = 0; gdkdev->info.num_keys = 0; + gdkdev->info.axes = NULL; gdkdev->info.keys = NULL; gdkdev->axes = 0; gdkdev->info.has_cursor = 0; @@ -237,6 +239,8 @@ gdk_input_device_new(XDeviceInfo *device, gint include_core) g_free(gdkdev->axes); if (gdkdev->info.keys) g_free(gdkdev->info.keys); + if (gdkdev->info.axes) + g_free (gdkdev->info.axes); g_free(gdkdev); return NULL; } diff --git a/gdk/x11/gdkinputprivate.h b/gdk/x11/gdkinputprivate.h index 2efbcb1283..552bd1b034 100644 --- a/gdk/x11/gdkinputprivate.h +++ b/gdk/x11/gdkinputprivate.h @@ -141,8 +141,8 @@ struct _GdkInputWindow GdkExtensionMode mode; /* position relative to root window */ - gint16 root_x; - gint16 root_y; + gint root_x; + gint root_y; /* rectangles relative to window of windows obscuring this one */ GdkRectangle *obscuring; diff --git a/gdk/x11/gdkmain-x11.c b/gdk/x11/gdkmain-x11.c index 332ad77183..869d5b731b 100644 --- a/gdk/x11/gdkmain-x11.c +++ b/gdk/x11/gdkmain-x11.c @@ -46,8 +46,8 @@ #include "gdk.h" -#include "gdkx.h" -#include "gdkprivate.h" +#include "gdkprivate-x11.h" +#include "gdkinternals.h" #include "gdkinputprivate.h" typedef struct _GdkPredicate GdkPredicate; diff --git a/gdk/x11/gdkpixmap-x11.c b/gdk/x11/gdkpixmap-x11.c index 45807cb613..f1822aabd3 100644 --- a/gdk/x11/gdkpixmap-x11.c +++ b/gdk/x11/gdkpixmap-x11.c @@ -33,8 +33,7 @@ #include <X11/Xlib.h> #include "gdkpixmap.h" -#include "gdkprivate.h" -#include "gdkx.h" +#include "gdkprivate-x11.h" typedef struct { @@ -119,6 +118,7 @@ gdk_pixmap_new (GdkWindow *window, width, height, depth); private->width = width; private->height = height; + private->depth = depth; gdk_xid_table_insert (&GDK_DRAWABLE_XID (pixmap), pixmap); @@ -149,6 +149,7 @@ gdk_bitmap_create_from_data (GdkWindow *window, private->width = width; private->height = height; + private->depth = 1; GDK_DRAWABLE_XDATA (private)->xdisplay = GDK_DRAWABLE_XDISPLAY (window); GDK_DRAWABLE_XDATA (private)->xid = XCreateBitmapFromData (GDK_DRAWABLE_XDISPLAY (window), @@ -193,6 +194,7 @@ gdk_pixmap_create_from_data (GdkWindow *window, private->width = width; private->height = height; + private->depth = depth; GDK_DRAWABLE_XDATA (private)->xdisplay = GDK_DRAWABLE_XDISPLAY (window); GDK_DRAWABLE_XDATA (private)->xid = XCreatePixmapFromBitmapData (GDK_DRAWABLE_XDISPLAY (window), @@ -804,6 +806,7 @@ gdk_pixmap_foreign_new (guint32 anid) private->width = w_ret; private->height = h_ret; + private->depth = depth_ret; gdk_xid_table_insert(&GDK_DRAWABLE_XID (pixmap), pixmap); diff --git a/gdk/x11/gdkpoly-generic.h b/gdk/x11/gdkpoly-generic.h new file mode 100644 index 0000000000..660c689adb --- /dev/null +++ b/gdk/x11/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/x11/gdkpolyreg-generic.c b/gdk/x11/gdkpolyreg-generic.c new file mode 100644 index 0000000000..b98bd5641e --- /dev/null +++ b/gdk/x11/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 = ®->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/x11/gdkprivate-x11.h b/gdk/x11/gdkprivate-x11.h index 27d3451dec..e61e7e28c6 100644 --- a/gdk/x11/gdkprivate-x11.h +++ b/gdk/x11/gdkprivate-x11.h @@ -1,109 +1,42 @@ +/* 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_X11_H__ #define __GDK_PRIVATE_X11_H__ -#include <X11/Xlib.h> -#include <X11/Xutil.h> - -#include <gdk/gdkfont.h> #include <gdk/gdkprivate.h> -#include <gdk/gdkcursor.h> - -typedef struct _GdkGCXData GdkGCXData; -typedef struct _GdkDrawableXData GdkDrawableXData; -typedef struct _GdkColormapPrivateX GdkColormapPrivateX; -typedef struct _GdkCursorPrivate GdkCursorPrivate; -typedef struct _GdkFontPrivateX GdkFontPrivateX; -typedef struct _GdkImagePrivateX GdkImagePrivateX; -typedef struct _GdkVisualPrivate GdkVisualPrivate; -typedef struct _GdkRegionPrivate GdkRegionPrivate; - -#ifdef USE_XIM -typedef struct _GdkICPrivate GdkICPrivate; -#endif /* USE_XIM */ - -#define GDK_DRAWABLE_XDATA(win) ((GdkDrawableXData *)(((GdkDrawablePrivate*)(win))->klass_data)) -#define GDK_GC_XDATA(gc) ((GdkGCXData *)(((GdkGCPrivate*)(gc))->klass_data)) - -struct _GdkGCXData -{ - GC xgc; - Display *xdisplay; -}; - -struct _GdkDrawableXData -{ - Window xid; - Display *xdisplay; -}; - -struct _GdkCursorPrivate -{ - GdkCursor cursor; - Cursor xcursor; - Display *xdisplay; -}; - -struct _GdkFontPrivateX -{ - GdkFontPrivate base; - /* XFontStruct *xfont; */ - /* generic pointer point to XFontStruct or XFontSet */ - gpointer xfont; - Display *xdisplay; - - GSList *names; -}; - -struct _GdkVisualPrivate -{ - GdkVisual visual; - Visual *xvisual; -}; - -struct _GdkColormapPrivateX -{ - GdkColormapPrivate base; - - Colormap xcolormap; - Display *xdisplay; - gint private_val; - - GHashTable *hash; - GdkColorInfo *info; - time_t last_sync_time; -}; - -struct _GdkImagePrivateX -{ - GdkImagePrivate base; - - XImage *ximage; - Display *xdisplay; - gpointer x_shm_info; -}; - -struct _GdkRegionPrivate -{ - GdkRegion region; - Region xregion; -}; - - -#ifdef USE_XIM - -struct _GdkICPrivate -{ - XIC xic; - GdkICAttr *attr; - GdkICAttributesType mask; -}; - -#endif /* USE_XIM */ +#include "gdkx.h" void gdk_xid_table_insert (XID *xid, gpointer data); void gdk_xid_table_remove (XID xid); -gpointer gdk_xid_table_lookup (XID xid); gint gdk_send_xevent (Window window, gboolean propagate, glong event_mask, @@ -114,6 +47,8 @@ GdkGC * _gdk_x11_gc_new (GdkDrawable *drawable, GdkColormap * gdk_colormap_lookup (Colormap xcolormap); GdkVisual * gdk_visual_lookup (Visual *xvisual); +void gdk_window_add_colormap_windows (GdkWindow *window); + /* Please see gdkwindow.c for comments on how to use */ Window gdk_window_xid_at (Window base, gint bx, @@ -127,19 +62,25 @@ Window gdk_window_xid_at_coords (gint x, GList *excludes, gboolean excl_child); +/* Routines from gdkgeometry-x11.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); + extern GdkDrawableClass _gdk_x11_drawable_class; extern gboolean gdk_use_xshm; -extern gchar *gdk_display_name; -extern Display *gdk_display; -extern Window gdk_root_window; -extern Window gdk_leader_window; extern Atom gdk_wm_delete_window; extern Atom gdk_wm_take_focus; extern Atom gdk_wm_protocols; extern Atom gdk_wm_window_protocols[]; -extern Atom gdk_selection_property; extern GdkWindow *selection_owner[]; -extern gchar *gdk_progclass; extern gboolean gdk_null_window_warnings; extern const int gdk_nevent_masks; extern const int gdk_event_mask_table[]; @@ -156,3 +97,4 @@ extern GdkWindow *gdk_xim_window; /* currently using Window */ #endif /* __GDK_PRIVATE_X11_H__ */ + diff --git a/gdk/x11/gdkregion-generic.c b/gdk/x11/gdkregion-generic.c new file mode 100644 index 0000000000..0319f939f4 --- /dev/null +++ b/gdk/x11/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(®ion->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(®ion->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 = ▭ + 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 (®ion->extents, prect)) + return GDK_OVERLAP_RECTANGLE_IN; + + 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/x11/gdkregion-generic.h b/gdk/x11/gdkregion-generic.h new file mode 100644 index 0000000000..659d44eb4c --- /dev/null +++ b/gdk/x11/gdkregion-generic.h @@ -0,0 +1,167 @@ +/* $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 struct _GdkRegionBox GdkRegionBox; + +struct _GdkRegionBox +{ + int x1, x2, y1, y2; +}; + +/* + * 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/x11/gdkregion-x11.c b/gdk/x11/gdkregion-x11.c index b21aba8938..58192fdb0b 100644 --- a/gdk/x11/gdkregion-x11.c +++ b/gdk/x11/gdkregion-x11.c @@ -89,19 +89,19 @@ void gdk_region_get_clipbox(GdkRegion *region, GdkRectangle *rectangle) { - GdkRegionPrivate *rp; - XRectangle r; - - g_return_if_fail(region != NULL); - g_return_if_fail(rectangle != NULL); - - rp = (GdkRegionPrivate *)region; - XClipBox(rp->xregion, &r); - - rectangle->x = r.x; - rectangle->y = r.y; - rectangle->width = r.width; - rectangle->height = r.height; + GdkRegionPrivate *rp; + XRectangle r; + + g_return_if_fail(region != NULL); + g_return_if_fail(rectangle != NULL); + + rp = (GdkRegionPrivate *)region; + XClipBox(rp->xregion, &r); + + rectangle->x = r.x; + rectangle->y = r.y; + rectangle->width = r.width; + rectangle->height = r.height; } gboolean diff --git a/gdk/x11/gdkselection-x11.c b/gdk/x11/gdkselection-x11.c index 42e00195ed..31a6eb0b91 100644 --- a/gdk/x11/gdkselection-x11.c +++ b/gdk/x11/gdkselection-x11.c @@ -31,7 +31,7 @@ #include "gdkproperty.h" #include "gdkselection.h" #include "gdkprivate.h" -#include "gdkx.h" +#include "gdkprivate-x11.h" gboolean diff --git a/gdk/x11/gdkvisual-x11.c b/gdk/x11/gdkvisual-x11.c index bb007d4a9b..279d2e3aa0 100644 --- a/gdk/x11/gdkvisual-x11.c +++ b/gdk/x11/gdkvisual-x11.c @@ -29,6 +29,7 @@ #include "gdkvisual.h" #include "gdkprivate-x11.h" +#include "gdkinternals.h" static void gdk_visual_add (GdkVisual *visual); static void gdk_visual_decompose_mask (gulong mask, diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c index fe1be34a49..0dfd24cd17 100644 --- a/gdk/x11/gdkwindow-x11.c +++ b/gdk/x11/gdkwindow-x11.c @@ -34,7 +34,7 @@ #include "gdkwindow.h" #include "gdkinputprivate.h" #include "gdkprivate-x11.h" -#include "gdkx.h" +#include "gdkinternals.h" #include "MwmUtil.h" #include <stdlib.h> @@ -78,6 +78,8 @@ static void gdk_window_set_static_win_gravity (GdkWindow *window, gboolean on); static gboolean gdk_window_have_shape_ext (void); +GdkDrawableClass _gdk_windowing_window_class; + static void gdk_x11_window_destroy (GdkDrawable *drawable) { @@ -98,22 +100,21 @@ gdk_x11_window_alloc (void) GdkWindow *window; GdkWindowPrivate *private; - static GdkDrawableClass klass; static gboolean initialized = FALSE; if (!initialized) { initialized = TRUE; - - klass = _gdk_x11_drawable_class; - klass.destroy = gdk_x11_window_destroy; + + _gdk_windowing_window_class = _gdk_x11_drawable_class; + _gdk_windowing_window_class.destroy = gdk_x11_window_destroy; } window = _gdk_window_alloc (); private = (GdkWindowPrivate *)window; - private->drawable.klass = &klass; - private->drawable.klass_data = g_new (GdkDrawableXData, 1); + private->drawable.klass = &_gdk_window_class; + private->drawable.klass_data = g_new (GdkWindowXData, 1); return window; } @@ -207,6 +208,10 @@ gdk_window_new (GdkWindow *parent, 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_window_init_position (window); + if (GDK_WINDOW_XDATA (window)->position_info.big) + private->guffaw_gravity = TRUE; if (attributes_mask & GDK_WA_VISUAL) visual = attributes->visual; @@ -232,7 +237,7 @@ gdk_window_new (GdkWindow *parent, } else xattributes.override_redirect = False; - + if (parent_private && parent_private->guffaw_gravity) { xattributes.win_gravity = StaticGravity; @@ -243,6 +248,9 @@ gdk_window_new (GdkWindow *parent, { class = InputOutput; depth = visual->depth; + + private->input_only = FALSE; + private->drawable.depth = depth; if (attributes_mask & GDK_WA_COLORMAP) private->drawable.colormap = attributes->colormap; @@ -254,10 +262,21 @@ gdk_window_new (GdkWindow *parent, private->drawable.colormap = gdk_colormap_new (visual, False); } - xattributes.background_pixel = BlackPixel (gdk_display, gdk_screen); + private->bg_color.pixel = BlackPixel (gdk_display, gdk_screen); + xattributes.background_pixel = private->bg_color.pixel; + + private->bg_pixmap = NULL; + xattributes.border_pixel = BlackPixel (gdk_display, gdk_screen); xattributes_mask |= CWBorderPixel | CWBackPixel; + + if (private->guffaw_gravity) + xattributes.bit_gravity = StaticGravity; + else + xattributes.bit_gravity = NorthWestGravity; + xattributes_mask |= CWBitGravity; + switch (private->drawable.window_type) { case GDK_WINDOW_TOPLEVEL: @@ -302,6 +321,7 @@ gdk_window_new (GdkWindow *parent, { depth = 0; class = InputOnly; + private->input_only = TRUE; private->drawable.colormap = NULL; } @@ -443,7 +463,7 @@ gdk_window_foreign_new (guint32 anid) parent_private->children = g_list_prepend (parent_private->children, window); GDK_DRAWABLE_XDATA (window)->xid = anid; - GDK_DRAWABLE_XDATA (window)->xdisplay = GDK_DRAWABLE_XDISPLAY (parent); + GDK_DRAWABLE_XDATA (window)->xdisplay = GDK_DRAWABLE_XDISPLAY (private->parent); private->x = attrs.x; private->y = attrs.y; @@ -495,6 +515,12 @@ gdk_window_internal_destroy (GdkWindow *window, 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) { @@ -624,8 +650,10 @@ gdk_window_show (GdkWindow *window) private->mapped = TRUE; XRaiseWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window)); - XMapWindow (GDK_DRAWABLE_XDISPLAY (window), - GDK_DRAWABLE_XID (window)); + + if (GDK_WINDOW_XDATA (window)->position_info.mapped) + XMapWindow (GDK_DRAWABLE_XDISPLAY (window), + GDK_DRAWABLE_XID (window)); } } @@ -663,23 +691,13 @@ gdk_window_move (GdkWindow *window, gint x, gint y) { - GdkWindowPrivate *private; + GdkWindowPrivate *private = (GdkWindowPrivate *)window; g_return_if_fail (window != NULL); - - private = (GdkWindowPrivate*) window; - if (!private->drawable.destroyed) - { - XMoveWindow (GDK_DRAWABLE_XDISPLAY (window), - GDK_DRAWABLE_XID (window), - x, y); - - if (private->drawable.window_type == GDK_WINDOW_CHILD) - { - private->x = x; - private->y = y; - } - } + g_return_if_fail (GDK_IS_WINDOW (window)); + + gdk_window_move_resize (window, x, y, + private->drawable.width, private->drawable.height); } void @@ -699,20 +717,17 @@ gdk_window_resize (GdkWindow *window, private = (GdkWindowPrivate*) window; - if (!private->drawable.destroyed && - ((private->resize_count > 0) || - (private->drawable.width != (guint16) width) || - (private->drawable.height != (guint16) height))) + if (!GDK_DRAWABLE_DESTROYED (window)) { - XResizeWindow (GDK_DRAWABLE_XDISPLAY (private), - GDK_DRAWABLE_XID (private), - width, height); - private->resize_count += 1; - if (GDK_DRAWABLE_TYPE (private) == GDK_WINDOW_CHILD) + _gdk_window_move_resize_child (window, private->x, private->y, + width, height); + else { - private->drawable.width = width; - private->drawable.height = height; + XResizeWindow (GDK_DRAWABLE_XDISPLAY (window), + GDK_DRAWABLE_XID (window), + width, height); + private->resize_count += 1; } } } @@ -738,30 +753,13 @@ gdk_window_move_resize (GdkWindow *window, if (!GDK_DRAWABLE_DESTROYED (window)) { - XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window), - GDK_DRAWABLE_XID (window), - x, y, width, height); - - if (private->guffaw_gravity) - { - GList *tmp_list = private->children; - while (tmp_list) - { - GdkWindowPrivate *child_private = tmp_list->data; - - child_private->x -= x - private->x; - child_private->y -= y - private->y; - - tmp_list = tmp_list->next; - } - } - if (GDK_DRAWABLE_TYPE (private) == GDK_WINDOW_CHILD) + _gdk_window_move_resize_child (window, x, y, width, height); + else { - private->x = x; - private->y = y; - private->drawable.width = width; - private->drawable.height = height; + XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window), + GDK_DRAWABLE_XID (window), + x, y, width, height); } } } @@ -818,11 +816,11 @@ gdk_window_clear (GdkWindow *window) } void -gdk_window_clear_area (GdkWindow *window, - gint x, - gint y, - gint width, - gint height) +_gdk_windowing_window_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) { g_return_if_fail (window != NULL); g_return_if_fail (GDK_IS_WINDOW (window)); @@ -833,11 +831,11 @@ gdk_window_clear_area (GdkWindow *window, } void -gdk_window_clear_area_e (GdkWindow *window, - gint x, - gint y, - gint width, - gint height) +_gdk_windowing_window_clear_area_e (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) { g_return_if_fail (window != NULL); g_return_if_fail (GDK_IS_WINDOW (window)); @@ -1058,12 +1056,24 @@ 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)); if (!GDK_DRAWABLE_DESTROYED (window)) XSetWindowBackground (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window), color->pixel); + + 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 @@ -1071,18 +1081,37 @@ gdk_window_set_back_pixmap (GdkWindow *window, GdkPixmap *pixmap, gboolean parent_relative) { + GdkWindowPrivate *private = (GdkWindowPrivate *)window; Pixmap xpixmap; g_return_if_fail (window != NULL); g_return_if_fail (GDK_IS_WINDOW (window)); - - if (pixmap) - xpixmap = GDK_DRAWABLE_XID (pixmap); - else - xpixmap = None; - + g_return_if_fail (pixmap == NULL || !parent_relative); + + if (private->bg_pixmap && + private->bg_pixmap != GDK_PARENT_RELATIVE_BG && + private->bg_pixmap != GDK_NO_BG) + gdk_pixmap_unref (private->bg_pixmap); + if (parent_relative) - xpixmap = ParentRelative; + { + xpixmap = ParentRelative; + private->bg_pixmap = GDK_PARENT_RELATIVE_BG; + } + else + { + if (pixmap) + { + gdk_pixmap_ref (pixmap); + private->bg_pixmap = pixmap; + xpixmap = GDK_DRAWABLE_XID (pixmap); + } + else + { + xpixmap = None; + private->bg_pixmap = GDK_NO_BG; + } + } if (!GDK_DRAWABLE_DESTROYED (window)) XSetWindowBackgroundPixmap (GDK_DRAWABLE_XDISPLAY (window), @@ -2181,9 +2210,12 @@ static void gdk_window_set_static_bit_gravity (GdkWindow *window, gboolean on) { XSetWindowAttributes xattributes; + guint xattributes_mask = 0; g_return_if_fail (window != NULL); + xattributes.bit_gravity = StaticGravity; + xattributes_mask |= CWBitGravity; xattributes.bit_gravity = on ? StaticGravity : ForgetGravity; XChangeWindowAttributes (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window), diff --git a/gdk/x11/gdkx.h b/gdk/x11/gdkx.h index dcbd26b803..d160b21ec7 100644 --- a/gdk/x11/gdkx.h +++ b/gdk/x11/gdkx.h @@ -27,26 +27,153 @@ #ifndef __GDK_X_H__ #define __GDK_X_H__ -#include <gdk/x11/gdkprivate-x11.h> +#include <gdk/gdkprivate.h> +#include <gdk/gdkcursor.h> + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +typedef struct _GdkGCXData GdkGCXData; +typedef struct _GdkDrawableXData GdkDrawableXData; +typedef struct _GdkWindowXData GdkWindowXData; +typedef struct _GdkXPositionInfo GdkXPositionInfo; +typedef struct _GdkColormapPrivateX GdkColormapPrivateX; +typedef struct _GdkCursorPrivate GdkCursorPrivate; +typedef struct _GdkFontPrivateX GdkFontPrivateX; +typedef struct _GdkImagePrivateX GdkImagePrivateX; +typedef struct _GdkVisualPrivate GdkVisualPrivate; + +#ifdef USE_XIM +typedef struct _GdkICPrivate GdkICPrivate; +#endif /* USE_XIM */ + +#define GDK_DRAWABLE_XDATA(win) ((GdkDrawableXData *)(((GdkDrawablePrivate*)(win))->klass_data)) +#define GDK_WINDOW_XDATA(win) ((GdkWindowXData *)(((GdkDrawablePrivate*)(win))->klass_data)) +#define GDK_GC_XDATA(gc) ((GdkGCXData *)(((GdkGCPrivate*)(gc))->klass_data)) + +struct _GdkGCXData +{ + GC xgc; + Display *xdisplay; + GdkRegion *clip_region; + guint dirty_mask; +}; + +struct _GdkDrawableXData +{ + Window xid; + Display *xdisplay; +}; + +struct _GdkXPositionInfo +{ + gint x; + gint y; + gint width; + gint height; + gint x_offset; /* Offsets to add to X coordinates within window */ + gint y_offset; /* to get GDK coodinates within window */ + gboolean big : 1; + gboolean mapped : 1; + gboolean no_bg : 1; /* Set when the window background is temporarily + * unset during resizing and scaling */ + GdkRectangle clip_rect; /* visible rectangle of window */ +}; + +struct _GdkWindowXData +{ + GdkDrawableXData drawable_data; + GdkXPositionInfo position_info; +}; + +struct _GdkCursorPrivate +{ + GdkCursor cursor; + Cursor xcursor; + Display *xdisplay; +}; + +struct _GdkFontPrivateX +{ + GdkFontPrivate base; + /* XFontStruct *xfont; */ + /* generic pointer point to XFontStruct or XFontSet */ + gpointer xfont; + Display *xdisplay; + + GSList *names; +}; + +struct _GdkVisualPrivate +{ + GdkVisual visual; + Visual *xvisual; +}; + +struct _GdkColormapPrivateX +{ + GdkColormapPrivate base; + + Colormap xcolormap; + Display *xdisplay; + gint private_val; + + GHashTable *hash; + GdkColorInfo *info; + time_t last_sync_time; +}; + +struct _GdkImagePrivateX +{ + GdkImagePrivate base; + + XImage *ximage; + Display *xdisplay; + gpointer x_shm_info; +}; + + +#ifdef USE_XIM + +struct _GdkICPrivate +{ + XIC xic; + GdkICAttr *attr; + GdkICAttributesType mask; +}; + +#endif /* USE_XIM */ #define GDK_ROOT_WINDOW() gdk_root_window -#define GDK_ROOT_PARENT() ((GdkWindow *)&gdk_parent_root) +#define GDK_ROOT_PARENT() ((GdkWindow *)gdk_parent_root) #define GDK_DISPLAY() gdk_display #define GDK_DRAWABLE_XDISPLAY(win) (GDK_DRAWABLE_XDATA(win)->xdisplay) #define GDK_DRAWABLE_XID(win) (GDK_DRAWABLE_XDATA(win)->xid) #define GDK_IMAGE_XDISPLAY(image) (((GdkImagePrivate*) image)->xdisplay) #define GDK_IMAGE_XIMAGE(image) (((GdkImagePrivate*) image)->ximage) #define GDK_GC_XDISPLAY(gc) (GDK_GC_XDATA(gc)->xdisplay) -#define GDK_GC_XGC(gc) (GDK_GC_XDATA(gc)->xgc) #define GDK_COLORMAP_XDISPLAY(cmap) (((GdkColormapPrivateX *)cmap)->xdisplay) #define GDK_COLORMAP_XCOLORMAP(cmap) (((GdkColormapPrivateX *)cmap)->xcolormap) #define GDK_VISUAL_XVISUAL(vis) (((GdkVisualPrivate*) vis)->xvisual) #define GDK_FONT_XDISPLAY(font) (((GdkFontPrivate*) font)->xdisplay) #define GDK_FONT_XFONT(font) (((GdkFontPrivateX *)font)->xfont) +#define GDK_GC_XGC(gc) (GDK_GC_XDATA(gc)->xgc) +#define GDK_GC_GET_XGC(gc) (GDK_GC_XDATA(gc)->dirty_mask ? _gdk_x11_gc_flush (gc) : GDK_GC_XGC (gc)) + #define GDK_WINDOW_XWINDOW GDK_DRAWABLE_XID #define GDK_WINDOW_XDISPLAY GDK_DRAWABLE_XDISPLAY +extern Display *gdk_display; +extern Window gdk_root_window; +extern gint gdk_screen; +extern gchar *gdk_display_name; +extern Window gdk_leader_window; + +extern Atom gdk_selection_property; + +extern gchar *gdk_progclass; + GdkVisual* gdkx_visual_get (VisualID xvisualid); /* XXX: Do not use this function until it is fixed. An X Colormap * is useless unless we also have the visual. */ @@ -60,4 +187,9 @@ Window gdk_get_client_window (Display *dpy, GdkPixmap *gdk_pixmap_foreign_new (guint32 anid); GdkWindow *gdk_window_foreign_new (guint32 anid); +/* Return the Gdk* for a particular XID */ +gpointer gdk_xid_table_lookup (XID xid); + +GC _gdk_x11_gc_flush (GdkGC *gc); + #endif /* __GDK_X_H__ */ |