RE: GDK_POINTER_MOTION_HINT_MASK has no effect
- From: "Stewart Weiss" <stewart weiss acm org>
- To: "richard boaz" <ivor boaz gmail com>
- Cc: gtk-list gnome org
- Subject: RE: GDK_POINTER_MOTION_HINT_MASK has no effect
- Date: Tue, 27 Nov 2007 22:17:14 -0500
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
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:
- Draw a solid line from point A to point B:
point A = point at
mouse-down
point B = point at mouse-up
- 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:
- On mouse-down, save the starting point (point A)
- 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:
- If mouse is not down, do nothing and return
- If mouse is down, create temporary pixmap and copy DAcontents to
it
- draw a dashed line from point A to Drag Point B (event->x,
event->y) on our temp pixmap
- Render temp pixmap to the screen
- unref temp pixmap
- 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 <
stewart weiss acm org> 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
gtk-list gnome org
http://mail.gnome.org/mailman/listinfo/gtk-list
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]