RE: GDK_POINTER_MOTION_HINT_MASK has no effect



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: jcupitt gmail com [mailto:jcupitt gmail com]
> Sent: Sunday, December 02, 2007 4:58 PM
> To: stewart weiss acm org
> 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 <stewart weiss acm org> 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 <stdio.h>
> #include <stdlib.h>
> #include <gtk/gtk.h>
>
> #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_intersect (&event->area,
> &app->box, NULL))
>     gdk_draw_line (GTK_WIDGET (area)->window,
> 		   GTK_WIDGET (area)->style->white_gc,
> 		   app->x1, app->y1, app->x2, app->y2);
>
>   return TRUE;
> }
>
> static gboolean
> timeout_cb (App * app)
> {
>   int i;
>
>   for (i = 0; i < app->n; i++)
>     {
>       const int right = app->drawing->allocation.width -
> app->area[i].width;
>       const int bottom =
> 	app->drawing->allocation.height - app->area[i].height;
>       int new_x, new_y;
>
>       new_x = app->area[i].x + app->u[i];
>       new_y = app->area[i].y + app->v[i];
>
>       if (new_x < 0)
> 	{
> 	  new_x = 0;
> 	  app->u[i] *= -1;
> 	}
>       if (new_x > right)
> 	{
> 	  new_x = right;
> 	  app->u[i] *= -1;
> 	}
>       if (new_y < 0)
> 	{
> 	  new_y = 0;
> 	  app->v[i] *= -1;
> 	}
>       if (new_y > bottom)
> 	{
> 	  new_y = bottom;
> 	  app->v[i] *= -1;
> 	}
>
>       if (new_x != app->area[i].x || new_y != app->area[i].y)
> 	{
> 	  repaint_rect (app, &app->area[i]);
> 	  app->area[i].x = new_x;
> 	  app->area[i].y = new_y;
> 	  repaint_rect (app, &app->area[i]);
> 	}
>
>     }
>
>   return TRUE;
> }
>
> int
> main (int argc, char **argv)
> {
>   App app;
>   GtkWidget *win;
>   GError *error = NULL;
>   int i;
>
>   gtk_init (&argc, &argv);
>
>   for (i = 0; i < argc - 1 && i < MAX_IMAGES; i++)
>     {
>       if (!(app.image[i] = gdk_pixbuf_new_from_file (argv[i + 1],
> &error)))
> 	{
> 	  fprintf (stderr, "%s\n", error->message);
> 	  g_error_free (error);
> 	  return -1;
> 	}
>       app.area[i].x = random () % 100;
>       app.area[i].y = random () % 100;
>       app.area[i].width = gdk_pixbuf_get_width (app.image[i]);
>       app.area[i].height = gdk_pixbuf_get_height (app.image[i]);
>       app.u[i] = random () % 10 - 5;
>       app.v[i] = random () % 10 - 5;
>     }
>   app.n = i;
>
>   g_timeout_add (50, (GSourceFunc) timeout_cb, &app);
>
>   win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
>   g_signal_connect (win, "destroy", G_CALLBACK (gtk_main_quit), NULL);
>
>   app.drawing = gtk_drawing_area_new ();
>   gtk_widget_add_events (GTK_WIDGET (app.drawing),
> 			 GDK_POINTER_MOTION_MASK |
> 			 GDK_POINTER_MOTION_HINT_MASK |
> 			 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
>
>   gtk_signal_connect_after (GTK_OBJECT (app.drawing), "event",
> 			    GTK_SIGNAL_FUNC (event_cb), &app);
>   gtk_signal_connect (GTK_OBJECT (app.drawing), "expose_event",
> 		      GTK_SIGNAL_FUNC (expose_cb), &app);
>
>   gtk_container_add (GTK_CONTAINER (win), app.drawing);
>
>   gtk_window_set_default_size (GTK_WINDOW (win), 250, 250);
>   gtk_widget_show_all (win);
>
>   gtk_main ();
>
>   return 0;
> }
> -----------------------
>
> John



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