Re: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-12-03 Thread jcupitt
Last post on this I swear, but I thought of another simple improvement.

GTK performs expose event compression, that is, when it sends an
expose to your program, the expose is the union of all the expose
events which the window system generated since your app last saw
expose. GTK computes the smallest set of non-overlapping rectangles
which are damaged (in event->region), and also the bounding box of
that set of rectangles (in event->area).

In the code I posted previously I was just using the bounding box of
the rects. If you have a large number of images moving around, this
will usually be almost the entire display. Very inefficient! Here's a
new version of the expose handler which extracts the list of the exact
damaged areas and only repaints those. This saves about 20% CPU on my
desktop machine, and would save much more if I used small images.

-
static gboolean
expose_cb (GtkDrawingArea * area, GdkEventExpose * event, App * app)
{
  GdkRectangle *rect;
  int i, j, n;

  gdk_region_get_rectangles (event->region, &rect, &n);
  for (j = 0; j < n; j++)
{
  for (i = 0; i < app->n; i++)
{
  GdkRectangle repaint;

  if (gdk_rectangle_intersect (&rect[j], &app->area[i], &repaint))
gdk_pixbuf_render_to_drawable (app->image[i],
   GTK_WIDGET (area)->window,
   GTK_WIDGET (area)->style->white_gc,
   repaint.x - app->area[i].x,
   repaint.y - app->area[i].y,
   repaint.x, repaint.y,
   repaint.width, repaint.height,
   GDK_RGB_DITHER_NORMAL, 0, 0);
}

  if (app->rubber && gdk_rectangle_intersect (&rect[j], &app->box, NULL))
gdk_draw_line (GTK_WIDGET (area)->window,
   GTK_WIDGET (area)->style->white_gc,
   app->x1, app->y1, app->x2, app->y2);
}
  g_free (rect);

  return TRUE;
}
-

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


RE: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-12-02 Thread Stewart Weiss
John,

Thanks. I will look at this one and try it out. So now there will be
two very different approaches to compare.  I am very grateful to all of
you for helping.

Stewart

