Re: more on re- draw at end of re-size



Not really. GTK has nothing to do with window resizing; it's the window
manager's job. All GTK is getting is an X event telling it that the window
state has changed (ConfigureNotify?). There's no way GTK *can* get this
information.

Win32 can... It provides an end-of-resize message... It is an important and identifiable action in the GUI 
repertoire. 

This *is* a window manager issue. An application shouldn't have anything to
do with any of this...

Everything that an application wants to do is an application issue. Only those things that an application 
does not want to do are operating system, window managger, etc.  issues...

Serious drawing applications hardly ever draw to a window; they draw to a "shadow pixmap" from which the 
window is refreshed as necessary. When a user starts resizing, a window is continously (and quicky) refreshed 
from (now size mis-matched) shadow - it's the best and the most reasonable the application can possibly do in 
a series of quicly following re-size messages. (Much better and no more time-consuming than "frame" resizing. 
Frame-resizing is for Win3.0... :). When the user ends the interaction (releasing the mouse button) the old 
pixmap is deleted, and a new one, of the right size, is allocated, its content is repainted (possibly in a 
separate task, so it does not interfere with the GUI response at all) and a re-paint message is posted. The 
code that follows does just that, but, since the button-up event is unobtainable, it does the best it can by 
timing the resize messages. I post it here as an example of the behaviour I was describing above, for those 
that might have any use for it, and especially for those that can improve on it and share the result with the 
audience... 
tk 

/* Program used to experiment with GTK resize/paint model. The program
   draws on a "shadow" pixmap, which is used to repaint the window.
   We would like to avoid resizing and repainting the pixmap
   at each resize callback as the user moves the mouse; the pixmap
   should be refreshed only after the mouse button has been released.
   But GTK/GDK provides no equivalentt of Win32 WM_EXITSIZEMOVE.
*/

#include <stdio.h>
#include <gtk/gtk.h>

struct mapControl {
    GtkWidget *hppmap;              /* Application graphics sub-vindow */
    GdkPixmap *pixmap;                        /* shadow bitmap of the above */
    gint timerCallbackHandle;
    GTimer *stopwatchHandle;
    };

#define STEP 3
#define TIMER_CALLBACK_GRANULARITY 200
#define WIN_SIZE_REDRAW_DELAY 0.50

static gint eventDelete(GtkWidget *, GdkEvent *, struct mapControl *);
static gint eventDestroy(GtkWidget *, struct mapControl *);
static gint eventExpose(GtkWidget *, GdkEventExpose *, struct mapControl *);
static gint eventConfigureMap(GtkWidget *, GdkEventConfigure *, struct mapControl *);
static gint timerCallback(struct mapControl *);

static void updatePixmapSize(struct mapControl *);
static void updatePixmapContents(struct mapControl *);
/* ======================================================================== */
int main(int argc, char *argv[]) {
   GtkWidget *app;
   struct mapControl mc;
/* ------------------------------------------------------------------------ */
   fprintf(stderr, "Painter2 as of: %s %s\n", __DATE__, __TIME__);
   gtk_init(&argc, &argv);

   mc.stopwatchHandle = g_timer_new();
   g_timer_start(mc.stopwatchHandle);
   mc.pixmap = NULL;
   mc.timerCallbackHandle = tk_timeout_add(TIMER_CALLBACK_GRANULARITY, (GtkFunction)timerCallback,  &mc);

   app = gtk_window_new(GTK_WINDOW_TOPLEVEL);            /* create main wdw */
   gtk_window_set_title(GTK_WINDOW(app), "Painter(GTK+)");
   gtk_window_set_policy(GTK_WINDOW(app), FALSE, TRUE, FALSE);   /* make it user-resizable */
   gtk_signal_connect(GTK_OBJECT(app), "delete_event", GTK_SIGNAL_FUNC(eventDelete), &mc);
   gtk_signal_connect(GTK_OBJECT(app), "destroy", GTK_SIGNAL_FUNC(eventDestroy), &mc);

   mc.hppmap = gtk_drawing_area_new();
   gtk_container_add(GTK_CONTAINER(app), mc.hppmap);
   gtk_signal_connect(GTK_OBJECT(mc.hppmap), "expose_event", GTK_SIGNAL_FUNC(eventExpose), &mc);
   gtk_signal_connect(GTK_OBJECT(mc.hppmap), "configure_event", GTK_SIGNAL_FUNC(eventConfigureMap), &mc);

   gtk_widget_show_all(app);
   gtk_main();
   return(0);
   }
/* ======================================================================== */
static gint eventConfigureMap(GtkWidget *widget,
                              GdkEventConfigure *event,
                              struct mapControl *mc) {
/* ------------------------------------------------------------------------ */
/* fprintf(stderr, "Config map: %d: %d x %d\n", event->send_event, event->width, event->height); */
   if ((event->width < 1) || (event->height < 1)) return(TRUE);
   if (mc->timerCallbackHandle == 0) mc->timerCallbackHandle = gtk_timeout_add(TIMER_CALLBACK_GRANULARITY, 
(GtkFunction)timerCallback, mc);
   if (mc->stopwatchHandle == NULL) {
      mc->stopwatchHandle = g_timer_new();
      g_timer_start(mc->stopwatchHandle);
      }
   else g_timer_reset(mc->stopwatchHandle);
   return(TRUE);
   }
