Re: cairo drawing commands to gdk_invalidate_region

2010-08-18 Thread Paul Davis
On Tue, Aug 17, 2010 at 4:22 PM, Dov Grobgeld dov.grobg...@gmail.com wrote:

 The solution won't work if the default expose-event handler returns TRUE.
 I would still like to resolve the issues that Paul has with my description
 of the code. Paul, why don't you like the fact that I call draw() twice?

that's overstating it a little bit. what i was taking issue with is
that *unless* draw() has some way to be able to tell that it is being
called from an expose event handler (and that would presumably have to
be some global variable, since nothing is passed to it as an
argument), it is by definition doing the wrong thing *if* it is
responsible for all the rendering that occurs in the expose handler.
why? because that would imply that it actually renders in both the
pre-expose call and the expose-event call, but you should only be
rendering (to the window at list) in the expose event call.

you asked:  How is update() supposed to know what region to invalidate?

in your original description, you showed the flow as:

# motion event calls update()
# update() calls draw() in order to get regions to expose.
# update() calls gdk_invalidate_region() based on output from draw
# exposure-event callback calls draw() to carry out the drawing
for each region

so you have logic that knows what regions are affected by the motion
event (the above description makes it sound as if that logic is inside
draw()). update should have that logic so that it can call
gdk_invalidate_region(), and then the expose-event call to draw()
should use the event region list to redraw.

if your code works, that's fine. i'm just trying to describe to you
what i *think* is the right way to do this so that its portable to all
backends of GTK and is following the overall drawing model embedded in
GTK.

--p
___
gtk-devel-list mailing list
gtk-devel-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-devel-list


Re: cairo drawing commands to gdk_invalidate_region

2010-08-18 Thread Dov Grobgeld
The problem of deciding what areas to expose are imho opinion too hard for
the motion handler to deal with. E.g. if the rubberband is e.g. of an
ellipse outline then you need quite a bit of mathematics to figure out what
areas to expose. You can of course expose the entire bounding box, but that
is very expensive for a large areas if it needs to be done several times a
second. The idea of painting a low res mask takes care of it.

Regarding the draw() routine, as you can see in the actual code, I do pass a
boolean flag that indicates whether it is the low res mask that should be
drawn or the actual drawing. This can be used to avoid drawing gradients and
other expensive drawing operations during mask creation.

In any case, thanks for your input.

Dov

On Wed, Aug 18, 2010 at 14:47, Paul Davis p...@linuxaudiosystems.comwrote:

 On Tue, Aug 17, 2010 at 4:22 PM, Dov Grobgeld dov.grobg...@gmail.com
 wrote:

  The solution won't work if the default expose-event handler returns TRUE.
  I would still like to resolve the issues that Paul has with my
 description
  of the code. Paul, why don't you like the fact that I call draw() twice?

 that's overstating it a little bit. what i was taking issue with is
 that *unless* draw() has some way to be able to tell that it is being
 called from an expose event handler (and that would presumably have to
 be some global variable, since nothing is passed to it as an
 argument), it is by definition doing the wrong thing *if* it is
 responsible for all the rendering that occurs in the expose handler.
 why? because that would imply that it actually renders in both the
 pre-expose call and the expose-event call, but you should only be
 rendering (to the window at list) in the expose event call.

 you asked:  How is update() supposed to know what region to invalidate?

 in your original description, you showed the flow as:

# motion event calls update()
 # update() calls draw() in order to get regions to expose.
 # update() calls gdk_invalidate_region() based on output from draw
 # exposure-event callback calls draw() to carry out the drawing
 for each region

 so you have logic that knows what regions are affected by the motion
 event (the above description makes it sound as if that logic is inside
 draw()). update should have that logic so that it can call
 gdk_invalidate_region(), and then the expose-event call to draw()
 should use the event region list to redraw.

 if your code works, that's fine. i'm just trying to describe to you
 what i *think* is the right way to do this so that its portable to all
 backends of GTK and is following the overall drawing model embedded in
 GTK.

 --p

___
gtk-devel-list mailing list
gtk-devel-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-devel-list


cairo drawing commands to gdk_invalidate_region

