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 <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

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

Reply via email to