From 8098546227671a5d082fdf8f4811ee3ffca7f6d8 Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Tue, 28 Mar 2000 01:24:44 +0000 Subject: [PATCH] Merge no-flicker branch into HEAD --- ChangeLog | 176 ++++ ChangeLog.pre-2-0 | 176 ++++ ChangeLog.pre-2-10 | 176 ++++ ChangeLog.pre-2-2 | 176 ++++ ChangeLog.pre-2-4 | 176 ++++ ChangeLog.pre-2-6 | 176 ++++ ChangeLog.pre-2-8 | 176 ++++ docs/Changes-1.4.txt | 4 +- gdk/Makefile.am | 1 + gdk/gdk.c | 2 +- gdk/gdkdraw.c | 19 +- gdk/gdkdrawable.h | 1 + gdk/gdkevents.c | 2 +- gdk/gdkevents.h | 6 +- gdk/gdkgc.c | 43 +- gdk/gdkimage.h | 4 +- gdk/gdkinput.h | 1 - gdk/gdkinternals.h | 210 +++++ gdk/gdkpoly-generic.h | 291 +++++++ gdk/gdkpolyreg-generic.c | 616 ++++++++++++++ gdk/gdkprivate.h | 161 +--- gdk/gdkrectangle.c | 26 +- gdk/gdkregion-generic.c | 1505 ++++++++++++++++++++++++++++++++++ gdk/gdkregion-generic.h | 167 ++++ gdk/gdkregion.h | 72 +- gdk/gdktypes.h | 20 +- gdk/gdkwindow.c | 1003 +++++++++++++++++++++- gdk/gdkwindow.h | 36 +- gdk/x11/Makefile.am | 67 +- gdk/x11/gdkcc-x11.c | 1 + gdk/x11/gdkcolor-x11.c | 2 +- gdk/x11/gdkdnd-x11.c | 4 +- gdk/x11/gdkdrawable-x11.c | 184 +++-- gdk/x11/gdkevents-x11.c | 296 ++----- gdk/x11/gdkfont-x11.c | 2 +- gdk/x11/gdkgc-x11.c | 156 +++- gdk/x11/gdkgeometry-x11.c | 698 ++++++++++++++++ gdk/x11/gdkim-x11.c | 4 +- gdk/x11/gdkimage-x11.c | 6 +- gdk/x11/gdkinput-x11.c | 4 + gdk/x11/gdkinputprivate.h | 4 +- gdk/x11/gdkmain-x11.c | 4 +- gdk/x11/gdkpixmap-x11.c | 7 +- gdk/x11/gdkpoly-generic.h | 291 +++++++ gdk/x11/gdkpolyreg-generic.c | 616 ++++++++++++++ gdk/x11/gdkprivate-x11.h | 150 ++-- gdk/x11/gdkregion-generic.c | 1505 ++++++++++++++++++++++++++++++++++ gdk/x11/gdkregion-generic.h | 167 ++++ gdk/x11/gdkregion-x11.c | 26 +- gdk/x11/gdkselection-x11.c | 2 +- gdk/x11/gdkvisual-x11.c | 1 + gdk/x11/gdkwindow-x11.c | 186 +++-- gdk/x11/gdkx.h | 138 +++- gtk/.cvsignore | 1 + gtk/Makefile.am | 1 + gtk/gtkaspectframe.c | 3 - gtk/gtkbin.c | 4 +- gtk/gtkcontainer.c | 4 +- gtk/gtkentry.c | 67 +- gtk/gtkhscrollbar.c | 3 - gtk/gtklayout.c | 530 +----------- gtk/gtkmain.c | 11 +- gtk/gtkrange.c | 19 +- gtk/gtkviewport.c | 10 +- gtk/gtkvpaned.c | 2 +- gtk/gtkvscrollbar.c | 3 - gtk/gtkwidget.c | 558 +------------ gtk/gtkwidget.h | 18 +- 68 files changed, 9281 insertions(+), 1896 deletions(-) create mode 100644 gdk/gdkinternals.h create mode 100644 gdk/gdkpoly-generic.h create mode 100644 gdk/gdkpolyreg-generic.c create mode 100644 gdk/gdkregion-generic.c create mode 100644 gdk/gdkregion-generic.h create mode 100644 gdk/x11/gdkgeometry-x11.c create mode 100644 gdk/x11/gdkpoly-generic.h create mode 100644 gdk/x11/gdkpolyreg-generic.c create mode 100644 gdk/x11/gdkregion-generic.c create mode 100644 gdk/x11/gdkregion-generic.h diff --git a/ChangeLog b/ChangeLog index 57509b88e8..77d464c22e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,179 @@ +Thu Feb 24 23:58:21 2000 Owen Taylor + + * gdk/x11/gdkgeometry-x11.c: Don't worry about clipping of + toplevel windows and their immediate children by their parents, + since the size of toplevel windows is out of our immediate + control and we don't get any real benefit from trying to track + this size for clipping. + + * gdk/gdkprivate.h (struct _GdkWindowPrivate) gdk/x11/gdkwindow-x11.c : Add a flag + for input_only windows. + + * gdk/gdkwindow.c gdk/x11/gdkgeometry-x11.c: Use the above flag + to fix some hacks and make sure that we don't try to set the + background of input only windows. + +Thu Feb 24 18:11:46 2000 Owen Taylor + + * gdk/gdkinternals.h gdk/gdkprivate.h gdk/Makefile.am: Add a header file for + the _really_ internal stuff, and leave gdkprivate.h for the fake private + stuff that we've traditionally exposed. + + * gdk/**.c: Use gdkinternals.h where appropriate. + + * gdk/x11/gdkx.h gdk/x11/gdkprivate-x11.h gdk/x11/*.c: Make gdkx.h + not include gdkprivate-x11.h, move all stuff of conceivable public + interest into gdkx.h; keep all really private stuff in + uninstalled header gdkprivate-x11.h. + + * gdk/gdkdraw.c gdk/gdkwindow.c gdk/gdkinternals: Redirect all calls to + image->image_put on windows through a new function _gdk_window_draw_image() + to allow us to do backing store for images. (Sort of ugly) + + * gdk/gdkgc.c gdk/gdkprivate.h: Cache the ts and clip origins for graphics + contexts locally so that we can offset them properly when drawing + onto backing pixmaps. + + * gdk/gdkinput.h: Reindented + + * gdk/gdkprivate.h gdk/x11/gdkwindow-x11.c: Store the background + pixmap or color for the window, so we can properly initialize + our double-buffer pixmaps, and also so that we temporarily set + a background of None while scrolling. + + * gdk/gdkregion.h: Revise region boolean operators to have an + interface that is actually convenient - switch from creating new + regions on every op, to "methods" that modify existing regions + (A = A OP B). 3 argument forms which allow dest == src, would also + be possible, but the current interfaces seem to map nicely + onto what needs to be done. (There is quite a lot of region + code in GDK now.) + + * gdk/gdkregion.h: Add constructor from rectangle and a copy + operator. + + * gdk/x11/{gdkregion-generic.[ch],gdkpolyreg-generic.c, + gdkpoly-generic.h: Copy region code from Xlib, switch it over + to 32 bit coordinates, modify it to be mostly GTK+ style + and to have interfaces that match gdkregion.h. + + * gdk/gdkwindow.c gdk/gdkprivate.h: Add facility for + double-buffered drawing. gdk_window_begin_paint_{rect,region}() + create a backing pixmap and redirect all drawing to + that backing pixmap until a matching gdk_window_end_paint(). + + * gdk/gdkwindow.[ch] gdk/gdkinternals.h gdk/x11/gdkdrawable-x11.c: + Create a special drawable class for GtkWindow's that + redirects the drawing to the backing pixmap as necessary + and then calls the real operations in _gdk_windowing_window_class. + + * gdk/gdkprivate.h gdk/gdkwindow.[ch] gdk/x11/gdkevents-x11.c: + Store invalid region for each window. Generate expose events for invalid + region in an idle. This replaces both the expose compression + and the redrawing queuing in GTK+. It is both more efficient and + simpler than either one individually and far more so then the + combination. + + * gdk/x11/gdkgeometry.c gdk/x11/gdkwindow.c gdk/x11/gdkprivate-x11.h: + Emulate 32 bit coordinates for windows with 16 bit coordinates + by offsetting drawing, guffaw scrolling techniques and + mapping/unmapping child windows as necessary. + + * gdk/gdkwindow.[ch] gdk/x11/gdkgeometry.c: Add anti-exposes, + where, when invalid regions are processed, the region is stored, + and if expose events come in that are detectably duplicate + the processed exposes (by comparison of event serial numbers), + the stored region is subtracted out of those exposes. + + * gdk/x11/gdkgeometry.c: Temporarily unset backing pixmaps of + regions newly exposed when scrolling or resizing windows. + This, combined with forcing processesing of queued invalidated + regions, gives nice flicker-free scrolling. + + * gtk/gtklayout.c gtk/gtkviewport.c: Force processing of + invalidated regions after every scroll. + + * gtk/gtklayout.c: Vastly simplify using the new 32 bit coordinate + emulation in GDK. Its, for all practical purposes just a + GtkViewport/GtkFixed hybrid now. + + * gdk/gdkdrawable-x11.c: Convert from GDK (32 bit) to X11 + (16-bit) structures as necessary instead of just casting. + + * gdk/x11/gdkgc-x11.c gdk/x11/gdkx.h: Replace XSetRegion with code + in terms of the structures from gdkregion-generic.c, using appropriate + offsets from GDK to X11 coordinates. Cache clip mask and + origin and ts origin locally and only flush to the server + when drawing, to avoid constantly setting and resetting these + values when offsetting GC's for scrolling and backing pixmaps. + + * gdk/x11/gdkinput-x11.c: Fix leak of axes structures. + + * gtk/gtkcontainer.c: Call process_all_updates at end + of resizing to reduce flicker. (Avoids having redraw + lag arbitrarily behind resize under some circumstances) + + * gtk/gtkentry.c: Remove old backing store code, and simply take + advantage of the new backing store capabilities of GDK. + + * gtk/gtkmain.c: Simple implementation of widget backing + store - simply push a paint while handling each expose. + (Should really be configurable widget for widget.) + + * gtk/gtkwidget.c: Remove all the old complicated redraw + code, and simply invalidate the GDK windows from + gdk_window_queue_clear(), etc. (Sigh, so much carefully + debugged complexity ... gone to the winds.) + + Remove all the code for suppressing expose events while + resizes are pending; this isn't needed since the invalid + areas won't be processed until after the resizes are + processed, since they are in a lower priority idle. + +Thu Feb 24 15:37:41 2000 Owen Taylor + + * gdk/gdkrectangle.c (gdk_rectangle_intersect): Set width + and height of dest rectangle for non-intersecting rectangles. + +Sun Feb 20 16:47:31 2000 Owen Taylor + + * gtk/gtkwidget.h: Make GtkAllocation just a typedef + for GdkRectangle. + +Sun Feb 20 11:27:00 2000 Owen Taylor + + * gdk/gdk{events,image,private,types,window}.h + gdk/x11/gdkinputprivate.h: Change all coordinates + from int16 to int. Also, Change width and height from + unsigned to signed to avoid all the stupid C + signedness bugs. + +Sat Feb 19 12:01:53 2000 Owen Taylor + + * gdk/x11/gdkdrawable-x11.c (gdk_x11_draw_drawable): + Use gdk_drawable_get_depth instead of gdk_drawable_get_visual. + Add some more detailed checking. + + * gdk/gdkdraw.c gdk/gdkdrawable.h (gdk_drawable_get_depth): + New function to retrieve the depth of a drawable. + + * gdk/gdkprivate.h (struct _GdkDrawablePrivate): Add a depth + field, reorder fields to save memory. + +Mon Dec 13 14:06:03 1999 Owen Taylor + + * gtk/gtkentry.c (gtk_entry_draw_cursor_on_drawable): Draw a small portion + of the background image instead of scaling the background down to + a line. + + * gtk/gtk[hv]scrollbar.c (gtk_hscrollbar_size_allocate): Removed mysterious + which temporarily set slider to wrong size. + + * gtk/gtkaspectframe.c gtkbin.c: Remove unecessary calls to + queue_clear(). + +Wed Nov 17 18:36:05 1999 Owen Taylor + 2000-03-23 Jonathan Blandford * gtk/gtkpaned.c (gtk_paned_get_position): add getter. diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 57509b88e8..77d464c22e 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,179 @@ +Thu Feb 24 23:58:21 2000 Owen Taylor + + * gdk/x11/gdkgeometry-x11.c: Don't worry about clipping of + toplevel windows and their immediate children by their parents, + since the size of toplevel windows is out of our immediate + control and we don't get any real benefit from trying to track + this size for clipping. + + * gdk/gdkprivate.h (struct _GdkWindowPrivate) gdk/x11/gdkwindow-x11.c : Add a flag + for input_only windows. + + * gdk/gdkwindow.c gdk/x11/gdkgeometry-x11.c: Use the above flag + to fix some hacks and make sure that we don't try to set the + background of input only windows. + +Thu Feb 24 18:11:46 2000 Owen Taylor + + * gdk/gdkinternals.h gdk/gdkprivate.h gdk/Makefile.am: Add a header file for + the _really_ internal stuff, and leave gdkprivate.h for the fake private + stuff that we've traditionally exposed. + + * gdk/**.c: Use gdkinternals.h where appropriate. + + * gdk/x11/gdkx.h gdk/x11/gdkprivate-x11.h gdk/x11/*.c: Make gdkx.h + not include gdkprivate-x11.h, move all stuff of conceivable public + interest into gdkx.h; keep all really private stuff in + uninstalled header gdkprivate-x11.h. + + * gdk/gdkdraw.c gdk/gdkwindow.c gdk/gdkinternals: Redirect all calls to + image->image_put on windows through a new function _gdk_window_draw_image() + to allow us to do backing store for images. (Sort of ugly) + + * gdk/gdkgc.c gdk/gdkprivate.h: Cache the ts and clip origins for graphics + contexts locally so that we can offset them properly when drawing + onto backing pixmaps. + + * gdk/gdkinput.h: Reindented + + * gdk/gdkprivate.h gdk/x11/gdkwindow-x11.c: Store the background + pixmap or color for the window, so we can properly initialize + our double-buffer pixmaps, and also so that we temporarily set + a background of None while scrolling. + + * gdk/gdkregion.h: Revise region boolean operators to have an + interface that is actually convenient - switch from creating new + regions on every op, to "methods" that modify existing regions + (A = A OP B). 3 argument forms which allow dest == src, would also + be possible, but the current interfaces seem to map nicely + onto what needs to be done. (There is quite a lot of region + code in GDK now.) + + * gdk/gdkregion.h: Add constructor from rectangle and a copy + operator. + + * gdk/x11/{gdkregion-generic.[ch],gdkpolyreg-generic.c, + gdkpoly-generic.h: Copy region code from Xlib, switch it over + to 32 bit coordinates, modify it to be mostly GTK+ style + and to have interfaces that match gdkregion.h. + + * gdk/gdkwindow.c gdk/gdkprivate.h: Add facility for + double-buffered drawing. gdk_window_begin_paint_{rect,region}() + create a backing pixmap and redirect all drawing to + that backing pixmap until a matching gdk_window_end_paint(). + + * gdk/gdkwindow.[ch] gdk/gdkinternals.h gdk/x11/gdkdrawable-x11.c: + Create a special drawable class for GtkWindow's that + redirects the drawing to the backing pixmap as necessary + and then calls the real operations in _gdk_windowing_window_class. + + * gdk/gdkprivate.h gdk/gdkwindow.[ch] gdk/x11/gdkevents-x11.c: + Store invalid region for each window. Generate expose events for invalid + region in an idle. This replaces both the expose compression + and the redrawing queuing in GTK+. It is both more efficient and + simpler than either one individually and far more so then the + combination. + + * gdk/x11/gdkgeometry.c gdk/x11/gdkwindow.c gdk/x11/gdkprivate-x11.h: + Emulate 32 bit coordinates for windows with 16 bit coordinates + by offsetting drawing, guffaw scrolling techniques and + mapping/unmapping child windows as necessary. + + * gdk/gdkwindow.[ch] gdk/x11/gdkgeometry.c: Add anti-exposes, + where, when invalid regions are processed, the region is stored, + and if expose events come in that are detectably duplicate + the processed exposes (by comparison of event serial numbers), + the stored region is subtracted out of those exposes. + + * gdk/x11/gdkgeometry.c: Temporarily unset backing pixmaps of + regions newly exposed when scrolling or resizing windows. + This, combined with forcing processesing of queued invalidated + regions, gives nice flicker-free scrolling. + + * gtk/gtklayout.c gtk/gtkviewport.c: Force processing of + invalidated regions after every scroll. + + * gtk/gtklayout.c: Vastly simplify using the new 32 bit coordinate + emulation in GDK. Its, for all practical purposes just a + GtkViewport/GtkFixed hybrid now. + + * gdk/gdkdrawable-x11.c: Convert from GDK (32 bit) to X11 + (16-bit) structures as necessary instead of just casting. + + * gdk/x11/gdkgc-x11.c gdk/x11/gdkx.h: Replace XSetRegion with code + in terms of the structures from gdkregion-generic.c, using appropriate + offsets from GDK to X11 coordinates. Cache clip mask and + origin and ts origin locally and only flush to the server + when drawing, to avoid constantly setting and resetting these + values when offsetting GC's for scrolling and backing pixmaps. + + * gdk/x11/gdkinput-x11.c: Fix leak of axes structures. + + * gtk/gtkcontainer.c: Call process_all_updates at end + of resizing to reduce flicker. (Avoids having redraw + lag arbitrarily behind resize under some circumstances) + + * gtk/gtkentry.c: Remove old backing store code, and simply take + advantage of the new backing store capabilities of GDK. + + * gtk/gtkmain.c: Simple implementation of widget backing + store - simply push a paint while handling each expose. + (Should really be configurable widget for widget.) + + * gtk/gtkwidget.c: Remove all the old complicated redraw + code, and simply invalidate the GDK windows from + gdk_window_queue_clear(), etc. (Sigh, so much carefully + debugged complexity ... gone to the winds.) + + Remove all the code for suppressing expose events while + resizes are pending; this isn't needed since the invalid + areas won't be processed until after the resizes are + processed, since they are in a lower priority idle. + +Thu Feb 24 15:37:41 2000 Owen Taylor + + * gdk/gdkrectangle.c (gdk_rectangle_intersect): Set width + and height of dest rectangle for non-intersecting rectangles. + +Sun Feb 20 16:47:31 2000 Owen Taylor + + * gtk/gtkwidget.h: Make GtkAllocation just a typedef + for GdkRectangle. + +Sun Feb 20 11:27:00 2000 Owen Taylor + + * gdk/gdk{events,image,private,types,window}.h + gdk/x11/gdkinputprivate.h: Change all coordinates + from int16 to int. Also, Change width and height from + unsigned to signed to avoid all the stupid C + signedness bugs. + +Sat Feb 19 12:01:53 2000 Owen Taylor + + * gdk/x11/gdkdrawable-x11.c (gdk_x11_draw_drawable): + Use gdk_drawable_get_depth instead of gdk_drawable_get_visual. + Add some more detailed checking. + + * gdk/gdkdraw.c gdk/gdkdrawable.h (gdk_drawable_get_depth): + New function to retrieve the depth of a drawable. + + * gdk/gdkprivate.h (struct _GdkDrawablePrivate): Add a depth + field, reorder fields to save memory. + +Mon Dec 13 14:06:03 1999 Owen Taylor + + * gtk/gtkentry.c (gtk_entry_draw_cursor_on_drawable): Draw a small portion + of the background image instead of scaling the background down to + a line. + + * gtk/gtk[hv]scrollbar.c (gtk_hscrollbar_size_allocate): Removed mysterious + which temporarily set slider to wrong size. + + * gtk/gtkaspectframe.c gtkbin.c: Remove unecessary calls to + queue_clear(). + +Wed Nov 17 18:36:05 1999 Owen Taylor + 2000-03-23 Jonathan Blandford * gtk/gtkpaned.c (gtk_paned_get_position): add getter. diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 57509b88e8..77d464c22e 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,179 @@ +Thu Feb 24 23:58:21 2000 Owen Taylor + + * gdk/x11/gdkgeometry-x11.c: Don't worry about clipping of + toplevel windows and their immediate children by their parents, + since the size of toplevel windows is out of our immediate + control and we don't get any real benefit from trying to track + this size for clipping. + + * gdk/gdkprivate.h (struct _GdkWindowPrivate) gdk/x11/gdkwindow-x11.c : Add a flag + for input_only windows. + + * gdk/gdkwindow.c gdk/x11/gdkgeometry-x11.c: Use the above flag + to fix some hacks and make sure that we don't try to set the + background of input only windows. + +Thu Feb 24 18:11:46 2000 Owen Taylor + + * gdk/gdkinternals.h gdk/gdkprivate.h gdk/Makefile.am: Add a header file for + the _really_ internal stuff, and leave gdkprivate.h for the fake private + stuff that we've traditionally exposed. + + * gdk/**.c: Use gdkinternals.h where appropriate. + + * gdk/x11/gdkx.h gdk/x11/gdkprivate-x11.h gdk/x11/*.c: Make gdkx.h + not include gdkprivate-x11.h, move all stuff of conceivable public + interest into gdkx.h; keep all really private stuff in + uninstalled header gdkprivate-x11.h. + + * gdk/gdkdraw.c gdk/gdkwindow.c gdk/gdkinternals: Redirect all calls to + image->image_put on windows through a new function _gdk_window_draw_image() + to allow us to do backing store for images. (Sort of ugly) + + * gdk/gdkgc.c gdk/gdkprivate.h: Cache the ts and clip origins for graphics + contexts locally so that we can offset them properly when drawing + onto backing pixmaps. + + * gdk/gdkinput.h: Reindented + + * gdk/gdkprivate.h gdk/x11/gdkwindow-x11.c: Store the background + pixmap or color for the window, so we can properly initialize + our double-buffer pixmaps, and also so that we temporarily set + a background of None while scrolling. + + * gdk/gdkregion.h: Revise region boolean operators to have an + interface that is actually convenient - switch from creating new + regions on every op, to "methods" that modify existing regions + (A = A OP B). 3 argument forms which allow dest == src, would also + be possible, but the current interfaces seem to map nicely + onto what needs to be done. (There is quite a lot of region + code in GDK now.) + + * gdk/gdkregion.h: Add constructor from rectangle and a copy + operator. + + * gdk/x11/{gdkregion-generic.[ch],gdkpolyreg-generic.c, + gdkpoly-generic.h: Copy region code from Xlib, switch it over + to 32 bit coordinates, modify it to be mostly GTK+ style + and to have interfaces that match gdkregion.h. + + * gdk/gdkwindow.c gdk/gdkprivate.h: Add facility for + double-buffered drawing. gdk_window_begin_paint_{rect,region}() + create a backing pixmap and redirect all drawing to + that backing pixmap until a matching gdk_window_end_paint(). + + * gdk/gdkwindow.[ch] gdk/gdkinternals.h gdk/x11/gdkdrawable-x11.c: + Create a special drawable class for GtkWindow's that + redirects the drawing to the backing pixmap as necessary + and then calls the real operations in _gdk_windowing_window_class. + + * gdk/gdkprivate.h gdk/gdkwindow.[ch] gdk/x11/gdkevents-x11.c: + Store invalid region for each window. Generate expose events for invalid + region in an idle. This replaces both the expose compression + and the redrawing queuing in GTK+. It is both more efficient and + simpler than either one individually and far more so then the + combination. + + * gdk/x11/gdkgeometry.c gdk/x11/gdkwindow.c gdk/x11/gdkprivate-x11.h: + Emulate 32 bit coordinates for windows with 16 bit coordinates + by offsetting drawing, guffaw scrolling techniques and + mapping/unmapping child windows as necessary. + + * gdk/gdkwindow.[ch] gdk/x11/gdkgeometry.c: Add anti-exposes, + where, when invalid regions are processed, the region is stored, + and if expose events come in that are detectably duplicate + the processed exposes (by comparison of event serial numbers), + the stored region is subtracted out of those exposes. + + * gdk/x11/gdkgeometry.c: Temporarily unset backing pixmaps of + regions newly exposed when scrolling or resizing windows. + This, combined with forcing processesing of queued invalidated + regions, gives nice flicker-free scrolling. + + * gtk/gtklayout.c gtk/gtkviewport.c: Force processing of + invalidated regions after every scroll. + + * gtk/gtklayout.c: Vastly simplify using the new 32 bit coordinate + emulation in GDK. Its, for all practical purposes just a + GtkViewport/GtkFixed hybrid now. + + * gdk/gdkdrawable-x11.c: Convert from GDK (32 bit) to X11 + (16-bit) structures as necessary instead of just casting. + + * gdk/x11/gdkgc-x11.c gdk/x11/gdkx.h: Replace XSetRegion with code + in terms of the structures from gdkregion-generic.c, using appropriate + offsets from GDK to X11 coordinates. Cache clip mask and + origin and ts origin locally and only flush to the server + when drawing, to avoid constantly setting and resetting these + values when offsetting GC's for scrolling and backing pixmaps. + + * gdk/x11/gdkinput-x11.c: Fix leak of axes structures. + + * gtk/gtkcontainer.c: Call process_all_updates at end + of resizing to reduce flicker. (Avoids having redraw + lag arbitrarily behind resize under some circumstances) + + * gtk/gtkentry.c: Remove old backing store code, and simply take + advantage of the new backing store capabilities of GDK. + + * gtk/gtkmain.c: Simple implementation of widget backing + store - simply push a paint while handling each expose. + (Should really be configurable widget for widget.) + + * gtk/gtkwidget.c: Remove all the old complicated redraw + code, and simply invalidate the GDK windows from + gdk_window_queue_clear(), etc. (Sigh, so much carefully + debugged complexity ... gone to the winds.) + + Remove all the code for suppressing expose events while + resizes are pending; this isn't needed since the invalid + areas won't be processed until after the resizes are + processed, since they are in a lower priority idle. + +Thu Feb 24 15:37:41 2000 Owen Taylor + + * gdk/gdkrectangle.c (gdk_rectangle_intersect): Set width + and height of dest rectangle for non-intersecting rectangles. + +Sun Feb 20 16:47:31 2000 Owen Taylor + + * gtk/gtkwidget.h: Make GtkAllocation just a typedef + for GdkRectangle. + +Sun Feb 20 11:27:00 2000 Owen Taylor + + * gdk/gdk{events,image,private,types,window}.h + gdk/x11/gdkinputprivate.h: Change all coordinates + from int16 to int. Also, Change width and height from + unsigned to signed to avoid all the stupid C + signedness bugs. + +Sat Feb 19 12:01:53 2000 Owen Taylor + + * gdk/x11/gdkdrawable-x11.c (gdk_x11_draw_drawable): + Use gdk_drawable_get_depth instead of gdk_drawable_get_visual. + Add some more detailed checking. + + * gdk/gdkdraw.c gdk/gdkdrawable.h (gdk_drawable_get_depth): + New function to retrieve the depth of a drawable. + + * gdk/gdkprivate.h (struct _GdkDrawablePrivate): Add a depth + field, reorder fields to save memory. + +Mon Dec 13 14:06:03 1999 Owen Taylor + + * gtk/gtkentry.c (gtk_entry_draw_cursor_on_drawable): Draw a small portion + of the background image instead of scaling the background down to + a line. + + * gtk/gtk[hv]scrollbar.c (gtk_hscrollbar_size_allocate): Removed mysterious + which temporarily set slider to wrong size. + + * gtk/gtkaspectframe.c gtkbin.c: Remove unecessary calls to + queue_clear(). + +Wed Nov 17 18:36:05 1999 Owen Taylor + 2000-03-23 Jonathan Blandford * gtk/gtkpaned.c (gtk_paned_get_position): add getter. diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 57509b88e8..77d464c22e 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,179 @@ +Thu Feb 24 23:58:21 2000 Owen Taylor + + * gdk/x11/gdkgeometry-x11.c: Don't worry about clipping of + toplevel windows and their immediate children by their parents, + since the size of toplevel windows is out of our immediate + control and we don't get any real benefit from trying to track + this size for clipping. + + * gdk/gdkprivate.h (struct _GdkWindowPrivate) gdk/x11/gdkwindow-x11.c : Add a flag + for input_only windows. + + * gdk/gdkwindow.c gdk/x11/gdkgeometry-x11.c: Use the above flag + to fix some hacks and make sure that we don't try to set the + background of input only windows. + +Thu Feb 24 18:11:46 2000 Owen Taylor + + * gdk/gdkinternals.h gdk/gdkprivate.h gdk/Makefile.am: Add a header file for + the _really_ internal stuff, and leave gdkprivate.h for the fake private + stuff that we've traditionally exposed. + + * gdk/**.c: Use gdkinternals.h where appropriate. + + * gdk/x11/gdkx.h gdk/x11/gdkprivate-x11.h gdk/x11/*.c: Make gdkx.h + not include gdkprivate-x11.h, move all stuff of conceivable public + interest into gdkx.h; keep all really private stuff in + uninstalled header gdkprivate-x11.h. + + * gdk/gdkdraw.c gdk/gdkwindow.c gdk/gdkinternals: Redirect all calls to + image->image_put on windows through a new function _gdk_window_draw_image() + to allow us to do backing store for images. (Sort of ugly) + + * gdk/gdkgc.c gdk/gdkprivate.h: Cache the ts and clip origins for graphics + contexts locally so that we can offset them properly when drawing + onto backing pixmaps. + + * gdk/gdkinput.h: Reindented + + * gdk/gdkprivate.h gdk/x11/gdkwindow-x11.c: Store the background + pixmap or color for the window, so we can properly initialize + our double-buffer pixmaps, and also so that we temporarily set + a background of None while scrolling. + + * gdk/gdkregion.h: Revise region boolean operators to have an + interface that is actually convenient - switch from creating new + regions on every op, to "methods" that modify existing regions + (A = A OP B). 3 argument forms which allow dest == src, would also + be possible, but the current interfaces seem to map nicely + onto what needs to be done. (There is quite a lot of region + code in GDK now.) + + * gdk/gdkregion.h: Add constructor from rectangle and a copy + operator. + + * gdk/x11/{gdkregion-generic.[ch],gdkpolyreg-generic.c, + gdkpoly-generic.h: Copy region code from Xlib, switch it over + to 32 bit coordinates, modify it to be mostly GTK+ style + and to have interfaces that match gdkregion.h. + + * gdk/gdkwindow.c gdk/gdkprivate.h: Add facility for + double-buffered drawing. gdk_window_begin_paint_{rect,region}() + create a backing pixmap and redirect all drawing to + that backing pixmap until a matching gdk_window_end_paint(). + + * gdk/gdkwindow.[ch] gdk/gdkinternals.h gdk/x11/gdkdrawable-x11.c: + Create a special drawable class for GtkWindow's that + redirects the drawing to the backing pixmap as necessary + and then calls the real operations in _gdk_windowing_window_class. + + * gdk/gdkprivate.h gdk/gdkwindow.[ch] gdk/x11/gdkevents-x11.c: + Store invalid region for each window. Generate expose events for invalid + region in an idle. This replaces both the expose compression + and the redrawing queuing in GTK+. It is both more efficient and + simpler than either one individually and far more so then the + combination. + + * gdk/x11/gdkgeometry.c gdk/x11/gdkwindow.c gdk/x11/gdkprivate-x11.h: + Emulate 32 bit coordinates for windows with 16 bit coordinates + by offsetting drawing, guffaw scrolling techniques and + mapping/unmapping child windows as necessary. + + * gdk/gdkwindow.[ch] gdk/x11/gdkgeometry.c: Add anti-exposes, + where, when invalid regions are processed, the region is stored, + and if expose events come in that are detectably duplicate + the processed exposes (by comparison of event serial numbers), + the stored region is subtracted out of those exposes. + + * gdk/x11/gdkgeometry.c: Temporarily unset backing pixmaps of + regions newly exposed when scrolling or resizing windows. + This, combined with forcing processesing of queued invalidated + regions, gives nice flicker-free scrolling. + + * gtk/gtklayout.c gtk/gtkviewport.c: Force processing of + invalidated regions after every scroll. + + * gtk/gtklayout.c: Vastly simplify using the new 32 bit coordinate + emulation in GDK. Its, for all practical purposes just a + GtkViewport/GtkFixed hybrid now. + + * gdk/gdkdrawable-x11.c: Convert from GDK (32 bit) to X11 + (16-bit) structures as necessary instead of just casting. + + * gdk/x11/gdkgc-x11.c gdk/x11/gdkx.h: Replace XSetRegion with code + in terms of the structures from gdkregion-generic.c, using appropriate + offsets from GDK to X11 coordinates. Cache clip mask and + origin and ts origin locally and only flush to the server + when drawing, to avoid constantly setting and resetting these + values when offsetting GC's for scrolling and backing pixmaps. + + * gdk/x11/gdkinput-x11.c: Fix leak of axes structures. + + * gtk/gtkcontainer.c: Call process_all_updates at end + of resizing to reduce flicker. (Avoids having redraw + lag arbitrarily behind resize under some circumstances) + + * gtk/gtkentry.c: Remove old backing store code, and simply take + advantage of the new backing store capabilities of GDK. + + * gtk/gtkmain.c: Simple implementation of widget backing + store - simply push a paint while handling each expose. + (Should really be configurable widget for widget.) + + * gtk/gtkwidget.c: Remove all the old complicated redraw + code, and simply invalidate the GDK windows from + gdk_window_queue_clear(), etc. (Sigh, so much carefully + debugged complexity ... gone to the winds.) + + Remove all the code for suppressing expose events while + resizes are pending; this isn't needed since the invalid + areas won't be processed until after the resizes are + processed, since they are in a lower priority idle. + +Thu Feb 24 15:37:41 2000 Owen Taylor + + * gdk/gdkrectangle.c (gdk_rectangle_intersect): Set width + and height of dest rectangle for non-intersecting rectangles. + +Sun Feb 20 16:47:31 2000 Owen Taylor + + * gtk/gtkwidget.h: Make GtkAllocation just a typedef + for GdkRectangle. + +Sun Feb 20 11:27:00 2000 Owen Taylor + + * gdk/gdk{events,image,private,types,window}.h + gdk/x11/gdkinputprivate.h: Change all coordinates + from int16 to int. Also, Change width and height from + unsigned to signed to avoid all the stupid C + signedness bugs. + +Sat Feb 19 12:01:53 2000 Owen Taylor + + * gdk/x11/gdkdrawable-x11.c (gdk_x11_draw_drawable): + Use gdk_drawable_get_depth instead of gdk_drawable_get_visual. + Add some more detailed checking. + + * gdk/gdkdraw.c gdk/gdkdrawable.h (gdk_drawable_get_depth): + New function to retrieve the depth of a drawable. + + * gdk/gdkprivate.h (struct _GdkDrawablePrivate): Add a depth + field, reorder fields to save memory. + +Mon Dec 13 14:06:03 1999 Owen Taylor + + * gtk/gtkentry.c (gtk_entry_draw_cursor_on_drawable): Draw a small portion + of the background image instead of scaling the background down to + a line. + + * gtk/gtk[hv]scrollbar.c (gtk_hscrollbar_size_allocate): Removed mysterious + which temporarily set slider to wrong size. + + * gtk/gtkaspectframe.c gtkbin.c: Remove unecessary calls to + queue_clear(). + +Wed Nov 17 18:36:05 1999 Owen Taylor + 2000-03-23 Jonathan Blandford * gtk/gtkpaned.c (gtk_paned_get_position): add getter. diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 57509b88e8..77d464c22e 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,179 @@ +Thu Feb 24 23:58:21 2000 Owen Taylor + + * gdk/x11/gdkgeometry-x11.c: Don't worry about clipping of + toplevel windows and their immediate children by their parents, + since the size of toplevel windows is out of our immediate + control and we don't get any real benefit from trying to track + this size for clipping. + + * gdk/gdkprivate.h (struct _GdkWindowPrivate) gdk/x11/gdkwindow-x11.c : Add a flag + for input_only windows. + + * gdk/gdkwindow.c gdk/x11/gdkgeometry-x11.c: Use the above flag + to fix some hacks and make sure that we don't try to set the + background of input only windows. + +Thu Feb 24 18:11:46 2000 Owen Taylor + + * gdk/gdkinternals.h gdk/gdkprivate.h gdk/Makefile.am: Add a header file for + the _really_ internal stuff, and leave gdkprivate.h for the fake private + stuff that we've traditionally exposed. + + * gdk/**.c: Use gdkinternals.h where appropriate. + + * gdk/x11/gdkx.h gdk/x11/gdkprivate-x11.h gdk/x11/*.c: Make gdkx.h + not include gdkprivate-x11.h, move all stuff of conceivable public + interest into gdkx.h; keep all really private stuff in + uninstalled header gdkprivate-x11.h. + + * gdk/gdkdraw.c gdk/gdkwindow.c gdk/gdkinternals: Redirect all calls to + image->image_put on windows through a new function _gdk_window_draw_image() + to allow us to do backing store for images. (Sort of ugly) + + * gdk/gdkgc.c gdk/gdkprivate.h: Cache the ts and clip origins for graphics + contexts locally so that we can offset them properly when drawing + onto backing pixmaps. + + * gdk/gdkinput.h: Reindented + + * gdk/gdkprivate.h gdk/x11/gdkwindow-x11.c: Store the background + pixmap or color for the window, so we can properly initialize + our double-buffer pixmaps, and also so that we temporarily set + a background of None while scrolling. + + * gdk/gdkregion.h: Revise region boolean operators to have an + interface that is actually convenient - switch from creating new + regions on every op, to "methods" that modify existing regions + (A = A OP B). 3 argument forms which allow dest == src, would also + be possible, but the current interfaces seem to map nicely + onto what needs to be done. (There is quite a lot of region + code in GDK now.) + + * gdk/gdkregion.h: Add constructor from rectangle and a copy + operator. + + * gdk/x11/{gdkregion-generic.[ch],gdkpolyreg-generic.c, + gdkpoly-generic.h: Copy region code from Xlib, switch it over + to 32 bit coordinates, modify it to be mostly GTK+ style + and to have interfaces that match gdkregion.h. + + * gdk/gdkwindow.c gdk/gdkprivate.h: Add facility for + double-buffered drawing. gdk_window_begin_paint_{rect,region}() + create a backing pixmap and redirect all drawing to + that backing pixmap until a matching gdk_window_end_paint(). + + * gdk/gdkwindow.[ch] gdk/gdkinternals.h gdk/x11/gdkdrawable-x11.c: + Create a special drawable class for GtkWindow's that + redirects the drawing to the backing pixmap as necessary + and then calls the real operations in _gdk_windowing_window_class. + + * gdk/gdkprivate.h gdk/gdkwindow.[ch] gdk/x11/gdkevents-x11.c: + Store invalid region for each window. Generate expose events for invalid + region in an idle. This replaces both the expose compression + and the redrawing queuing in GTK+. It is both more efficient and + simpler than either one individually and far more so then the + combination. + + * gdk/x11/gdkgeometry.c gdk/x11/gdkwindow.c gdk/x11/gdkprivate-x11.h: + Emulate 32 bit coordinates for windows with 16 bit coordinates + by offsetting drawing, guffaw scrolling techniques and + mapping/unmapping child windows as necessary. + + * gdk/gdkwindow.[ch] gdk/x11/gdkgeometry.c: Add anti-exposes, + where, when invalid regions are processed, the region is stored, + and if expose events come in that are detectably duplicate + the processed exposes (by comparison of event serial numbers), + the stored region is subtracted out of those exposes. + + * gdk/x11/gdkgeometry.c: Temporarily unset backing pixmaps of + regions newly exposed when scrolling or resizing windows. + This, combined with forcing processesing of queued invalidated + regions, gives nice flicker-free scrolling. + + * gtk/gtklayout.c gtk/gtkviewport.c: Force processing of + invalidated regions after every scroll. + + * gtk/gtklayout.c: Vastly simplify using the new 32 bit coordinate + emulation in GDK. Its, for all practical purposes just a + GtkViewport/GtkFixed hybrid now. + + * gdk/gdkdrawable-x11.c: Convert from GDK (32 bit) to X11 + (16-bit) structures as necessary instead of just casting. + + * gdk/x11/gdkgc-x11.c gdk/x11/gdkx.h: Replace XSetRegion with code + in terms of the structures from gdkregion-generic.c, using appropriate + offsets from GDK to X11 coordinates. Cache clip mask and + origin and ts origin locally and only flush to the server + when drawing, to avoid constantly setting and resetting these + values when offsetting GC's for scrolling and backing pixmaps. + + * gdk/x11/gdkinput-x11.c: Fix leak of axes structures. + + * gtk/gtkcontainer.c: Call process_all_updates at end + of resizing to reduce flicker. (Avoids having redraw + lag arbitrarily behind resize under some circumstances) + + * gtk/gtkentry.c: Remove old backing store code, and simply take + advantage of the new backing store capabilities of GDK. + + * gtk/gtkmain.c: Simple implementation of widget backing + store - simply push a paint while handling each expose. + (Should really be configurable widget for widget.) + + * gtk/gtkwidget.c: Remove all the old complicated redraw + code, and simply invalidate the GDK windows from + gdk_window_queue_clear(), etc. (Sigh, so much carefully + debugged complexity ... gone to the winds.) + + Remove all the code for suppressing expose events while + resizes are pending; this isn't needed since the invalid + areas won't be processed until after the resizes are + processed, since they are in a lower priority idle. + +Thu Feb 24 15:37:41 2000 Owen Taylor + + * gdk/gdkrectangle.c (gdk_rectangle_intersect): Set width + and height of dest rectangle for non-intersecting rectangles. + +Sun Feb 20 16:47:31 2000 Owen Taylor + + * gtk/gtkwidget.h: Make GtkAllocation just a typedef + for GdkRectangle. + +Sun Feb 20 11:27:00 2000 Owen Taylor + + * gdk/gdk{events,image,private,types,window}.h + gdk/x11/gdkinputprivate.h: Change all coordinates + from int16 to int. Also, Change width and height from + unsigned to signed to avoid all the stupid C + signedness bugs. + +Sat Feb 19 12:01:53 2000 Owen Taylor + + * gdk/x11/gdkdrawable-x11.c (gdk_x11_draw_drawable): + Use gdk_drawable_get_depth instead of gdk_drawable_get_visual. + Add some more detailed checking. + + * gdk/gdkdraw.c gdk/gdkdrawable.h (gdk_drawable_get_depth): + New function to retrieve the depth of a drawable. + + * gdk/gdkprivate.h (struct _GdkDrawablePrivate): Add a depth + field, reorder fields to save memory. + +Mon Dec 13 14:06:03 1999 Owen Taylor + + * gtk/gtkentry.c (gtk_entry_draw_cursor_on_drawable): Draw a small portion + of the background image instead of scaling the background down to + a line. + + * gtk/gtk[hv]scrollbar.c (gtk_hscrollbar_size_allocate): Removed mysterious + which temporarily set slider to wrong size. + + * gtk/gtkaspectframe.c gtkbin.c: Remove unecessary calls to + queue_clear(). + +Wed Nov 17 18:36:05 1999 Owen Taylor + 2000-03-23 Jonathan Blandford * gtk/gtkpaned.c (gtk_paned_get_position): add getter. diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 57509b88e8..77d464c22e 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,179 @@ +Thu Feb 24 23:58:21 2000 Owen Taylor + + * gdk/x11/gdkgeometry-x11.c: Don't worry about clipping of + toplevel windows and their immediate children by their parents, + since the size of toplevel windows is out of our immediate + control and we don't get any real benefit from trying to track + this size for clipping. + + * gdk/gdkprivate.h (struct _GdkWindowPrivate) gdk/x11/gdkwindow-x11.c : Add a flag + for input_only windows. + + * gdk/gdkwindow.c gdk/x11/gdkgeometry-x11.c: Use the above flag + to fix some hacks and make sure that we don't try to set the + background of input only windows. + +Thu Feb 24 18:11:46 2000 Owen Taylor + + * gdk/gdkinternals.h gdk/gdkprivate.h gdk/Makefile.am: Add a header file for + the _really_ internal stuff, and leave gdkprivate.h for the fake private + stuff that we've traditionally exposed. + + * gdk/**.c: Use gdkinternals.h where appropriate. + + * gdk/x11/gdkx.h gdk/x11/gdkprivate-x11.h gdk/x11/*.c: Make gdkx.h + not include gdkprivate-x11.h, move all stuff of conceivable public + interest into gdkx.h; keep all really private stuff in + uninstalled header gdkprivate-x11.h. + + * gdk/gdkdraw.c gdk/gdkwindow.c gdk/gdkinternals: Redirect all calls to + image->image_put on windows through a new function _gdk_window_draw_image() + to allow us to do backing store for images. (Sort of ugly) + + * gdk/gdkgc.c gdk/gdkprivate.h: Cache the ts and clip origins for graphics + contexts locally so that we can offset them properly when drawing + onto backing pixmaps. + + * gdk/gdkinput.h: Reindented + + * gdk/gdkprivate.h gdk/x11/gdkwindow-x11.c: Store the background + pixmap or color for the window, so we can properly initialize + our double-buffer pixmaps, and also so that we temporarily set + a background of None while scrolling. + + * gdk/gdkregion.h: Revise region boolean operators to have an + interface that is actually convenient - switch from creating new + regions on every op, to "methods" that modify existing regions + (A = A OP B). 3 argument forms which allow dest == src, would also + be possible, but the current interfaces seem to map nicely + onto what needs to be done. (There is quite a lot of region + code in GDK now.) + + * gdk/gdkregion.h: Add constructor from rectangle and a copy + operator. + + * gdk/x11/{gdkregion-generic.[ch],gdkpolyreg-generic.c, + gdkpoly-generic.h: Copy region code from Xlib, switch it over + to 32 bit coordinates, modify it to be mostly GTK+ style + and to have interfaces that match gdkregion.h. + + * gdk/gdkwindow.c gdk/gdkprivate.h: Add facility for + double-buffered drawing. gdk_window_begin_paint_{rect,region}() + create a backing pixmap and redirect all drawing to + that backing pixmap until a matching gdk_window_end_paint(). + + * gdk/gdkwindow.[ch] gdk/gdkinternals.h gdk/x11/gdkdrawable-x11.c: + Create a special drawable class for GtkWindow's that + redirects the drawing to the backing pixmap as necessary + and then calls the real operations in _gdk_windowing_window_class. + + * gdk/gdkprivate.h gdk/gdkwindow.[ch] gdk/x11/gdkevents-x11.c: + Store invalid region for each window. Generate expose events for invalid + region in an idle. This replaces both the expose compression + and the redrawing queuing in GTK+. It is both more efficient and + simpler than either one individually and far more so then the + combination. + + * gdk/x11/gdkgeometry.c gdk/x11/gdkwindow.c gdk/x11/gdkprivate-x11.h: + Emulate 32 bit coordinates for windows with 16 bit coordinates + by offsetting drawing, guffaw scrolling techniques and + mapping/unmapping child windows as necessary. + + * gdk/gdkwindow.[ch] gdk/x11/gdkgeometry.c: Add anti-exposes, + where, when invalid regions are processed, the region is stored, + and if expose events come in that are detectably duplicate + the processed exposes (by comparison of event serial numbers), + the stored region is subtracted out of those exposes. + + * gdk/x11/gdkgeometry.c: Temporarily unset backing pixmaps of + regions newly exposed when scrolling or resizing windows. + This, combined with forcing processesing of queued invalidated + regions, gives nice flicker-free scrolling. + + * gtk/gtklayout.c gtk/gtkviewport.c: Force processing of + invalidated regions after every scroll. + + * gtk/gtklayout.c: Vastly simplify using the new 32 bit coordinate + emulation in GDK. Its, for all practical purposes just a + GtkViewport/GtkFixed hybrid now. + + * gdk/gdkdrawable-x11.c: Convert from GDK (32 bit) to X11 + (16-bit) structures as necessary instead of just casting. + + * gdk/x11/gdkgc-x11.c gdk/x11/gdkx.h: Replace XSetRegion with code + in terms of the structures from gdkregion-generic.c, using appropriate + offsets from GDK to X11 coordinates. Cache clip mask and + origin and ts origin locally and only flush to the server + when drawing, to avoid constantly setting and resetting these + values when offsetting GC's for scrolling and backing pixmaps. + + * gdk/x11/gdkinput-x11.c: Fix leak of axes structures. + + * gtk/gtkcontainer.c: Call process_all_updates at end + of resizing to reduce flicker. (Avoids having redraw + lag arbitrarily behind resize under some circumstances) + + * gtk/gtkentry.c: Remove old backing store code, and simply take + advantage of the new backing store capabilities of GDK. + + * gtk/gtkmain.c: Simple implementation of widget backing + store - simply push a paint while handling each expose. + (Should really be configurable widget for widget.) + + * gtk/gtkwidget.c: Remove all the old complicated redraw + code, and simply invalidate the GDK windows from + gdk_window_queue_clear(), etc. (Sigh, so much carefully + debugged complexity ... gone to the winds.) + + Remove all the code for suppressing expose events while + resizes are pending; this isn't needed since the invalid + areas won't be processed until after the resizes are + processed, since they are in a lower priority idle. + +Thu Feb 24 15:37:41 2000 Owen Taylor + + * gdk/gdkrectangle.c (gdk_rectangle_intersect): Set width + and height of dest rectangle for non-intersecting rectangles. + +Sun Feb 20 16:47:31 2000 Owen Taylor + + * gtk/gtkwidget.h: Make GtkAllocation just a typedef + for GdkRectangle. + +Sun Feb 20 11:27:00 2000 Owen Taylor + + * gdk/gdk{events,image,private,types,window}.h + gdk/x11/gdkinputprivate.h: Change all coordinates + from int16 to int. Also, Change width and height from + unsigned to signed to avoid all the stupid C + signedness bugs. + +Sat Feb 19 12:01:53 2000 Owen Taylor + + * gdk/x11/gdkdrawable-x11.c (gdk_x11_draw_drawable): + Use gdk_drawable_get_depth instead of gdk_drawable_get_visual. + Add some more detailed checking. + + * gdk/gdkdraw.c gdk/gdkdrawable.h (gdk_drawable_get_depth): + New function to retrieve the depth of a drawable. + + * gdk/gdkprivate.h (struct _GdkDrawablePrivate): Add a depth + field, reorder fields to save memory. + +Mon Dec 13 14:06:03 1999 Owen Taylor + + * gtk/gtkentry.c (gtk_entry_draw_cursor_on_drawable): Draw a small portion + of the background image instead of scaling the background down to + a line. + + * gtk/gtk[hv]scrollbar.c (gtk_hscrollbar_size_allocate): Removed mysterious + which temporarily set slider to wrong size. + + * gtk/gtkaspectframe.c gtkbin.c: Remove unecessary calls to + queue_clear(). + +Wed Nov 17 18:36:05 1999 Owen Taylor + 2000-03-23 Jonathan Blandford * gtk/gtkpaned.c (gtk_paned_get_position): add getter. diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 57509b88e8..77d464c22e 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,179 @@ +Thu Feb 24 23:58:21 2000 Owen Taylor + + * gdk/x11/gdkgeometry-x11.c: Don't worry about clipping of + toplevel windows and their immediate children by their parents, + since the size of toplevel windows is out of our immediate + control and we don't get any real benefit from trying to track + this size for clipping. + + * gdk/gdkprivate.h (struct _GdkWindowPrivate) gdk/x11/gdkwindow-x11.c : Add a flag + for input_only windows. + + * gdk/gdkwindow.c gdk/x11/gdkgeometry-x11.c: Use the above flag + to fix some hacks and make sure that we don't try to set the + background of input only windows. + +Thu Feb 24 18:11:46 2000 Owen Taylor + + * gdk/gdkinternals.h gdk/gdkprivate.h gdk/Makefile.am: Add a header file for + the _really_ internal stuff, and leave gdkprivate.h for the fake private + stuff that we've traditionally exposed. + + * gdk/**.c: Use gdkinternals.h where appropriate. + + * gdk/x11/gdkx.h gdk/x11/gdkprivate-x11.h gdk/x11/*.c: Make gdkx.h + not include gdkprivate-x11.h, move all stuff of conceivable public + interest into gdkx.h; keep all really private stuff in + uninstalled header gdkprivate-x11.h. + + * gdk/gdkdraw.c gdk/gdkwindow.c gdk/gdkinternals: Redirect all calls to + image->image_put on windows through a new function _gdk_window_draw_image() + to allow us to do backing store for images. (Sort of ugly) + + * gdk/gdkgc.c gdk/gdkprivate.h: Cache the ts and clip origins for graphics + contexts locally so that we can offset them properly when drawing + onto backing pixmaps. + + * gdk/gdkinput.h: Reindented + + * gdk/gdkprivate.h gdk/x11/gdkwindow-x11.c: Store the background + pixmap or color for the window, so we can properly initialize + our double-buffer pixmaps, and also so that we temporarily set + a background of None while scrolling. + + * gdk/gdkregion.h: Revise region boolean operators to have an + interface that is actually convenient - switch from creating new + regions on every op, to "methods" that modify existing regions + (A = A OP B). 3 argument forms which allow dest == src, would also + be possible, but the current interfaces seem to map nicely + onto what needs to be done. (There is quite a lot of region + code in GDK now.) + + * gdk/gdkregion.h: Add constructor from rectangle and a copy + operator. + + * gdk/x11/{gdkregion-generic.[ch],gdkpolyreg-generic.c, + gdkpoly-generic.h: Copy region code from Xlib, switch it over + to 32 bit coordinates, modify it to be mostly GTK+ style + and to have interfaces that match gdkregion.h. + + * gdk/gdkwindow.c gdk/gdkprivate.h: Add facility for + double-buffered drawing. gdk_window_begin_paint_{rect,region}() + create a backing pixmap and redirect all drawing to + that backing pixmap until a matching gdk_window_end_paint(). + + * gdk/gdkwindow.[ch] gdk/gdkinternals.h gdk/x11/gdkdrawable-x11.c: + Create a special drawable class for GtkWindow's that + redirects the drawing to the backing pixmap as necessary + and then calls the real operations in _gdk_windowing_window_class. + + * gdk/gdkprivate.h gdk/gdkwindow.[ch] gdk/x11/gdkevents-x11.c: + Store invalid region for each window. Generate expose events for invalid + region in an idle. This replaces both the expose compression + and the redrawing queuing in GTK+. It is both more efficient and + simpler than either one individually and far more so then the + combination. + + * gdk/x11/gdkgeometry.c gdk/x11/gdkwindow.c gdk/x11/gdkprivate-x11.h: + Emulate 32 bit coordinates for windows with 16 bit coordinates + by offsetting drawing, guffaw scrolling techniques and + mapping/unmapping child windows as necessary. + + * gdk/gdkwindow.[ch] gdk/x11/gdkgeometry.c: Add anti-exposes, + where, when invalid regions are processed, the region is stored, + and if expose events come in that are detectably duplicate + the processed exposes (by comparison of event serial numbers), + the stored region is subtracted out of those exposes. + + * gdk/x11/gdkgeometry.c: Temporarily unset backing pixmaps of + regions newly exposed when scrolling or resizing windows. + This, combined with forcing processesing of queued invalidated + regions, gives nice flicker-free scrolling. + + * gtk/gtklayout.c gtk/gtkviewport.c: Force processing of + invalidated regions after every scroll. + + * gtk/gtklayout.c: Vastly simplify using the new 32 bit coordinate + emulation in GDK. Its, for all practical purposes just a + GtkViewport/GtkFixed hybrid now. + + * gdk/gdkdrawable-x11.c: Convert from GDK (32 bit) to X11 + (16-bit) structures as necessary instead of just casting. + + * gdk/x11/gdkgc-x11.c gdk/x11/gdkx.h: Replace XSetRegion with code + in terms of the structures from gdkregion-generic.c, using appropriate + offsets from GDK to X11 coordinates. Cache clip mask and + origin and ts origin locally and only flush to the server + when drawing, to avoid constantly setting and resetting these + values when offsetting GC's for scrolling and backing pixmaps. + + * gdk/x11/gdkinput-x11.c: Fix leak of axes structures. + + * gtk/gtkcontainer.c: Call process_all_updates at end + of resizing to reduce flicker. (Avoids having redraw + lag arbitrarily behind resize under some circumstances) + + * gtk/gtkentry.c: Remove old backing store code, and simply take + advantage of the new backing store capabilities of GDK. + + * gtk/gtkmain.c: Simple implementation of widget backing + store - simply push a paint while handling each expose. + (Should really be configurable widget for widget.) + + * gtk/gtkwidget.c: Remove all the old complicated redraw + code, and simply invalidate the GDK windows from + gdk_window_queue_clear(), etc. (Sigh, so much carefully + debugged complexity ... gone to the winds.) + + Remove all the code for suppressing expose events while + resizes are pending; this isn't needed since the invalid + areas won't be processed until after the resizes are + processed, since they are in a lower priority idle. + +Thu Feb 24 15:37:41 2000 Owen Taylor + + * gdk/gdkrectangle.c (gdk_rectangle_intersect): Set width + and height of dest rectangle for non-intersecting rectangles. + +Sun Feb 20 16:47:31 2000 Owen Taylor + + * gtk/gtkwidget.h: Make GtkAllocation just a typedef + for GdkRectangle. + +Sun Feb 20 11:27:00 2000 Owen Taylor + + * gdk/gdk{events,image,private,types,window}.h + gdk/x11/gdkinputprivate.h: Change all coordinates + from int16 to int. Also, Change width and height from + unsigned to signed to avoid all the stupid C + signedness bugs. + +Sat Feb 19 12:01:53 2000 Owen Taylor + + * gdk/x11/gdkdrawable-x11.c (gdk_x11_draw_drawable): + Use gdk_drawable_get_depth instead of gdk_drawable_get_visual. + Add some more detailed checking. + + * gdk/gdkdraw.c gdk/gdkdrawable.h (gdk_drawable_get_depth): + New function to retrieve the depth of a drawable. + + * gdk/gdkprivate.h (struct _GdkDrawablePrivate): Add a depth + field, reorder fields to save memory. + +Mon Dec 13 14:06:03 1999 Owen Taylor + + * gtk/gtkentry.c (gtk_entry_draw_cursor_on_drawable): Draw a small portion + of the background image instead of scaling the background down to + a line. + + * gtk/gtk[hv]scrollbar.c (gtk_hscrollbar_size_allocate): Removed mysterious + which temporarily set slider to wrong size. + + * gtk/gtkaspectframe.c gtkbin.c: Remove unecessary calls to + queue_clear(). + +Wed Nov 17 18:36:05 1999 Owen Taylor + 2000-03-23 Jonathan Blandford * gtk/gtkpaned.c (gtk_paned_get_position): add getter. diff --git a/docs/Changes-1.4.txt b/docs/Changes-1.4.txt index 1f5cad504b..436af8d204 100644 --- a/docs/Changes-1.4.txt +++ b/docs/Changes-1.4.txt @@ -18,4 +18,6 @@ Incompatible Changes from GTK+-1.2 to GTK+-1.4: that the automatic grab that occurs when the user presses a button will have owner_events = FALSE, so all events are redirected to the grab window, even events that would normally go to other windows of the - window's owner. \ No newline at end of file + window's owner. + +- The detail arguments in the GtkStyleClass structure are now 'const gchar *'. diff --git a/gdk/Makefile.am b/gdk/Makefile.am index 5130ac1c70..b91ce20d14 100644 --- a/gdk/Makefile.am +++ b/gdk/Makefile.am @@ -83,6 +83,7 @@ gdk_c_sources = @STRIP_BEGIN@ \ gdkgc.c \ gdkglobals.c \ gdkimage.c \ + gdkinternals.h \ gdkrgb.c \ gdkrectangle.c \ gdkwindow.c \ diff --git a/gdk/gdk.c b/gdk/gdk.c index 9c4ed33208..7a1b7de48a 100644 --- a/gdk/gdk.c +++ b/gdk/gdk.c @@ -30,7 +30,7 @@ #include #include "gdk.h" -#include "gdkprivate.h" +#include "gdkinternals.h" #ifndef HAVE_XCONVERTCASE #include "gdkkeysyms.h" diff --git a/gdk/gdkdraw.c b/gdk/gdkdraw.c index ef007c6c57..a30c1c4e2f 100644 --- a/gdk/gdkdraw.c +++ b/gdk/gdkdraw.c @@ -47,6 +47,8 @@ gdk_drawable_alloc (void) private->width = 1; private->height = 1; + private->depth = 0; + private->colormap = NULL; return drawable; @@ -104,6 +106,15 @@ gdk_drawable_get_visual (GdkDrawable *drawable) return colormap ? gdk_colormap_get_visual (colormap) : NULL; } +gint +gdk_drawable_get_depth (GdkDrawable *drawable) +{ + GdkDrawablePrivate *private = (GdkDrawablePrivate *)drawable; + g_return_val_if_fail (drawable != NULL, 0); + + return private->depth; +} + GdkDrawable* gdk_drawable_ref (GdkDrawable *drawable) { @@ -365,8 +376,12 @@ gdk_draw_image (GdkDrawable *drawable, height = image->height; - image_private->klass->image_put (image, drawable, gc, xsrc, ysrc, - xdest, ydest, width, height); + if (GDK_IS_WINDOW (drawable)) + _gdk_window_draw_image (drawable, gc, image, xsrc, ysrc, + xdest, ydest, width, height); + else + image_private->klass->image_put (image, drawable, gc, xsrc, ysrc, + xdest, ydest, width, height); } void diff --git a/gdk/gdkdrawable.h b/gdk/gdkdrawable.h index 80d797ef53..3b05d24a27 100644 --- a/gdk/gdkdrawable.h +++ b/gdk/gdkdrawable.h @@ -130,6 +130,7 @@ void gdk_drawable_set_colormap (GdkDrawable *drawable, GdkColormap *colormap); GdkColormap* gdk_drawable_get_colormap (GdkDrawable *drawable); GdkVisual* gdk_drawable_get_visual (GdkDrawable *drawable); +gint gdk_drawable_get_depth (GdkDrawable *drawable); GdkDrawable* gdk_drawable_ref (GdkDrawable *drawable); void gdk_drawable_unref (GdkDrawable *drawable); diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c index 8df54a0939..5dabc26108 100644 --- a/gdk/gdkevents.c +++ b/gdk/gdkevents.c @@ -25,7 +25,7 @@ */ #include "gdk.h" -#include "gdkprivate.h" +#include "gdkinternals.h" typedef struct _GdkIOClosure GdkIOClosure; typedef struct _GdkEventPrivate GdkEventPrivate; diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h index 29dde26a77..401ffbfd4b 100644 --- a/gdk/gdkevents.h +++ b/gdk/gdkevents.h @@ -317,9 +317,9 @@ struct _GdkEventConfigure GdkEventType type; GdkWindow *window; gint8 send_event; - gint16 x, y; - gint16 width; - gint16 height; + gint x, y; + gint width; + gint height; }; struct _GdkEventProperty diff --git a/gdk/gdkgc.c b/gdk/gdkgc.c index 3853485215..8eb6eaad46 100644 --- a/gdk/gdkgc.c +++ b/gdk/gdkgc.c @@ -38,6 +38,10 @@ gdk_gc_alloc (void) private->ref_count = 1; private->klass = NULL; private->klass_data = NULL; + private->clip_x_origin = 0; + private->clip_y_origin = 0; + private->ts_x_origin = 0; + private->ts_y_origin = 0; return (GdkGC *)private; } @@ -58,14 +62,29 @@ gdk_gc_new_with_values (GdkDrawable *drawable, GdkGCValues *values, GdkGCValuesMask values_mask) { + GdkGC *gc; + GdkGCPrivate *private; + g_return_val_if_fail (drawable != NULL, NULL); if (GDK_DRAWABLE_DESTROYED (drawable)) return NULL; - return ((GdkDrawablePrivate *)drawable)->klass->create_gc (drawable, - values, - values_mask); + gc = ((GdkDrawablePrivate *)drawable)->klass->create_gc (drawable, + values, + values_mask); + private = (GdkGCPrivate *)gc; + + if (values_mask & GDK_GC_CLIP_X_ORIGIN) + private->clip_x_origin = values->clip_x_origin; + if (values_mask & GDK_GC_CLIP_Y_ORIGIN) + private->clip_y_origin = values->clip_y_origin; + if (values_mask & GDK_GC_TS_X_ORIGIN) + private->ts_x_origin = values->ts_x_origin; + if (values_mask & GDK_GC_TS_Y_ORIGIN) + private->ts_y_origin = values->ts_y_origin; + + return gc; } GdkGC * @@ -90,7 +109,10 @@ gdk_gc_unref (GdkGC *gc) private->ref_count--; if (private->ref_count == 0) - private->klass->destroy (gc); + { + private->klass->destroy (gc); + g_free (private); + } } void @@ -108,10 +130,21 @@ gdk_gc_set_values (GdkGC *gc, GdkGCValues *values, GdkGCValuesMask values_mask) { + GdkGCPrivate *private = (GdkGCPrivate *)gc; + g_return_if_fail (gc != NULL); g_return_if_fail (values != NULL); - ((GdkGCPrivate *)gc)->klass->set_values (gc, values, values_mask); + if (values_mask & GDK_GC_CLIP_X_ORIGIN) + private->clip_x_origin = values->clip_x_origin; + if (values_mask & GDK_GC_CLIP_Y_ORIGIN) + private->clip_y_origin = values->clip_y_origin; + if (values_mask & GDK_GC_TS_X_ORIGIN) + private->ts_x_origin = values->ts_x_origin; + if (values_mask & GDK_GC_TS_Y_ORIGIN) + private->ts_y_origin = values->ts_y_origin; + + private->klass->set_values (gc, values, values_mask); } void diff --git a/gdk/gdkimage.h b/gdk/gdkimage.h index 48cf507b51..1dc8a880cd 100644 --- a/gdk/gdkimage.h +++ b/gdk/gdkimage.h @@ -34,8 +34,8 @@ struct _GdkImage GdkImageType type; GdkVisual *visual; /* visual used to create the image */ GdkByteOrder byte_order; - guint16 width; - guint16 height; + gint width; + gint height; guint16 depth; guint16 bpp; /* bytes per pixel */ guint16 bpl; /* bytes per line */ diff --git a/gdk/gdkinput.h b/gdk/gdkinput.h index 35550b2655..db23b3f6d5 100644 --- a/gdk/gdkinput.h +++ b/gdk/gdkinput.h @@ -99,7 +99,6 @@ GdkTimeCoord *gdk_input_motion_events (GdkWindow *window, guint32 deviceid, guint32 start, guint32 stop, - gint *nevents_return); #ifdef __cplusplus } diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h new file mode 100644 index 0000000000..b7a6336375 --- /dev/null +++ b/gdk/gdkinternals.h @@ -0,0 +1,210 @@ +/* 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/. + */ + +/* Uninstalled header defining types and functions internal to GDK */ + +#include +#include + +#ifndef __GDK_INTERNALS_H__ +#define __GDK_INTERNALS_H__ + +/********************** + * General Facilities * + **********************/ + +/* Debugging support */ + +typedef enum { + GDK_DEBUG_MISC = 1 << 0, + GDK_DEBUG_EVENTS = 1 << 1, + GDK_DEBUG_DND = 1 << 2, + GDK_DEBUG_COLOR_CONTEXT = 1 << 3, + GDK_DEBUG_XIM = 1 << 4 +} GdkDebugFlag; + +extern gint gdk_debug_level; +extern gboolean gdk_show_events; +extern GList *gdk_default_filters; + +GDKVAR guint gdk_debug_flags; + +#ifdef G_ENABLE_DEBUG + +#define GDK_NOTE(type,action) G_STMT_START { \ + if (gdk_debug_flags & GDK_DEBUG_##type) \ + { action; }; } G_STMT_END + +#else /* !G_ENABLE_DEBUG */ + +#define GDK_NOTE(type,action) + +#endif /* G_ENABLE_DEBUG */ + +/* Arg parsing */ + +typedef enum +{ + GDK_ARG_STRING, + GDK_ARG_INT, + GDK_ARG_BOOL, + GDK_ARG_NOBOOL, + GDK_ARG_CALLBACK +} GdkArgType; + +typedef struct _GdkArgContext GdkArgContext; +typedef struct _GdkArgDesc GdkArgDesc; + +typedef void (*GdkArgFunc) (const char *name, const char *arg, gpointer data); + +struct _GdkArgContext +{ + GPtrArray *tables; + gpointer cb_data; +}; + +struct _GdkArgDesc +{ + const char *name; + GdkArgType type; + gpointer location; + GdkArgFunc callback; +}; + +/* Event handling */ + +extern GdkEventFunc gdk_event_func; /* Callback for events */ +extern gpointer gdk_event_data; +extern GDestroyNotify gdk_event_notify; + +/* FIFO's for event queue, and for events put back using + * gdk_event_put(). + */ +extern GList *gdk_queued_events; +extern GList *gdk_queued_tail; + +GdkEvent* gdk_event_new (void); + +void gdk_events_init (void); +void gdk_events_queue (void); +GdkEvent* gdk_event_unqueue (void); + +GList* gdk_event_queue_find_first (void); +void gdk_event_queue_remove_link (GList *node); +void gdk_event_queue_append (GdkEvent *event); + +void gdk_event_button_generate (GdkEvent *event); + +/************************************* + * Interfaces used by windowing code * + *************************************/ + +#ifdef USE_XIM +/* XIM support */ +gint gdk_im_open (void); +void gdk_im_close (void); +void gdk_ic_cleanup (void); +#endif /* USE_XIM */ + +GdkWindow* _gdk_window_alloc (void); +void _gdk_window_draw_image (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); + +/***************************************** + * Interfaces provided by windowing code * + *****************************************/ + +/* Font/string functions implemented in module-specific code */ +gint _gdk_font_strlen (GdkFont *font, const char *str); +void _gdk_font_destroy (GdkFont *font); + +void _gdk_colormap_real_destroy (GdkColormap *colormap); + +void _gdk_cursor_destroy (GdkCursor *cursor); + +/* Class supplied by windowing-system-dependent code for GdkWindow. + */ +extern GdkDrawableClass _gdk_windowing_window_class; + +/* Class for covering over windowing-system-dependent and backing-store + * code for GdkWindow + */ +extern GdkDrawableClass _gdk_window_class; + +extern GdkArgDesc _gdk_windowing_args[]; +gboolean _gdk_windowing_init_check (int argc, + char **argv); +void _gdk_windowing_window_get_offsets (GdkWindow *window, + gint *x_offset, + gint *y_offset); +void _gdk_windowing_window_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height); +void _gdk_windowing_window_clear_area_e (GdkWindow *window, + gint x, + gint y, + gint width, + gint height); + +/* Called before processing updates for a window. This gives the windowing + * layer a chance to save the region for later use in avoiding duplicate + * exposes. The return value indicates whether the function has a saved + * the region; if the result is TRUE, then the windowing layer is responsible + * for destroying the region later. + */ +gboolean _gdk_windowing_window_queue_antiexpose (GdkWindow *window, + GdkRegion *area); + +/************************************ + * Initialization and exit routines * + ************************************/ + +void gdk_window_init (void); +void gdk_visual_init (void); +void gdk_dnd_init (void); + +void gdk_image_init (void); +void gdk_image_exit (void); + +void gdk_input_init (void); +void gdk_input_exit (void); + +void gdk_windowing_exit (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __GDK_INTERNALS_H__ */ diff --git a/gdk/gdkpoly-generic.h b/gdk/gdkpoly-generic.h new file mode 100644 index 0000000000..660c689adb --- /dev/null +++ b/gdk/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/gdkpolyreg-generic.c b/gdk/gdkpolyreg-generic.c new file mode 100644 index 0000000000..b98bd5641e --- /dev/null +++ b/gdk/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 +#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/gdkprivate.h b/gdk/gdkprivate.h index 4eefea9e44..ef92a2663c 100644 --- a/gdk/gdkprivate.h +++ b/gdk/gdkprivate.h @@ -41,6 +41,9 @@ extern "C" { #endif /* __cplusplus */ +#define GDK_PARENT_RELATIVE_BG ((GdkPixmap *)1L) +#define GDK_NO_BG ((GdkPixmap *)2L) + #define GDK_DRAWABLE_TYPE(d) (((GdkDrawablePrivate *)d)->window_type) #define GDK_IS_WINDOW(d) (GDK_DRAWABLE_TYPE(d) <= GDK_WINDOW_TEMP || \ GDK_DRAWABLE_TYPE(d) == GDK_WINDOW_FOREIGN) @@ -52,7 +55,6 @@ extern "C" { #define gdk_font_lookup(xid) ((GdkFont*) gdk_xid_table_lookup (xid)) typedef struct _GdkDrawablePrivate GdkDrawablePrivate; -/* typedef struct _GdkDrawablePrivate GdkPixmapPrivate; */ typedef struct _GdkWindowPrivate GdkWindowPrivate; typedef struct _GdkImageClass GdkImageClass; typedef struct _GdkImagePrivate GdkImagePrivate; @@ -69,14 +71,16 @@ struct _GdkDrawablePrivate GdkDrawableClass *klass; gpointer klass_data; - guint8 window_type; guint ref_count; - guint16 width; - guint16 height; + gint width; + gint height; GdkColormap *colormap; + guint8 window_type; + guint8 depth; + guint destroyed : 2; }; @@ -85,16 +89,25 @@ struct _GdkWindowPrivate GdkDrawablePrivate drawable; GdkWindow *parent; - gint16 x; - gint16 y; + gint x; + gint y; guint8 resize_count; guint mapped : 1; guint guffaw_gravity : 1; + guint input_only : 1; gint extension_events; GList *filters; GList *children; + + GdkColor bg_color; + GdkPixmap *bg_pixmap; + + GSList *paint_stack; + + GdkRegion *update_area; + guint update_freeze_count; }; struct _GdkImageClass @@ -130,6 +143,11 @@ struct _GdkGCPrivate guint ref_count; GdkGCClass *klass; gpointer klass_data; + + gint clip_x_origin; + gint clip_y_origin; + gint ts_x_origin; + gint ts_y_origin; }; typedef enum { @@ -161,137 +179,11 @@ struct _GdkClientFilter { gpointer data; }; -typedef enum -{ - GDK_ARG_STRING, - GDK_ARG_INT, - GDK_ARG_BOOL, - GDK_ARG_NOBOOL, - GDK_ARG_CALLBACK -} GdkArgType; - - -typedef struct _GdkArgContext GdkArgContext; -typedef struct _GdkArgDesc GdkArgDesc; - -typedef void (*GdkArgFunc) (const char *name, const char *arg, gpointer data); - -struct _GdkArgContext -{ - GPtrArray *tables; - gpointer cb_data; -}; - -struct _GdkArgDesc -{ - const char *name; - GdkArgType type; - gpointer location; - GdkArgFunc callback; -}; - - -typedef enum { - GDK_DEBUG_MISC = 1 << 0, - GDK_DEBUG_EVENTS = 1 << 1, - GDK_DEBUG_DND = 1 << 2, - GDK_DEBUG_COLOR_CONTEXT = 1 << 3, - GDK_DEBUG_XIM = 1 << 4 -} GdkDebugFlag; - -void gdk_event_button_generate (GdkEvent *event); - -/* FIFO's for event queue, and for events put back using - * gdk_event_put(). - */ -extern GList *gdk_queued_events; -extern GList *gdk_queued_tail; - -extern GdkEventFunc gdk_event_func; /* Callback for events */ -extern gpointer gdk_event_data; -extern GDestroyNotify gdk_event_notify; - -GdkEvent* gdk_event_new (void); - -void gdk_events_init (void); -void gdk_events_queue (void); -GdkEvent* gdk_event_unqueue (void); - -GList* gdk_event_queue_find_first (void); -void gdk_event_queue_remove_link (GList *node); -void gdk_event_queue_append (GdkEvent *event); - -void gdk_window_init (void); -void gdk_visual_init (void); -void gdk_dnd_init (void); - -void gdk_image_init (void); -void gdk_image_exit (void); - -void gdk_input_init (void); -void gdk_input_exit (void); - -void gdk_windowing_exit (void); - -void gdk_window_add_colormap_windows (GdkWindow *window); void gdk_window_destroy_notify (GdkWindow *window); -/* If you pass x = y = -1, it queries the pointer - to find out where it currently is. - If you pass x = y = -2, it does anything necessary - to know that the drag is ending. -*/ -void gdk_dnd_display_drag_cursor(gint x, - gint y, - gboolean drag_ok, - gboolean change_made); - -extern gint gdk_debug_level; -extern gboolean gdk_show_events; -extern gint gdk_screen; GDKVAR GdkWindow *gdk_parent_root; GDKVAR gint gdk_error_code; GDKVAR gint gdk_error_warnings; -extern GList *gdk_default_filters; - -GdkWindow* _gdk_window_alloc (void); - -/* Font/string functions implemented in module-specific code */ -gint _gdk_font_strlen (GdkFont *font, const char *str); -void _gdk_font_destroy (GdkFont *font); - -void _gdk_colormap_real_destroy (GdkColormap *colormap); - -void _gdk_cursor_destroy (GdkCursor *cursor); - -/* Initialization */ - -extern GdkArgDesc _gdk_windowing_args[]; -gboolean _gdk_windowing_init_check (int argc, char **argv); - -#ifdef USE_XIM -/* XIM support */ -gint gdk_im_open (void); -void gdk_im_close (void); -void gdk_ic_cleanup (void); -#endif /* USE_XIM */ - -/* Debugging support */ - -#ifdef G_ENABLE_DEBUG - -#define GDK_NOTE(type,action) G_STMT_START { \ - if (gdk_debug_flags & GDK_DEBUG_##type) \ - { action; }; } G_STMT_END - -#else /* !G_ENABLE_DEBUG */ - -#define GDK_NOTE(type,action) - -#endif /* G_ENABLE_DEBUG */ - -GDKVAR guint gdk_debug_flags; - #ifdef __cplusplus } @@ -299,3 +191,8 @@ GDKVAR guint gdk_debug_flags; #endif /* __GDK_PRIVATE_H__ */ + + + + + diff --git a/gdk/gdkrectangle.c b/gdk/gdkrectangle.c index 9d8bb5a17b..a2bffdf742 100644 --- a/gdk/gdkrectangle.c +++ b/gdk/gdkrectangle.c @@ -31,14 +31,18 @@ gdk_rectangle_union (GdkRectangle *src1, GdkRectangle *src2, GdkRectangle *dest) { + gint dest_x, dest_y; + g_return_if_fail (src1 != NULL); g_return_if_fail (src2 != NULL); g_return_if_fail (dest != NULL); - dest->x = MIN (src1->x, src2->x); - dest->y = MIN (src1->y, src2->y); - dest->width = MAX (src1->x + src1->width, src2->x + src2->width) - dest->x; - dest->height = MAX (src1->y + src1->height, src2->y + src2->height) - dest->y; + dest_x = MIN (src1->x, src2->x); + dest_y = MIN (src1->y, src2->y); + dest->width = MAX (src1->x + src1->width, src2->x + src2->width) - dest_x; + dest->height = MAX (src1->y + src1->height, src2->y + src2->height) - dest_y; + dest->x = dest_x; + dest->y = dest_y; } gboolean @@ -63,13 +67,13 @@ gdk_rectangle_intersect (GdkRectangle *src1, src1 = src2; src2 = temp; } - dest->x = src2->x; - src1_x2 = src1->x + src1->width; src2_x2 = src2->x + src2->width; if (src2->x < src1_x2) { + dest->x = src2->x; + if (src1_x2 < src2_x2) dest->width = src1_x2 - dest->x; else @@ -81,8 +85,6 @@ gdk_rectangle_intersect (GdkRectangle *src1, src1 = src2; src2 = temp; } - dest->y = src2->y; - src1_y2 = src1->y + src1->height; src2_y2 = src2->y + src2->height; @@ -90,6 +92,8 @@ gdk_rectangle_intersect (GdkRectangle *src1, { return_val = TRUE; + dest->y = src2->y; + if (src1_y2 < src2_y2) dest->height = src1_y2 - dest->y; else @@ -102,5 +106,11 @@ gdk_rectangle_intersect (GdkRectangle *src1, } } + if (!return_val) + { + dest->width = 0; + dest->height = 0; + } + return return_val; } diff --git a/gdk/gdkregion-generic.c b/gdk/gdkregion-generic.c new file mode 100644 index 0000000000..0319f939f4 --- /dev/null +++ b/gdk/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 +#include "gdkregion-generic.h" + +#ifdef DEBUG +#include +#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 (y1rects); + 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].x1rects); \ + 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 (y1x1 < 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(y1x1x2); + 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(y1rects[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(x1x1); + 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(x1x2); + 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; inumRects; 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/gdkregion-generic.h b/gdk/gdkregion-generic.h new file mode 100644 index 0000000000..659d44eb4c --- /dev/null +++ b/gdk/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/gdkregion.h b/gdk/gdkregion.h index c52b702bad..2551797a85 100644 --- a/gdk/gdkregion.h +++ b/gdk/gdkregion.h @@ -29,48 +29,42 @@ typedef enum GDK_OVERLAP_RECTANGLE_PART } GdkOverlapType; -struct _GdkRegion -{ - gpointer user_data; -}; +GdkRegion *gdk_region_new (void); +GdkRegion *gdk_region_polygon (GdkPoint *points, + gint npoints, + GdkFillRule fill_rule); +GdkRegion *gdk_region_copy (GdkRegion *region); +GdkRegion *gdk_region_rectangle (GdkRectangle *rectangle); +void gdk_region_destroy (GdkRegion *region); -GdkRegion* gdk_region_new (void); -void gdk_region_destroy (GdkRegion *region); +void gdk_region_get_clipbox (GdkRegion *region, + GdkRectangle *rectangle); -void gdk_region_get_clipbox(GdkRegion *region, - GdkRectangle *rectangle); - -gboolean gdk_region_empty (GdkRegion *region); -gboolean gdk_region_equal (GdkRegion *region1, - GdkRegion *region2); -gboolean gdk_region_point_in (GdkRegion *region, - int x, - int y); -GdkOverlapType gdk_region_rect_in (GdkRegion *region, - GdkRectangle *rect); - -GdkRegion* gdk_region_polygon (GdkPoint *points, - gint npoints, - GdkFillRule fill_rule); - -void gdk_region_offset (GdkRegion *region, - gint dx, - gint dy); -void gdk_region_shrink (GdkRegion *region, - gint dx, - gint dy); - -GdkRegion* gdk_region_union_with_rect (GdkRegion *region, - GdkRectangle *rect); -GdkRegion* gdk_regions_intersect (GdkRegion *source1, - GdkRegion *source2); -GdkRegion* gdk_regions_union (GdkRegion *source1, - GdkRegion *source2); -GdkRegion* gdk_regions_subtract (GdkRegion *source1, - GdkRegion *source2); -GdkRegion* gdk_regions_xor (GdkRegion *source1, - GdkRegion *source2); +gboolean gdk_region_empty (GdkRegion *region); +gboolean gdk_region_equal (GdkRegion *region1, + GdkRegion *region2); +gboolean gdk_region_point_in (GdkRegion *region, + int x, + int y); +GdkOverlapType gdk_region_rect_in (GdkRegion *region, + GdkRectangle *rect); +void gdk_region_offset (GdkRegion *region, + gint dx, + gint dy); +void gdk_region_shrink (GdkRegion *region, + gint dx, + gint dy); +void gdk_region_union_with_rect (GdkRegion *region, + GdkRectangle *rect); +void gdk_region_intersect (GdkRegion *source1, + GdkRegion *source2); +void gdk_region_union (GdkRegion *source1, + GdkRegion *source2); +void gdk_region_subtract (GdkRegion *source1, + GdkRegion *source2); +void gdk_region_xor (GdkRegion *source1, + GdkRegion *source2); #ifdef __cplusplus } diff --git a/gdk/gdktypes.h b/gdk/gdktypes.h index de5d6ac8a9..3ba5abf1dc 100644 --- a/gdk/gdktypes.h +++ b/gdk/gdktypes.h @@ -143,24 +143,24 @@ typedef void (*GdkDestroyNotify) (gpointer data); struct _GdkPoint { - gint16 x; - gint16 y; + gint x; + gint y; }; struct _GdkRectangle { - gint16 x; - gint16 y; - guint16 width; - guint16 height; + gint x; + gint y; + gint width; + gint height; }; struct _GdkSegment { - gint16 x1; - gint16 y1; - gint16 x2; - gint16 y2; + gint x1; + gint y1; + gint x2; + gint y2; }; diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 1e1a947ebd..efe2fe57ae 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -25,7 +25,98 @@ */ #include "gdkwindow.h" -#include "gdkprivate.h" +#include "gdkinternals.h" +#include "gdk.h" /* For gdk_rectangle_union() */ +#include "gdkpixmap.h" + +typedef struct _GdkWindowPaint GdkWindowPaint; + +struct _GdkWindowPaint +{ + GdkRegion *region; + GdkPixmap *pixmap; + gint x_offset; + gint y_offset; +}; + +static void gdk_window_draw_destroy (GdkDrawable *drawable); +static GdkGC *gdk_window_draw_create_gc (GdkDrawable *drawable, + GdkGCValues *values, + GdkGCValuesMask mask); +static void gdk_window_draw_rectangle (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height); +static void gdk_window_draw_arc (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height, + gint angle1, + gint angle2); +static void gdk_window_draw_polygon (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + GdkPoint *points, + gint npoints); +static void gdk_window_draw_text (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *text, + gint text_length); +static void gdk_window_draw_text_wc (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const GdkWChar *text, + gint text_length); +static void gdk_window_draw_drawable (GdkDrawable *drawable, + GdkGC *gc, + GdkPixmap *src, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +static void gdk_window_draw_points (GdkDrawable *drawable, + GdkGC *gc, + GdkPoint *points, + gint npoints); +static void gdk_window_draw_segments (GdkDrawable *drawable, + GdkGC *gc, + GdkSegment *segs, + gint nsegs); +static void gdk_window_draw_lines (GdkDrawable *drawable, + GdkGC *gc, + GdkPoint *points, + gint npoints); + + +/* All drawing operations on windows are forwarded through the following + * class to enable the automatic-backing-store feature. + */ +GdkDrawableClass _gdk_window_class = { + gdk_window_draw_destroy, + gdk_window_draw_create_gc, + gdk_window_draw_rectangle, + gdk_window_draw_arc, + gdk_window_draw_polygon, + gdk_window_draw_text, + gdk_window_draw_text_wc, + gdk_window_draw_drawable, + gdk_window_draw_points, + gdk_window_draw_segments, + gdk_window_draw_lines +}; GdkWindow * _gdk_window_alloc (void) @@ -58,6 +149,18 @@ _gdk_window_alloc (void) private->filters = NULL; private->children = NULL; + private->bg_color.pixel = 0; + private->bg_color.red = 0; + private->bg_color.green = 0; + private->bg_color.blue = 0; + + private->bg_pixmap = NULL; + + private->paint_stack = NULL; + + private->update_area = NULL; + private->update_freeze_count = 0; + return window; } @@ -268,3 +371,901 @@ gdk_window_is_viewable (GdkWindow *window) return TRUE; } +void +gdk_window_begin_paint_rect (GdkWindow *window, + GdkRectangle *rectangle) +{ + GdkRegion *region; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + region = gdk_region_rectangle (rectangle); + gdk_window_begin_paint_region (window, region); + gdk_region_destroy (region); +} + +static GdkGC * +gdk_window_get_bg_gc (GdkWindow *window, GdkWindowPaint *paint) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + + guint gc_mask = 0; + GdkGCValues gc_values; + + if (private->bg_pixmap == GDK_PARENT_RELATIVE_BG && private->parent) + { + GdkWindowPaint tmp_paint = *paint; + tmp_paint.x_offset += private->x; + tmp_paint.y_offset += private->y; + + return gdk_window_get_bg_gc (private->parent, &tmp_paint); + } + else if (private->bg_pixmap && private->bg_pixmap != GDK_PARENT_RELATIVE_BG && private->bg_pixmap != GDK_NO_BG) + { + gc_values.fill = GDK_TILED; + gc_values.tile = private->bg_pixmap; + gc_values.ts_x_origin = - paint->x_offset; + gc_values.ts_y_origin = - paint->y_offset; + + gc_mask = GDK_GC_FILL | GDK_GC_TILE | GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN; + } + else + { + gc_values.foreground = private->bg_color; + gc_mask = GDK_GC_FOREGROUND; + } + + return gdk_gc_new_with_values (paint->pixmap, &gc_values, gc_mask); +} + +static void +gdk_window_paint_init_bg (GdkWindow *window, + GdkWindowPaint *paint, + GdkRegion *init_region) +{ + GdkGC *tmp_gc; + + tmp_gc = gdk_window_get_bg_gc (window, paint); + gdk_draw_rectangle (paint->pixmap, tmp_gc, TRUE, 0, 0, -1, -1); + gdk_gc_unref (tmp_gc); +} + +void +gdk_window_begin_paint_region (GdkWindow *window, + GdkRegion *region) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + GdkRectangle clip_box; + GdkWindowPaint *paint; + GdkRegion *init_region; + GdkGC *tmp_gc; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + paint = g_new (GdkWindowPaint, 1); + + paint->region = gdk_region_copy (region); + + init_region = gdk_region_copy (region); + gdk_region_get_clipbox (paint->region, &clip_box); + + if (private->paint_stack) + { + gint old_width, old_height; + GdkWindowPaint *tmp_paint = private->paint_stack->data; + GdkRectangle old_rect, new_rect; + GSList *tmp_list; + + gdk_drawable_get_size (tmp_paint->pixmap, &old_width, &old_height); + old_rect.x = tmp_paint->x_offset; + old_rect.y = tmp_paint->y_offset; + old_rect.width = old_width; + old_rect.height = old_height; + + gdk_rectangle_union (&clip_box, &old_rect, &new_rect); + + if (new_rect.width > old_rect.width || new_rect.height > old_rect.height) + { + paint->pixmap = gdk_pixmap_new (window, new_rect.width, new_rect.height, -1); + tmp_gc = gdk_gc_new (paint->pixmap); + gdk_draw_drawable (paint->pixmap, tmp_gc, tmp_paint->pixmap, + 0, 0, old_rect.width, old_rect.height, + old_rect.x - new_rect.x, old_rect.y - new_rect.y); + gdk_gc_unref (tmp_gc); + gdk_drawable_unref (tmp_paint->pixmap); + + paint->x_offset = new_rect.x; + paint->y_offset = new_rect.y; + + tmp_list = private->paint_stack; + while (tmp_list) + { + tmp_paint = private->paint_stack->data; + gdk_region_subtract (init_region, tmp_paint->region); + + tmp_paint->pixmap = paint->pixmap; + tmp_paint->x_offset = paint->x_offset; + tmp_paint->y_offset = paint->x_offset; + + tmp_list = tmp_list->next; + } + } + else + { + paint->x_offset = tmp_paint->x_offset; + paint->y_offset = tmp_paint->y_offset; + paint->pixmap = tmp_paint->pixmap; + + tmp_list = private->paint_stack; + while (tmp_list) + { + tmp_paint = private->paint_stack->data; + gdk_region_subtract (init_region, tmp_paint->region); + + tmp_list = tmp_list->next; + } + } + } + else + { + paint->x_offset = clip_box.x; + paint->y_offset = clip_box.y; + paint->pixmap = gdk_pixmap_new (window, clip_box.width, clip_box.height, -1); + } + + if (!gdk_region_empty (init_region)) + gdk_window_paint_init_bg (window, paint, init_region); + gdk_region_destroy (init_region); + + private->paint_stack = g_slist_prepend (private->paint_stack, paint); +} + +void +gdk_window_end_paint (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + GdkWindowPaint *paint; + GdkGC *tmp_gc; + GdkRectangle clip_box; + gint x_offset, y_offset; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (private->paint_stack != NULL); + + paint = private->paint_stack->data; + private->paint_stack = g_slist_delete_link (private->paint_stack, private->paint_stack); + + gdk_region_get_clipbox (paint->region, &clip_box); + + tmp_gc = gdk_gc_new (window); + + _gdk_windowing_window_get_offsets (window, &x_offset, &y_offset); + + gdk_gc_set_clip_region (tmp_gc, paint->region); + gdk_gc_set_clip_origin (tmp_gc, -x_offset, -y_offset); + + _gdk_windowing_window_class.draw_drawable (window, tmp_gc, paint->pixmap, + clip_box.x - paint->x_offset, + clip_box.y - paint->y_offset, + clip_box.x - x_offset, clip_box.y - y_offset, + clip_box.width, clip_box.height); + gdk_gc_unref (tmp_gc); + + if (private->paint_stack) + { + GSList *tmp_list = private->paint_stack; + while (tmp_list) + { + GdkWindowPaint *tmp_paint = tmp_list->data; + gdk_region_subtract (tmp_paint->region, paint->region); + + tmp_list = tmp_list->next; + } + } + else + gdk_drawable_unref (paint->pixmap); + + gdk_region_destroy (paint->region); + g_free (paint); +} + +static void +gdk_window_get_offsets (GdkWindow *window, + gint *x_offset, + gint *y_offset) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + + if (private->paint_stack) + { + GdkWindowPaint *paint = private->paint_stack->data; + *x_offset = paint->x_offset; + *y_offset = paint->y_offset; + } + else + _gdk_windowing_window_get_offsets (window, x_offset, y_offset); +} + +#define OFFSET_GC(gc) \ + gint x_offset, y_offset; \ + gint old_clip_x = ((GdkGCPrivate *)gc)->clip_x_origin; \ + gint old_clip_y = ((GdkGCPrivate *)gc)->clip_y_origin; \ + gint old_ts_x = ((GdkGCPrivate *)gc)->ts_x_origin; \ + gint old_ts_y = ((GdkGCPrivate *)gc)->ts_y_origin; \ + gdk_window_get_offsets (drawable, &x_offset, &y_offset); \ + if (x_offset != 0 || y_offset != 0) \ + { \ + gdk_gc_set_clip_origin (gc, old_clip_x - x_offset, \ + old_clip_y - y_offset); \ + gdk_gc_set_ts_origin (gc, old_ts_x - x_offset, \ + old_ts_y - y_offset); \ + } + +#define RESTORE_GC(gc) \ + if (x_offset != 0 || y_offset != 0) \ + { \ + gdk_gc_set_clip_origin (gc, old_clip_x, old_clip_y); \ + gdk_gc_set_ts_origin (gc, old_ts_x, old_ts_y); \ + } + +static void +gdk_window_draw_destroy (GdkDrawable *drawable) +{ + _gdk_windowing_window_class.destroy (drawable); +} + +static GdkGC * +gdk_window_draw_create_gc (GdkDrawable *drawable, + GdkGCValues *values, + GdkGCValuesMask mask) +{ + return _gdk_windowing_window_class.create_gc (drawable, values, mask); +} + +static void +gdk_window_draw_rectangle (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)drawable; + OFFSET_GC (gc); + + if (private->paint_stack) + { + GdkWindowPaint *paint = private->paint_stack->data; + gdk_draw_rectangle (paint->pixmap, gc, filled, + x - x_offset, y - y_offset, width, height); + } + else + _gdk_windowing_window_class.draw_rectangle (drawable, gc, filled, + x - x_offset, y - y_offset, width, height); + + RESTORE_GC (gc); +} + +static void +gdk_window_draw_arc (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height, + gint angle1, + gint angle2) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)drawable; + OFFSET_GC (gc); + + if (private->paint_stack) + { + GdkWindowPaint *paint = private->paint_stack->data; + gdk_draw_arc (paint->pixmap, gc, filled, + x - x_offset, y_offset, + width, height, angle1, angle2); + } + else + _gdk_windowing_window_class.draw_arc (drawable, gc, filled, + x - x_offset, y - y_offset, + width, height, angle1, angle2); + RESTORE_GC (gc); +} + +static void +gdk_window_draw_polygon (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + GdkPoint *points, + gint npoints) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)drawable; + GdkPoint *new_points; + + OFFSET_GC (gc); + + if (x_offset != 0 || y_offset != 0) + { + int i; + + new_points = g_new (GdkPoint, npoints); + for (i=0; ipaint_stack) + { + GdkWindowPaint *paint = private->paint_stack->data; + gdk_draw_polygon (paint->pixmap, gc, filled, new_points, npoints); + + } + else + _gdk_windowing_window_class.draw_polygon (drawable, gc, filled, new_points, npoints); + + if (new_points != points) + g_free (new_points); + + RESTORE_GC (gc); +} + +static void +gdk_window_draw_text (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *text, + gint text_length) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)drawable; + OFFSET_GC (gc); + + if (private->paint_stack) + { + GdkWindowPaint *paint = private->paint_stack->data; + gdk_draw_text (paint->pixmap, font, gc, + x - x_offset, y - y_offset, text, text_length); + + } + else + _gdk_windowing_window_class.draw_text (drawable, font, gc, + x - x_offset, y - y_offset, text, text_length); + + RESTORE_GC (gc); +} + +static void +gdk_window_draw_text_wc (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const GdkWChar *text, + gint text_length) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)drawable; + OFFSET_GC (gc); + + if (private->paint_stack) + { + GdkWindowPaint *paint = private->paint_stack->data; + gdk_draw_text_wc (paint->pixmap, font, gc, + x - x_offset, y - y_offset, text, text_length); + } + else + _gdk_windowing_window_class.draw_text_wc (drawable, font, gc, + x - x_offset, y - y_offset, text, text_length); + + RESTORE_GC (gc); +} + +static void +gdk_window_draw_drawable (GdkDrawable *drawable, + GdkGC *gc, + GdkPixmap *src, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)drawable; + OFFSET_GC (gc); + + if (private->paint_stack) + { + GdkWindowPaint *paint = private->paint_stack->data; + gdk_draw_drawable (paint->pixmap, gc, src, xsrc, ysrc, + xdest - x_offset, ydest - y_offset, width, height); + + } + else + _gdk_windowing_window_class.draw_drawable (drawable, gc, src, xsrc, ysrc, + xdest - x_offset, ydest - y_offset, + width, height); + RESTORE_GC (gc); +} + +static void +gdk_window_draw_points (GdkDrawable *drawable, + GdkGC *gc, + GdkPoint *points, + gint npoints) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)drawable; + GdkPoint *new_points; + + OFFSET_GC (gc); + + if (x_offset != 0 || y_offset != 0) + { + gint i; + + new_points = g_new (GdkPoint, npoints); + for (i=0; ipaint_stack) + { + GdkWindowPaint *paint = private->paint_stack->data; + gdk_draw_points (paint->pixmap, gc, new_points, npoints); + } + else + _gdk_windowing_window_class.draw_points (drawable, gc, points, npoints); + + if (new_points != points) + g_free (new_points); + + RESTORE_GC (gc); +} + +static void +gdk_window_draw_segments (GdkDrawable *drawable, + GdkGC *gc, + GdkSegment *segs, + gint nsegs) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)drawable; + GdkSegment *new_segs; + + OFFSET_GC (gc); + + if (x_offset != 0 || y_offset != 0) + { + gint i; + + new_segs = g_new (GdkSegment, nsegs); + for (i=0; ipaint_stack) + { + GdkWindowPaint *paint = private->paint_stack->data; + gdk_draw_segments (paint->pixmap, gc, new_segs, nsegs); + } + else + _gdk_windowing_window_class.draw_segments (drawable, gc, new_segs, nsegs); + + if (new_segs != segs) + g_free (new_segs); + + RESTORE_GC (gc); +} + +static void +gdk_window_draw_lines (GdkDrawable *drawable, + GdkGC *gc, + GdkPoint *points, + gint npoints) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)drawable; + GdkPoint *new_points; + + OFFSET_GC (gc); + + if (x_offset != 0 || y_offset != 0) + { + gint i; + + new_points = g_new (GdkPoint, npoints); + for (i=0; ipaint_stack) + { + GdkWindowPaint *paint = private->paint_stack->data; + gdk_draw_lines (paint->pixmap, gc, new_points, npoints); + } + else + _gdk_windowing_window_class.draw_lines (drawable, gc, new_points, npoints); + + if (new_points != points) + g_free (new_points); + + RESTORE_GC (gc); +} + +/* Fixme - this is just like gdk_window_paint_init_bg */ +static void +gdk_window_clear_backing_rect (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + GdkWindowPaint *paint = private->paint_stack->data; + GdkGC *tmp_gc; + + tmp_gc = gdk_window_get_bg_gc (window, paint); + gdk_draw_rectangle (paint->pixmap, tmp_gc, TRUE, + x - paint->x_offset, y - paint->y_offset, width, height); + gdk_gc_unref (tmp_gc); +} + +void +gdk_window_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (private->paint_stack) + gdk_window_clear_backing_rect (window, x, y, width, height); + else + _gdk_windowing_window_clear_area (window, x, y, width, height); +} + +void +gdk_window_clear_area_e (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (private->paint_stack) + gdk_window_clear_backing_rect (window, x, y, width, height); + + _gdk_windowing_window_clear_area_e (window, x, y, width, height); +} + +void +_gdk_window_draw_image (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkImagePrivate *image_private = (GdkImagePrivate*) image; + GdkWindowPrivate *private = (GdkWindowPrivate *)drawable; + + OFFSET_GC (gc); + + if (private->paint_stack) + { + GdkWindowPaint *paint = private->paint_stack->data; + image_private->klass->image_put (image, paint->pixmap, gc, xsrc, ysrc, + xdest - x_offset, ydest - y_offset, + width, height); + + } + else + image_private->klass->image_put (image, drawable, gc, xsrc, ysrc, + xdest - x_offset, ydest - y_offset, + width, height); + + RESTORE_GC (gc); +} + +/* Code for dirty-region queueing + */ + +static GSList *update_windows = NULL; +static guint update_idle = 0; + +#define GDK_PRIORITY_REDRAW (G_PRIORITY_HIGH_IDLE + 20) + +static void +gdk_window_process_updates_internal (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + gboolean save_region = FALSE; + + if (gdk_event_func) + { + GdkEvent event; + GdkRectangle window_rect; + + window_rect.x = 0; + window_rect.y = 0; + window_rect.width = private->drawable.width; + window_rect.height = private->drawable.height; + + save_region = _gdk_windowing_window_queue_antiexpose (window, private->update_area); + + event.expose.type = GDK_EXPOSE; + event.expose.window = gdk_window_ref ((GdkWindow *)private); + event.expose.count = 0; + + gdk_region_get_clipbox (private->update_area, &event.expose.area); + if (gdk_rectangle_intersect (&event.expose.area, &window_rect, &event.expose.area)) + { + (*gdk_event_func) (&event, gdk_event_data); + } + } + + if (!save_region) + gdk_region_destroy (private->update_area); + private->update_area = NULL; +} + +void +gdk_window_process_all_updates (void) +{ + GSList *old_update_windows = update_windows; + GSList *tmp_list = update_windows; + + if (update_idle) + g_source_remove (update_idle); + + update_windows = NULL; + update_idle = 0; + + while (tmp_list) + { + gdk_window_process_updates_internal (tmp_list->data); + tmp_list = tmp_list->next; + } + + g_slist_free (old_update_windows); + + gdk_flush(); +} + +static gboolean +gdk_window_update_idle (gpointer data) +{ + gdk_window_process_all_updates (); + + return FALSE; +} + +void +gdk_window_process_updates (GdkWindow *window, + gboolean update_children) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (private->update_area) + { + gdk_window_process_updates_internal (window); + update_windows = g_slist_remove (update_windows, window); + } + + if (update_children) + { + GList *tmp_list = private->children; + while (tmp_list) + { + gdk_window_process_updates (tmp_list->data, TRUE); + tmp_list = tmp_list->next; + } + } +} + +void +gdk_window_invalidate_rect (GdkWindow *window, + GdkRectangle *rect, + gboolean invalidate_children) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (private->update_area) + { + gdk_region_union_with_rect (private->update_area, rect); + } + else + { + update_windows = g_slist_prepend (update_windows, window); + private->update_area = gdk_region_rectangle (rect); + + if (!private->update_freeze_count && !update_idle) + update_idle = g_idle_add_full (GDK_PRIORITY_REDRAW, + gdk_window_update_idle, NULL, NULL); + } + + + if (invalidate_children) + { + GList *tmp_list; + GdkRectangle child_rect, new_rect; + + tmp_list = private->children; + while (tmp_list) + { + GdkWindowPrivate *child = tmp_list->data; + tmp_list = tmp_list->next; + + /* FIXME: this is a HACK to figure out if the child is + * input-only. + */ + if (child->drawable.colormap) + { + child_rect.x = child->x; + child_rect.y = child->y; + child_rect.width = child->drawable.width; + child_rect.height = child->drawable.height; + + if (gdk_rectangle_intersect (rect, &child_rect, &new_rect)) + { + new_rect.x -= child_rect.x; + new_rect.y -= child_rect.y; + + gdk_window_invalidate_rect ((GdkWindow *)child, &new_rect, TRUE); + } + } + } + } +} + +void +gdk_window_invalidate_region (GdkWindow *window, + GdkRegion *region, + gboolean invalidate_children) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (private->input_only) + return; + + if (private->update_area) + { + gdk_region_union (private->update_area, region); + } + else + { + update_windows = g_slist_prepend (update_windows, window); + private->update_area = gdk_region_copy (region); + + if (!private->update_freeze_count && !update_idle) + update_idle = g_idle_add_full (GDK_PRIORITY_REDRAW, + gdk_window_update_idle, NULL, NULL); + } + + if (invalidate_children) + { + GList *tmp_list; + GdkRectangle child_rect; + GdkRegion *child_region; + + tmp_list = private->children; + while (tmp_list) + { + GdkWindowPrivate *child = tmp_list->data; + tmp_list = tmp_list->next; + + if (child->input_only) + { + child_rect.x = child->x; + child_rect.y = child->y; + child_rect.width = child->drawable.width; + child_rect.height = child->drawable.height; + + child_region = gdk_region_rectangle (&child_rect); + gdk_region_intersect (child_region, region); + + if (!gdk_region_empty (child_region)) + { + gdk_region_offset (child_region, - child_rect.x, - child_rect.y); + gdk_window_invalidate_region ((GdkWindow *)child, child_region, TRUE); + } + + gdk_region_destroy (child_region); + } + } + } +} + +GdkRegion * +gdk_window_get_update_area (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + GdkRegion *tmp_region; + + g_return_val_if_fail (window != NULL, NULL); + g_return_val_if_fail (GDK_IS_WINDOW (window), NULL); + + if (private->update_area) + { + tmp_region = private->update_area; + private->update_area = NULL; + + update_windows = g_slist_remove (update_windows, window); + + return tmp_region; + } + else + return NULL; +} + +void +gdk_window_freeze_updates (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + private->update_freeze_count++; +} + +void +gdk_window_thaw_updates (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (private->update_freeze_count > 0); + + private->update_freeze_count--; + if (!private->update_freeze_count && private->update_area && !update_idle) + update_idle = g_idle_add_full (GDK_PRIORITY_REDRAW, + gdk_window_update_idle, NULL, NULL); +} + diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h index 47c09e9ef0..41087d2cc1 100644 --- a/gdk/gdkwindow.h +++ b/gdk/gdkwindow.h @@ -91,9 +91,9 @@ struct _GdkWindowAttr { gchar *title; gint event_mask; - gint16 x, y; - gint16 width; - gint16 height; + gint x, y; + gint width; + gint height; GdkWindowClass wclass; GdkVisual *visual; GdkColormap *colormap; @@ -230,6 +230,11 @@ void gdk_window_set_geometry_hints (GdkWindow *window, GdkWindowHints flags); void gdk_set_sm_client_id (const gchar *sm_client_id); +void gdk_window_begin_paint_rect (GdkWindow *window, + GdkRectangle *rectangle); +void gdk_window_begin_paint_region (GdkWindow *window, + GdkRegion *region); +void gdk_window_end_paint (GdkWindow *window); void gdk_window_set_title (GdkWindow *window, const gchar *title); @@ -268,9 +273,10 @@ GdkWindow* gdk_window_get_pointer (GdkWindow *window, gint *x, gint *y, GdkModifierType *mask); -GdkWindow* gdk_window_get_parent (GdkWindow *window); -GdkWindow* gdk_window_get_toplevel (GdkWindow *window); -GList* gdk_window_get_children (GdkWindow *window); +GdkWindow * gdk_window_get_parent (GdkWindow *window); +GdkWindow * gdk_window_get_toplevel (GdkWindow *window); + +GList * gdk_window_get_children (GdkWindow *window); GdkEventMask gdk_window_get_events (GdkWindow *window); void gdk_window_set_events (GdkWindow *window, GdkEventMask event_mask); @@ -291,6 +297,24 @@ GList * gdk_window_get_toplevels (void); void gdk_window_register_dnd (GdkWindow *window); +/* Interface for dirty-region queueing */ +void gdk_window_invalidate_rect (GdkWindow *window, + GdkRectangle *rect, + gboolean invalidate_children); +void gdk_window_invalidate_region (GdkWindow *window, + GdkRegion *region, + gboolean invalidate_children); +GdkRegion *gdk_window_get_update_area (GdkWindow *window); + +void gdk_window_freeze_updates (GdkWindow *window); +void gdk_window_thaw_updates (GdkWindow *window); + +void gdk_window_process_all_updates (void); +void gdk_window_process_updates (GdkWindow *window, + gboolean update_children); + + + #ifdef __cplusplus } #endif /* __cplusplus */ 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 #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; itype == 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; itype == 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; idepth == 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 if (dest_depth != 0 && src_depth == dest_depth) + { + XCopyArea (GDK_DRAWABLE_XDISPLAY (drawable), + GDK_DRAWABLE_XID (src), + GDK_DRAWABLE_XID (drawable), + GDK_GC_GET_XGC (gc), xsrc, ysrc, width, height, xdest, ydest); } else - { - XCopyArea (GDK_DRAWABLE_XDISPLAY (drawable), - GDK_DRAWABLE_XID (src), - GDK_DRAWABLE_XID (drawable), - GDK_GC_XGC (gc), - xsrc, ysrc, - width, height, - xdest, ydest); - } + 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; iwidth * 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 #include #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; iclip_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) - { - 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 = gdk_region_rectangle (rectangle); else - XSetClipMask (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), None); + { + data->clip_region = NULL; + 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) - { - GdkRegionPrivate *region_private; - - region_private = (GdkRegionPrivate*) region; - XSetRegion (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), region_private->xregion); - } + data->clip_region = gdk_region_copy (region); else - XSetClipMask (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), None); + { + data->clip_region = NULL; + 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 + * 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 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 #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 +#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 -#include - -#include #include -#include - -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 +#include "gdkregion-generic.h" + +#ifdef DEBUG +#include +#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 (y1rects); + 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].x1rects); \ + 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 (y1x1 < 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(y1x1x2); + 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(y1rects[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(x1x1); + 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(x1x2); + 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; inumRects; 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 @@ -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 +#include +#include + +#include +#include + +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__ */ diff --git a/gtk/.cvsignore b/gtk/.cvsignore index 14e0a2d723..af39208dbe 100644 --- a/gtk/.cvsignore +++ b/gtk/.cvsignore @@ -14,6 +14,7 @@ testtree gtkcompat.h testthreads libgtk.la +gtkfeatures.h gtkmarshal.h gtktypebuiltins.h gtkmarshal.c diff --git a/gtk/Makefile.am b/gtk/Makefile.am index adbd671998..50b77f76c3 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -288,6 +288,7 @@ gtk_built_sources = @STRIP_BEGIN@ \ @STRIP_END@ # built sources that get installed with the header files gtk_built_public_sources = @STRIP_BEGIN@ \ + gtkcompat.h \ gtkmarshal.h \ gtktypebuiltins.h \ @STRIP_END@ diff --git a/gtk/gtkaspectframe.c b/gtk/gtkaspectframe.c index 788399fb54..3d084b1c9c 100644 --- a/gtk/gtkaspectframe.c +++ b/gtk/gtkaspectframe.c @@ -238,9 +238,6 @@ gtk_aspect_frame_set (GtkAspectFrame *aspect_frame, aspect_frame->ratio = ratio; aspect_frame->obey_child = obey_child; - if (GTK_WIDGET_DRAWABLE(widget)) - gtk_widget_queue_clear (widget); - gtk_widget_queue_resize (widget); } } diff --git a/gtk/gtkbin.c b/gtk/gtkbin.c index bfb3dfadf3..d5100ba3a6 100644 --- a/gtk/gtkbin.c +++ b/gtk/gtkbin.c @@ -147,9 +147,7 @@ gtk_bin_unmap (GtkWidget *widget) GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); bin = GTK_BIN (widget); - if (GTK_WIDGET_NO_WINDOW (widget)) - gtk_widget_queue_clear (widget); - else + if (!GTK_WIDGET_NO_WINDOW (widget)) gdk_window_hide (widget->window); if (bin->child && GTK_WIDGET_MAPPED (bin->child)) diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c index 2e9367bb58..5e3fbd149e 100644 --- a/gtk/gtkcontainer.c +++ b/gtk/gtkcontainer.c @@ -847,8 +847,10 @@ gtk_container_idle_sizer (gpointer data) gtk_container_check_resize (GTK_CONTAINER (widget)); } + gdk_window_process_all_updates (); + GDK_THREADS_LEAVE (); - + return FALSE; } diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index 6cc62ad2e5..50db536b07 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -826,14 +826,25 @@ static void gtk_entry_draw (GtkWidget *widget, GdkRectangle *area) { + GtkEntry *entry; + g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_ENTRY (widget)); g_return_if_fail (area != NULL); + entry = GTK_ENTRY (widget); + if (GTK_WIDGET_DRAWABLE (widget)) { + GdkRectangle tmp_area = *area; + + tmp_area.x -= widget->style->klass->xthickness; + tmp_area.y -= widget->style->klass->xthickness; + + gdk_window_begin_paint_rect (entry->text_area, &tmp_area); gtk_widget_draw_focus (widget); gtk_entry_draw_text (GTK_ENTRY (widget)); + gdk_window_end_paint (entry->text_area); } } @@ -1295,7 +1306,6 @@ gtk_entry_draw_text (GtkEntry *entry) gint width, height; gint y; GdkDrawable *drawable; - gint use_backing_pixmap; GdkWChar *stars; GdkWChar *toprint; @@ -1327,25 +1337,10 @@ gtk_entry_draw_text (GtkEntry *entry) gdk_window_get_size (entry->text_area, &width, &height); - /* - If the widget has focus, draw on a backing pixmap to avoid flickering - and copy it to the text_area. - Otherwise draw to text_area directly for better speed. - */ - use_backing_pixmap = GTK_WIDGET_HAS_FOCUS (widget) && (entry->text != NULL); - if (use_backing_pixmap) - { - gtk_entry_make_backing_pixmap (entry, width, height); - drawable = entry->backing_pixmap; - } - else - { - drawable = entry->text_area; - } - gtk_paint_flat_box (widget->style, drawable, - GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE, - NULL, widget, "entry_bg", - 0, 0, width, height); + gtk_paint_flat_box (widget->style, entry->text_area, + GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE, + NULL, widget, "entry_bg", + 0, 0, width, height); y = (height - (widget->style->font->ascent + widget->style->font->descent)) / 2; y += widget->style->font->ascent; @@ -1388,7 +1383,7 @@ gtk_entry_draw_text (GtkEntry *entry) } if (selection_start_pos > start_pos) - gdk_draw_text_wc (drawable, widget->style->font, + gdk_draw_text_wc (entry->text_area, widget->style->font, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], INNER_BORDER + start_xoffset, y, toprint, @@ -1398,14 +1393,14 @@ gtk_entry_draw_text (GtkEntry *entry) (selection_start_pos < end_pos) && (selection_start_pos != selection_end_pos)) { - gtk_paint_flat_box (widget->style, drawable, + gtk_paint_flat_box (widget->style, entry->text_area, selected_state, GTK_SHADOW_NONE, NULL, widget, "text", INNER_BORDER + selection_start_xoffset, INNER_BORDER, selection_end_xoffset - selection_start_xoffset, height - 2*INNER_BORDER); - gdk_draw_text_wc (drawable, widget->style->font, + gdk_draw_text_wc (entry->text_area, widget->style->font, widget->style->fg_gc[selected_state], INNER_BORDER + selection_start_xoffset, y, toprint + selection_start_pos - start_pos, @@ -1413,7 +1408,7 @@ gtk_entry_draw_text (GtkEntry *entry) } if (selection_end_pos < end_pos) - gdk_draw_text_wc (drawable, widget->style->font, + gdk_draw_text_wc (entry->text_area, widget->style->font, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], INNER_BORDER + selection_end_xoffset, y, toprint + selection_end_pos - start_pos, @@ -1423,13 +1418,7 @@ gtk_entry_draw_text (GtkEntry *entry) g_free (toprint); if (editable->editable) - gtk_entry_draw_cursor_on_drawable (entry, drawable); - - if (use_backing_pixmap) - gdk_draw_pixmap(entry->text_area, - widget->style->fg_gc[GTK_STATE_NORMAL], - entry->backing_pixmap, - 0, 0, 0, 0, width, height); + gtk_entry_draw_cursor_on_drawable (entry, entry->text_area); } } @@ -1472,16 +1461,26 @@ gtk_entry_draw_cursor_on_drawable (GtkEntry *entry, GdkDrawable *drawable) } else { + int width, height; + GdkRectangle area; + gint yoffset = (text_area_height - (widget->style->font->ascent + widget->style->font->descent)) / 2 + widget->style->font->ascent; + area.x = xoffset; + area.y = INNER_BORDER; + area.width = 1; + area.height = text_area_height - INNER_BORDER; + + gdk_window_get_size (entry->text_area, &width, &height); + gtk_paint_flat_box (widget->style, drawable, GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE, - NULL, widget, "entry_bg", - xoffset, INNER_BORDER, - 1, text_area_height - INNER_BORDER); + &area, widget, "entry_bg", + 0, 0, width, height); + /* Draw the character under the cursor again */ diff --git a/gtk/gtkhscrollbar.c b/gtk/gtkhscrollbar.c index 64ac38d4cb..9ab5fa875d 100644 --- a/gtk/gtkhscrollbar.c +++ b/gtk/gtkhscrollbar.c @@ -289,9 +289,6 @@ gtk_hscrollbar_size_allocate (GtkWidget *widget, widget->style->klass->ythickness, RANGE_CLASS (widget)->stepper_size, widget->requisition.height - widget->style->klass->ythickness * 2); - gdk_window_resize (range->slider, - RANGE_CLASS (widget)->min_slider_size, - widget->requisition.height - widget->style->klass->ythickness * 2); gtk_range_slider_update (GTK_RANGE (widget)); } diff --git a/gtk/gtklayout.c b/gtk/gtklayout.c index bd21eead61..a57e52df1d 100644 --- a/gtk/gtklayout.c +++ b/gtk/gtklayout.c @@ -30,33 +30,18 @@ #include "gdkconfig.h" -#if defined (GDK_WINDOWING_X11) -#include "x11/gdkx.h" -#elif defined (GDK_WINDOWING_WIN32) -#include "win32/gdkwin32.h" -#endif - #include "gtklayout.h" #include "gtksignal.h" #include "gtkprivate.h" -typedef struct _GtkLayoutAdjData GtkLayoutAdjData; typedef struct _GtkLayoutChild GtkLayoutChild; -struct _GtkLayoutAdjData { - gint dx; - gint dy; -}; - struct _GtkLayoutChild { GtkWidget *widget; gint x; gint y; }; -#define IS_ONSCREEN(x,y) ((x >= G_MINSHORT) && (x <= G_MAXSHORT) && \ - (y >= G_MINSHORT) && (y <= G_MAXSHORT)) - static void gtk_layout_class_init (GtkLayoutClass *class); static void gtk_layout_init (GtkLayout *layout); @@ -83,33 +68,14 @@ static void gtk_layout_set_adjustments (GtkLayout *layout, GtkAdjustment *hadj, GtkAdjustment *vadj); -static void gtk_layout_position_child (GtkLayout *layout, - GtkLayoutChild *child); static void gtk_layout_allocate_child (GtkLayout *layout, GtkLayoutChild *child); -static void gtk_layout_position_children (GtkLayout *layout); - -static void gtk_layout_adjust_allocations_recurse (GtkWidget *widget, - gpointer cb_data); -static void gtk_layout_adjust_allocations (GtkLayout *layout, - gint dx, - gint dy); - -static void gtk_layout_expose_area (GtkLayout *layout, - gint x, - gint y, - gint width, - gint height); static void gtk_layout_adjustment_changed (GtkAdjustment *adjustment, GtkLayout *layout); -static GdkFilterReturn gtk_layout_main_filter (GdkXEvent *gdk_xevent, - GdkEvent *event, - gpointer data); static GtkWidgetClass *parent_class = NULL; -static gboolean gravity_works; /* Public interface */ @@ -261,9 +227,6 @@ gtk_layout_put (GtkLayout *layout, if (GTK_WIDGET_REALIZED (layout)) gtk_widget_set_parent_window (child->widget, layout->bin_window); - if (!IS_ONSCREEN (x, y)) - GTK_PRIVATE_SET_FLAG (child_widget, GTK_IS_OFFSCREEN); - if (GTK_WIDGET_REALIZED (layout)) gtk_widget_realize (child_widget); @@ -323,6 +286,9 @@ gtk_layout_set_size (GtkLayout *layout, layout->vadjustment->upper = layout->height; gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed"); + + if (GTK_WIDGET_REALIZED (layout)) + gdk_window_resize (layout->bin_window, width, height); } void @@ -342,10 +308,7 @@ gtk_layout_thaw (GtkLayout *layout) if (layout->freeze_count) if (!(--layout->freeze_count)) - { - gtk_layout_position_children (layout); - gtk_widget_draw (GTK_WIDGET (layout), NULL); - } + gtk_widget_draw (GTK_WIDGET (layout), NULL); } /* Basic Object handling procedures @@ -467,7 +430,9 @@ gtk_layout_realize (GtkWidget *widget) attributes.x = 0; attributes.y = 0; - attributes.event_mask = GDK_EXPOSURE_MASK | GDK_SCROLL_MASK | + attributes.width = layout->width; + attributes.height = layout->height; + attributes.event_mask = GDK_EXPOSURE_MASK | GDK_SCROLL_MASK | gtk_widget_get_events (widget); layout->bin_window = gdk_window_new (widget->window, @@ -478,15 +443,6 @@ gtk_layout_realize (GtkWidget *widget) gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); gtk_style_set_background (widget->style, layout->bin_window, GTK_STATE_NORMAL); - gdk_window_add_filter (widget->window, gtk_layout_main_filter, layout); - /* gdk_window_add_filter (layout->bin_window, gtk_layout_filter, layout);*/ - - /* XXX: If we ever get multiple displays for GTK+, then gravity_works - * will have to become a widget member. Right now we just - * keep it as a global - */ - gravity_works = gdk_window_set_static_gravities (layout->bin_window, TRUE); - tmp_list = layout->children; while (tmp_list) { @@ -595,7 +551,6 @@ gtk_layout_size_allocate (GtkWidget *widget, GtkLayoutChild *child = tmp_list->data; tmp_list = tmp_list->next; - gtk_layout_position_child (layout, child); gtk_layout_allocate_child (layout, child); } @@ -604,9 +559,6 @@ gtk_layout_size_allocate (GtkWidget *widget, gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height); - gdk_window_move_resize (GTK_LAYOUT(widget)->bin_window, - 0, 0, - allocation->width, allocation->height); } layout->hadjustment->page_size = allocation->width; @@ -748,38 +700,6 @@ gtk_layout_forall (GtkContainer *container, /* Operations on children */ -static void -gtk_layout_position_child (GtkLayout *layout, - GtkLayoutChild *child) -{ - gint x; - gint y; - - x = child->x - layout->xoffset; - y = child->y - layout->yoffset; - - if (IS_ONSCREEN (x,y)) - { - if (GTK_WIDGET_MAPPED (layout) && - GTK_WIDGET_VISIBLE (child->widget)) - { - if (!GTK_WIDGET_MAPPED (child->widget)) - gtk_widget_map (child->widget); - } - - if (GTK_WIDGET_IS_OFFSCREEN (child->widget)) - GTK_PRIVATE_UNSET_FLAG (child->widget, GTK_IS_OFFSCREEN); - } - else - { - if (!GTK_WIDGET_IS_OFFSCREEN (child->widget)) - GTK_PRIVATE_SET_FLAG (child->widget, GTK_IS_OFFSCREEN); - - if (GTK_WIDGET_MAPPED (child->widget)) - gtk_widget_unmap (child->widget); - } -} - static void gtk_layout_allocate_child (GtkLayout *layout, GtkLayoutChild *child) @@ -796,451 +716,25 @@ gtk_layout_allocate_child (GtkLayout *layout, gtk_widget_size_allocate (child->widget, &allocation); } -static void -gtk_layout_position_children (GtkLayout *layout) -{ - GList *tmp_list; - - tmp_list = layout->children; - while (tmp_list) - { - GtkLayoutChild *child = tmp_list->data; - tmp_list = tmp_list->next; - - gtk_layout_position_child (layout, child); - } -} - -static void -gtk_layout_adjust_allocations_recurse (GtkWidget *widget, - gpointer cb_data) -{ - GtkLayoutAdjData *data = cb_data; - - widget->allocation.x += data->dx; - widget->allocation.y += data->dy; - - if (GTK_WIDGET_NO_WINDOW (widget) && - GTK_IS_CONTAINER (widget)) - gtk_container_forall (GTK_CONTAINER (widget), - gtk_layout_adjust_allocations_recurse, - cb_data); -} - -static void -gtk_layout_adjust_allocations (GtkLayout *layout, - gint dx, - gint dy) -{ - GList *tmp_list; - GtkLayoutAdjData data; - - data.dx = dx; - data.dy = dy; - - tmp_list = layout->children; - while (tmp_list) - { - GtkLayoutChild *child = tmp_list->data; - tmp_list = tmp_list->next; - - child->widget->allocation.x += dx; - child->widget->allocation.y += dy; - - if (GTK_WIDGET_NO_WINDOW (child->widget) && - GTK_IS_CONTAINER (child->widget)) - gtk_container_forall (GTK_CONTAINER (child->widget), - gtk_layout_adjust_allocations_recurse, - &data); - } -} - /* Callbacks */ -/* Send a synthetic expose event to the widget - */ -static void -gtk_layout_expose_area (GtkLayout *layout, - gint x, gint y, gint width, gint height) -{ - if (layout->visibility == GDK_VISIBILITY_UNOBSCURED) - { - GdkEventExpose event; - - event.type = GDK_EXPOSE; - event.send_event = TRUE; - event.window = layout->bin_window; - event.count = 0; - - event.area.x = x; - event.area.y = y; - event.area.width = width; - event.area.height = height; - - gdk_window_ref (event.window); - gtk_widget_event (GTK_WIDGET (layout), (GdkEvent *)&event); - gdk_window_unref (event.window); - } -} - -#ifdef GDK_WINDOWING_X11 - -/* This function is used to find events to process while scrolling - */ - -static Bool -gtk_layout_expose_predicate (Display *display, - XEvent *xevent, - XPointer arg) -{ - if ((xevent->type == Expose) || - ((xevent->xany.window == *(Window *)arg) && - (xevent->type == ConfigureNotify))) - return True; - else - return False; -} - -#endif /* X11 */ - -/* This is the main routine to do the scrolling. Scrolling is - * done by "Guffaw" scrolling, as in the Mozilla XFE, with - * a few modifications. - * - * The main improvement is that we keep track of whether we - * are obscured or not. If not, we ignore the generated expose - * events and instead do the exposes ourself, without having - * to wait for a roundtrip to the server. This also provides - * a limited form of expose-event compression, since we do - * the affected area as one big chunk. - * - * Real expose event compression, as in the XFE, could be added - * here. It would help opaque drags over the region, and the - * obscured case. - * - * Code needs to be added here to do the scrolling on machines - * that don't have working WindowGravity. That could be done - * - * - XCopyArea and move the windows, and accept trailing the - * background color. (Since it is only a fallback method) - * - XmHTML style. As above, but turn off expose events when - * not obscured and do the exposures ourself. - * - gzilla-style. Move the window continuously, and reset - * every 32768 pixels - */ - static void gtk_layout_adjustment_changed (GtkAdjustment *adjustment, GtkLayout *layout) { GtkWidget *widget; -#ifdef GDK_WINDOWING_X11 - XEvent xevent; -#endif - gint dx, dy; widget = GTK_WIDGET (layout); - dx = (gint)layout->hadjustment->value - layout->xoffset; - dy = (gint)layout->vadjustment->value - layout->yoffset; - - layout->xoffset = (gint)layout->hadjustment->value; - layout->yoffset = (gint)layout->vadjustment->value; - if (layout->freeze_count) return; - if (!GTK_WIDGET_MAPPED (layout)) + if (GTK_WIDGET_REALIZED (layout)) { - gtk_layout_position_children (layout); - return; - } - - gtk_layout_adjust_allocations (layout, -dx, -dy); - - if (dx > 0) - { - if (gravity_works) - { - gdk_window_resize (layout->bin_window, - widget->allocation.width + dx, - widget->allocation.height); - gdk_window_move (layout->bin_window, -dx, 0); - gdk_window_move_resize (layout->bin_window, - 0, 0, - widget->allocation.width, - widget->allocation.height); - } - else - { - /* FIXME */ - } - - gtk_layout_expose_area (layout, - MAX ((gint)widget->allocation.width - dx, 0), - 0, - MIN (dx, widget->allocation.width), - widget->allocation.height); - } - else if (dx < 0) - { - if (gravity_works) - { - gdk_window_move_resize (layout->bin_window, - dx, 0, - widget->allocation.width - dx, - widget->allocation.height); - gdk_window_move (layout->bin_window, 0, 0); - gdk_window_resize (layout->bin_window, - widget->allocation.width, - widget->allocation.height); - } - else - { - /* FIXME */ - } - - gtk_layout_expose_area (layout, - 0, - 0, - MIN (-dx, widget->allocation.width), - widget->allocation.height); - } - - if (dy > 0) - { - if (gravity_works) - { - gdk_window_resize (layout->bin_window, - widget->allocation.width, - widget->allocation.height + dy); - gdk_window_move (layout->bin_window, 0, -dy); - gdk_window_move_resize (layout->bin_window, - 0, 0, - widget->allocation.width, - widget->allocation.height); - } - else - { - /* FIXME */ - } - - gtk_layout_expose_area (layout, - 0, - MAX ((gint)widget->allocation.height - dy, 0), - widget->allocation.width, - MIN (dy, widget->allocation.height)); - } - else if (dy < 0) - { - if (gravity_works) - { - gdk_window_move_resize (layout->bin_window, - 0, dy, - widget->allocation.width, - widget->allocation.height - dy); - gdk_window_move (layout->bin_window, 0, 0); - gdk_window_resize (layout->bin_window, - widget->allocation.width, - widget->allocation.height); - } - else - { - /* FIXME */ - } - gtk_layout_expose_area (layout, - 0, - 0, - widget->allocation.width, - MIN (-dy, (gint)widget->allocation.height)); - } - - gtk_layout_position_children (layout); - - /* We have to make sure that all exposes from this scroll get - * processed before we scroll again, or the expose events will - * have invalid coordinates. - * - * We also do expose events for other windows, since otherwise - * their updating will fall behind the scrolling - * - * This also avoids a problem in pre-1.0 GTK where filters don't - * have access to configure events that were compressed. - */ - - gdk_flush(); - -#ifdef GDK_WINDOWING_X11 - while (XCheckIfEvent(GDK_WINDOW_XDISPLAY (layout->bin_window), - &xevent, - gtk_layout_expose_predicate, - (XPointer)&GDK_WINDOW_XWINDOW (layout->bin_window))) - { - GdkEvent event; - GtkWidget *event_widget; - - switch (xevent.type) - { - case Expose: - - if (xevent.xany.window == GDK_WINDOW_XWINDOW (layout->bin_window)) - { - /* If the window is unobscured, then we've exposed the - * regions with the following serials already, so we - * can throw out the expose events. - */ - if (layout->visibility == GDK_VISIBILITY_UNOBSCURED && - (((dx > 0 || dy > 0) && - xevent.xexpose.serial == layout->configure_serial) || - ((dx < 0 || dy < 0) && - xevent.xexpose.serial == layout->configure_serial + 1))) - continue; - /* The following expose was generated while the origin was - * different from the current origin, so we need to offset it. - */ - else if (xevent.xexpose.serial == layout->configure_serial) - { - xevent.xexpose.x += layout->scroll_x; - xevent.xexpose.y += layout->scroll_y; - } - event.expose.window = layout->bin_window; - event_widget = widget; - } - else - { - event.expose.window = gdk_window_lookup (xevent.xany.window); - gdk_window_get_user_data (event.expose.window, - (gpointer *)&event_widget); - } - - if (event_widget) - { - event.expose.type = GDK_EXPOSE; - 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; - - gdk_window_ref (event.expose.window); - gtk_widget_event (event_widget, &event); - gdk_window_unref (event.expose.window); - } - break; - - case ConfigureNotify: - if (xevent.xany.window == GDK_WINDOW_XWINDOW (layout->bin_window) && - (xevent.xconfigure.x != 0 || xevent.xconfigure.y != 0)) - { - layout->configure_serial = xevent.xconfigure.serial; - layout->scroll_x = xevent.xconfigure.x; - layout->scroll_y = xevent.xconfigure.y; - } - break; - } - } -#elif defined (GDK_WINDOWING_WIN32) - /* XXX Not implemented */ -#endif -} - -#if 0 -/* The main event filter. Actually, we probably don't really need - * this filter at all, since we are calling it directly above in the - * expose-handling hack. But in case scrollbars - * are fixed up in some manner... - * - * This routine identifies expose events that are generated when - * we've temporarily moved the bin_window_origin, and translates - * them or discards them, depending on whether we are obscured - * or not. - */ -static GdkFilterReturn -gtk_layout_filter (GdkXEvent *gdk_xevent, - GdkEvent *event, - gpointer data) -{ -#ifdef GDK_WINDOWING_X11 - - XEvent *xevent; - GtkLayout *layout; - - xevent = (XEvent *)gdk_xevent; - layout = GTK_LAYOUT (data); - - switch (xevent->type) - { - case Expose: - if (xevent->xexpose.serial == layout->configure_serial) - { - if (layout->visibility == GDK_VISIBILITY_UNOBSCURED) - return GDK_FILTER_REMOVE; - else - { - xevent->xexpose.x += layout->scroll_x; - xevent->xexpose.y += layout->scroll_y; - - break; - } - } - break; + gdk_window_move (layout->bin_window, + - layout->hadjustment->value, + - layout->vadjustment->value); - case ConfigureNotify: - if ((xevent->xconfigure.x != 0) || (xevent->xconfigure.y != 0)) - { - layout->configure_serial = xevent->xconfigure.serial; - layout->scroll_x = xevent->xconfigure.x; - layout->scroll_y = xevent->xconfigure.y; - } - break; + gdk_window_process_updates (layout->bin_window, TRUE); } -#elif defined (GDK_WINDOWING_WIN32) - /* XXX Not implemented */ -#endif - - return GDK_FILTER_CONTINUE; } -#endif 0 - -/* Although GDK does have a GDK_VISIBILITY_NOTIFY event, - * there is no corresponding event in GTK, so we have - * to get the events from a filter - */ -static GdkFilterReturn -gtk_layout_main_filter (GdkXEvent *gdk_xevent, - GdkEvent *event, - gpointer data) -{ -#ifdef GDK_WINDOWING_X11 - XEvent *xevent; - GtkLayout *layout; - - xevent = (XEvent *)gdk_xevent; - layout = GTK_LAYOUT (data); - - if (xevent->type == VisibilityNotify) - { - switch (xevent->xvisibility.state) - { - case VisibilityFullyObscured: - layout->visibility = GDK_VISIBILITY_FULLY_OBSCURED; - break; - - case VisibilityPartiallyObscured: - layout->visibility = GDK_VISIBILITY_PARTIAL; - break; - - case VisibilityUnobscured: - layout->visibility = GDK_VISIBILITY_UNOBSCURED; - break; - } - - return GDK_FILTER_REMOVE; - } -#elif defined (GDK_WINDOWING_WIN32) - /* XXX Not implemented */ -#endif - - return GDK_FILTER_CONTINUE; -} - diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c index becef2c4c7..d80dfb24c3 100644 --- a/gtk/gtkmain.c +++ b/gtk/gtkmain.c @@ -742,8 +742,17 @@ gtk_main_do_event (GdkEvent *event) } break; - case GDK_PROPERTY_NOTIFY: case GDK_EXPOSE: + if (event->any.window) + gdk_window_begin_paint_rect (event->any.window, &event->expose.area); + + gtk_widget_event (event_widget, event); + + if (event->any.window) + gdk_window_end_paint (event->any.window); + break; + + case GDK_PROPERTY_NOTIFY: case GDK_NO_EXPOSE: case GDK_FOCUS_CHANGE: case GDK_CONFIGURE: diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c index 43c2836bc5..1805629111 100644 --- a/gtk/gtkrange.c +++ b/gtk/gtkrange.c @@ -810,23 +810,12 @@ gtk_range_expose (GtkWidget *widget, range = GTK_RANGE (widget); + /* We should really pass another argument - + *the redrawn area - to all the drawing functions) + */ if (event->window == range->trough) { - /* Don't redraw if we are only exposing the literal trough region. - * this may not work correctly if someone overrides the default - * trough-drawing handler. (Probably should really pass another - * argument - the redrawn area to all the drawing functions) - */ - gint xt = widget->style->klass->xthickness; - gint yt = widget->style->klass->ythickness; - - if (!((event->area.x >= xt) && - (event->area.y >= yt) && - (event->area.x + event->area.width <= - widget->allocation.width - xt) && - (event->area.y + event->area.height <= - widget->allocation.height - yt))) - gtk_range_draw_trough (range); + gtk_range_draw_trough (range); } else if (event->window == widget->window) { diff --git a/gtk/gtkviewport.c b/gtk/gtkviewport.c index afffdf01ad..f602e92247 100644 --- a/gtk/gtkviewport.c +++ b/gtk/gtkviewport.c @@ -822,9 +822,13 @@ gtk_viewport_adjustment_value_changed (GtkAdjustment *adjustment, child_allocation.y = viewport->vadjustment->lower - viewport->vadjustment->value; if (GTK_WIDGET_REALIZED (viewport)) - gdk_window_move (viewport->bin_window, - child_allocation.x, - child_allocation.y); + { + gdk_window_move (viewport->bin_window, + child_allocation.x, + child_allocation.y); + + gdk_window_process_updates (viewport->bin_window, TRUE); + } } } diff --git a/gtk/gtkvpaned.c b/gtk/gtkvpaned.c index 328f7587a1..698dda2f87 100644 --- a/gtk/gtkvpaned.c +++ b/gtk/gtkvpaned.c @@ -61,7 +61,7 @@ gtk_vpaned_get_type (void) (GtkClassInitFunc) NULL, }; - vpaned_type = gtk_type_unique(gtk_paned_get_type(), &vpaned_info); + vpaned_type = gtk_type_unique (GTK_TYPE_PANED, &vpaned_info); } return vpaned_type; diff --git a/gtk/gtkvscrollbar.c b/gtk/gtkvscrollbar.c index 867069147f..082fb746ba 100644 --- a/gtk/gtkvscrollbar.c +++ b/gtk/gtkvscrollbar.c @@ -289,9 +289,6 @@ gtk_vscrollbar_size_allocate (GtkWidget *widget, RANGE_CLASS (widget)->stepper_size, widget->requisition.width - widget->style->klass->xthickness * 2, RANGE_CLASS (widget)->stepper_size); - gdk_window_resize (range->slider, - widget->requisition.width - widget->style->klass->xthickness * 2, - RANGE_CLASS (range)->min_slider_size); gtk_range_slider_update (GTK_RANGE (widget)); } diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index dd844777d0..88d6d13e75 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -164,9 +164,6 @@ static void gtk_widget_style_set (GtkWidget *widget, GtkStyle *previous_style); static void gtk_widget_real_grab_focus (GtkWidget *focus_widget); -static void gtk_widget_redraw_queue_remove (GtkWidget *widget); - - static GdkColormap* gtk_widget_peek_colormap (void); static GdkVisual* gtk_widget_peek_visual (void); static GtkStyle* gtk_widget_peek_style (void); @@ -199,7 +196,6 @@ static GSList *colormap_stack = NULL; static GSList *visual_stack = NULL; static GSList *style_stack = NULL; static guint composite_child_stack = 0; -static GSList *gtk_widget_redraw_queue = NULL; static const gchar *aux_info_key = "gtk-aux-info"; static guint aux_info_key_id = 0; @@ -1297,9 +1293,6 @@ gtk_widget_unparent (GtkWidget *widget) gtk_window_set_default (GTK_WINDOW (toplevel), NULL); } - if (GTK_WIDGET_REDRAW_PENDING (widget)) - gtk_widget_redraw_queue_remove (widget); - if (GTK_IS_RESIZE_CONTAINER (widget)) gtk_container_clear_resize_widgets (GTK_CONTAINER (widget)); @@ -1697,9 +1690,6 @@ gtk_widget_unrealize (GtkWidget *widget) g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_WIDGET (widget)); - if (GTK_WIDGET_REDRAW_PENDING (widget)) - gtk_widget_redraw_queue_remove (widget); - if (GTK_WIDGET_HAS_SHAPE_MASK (widget)) gtk_widget_shape_combine_mask (widget, NULL, -1, -1); @@ -1713,124 +1703,20 @@ gtk_widget_unrealize (GtkWidget *widget) } /***************************************** - * gtk_widget_queue_draw: - * - * arguments: - * - * results: + * Draw queueing. *****************************************/ -typedef struct _GtkDrawData GtkDrawData; -struct _GtkDrawData { - GdkRectangle rect; - GdkWindow *window; -}; - -static GMemChunk *draw_data_mem_chunk = NULL; -static GSList *draw_data_free_list = NULL; -static const gchar *draw_data_key = "gtk-draw-data"; -static GQuark draw_data_key_id = 0; -static const gchar *draw_data_tmp_key = "gtk-draw-data-tmp"; -static GQuark draw_data_tmp_key_id = 0; - -static gint gtk_widget_idle_draw (gpointer data); - -static void -gtk_widget_queue_draw_data (GtkWidget *widget, - gint x, - gint y, - gint width, - gint height, - GdkWindow *window) -{ - GSList *node; - GtkDrawData *data; - - g_return_if_fail (widget != NULL); - g_return_if_fail (!(width < 0 || height < 0) || window == NULL); - - if ((width != 0) && (height != 0) && GTK_WIDGET_DRAWABLE (widget)) - { - if (!draw_data_key_id) - draw_data_key_id = g_quark_from_static_string (draw_data_key); - - if (draw_data_free_list) - { - node = draw_data_free_list; - data = node->data; - draw_data_free_list = draw_data_free_list->next; - } - else - { - if (!draw_data_mem_chunk) - draw_data_mem_chunk = g_mem_chunk_create (GtkDrawData, 64, - G_ALLOC_ONLY); - data = g_chunk_new (GtkDrawData, draw_data_mem_chunk); - node = g_slist_alloc(); - node->data = data; - } - - data->rect.x = x; - data->rect.y = y; - - if ((width < 1 && height < 1) || - (width >= widget->allocation.width && - height >= widget->allocation.height)) - GTK_PRIVATE_SET_FLAG (widget, GTK_FULLDRAW_PENDING); - - if ((width < 0) || (height < 0)) - { - data->rect.width = 0; - data->rect.height = 0; - } - else - { - data->rect.width = width; - data->rect.height = height; - } - data->window = window; - - if ((width < 0) || (height < 0)) - { - GSList *draw_data_list = - gtk_object_get_data_by_id (GTK_OBJECT (widget), - draw_data_key_id); - if (draw_data_list) - draw_data_free_list = g_slist_concat (draw_data_list, - draw_data_free_list); - node->next = NULL; - } - else - node->next = gtk_object_get_data_by_id (GTK_OBJECT (widget), - draw_data_key_id); - - if (!GTK_WIDGET_REDRAW_PENDING (widget)) - { - GTK_PRIVATE_SET_FLAG (widget, GTK_REDRAW_PENDING); - if (gtk_widget_redraw_queue == NULL) - gtk_idle_add_priority (GTK_PRIORITY_REDRAW, - gtk_widget_idle_draw, - NULL); - gtk_widget_redraw_queue = g_slist_prepend (gtk_widget_redraw_queue, widget); - } - - gtk_object_set_data_by_id (GTK_OBJECT (widget), draw_data_key_id, node); - } -} - void gtk_widget_queue_draw_area (GtkWidget *widget, gint x, gint y, gint width, - gint height) + gint height) { g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_WIDGET (widget)); - if (widget->window && gdk_window_is_viewable (widget->window) && - !gtk_widget_is_offscreen (widget)) - gtk_widget_queue_draw_data (widget, x, y, width, height, NULL); + gtk_widget_queue_clear_area (widget, x, y, width, height); } void @@ -1839,11 +1725,12 @@ gtk_widget_queue_draw (GtkWidget *widget) g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_WIDGET (widget)); - if (widget->window && gdk_window_is_viewable (widget->window) && - !gtk_widget_is_offscreen (widget)) - gtk_widget_queue_draw_data (widget, 0, 0, -1, -1, NULL); + gtk_widget_queue_clear (widget); } +/* Invalidates the given area (allocation-relative-coordinates) + * in all of the widget's windows + */ void gtk_widget_queue_clear_area (GtkWidget *widget, gint x, @@ -1851,7 +1738,7 @@ gtk_widget_queue_clear_area (GtkWidget *widget, gint width, gint height) { - GtkWidget *parent; + GdkRectangle invalid_rect; g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_WIDGET (widget)); @@ -1888,8 +1775,9 @@ gtk_widget_queue_clear_area (GtkWidget *widget, { if (widget->parent) { - gint wx, wy, wwidth, wheight; /* Translate widget relative to window-relative */ + + gint wx, wy, wwidth, wheight; gdk_window_get_position (widget->window, &wx, &wy); x -= wx - widget->allocation.x; @@ -1914,36 +1802,14 @@ gtk_widget_queue_clear_area (GtkWidget *widget, if (y + height > wheight) height = wheight - y; } - - gtk_widget_queue_draw_data (widget, x, y, width, height, widget->window); - } -} - -static void -gtk_widget_redraw_queue_remove (GtkWidget *widget) -{ - GSList *draw_data_list; - GSList *tmp_list; - - g_return_if_fail (GTK_WIDGET_REDRAW_PENDING (widget)); - - gtk_widget_redraw_queue = g_slist_remove (gtk_widget_redraw_queue, widget); - - draw_data_list = gtk_object_get_data_by_id (GTK_OBJECT (widget), - draw_data_key_id); - tmp_list = g_slist_last (draw_data_list); - if (tmp_list) - { - tmp_list->next = draw_data_free_list; - draw_data_free_list = draw_data_list; } - gtk_object_set_data_by_id (GTK_OBJECT (widget), - draw_data_key_id, - NULL); + invalid_rect.x = x; + invalid_rect.y = y; + invalid_rect.width = width; + invalid_rect.height = height; - GTK_PRIVATE_UNSET_FLAG (widget, GTK_REDRAW_PENDING); - GTK_PRIVATE_UNSET_FLAG (widget, GTK_FULLDRAW_PENDING); + gdk_window_invalidate_rect (widget->window, &invalid_rect, TRUE); } void @@ -1966,324 +1832,6 @@ gtk_widget_queue_clear (GtkWidget *widget) } } -static gint -gtk_widget_draw_data_combine (GtkDrawData *parent, GtkDrawData *child) -{ - gint parent_x2, parent_y2; - gint child_x2, child_y2; - - /* Check for intersection */ - - parent_x2 = parent->rect.x + parent->rect.width; - child_x2 = child->rect.x + child->rect.width; - parent_y2 = parent->rect.y + parent->rect.height; - child_y2 = child->rect.y + child->rect.height; - - if ((child->rect.x > parent_x2) || (parent->rect.x > child_x2) || - (child->rect.y > parent_y2) || (parent->rect.y > child_y2)) - return FALSE; - else - { - parent->rect.x = MIN (parent->rect.x, child->rect.x); - parent->rect.y = MIN (parent->rect.y, child->rect.y); - parent->rect.width = MAX (parent_x2, child_x2) - parent->rect.x; - parent->rect.height = MAX (parent_y2, child_y2) - parent->rect.y; - } - - return TRUE; -} - -/* Take a rectangle with respect to window, and translate it - * to coordinates relative to widget's allocation, clipping through - * intermediate windows. Returns whether translation failed. If the - * translation failed, we have something like a handlebox, where - * the child widget's GdkWindow is not a child of the parents GdkWindow. - */ -static gboolean -gtk_widget_clip_rect (GtkWidget *widget, - GdkWindow *window, - GdkRectangle *rect, - gint *x_offset, - gint *y_offset) -{ - gint x,y, width, height; - - while (window && (window != widget->window)) - { - gdk_window_get_position (window, &x, &y); - rect->x += x; - if (x_offset) - *x_offset += x; - rect->y += y; - if (y_offset) - *y_offset += y; - - window = gdk_window_get_parent (window); - if (!window) - return FALSE; - - gdk_window_get_size (window, &width, &height); - - if (rect->x < 0) - { - rect->width = (rect->width > -rect->x) ? rect->width + rect->x : 0; - rect->x = 0; - } - if (rect->y < 0) - { - rect->height = (rect->height > -rect->y) ? rect->width + rect->y : 0; - rect->y = 0; - } - if (rect->x + rect->width > width) - rect->width = (width > rect->x) ? width - rect->x : 0; - if (rect->y + rect->height > height) - rect->height = (height > rect->y) ? height - rect->y : 0; - } - - if (!window) - return FALSE; - - if (!GTK_WIDGET_NO_WINDOW (widget)) - { - if (gdk_window_get_toplevel (window) != window) - { - gdk_window_get_position (window, &x, &y); - rect->x += x - widget->allocation.x; - if (x_offset) - *x_offset += x - widget->allocation.x; - rect->y += y - widget->allocation.y; - if (y_offset) - *y_offset += y - widget->allocation.y; - } - } - - return TRUE; -} - -static gint -gtk_widget_idle_draw (gpointer cb_data) -{ - GSList *widget_list; - GSList *old_queue; - GSList *draw_data_list; - GtkWidget *widget; - - if (!draw_data_tmp_key_id) - draw_data_tmp_key_id = g_quark_from_static_string (draw_data_tmp_key); - - GDK_THREADS_ENTER (); - - old_queue = gtk_widget_redraw_queue; - gtk_widget_redraw_queue = NULL; - - /* Translate all draw requests to be allocation-relative. - * At the same time, move all the data out of the way, - * so when we get down to the draw step, we can queue - * more information for "next time", if the application - * is that foolhardy. - */ - widget_list = old_queue; - - while (widget_list) - { - widget = widget_list->data; - draw_data_list = gtk_object_get_data_by_id (GTK_OBJECT (widget), - draw_data_key_id); - gtk_object_set_data_by_id (GTK_OBJECT (widget), - draw_data_key_id, - NULL); - gtk_object_set_data_by_id (GTK_OBJECT (widget), - draw_data_tmp_key_id, - draw_data_list); - - /* XXX: Since we are unsetting this flag here, further - * down the only way we can check if a redraw is queued - * on a given widget is by calling gtk_object_get_data. - * for speed purposes we might well want a private - * flag GTK_REDRAW_PROCESSING or something. - */ - GTK_PRIVATE_UNSET_FLAG (widget, GTK_REDRAW_PENDING); - GTK_PRIVATE_UNSET_FLAG (widget, GTK_FULLDRAW_PENDING); - - while (draw_data_list) - { - gboolean full_allocation = FALSE; - GtkDrawData *data = draw_data_list->data; - - if (data->window) - { - /* If the translation fails, we have a handlebox, - * so redraw the whole widget. Could be done better? - */ - full_allocation = !gtk_widget_clip_rect (widget, - data->window, - &data->rect, - NULL, NULL); - data->window = NULL; - } - else if ((data->rect.width == 0) && (data->rect.height == 0)) - full_allocation = TRUE; - - if (full_allocation) - { - if (GTK_WIDGET_NO_WINDOW (widget)) - { - data->rect.x = widget->allocation.x; - data->rect.y = widget->allocation.y; - } - else - { - data->rect.x = 0; - data->rect.y = 0; - } - data->rect.width = widget->allocation.width; - data->rect.height = widget->allocation.height; - } - - draw_data_list = draw_data_list->next; - } - - widget_list = widget_list->next; - } - - /* Coalesce redraws. - */ - widget_list = old_queue; - while (widget_list) - { - GSList *prev_node = NULL; - widget = widget_list->data; - draw_data_list = gtk_object_get_data_by_id (GTK_OBJECT (widget), - draw_data_tmp_key_id); - - while (draw_data_list) - { - gint x_offset, y_offset; - GtkDrawData *data = draw_data_list->data; - GSList *parent_list = draw_data_list->next; - GtkWidget *parent; - GdkWindow *window; - - x_offset = 0; - y_offset = 0; - - parent = widget; - while (parent) - { - while (parent_list) - { - if (gtk_widget_draw_data_combine (parent_list->data, data)) - { - GSList *tmp; - if (prev_node) - prev_node->next = draw_data_list->next; - else - gtk_object_set_data_by_id (GTK_OBJECT (widget), - draw_data_tmp_key_id, - draw_data_list->next); - - tmp = draw_data_list->next; - draw_data_list->next = draw_data_free_list; - draw_data_free_list = draw_data_list; - draw_data_list = tmp; - - goto next_rect; - } - - parent_list = parent_list->next; - } - - window = parent->window; - - if (parent->parent && parent->parent->window != window) - { - if (!GTK_WIDGET_NO_WINDOW (parent)) - { - gint x, y; - gdk_window_get_position (window, &x, &y); - data->rect.x -= x - parent->allocation.x; - x_offset -= x - parent->allocation.x; - data->rect.y -= y - parent->allocation.y; - y_offset -= y - parent->allocation.y; - } - /* If we can't translate the rectangle, stop trying to - * merge. (This occurs for a handlebox) - */ - if (!gtk_widget_clip_rect (parent->parent, window, &data->rect, - &x_offset, &y_offset)) - parent = NULL; - } - - if (parent) - parent = parent->parent; - - if (parent) - parent_list = gtk_object_get_data_by_id (GTK_OBJECT (parent), - draw_data_tmp_key_id); - else - parent_list = NULL; - } - - /* OK, this rectangle stays around. But take advantage - * of the work we've done to clip it to the visible area - - * rect.width/height have already been appropriately - * decreased - */ - data->rect.x -= x_offset; - data->rect.y -= y_offset; - - - prev_node = draw_data_list; - - draw_data_list = draw_data_list->next; - next_rect: - continue; - } - widget_list = widget_list->next; - } - - /* Process the draws */ - - widget_list = old_queue; - - while (widget_list) - { - GSList *tmp_list; - - widget = widget_list->data; - draw_data_list = gtk_object_get_data_by_id (GTK_OBJECT (widget), - draw_data_tmp_key_id); - gtk_object_set_data_by_id (GTK_OBJECT (widget), - draw_data_tmp_key_id, - NULL); - - tmp_list = draw_data_list; - while (tmp_list) - { - GtkDrawData *data = tmp_list->data; - if ((data->rect.width != 0) && (data->rect.height != 0)) - gtk_widget_draw (widget, &data->rect); - - if (tmp_list->next) - tmp_list = tmp_list->next; - else - { - tmp_list->next = draw_data_free_list; - draw_data_free_list = draw_data_list; - break; - } - } - - widget_list = widget_list->next; - } - - g_slist_free (old_queue); - - GDK_THREADS_LEAVE (); - - return FALSE; -} - void gtk_widget_queue_resize (GtkWidget *widget) { @@ -2338,7 +1886,25 @@ gtk_widget_draw (GtkWidget *widget, area = &temp_area; } + if (!GTK_WIDGET_NO_WINDOW (widget)) + { + GdkRectangle tmp_area = *area; + gint x, y; + + if (!GTK_WIDGET_TOPLEVEL (widget)) + { + gdk_window_get_position (widget->window, &x, &y); + tmp_area.x -= x - widget->allocation.x; + tmp_area.y -= y - widget->allocation.y; + } + + gdk_window_begin_paint_rect (widget->window, &tmp_area); + } + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[DRAW], area); + + if (!GTK_WIDGET_NO_WINDOW (widget)) + gdk_window_end_paint (widget->window); } } @@ -2469,14 +2035,13 @@ gtk_widget_size_allocate (GtkWidget *widget, real_allocation.width = MAX (real_allocation.width, 1); real_allocation.height = MAX (real_allocation.height, 1); - if (real_allocation.width > 32767 || - real_allocation.height > 32767) + if (real_allocation.width < 0 || real_allocation.height < 0) { g_warning ("gtk_widget_size_allocate(): attempt to allocate widget with width %d and height %d", real_allocation.width, real_allocation.height); - real_allocation.width = MIN (real_allocation.width, 32767); - real_allocation.height = MIN (real_allocation.height, 32767); + real_allocation.width = 1; + real_allocation.height = 1; } if (GTK_WIDGET_NO_WINDOW (widget)) @@ -2727,7 +2292,7 @@ gint gtk_widget_event (GtkWidget *widget, GdkEvent *event) { - gint return_val; + gboolean return_val; gint signal_num; g_return_val_if_fail (widget != NULL, TRUE); @@ -2738,14 +2303,10 @@ gtk_widget_event (GtkWidget *widget, gtk_signal_emit (GTK_OBJECT (widget), widget_signals[EVENT], event, &return_val); if (return_val || GTK_OBJECT_DESTROYED (widget)) - { - gtk_widget_unref (widget); - return TRUE; - } + goto out; switch (event->type) { - GtkWidget *parent; case GDK_NOTHING: signal_num = -1; break; @@ -2821,42 +2382,9 @@ gtk_widget_event (GtkWidget *widget, signal_num = CLIENT_EVENT; break; case GDK_EXPOSE: - /* there is no sense in providing a widget with bogus expose events. - * also we make the optimization to discard expose events for widgets - * that have a full redraw pending (given that the event is !send_event, - * otherwise we assume we can trust the event). - */ - if (event->any.send_event) - parent = NULL; - else if (event->any.window) - { - parent = widget; - while (parent) - { - if (GTK_WIDGET_FULLDRAW_PENDING (parent)) - break; - parent = parent->parent; - } - /* gnome-dock didn't propagate draws to torn off - * children. So don't consider those ancestors. - */ - if (parent) - { - GdkWindow *parent_window = event->any.window; + if (!event->any.window) /* Why is this necessary */ + goto out; - while (parent_window && parent_window != parent->window) - parent_window = gdk_window_get_parent (parent_window); - - if (!parent_window) - parent = NULL; - } - /* */ - } - if (!event->any.window || parent) - { - gtk_widget_unref (widget); - return TRUE; - } signal_num = EXPOSE_EVENT; break; case GDK_VISIBILITY_NOTIFY: @@ -2864,8 +2392,7 @@ gtk_widget_event (GtkWidget *widget, break; default: g_warning ("could not determine signal number for event: %d", event->type); - gtk_widget_unref (widget); - return TRUE; + goto out; } if (signal_num != -1) @@ -2873,6 +2400,7 @@ gtk_widget_event (GtkWidget *widget, return_val |= GTK_OBJECT_DESTROYED (widget); + out: gtk_widget_unref (widget); return return_val; @@ -3056,7 +2584,7 @@ gtk_widget_intersect (GtkWidget *widget, else dest = &tmp; - return_val = gdk_rectangle_intersect ((GdkRectangle*) &widget->allocation, area, dest); + return_val = gdk_rectangle_intersect (&widget->allocation, area, dest); if (return_val && intersection && !GTK_WIDGET_NO_WINDOW (widget)) { diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h index 15e3c628e2..66568b4228 100644 --- a/gtk/gtkwidget.h +++ b/gtk/gtkwidget.h @@ -110,7 +110,7 @@ typedef enum typedef struct _GtkRequisition GtkRequisition; -typedef struct _GtkAllocation GtkAllocation; +typedef struct _GdkRectangle GtkAllocation; typedef struct _GtkSelectionData GtkSelectionData; typedef struct _GtkWidgetClass GtkWidgetClass; typedef struct _GtkWidgetAuxInfo GtkWidgetAuxInfo; @@ -124,20 +124,8 @@ typedef void (*GtkCallback) (GtkWidget *widget, */ struct _GtkRequisition { - gint16 width; - gint16 height; -}; - -/* An allocation is a size and position. Where a widget - * can ask for a desired size, it is actually given - * this amount of space at the specified position. - */ -struct _GtkAllocation -{ - gint16 x; - gint16 y; - guint16 width; - guint16 height; + gint width; + gint height; }; /* The contents of a selection are returned in a GtkSelectionData