> -Original Message-
> From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]
> Sent: Sunday, December 02, 2007 4:58 PM
> To: [EMAIL PROTECTED]
> Cc: gtk-list
> Subject: Re: GDK_POINTER_MOTION_HINT_MASK has no effect
>
>
> Hi again Stewart,
>
> On Dec 2, 2007 5:12 AM, Stewart Weiss <[EMAIL PROTECTED]> wrote:
> > I do still have one question about a specific suggestion that
> you made in
> > this thread, below:
>
> I've just spent a while writing you a sample rubberband program and
> now I come to post it I see Richard has done the same! Ah well,
> perhaps you can't have too much sample code. Mine is a little
> different from Richard's, so I'm going to paste it here anyway.
>
> Richard's is a retained mode program. He keeps a complete bitmap for
> his display in an offscreen buffer and does all animation there. On
> expose, he just copies the relevant part to the screen.
>
> Mine is a list-mode program. I have no backing pixmaps: I do all
> drawing in the expose handler. The display only exists as a few
> numbers for the positions of the images and the rubberband line.
>
> The two styles are probably appropriate for different type of program
> (as I guess our discussion showed). I suppose most programs will fall
> somewhere inbetween these two.
>
> If you try it out, run with something like:
>
>   ./a.out ~/pics/*.jpg
>
> (or wherever you keep some pictures). It creates a window with the
> first 10 images bouncing around and lets you rubberband a white line
> that floats on top. It has the following nice properties:
>
> - the images animate smoothly, they float over each other in a clearly
> defined stacking order, and the rubberband line is always on top
> - the animation routine is very simple, since it does no drawing
> - because drawing and animation are decoupled, the speed stays
> constant even under load (the framerate just drops)
> - resizing is fluid and doesn't interrupt the animation, since there's
> no pixmap to rebuild
> - it uses motion hints so the rubberband doesn't lag
>
> -
> /* compile with
>  *  gcc -g -Wall try144.c `pkg-config gtk+-2.0 --cflags --libs`
>  */
>
> #include 
> #include 
> #include 
>
> #define MAX_IMAGES (10)
>
> /* Application state.
>  */
> typedef struct _App
> {
>   /* Drawingarea we draw to.
>*/
>   GtkWidget *drawing;
>
>   /* Loaded images.
>*/
>   GdkPixbuf *image[MAX_IMAGES];
>   int n;
>
>   /* Bounding box and velocity of each image.
>*/
>   GdkRectangle area[MAX_IMAGES];
>   int u[MAX_IMAGES];
>   int v[MAX_IMAGES];
>
>   /* Rubberband state.
>*/
>   gboolean rubber;
>   int x1, y1;
>   int x2, y2;
>   GdkRectangle box;   /* Bounding box of rubberband line */
> } App;
>
> static void
> repaint_rect (App * app, GdkRectangle * rect)
> {
>   gtk_widget_queue_draw_area (app->drawing,
> rect->x, rect->y, rect->width, rect->height);
> }
>
> static gboolean
> event_cb (GtkWidget * widget, GdkEvent * ev, App * app)
> {
>   gboolean handled;
>
>   handled = FALSE;
>
>   switch (ev->type)
> {
> case GDK_BUTTON_PRESS:
>   if (ev->button.button == 1)
>   {
> app->rubber = TRUE;
> app->x1 = app->x2 = ev->button.x;
> app->y1 = app->y2 = ev->button.y;
> handled = TRUE;
>   }
>   break;
>
> case GDK_BUTTON_RELEASE:
>   if (ev->button.button == 1)
>   {
> app->rubber = FALSE;
> handled = TRUE;
>   }
>   break;
>
> case GDK_MOTION_NOTIFY:
>   if (ev->motion.state & GDK_BUTTON1_MASK && app->rubber)
>   {
> /* A hint? Read the position to get the latest value.
>  */
> if (ev->motion.is_hint)
>   {
> int x, y;
>
> gdk_window_get_pointer (widget->window, &x, &y, NULL);
> ev->motion.x = x;
> ev->motion.y = y;
>   }
>
> app->x2 = ev->motion.x;
> app->y2 = ev->motion.y;
>
> /* Queue a repaint at the old position to wipe out where te line
>  * was.
>  */
> repaint_rect (app, &app->box);
>
> handled = TRUE;
>   }
>
>   break;
>
> default:
>   break;
> }

Re: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-12-02 Thread jcupitt
Hi again Stewart,

On Dec 2, 2007 5:12 AM, Stewart Weiss <[EMAIL PROTECTED]> wrote:
> I do still have one question about a specific suggestion that you made in
> this thread, below:

I've just spent a while writing you a sample rubberband program and
now I come to post it I see Richard has done the same! Ah well,
perhaps you can't have too much sample code. Mine is a little
different from Richard's, so I'm going to paste it here anyway.

Richard's is a retained mode program. He keeps a complete bitmap for
his display in an offscreen buffer and does all animation there. On
expose, he just copies the relevant part to the screen.

Mine is a list-mode program. I have no backing pixmaps: I do all
drawing in the expose handler. The display only exists as a few
numbers for the positions of the images and the rubberband line.

The two styles are probably appropriate for different type of program
(as I guess our discussion showed). I suppose most programs will fall
somewhere inbetween these two.

If you try it out, run with something like:

  ./a.out ~/pics/*.jpg

(or wherever you keep some pictures). It creates a window with the
first 10 images bouncing around and lets you rubberband a white line
that floats on top. It has the following nice properties:

- the images animate smoothly, they float over each other in a clearly
defined stacking order, and the rubberband line is always on top
- the animation routine is very simple, since it does no drawing
- because drawing and animation are decoupled, the speed stays
constant even under load (the framerate just drops)
- resizing is fluid and doesn't interrupt the animation, since there's
no pixmap to rebuild
- it uses motion hints so the rubberband doesn't lag

-
/* compile with
 *  gcc -g -Wall try144.c `pkg-config gtk+-2.0 --cflags --libs`
 */

#include 
#include 
#include 

#define MAX_IMAGES (10)

/* Application state.
 */
typedef struct _App
{
  /* Drawingarea we draw to.
   */
  GtkWidget *drawing;

  /* Loaded images.
   */
  GdkPixbuf *image[MAX_IMAGES];
  int n;

  /* Bounding box and velocity of each image.
   */
  GdkRectangle area[MAX_IMAGES];
  int u[MAX_IMAGES];
  int v[MAX_IMAGES];

  /* Rubberband state.
   */
  gboolean rubber;
  int x1, y1;
  int x2, y2;
  GdkRectangle box; /* Bounding box of rubberband line */
} App;

static void
repaint_rect (App * app, GdkRectangle * rect)
{
  gtk_widget_queue_draw_area (app->drawing,
  rect->x, rect->y, rect->width, rect->height);
}

static gboolean
event_cb (GtkWidget * widget, GdkEvent * ev, App * app)
{
  gboolean handled;

  handled = FALSE;

  switch (ev->type)
{
case GDK_BUTTON_PRESS:
  if (ev->button.button == 1)
{
  app->rubber = TRUE;
  app->x1 = app->x2 = ev->button.x;
  app->y1 = app->y2 = ev->button.y;
  handled = TRUE;
}
  break;

case GDK_BUTTON_RELEASE:
  if (ev->button.button == 1)
{
  app->rubber = FALSE;
  handled = TRUE;
}
  break;

case GDK_MOTION_NOTIFY:
  if (ev->motion.state & GDK_BUTTON1_MASK && app->rubber)
{
  /* A hint? Read the position to get the latest value.
   */
  if (ev->motion.is_hint)
{
  int x, y;

  gdk_window_get_pointer (widget->window, &x, &y, NULL);
  ev->motion.x = x;
  ev->motion.y = y;
}

  app->x2 = ev->motion.x;
  app->y2 = ev->motion.y;

  /* Queue a repaint at the old position to wipe out where te line
   * was.
   */
  repaint_rect (app, &app->box);

  handled = TRUE;
}

  break;

default:
  break;
}

  /* If we handled the event, update the bounding box for the rubberband
   * line and queue a repaint.
   */
  if (handled)
{
  app->box.x = MIN (app->x1, app->x2);
  app->box.width = MAX (app->x1, app->x2) - app->box.x;
  app->box.y = MIN (app->y1, app->y2);
  app->box.height = MAX (app->y1, app->y2) - app->box.y;

  repaint_rect (app, &app->box);
}

  return handled;
}

static gboolean
expose_cb (GtkDrawingArea * area, GdkEventExpose * event, App * app)
{
  int i;

  for (i = 0; i < app->n; i++)
{
  GdkRectangle repaint;

  if (gdk_rectangle_intersect (&event->area, &app->area[i], &repaint))
gdk_pixbuf_render_to_drawable (app->image[i],
   GTK_WIDGET (area)->window,
   GTK_WIDGET (area)->style->white_gc,
   repaint.x - app->area[i].x,
   repaint.y - app->area[i].y,
   repaint.x, repaint.y, repaint.width,
   repaint.height,
   GDK_RGB_DITHER_NORMAL, 0, 0);
}

  if (app->rubber && gdk_rectangle_inte

RE: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-12-01 Thread Stewart Weiss
John,

For someone relatively new to GTK like myself, the thread of messages
from you, Richard Boaz, and Paul Davis was extremely eye-opening but also
confusing. I am grateful to hear the exchange of ideas, to the extent that
I understood it. The confusing part is simply trying to decide which of the
design principles makes sense for what I am trying to do now, but also
trying
to extrapolate and understand what principles to follow in general when
starting
up a new application. I am not fishing for answers here; this problem is
mine.

I do still have one question about a specific suggestion that you made in
this thread, below:

> -Original Message-
> From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]
> Sent: Thursday, November 29, 2007 4:48 PM
>
>-- snip --
>
> This is often not the case, especially in a complex application.
> Instead, you should think of your window as being composed from a
> number of separate layers (like photoshop layers), and that on an
> expose you should completely repaint that section of the window by
> drawing all layers from the back forwards.
>
>   -- snip --
>
> Assuming it's raster, you should have two separate data structures.
> Keep a large image around which has the current state of your user's
> image. Only drawing operations go into this, no rubberbanding. This is
> your background layer. Rubberband operations are in another layer
> which floats on top of this.

Do you mean a second pixmap? If so, how does one draw the second one on top
of the first without replacing pixels, assuming the GC function is just
GDK_COPY?

>
> On an expose, use your background image to paint the exposed pixels.
> Then, if there's a rubber band active at the moment and if the
> bounding box of the rubber band intersects the expose, draw that as
> well on top of the image.

How does one draw layers "on top of" layers?  If I am understanding you
correctly, you are saying that I can use one bg pixmap to store one layer,
and another pixmap to store a second, higher layer. To be precise, suppose
that I have added the original scribble example, tools so that the user can
draw shapes in addition to the brush strokes. I keep the drawing the user
has created so far in a bg pixmap. Now the user wants to put a line on top
of that drawing, and I want to rubberband it. Are you saying that
(1) the rubberbanded line is drawn into a second pixmap that is drawn "on
top of"
the other, and if so, how does one draw on top without obscuring the
pixels
underneath using a straightforward GDK_COPY function in the gc, or
(2) do you mean that I should draw into the window, not a second pixmap,
after I have drawn the bg pixmap underneath it?

I have tried drawing directly into the window for the rubberbanded line,
and sending an invalidate_rect event for that line to force a redraw of the
rectangle that includes it as I move the mouse, to make it "disappear",
but the result is that it disappears so fast that it is not visible.  Could
you clarify?

Thanks
Stewart

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


RE: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-11-29 Thread Stewart Weiss
John,

I will study the application you sent me the link to.
My  program is not raster; it lets the user draw with a brush
or use a line tool in the window. Since the user has drawn with a
brush already, the underlying layer is in a pixmap.
First I will look at your application's  code, and if I cannot figure it
out,
I will post again.

Many thanks
Stewart

> -Original Message-
> From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]
> Sent: Thursday, November 29, 2007 4:48 PM
> To: [EMAIL PROTECTED]
> Cc: gtk-list
> Subject: Re: GDK_POINTER_MOTION_HINT_MASK has no effect
>
>
> On 11/29/07, Stewart Weiss <[EMAIL PROTECTED]> wrote:
> > 1. I am assuming that when I queue a draw for the old position of
> > the rubberbanded line, I am using XOR to draw it, so that it is in
> > effect, an erasing, right?
>
> Actually, I'd suggest using a plain draw rather than an XOR.
>
> XOR rubberbanding works if you can treat your display as something you
> can draw incrementally, that is, you know what is on the screen and
> therefore you know whether this XOR draw will set or unset a line.
>
> This is often not the case, especially in a complex application.
> Instead, you should think of your window as being composed from a
> number of separate layers (like photoshop layers), and that on an
> expose you should completely repaint that section of the window by
> drawing all layers from the back forwards.
>
> > Right now, my function to draw a line uses gdk_draw_line into the pixmap
> > and then calls gdk_window_invalidate_rect to send the expose
> event later.
> > If I actually call the gdk_draw_line in the expose event
> handler, directly
> > into the pixmap, would I then use gdk_draw_drawable to copy the
> pixmap into
> > the window?   I know I can't queue a drawing event in the
> handler or else
> > I have an infinite indirect recursive loop. Is this how?
>
> Is this a raster drawing program, or a vector one?
>
> Assuming it's raster, you should have two separate data structures.
> Keep a large image around which has the current state of your user's
> image. Only drawing operations go into this, no rubberbanding. This is
> your background layer. Rubberband operations are in another layer
> which floats on top of this.
>
> On an expose, use your background image to paint the exposed pixels.
> Then, if there's a rubber band active at the moment and if the
> bounding box of the rubber band intersects the expose, draw that as
> well on top of the image.
>
> If you're curious, my app is here:
>
>   http://www.vips.ecs.soton.ac.uk
>
> To see the rubberbanding, load an image, doubleclick the thumbnail to
> get a view window, then hold down CTRL and click and drag up and left
> to get a vector, down and right to get a region, just click to get a
> point, or drag from a ruler to get a guide.
>
> If you try resizing outside the edge of the window, the window will
> scroll in the background. You can move objects around by dragging on
> their names. Hopefully you'll see all the objects, including the
> animated ones, float over each other smoothly. There's a simple
> paintbox on the View menu which also does some rubberbanding with some
> of the tools.
>
> John

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


Re: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-11-29 Thread jcupitt
On 11/29/07, Stewart Weiss <[EMAIL PROTECTED]> wrote:
> 1. I am assuming that when I queue a draw for the old position of
> the rubberbanded line, I am using XOR to draw it, so that it is in
> effect, an erasing, right?

Actually, I'd suggest using a plain draw rather than an XOR.

XOR rubberbanding works if you can treat your display as something you
can draw incrementally, that is, you know what is on the screen and
therefore you know whether this XOR draw will set or unset a line.

This is often not the case, especially in a complex application.
Instead, you should think of your window as being composed from a
number of separate layers (like photoshop layers), and that on an
expose you should completely repaint that section of the window by
drawing all layers from the back forwards.

> Right now, my function to draw a line uses gdk_draw_line into the pixmap
> and then calls gdk_window_invalidate_rect to send the expose event later.
> If I actually call the gdk_draw_line in the expose event handler, directly
> into the pixmap, would I then use gdk_draw_drawable to copy the pixmap into
> the window?   I know I can't queue a drawing event in the handler or else
> I have an infinite indirect recursive loop. Is this how?

Is this a raster drawing program, or a vector one?

Assuming it's raster, you should have two separate data structures.
Keep a large image around which has the current state of your user's
image. Only drawing operations go into this, no rubberbanding. This is
your background layer. Rubberband operations are in another layer
which floats on top of this.

On an expose, use your background image to paint the exposed pixels.
Then, if there's a rubber band active at the moment and if the
bounding box of the rubber band intersects the expose, draw that as
well on top of the image.

If you're curious, my app is here:

  http://www.vips.ecs.soton.ac.uk

To see the rubberbanding, load an image, doubleclick the thumbnail to
get a view window, then hold down CTRL and click and drag up and left
to get a vector, down and right to get a region, just click to get a
point, or drag from a ruler to get a guide.

If you try resizing outside the edge of the window, the window will
scroll in the background. You can move objects around by dragging on
their names. Hopefully you'll see all the objects, including the
animated ones, float over each other smoothly. There's a simple
paintbox on the View menu which also does some rubberbanding with some
of the tools.

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


Re: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-11-29 Thread Paul Davis
On Thu, 2007-11-29 at 20:03 +0100, Richard Boaz wrote:

> 
> To illustrate: I have been called once, and GTK+ has drawn to the double
> buffer pixmap as you say.  I was partially obscured and am now re-exposed,
> i.e., the main loop calls me again specifying an invalidated rectangle via
> the GdkEvent structure.
> 
> Do I:
>   1) redraw the entire picture since I've been called, ignoring all else,
> knowing this will result in a fully refreshed screen?
> 
>   2) redraw only that part which was obscured (rectangle parameters
> provided), having to determine programmatically what drawing commands
> actually constitute refreshing the obscured portion?
> 
>   3) know that my drawing hasn't changed its state since the last complete
> draw and doesn't need to be redrawn at all since upon exiting this call,
> the double buffer I had previously written to still contains my drawing
> and will physically refresh only the rectangle which was passed to the
> expose handler for re-exposure?
> 
> Naturally I will demand that the third option is really the only
> acceptable answer since:
> 
>   1) option 1 is a complete waste of resources when I have to process 100
> million data points for drawing to the screen (I exaggerate not).
> 
>   2) option 2 is simply impossible to make a one-to-one calculation as to
> which pixels must be refreshed, programmatically.

