Getting backing pixmap



Anders Carlsson pointed out to me (http://bugzilla.gnome.org/show_bug.cgi?id=57212)
that there is currently no way of drawing onto a GdkWindow with X functions directly,
since the backing pixmap is hidden inside private structures.

I think this is a fairly serious defect, so I'd like to apply the
following patch which adds a somewhat clumsy, but workable, way to get
the necessary information:

With this patch, an X only emulation of gdk_draw_line() would be something like:

void
my_draw_line (GdkDrawable *drawable, GdkGC *gc,
              gint x1, gint y1, gint x2, gint y2)
{
  GdkDrawable *real_drawable;
    
  gint x_off, y_off;

  if (GDK_IS_WINDOW (drawable))
    {
      gdk_window_get_internal_paint_info (drawable, &real_drawable, &x_off, &y_off);
    }
  else if (GDK_IS_PIXMAP (drawable))
    {
      real_drawable = drawable;
      x_off = y_off = 0;
    }
  else
    {
      g_warning ("my_draw_line() called on non-X drawable");
      return;
    }
  
  gdk_gc_offset (gc, x_off, y_off);

  XDrawLine (GDK_DRAWABLE_XDISPLAY (real_drawable),
	     GDK_DRAWABLE_XID (real_drawable),
	     GDK_GC_XGC (gc),
	     x1 - x_off, y1 - y_off, x2 - x_off, y2 - y_off);

  gdk_gc_offset (gc, -x_off, -y_off);
}

The use of GDK_IS_WINDOW() could be eliminated by making this a virtualized
operation on GdkDrawable, but I avoided doing this on the principle
of keeping hacks localized.

This change does not affect either source or binary compatibility. 

Regards,
                                        Owen

Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gtk+/ChangeLog,v
retrieving revision 1.2120
diff -u -r1.2120 ChangeLog
--- ChangeLog	2001/07/12 22:45:03	1.2120
+++ ChangeLog	2001/07/13 19:40:03
@@ -1,3 +1,13 @@
+Fri Jul 13 15:33:32 2001  Owen Taylor  <otaylor redhat com>
+
+	* gdk/gdkwindow.[ch]: Add a function gdk_window_get_internal_paint_info(),
+	so that using X functions on a GdkWindow is possible, if
+	a little hairy.
+
+	* gdk/gdkgc.c (gdk_gc_offset): Add a function to offset the clip
+	and ts_origin of a GC, so that external parties can offset/restore
+	a GC, when using gdk_window_get_internal_paint_info().
+
 Thu Jul 12 18:29:40 2001  Owen Taylor  <otaylor redhat com>
 
 	* gtk/gtkradiomenuitem.[ch] (gtk_radio_menu_item_group): 
Index: gdk/gdkgc.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkgc.c,v
retrieving revision 1.32
diff -u -r1.32 gdkgc.c
--- gdk/gdkgc.c	2001/02/20 05:21:44	1.32
+++ gdk/gdkgc.c	2001/07/13 19:40:03
@@ -367,6 +367,35 @@
 }
 
 /**
+ * gdk_gc_offset:
+ * @gc: a #GdkGC
+ * @x_offset: amount by which to offset the GC in the X direction
+ * @y_offset: amount by which to offset the GC in the Y direction
+ * 
+ * Offset attributes such as the clip and tile-stipple origins
+ * of the GC so that drawing at x - x_offset, y - y_offset with
+ * the offset GC  has the same effect as drawing at x, y with the original
+ * GC.
+ **/
+void
+gdk_gc_offset (GdkGC *gc,
+	       gint   x_offset,
+	       gint   y_offset)
+{
+  if (x_offset != 0 || y_offset != 0)
+    {
+      gint clip_x_origin, clip_y_origin;
+      gint ts_x_origin, ts_y_origin;
+      
+      gdk_gc_get_clip_offset (gc, &clip_x_origin, &clip_y_origin);
+      gdk_gc_get_ts_offset (gc, &ts_x_origin, &ts_y_origin);
+      
+      gdk_gc_set_clip_offset (gc, clip_x_origin - x_offset, clip_y_origin - y_offset);
+      gdk_gc_set_ts_offset (gc, ts_x_origin - x_offset, _y_origin - y_offset);
+    }
+}
+
+/**
  * gdk_gc_set_colormap:
  * @gc: a #GdkGC
  * @colormap: a #GdkColormap
Index: gdk/gdkgc.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkgc.h,v
retrieving revision 1.7
diff -u -r1.7 gdkgc.h
--- gdk/gdkgc.h	2000/08/30 00:33:35	1.7
+++ gdk/gdkgc.h	2001/07/13 19:40:03
@@ -237,6 +237,9 @@
 				   gint	             dash_offset,
 				   gint8             dash_list[],
 				   gint              n);
+void   gdk_gc_offset              (GdkGC            *gc,
+				   gint              x_offset,
+				   gint              y_offset);
 void   gdk_gc_copy		  (GdkGC	    *dst_gc,
 				   GdkGC	    *src_gc);
 
Index: gdk/gdkwindow.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkwindow.c,v
retrieving revision 1.119
diff -u -r1.119 gdkwindow.c
--- gdk/gdkwindow.c	2001/07/05 13:41:33	1.119
+++ gdk/gdkwindow.c	2001/07/13 19:40:03
@@ -979,6 +979,59 @@
     _gdk_windowing_window_get_offsets (window, x_offset, y_offset);
 }
 
+/**
+ * gdk_window_get_internal_paint_info:
+ * @window: a #GdkWindow
+ * @real_drawable: location to store the drawable to which drawing should be done.
+ * @x_offset: location to store the X offset between coordinates in @window, and
+ *            the underlying window system primitive coordinates for * real_drawable 
+ * @y_offset: location to store the Y offset between coordinates in @window, and
+ *            the underlying window system primitive coordinates for * real_drawable 
+ * 
+ * If you bypass the GDK layer and use windowing system primitives to
+ * draw directly onto a #GdkWindow, then you need to deal with two
+ * details: there may be an offset between GDK coordinates and windowing
+ * system coordinates, and GDK may have redirected drawing to a offscreen
+ * pixmap as the result of a gdk_window_begin_paint_region() calls.
+ * This function allows retrieving the information you need to compensate
+ * for these effects.
+ *
+ * This function exposes details of the GDK implementation, and is thus
+ * likely to change in future releases of GDK.
+ **/
+void
+gdk_window_get_internal_paint_info (GdkWindow    *window,
+				    GdkDrawable **real_drawable,
+				    gint         *x_offset,
+				    gint         *y_offset)
+{
+  gint x_off, y_off;
+  
+  GdkWindowObject *private;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *)window;
+
+  if (real_drawable)
+    {
+      if (private->paint_stack)
+	{
+	  GdkWindowPaint *paint = private->paint_stack->data;
+	  *real_drawable = paint->pixmap;
+	}
+      else
+	*real_drawable = window;
+    }
+
+  gdk_window_get_offsets (window, &x_off, &y_off);
+
+  if (x_offset)
+    *x_offset = x_off;
+  if (y_offset)
+    *y_offset = y_off;
+}
+
 #define OFFSET_GC(gc)                                         \
     gint x_offset, y_offset; 				      \
     gint old_clip_x = gc->clip_x_origin;    \
Index: gdk/gdkwindow.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkwindow.h,v
retrieving revision 1.26
diff -u -r1.26 gdkwindow.h
--- gdk/gdkwindow.h	2001/07/05 13:41:33	1.26
+++ gdk/gdkwindow.h	2001/07/13 19:40:03
@@ -507,6 +507,11 @@
                                            gint         *new_width,
                                            gint         *new_height);
 
+void gdk_window_get_internal_paint_info (GdkWindow    *window,
+					 GdkDrawable **real_drawable,
+					 gint         *x_offset,
+					 gint         *y_offset);
+
 GdkPointerHooks *gdk_set_pointer_hooks (const GdkPointerHooks *new_hooks);   
 
 #ifdef __cplusplus




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]