Stewart, Yes, all philosophies must ultimately collapse to an actual workable frame at the end of the day. Sorry for any confusion caused. In an attempt to clear this up (and hopefully not make more), you will find below a complete workable program that does nothing, really, except to demonstrate: 1) programmatically generated RGB buffers converted to pixmap for display 2) bg pixmaps used as the main background layer 3) temporary bg pixmaps used to display layers of other drawing info 4) copying parts of bg pixmaps to another bg pixmap 5) swapping multiple background pixmaps for display (via the expose handler) according to a deterministic display state 6) a pixel to user coordinate and conversion system (very handy) 7) dragging with mouse-down and mouse-up, with effect 8) mouse leaving and entering drawing area, with effect 9) etc... Copy to drawingSample.c and it will compile "out of the box" using: sh> gcc `pkg-config --cflags --libs gtk+2.0` drawSample.c -o drawSample User functions: 1) startup - display program-generated RGB buffer 2) drag/mouse-UP - draw dashed lines as cross hairs at mouse point 3) drag/mouse-DOWN - draw dashed lines - display user-defined bounding box 4) mouse-UP/post-Drag - draw solid lines - display bounding box 5) drawing area leave/enter - display an interesting effect, before and after bounding box definitions 6) mouse-CLICK/no-Drag - start over 7) resize window - start over As Paul and John have made clear, one issue in deciding how to effectuate all this rests very much on the size of your background pixmaps (among other important points). My problem entails many data points that all map to a single displayable pixmap, i.e., my bg pixmaps are not very big, so they're cheap. Employing this method for large pixmaps on display could be costly memory-wise. As Paul also pointed out, pixmaps are server-side objects. When they are not large, and the distance between the client and the server is relatively close, this is not such an issue for me. However, one way that the attached program could be brought more "up-to-date" (and work everywhere) would be to convert all drawing commands to cairo routines, thus using a drawing canvas that is client-side, only converting to a pixmap at the last possible moment (or wherever it would make the most sense). As I said, hope this helps. If there is anything confusing, please ask. Also, I program from the bottom of the file to the top, start at the bottom and work your way backwards when reading it the first time. cheers, richard === BEGIN drawingSample.c === #include <string.h> #include <stdlib.h> #include <sys/time.h> #include <gtk/gtk.h> // defines and structures we need enum { MOUSEIN, MOUSEOUT, TTLPMAPS }; #define MAX_PIXEL_VALUE 255 typedef struct { gint startX, startY, endX, endY; gboolean mouseDown; gboolean mouseIn; } MouseState; typedef struct { double user_xmin, user_xmax; float user_ymin, user_ymax; float user_xdif, user_ydif; int pix_xmin, pix_xmax; int pix_ymin, pix_ymax; int pix_ydif, pix_xdif; } graph; typedef struct { guchar R, G, B; } myColorStruct; // some globals GdkPixmap *DAdisplay, *pmap[TTLPMAPS]; GdkGC *gcSolid, *gcDash; int CG[6][3] = // color spectrum {{255, 0, 255}, // R = 255->0 {0, 0, 255}, // G = 0->255 {0, 255, 255}, // B = 255->0 {0, 255, 0}, // R = 0->255 {255, 255, 0}, // G = 255->0 {240, 240, 240}}; // 0% myColorStruct * colorP(float prob) { // probability to color conversion routine // return the color to be associated with the given input of probability: // each probability falls into a colour range as follows: // 0 - 1%: 240,240,240 - 255,000,255 (grey (background) to purple) // 1 - 6%: 255,000,255 - 000,000,255 (purple to blue) // 6 - 12%: 000,000,255 - 000,255,255 (blue to cyan) // 12 - 18%: 000,255,255 - 000,255,000 (cyan to green) // 18 - 24%: 000,255,000 - 255,255,000 (green to yellow) // 24 - 30%: 255,255,000 - 255,000,000 (yellow to red) // int probI = prob, cg; static myColorStruct probColor; if (prob < 1.f) { probColor.R = 240 - prob*27.; // R = 213 - 240, 1% - 0% probColor.G = 240 - prob*240.; // G = 0 - 240, 1% - 0% probColor.B = 240 + prob*15.; // B = 255 - 240, 1% - 0% return &probColor; } cg = probI/6; if (cg>4) // normalize all probs > 30... { cg = 4; prob = 30.f; } probColor.R = CG[cg][0]; probColor.G = CG[cg][1]; probColor.B = CG[cg][2]; switch(cg) { case 0: probColor.R = 255 - (prob*(MAX_PIXEL_VALUE/6.)); // R=255->0 break; // 1% - 6% case 1: probColor.G = (prob-6.)*(MAX_PIXEL_VALUE/6.); // G=0->255 break; // 6% - 12% case 2: probColor.B = 255 - ((prob-12.)*(MAX_PIXEL_VALUE/6.)); // B=255->0 break; // 12% - 18% case 3: probColor.R = (prob-18.)*(MAX_PIXEL_VALUE/6.); // R=0->255 break; // 18% - 24% case 4: probColor.G = 255 - ((prob-24.)*(MAX_PIXEL_VALUE/6.)); // G=255->0 break; // 24% - 30% } return &probColor; } // our graphing/user coordinate system and conversions int user_to_pix_x(graph *gr, double x) { double rint(); return ((rint) (((x - gr->user_xmin) / gr->user_xdif) * ((double) gr->pix_xdif) + ((double) gr->pix_xmin))); } int user_to_pix_y(graph *gr, double y) { return ((int) ((double) gr->pix_ydif) - ((double) (y - gr->user_ymin) / gr->user_ydif) * ((double) gr->pix_ydif) + ((double) gr->pix_ymin)); } double pix_to_user_x(graph *gr, int pix_x) { return ((double) (((pix_x - gr->pix_xmin) / ((double) gr->pix_xdif))* (double) (gr->user_xdif) + gr->user_xmin)); } double pix_to_user_y(graph *gr, int pix_y) { return((double) (1. - (((double) pix_y - gr->pix_ymin) / ((double) gr->pix_ydif))) * gr->user_ydif + gr->user_ymin); } void window(graph *gr, double x1, double x2, double y1, double y2) { gr->user_xmin = x1; gr->user_xmax = x2; gr->user_ymin = y1; gr->user_ymax = y2; gr->user_xdif = gr->user_xmax - gr->user_xmin; gr->user_ydif = gr->user_ymax - gr->user_ymin; } void viewport(graph *gr, int x1, int x2, int y1, int y2) { gr->pix_xmin = x1; gr->pix_xmax = x2; gr->pix_xdif = x2 - x1; gr->pix_ymin = y1; gr->pix_ymax = y2; gr->pix_ydif = y2 - y1; } // make our RBG Buffer and convert to pixmap for display void makeRGBpmap(GtkWidget *da) { struct timeval tv; struct timezone tz; int startColor; gint w = da->allocation.width; gint h = da->allocation.height; int i, j, y, y1, lumin; graph grL; myColorStruct *colorProb; guchar *posC, *rgbbufC; guchar *posG, *rgbbufG; static GdkGC *gc=NULL; gettimeofday(&tv, &tz); srand(tv.tv_usec); // randomly select our starting color startColor = (int) ((float) 30 * rand()/(RAND_MAX+1.0)); if (!gc) gc = gdk_gc_new(da->window); if (pmap[MOUSEIN]) { g_object_unref(pmap[MOUSEIN]); g_object_unref(pmap[MOUSEOUT]); } pmap[MOUSEIN] = gdk_pixmap_new(da->window, w, h, -1); pmap[MOUSEOUT] = gdk_pixmap_new(da->window, w, h, -1); rgbbufC = malloc(w * h * 3); rgbbufG = malloc(w * h * 3); viewport(&grL, 0, w, 0, h); window(&grL, (double) 0, (double) w, (double) 0., (double) 30.0); posC = rgbbufC; posG = rgbbufG; for(i=0;i<h;i++) { colorProb = colorP((float) pix_to_user_y(&grL, i)); lumin = (int) (colorProb->R*.299+colorProb->G*.587+colorProb->B*.114); for(j=0;j<w;j++) { *posC++ = colorProb->R; *posC++ = colorProb->G; *posC++ = colorProb->B; *posG++ = (guchar) lumin; *posG++ = (guchar) lumin; *posG++ = (guchar) lumin; } } gdk_draw_rgb_image (pmap[MOUSEIN], gc, 0, 0, w, h, GDK_RGB_DITHER_NONE, rgbbufC, w*3); gdk_draw_rgb_image (pmap[MOUSEOUT], gc, 0, 0, w, h, GDK_RGB_DITHER_NONE, rgbbufG, w*3); free(rgbbufC); free(rgbbufG); DAdisplay = pmap[MOUSEIN]; return; } // draw our user-defined bounding box void drawBox(GdkPixmap *pixM, GdkGC *gc, MouseState *mouse) { GdkPoint rect[5]; rect[0].x = mouse->startX; rect[0].y = mouse->startY; rect[1].x = mouse->endX; rect[1].y = mouse->startY; rect[2].x = mouse->endX; rect[2].y = mouse->endY; rect[3].x = mouse->startX; rect[3].y = mouse->endY; rect[4].x = mouse->startX; rect[4].y = mouse->startY; gdk_draw_lines(pixM, gc, rect, 5); } gboolean doMouse(GtkWidget *da, GdkEventButton *event, MouseState *mouse) { // got a cat? gint w = da->allocation.width; gint h = da->allocation.height; switch(event->type) { case GDK_BUTTON_PRESS: mouse->startX = event->x; mouse->startY = event->y; mouse->mouseDown = TRUE; break; case GDK_BUTTON_RELEASE: mouse->endX = event->x; mouse->endY = event->y; if (mouse->startX == mouse->endX && mouse->startY == mouse->endY) { // start over makeRGBpmap(da); } else { // copy to greymap and draw the solid outline if (mouse->startX > mouse->endX) { gint tmp = mouse->startX; mouse->startX = mouse->endX; mouse->endX = tmp; } if (mouse->startY > mouse->endY) { gint tmp = mouse->startY; mouse->startY = mouse->endY; mouse->endY = tmp; } gdk_draw_drawable(pmap[MOUSEOUT], da->style->fg_gc[GTK_STATE_NORMAL], pmap[MOUSEIN], mouse->startX, mouse->startY, // source (x,y) mouse->startX, mouse->startY, // dest (x,y) mouse->endX - mouse->startX, // width mouse->endY - mouse->startY); // height drawBox(pmap[MOUSEIN], gcSolid, mouse); } mouse->mouseDown = FALSE; break; } gtk_widget_queue_draw_area(da, 0, 0, w, h); return TRUE; } gboolean doDrag (GtkWidget *da, GdkEventMotion *event, MouseState *mouse) { // as often as possible GdkModifierType state; gint x, y; gint w = da->allocation.width; gint h = da->allocation.height; GdkPixmap *pixmap; pixmap = gdk_pixmap_new(da->window, w, h, -1); gdk_draw_drawable(pixmap, da->style->fg_gc[GTK_STATE_NORMAL], pmap[MOUSEIN], 0, 0, 0, 0, -1, -1); switch(mouse->mouseDown) { case FALSE: // draw dashed lines as cross-hairs gdk_draw_line(pixmap, gcDash, event->x, 0, event->x, h); gdk_draw_line(pixmap, gcDash, 0, event->y, w, event->y); break; case TRUE: // draw dashed lines as box mouse->endX = event->x; mouse->endY = event->y; drawBox(pixmap, gcDash, mouse); break; } gdk_draw_drawable(da->window, da->style->fg_gc[GTK_STATE_NORMAL], pixmap, 0, 0, 0, 0, -1, -1); g_object_unref(pixmap); gdk_window_get_pointer(event->window, &x, &y, &state); return TRUE; } gboolean doFocus(GtkWidget *da, GdkEvent *event, MouseState *mouse) { gint w = da->allocation.width; gint h = da->allocation.height; switch(event->type) { case GDK_ENTER_NOTIFY: mouse->mouseIn = TRUE; DAdisplay = pmap[MOUSEIN]; break; case GDK_LEAVE_NOTIFY: mouse->mouseIn = FALSE; DAdisplay = pmap[MOUSEOUT]; break; } gtk_widget_queue_draw_area(da, 0, 0, w, h); return TRUE; } gboolean exposeME(GtkWidget *da, GdkEventExpose *event, gpointer nil) { gdk_draw_drawable(da->window, da->style->fg_gc[GTK_WIDGET_STATE (da)], DAdisplay, event->area.x, event->area.y, event->area.x, event->area.y, event->area.width, event->area.height); } gboolean configME(GtkWidget *da, GdkEventConfigure *event, gpointer nil) { if (!gcSolid) { // first-time called gcSolid = gdk_gc_new(da->window); gcDash = gdk_gc_new(da->window); gdk_gc_set_function(gcSolid, GDK_INVERT); gdk_gc_set_function(gcDash, GDK_INVERT); gdk_gc_set_line_attributes(gcDash, 1, GDK_LINE_ON_OFF_DASH, 0, 0); } makeRGBpmap(da); } int main(int argc, char **argv) { GtkWidget *topWindow, *frame, *da; MouseState mouseState; memset(&mouseState, 0, sizeof(MouseState)); gtk_init(&argc, &argv); topWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_container_set_border_width(GTK_CONTAINER (topWindow), 2); g_signal_connect (topWindow, "destroy", G_CALLBACK (gtk_main_quit), NULL); frame = gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME (frame), GTK_SHADOW_IN); da = gtk_drawing_area_new(); gtk_container_add(GTK_CONTAINER (frame), da); gtk_container_add (GTK_CONTAINER (topWindow), frame); g_signal_connect (da, "configure_event", G_CALLBACK(configME), NULL); g_signal_connect (da, "expose_event", G_CALLBACK(exposeME), NULL); g_signal_connect (da, "button_press_event", G_CALLBACK (doMouse), (gpointer) &mouseState); g_signal_connect (da, "button_release_event", G_CALLBACK (doMouse), (gpointer) &mouseState); g_signal_connect (da, "motion_notify_event", G_CALLBACK (doDrag), (gpointer) &mouseState); g_signal_connect (da, "enter_notify_event", G_CALLBACK (doFocus), (gpointer) &mouseState); g_signal_connect (da, "leave_notify_event", G_CALLBACK (doFocus), (gpointer) &mouseState); gtk_widget_set_events (da, gtk_widget_get_events (da) | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); gtk_widget_show_all(topWindow); gtk_window_resize (GTK_WINDOW (topWindow), 300, 350); gtk_main(); } === END drawingSample.c === _______________________________________________ gtk-list mailing list gtk-list@xxxxxxxxx http://mail.gnome.org/mailman/listinfo/gtk-list