/* ======================================================================== */
static gint eventExpose(GtkWidget *map,
                        GdkEventExpose *event,
                        struct mapControl *mc) {
   gint xsrc, ysrc;
   gint xdest, ydest;
   gint hppmapWidth, hppmapHeight;
   gint pixmapWidth, pixmapHeight;
   gint pasteWidth, pasteHeight;
   gint dx, dy;
/* ------------------------------------------------------------------------ */
   if (mc->pixmap == NULL) return(FALSE);              /* no shadow pixmap? */
   gdk_window_get_size(mc->pixmap, &pixmapWidth, &pixmapHeight);
/* fprintf(stderr, "Pixmap size map %d x %d\n", pixmapWidth, pixmapHeight); */
   hppmapWidth = mc->hppmap->allocation.width;
   hppmapHeight = mc->hppmap->allocation.height;
/* fprintf(stderr, "Hppmap size map %d x %d\n", hppmapWidth, hppmapHeight); */
   dx = (hppmapWidth - pixmapWidth) / 2;
   dy = (hppmapHeight - pixmapHeight) / 2;
   if (dx < 0) {
      xsrc = -dx;
      xdest = event->area.x;
      pasteWidth = event->area.width - dx;
      }
   else {
      xsrc = event->area.x;
      xdest = event->area.x + dx;
      pasteWidth = event->area.width;
      }
   if (dy < 0) {
      ysrc = -dy;
      ydest = event->area.y;
      pasteHeight = event->area.height - dy;
      }
   else {
      ysrc = event->area.y;
      ydest = event->area.y + dy;
      pasteHeight = event->area.height;
      }
/* fprintf(stderr, "Exposing map %d x %d\n", event->area.width, event->area.height); */
   gdk_draw_pixmap(map->window, map->style->black_gc, mc->pixmap, xsrc, ysrc, xdest, ydest, pasteWidth, 
pasteHeight);
   return(TRUE);
   }
/* ======================================================================== */
static void updatePixmapSize(struct mapControl *mc) {
/* ------------------------------------------------------------------------ */
/* If pixmap exists, delete it, then crate one same size as mc->hppmap. */
   if (mc->pixmap) gdk_pixmap_unref(mc->pixmap);
   mc->pixmap = gdk_pixmap_new(mc->hppmap->window, mc->hppmap->allocation.width, 
mc->hppmap->allocation.height, -1);
   if (mc->pixmap == NULL) return;                    /* something is sick? */
   fprintf(stderr, "Creating new pixmap %p\n", mc->pixmap);
   gdk_draw_rectangle(mc->pixmap, mc->hppmap->style->white_gc, TRUE, 0, 0, mc->hppmap->allocation.width, 
mc->hppmap->allocation.height);
   return;
   }
/* ======================================================================== */
static void updatePixmapContents(struct mapControl *mc) {
   int x1, y1, x2, y2;
   int pixmapWidth, pixmapHeight;
/* ------------------------------------------------------------------------ */
   if (mc->pixmap == NULL) return;                    /* something is sick? */
   gdk_window_get_size(mc->pixmap, &pixmapWidth, &pixmapHeight);
   x1 = 10;
   y1 = 10;
   x2 = pixmapWidth - 10;
   y2 = pixmapHeight - 10;
   fprintf(stderr, "Repainting pixmap %d %d\n", pixmapWidth, pixmapHeight);
   while((x1 < x2) && (y1 < y2)) {
      gdk_draw_line(mc->pixmap, mc->hppmap->style->black_gc, x1, y1, x2, y1);
      gdk_draw_line(mc->pixmap, mc->hppmap->style->black_gc, x2, y1, x2, y2);
      gdk_draw_line(mc->pixmap, mc->hppmap->style->black_gc, x2, y2, x1, y2);
      gdk_draw_line(mc->pixmap, mc->hppmap->style->black_gc, x1, y2, x1, y1);
      x1 += STEP;
      y1 += STEP;
      x2 -= STEP;
      y2 -= STEP;
      }
   return;
   }
/* ======================================================================== */
static gint timerCallback(struct mapControl *mc) {
/* ------------------------------------------------------------------------ */
/* fprintf(stderr, "Timer test %.3f\n", g_timer_elapsed(mc->stopwatchHandle, NULL)); */
   if (g_timer_elapsed(mc->stopwatchHandle, NULL) < WIN_SIZE_REDRAW_DELAY) return(TRUE);
   updatePixmapSize(mc);                                   /* resize pixmap */
   updatePixmapContents(mc);                              /* repaint pixmap */
   gtk_widget_draw(mc->hppmap, NULL);                        /* refresh window */
   g_timer_destroy(mc->stopwatchHandle);             /* terminate stopwatch */
   mc->stopwatchHandle = NULL;                           /* it's terminated */
   mc->timerCallbackHandle = 0;                 /* terminate timer callback */
   return(FALSE);                                  /* 0 return will kill it */
   }
/* ======================================================================== */
gint eventDelete(GtkWidget *widget, GdkEvent *event,  struct mapControl *mc) {
   return(FALSE);          /* fprintf(stderr, "Closing unconditionally\n"); */
   }
/* ======================================================================== */
gint eventDestroy(GtkWidget *widget, struct mapControl *mc) {
/* ------------------------------------------------------------------------ */
   if (mc->pixmap) gdk_pixmap_unref(mc->pixmap);
   if (mc->stopwatchHandle) g_timer_destroy(mc->stopwatchHandle);
   gtk_main_quit();
   return(0);
   }
/* ======================================================================== */







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