2010-08-17 Thread Dov Grobgeld
Assume I have a routine:

int draw(cairo_t *cr)

used to draw an overlay in a GdkWindow.

In order to minimize redrawing, I would like to get the minimal (up to some
accuracy to be determined) set of GdkRegion's that encompasses all the
drawing of draw().

I thought of doing this by creating a low resolution cairo image surface
that I pass to draw() and check if pixels are dirty in which case it
indicates that the corresponding rectangle in the source GdkWindow needs to
redrawn.

Is there a better method?

Thanks!
Dov
___
gtk-devel-list mailing list
gtk-devel-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-devel-list


Re: cairo drawing commands to gdk_invalidate_region

2010-08-17 Thread Claudio Saavedra
On Tue, 2010-08-17 at 10:35 +0300, Dov Grobgeld wrote:
 Assume I have a routine:
 
 int draw(cairo_t *cr)
 
 used to draw an overlay in a GdkWindow. 
 
 In order to minimize redrawing, I would like to get the minimal (up to
 some accuracy to be determined) set of GdkRegion's that encompasses
 all the drawing of draw(). 
 
 I thought of doing this by creating a low resolution cairo image
 surface that I pass to draw() and check if pixels are dirty in which
 case it indicates that the corresponding rectangle in the source
 GdkWindow needs to redrawn.
 
 Is there a better method?

Just call

  gdk_cairo_region (cr, event-region);
  cairo_clip (cr);

right after creating the context, and after that, draw as if you didn't
need to care about the dirty regions at all. The clipping will take care
of the rest. This assumes that you only draw as a response to your
expose-event handler, of course.

Claudio


-- 
Claudio Saavedra csaave...@gnome.org

___
gtk-devel-list mailing list
gtk-devel-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-devel-list


Re: cairo drawing commands to gdk_invalidate_region

2010-08-17 Thread Dov Grobgeld
Thanks, but this is not what I am looking for.

Here is a description of my flow, which might e.g. be used to draw a rubber
band box:

   1. motion event calls update()
   2. update() calls draw() in order to get regions to expose.
   3. update() calls gdk_invalidate_region() based on output from draw
   4. exposure-event callback calls draw() to carry out the drawing for each
   region

I.e. draw() is called twice with different purposes. (That's part of the
beauty of the generic cairo_t structure). The first call in 2 should be used
to determine where we are drawing. The second call in 4 is used to do the
drawing.

update() holds a list of rectangle corresponding to the old draw() and the
new draw() and expose both of these. (The exposure of the old commands are
needed to restore the background).

Your example indeed shows how to carry out the drawing as response of a
exposure-event (point 4 above), but doesn't answer my question of what
regions to invalidate (point 2-3).

Meanwhile I already have working code in which the user chooses what regions
to expose, but I would like to make it automatic to make this unnecessary.
Note that I assume that exposing the entire widget for each motion event is
too slow.

Dov

On Tue, Aug 17, 2010 at 11:14, Claudio Saavedra csaave...@gnome.org wrote:

 On Tue, 2010-08-17 at 10:35 +0300, Dov Grobgeld wrote:
  Assume I have a routine:
 
  int draw(cairo_t *cr)
 
  used to draw an overlay in a GdkWindow.
 
  In order to minimize redrawing, I would like to get the minimal (up to
  some accuracy to be determined) set of GdkRegion's that encompasses
  all the drawing of draw().
 
  I thought of doing this by creating a low resolution cairo image
  surface that I pass to draw() and check if pixels are dirty in which
  case it indicates that the corresponding rectangle in the source
  GdkWindow needs to redrawn.
 
  Is there a better method?

 Just call

  gdk_cairo_region (cr, event-region);
  cairo_clip (cr);

 right after creating the context, and after that, draw as if you didn't
 need to care about the dirty regions at all. The clipping will take care
 of the rest. This assumes that you only draw as a response to your
 expose-event handler, of course.

 Claudio


 --
 Claudio Saavedra csaave...@gnome.org

 ___
 gtk-devel-list mailing list
 gtk-devel-list@gnome.org
 http://mail.gnome.org/mailman/listinfo/gtk-devel-list