for many (perhaps even for an overwhelming majority of applications (2)
works just fine. if you application can't do this cheaply, then your
approach is the right way. 

> If the third option is how GTK+ handles this scenario (more kudos...),
> then the expose handler would look something like?:

no, GTK discards the bg pixmaps between exposes. they exist primarily to
improve the visual appearance of the GUI (by avoid tearing and other
artifacts of the drawing process).



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


Re: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-11-29 Thread jcupitt
On 11/29/07, Stewart Weiss <[EMAIL PROTECTED]> wrote:
> This also explains why my solution for drawing the line worked
> reasonably well on Windows but on Linux, the old lines did not get
> erased. So I guess I have to resort to conditional compilation
> directives to make it work in both environments.

The code I pasted will work well on windows and on linux, you
shouldn't need to do any conditional compilation.

The line drawing problems are for other reasons ... you should do all
drawing in the expose handler. If I get a moment, I'll try to make a
small rubber-band example for you.

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


Re: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-11-29 Thread Richard Boaz
Paul,

Thanks for the information, it's good to learn about how GTK+ does its
double buffering in detail.  However...

On Nov 29, 2007 5:22 PM, Paul Davis <[EMAIL PROTECTED]> wrote:

>   And this particular
> case is wholly not addressed in code sample 1; there, you must
redraw the
> entire screen even if only 4 pixels in the lower right corner require a
> re-draw.  As I said before, using the GdkEvent* info to be efficient in
> redrawing only what's required is impossible, and if not, a complete
waste
> of programming time and resources.

no, there is never any need to do this. expose events always contain
information on the region (a collection of 1 or more non-overlapping
rectangles) to redraw. this is based either on information from the
underlying window system or whatever was passed to
gdk_window_invalidate_rect() and its cousins. the only limitation is
that GDK generally "tiles" a drawable with rects no smaller than a given
size, so if there were really just 4 pixels to redraw, you'd like end up
redrawing 32 or 16 or some such number.

I'm still confused as to how this case should be handled in an expose
handler if you do all your drawing there.

To illustrate: I have been called once, and GTK+ has drawn to the double
buffer pixmap as you say.  I was partially obscured and am now re-exposed,
i.e., the main loop calls me again specifying an invalidated rectangle via
the GdkEvent structure.

Do I:
  1) redraw the entire picture since I've been called, ignoring all else,
knowing this will result in a fully refreshed screen?

  2) redraw only that part which was obscured (rectangle parameters
provided), having to determine programmatically what drawing commands
actually constitute refreshing the obscured portion?

  3) know that my drawing hasn't changed its state since the last complete
draw and doesn't need to be redrawn at all since upon exiting this call,
the double buffer I had previously written to still contains my drawing
and will physically refresh only the rectangle which was passed to the
expose handler for re-exposure?

Naturally I will demand that the third option is really the only
acceptable answer since:

  1) option 1 is a complete waste of resources when I have to process 100
million data points for drawing to the screen (I exaggerate not).

  2) option 2 is simply impossible to make a one-to-one calculation as to
which pixels must be refreshed, programmatically.

If the third option is how GTK+ handles this scenario (more kudos...),
then the expose handler would look something like?:

gboolean exposeME(.)
{
   if (redrawRequired || firstTime)
   {
  // process 100,000,000 data points to draw to da->window
   }
   return TRUE;
}

If, however, the double buffer no longer exists when called the second
time, and I have to take option 1, then it is utterly inefficient to have
to redraw the entire screen each time the expose handler is called when I
have to do so much to actually redraw.  (And besides, what's the
invalidated rectangle information used for then anyway?)

(Getting a little ahead of myself since I don't know the answer to my
previous question yet, but...)

If I must do it as per option 1, consider then the two options:

Option 1:
- draw to da->window in expose handler (...of 100M data points)
- expose handler called 10 times by main loop

Option 2:
- make bg pixmap in separate routine (...of 100M data points)
- expose pixmap in expose handler via drawing of bg pixmap
- expose handler called 10 times

Would you not take option 2 and save the time required to process 900M
points of data unnecessarily?

Or am I missing something?  It just strikes me as more efficient to issue
real drawing commands as little as possible, i.e., once to a bg pixmap,
and then to draw this pixmap to the screen.  Not only is it more efficient
(simple less CPU usage), it also makes the application more "responsive"
and "snappy" since the operation of transferring a pixmap to the screen is
instantaneous, while processing 100M data points is, er, not.

And we haven't even begun to discuss animations of these drawings.  Most
definitely in this case, you would want to:
- make all your drawings making up the entire animation as bg pixmaps
- use g_timeout_add() to invalidate the entire drawing area for redraw,
being called over and over until no more drawings
- while the expose handler does nothing more than render the next pixmap
of the animation sequence to the screen.

No?  Or would you still do all your drawing in the expose handler for an
animation?

And I still don't understand why this particular paradigm which works
without fail for me is opposite to GTK+ design.  It's nothing more than an
alternative to the scribble example that, for my requirements, doesn't
work.

The way I see it, the GTK+ designers and developers have succeeded at
doing what you said: to make it as efficient and as smooth as possible,
and this they have done well.  Is

