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: [email protected]
  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 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();
  }

  int    startX, 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;
      gint                x, 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) {
           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
    [email protected]
    http://mail.gnome.org/mailman/listinfo/gtk-list


_______________________________________________
gtk-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/gtk-list

Reply via email to