___
gtk-devel-list mailing list
gtk-devel-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-devel-list


Re: cairo drawing commands to gdk_invalidate_region

2010-08-17 Thread Paul Davis
On Tue, Aug 17, 2010 at 4:39 AM, Dov Grobgeld dov.grobg...@gmail.com wrote:
 Thanks, but this is not what I am looking for.

 Here is a description of my flow, which might e.g. be used to draw a rubber
 band box:


based on an IRC exchange about this a couple of days ago, the answer
is two-fold:

1) you assume that cairo_clip() was called with ev-region before
draw() is invokved
2) you call something like cairo_clip_rectangle_lists() to get the
list of rects that need to be redrawn

there have been some suggestions that one should ignore this and just
redraw everything and let cairo clipping deal with it, but i think
this is clearly wrong when the drawing is computationally expensive.

--p
___
gtk-devel-list mailing list
gtk-devel-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-devel-list


Re: cairo drawing commands to gdk_invalidate_region

2010-08-17 Thread Paul Davis
On Tue, Aug 17, 2010 at 9:11 AM, Dov Grobgeld dov.grobg...@gmail.com wrote:
 Sorry, I still don't get it. In my scenario there is initially is no
 external request of a region that should be drawn. The only source of what
 should be drawn, including what areas should be exposed, are in the draw()
 routine. The challenge is to translate a set of drawing routines to a set of
 invalidation areas.

This is how you described it:

Here is a description of my flow, which might e.g. be used to draw a rubber 
band box:

   1. motion event calls update()
   2. update() calls draw() in order to get regions to expose.
   3. update() calls gdk_invalidate_region() based on output from draw
   4. exposure-event callback calls draw() to carry out the drawing for each 
 region

this is wrong. update() should just call gdk_invalidate_region(). this
will cause expose to be invoked with the region passed in.
the way you've described it above, your draw() method does two
entirely separate tasks.
___
gtk-devel-list mailing list
gtk-devel-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-devel-list


Re: cairo drawing commands to gdk_invalidate_region

2010-08-17 Thread Dov Grobgeld
How is update() supposed to know what region to invalidate? By a list of
GdkRegions as a parameters? The dual functionality of draw is just a way of
automizing this.

Dov

On Tue, Aug 17, 2010 at 18:50, Paul Davis p...@linuxaudiosystems.comwrote:

 On Tue, Aug 17, 2010 at 9:11 AM, Dov Grobgeld dov.grobg...@gmail.com
 wrote:
  Sorry, I still don't get it. In my scenario there is initially is no
  external request of a region that should be drawn. The only source of
 what
  should be drawn, including what areas should be exposed, are in the
 draw()
  routine. The challenge is to translate a set of drawing routines to a set
 of
  invalidation areas.

 This is how you described it:

 Here is a description of my flow, which might e.g. be used to draw a
 rubber band box:
 
1. motion event calls update()
2. update() calls draw() in order to get regions to expose.
3. update() calls gdk_invalidate_region() based on output from draw
4. exposure-event callback calls draw() to carry out the drawing for
 each region

 this is wrong. update() should just call gdk_invalidate_region(). this
 will cause expose to be invoked with the region passed in.
 the way you've described it above, your draw() method does two
 entirely separate tasks.

___
gtk-devel-list mailing list
gtk-devel-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-devel-list


Re: cairo drawing commands to gdk_invalidate_region

2010-08-17 Thread Federico Mena Quintero
On Tue, 2010-08-17 at 10:35 +0300, Dov Grobgeld wrote:
 Assume I have a routine:
 
 int draw(cairo_t *cr)
 
 used to draw an overlay in a GdkWindow. 
 
 In order to minimize redrawing, I would like to get the minimal (up to
 some accuracy to be determined) set of GdkRegion's that encompasses
 all the drawing of draw(). 

You may have a different case, but let me tell you about a cute trick I
had to do for iogrind [1].

One of iogrind's displays is essentially a point-cloud on which you move
a crosshair with the mouse:

  +-+
  |   .   . | . .. . . .|
  | .   . . |.. . . .  .|
  |-+---|
  |..  .. . |...  . . . |
  |   .   . |. . .. ..  |
  +-+