Re: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-11-29 Thread Paul Davis
On Thu, 2007-11-29 at 16:24 +0100, Richard Boaz wrote:
> On Nov 29, 2007 1:36 PM, Paul Davis <[EMAIL PROTECTED]> wrote:
> 
> On Thu, 2007-11-29 at 09:51 +0100, Richard Boaz wrote:
> > This is the paradigm I use in all my drawing apps that has served me
> well:
> >
> > 1) Do all drawing to one or more background pixmaps.
> 
> GTK already does this for you now. All widgets are double buffered
> unless you explicitly request otherwise. So you are currently drawing
> into your bg pixmap, than GTK will copy it into another bg pixmap and
> then finally render it to the screen.
> 
> Well, this confuses me a bit.  Help me understand?

   [ ... code  ]

> I assume the double-buffering occurs at least with each call to
> gdk_draw_line(), but when is this double-buffer (that you the programmer
> have no access to, I assume?) actually rendered to the screen?  After each
> call, or only once the expose handler has exited?
> 
> If this physical event occurs only after the expose handler has exited,
> then kudos to the GTK+ designers and developers, this is very good.  And
> you are correct, my method employs an extra bg pixmap that is, in this
> simple case, unnecessary, though in any case, not expensive.

that is precisely what happens. drawing calls made during an expose
event handler are "redirected" into a bg pixmap; at the end of the
expose handler, the relevant parts of the bg pixmap are flushed to the
screen.

>   And this particular
> case is wholly not addressed in code sample 1; there, you must redraw the
> entire screen even if only 4 pixels in the lower right corner require a
> re-draw.  As I said before, using the GdkEvent* info to be efficient in
> redrawing only what's required is impossible, and if not, a complete waste
> of programming time and resources.

no, there is never any need to do this. expose events always contain
information on the region (a collection of 1 or more non-overlapping
rectangles) to redraw. this is based either on information from the
underlying window system or whatever was passed to
gdk_window_invalidate_rect() and its cousins. the only limitation is
that GDK generally "tiles" a drawable with rects no smaller than a given
size, so if there were really just 4 pixels to redraw, you'd like end up
redrawing 32 or 16 or some such number.

> As I also stated, a particular method to choose comes down to
> requirements.  I now have an application that has more than 30 drawing
> areas (across several tabs/screens), each requiring different routines to
> make their picture.  Doing all my drawing in an expose handler means that
> I must define a different expose handler for each drawing area.  But this
> goes against another principle I have come to embrace, define as few
> callbacks as possible for widgets to use; I have a single configure and
> expose handler for all drawing areas, a single callback for all mouse
> events, drag events, radio button groups, etc.  Why?  This minimizes the
> number of routines that are required to exist and be defined, and for me,
> using nothing more than gedit as my editor, infinitely makes the chore of
> coding much easier to manage.

i didn't suggest unique code per expose handler. i said that all drawing
should be done in *an* expose handler. your examples look perfectly
"sensible" and "correct" to me. you're doing precisely what i was trying
to convey as far as callbacks, except that:

(a) you're using bg pixmaps that are unnecessary
(b) i believe that configure events will be followed by the necessary
expose events, so your queue_draw() calls in the configure handler are
not required (they won't hurt though)

--p





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


Re: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-11-29 Thread Richard Boaz

On Nov 29, 2007 1:36 PM, Paul Davis <[EMAIL PROTECTED]> wrote:

On Thu, 2007-11-29 at 09:51 +0100, Richard Boaz wrote:
> This is the paradigm I use in all my drawing apps that has served me
well:
>
> 1) Do all drawing to one or more background pixmaps.

GTK already does this for you now. All widgets are double buffered
unless you explicitly request otherwise. So you are currently drawing
into your bg pixmap, than GTK will copy it into another bg pixmap and
then finally render it to the screen.

Well, this confuses me a bit.  Help me understand?

Given the following expose handler has been attached to a drawing area:

=== begin code sample 1 ===

gboolean exposeME(GtkWidget *da, GdkEventExpose *event, gpointer *nil)
{
  int w = da->allocation.width;
  int h = da->allocation.height;
  GdkGC *gc = da->style->fg_gc[GTK_WIDGET_STATE(widget)]

  // some lines:
  gdk_draw_line(da->window, gc, w/2, 0, w/2, h);  // vertical
  gdk_draw_line(da->window, gc, 0, h/2, w, h/2);  // horizontal
  gdk_draw_line(da->window, gc, 0, 0, w, h);  // diagonal
  gdk_draw_line(da->window, gc, 0, h, w, 0);  // diagonal

  return TRUE;
}

=== end code sample 2 ===

I assume the double-buffering occurs at least with each call to
gdk_draw_line(), but when is this double-buffer (that you the programmer
have no access to, I assume?) actually rendered to the screen?  After each
call, or only once the expose handler has exited?

If this physical event occurs only after the expose handler has exited,
then kudos to the GTK+ designers and developers, this is very good.  And
you are correct, my method employs an extra bg pixmap that is, in this
simple case, unnecessary, though in any case, not expensive.

*If* this occurs after each call, then I can do better:

=== begin code sample 2 

GdkPixmap *pmap;

void drawMe(GtkWidget *da)
{
  int w = da->allocation.width;
  int h = da->allocation.height;
  GdkGC *gc = da->style->fg_gc[GTK_WIDGET_STATE(widget)]

  gdk_draw_line(pmap, gc, w/2, 0, w/2, h);  // vertical
  gdk_draw_line(pmap, gc, 0, h/2, w, h/2);  // horizontal
  gdk_draw_line(pmap, gc, 0, 0, w, h);  // diagonal
  gdk_draw_line(pmap, gc, 0, h, w, 0);  // diagonal

  gtk_widget_queue_draw_area(da, 0, 0, w, h);
}

gboolean exposeME(GtkWidget *da, GdkEventExpose *event, GdkPixmap *pmap)
{
  int w = da->allocation.width;
  int h = da->allocation.height;
  GdkGC *gc = da->style->fg_gc[GTK_WIDGET_STATE(widget)]

  gdk_draw_drawable(da->window, gc, pmap,
event->area.x, event->area.y,
event->area.width, event->area.height);
  return TRUE;
}

=== end code sample 2 ===

Why better? For at least a couple of reasons.  First, the physical event
to render to the screen has been reduced to one instead of after each
drawing call to da->window in the previous code sample.  (Again, depending
on when the physical render actually occurs.)

Second, double-buffering aside, since (I am assuming here, please correct
me if I'm wrong) you the programmer don't have access to this double
buffer pmap, if you get an expose event from the window manager using code
sample 2, you are making a request for a physical draw that corresponds
exactly to those pixels which require being exposed.  And this particular
case is wholly not addressed in code sample 1; there, you must redraw the
entire screen even if only 4 pixels in the lower right corner require a
re-draw.  As I said before, using the GdkEvent* info to be efficient in
redrawing only what's required is impossible, and if not, a complete waste
of programming time and resources.

In both cases, this equates to a program that is more efficient.  Perhaps
a negligible increase, but an increase nonetheless.  Call me a pedantic
purist, but where graphical programming is concerned, anywhere I can find
a method that is more efficient than another and that will be the method I
choose.

For the record, I have always disagreed with the scribble example in the
demo code; it gets a simple job done, but in the real world, these things
are rarely so simple.

> 2) Do all drawing in routines separate from your configure
handler or
> your expose handler.
> 3) Call your drawing routine(s) from the configure handler.
> 4) Once your drawing routine has completed its task, call
> gtk_widget_queue_draw_area() to force the expose event.
> 5) Do no drawing in your expose event except to
gtk_draw_drawable(),
> rendering your background pixmap to the physical display.
> 6) Use temporary pixmaps liberally when rendering a "temporary"
state
> to the screen.  (For example, display of cross-hairs and coordinates
> when user is simply dragging the mouse (no buttons down) across the
> drawing area.)

richard, i know you have a lot of experience with GTK, but i believe
this is the opposite of the design structure of GTK (and X and also
Quartz; not sure about win32). i am not saying t

Re: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-11-29 Thread Paul Davis
On Thu, 2007-11-29 at 09:51 +0100, Richard Boaz wrote:
> This is the paradigm I use in all my drawing apps that has served me well:
> 
> 1) Do all drawing to one or more background pixmaps.

GTK already does this for you now. All widgets are double buffered
unless you explicitly request otherwise. So you are currently drawing
into your bg pixmap, than GTK will copy it into another bg pixmap and
then finally render it to the screen.

