I happened to see a mail list conversation about drawing rubberbanding
lines that gave me enough examples to start to answer my own question,
and code that does what I want is below. Here's what I think I
learned, corrections welcome, and a question:
1. You can draw shapes with the gdk drawing functions, such as
gdk_draw_line, by writing on the widget's "window" member.
1a (?The window this draws on is a gdk window, not a gtk window.?)
2. GTK only notifies your event box of mouse movements if you say:
gtk_widget_add_events(eventbox, GDK_POINTER_MOTION_MASK)
If there's a alternate/better way to go about this, I'd be happy to hear.
Note that you have to have a readable graphic file named
/home/levin/ex.jpg for this program. If you don't, either edit the
program to reflect a valid name on your system or update to a
distribution that includes a readable jpg file with that name.
Code:
#include <gtk/gtk.h>
/* compile with
gcc lines.c -Wall -o runme `pkg-config --cflags --libs gtk+-2.0`
*/
static gboolean cross_pointer (GtkWidget *widget,
GdkEventMotion *event,
gpointer user_data) ;
int main(int argc, char *argv[]) {
GError *openError = NULL ;
GtkWidget *window, *box, *image, *eventbox ;
GdkPixbuf *bigPicture ;
gtk_init(&argc, &argv) ;
bigPicture = gdk_pixbuf_new_from_file( "/home/levin/ex.jpg", &openError) ;
image = gtk_image_new_from_pixbuf( bigPicture ) ;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (gtk_main_quit), NULL);
/* put the image in an event box. The window associated with the
event box has to enable GDK_POINTER_MOTION_MASK. For user data,
send the image so that the cross_pointer function can restore
from image when mouse moves away
*/
eventbox = gtk_event_box_new() ;
g_signal_connect (G_OBJECT (eventbox), "motion_notify_event",
G_CALLBACK (cross_pointer), image) ;
gtk_widget_add_events(eventbox, GDK_POINTER_MOTION_MASK ) ;
gtk_container_add(GTK_CONTAINER ( eventbox ), image ) ;
box = gtk_vbox_new (FALSE, 5 );
gtk_box_pack_start( GTK_BOX(box), eventbox, FALSE, FALSE, 0);
gtk_container_add( GTK_CONTAINER (window), box);
gtk_widget_show_all(window) ;
gtk_main() ;
return 0 ;
}
static gboolean cross_pointer (GtkWidget *widget,
GdkEventMotion *event,
gpointer image)
{
static gint h, w, X, Y ; /* h&w: height & width of event box;
X,Y mouse pointer coordinates */
static gboolean initialized = FALSE ;
if( initialized ) {
/*
Line have previouslybeen drawn; X & Y are set. Redraw from the image IF
it's not the same as the new line. Usually, the motion is only
in the x or y direction, so one of the lines, she is still valid
*/
if((gint)event->x != X) {
/* we moved horiz - get rid of old horiz line */
gtk_widget_queue_draw_area( image, X, 0, 1, h+1) ;
}
if((gint)event->y != Y ) {
/* we move vertically - remove the old vertical line */
gtk_widget_queue_draw_area( image, 0, Y, w+1, 1) ;
}
}
else {
w = widget->allocation.width-1 ;
h = widget->allocation.height-1 ; /* get size of box */
initialized = TRUE ;
}
X = (gint) event->x ;
Y = (gint) event->y ; /* where the mouse is */
/* first draw horiz line */
gdk_draw_line( GTK_WIDGET (image)->window,
GTK_WIDGET (image)->style->white_gc,
0, Y, w, Y ) ;
/* and then draw vert line */
gdk_draw_line( GTK_WIDGET (image)->window,
GTK_WIDGET (image)->style->white_gc,
X, 0, X, h ) ;
return TRUE ;
}