RE: GDK_POINTER_MOTION_HINT_MASK has no effect
- From: "Stewart Weiss" <stewart weiss acm org>
- To: <jcupitt gmail com>
- Cc: gtk-list <gtk-list gnome org>
- Subject: RE: GDK_POINTER_MOTION_HINT_MASK has no effect
- Date: Sun, 2 Dec 2007 18:43:27 -0500
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]