> 2) Do all drawing in routines separate from your configure handler or
> your expose handler.
> 3) Call your drawing routine(s) from the configure handler.
> 4) Once your drawing routine has completed its task, call
> gtk_widget_queue_draw_area() to force the expose event.
> 5) Do no drawing in your expose event except to gtk_draw_drawable(),
> rendering your background pixmap to the physical display.
> 6) Use temporary pixmaps liberally when rendering a "temporary" state
> to the screen.  (For example, display of cross-hairs and coordinates
> when user is simply dragging the mouse (no buttons down) across the
> drawing area.)

richard, i know you have a lot of experience with GTK, but i believe
this is the opposite of the design structure of GTK (and X and also
Quartz; not sure about win32). i am not saying that it doesn't work -
clearly it does. but the internal design of GTK is assuming that drawing
occurs inside expose event handlers, and is set up to make this as
efficient and smooth as possible.

> Basically, in de-coupling your configure and expose events from actual
> drawing, you gain much more power in managing all the requirements of your
> drawing area than if you use a single drawing area that is the screen. 
> Not to mention that drawing directly to the screen is absolutely the
> slower of the two options.

this is false.


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


Re: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-11-29 Thread Richard Boaz
This is the paradigm I use in all my drawing apps that has served me well:

1) Do all drawing to one or more background pixmaps.
2) Do all drawing in routines separate from your configure handler or
your expose handler.
3) Call your drawing routine(s) from the configure handler.
4) Once your drawing routine has completed its task, call
gtk_widget_queue_draw_area() to force the expose event.
5) Do no drawing in your expose event except to gtk_draw_drawable(),
rendering your background pixmap to the physical display.
6) Use temporary pixmaps liberally when rendering a "temporary" state
to the screen.  (For example, display of cross-hairs and coordinates
when user is simply dragging the mouse (no buttons down) across the
drawing area.)

You will notice, here, that there is no actual drawing to the physical
screen except to render your pixmap.  This is the fastest possible manner
in which to draw to the screen.  As well, the expose handler is called
whenever your drawing area is exposed by the window manager, say if it has
been partially obscured by other windows and the user brings it to the
front.  By using gtk_draw_drawable(), you can use the same (x,y)
parameters passed to the callback to render only that part of the pixmap
requiring exposure, i.e., making it as fast as possible.  (Not to mention
that to use these (x,y) parameters to programmatically figure out what
should be re-drawn is practically impossible.)

By maintaining all drawing activity in separate routines, you are able to:

1) have multiple routines responsible for drawing a picture to a
single drawing area, determining programmatically which routine should
be called at any given moment.  These separate routines can draw to
separate backing store pixmaps.
2) easily call any drawing routine from anywhere else in your
application, including background threads (via g_idle_add()), thus
making it trivial to maintain a multi-threaded graphical application.
3) maintain, possibly, multiple backing store pixmaps that can be
easily referenced for redrawing without having to go through an entire
redraw.  (For example, to maintain "before" and "after" states of a
drawing action.  It is much easier to simply re-render a pixmap as
part of an Undo operation than to have to "remember" and redraw the
previous state.)

Basically, in de-coupling your configure and expose events from actual
drawing, you gain much more power in managing all the requirements of your
drawing area than if you use a single drawing area that is the screen. 
Not to mention that drawing directly to the screen is absolutely the
slower of the two options.

As John's post indicates, there is no single way to do all this; gtk gives
you way more than enough rope.  The trick is finding the method that works
for you and your specific requirements.

cheers,

richard

On Nov 29, 2007 4:30 AM, Stewart Weiss <[EMAIL PROTECTED]> wrote:

Many thanks for these posts. They are moving me closer to a better
understanding of the right way to tackle the drawing issues.
I still need a bit of clarification.

1. I am assuming that when I queue a draw for the old position of
the rubberbanded line, I am using XOR to draw it, so that it is in
effect, an erasing, right?

2. You say in the post referenced below that we should really draw
only in the expose event handler, not in the motion or button event
handlers.
Right now, my function to draw a line uses gdk_draw_line into the pixmap
and then calls gdk_window_invalidate_rect to send the expose event later.
If I actually call the gdk_draw_line in the expose event handler,
directly
into the pixmap, would I then use gdk_draw_drawable to copy the pixmap
into
the window?   I know I can't queue a drawing event in the handler or else
I have an infinite indirect recursive loop. Is this how?

Stewart



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


RE: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-11-28 Thread Stewart Weiss
Many thanks for these posts. They are moving me closer to a better
understanding of the right way to tackle the drawing issues.
I still need a bit of clarification.

1. I am assuming that when I queue a draw for the old position of
the rubberbanded line, I am using XOR to draw it, so that it is in
effect, an erasing, right?

2. You say in the post referenced below that we should really draw
only in the expose event handler, not in the motion or button event
handlers.
Right now, my function to draw a line uses gdk_draw_line into the pixmap
and then calls gdk_window_invalidate_rect to send the expose event later.
If I actually call the gdk_draw_line in the expose event handler, directly
into the pixmap, would I then use gdk_draw_drawable to copy the pixmap into
the window?   I know I can't queue a drawing event in the handler or else
I have an infinite indirect recursive loop. Is this how?

Stewart

> -Original Message-
> From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]
> Sent: Wednesday, November 28, 2007 3:53 AM
> To: [EMAIL PROTECTED]
> Cc: gtk-list
> Subject: Re: GDK_POINTER_MOTION_HINT_MASK has no effect
>
>
> On Nov 28, 2007 4:27 AM, Stewart Weiss <[EMAIL PROTECTED]> wrote:
> > Aha!  I did not know that I could configure the GC to draw using
> > various functions of the source and dest pixels values. Thanks !
>
> I posted a mail about rubberbanding a couple of months ago:
>
> http://mail.gnome.org/archives/gtk-app-devel-list/2007-October/msg
> 7.html
>
> Might be helpful. In my opinion, you should structure your
> program like this:
>
> - appstate should have a flag for "displaying rubberband line", plus
> start/end points
> - in your expose handler, first draw the background for the exposed
> area, then draw the rubberband liine on top
> - in your button-press handler, set the rubber band flag and note the
> start position
> - in mouse-motion, if rubberband is set and this is a button drag
> event, queue a draw for the old position of the rubber band line,
> update appstate with the new position, and queue a draw there too
> - in button-release, unset the rubber flag and queue a draw for the
> position of the line
>
> John

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


RE: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-11-28 Thread Stewart Weiss
Thank you. This is a very helpful explanation. I just ran the 
program you sent on my Linux box, remotely displaying on my
Windows box, and sure enough, I see the "seen a hint!" messages.

This also explains why my solution for drawing the line worked
reasonably well on Windows but on Linux, the old lines did not get
erased. So I guess I have to resort to conditional compilation
directives to make it work in both environments.

Are there white papers or other documents that explain the GDK
implementation on Windows? That would sure make it easier to 
understand how to build code for both platforms.

Stewart


> -Original Message-
> From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]
> Sent: Wednesday, November 28, 2007 3:40 AM
> To: [EMAIL PROTECTED]
> Cc: gtk-list@gnome.org
> Subject: Re: GDK_POINTER_MOTION_HINT_MASK has no effect
> 
> 
> On Nov 28, 2007 2:44 AM, Stewart Weiss <[EMAIL PROTECTED]> wrote:
> > I am running this on a Windows box with gtk+ 2.12 installed.
> 
> Ah, OK. I don't think the windows backend uses the is_hint field, so
> you can just ignore it.
> 
> It's because X11 is asynchronous. The window server keeps on trucking
> (and sending a lot of highly detailed mouse tracking information) even
> if your program pauses for a moment. As a result, you can get a
> backlog of mouse events and this causes very annoying lag in your
> application.
> 
> The idea of is_hint is that when your program comes back to check for
> mouse events it just sees an is_hint event, meaning "a lot of mouse
> action has taken place, read the pointer explicitly to get the
> latest". So you get asynchronous mouse evnts and no lag.
> 
> Windows is synchronous (the server can never run ahead of the
> application) so it doesn;t need this mechanism. Just ignnore is_hint
> and it'll work fine.
> 
> John
___
gtk-list mailing list
gtk-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-list


Re: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-11-28 Thread jcupitt
On Nov 28, 2007 4:27 AM, Stewart Weiss <[EMAIL PROTECTED]> wrote:
> Aha!  I did not know that I could configure the GC to draw using
> various functions of the source and dest pixels values. Thanks !

I posted a mail about rubberbanding a couple of months ago:

