Re: GDK_POINTER_MOTION_HINT_MASK has no effect
Last post on this I swear, but I thought of another simple improvement. GTK performs expose event compression, that is, when it sends an expose to your program, the expose is the union of all the expose events which the window system generated since your app last saw expose. GTK computes the smallest set of non-overlapping rectangles which are damaged (in event-region), and also the bounding box of that set of rectangles (in event-area). In the code I posted previously I was just using the bounding box of the rects. If you have a large number of images moving around, this will usually be almost the entire display. Very inefficient! Here's a new version of the expose handler which extracts the list of the exact damaged areas and only repaints those. This saves about 20% CPU on my desktop machine, and would save much more if I used small images. - static gboolean expose_cb (GtkDrawingArea * area, GdkEventExpose * event, App * app) { GdkRectangle *rect; int i, j, n; gdk_region_get_rectangles (event-region, rect, n); for (j = 0; j n; j++) { for (i = 0; i app-n; i++) { GdkRectangle repaint; if (gdk_rectangle_intersect (rect[j], 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 (rect[j], app-box, NULL)) gdk_draw_line (GTK_WIDGET (area)-window, GTK_WIDGET (area)-style-white_gc, app-x1, app-y1, app-x2, app-y2); } g_free (rect); return TRUE; } - John ___ gtk-list mailing list gtk-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-list
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; intpix_xmin, pix_xmax; intpix_ymin, pix_ymax; intpix_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 (cg4) // 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 -
Re: GDK_POINTER_MOTION_HINT_MASK has no effect
Hi again Stewart, On Dec 2, 2007 5:12 AM, Stewart Weiss [EMAIL PROTECTED] 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))
RE: GDK_POINTER_MOTION_HINT_MASK has no effect
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: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] Sent: Sunday, December 02, 2007 4:58 PM To: [EMAIL PROTECTED] 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 [EMAIL PROTECTED] 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
RE: GDK_POINTER_MOTION_HINT_MASK has no effect
John, For someone relatively new to GTK like myself, the thread of messages from you, Richard Boaz, and Paul Davis was extremely eye-opening but also confusing. I am grateful to hear the exchange of ideas, to the extent that I understood it. The confusing part is simply trying to decide which of the design principles makes sense for what I am trying to do now, but also trying to extrapolate and understand what principles to follow in general when starting up a new application. I am not fishing for answers here; this problem is mine. I do still have one question about a specific suggestion that you made in this thread, below: -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] Sent: Thursday, November 29, 2007 4:48 PM -- snip -- This is often not the case, especially in a complex application. Instead, you should think of your window as being composed from a number of separate layers (like photoshop layers), and that on an expose you should completely repaint that section of the window by drawing all layers from the back forwards. -- snip -- Assuming it's raster, you should have two separate data structures. Keep a large image around which has the current state of your user's image. Only drawing operations go into this, no rubberbanding. This is your background layer. Rubberband operations are in another layer which floats on top of this. Do you mean a second pixmap? If so, how does one draw the second one on top of the first without replacing pixels, assuming the GC function is just GDK_COPY? On an expose, use your background image to paint the exposed pixels. Then, if there's a rubber band active at the moment and if the bounding box of the rubber band intersects the expose, draw that as well on top of the image. How does one draw layers on top of layers? If I am understanding you correctly, you are saying that I can use one bg pixmap to store one layer, and another pixmap to store a second, higher layer. To be precise, suppose that I have added the original scribble example, tools so that the user can draw shapes in addition to the brush strokes. I keep the drawing the user has created so far in a bg pixmap. Now the user wants to put a line on top of that drawing, and I want to rubberband it. Are you saying that (1) the rubberbanded line is drawn into a second pixmap that is drawn on top of the other, and if so, how does one draw on top without obscuring the pixels underneath using a straightforward GDK_COPY function in the gc, or (2) do you mean that I should draw into the window, not a second pixmap, after I have drawn the bg pixmap underneath it? I have tried drawing directly into the window for the rubberbanded line, and sending an invalidate_rect event for that line to force a redraw of the rectangle that includes it as I move the mouse, to make it disappear, but the result is that it disappears so fast that it is not visible. Could you clarify? Thanks Stewart ___ gtk-list mailing list gtk-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-list
Re: GDK_POINTER_MOTION_HINT_MASK has no effect
This is the paradigm I use in all my drawing apps that has served me well: 1) Do all drawing to one or more background pixmaps. 2) Do all drawing in routines separate from your configure handler or your expose handler. 3) Call your drawing routine(s) from the configure handler. 4) Once your drawing routine has completed its task, call gtk_widget_queue_draw_area() to force the expose event. 5) Do no drawing in your expose event except to gtk_draw_drawable(), rendering your background pixmap to the physical display. 6) Use temporary pixmaps liberally when rendering a temporary state to the screen. (For example, display of cross-hairs and coordinates when user is simply dragging the mouse (no buttons down) across the drawing area.) You will notice, here, that there is no actual drawing to the physical screen except to render your pixmap. This is the fastest possible manner in which to draw to the screen. As well, the expose handler is called whenever your drawing area is exposed by the window manager, say if it has been partially obscured by other windows and the user brings it to the front. By using gtk_draw_drawable(), you can use the same (x,y) parameters passed to the callback to render only that part of the pixmap requiring exposure, i.e., making it as fast as possible. (Not to mention that to use these (x,y) parameters to programmatically figure out what should be re-drawn is practically impossible.) By maintaining all drawing activity in separate routines, you are able to: 1) have multiple routines responsible for drawing a picture to a single drawing area, determining programmatically which routine should be called at any given moment. These separate routines can draw to separate backing store pixmaps. 2) easily call any drawing routine from anywhere else in your application, including background threads (via g_idle_add()), thus making it trivial to maintain a multi-threaded graphical application. 3) maintain, possibly, multiple backing store pixmaps that can be easily referenced for redrawing without having to go through an entire redraw. (For example, to maintain before and after states of a drawing action. It is much easier to simply re-render a pixmap as part of an Undo operation than to have to remember and redraw the previous state.) Basically, in de-coupling your configure and expose events from actual drawing, you gain much more power in managing all the requirements of your drawing area than if you use a single drawing area that is the screen. Not to mention that drawing directly to the screen is absolutely the slower of the two options. As John's post indicates, there is no single way to do all this; gtk gives you way more than enough rope. The trick is finding the method that works for you and your specific requirements. cheers, richard On Nov 29, 2007 4:30 AM, Stewart Weiss [EMAIL PROTECTED] wrote: Many thanks for these posts. They are moving me closer to a better understanding of the right way to tackle the drawing issues. I still need a bit of clarification. 1. I am assuming that when I queue a draw for the old position of the rubberbanded line, I am using XOR to draw it, so that it is in effect, an erasing, right? 2. You say in the post referenced below that we should really draw only in the expose event handler, not in the motion or button event handlers. Right now, my function to draw a line uses gdk_draw_line into the pixmap and then calls gdk_window_invalidate_rect to send the expose event later. If I actually call the gdk_draw_line in the expose event handler, directly into the pixmap, would I then use gdk_draw_drawable to copy the pixmap into the window? I know I can't queue a drawing event in the handler or else I have an infinite indirect recursive loop. Is this how? Stewart ___ gtk-list mailing list gtk-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-list
Re: GDK_POINTER_MOTION_HINT_MASK has no effect
On Thu, 2007-11-29 at 09:51 +0100, Richard Boaz wrote: This is the paradigm I use in all my drawing apps that has served me well: 1) Do all drawing to one or more background pixmaps. GTK already does this for you now. All widgets are double buffered unless you explicitly request otherwise. So you are currently drawing into your bg pixmap, than GTK will copy it into another bg pixmap and then finally render it to the screen. 2) Do all drawing in routines separate from your configure handler or your expose handler. 3) Call your drawing routine(s) from the configure handler. 4) Once your drawing routine has completed its task, call gtk_widget_queue_draw_area() to force the expose event. 5) Do no drawing in your expose event except to gtk_draw_drawable(), rendering your background pixmap to the physical display. 6) Use temporary pixmaps liberally when rendering a temporary state to the screen. (For example, display of cross-hairs and coordinates when user is simply dragging the mouse (no buttons down) across the drawing area.) richard, i know you have a lot of experience with GTK, but i believe this is the opposite of the design structure of GTK (and X and also Quartz; not sure about win32). i am not saying that it doesn't work - clearly it does. but the internal design of GTK is assuming that drawing occurs inside expose event handlers, and is set up to make this as efficient and smooth as possible. Basically, in de-coupling your configure and expose events from actual drawing, you gain much more power in managing all the requirements of your drawing area than if you use a single drawing area that is the screen. Not to mention that drawing directly to the screen is absolutely the slower of the two options. this is false. ___ gtk-list mailing list gtk-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-list
Re: GDK_POINTER_MOTION_HINT_MASK has no effect
On Nov 29, 2007 1:36 PM, Paul Davis [EMAIL PROTECTED] wrote: On Thu, 2007-11-29 at 09:51 +0100, Richard Boaz wrote: This is the paradigm I use in all my drawing apps that has served me well: 1) Do all drawing to one or more background pixmaps. GTK already does this for you now. All widgets are double buffered unless you explicitly request otherwise. So you are currently drawing into your bg pixmap, than GTK will copy it into another bg pixmap and then finally render it to the screen. Well, this confuses me a bit. Help me understand? Given the following expose handler has been attached to a drawing area: === begin code sample 1 === gboolean exposeME(GtkWidget *da, GdkEventExpose *event, gpointer *nil) { int w = da-allocation.width; int h = da-allocation.height; GdkGC *gc = da-style-fg_gc[GTK_WIDGET_STATE(widget)] // some lines: gdk_draw_line(da-window, gc, w/2, 0, w/2, h); // vertical gdk_draw_line(da-window, gc, 0, h/2, w, h/2); // horizontal gdk_draw_line(da-window, gc, 0, 0, w, h); // diagonal gdk_draw_line(da-window, gc, 0, h, w, 0); // diagonal return TRUE; } === end code sample 2 === I assume the double-buffering occurs at least with each call to gdk_draw_line(), but when is this double-buffer (that you the programmer have no access to, I assume?) actually rendered to the screen? After each call, or only once the expose handler has exited? If this physical event occurs only after the expose handler has exited, then kudos to the GTK+ designers and developers, this is very good. And you are correct, my method employs an extra bg pixmap that is, in this simple case, unnecessary, though in any case, not expensive. *If* this occurs after each call, then I can do better: === begin code sample 2 GdkPixmap *pmap; void drawMe(GtkWidget *da) { int w = da-allocation.width; int h = da-allocation.height; GdkGC *gc = da-style-fg_gc[GTK_WIDGET_STATE(widget)] gdk_draw_line(pmap, gc, w/2, 0, w/2, h); // vertical gdk_draw_line(pmap, gc, 0, h/2, w, h/2); // horizontal gdk_draw_line(pmap, gc, 0, 0, w, h); // diagonal gdk_draw_line(pmap, gc, 0, h, w, 0); // diagonal gtk_widget_queue_draw_area(da, 0, 0, w, h); } gboolean exposeME(GtkWidget *da, GdkEventExpose *event, GdkPixmap *pmap) { int w = da-allocation.width; int h = da-allocation.height; GdkGC *gc = da-style-fg_gc[GTK_WIDGET_STATE(widget)] gdk_draw_drawable(da-window, gc, pmap, event-area.x, event-area.y, event-area.width, event-area.height); return TRUE; } === end code sample 2 === Why better? For at least a couple of reasons. First, the physical event to render to the screen has been reduced to one instead of after each drawing call to da-window in the previous code sample. (Again, depending on when the physical render actually occurs.) Second, double-buffering aside, since (I am assuming here, please correct me if I'm wrong) you the programmer don't have access to this double buffer pmap, if you get an expose event from the window manager using code sample 2, you are making a request for a physical draw that corresponds exactly to those pixels which require being exposed. And this particular case is wholly not addressed in code sample 1; there, you must redraw the entire screen even if only 4 pixels in the lower right corner require a re-draw. As I said before, using the GdkEvent* info to be efficient in redrawing only what's required is impossible, and if not, a complete waste of programming time and resources. In both cases, this equates to a program that is more efficient. Perhaps a negligible increase, but an increase nonetheless. Call me a pedantic purist, but where graphical programming is concerned, anywhere I can find a method that is more efficient than another and that will be the method I choose. For the record, I have always disagreed with the scribble example in the demo code; it gets a simple job done, but in the real world, these things are rarely so simple. 2) Do all drawing in routines separate from your configure handler or your expose handler. 3) Call your drawing routine(s) from the configure handler. 4) Once your drawing routine has completed its task, call gtk_widget_queue_draw_area() to force the expose event. 5) Do no drawing in your expose event except to gtk_draw_drawable(), rendering your background pixmap to the physical display. 6) Use temporary pixmaps liberally when rendering a temporary state to the screen. (For example, display of cross-hairs and coordinates when user is simply dragging the mouse (no buttons down) across the drawing area.) richard, i know you have a lot of experience with GTK, but i believe this is the opposite of the design structure of GTK (and X and also Quartz; not sure about win32). i am not saying that it doesn't work - clearly it
Re: GDK_POINTER_MOTION_HINT_MASK has no effect
On Thu, 2007-11-29 at 16:24 +0100, Richard Boaz wrote: On Nov 29, 2007 1:36 PM, Paul Davis [EMAIL PROTECTED] wrote: On Thu, 2007-11-29 at 09:51 +0100, Richard Boaz wrote: This is the paradigm I use in all my drawing apps that has served me well: 1) Do all drawing to one or more background pixmaps. GTK already does this for you now. All widgets are double buffered unless you explicitly request otherwise. So you are currently drawing into your bg pixmap, than GTK will copy it into another bg pixmap and then finally render it to the screen. Well, this confuses me a bit. Help me understand? [ ... code ] I assume the double-buffering occurs at least with each call to gdk_draw_line(), but when is this double-buffer (that you the programmer have no access to, I assume?) actually rendered to the screen? After each call, or only once the expose handler has exited? If this physical event occurs only after the expose handler has exited, then kudos to the GTK+ designers and developers, this is very good. And you are correct, my method employs an extra bg pixmap that is, in this simple case, unnecessary, though in any case, not expensive. that is precisely what happens. drawing calls made during an expose event handler are redirected into a bg pixmap; at the end of the expose handler, the relevant parts of the bg pixmap are flushed to the screen. And this particular case is wholly not addressed in code sample 1; there, you must redraw the entire screen even if only 4 pixels in the lower right corner require a re-draw. As I said before, using the GdkEvent* info to be efficient in redrawing only what's required is impossible, and if not, a complete waste of programming time and resources. no, there is never any need to do this. expose events always contain information on the region (a collection of 1 or more non-overlapping rectangles) to redraw. this is based either on information from the underlying window system or whatever was passed to gdk_window_invalidate_rect() and its cousins. the only limitation is that GDK generally tiles a drawable with rects no smaller than a given size, so if there were really just 4 pixels to redraw, you'd like end up redrawing 32 or 16 or some such number. As I also stated, a particular method to choose comes down to requirements. I now have an application that has more than 30 drawing areas (across several tabs/screens), each requiring different routines to make their picture. Doing all my drawing in an expose handler means that I must define a different expose handler for each drawing area. But this goes against another principle I have come to embrace, define as few callbacks as possible for widgets to use; I have a single configure and expose handler for all drawing areas, a single callback for all mouse events, drag events, radio button groups, etc. Why? This minimizes the number of routines that are required to exist and be defined, and for me, using nothing more than gedit as my editor, infinitely makes the chore of coding much easier to manage. i didn't suggest unique code per expose handler. i said that all drawing should be done in *an* expose handler. your examples look perfectly sensible and correct to me. you're doing precisely what i was trying to convey as far as callbacks, except that: (a) you're using bg pixmaps that are unnecessary (b) i believe that configure events will be followed by the necessary expose events, so your queue_draw() calls in the configure handler are not required (they won't hurt though) --p ___ gtk-list mailing list gtk-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-list
Re: GDK_POINTER_MOTION_HINT_MASK has no effect
Paul, Thanks for the information, it's good to learn about how GTK+ does its double buffering in detail. However... On Nov 29, 2007 5:22 PM, Paul Davis [EMAIL PROTECTED] wrote: And this particular case is wholly not addressed in code sample 1; there, you must redraw the entire screen even if only 4 pixels in the lower right corner require a re-draw. As I said before, using the GdkEvent* info to be efficient in redrawing only what's required is impossible, and if not, a complete waste of programming time and resources. no, there is never any need to do this. expose events always contain information on the region (a collection of 1 or more non-overlapping rectangles) to redraw. this is based either on information from the underlying window system or whatever was passed to gdk_window_invalidate_rect() and its cousins. the only limitation is that GDK generally tiles a drawable with rects no smaller than a given size, so if there were really just 4 pixels to redraw, you'd like end up redrawing 32 or 16 or some such number. I'm still confused as to how this case should be handled in an expose handler if you do all your drawing there. To illustrate: I have been called once, and GTK+ has drawn to the double buffer pixmap as you say. I was partially obscured and am now re-exposed, i.e., the main loop calls me again specifying an invalidated rectangle via the GdkEvent structure. Do I: 1) redraw the entire picture since I've been called, ignoring all else, knowing this will result in a fully refreshed screen? 2) redraw only that part which was obscured (rectangle parameters provided), having to determine programmatically what drawing commands actually constitute refreshing the obscured portion? 3) know that my drawing hasn't changed its state since the last complete draw and doesn't need to be redrawn at all since upon exiting this call, the double buffer I had previously written to still contains my drawing and will physically refresh only the rectangle which was passed to the expose handler for re-exposure? Naturally I will demand that the third option is really the only acceptable answer since: 1) option 1 is a complete waste of resources when I have to process 100 million data points for drawing to the screen (I exaggerate not). 2) option 2 is simply impossible to make a one-to-one calculation as to which pixels must be refreshed, programmatically. If the third option is how GTK+ handles this scenario (more kudos...), then the expose handler would look something like?: gboolean exposeME(.) { if (redrawRequired || firstTime) { // process 100,000,000 data points to draw to da-window } return TRUE; } If, however, the double buffer no longer exists when called the second time, and I have to take option 1, then it is utterly inefficient to have to redraw the entire screen each time the expose handler is called when I have to do so much to actually redraw. (And besides, what's the invalidated rectangle information used for then anyway?) (Getting a little ahead of myself since I don't know the answer to my previous question yet, but...) If I must do it as per option 1, consider then the two options: Option 1: - draw to da-window in expose handler (...of 100M data points) - expose handler called 10 times by main loop Option 2: - make bg pixmap in separate routine (...of 100M data points) - expose pixmap in expose handler via drawing of bg pixmap - expose handler called 10 times Would you not take option 2 and save the time required to process 900M points of data unnecessarily? Or am I missing something? It just strikes me as more efficient to issue real drawing commands as little as possible, i.e., once to a bg pixmap, and then to draw this pixmap to the screen. Not only is it more efficient (simple less CPU usage), it also makes the application more responsive and snappy since the operation of transferring a pixmap to the screen is instantaneous, while processing 100M data points is, er, not. And we haven't even begun to discuss animations of these drawings. Most definitely in this case, you would want to: - make all your drawings making up the entire animation as bg pixmaps - use g_timeout_add() to invalidate the entire drawing area for redraw, being called over and over until no more drawings - while the expose handler does nothing more than render the next pixmap of the animation sequence to the screen. No? Or would you still do all your drawing in the expose handler for an animation? And I still don't understand why this particular paradigm which works without fail for me is opposite to GTK+ design. It's nothing more than an alternative to the scribble example that, for my requirements, doesn't work. The way I see it, the GTK+ designers and developers have succeeded at doing what you said: to make it as efficient and as smooth as possible, and this they have done well. Is that to say,
Re: GDK_POINTER_MOTION_HINT_MASK has no effect
On 11/29/07, Stewart Weiss [EMAIL PROTECTED] wrote: This also explains why my solution for drawing the line worked reasonably well on Windows but on Linux, the old lines did not get erased. So I guess I have to resort to conditional compilation directives to make it work in both environments. The code I pasted will work well on windows and on linux, you shouldn't need to do any conditional compilation. The line drawing problems are for other reasons ... you should do all drawing in the expose handler. If I get a moment, I'll try to make a small rubber-band example for you. John ___ gtk-list mailing list gtk-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-list
Re: GDK_POINTER_MOTION_HINT_MASK has no effect
On Thu, 2007-11-29 at 20:03 +0100, Richard Boaz wrote: To illustrate: I have been called once, and GTK+ has drawn to the double buffer pixmap as you say. I was partially obscured and am now re-exposed, i.e., the main loop calls me again specifying an invalidated rectangle via the GdkEvent structure. Do I: 1) redraw the entire picture since I've been called, ignoring all else, knowing this will result in a fully refreshed screen? 2) redraw only that part which was obscured (rectangle parameters provided), having to determine programmatically what drawing commands actually constitute refreshing the obscured portion? 3) know that my drawing hasn't changed its state since the last complete draw and doesn't need to be redrawn at all since upon exiting this call, the double buffer I had previously written to still contains my drawing and will physically refresh only the rectangle which was passed to the expose handler for re-exposure? Naturally I will demand that the third option is really the only acceptable answer since: 1) option 1 is a complete waste of resources when I have to process 100 million data points for drawing to the screen (I exaggerate not). 2) option 2 is simply impossible to make a one-to-one calculation as to which pixels must be refreshed, programmatically. for many (perhaps even for an overwhelming majority of applications (2) works just fine. if you application can't do this cheaply, then your approach is the right way. If the third option is how GTK+ handles this scenario (more kudos...), then the expose handler would look something like?: no, GTK discards the bg pixmaps between exposes. they exist primarily to improve the visual appearance of the GUI (by avoid tearing and other artifacts of the drawing process). ___ gtk-list mailing list gtk-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-list
Re: GDK_POINTER_MOTION_HINT_MASK has no effect
On 11/29/07, Stewart Weiss [EMAIL PROTECTED] wrote: 1. I am assuming that when I queue a draw for the old position of the rubberbanded line, I am using XOR to draw it, so that it is in effect, an erasing, right? Actually, I'd suggest using a plain draw rather than an XOR. XOR rubberbanding works if you can treat your display as something you can draw incrementally, that is, you know what is on the screen and therefore you know whether this XOR draw will set or unset a line. This is often not the case, especially in a complex application. Instead, you should think of your window as being composed from a number of separate layers (like photoshop layers), and that on an expose you should completely repaint that section of the window by drawing all layers from the back forwards. Right now, my function to draw a line uses gdk_draw_line into the pixmap and then calls gdk_window_invalidate_rect to send the expose event later. If I actually call the gdk_draw_line in the expose event handler, directly into the pixmap, would I then use gdk_draw_drawable to copy the pixmap into the window? I know I can't queue a drawing event in the handler or else I have an infinite indirect recursive loop. Is this how? Is this a raster drawing program, or a vector one? Assuming it's raster, you should have two separate data structures. Keep a large image around which has the current state of your user's image. Only drawing operations go into this, no rubberbanding. This is your background layer. Rubberband operations are in another layer which floats on top of this. On an expose, use your background image to paint the exposed pixels. Then, if there's a rubber band active at the moment and if the bounding box of the rubber band intersects the expose, draw that as well on top of the image. If you're curious, my app is here: http://www.vips.ecs.soton.ac.uk To see the rubberbanding, load an image, doubleclick the thumbnail to get a view window, then hold down CTRL and click and drag up and left to get a vector, down and right to get a region, just click to get a point, or drag from a ruler to get a guide. If you try resizing outside the edge of the window, the window will scroll in the background. You can move objects around by dragging on their names. Hopefully you'll see all the objects, including the animated ones, float over each other smoothly. There's a simple paintbox on the View menu which also does some rubberbanding with some of the tools. John ___ gtk-list mailing list gtk-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-list
RE: GDK_POINTER_MOTION_HINT_MASK has no effect
John, I will study the application you sent me the link to. My program is not raster; it lets the user draw with a brush or use a line tool in the window. Since the user has drawn with a brush already, the underlying layer is in a pixmap. First I will look at your application's code, and if I cannot figure it out, I will post again. Many thanks Stewart -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] Sent: Thursday, November 29, 2007 4:48 PM To: [EMAIL PROTECTED] Cc: gtk-list Subject: Re: GDK_POINTER_MOTION_HINT_MASK has no effect On 11/29/07, Stewart Weiss [EMAIL PROTECTED] wrote: 1. I am assuming that when I queue a draw for the old position of the rubberbanded line, I am using XOR to draw it, so that it is in effect, an erasing, right? Actually, I'd suggest using a plain draw rather than an XOR. XOR rubberbanding works if you can treat your display as something you can draw incrementally, that is, you know what is on the screen and therefore you know whether this XOR draw will set or unset a line. This is often not the case, especially in a complex application. Instead, you should think of your window as being composed from a number of separate layers (like photoshop layers), and that on an expose you should completely repaint that section of the window by drawing all layers from the back forwards. Right now, my function to draw a line uses gdk_draw_line into the pixmap and then calls gdk_window_invalidate_rect to send the expose event later. If I actually call the gdk_draw_line in the expose event handler, directly into the pixmap, would I then use gdk_draw_drawable to copy the pixmap into the window? I know I can't queue a drawing event in the handler or else I have an infinite indirect recursive loop. Is this how? Is this a raster drawing program, or a vector one? Assuming it's raster, you should have two separate data structures. Keep a large image around which has the current state of your user's image. Only drawing operations go into this, no rubberbanding. This is your background layer. Rubberband operations are in another layer which floats on top of this. On an expose, use your background image to paint the exposed pixels. Then, if there's a rubber band active at the moment and if the bounding box of the rubber band intersects the expose, draw that as well on top of the image. If you're curious, my app is here: http://www.vips.ecs.soton.ac.uk To see the rubberbanding, load an image, doubleclick the thumbnail to get a view window, then hold down CTRL and click and drag up and left to get a vector, down and right to get a region, just click to get a point, or drag from a ruler to get a guide. If you try resizing outside the edge of the window, the window will scroll in the background. You can move objects around by dragging on their names. Hopefully you'll see all the objects, including the animated ones, float over each other smoothly. There's a simple paintbox on the View menu which also does some rubberbanding with some of the tools. John ___ gtk-list mailing list gtk-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-list
Re: GDK_POINTER_MOTION_HINT_MASK has no effect
On Nov 28, 2007 4:27 AM, Stewart Weiss [EMAIL PROTECTED] wrote: Aha! I did not know that I could configure the GC to draw using various functions of the source and dest pixels values. Thanks ! I posted a mail about rubberbanding a couple of months ago: http://mail.gnome.org/archives/gtk-app-devel-list/2007-October/msg7.html Might be helpful. In my opinion, you should structure your program like this: - appstate should have a flag for displaying rubberband line, plus start/end points - in your expose handler, first draw the background for the exposed area, then draw the rubberband liine on top - in your button-press handler, set the rubber band flag and note the start position - in mouse-motion, if rubberband is set and this is a button drag event, queue a draw for the old position of the rubber band line, update appstate with the new position, and queue a draw there too - in button-release, unset the rubber flag and queue a draw for the position of the line John ___ gtk-list mailing list gtk-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-list
RE: GDK_POINTER_MOTION_HINT_MASK has no effect
Thank you. This is a very helpful explanation. I just ran the program you sent on my Linux box, remotely displaying on my Windows box, and sure enough, I see the seen a hint! messages. This also explains why my solution for drawing the line worked reasonably well on Windows but on Linux, the old lines did not get erased. So I guess I have to resort to conditional compilation directives to make it work in both environments. Are there white papers or other documents that explain the GDK implementation on Windows? That would sure make it easier to understand how to build code for both platforms. Stewart -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] Sent: Wednesday, November 28, 2007 3:40 AM To: [EMAIL PROTECTED] Cc: gtk-list@gnome.org Subject: Re: GDK_POINTER_MOTION_HINT_MASK has no effect On Nov 28, 2007 2:44 AM, Stewart Weiss [EMAIL PROTECTED] wrote: I am running this on a Windows box with gtk+ 2.12 installed. Ah, OK. I don't think the windows backend uses the is_hint field, so you can just ignore it. It's because X11 is asynchronous. The window server keeps on trucking (and sending a lot of highly detailed mouse tracking information) even if your program pauses for a moment. As a result, you can get a backlog of mouse events and this causes very annoying lag in your application. The idea of is_hint is that when your program comes back to check for mouse events it just sees an is_hint event, meaning a lot of mouse action has taken place, read the pointer explicitly to get the latest. So you get asynchronous mouse evnts and no lag. Windows is synchronous (the server can never run ahead of the application) so it doesn;t need this mechanism. Just ignnore is_hint and it'll work fine. John ___ gtk-list mailing list gtk-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-list
RE: GDK_POINTER_MOTION_HINT_MASK has no effect
Many thanks for these posts. They are moving me closer to a better understanding of the right way to tackle the drawing issues. I still need a bit of clarification. 1. I am assuming that when I queue a draw for the old position of the rubberbanded line, I am using XOR to draw it, so that it is in effect, an erasing, right? 2. You say in the post referenced below that we should really draw only in the expose event handler, not in the motion or button event handlers. Right now, my function to draw a line uses gdk_draw_line into the pixmap and then calls gdk_window_invalidate_rect to send the expose event later. If I actually call the gdk_draw_line in the expose event handler, directly into the pixmap, would I then use gdk_draw_drawable to copy the pixmap into the window? I know I can't queue a drawing event in the handler or else I have an infinite indirect recursive loop. Is this how? Stewart -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] Sent: Wednesday, November 28, 2007 3:53 AM To: [EMAIL PROTECTED] Cc: gtk-list Subject: Re: GDK_POINTER_MOTION_HINT_MASK has no effect On Nov 28, 2007 4:27 AM, Stewart Weiss [EMAIL PROTECTED] wrote: Aha! I did not know that I could configure the GC to draw using various functions of the source and dest pixels values. Thanks ! I posted a mail about rubberbanding a couple of months ago: http://mail.gnome.org/archives/gtk-app-devel-list/2007-October/msg 7.html Might be helpful. In my opinion, you should structure your program like this: - appstate should have a flag for displaying rubberband line, plus start/end points - in your expose handler, first draw the background for the exposed area, then draw the rubberband liine on top - in your button-press handler, set the rubber band flag and note the start position - in mouse-motion, if rubberband is set and this is a button drag event, queue a draw for the old position of the rubber band line, update appstate with the new position, and queue a draw there too - in button-release, unset the rubber flag and queue a draw for the position of the line John ___ gtk-list mailing list gtk-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-list
Re: GDK_POINTER_MOTION_HINT_MASK has no effect
Hi, I'm not really sure what *is_hint* is intended to provide, but anyway, what you are trying to achieve is totally possible without its use (if I understand you properly). Going on the assumption I do understand what you are trying to achieve, I am providing below some code to illustrate this. Though actual code, it is not runnable in its stand-alone form, you will need to tweak it a bit to make it actually work. However, it does contain all the hooks necessary to do the following: 1. Draw a solid line from point A to point B: point A = point at mouse-down point B = point at mouse-up 2. Draw a dashed line from point A (same as in 1) to Drag Point B: Drag Point B = point at drag event callback I have left out the configure and expose callbacks, I assume that these have been called and produce a pixmap for display, this pixmap being held in the global variable *DAcontents*. (Again, this is to illustrate, not to demonstrate proper coding, you probably shouldn't make a global variable for this purpose.) The mouse event callback: 1. On mouse-down, save the starting point (point A) 2. On mouse-up, draw a solid line from point A to the ending point (point B) and render to the screen. The drag event callback: 1. If mouse is not down, do nothing and return 2. If mouse is down, create temporary pixmap and copy *DAcontents* to it 3. draw a dashed line from point A to Drag Point B (event-x, event-y) on our temp pixmap 4. Render temp pixmap to the screen 5. unref temp pixmap 6. call gdk_window_get_pointer() to tell the main loop we are done with the drag event and are ready to receive another call to the drag event callback Not sure where the problem is in your implementation, but doing these sorts of things with GTK+ is typically not problematic. cheers, richard = begin code === GdkPixmap*DAcontents; GdkGC*gcMain; int main(int argc, char **argv) { GtkWidget*da; gtk_init(argc, argv); da = gtk_drawing_area_new(); g_signal_connect (da, button_press_event, G_CALLBACK (doMouse), NULL); g_signal_connect (da, button_release_event, G_CALLBACK (doMouse), NULL); g_signal_connect (da, motion_notify_event, G_CALLBACK (doDrag), NULL); gtk_widget_set_events (da, gtk_widget_get_events (da) | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); gtk_main(); } intstartX, startY, endX, endY; gboolean mouseDown; gboolean doMouse(GtkWidget *da, GdkEventButton *event, gpointer nothing) { if (!gcMain) gcMain = gdk_gc_new(da-window); switch(event-type) { case GDK_BUTTON_PRESS: startX = event-x; startY = event-y; mouseDown = TRUE; break; case GDK_BUTTON_RELEASE: endX = event-x; endY = event-y; gdk_draw_line(DAcontents, gcMain, startX, startY, endX, endY); gdk_draw_drawable(da-window, da-style-fg_gc[GTK_STATE_NORMAL], DAcontents, 0, 0, 0, 0, -1, -1); mouseDown = FALSE; break; } return TRUE; } gboolean doDrag (GtkWidget *da, GdkEventMotion *event, gpointer nothing) { GdkModifierType state; gintx, y; GdkPixmap*pixmap; static GdkGC*gcDash=NULL; if (!gcDash) {// first time call setup gcDash = gdk_gc_new(da-window); gdk_gc_set_line_attributes(gcDash, 1, GDK_LINE_ON_OFF_DASH, 0, 0); } switch(mouseDown) { case FALSE: break; case TRUE: pixmap = gdk_pixmap_new(da-window, da-allocation.width, da- allocation.height, -1); gdk_draw_drawable(pixmap, da-style-fg_gc[GTK_STATE_NORMAL], DAcontents, 0, 0, 0, 0, -1, -1); gdk_draw_line(pixmap, gcDash, startX, startY, event-x, event-y); gdk_draw_drawable(da-window, da-style-fg_gc[GTK_STATE_NORMAL], pixmap, 0, 0, 0, 0, -1, -1); g_object_unref(pixmap); break; } gdk_window_get_pointer(event-window, x, y, state); return TRUE; } = end code === On Nov 27, 2007 3:27 AM, Stewart Weiss [EMAIL PROTECTED] wrote: I have been playing around with the motion_notify_event callback in the Scribble example from the tutorial, and I have discovered that none of what the documentation states is correct. I modified the handler to generate output on the standard outout device as follows: gboolean motion_notify_event( GtkWidget *widget, GdkEventMotion *event, gpointer *mydata ) { int x, y; GdkModifierType state; if (event-is_hint) {
Re: GDK_POINTER_MOTION_HINT_MASK has no effect
Hi, I'm not really sure what is_hint is intended to provide, but anyway, what you are trying to achieve is totally possible without its use (if I understand you properly). Going on the assumption I do understand what you are trying to achieve, I am providing below some code to illustrate this. Though actual code, it is not runnable in its stand-alone form, you will need to tweak it a bit to make it actually work. However, it does contain all the hooks necessary to do the following: 1. Draw a solid line from point A to point B: point A = point at mouse-down point B = point at mouse-up 2. Draw a dashed line from point A (same as in 1) to Drag Point B: Drag Point B = point at drag event callback I have left out the configure and expose callbacks, I assume that these have been called and produce a pixmap for display, this pixmap being held in the global variable DAcontents. (Again, this is to illustrate, not to demonstrate proper coding, you probably shouldn't make a global variable for this purpose.) The mouse event callback: 1. On mouse-down, save the starting point (point A) 2. On mouse-up, draw a solid line from point A to the ending point (point B) and render to the screen. The drag event callback: 1. If mouse is not down, do nothing and return 2. If mouse is down, create temporary pixmap and copy DAcontents to it 3. draw a dashed line from point A to Drag Point B (event-x, event-y) on our temp pixmap 4. Render temp pixmap to the screen 5. unref temp pixmap 6. call gdk_window_get_pointer() to tell the main loop we are done with the drag event and are ready to receive another call to the drag event callback Not sure where the problem is in your implementation, but doing these sorts of things with GTK+ is typically not problematic. cheers, richard = begin code === GdkPixmap*DAcontents; GdkGC*gcMain; int main(int argc, char **argv) { GtkWidget*da; gtk_init(argc, argv); da = gtk_drawing_area_new(); g_signal_connect (da, button_press_event, G_CALLBACK (doMouse), NULL); g_signal_connect (da, button_release_event, G_CALLBACK (doMouse), NULL); g_signal_connect (da, motion_notify_event, G_CALLBACK (doDrag), NULL); gtk_widget_set_events (da, gtk_widget_get_events (da) | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); gtk_main(); } intstartX, startY, endX, endY; gboolean mouseDown; gboolean doMouse(GtkWidget *da, GdkEventButton *event, gpointer nothing) { if (!gcMain) gcMain = gdk_gc_new(da-window); switch(event-type) { case GDK_BUTTON_PRESS: startX = event-x; startY = event-y; mouseDown = TRUE; break; case GDK_BUTTON_RELEASE: endX = event-x; endY = event-y; gdk_draw_line(DAcontents, gcMain, startX, startY, endX, endY); gdk_draw_drawable(da-window, da-style-fg_gc[GTK_STATE_NORMAL], DAcontents, 0, 0, 0, 0, -1, -1); mouseDown = FALSE; break; } return TRUE; } gboolean doDrag (GtkWidget *da, GdkEventMotion *event, gpointer nothing) { GdkModifierType state; gintx, y; GdkPixmap*pixmap; static GdkGC*gcDash=NULL; if (!gcDash) {// first time call setup gcDash = gdk_gc_new(da-window); gdk_gc_set_line_attributes(gcDash, 1, GDK_LINE_ON_OFF_DASH, 0, 0); } switch(mouseDown) { case FALSE: break; case TRUE: pixmap = gdk_pixmap_new(da-window, da- allocation.width, da-allocation.height, -1); gdk_draw_drawable(pixmap, da-style-fg_gc[GTK_STATE_NORMAL], DAcontents, 0, 0, 0, 0, -1, -1); gdk_draw_line(pixmap, gcDash, startX, startY, event-x, event-y); gdk_draw_drawable(da-window, da-style-fg_gc[GTK_STATE_NORMAL], pixmap, 0, 0, 0, 0, -1, -1); g_object_unref(pixmap); break; } gdk_window_get_pointer(event-window, x, y, state); return TRUE; } = end code === ___ gtk-list mailing list gtk-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-list
Re: GDK_POINTER_MOTION_HINT_MASK has no effect
On Nov 27, 2007 2:27 AM, Stewart Weiss [EMAIL PROTECTED] wrote: Does anyone know what the real semantics are, and when is_hint is true? Here's a complete small program that shows mouse events (with hints) for a drawing area. -- /* compile with * gcc -g -Wall try32.c `pkg-config gtk+-2.0 --cflags --libs` */ #include stdio.h #include gtk/gtk.h static gboolean event_cb (GtkWidget * widget, GdkEvent * ev) { gboolean handled; handled = FALSE; switch (ev-type) { case GDK_BUTTON_PRESS: printf (button %d press\n, ev-button.button); handled = TRUE; break; case GDK_BUTTON_RELEASE: printf (button %d release\n, ev-button.button); handled = TRUE; break; case GDK_MOTION_NOTIFY: /* A hint? Read the position to get the latest value. */ if (ev-motion.is_hint) { GdkDisplay *display = gtk_widget_get_display (widget); GdkScreen *screen; int x_root, y_root; printf (seen a hint!\n); gdk_display_get_pointer (display, screen, x_root, y_root, NULL); ev-motion.x_root = x_root; ev-motion.y_root = y_root; } printf (motion at %g x %g\n, ev-motion.x_root, ev-motion.y_root); if (ev-motion.state GDK_BUTTON1_MASK) printf ((and btn1 held down)\n); if (ev-motion.state GDK_BUTTON2_MASK) printf ((and btn2 held down)\n); handled = TRUE; break; default: break; } return (handled); } int main (int argc, char **argv) { GtkWidget *win; GtkWidget *area; gtk_init (argc, argv); win = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (win, destroy, G_CALLBACK (gtk_main_quit), NULL); area = gtk_drawing_area_new (); gtk_widget_add_events (GTK_WIDGET (area), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); gtk_signal_connect_after (GTK_OBJECT (area), event, GTK_SIGNAL_FUNC (event_cb), NULL); gtk_container_add (GTK_CONTAINER (win), area); gtk_window_set_default_size (GTK_WINDOW (win), 250, 250); gtk_widget_show_all (win); gtk_main (); return (0); } You get output like: seen a hint! motion at 1367 x 446 seen a hint! motion at 1368 x 446 button 1 press seen a hint! motion at 1368 x 447 (and btn1 held down) button 2 press seen a hint! motion at 1368 x 448 (and btn1 held down) (and btn2 held down) John ___ gtk-list mailing list gtk-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-list
RE: GDK_POINTER_MOTION_HINT_MASK has no effect
Thanks for the code, BUT... when I run it exactly as you typed it below, I get NO output lines that say seen a hint! no matter how I move the mouse and press the buttons. I get all other outputs: all button down and release and motion at r x c type messages. No hints. I am running this on a Windows box with gtk+ 2.12 installed. Stewart -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] Sent: Tuesday, November 27, 2007 9:30 AM To: [EMAIL PROTECTED] Cc: gtk-list@gnome.org Subject: Re: GDK_POINTER_MOTION_HINT_MASK has no effect On Nov 27, 2007 2:27 AM, Stewart Weiss [EMAIL PROTECTED] wrote: Does anyone know what the real semantics are, and when is_hint is true? Here's a complete small program that shows mouse events (with hints) for a drawing area. -- /* compile with * gcc -g -Wall try32.c `pkg-config gtk+-2.0 --cflags --libs` */ #include stdio.h #include gtk/gtk.h static gboolean event_cb (GtkWidget * widget, GdkEvent * ev) { gboolean handled; handled = FALSE; switch (ev-type) { case GDK_BUTTON_PRESS: printf (button %d press\n, ev-button.button); handled = TRUE; break; case GDK_BUTTON_RELEASE: printf (button %d release\n, ev-button.button); handled = TRUE; break; case GDK_MOTION_NOTIFY: /* A hint? Read the position to get the latest value. */ if (ev-motion.is_hint) { GdkDisplay *display = gtk_widget_get_display (widget); GdkScreen *screen; int x_root, y_root; printf (seen a hint!\n); gdk_display_get_pointer (display, screen, x_root, y_root, NULL); ev-motion.x_root = x_root; ev-motion.y_root = y_root; } printf (motion at %g x %g\n, ev-motion.x_root, ev-motion.y_root); if (ev-motion.state GDK_BUTTON1_MASK) printf ((and btn1 held down)\n); if (ev-motion.state GDK_BUTTON2_MASK) printf ((and btn2 held down)\n); handled = TRUE; break; default: break; } return (handled); } int main (int argc, char **argv) { GtkWidget *win; GtkWidget *area; gtk_init (argc, argv); win = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (win, destroy, G_CALLBACK (gtk_main_quit), NULL); area = gtk_drawing_area_new (); gtk_widget_add_events (GTK_WIDGET (area), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); gtk_signal_connect_after (GTK_OBJECT (area), event, GTK_SIGNAL_FUNC (event_cb), NULL); gtk_container_add (GTK_CONTAINER (win), area); gtk_window_set_default_size (GTK_WINDOW (win), 250, 250); gtk_widget_show_all (win); gtk_main (); return (0); } You get output like: seen a hint! motion at 1367 x 446 seen a hint! motion at 1368 x 446 button 1 press seen a hint! motion at 1368 x 447 (and btn1 held down) button 2 press seen a hint! motion at 1368 x 448 (and btn1 held down) (and btn2 held down) John ___ gtk-list mailing list gtk-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-list
RE: GDK_POINTER_MOTION_HINT_MASK has no effect
Richard: Thanks for this suggestion. Last night after sending the message, I did, in fact, resort to doing pretty much what you suggested below, by getting the mouse-down, then tracking it with button-motion-notify, and then getting the mouse-up event. But I am not using a temporary pixmap, and I have to erase each previously drawn line. What I want to achieve is a typical Line Tool, like the one in Windows Paint, one that will continuously redraw the line as I drag the mouse. In order to solve this, in my motion-notify-event handler I erase the previous line by drawing it on the window (not the pixmap) using the background color of my pixmap, then draw a new one in the window (not in the pixmap). When I get the mouse up event, I draw the last line into the pixmap and render it to the screen. But I still have some problems. When I erase the previous line, I also erase pixels that might have been drawn as part of something else in the window, so my solution is that when I get the button-up event I invalidate the entire window to redraw it. But until I release the mouse button, the erase pixels remain erased. I was thinking of invalidating the rectangle containing the line each time to se if that would work, but I have not tried it yet (busy day). But any other ideas would be appreciated. The motion event handler is basically this (with stuff removed because I use the same handler to draw free-form lines with a brush): gboolean motion_notify_event( GtkWidget *widget, GdkEventMotion *event, ApplicationState *appState ) { int x, y; GdkModifierType state; if (event-is_hint) { gdk_window_get_pointer (event-window, x, y, state); } else { state = event-state; if (state GDK_BUTTON1_MASK appState-pixmap != NULL appState-isLineToolOn ) erase_line ( widget, appState, line_start_x, line_start_y, line_end_x, line_end_y ); x = event-x; y = event-y; } if (state GDK_BUTTON1_MASK appState-pixmap != NULL appState-isLineToolOn ) { line_end_x = x; line_end_y = y; draw_line ( widget, appState, line_start_x, line_start_y, line_end_x, line_end_y, FALSE ); } return TRUE; } The appState is just a struct that has all the application data in it. The button press event callback handles both down and up events: gboolean button_press_event( GtkWidget *widget, GdkEventButton *event, ApplicationState *appState ) { const gboolean finalize = TRUE; if ( event-button == 1 appState-pixmap != NULL appState-isLineToolOn) { if ( event-type == GDK_BUTTON_PRESS ) { line_start_x = event-x; line_start_y = event-y; } else if ( event-type == GDK_BUTTON_RELEASE appState-isLineToolOn) { draw_line ( widget, appState, line_start_x, line_start_y, line_end_x, line_end_y, finalize); } } return TRUE; } Thanks for the help Stewart -Original Message- From: richard boaz [mailto:[EMAIL PROTECTED] Sent: Tuesday, November 27, 2007 6:19 AM To: [EMAIL PROTECTED] Cc: gtk-list@gnome.org Subject: Re: GDK_POINTER_MOTION_HINT_MASK has no effect Hi, I'm not really sure what is_hint is intended to provide, but anyway, what you are trying to achieve is totally possible without its use (if I understand you properly). Going on the assumption I do understand what you are trying to achieve, I am providing below some code to illustrate this. Though actual code, it is not runnable in its stand-alone form, you will need to tweak it a bit to make it actually work. However, it does contain all the hooks necessary to do the following: 1.. Draw a solid line from point A to point B: point A = point at mouse-down point B = point at mouse-up 2.. Draw a dashed line from point A (same as in 1) to Drag Point B: Drag Point B = point at drag event callback I have left out the configure and expose callbacks, I assume that these have been called and produce a pixmap for display, this pixmap being held in the global variable DAcontents. (Again, this is to illustrate, not to demonstrate proper coding, you probably shouldn't make a global variable for this purpose.) The mouse event callback: 1.. On mouse-down, save the starting point (point A) 2.. On mouse-up, draw a solid line from point A to the ending point (point B) and render to the screen. The drag event callback: 1.. If mouse is not down, do nothing and return 2.. If mouse is down, create temporary pixmap and copy DAcontents to it 3.. draw a dashed line
RE: GDK_POINTER_MOTION_HINT_MASK has no effect
Aha! I did not know that I could configure the GC to draw using various functions of the source and dest pixels values. Thanks ! Stewart -Original Message- From: Paul Davis [mailto:[EMAIL PROTECTED] Sent: Tuesday, November 27, 2007 11:13 PM To: [EMAIL PROTECTED] Cc: richard boaz; gtk-list@gnome.org Subject: RE: GDK_POINTER_MOTION_HINT_MASK has no effect On Tue, 2007-11-27 at 22:17 -0500, Stewart Weiss wrote: Richard: Thanks for this suggestion. Last night after sending the message, I did, in fact, resort to doing pretty much what you suggested below, by getting the mouse-down, then tracking it with button-motion-notify, and then getting the mouse-up event. But I am not using a temporary pixmap, and I have to erase each previously drawn line. What I want to achieve is a typical Line Tool, like the one in Windows Paint, one that will continuously redraw the line as I drag the mouse. In order to solve this, in my motion-notify-event handler I erase the previous line by drawing it on the window (not the pixmap) using the background color of my pixmap, then draw a new one in the window (not in the pixmap). When I get the mouse up event, I draw the last line into the pixmap and render it to the screen. But I still have some problems. When I erase the previous line, I also erase pixels that might have been drawn as part of something else in the window, so my solution is that when I get the button-up event I invalidate the entire window to redraw it. But until I release the mouse button, the erase pixels remain erased. I was thinking of invalidating the rectangle containing the line each time to se if that would work, but I have not tried it yet (busy day). But any other ideas would be appreciated. google for draw xor gtk and read on ... ___ gtk-list mailing list gtk-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-list
RE: GDK_POINTER_MOTION_HINT_MASK has no effect
On Tue, 2007-11-27 at 22:17 -0500, Stewart Weiss wrote: Richard: Thanks for this suggestion. Last night after sending the message, I did, in fact, resort to doing pretty much what you suggested below, by getting the mouse-down, then tracking it with button-motion-notify, and then getting the mouse-up event. But I am not using a temporary pixmap, and I have to erase each previously drawn line. What I want to achieve is a typical Line Tool, like the one in Windows Paint, one that will continuously redraw the line as I drag the mouse. In order to solve this, in my motion-notify-event handler I erase the previous line by drawing it on the window (not the pixmap) using the background color of my pixmap, then draw a new one in the window (not in the pixmap). When I get the mouse up event, I draw the last line into the pixmap and render it to the screen. But I still have some problems. When I erase the previous line, I also erase pixels that might have been drawn as part of something else in the window, so my solution is that when I get the button-up event I invalidate the entire window to redraw it. But until I release the mouse button, the erase pixels remain erased. I was thinking of invalidating the rectangle containing the line each time to se if that would work, but I have not tried it yet (busy day). But any other ideas would be appreciated. google for draw xor gtk and read on ... ___ gtk-list mailing list gtk-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-list
GDK_POINTER_MOTION_HINT_MASK has no effect
I have been playing around with the motion_notify_event callback in the Scribble example from the tutorial, and I have discovered that none of what the documentation states is correct. I modified the handler to generate output on the standard outout device as follows: gboolean motion_notify_event( GtkWidget *widget, GdkEventMotion *event, gpointer *mydata ) { int x, y; GdkModifierType state; if (event-is_hint) { gdk_window_get_pointer (event-window, x, y, state); g_print ( is hint at %d, %d\n, x, y ); } else { x = event-x; y = event-y; state = event-state; g_print ( is not hint at %d, %d\n, x, y ); } I have set events on the widget using all 8 possible combinations of the three masks: GDK_POINTER_MOTION_MASK GDK_BUTTON_MOTION_MASK GDK_POINTER_MOTION_HINT_MASK What I have found is that the event-is_hint IS NEVER true, regardless of the masks I set on the widget. What IS TRUE is that when the GDK_BUTTON_MOTION_MASK is set on the widget, with or without the GDK_POINTER_MOTION_HINT_MASK, the only signals emitted by the widget are when the mouse button is down while the pointer is in motion. This is contrary to what is written in the GDK Reference Manual. Because the is hint at ... is never displayed, it also implies that gdk_window_get_pointer() is never called. I was trying to implement a straight-line tool and I had hoped that I could detect the starting and ending points using the fact that the is_hint member would be true only when the window was entered, or a button press or release event (as it says in the tutorial.) I figured I could get the point when the mouse button was first pressed and then wait until the mouse button was released to write the line into my pixmap. Does anyone know what the real semantics are, and when is_hint is true? Stewart ___ gtk-list mailing list gtk-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-list