GDK_POINTER_MOTION_HINT_MASK has no effect



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



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