http://mail.gnome.org/archives/gtk-app-devel-list/2007-October/msg7.html

Might be helpful. In my opinion, you should structure your program like this:

- appstate should have a flag for "displaying rubberband line", plus
start/end points
- in your expose handler, first draw the background for the exposed
area, then draw the rubberband liine on top
- in your button-press handler, set the rubber band flag and note the
start position
- in mouse-motion, if rubberband is set and this is a button drag
event, queue a draw for the old position of the rubber band line,
update appstate with the new position, and queue a draw there too
- in button-release, unset the rubber flag and queue a draw for the
position of the line

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


Re: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-11-28 Thread jcupitt
On Nov 28, 2007 2:44 AM, Stewart Weiss <[EMAIL PROTECTED]> wrote:
> I am running this on a Windows box with gtk+ 2.12 installed.

Ah, OK. I don't think the windows backend uses the is_hint field, so
you can just ignore it.

It's because X11 is asynchronous. The window server keeps on trucking
(and sending a lot of highly detailed mouse tracking information) even
if your program pauses for a moment. As a result, you can get a
backlog of mouse events and this causes very annoying lag in your
application.

The idea of is_hint is that when your program comes back to check for
mouse events it just sees an is_hint event, meaning "a lot of mouse
action has taken place, read the pointer explicitly to get the
latest". So you get asynchronous mouse evnts and no lag.

Windows is synchronous (the server can never run ahead of the
application) so it doesn;t need this mechanism. Just ignnore is_hint
and it'll work fine.

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


RE: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-11-27 Thread Stewart Weiss
Aha!  I did not know that I could configure the GC to draw using
various functions of the source and dest pixels values. Thanks !

Stewart