The crosshair spans the whole width and height of the widget.  Drawing
the points is expensive, as there may be thousands of them.  With each
mouse motion event, you must repaint the crosshair.

My solution went like this:

1. The widget keeps a GdkPixmap where it draws the point-cloud at
startup.  The points don't move (thankfully), so that pixmap is
basically read-only after initialization.

2. My motion-notify handler does this:

invalidate_vertical_line (w-cursor_x);
invalidate_horizontal_line (w-cursor_y);
w-cursor_x = event-x;
w-cursor_y = event-y;
invalidate_vertical_line (w-cursor_x);
invalidate_horizontal_line (w-cursor_y);

3. My expose handler does this:

   bitblt (w-pixmap_with_points, widget-window);
   paint_vertical_line (w-cursor_x);
   paint_horizontal_line (w-cursor_y);

So, repaints are very fast as I can avoid regenerating the points; I
basically just paint the crosshair and that's it.

If your drawing can be done with mostly-static contents and an
occasional rubberband rectangle, this is a good way to do it.

[1] http://live.gnome.org/iogrind

  Federico


___
gtk-devel-list mailing list
gtk-devel-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-devel-list


Re: cairo drawing commands to gdk_invalidate_region

2010-08-17 Thread Dov Grobgeld
I uploaded my solution that I gave the working name dovtk-lasso to github
at:

http://github.com/dov/dovtk-lasso

On the one hand it works beautifully as it allows drawing dynamic overlays
with cairo with very little overhead. On the other hand it still has some
problems:

   - The solution won't work if the default expose-event handler returns
   TRUE.
   - I would still like to resolve the issues that Paul has with my
   description of the code. Paul, why don't you like the fact that I call
   draw() twice?

Have a look at the png file at github to see an example of a caliper like
measuring tool that I made with dovtk-lasso. Again, the graphics is
arbitrary, and could just as well be a rectangle, a cross hair, or whatever
the user feels like.

Looking forward to comments.

Regards,
Dov

On Tue, Aug 17, 2010 at 22:03, Federico Mena Quintero
feder...@ximian.comwrote:

 On Tue, 2010-08-17 at 10:35 +0300, Dov Grobgeld wrote:
  Assume I have a routine:
 
  int draw(cairo_t *cr)
 
  used to draw an overlay in a GdkWindow.
 
  In order to minimize redrawing, I would like to get the minimal (up to
  some accuracy to be determined) set of GdkRegion's that encompasses
  all the drawing of draw().

 You may have a different case, but let me tell you about a cute trick I
 had to do for iogrind [1].

 One of iogrind's displays is essentially a point-cloud on which you move
 a crosshair with the mouse:

  +-+
  |   .   . | . .. . . .|
  | .   . . |.. . . .  .|
  |-+---|
  |..  .. . |...  . . . |
  |   .   . |. . .. ..  |
  +-+

 The crosshair spans the whole width and height of the widget.  Drawing
 the points is expensive, as there may be thousands of them.  With each
 mouse motion event, you must repaint the crosshair.

 My solution went like this:

 1. The widget keeps a GdkPixmap where it draws the point-cloud at
 startup.  The points don't move (thankfully), so that pixmap is
 basically read-only after initialization.

 2. My motion-notify handler does this:

invalidate_vertical_line (w-cursor_x);
invalidate_horizontal_line (w-cursor_y);
w-cursor_x = event-x;
w-cursor_y = event-y;
invalidate_vertical_line (w-cursor_x);
invalidate_horizontal_line (w-cursor_y);

 3. My expose handler does this:

   bitblt (w-pixmap_with_points, widget-window);
   paint_vertical_line (w-cursor_x);
   paint_horizontal_line (w-cursor_y);

 So, repaints are very fast as I can avoid regenerating the points; I
 basically just paint the crosshair and that's it.

 If your drawing can be done with mostly-static contents and an
 occasional rubberband rectangle, this is a good way to do it.

 [1] http://live.gnome.org/iogrind

  Federico



___
gtk-devel-list mailing list
gtk-devel-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-devel-list