bug in Cairo or Gtk - peculiar behaviour on resizing or exposing window



I am hoping someone will have the time to look at this. I have been
developing a gtk/cairo program to draw views of the Mandelbrot set. I
wanted to show how the usual iteration progressed for an arbitrary
starting point; it worked but occasionally seemed to misbehave. Below is
a cut-back version which illustrates the problem. A left click with the
mouse sets a starting point which behaves correctly; a right click sets
a nearby point which produces a very similar figure but which
misbehaves. To see this first try resizing the window - for some sizes
it is drawn correctly but for others not. With a bad version, slide
another window in front and then away to the side, when the picture is
redrawn correctly. Then try minimising it and restoring it, which makes
it go wrong again.
I am using gtk2-2.22.0-1.fc14.1.x86_64, cairo-1.10.0-2.fc14.x86_64 and
gcc-4.5.1-4.fc14.x86_64

So, first: have I done something wrong (probably in draw_iter())?

If not, is there a bug in gtk or gdk or cairo ?

Many thanks for any help

James Bridge

=======================================================================

/*  mbrot.c  
    compile with: 
    cc `pkg-config --cflags gtk+-2.0 --libs gtk+-2.0` mbrot.c -lm
*/

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

typedef struct {gdouble x, y;} complex_t;

GtkWidget *map;
complex_t cc = {0., 0.};

/******************************************************************************/

static gdouble step (complex_t* z, const complex_t* c);
void draw_iter (GtkWidget *area, const complex_t *c);
static void destroy( GtkWidget *widget, gpointer data );
static gboolean expose_event( GtkWidget *widget, GdkEventExpose *event, 
                                                                                gpointer data );
static gboolean button_pressed (GtkWidget* widget, GdkEventButton*
event, 
                                gpointer data);
static gboolean motion_notify (GtkWidget* map, GdkEventMotion* event, 
                                 GtkLabel *z_label);

/******************************************************************************/

static gdouble step (complex_t* z, const complex_t* c)
{
   gdouble xsq = z->x * z->x;
   gdouble ysq = z->y * z->y;
   z->y = 2 * z->x * z->y + c->y;
   z->x = xsq - ysq + c->x;
   return xsq + ysq;
}

/******************************************************************************/

void draw_iter (GtkWidget *area, const complex_t *c)
{       
        GtkAllocation alloc;
        gtk_widget_get_allocation (area, &alloc);
        gdouble scale = 3.5 / alloc.width;

        gint n;
        gdouble r;
        complex_t z = cc;
        cairo_t *cra = gdk_cairo_create (gtk_widget_get_window (area));
        cairo_translate (cra, 0.5, 0.5);
   cairo_set_source_rgb (cra, .2, .2, .2);
   cairo_set_line_width (cra, 1.0);
   cairo_move_to (cra, (z.x + 2.5) / scale, - (z.y - 1.4) / scale);
   for (n = 0; n < 70; n++)

      if ((r = step (&z, c)) > 9.0) 
        return;
   for (; n < 100; n++)
   {
      if ((r = step (&z, c)) > 9.0) 
        break;
      cairo_line_to (cra, (z.x + 2.5) / scale, - (z.y - 1.4) / scale);
    }
   cairo_stroke (cra);
   cairo_destroy (cra);
   return;
}

/******************************************************************************/

static void destroy( GtkWidget *widget, gpointer data )
{
   gtk_main_quit ();
}

/******************************************************************************/

static gboolean
expose_event( GtkWidget *area, GdkEventExpose *event, gpointer data )
{
        if (cc.x != 0)
                draw_iter (area, &cc);

return FALSE;
}

/******************************************************************************/

static gboolean button_pressed (GtkWidget* map, GdkEventButton* event, 
                                 gpointer data)
{
        if (event->button == 1)
        {
                cc.x = -.99439;
                cc.y = 0.2626584; 

        gdk_window_invalidate_rect (gtk_widget_get_window (map), NULL,
FALSE);
        }
        else if (event->button == 3)
   {
                cc.x = -.99063;
                cc.y = 0.26797; 

        gdk_window_invalidate_rect (gtk_widget_get_window (map), NULL,
FALSE);
        }
   return FALSE;
}

/******************************************************************************/

gint main (gint argc, char* argv[])
{  
   GtkWidget *window, *vbox, *hbox, *z_label, *start_button;
   gtk_init (&argc, &argv);
   
   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
   map = gtk_drawing_area_new ();
   gtk_widget_set_can_focus (map, TRUE);
   gtk_widget_set_size_request (map, 500, 400);
   gtk_widget_add_events (map, GDK_BUTTON_PRESS_MASK );
   gtk_container_add (GTK_CONTAINER (window), map);
   g_signal_connect (G_OBJECT (window), "delete-event",
                     G_CALLBACK (destroy), NULL);
   g_signal_connect (G_OBJECT (map), "expose-event",
                     G_CALLBACK (expose_event), NULL);
   g_signal_connect (G_OBJECT (map), "button-press-event",
                     G_CALLBACK (button_pressed), NULL);
   gtk_widget_show_all (window);
   gtk_main ();
   return 0;
}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]