> -Original Message-
> From: Paul Davis [mailto:[EMAIL PROTECTED]
> Sent: Tuesday, November 27, 2007 11:13 PM
> To: [EMAIL PROTECTED]
> Cc: richard boaz; gtk-list@gnome.org
> Subject: RE: GDK_POINTER_MOTION_HINT_MASK has no effect
> 
> 
> On Tue, 2007-11-27 at 22:17 -0500, Stewart Weiss wrote:
> > Richard:
> >  
> > Thanks for this suggestion.  Last night after sending the message, I
> > did, in fact, resort to
> > doing pretty much what you suggested below, by getting the mouse-down,
> > then tracking it 
> > with button-motion-notify, and then getting the mouse-up event. But I
> > am not using a temporary
> > pixmap, and I have to erase each previously drawn line.
> >  
> > What I want to achieve is a typical Line Tool, like the one in Windows
> > Paint, one that will
> > continuously redraw the line as I drag the mouse.   In order to solve
> > this, in my motion-notify-event
> > handler I erase the previous line by drawing it on the window (not the
> > pixmap) using the background 
> > color of my pixmap, then draw a new one in the window (not in the
> > pixmap). When I get the mouse up event,
> > I draw the last line into the pixmap and render it to the screen. But
> > I still have some problems.
> > When I erase the previous line, I also erase pixels that might have
> > been drawn as part of something
> > else in the window, so my solution is that when I get the button-up
> > event I invalidate the entire
> > window to redraw it. But until I release the mouse button, the erase
> > pixels remain erased. I was thinking
> > of invalidating the rectangle containing the line each time to se if
> > that would work, but I have not tried it
> > yet (busy day). But any other ideas would be appreciated.
> 
> google for "draw xor gtk" and read on ...
> 
> 
___
gtk-list mailing list
gtk-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-list


RE: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-11-27 Thread Paul Davis
On Tue, 2007-11-27 at 22:17 -0500, Stewart Weiss wrote:
> Richard:
>  
> Thanks for this suggestion.  Last night after sending the message, I
> did, in fact, resort to
> doing pretty much what you suggested below, by getting the mouse-down,
> then tracking it 
> with button-motion-notify, and then getting the mouse-up event. But I
> am not using a temporary
> pixmap, and I have to erase each previously drawn line.
>  
> What I want to achieve is a typical Line Tool, like the one in Windows
> Paint, one that will
> continuously redraw the line as I drag the mouse.   In order to solve
> this, in my motion-notify-event
> handler I erase the previous line by drawing it on the window (not the
> pixmap) using the background 
> color of my pixmap, then draw a new one in the window (not in the
> pixmap). When I get the mouse up event,
> I draw the last line into the pixmap and render it to the screen. But
> I still have some problems.
> When I erase the previous line, I also erase pixels that might have
> been drawn as part of something
> else in the window, so my solution is that when I get the button-up
> event I invalidate the entire
> window to redraw it. But until I release the mouse button, the erase
> pixels remain erased. I was thinking
> of invalidating the rectangle containing the line each time to se if
> that would work, but I have not tried it
> yet (busy day). But any other ideas would be appreciated.

google for "draw xor gtk" and read on ...



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


RE: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-11-27 Thread Stewart Weiss
Richard:

Thanks for this suggestion.  Last night after sending the message, I did, in
fact, resort to
doing pretty much what you suggested below, by getting the mouse-down, then
tracking it
with button-motion-notify, and then getting the mouse-up event. But I am not
using a temporary
pixmap, and I have to erase each previously drawn line.

What I want to achieve is a typical Line Tool, like the one in Windows
Paint, one that will
continuously redraw the line as I drag the mouse.   In order to solve this,
in my motion-notify-event
handler I erase the previous line by drawing it on the window (not the
pixmap) using the background
color of my pixmap, then draw a new one in the window (not in the pixmap).
When I get the mouse up event,
I draw the last line into the pixmap and render it to the screen. But I
still have some problems.
When I erase the previous line, I also erase pixels that might have been
drawn as part of something
else in the window, so my solution is that when I get the button-up event I
invalidate the entire
window to redraw it. But until I release the mouse button, the erase pixels
remain erased. I was thinking
of invalidating the rectangle containing the line each time to se if that
would work, but I have not tried it
yet (busy day). But any other ideas would be appreciated.

The motion event handler is basically this (with stuff removed because I use
the same handler
to draw free-form lines with a brush):

gboolean motion_notify_event( GtkWidget *widget,
  GdkEventMotion *event,
  ApplicationState *appState )
{
int x, y;
GdkModifierType state;

if (event->is_hint) {
gdk_window_get_pointer (event->window, &x, &y, &state);
}
else
{
state = event->state;
if (state & GDK_BUTTON1_MASK && appState->pixmap != NULL &&
appState->isLineToolOn )
erase_line ( widget, appState,
line_start_x,
line_start_y,
line_end_x, line_end_y );
x = event->x;
y = event->y;
}

if (state & GDK_BUTTON1_MASK && appState->pixmap != NULL
  && appState->isLineToolOn  ) {
line_end_x = x;
line_end_y = y;
draw_line ( widget, appState,
line_start_x,
line_start_y,
line_end_x, line_end_y, FALSE );

}

return TRUE;
}

The appState is just a struct that has all the application data in it. The
button press
event callback handles both down and up events:

gboolean button_press_event( GtkWidget  *widget,
GdkEventButton *event,
ApplicationState *appState )
{
const gboolean  finalize = TRUE;

if ( event->button == 1 && appState->pixmap != NULL &&
appState->isLineToolOn) {
if ( event->type == GDK_BUTTON_PRESS ) {
line_start_x = event->x;
line_start_y = event->y;
}
else if ( event->type == GDK_BUTTON_RELEASE &&
appState->isLineToolOn) {
draw_line ( widget, appState,
line_start_x,
line_start_y,
line_end_x, line_end_y, finalize);
}
}
return TRUE;
}

 Thanks for the help
Stewart
  -Original Message-
  From: richard boaz [mailto:[EMAIL PROTECTED]
  Sent: Tuesday, November 27, 2007 6:19 AM
  To: [EMAIL PROTECTED]
  Cc: gtk-list@gnome.org
  Subject: Re: GDK_POINTER_MOTION_HINT_MASK has no effect


  Hi,

  I'm not really sure what is_hint is intended to provide, but anyway, what
you are trying to achieve is totally possible without its use (if I
understand you properly).

  Going on the assumption I do understand what you are trying to achieve, I
am providing below some code to illustrate this.  Though actual code, it is
not runnable in its stand-alone form, you will need to tweak it a bit to
make it actually work.  However, it does contain all the hooks necessary to
do the following:

1.. Draw a solid line from point A to point B:
point A = point at mouse-down
point B = point at mouse-up
2.. Draw a dashed line from point A (same as in 1) to Drag Point B:
Drag Point B = point at drag event callback
  I have left out the configure and expose callbacks, I assume that these
have been called and produce a pixmap for display, this pixmap being held in
the global variable DAcontents.  (Again, this is to illustrate, not to
demonstrate proper coding, you probably shouldn't make a global variable for
this purpose.)

  The mouse event callback:

1.. On mouse-down, save the starting point (point A)

2.. On mouse-up, draw a solid line from point A to the ending point
(point B) and render to the screen.
  The drag ev

RE: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-11-27 Thread Stewart Weiss
Thanks for the code, BUT... when I run it exactly as you
typed it below, I get NO output lines that say
seen a hint!
no matter how I move the mouse and press the buttons.
I get all other outputs: all button down and release and
motion at r x c type messages. No hints.

I am running this on a Windows box with gtk+ 2.12 installed.


Stewart


> -Original Message-
> From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]
> Sent: Tuesday, November 27, 2007 9:30 AM
> To: [EMAIL PROTECTED]
> Cc: gtk-list@gnome.org
> Subject: Re: GDK_POINTER_MOTION_HINT_MASK has no effect
> 
> 
> On Nov 27, 2007 2:27 AM, Stewart Weiss <[EMAIL PROTECTED]> wrote:
> > Does anyone know what the real semantics are, and when is_hint is true?
> 
> Here's a complete small program that shows mouse events (with hints)
> for a drawing area.
> 
> --
> /* compile with
>  *  gcc -g -Wall try32.c `pkg-config gtk+-2.0 --cflags --libs`
>  */
> 
> #include 
> #include 
> 
> static gboolean
> event_cb (GtkWidget * widget, GdkEvent * ev)
> {
>   gboolean handled;
> 
>   handled = FALSE;
> 
>   switch (ev->type)
> {
> case GDK_BUTTON_PRESS:
>   printf ("button %d press\n", ev->button.button);
>   handled = TRUE;
>   break;
> 
> case GDK_BUTTON_RELEASE:
>   printf ("button %d release\n", ev->button.button);
>   handled = TRUE;
>   break;
> 
> case GDK_MOTION_NOTIFY:
>   /* A hint? Read the position to get the latest value.
>*/
>   if (ev->motion.is_hint)
> {
>   GdkDisplay *display = gtk_widget_get_display (widget);
>   GdkScreen *screen;
>   int x_root, y_root;
> 
>   printf ("seen a hint!\n");
> 
>   gdk_display_get_pointer (display, &screen, &x_root, 
> &y_root, NULL);
>   ev->motion.x_root = x_root;
>   ev->motion.y_root = y_root;
> }
> 
>   printf ("motion at %g x %g\n", ev->motion.x_root, 
> ev->motion.y_root);
> 
>   if (ev->motion.state & GDK_BUTTON1_MASK)
> printf ("(and btn1 held down)\n");
>   if (ev->motion.state & GDK_BUTTON2_MASK)
> printf ("(and btn2 held down)\n");
> 
>   handled = TRUE;
> 
>   break;
> 
> default:
>   break;
> }
> 
>   return (handled);
> }
> 
> int
> main (int argc, char **argv)
> {
>   GtkWidget *win;
>   GtkWidget *area;
> 
>   gtk_init (&argc, &argv);
>   win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
>   g_signal_connect (win, "destroy", G_CALLBACK (gtk_main_quit), NULL);
> 
>   area = gtk_drawing_area_new ();
>   gtk_widget_add_events (GTK_WIDGET (area),
>  GDK_POINTER_MOTION_MASK |
>  GDK_POINTER_MOTION_HINT_MASK |
>  GDK_BUTTON_PRESS_MASK |
>  GDK_BUTTON_RELEASE_MASK);
> 
>   gtk_signal_connect_after (GTK_OBJECT (area), "event",
> GTK_SIGNAL_FUNC (event_cb), NULL);
> 
>   gtk_container_add (GTK_CONTAINER (win), area);
> 
>   gtk_window_set_default_size (GTK_WINDOW (win), 250, 250);
>   gtk_widget_show_all (win);
> 
>   gtk_main ();
> 
>   return (0);
> }
> 
> 
> You get output like:
> 
> seen a hint!
> motion at 1367 x 446
> seen a hint!
> motion at 1368 x 446
> button 1 press
> seen a hint!
> motion at 1368 x 447
> (and btn1 held down)
> button 2 press
> seen a hint!
> motion at 1368 x 448
> (and btn1 held down)
> (and btn2 held down)
> 
> John
___
gtk-list mailing list
gtk-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-list


Re: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-11-27 Thread jcupitt
On Nov 27, 2007 2:27 AM, Stewart Weiss <[EMAIL PROTECTED]> wrote:
> Does anyone know what the real semantics are, and when is_hint is true?

Here's a complete small program that shows mouse events (with hints)
for a drawing area.

--
/* compile with
 *  gcc -g -Wall try32.c `pkg-config gtk+-2.0 --cflags --libs`
 */

#include 
#include 

static gboolean
event_cb (GtkWidget * widget, GdkEvent * ev)
{
  gboolean handled;

  handled = FALSE;

  switch (ev->type)
{
case GDK_BUTTON_PRESS:
  printf ("button %d press\n", ev->button.button);
  handled = TRUE;
  break;

case GDK_BUTTON_RELEASE:
  printf ("button %d release\n", ev->button.button);
  handled = TRUE;
  break;

case GDK_MOTION_NOTIFY:
  /* A hint? Read the position to get the latest value.
   */
  if (ev->motion.is_hint)
{
  GdkDisplay *display = gtk_widget_get_display (widget);
  GdkScreen *screen;
  int x_root, y_root;

  printf ("seen a hint!\n");

  gdk_display_get_pointer (display, &screen, &x_root, &y_root, NULL);
  ev->motion.x_root = x_root;
  ev->motion.y_root = y_root;
}

  printf ("motion at %g x %g\n", ev->motion.x_root, ev->motion.y_root);

  if (ev->motion.state & GDK_BUTTON1_MASK)
printf ("(and btn1 held down)\n");
  if (ev->motion.state & GDK_BUTTON2_MASK)
printf ("(and btn2 held down)\n");

  handled = TRUE;

  break;

default:
  break;
}

  return (handled);
}

int
main (int argc, char **argv)
{
  GtkWidget *win;
  GtkWidget *area;

  gtk_init (&argc, &argv);
  win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  g_signal_connect (win, "destroy", G_CALLBACK (gtk_main_quit), NULL);

  area = gtk_drawing_area_new ();
  gtk_widget_add_events (GTK_WIDGET (area),
 GDK_POINTER_MOTION_MASK |
 GDK_POINTER_MOTION_HINT_MASK |
 GDK_BUTTON_PRESS_MASK |
 GDK_BUTTON_RELEASE_MASK);

  gtk_signal_connect_after (GTK_OBJECT (area), "event",
GTK_SIGNAL_FUNC (event_cb), NULL);

  gtk_container_add (GTK_CONTAINER (win), area);

  gtk_window_set_default_size (GTK_WINDOW (win), 250, 250);
  gtk_widget_show_all (win);

  gtk_main ();

  return (0);
}


You get output like:

seen a hint!
motion at 1367 x 446
seen a hint!
motion at 1368 x 446
button 1 press
seen a hint!
motion at 1368 x 447
(and btn1 held down)
button 2 press
seen a hint!
motion at 1368 x 448
(and btn1 held down)
(and btn2 held down)

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


Re: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-11-27 Thread Richard Boaz
Hi,

I'm not really sure what is_hint is intended to provide, but anyway, what
you are trying to achieve is totally possible without its use (if I
understand you properly).

Going on the assumption I do understand what you are trying to achieve, I
am providing below some code to illustrate this.  Though actual code, it
is not runnable in its stand-alone form, you will need to tweak it a bit
to make it actually work.  However, it does contain all the hooks
necessary to do the following:

   1. Draw a solid line from point A to point B:
  point A = point at mouse-down
  point B = point at mouse-up
   2. Draw a dashed line from point A (same as in 1) to Drag Point B:
  Drag Point B = point at drag event callback

I have left out the configure and expose callbacks, I assume that these
have been called and produce a pixmap for display, this pixmap being held
in the global variable DAcontents.  (Again, this is to illustrate, not to
demonstrate proper coding, you probably shouldn't make a global variable
for this purpose.)

The mouse event callback:

   1. On mouse-down, save the starting point (point A)
   2. On mouse-up, draw a solid line from point A to the ending point
(point B) and render to the screen.

The drag event callback:

   1. If mouse is not down, do nothing and return
   2. If mouse is down, create temporary pixmap and copy DAcontents to it
   3. draw a dashed line from point A to Drag Point B (event->x, event->y)
on our temp pixmap
   4. Render temp pixmap to the screen
   5. unref temp pixmap
   6. call gdk_window_get_pointer() to tell the main loop we are done with
the drag event and are ready to receive another call to the drag event
callback

Not sure where the problem is in your implementation, but doing these
sorts of things with GTK+ is typically not problematic.

cheers,

richard

= begin code ===

GdkPixmap*DAcontents;
GdkGC*gcMain;

int main(int argc, char **argv)
{
GtkWidget*da;

gtk_init(&argc, &argv);

da = gtk_drawing_area_new();
g_signal_connect (da, "button_press_event", G_CALLBACK (doMouse), NULL);
g_signal_connect (da, "button_release_event", G_CALLBACK (doMouse),
NULL);
g_signal_connect (da, "motion_notify_event", G_CALLBACK (doDrag), NULL);
gtk_widget_set_events (da, gtk_widget_get_events (da)
  | GDK_BUTTON_PRESS_MASK
  | GDK_BUTTON_RELEASE_MASK
  | GDK_POINTER_MOTION_MASK
  | GDK_POINTER_MOTION_HINT_MASK);
gtk_main();
}

intstartX, startY, endX, endY;
gboolean mouseDown;

gboolean doMouse(GtkWidget *da, GdkEventButton *event, gpointer nothing)
{
if (!gcMain)
gcMain = gdk_gc_new(da->window);

switch(event->type)
{
case GDK_BUTTON_PRESS:
startX = event->x;
startY = event->y;
mouseDown = TRUE;
break;
case GDK_BUTTON_RELEASE:
endX = event->x;
endY = event->y;
gdk_draw_line(DAcontents, gcMain, startX, startY, endX, endY);
gdk_draw_drawable(da->window, da->style->fg_gc[GTK_STATE_NORMAL],
DAcontents, 0, 0, 0, 0, -1, -1);
mouseDown = FALSE;
break;
}
return TRUE;
}

gboolean doDrag (GtkWidget *da, GdkEventMotion *event, gpointer nothing)
{
GdkModifierType state;
gintx, y;
GdkPixmap*pixmap;
static GdkGC*gcDash=NULL;

if (!gcDash)
{// first time call setup
gcDash = gdk_gc_new(da->window);
gdk_gc_set_line_attributes(gcDash, 1, GDK_LINE_ON_OFF_DASH, 0, 0);
}

switch(mouseDown)
{
case FALSE:
break;

case TRUE:
pixmap = gdk_pixmap_new(da->window, da-> allocation.width,
da->allocation.height, -1);
gdk_draw_drawable(pixmap, da->style->fg_gc[GTK_STATE_NORMAL],
DAcontents,
0, 0, 0, 0, -1, -1);
gdk_draw_line(pixmap, gcDash, startX, startY, event->x,
event->y);
gdk_draw_drawable(da->window, da->style->fg_gc[GTK_STATE_NORMAL],
pixmap, 0, 0, 0, 0, -1, -1);
g_object_unref(pixmap);
break;

}

gdk_window_get_pointer(event->window, &x, &y, &state);
return TRUE;
}

= end code ===

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


Re: GDK_POINTER_MOTION_HINT_MASK has no effect

2007-11-27 Thread richard boaz
Hi,

I'm not really sure what *is_hint* is intended to provide, but anyway, what
you are trying to achieve is totally possible without its use (if I
understand you properly).

Going on the assumption I do understand what you are trying to achieve, I am
providing below some code to illustrate this.  Though actual code, it is not
runnable in its stand-alone form, you will need to tweak it a bit to make it
actually work.  However, it does contain all the hooks necessary to do the
following:

   1. Draw a solid line from point A to point B:
   point A = point at mouse-down
   point B = point at mouse-up
   2. Draw a dashed line from point A (same as in 1) to Drag Point B:
   Drag Point B = point at drag event callback

I have left out the configure and expose callbacks, I assume that these have
been called and produce a pixmap for display, this pixmap being held in the
global variable *DAcontents*.  (Again, this is to illustrate, not to
demonstrate proper coding, you probably shouldn't make a global variable for
this purpose.)

The mouse event callback:

   1. On mouse-down, save the starting point (point A)
   2. On mouse-up, draw a solid line from point A to the ending point
   (point B) and render to the screen.

The drag event callback:

   1. If mouse is not down, do nothing and return
   2. If mouse is down, create temporary pixmap and copy *DAcontents* to
   it
   3. draw a dashed line from point A to Drag Point B (event->x,
   event->y) on our temp pixmap
   4. Render temp pixmap to the screen
   5. unref temp pixmap
   6. call gdk_window_get_pointer() to tell the main loop we are done
   with the drag event and are ready to receive another call to the drag event
   callback

Not sure where the problem is in your implementation, but doing these sorts
of things with GTK+ is typically not problematic.

cheers,

richard

= begin code ===

GdkPixmap*DAcontents;
GdkGC*gcMain;

int main(int argc, char **argv)
{
GtkWidget*da;

gtk_init(&argc, &argv);

da = gtk_drawing_area_new();
g_signal_connect (da, "button_press_event", G_CALLBACK (doMouse), NULL);
g_signal_connect (da, "button_release_event", G_CALLBACK (doMouse),
NULL);
g_signal_connect (da, "motion_notify_event", G_CALLBACK (doDrag), NULL);
gtk_widget_set_events (da, gtk_widget_get_events (da)
  | GDK_BUTTON_PRESS_MASK
  | GDK_BUTTON_RELEASE_MASK
  | GDK_POINTER_MOTION_MASK
  | GDK_POINTER_MOTION_HINT_MASK);
gtk_main();
}

intstartX, startY, endX, endY;
gboolean mouseDown;

gboolean doMouse(GtkWidget *da, GdkEventButton *event, gpointer nothing)
{
if (!gcMain)
gcMain = gdk_gc_new(da->window);

switch(event->type)
{
case GDK_BUTTON_PRESS:
startX = event->x;
startY = event->y;
mouseDown = TRUE;
break;
case GDK_BUTTON_RELEASE:
endX = event->x;
endY = event->y;
gdk_draw_line(DAcontents, gcMain, startX, startY, endX, endY);
gdk_draw_drawable(da->window,
da->style->fg_gc[GTK_STATE_NORMAL],
DAcontents, 0, 0, 0, 0, -1, -1);
mouseDown = FALSE;
break;
}
return TRUE;
}

gboolean doDrag (GtkWidget *da, GdkEventMotion *event, gpointer nothing)
{
GdkModifierType state;
gintx, y;
GdkPixmap*pixmap;
static GdkGC*gcDash=NULL;

if (!gcDash)
{// first time call setup
gcDash = gdk_gc_new(da->window);
gdk_gc_set_line_attributes(gcDash, 1, GDK_LINE_ON_OFF_DASH, 0, 0);
}

switch(mouseDown)
{
case FALSE:
break;

case TRUE:
pixmap = gdk_pixmap_new(da->window, da->allocation.width, da->
allocation.height, -1);
gdk_draw_drawable(pixmap, da->style->fg_gc[GTK_STATE_NORMAL],
DAcontents,
0, 0, 0, 0, -1, -1);
gdk_draw_line(pixmap, gcDash, startX, startY, event->x,
event->y);
gdk_draw_drawable(da->window,
da->style->fg_gc[GTK_STATE_NORMAL],
pixmap, 0, 0, 0, 0, -1, -1);
g_object_unref(pixmap);
break;
}

gdk_window_get_pointer(event->window, &x, &y, &state);
return TRUE;
}

= end code ===


On Nov 27, 2007 3:27 AM, Stewart Weiss <[EMAIL PROTECTED]> wrote:

> I have been playing around with the motion_notify_event callback in the
> Scribble example from the tutorial, and I have discovered that none of
> what the documentation states is correct.  I modified the handler to
> generate
> output on the standard outout device as follows:
>
> gboolean motion_notify_event( GtkWidget  *widget,
>  GdkEventMotion *event,
>  gpointer   *mydata )
> {
>int x, y;
>GdkModifierType state;
>
>