hi,

the problem isn't the mouse going "too fast" (this is "not possible", if it
can go fast, it can), it's that you're wanting to draw a line using points.

drawing a real line between the last point received by the drag event and
the new/next point will get you what you want, example code below.

and to answer your question, yes it can be made more efficient.

cheers,

richard

p.s. be careful re: your callback parameters, your drag function defined the
2nd argument wrong.

======== BEGIN CODE EXAMPLE ========

#include <string.h>
#include <gtk/gtk.h>

enum {
 MOUSE_CLICK,
MOUSE_DRAG,
 TTL_MOUSE_EVENTS
};

static inline void brush(cairo_t *cr, double x1, double y1, double x2,
double y2)
{
cairo_move_to(cr, x1, y1);
 cairo_line_to(cr, x2, y2);
cairo_stroke(cr);
}

static gboolean handle_mouse(GtkWidget *widget, void *e, gpointer *t)
{
static struct {
 gboolean isdragging;
cairo_t *cr;
 double x, y;
} mouseState;
 gint type = GPOINTER_TO_INT(t);
 switch(type)
 {
case MOUSE_CLICK:
 {
GdkEventButton *event = (GdkEventButton*) e;
 switch(event->type)
{
 case GDK_BUTTON_PRESS:
{
 mouseState.isdragging = TRUE;
mouseState.cr = gdk_cairo_create(widget->window);
 cairo_set_source_rgb(mouseState.cr, 0, 0, 0);
cairo_set_line_width(mouseState.cr, 2);
 mouseState.x = event->x; mouseState.y = event->y;
 }
break;
 case GDK_BUTTON_RELEASE:
{
 cairo_destroy(mouseState.cr);
memset(&mouseState, 0, sizeof(mouseState));
 }
break;
 default:
break;
 }
}
 break;
 case MOUSE_DRAG:
{
 GdkEventMotion *event = (GdkEventMotion*) e;
static GdkWindow *gdkWindow;

if (!gdkWindow)
 { // initialize
 gdkWindow = gdk_get_default_root_window();
memset(&mouseState, 0, sizeof(mouseState));
 return TRUE;
}

if (!mouseState.isdragging ||
     (mouseState.x == event->x && mouseState.y == event->y))
 return TRUE;

 brush(mouseState.cr, mouseState.x, mouseState.y, event->x, event->y);
 mouseState.x = event->x; mouseState.y = event->y;

{
 // even though we don't use the resulting information from this call,
 // calling it is an indication to the main_loop()
// that we are ready to receive the next mouse motion notify event
 gint x, y;
GdkModifierType state;
 gdk_window_get_pointer(gdkWindow, &x, &y, &state);
}
 }
break;
 default:
break;
 }

 return TRUE;
}

int main( int argc,
          char *argv[] )
{
  GtkWidget *window;
  GtkWidget *main_vbox;

  gtk_init (&argc, &argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC
(gtk_main_quit), "WM destroy");
  gtk_widget_set_usize (GTK_WIDGET(window), 300, 200);

  main_vbox = gtk_vbox_new (FALSE, 1);
  gtk_container_border_width (GTK_CONTAINER (main_vbox), 1);
  gtk_container_add (GTK_CONTAINER (window), main_vbox);
  gtk_widget_show (main_vbox);

  //gtkdrawable + cairo
  GtkWidget *canvas = gtk_drawing_area_new();
  gtk_widget_set_size_request (canvas, 500, 600);

  //gtk_widget_add_events(canvas, GDK_BUTTON_PRESS_MASK);
  gtk_widget_add_events(canvas, GDK_ALL_EVENTS_MASK);
  g_signal_connect(canvas, "button-press-event", G_CALLBACK(handle_mouse),
GINT_TO_POINTER(MOUSE_CLICK));
  g_signal_connect(canvas, "button-release-event", G_CALLBACK(handle_mouse),
GINT_TO_POINTER(MOUSE_CLICK));
  g_signal_connect(canvas, "motion-notify-event",G_CALLBACK(handle_mouse),
GINT_TO_POINTER(MOUSE_DRAG));

  gtk_box_pack_start (GTK_BOX (main_vbox), canvas, FALSE, TRUE, 0);

  //ends gtkdrawable + cairo example
  gtk_widget_show_all (window);
  gtk_main ();

  return(0);
}

