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@xxxxxxxxx [mailto:jcupitt@xxxxxxxxx] > Sent: Sunday, December 02, 2007 4:58 PM > To: stewart.weiss@xxxxxxx > 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@xxxxxxx> 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@xxxxxxxxx http://mail.gnome.org/mailman/listinfo/gtk-list