======== END CODE EXAMPLE ========

2011/7/23 Carlos López Camey <[email protected]>

> Hello, I'm new to the list, GTK+ and C. I'm building a Paint-like
> application and was trying how to simulate the Brush tool with an
> example to see how it performs. I read about GtkImage, GtkBitmap and
> GtkPixmap but was recommended in #gtk+ over at irc.gnome.org to use a
> GtkDrawingArea + Cairo since in GTK3 some of these were deprecated,
> and it's encouraged to use cairo surfaces instead.
>
> The problem with my example is, when you click and "brush" with the
> mouse moving *too fast*, the signal doesn't come fast enough. What
> could/would be faster? using pixbufs + GtkImage? I couldn't find
> enough documentation about that, but that's why I am asking :)
>
> Here's what I got (or if you prefer http://paste.pocoo.org/show/444721/)
>
> Thank you!
>
> ----- canvas-test.c ------
> #include <gtk/gtk.h>
>
> int isdragging = 0;
>
> /* Brush, paints a single pixel in coordinate x,y*/
> void brush(cairo_t *cr, double x, double y){
>  cairo_set_source_rgb(cr, 0, 0, 0);
>  cairo_set_line_width (cr, 1);
>  cairo_rectangle(cr,x,y,1,1);
>  cairo_stroke(cr);
>  cairo_destroy(cr);
> }
>
> gboolean handle_mouse_click(GtkWidget *widget, GdkEventButton *event,
> gpointer user_data){
>  brush(gdk_cairo_create(widget->window), event->x, event->y);
>  isdragging = 1;
>  return TRUE;
> }
>
> gboolean handle_mouse_release(GtkWidget *widget, GdkEventButton
> *event, gpointer user_data){
>  if (event->button == 1) {
>    isdragging = 0;
>  }
>
>  return TRUE;
> }
>
> gboolean handle_mouse_drag(GtkWidget *widget, GdkEventButton *event,
> gpointer user_data){
>  if (isdragging)
>    brush(gdk_cairo_create(widget->window), event->x, event->y);
>  return TRUE;
> }
>
> int main( int argc,
>          char *argv[] )
> {
>  GtkWidget *window;
>  GtkWidget *main_vbox;
>
>  gtk_init (&argc, &argv);
>
>  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
>  gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC
> (gtk_main_quit), "WM destroy");
>  gtk_widget_set_usize (GTK_WIDGET(window), 300, 200);
>
>  main_vbox = gtk_vbox_new (FALSE, 1);
>  gtk_container_border_width (GTK_CONTAINER (main_vbox), 1);
>  gtk_container_add (GTK_CONTAINER (window), main_vbox);
>  gtk_widget_show (main_vbox);
>
>  //gtkdrawable + cairo
>  GtkWidget *canvas = gtk_drawing_area_new();
>  gtk_widget_set_size_request (canvas, 500, 600);
>
>  //gtk_widget_add_events(canvas, GDK_BUTTON_PRESS_MASK);
>  gtk_widget_add_events(canvas, GDK_ALL_EVENTS_MASK);
>  g_signal_connect(canvas, "button-press-event",
> G_CALLBACK(handle_mouse_click), NULL);
>  g_signal_connect(canvas, "button-release-event",
> G_CALLBACK(handle_mouse_release), NULL);
>  g_signal_connect(canvas,
> "motion-notify-event",G_CALLBACK(handle_mouse_drag), NULL);
>
>  gtk_box_pack_start (GTK_BOX (main_vbox), canvas, FALSE, TRUE, 0);
>
>  //ends gtkdrawable + cairo example
>  gtk_widget_show_all (window);
>  gtk_main ();
>
>  return(0);
> }
> _______________________________________________
> 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