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

problem with delayed update after gtk_widget_draw()



hi all,

i'm having a problem with a a small application, where the
expose_event handler used to copy a backing pixmap onto the
drawing_area widget appears to have an odd delayed effect.

the application is multi-threaded, and in one thread gets a network
packet which has data used to update the backing pixmap.  before
calling any of the gdk_* functions to write to the pixmap, i call
gdk_threads_enter(), do my drawing, call gtk_widget_draw() and finally
gdk_threads_leave() after i'm done.

i've also got the threads_enter/leave around the gtk_main().

problem is, the update doesn't seem to happen.  the expose_event
handler runs ok, but the drawing_area does not change until either 3
or 4 expose_events have been processed, or, until i move the mouse
over the application window.  if i do just one update/expose, the
drawing_area does not get updated (well, i've only waiting for like 10
minutes).

after sending 3 or 4 updates (and thus gtk_widget_draw() is called 3
or 4 times), the drawing_area is updated, but the data might from
either the last or the second last update.

it feels like the X event queue is not being processed in reasonable
time for some reason.  i fear thread problems, but wondered if anyone
had suggestions for stupid error i might have made?

for further oddness, under gdb on Linux (debian 2.1) the problem does
not occur.  under gdb on solaris i get the same broken-ness as normal
execution.


thanks in advance for any ideas,



d



code below has been cut&pasted out of order ... the Elvin stuff is a
notification service which does callbacks in a separate thread (which
calls deliver()).


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


  /* initialise Gtk */
  if (! g_thread_supported()) {
    g_thread_init(NULL);
  }
  gtk_init(&argc, &argv);

  /* create application window */
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(window), "Brisbane");
  gtk_signal_connect(GTK_OBJECT(window), 
		     "destroy", 
		     GTK_SIGNAL_FUNC (quit),
		     NULL);
  vbox = gtk_vbox_new(FALSE, 0);
  gtk_container_add(GTK_CONTAINER(window), vbox);
  gtk_widget_show(vbox);

  /* create the drawing area */
  drawing_area = gtk_drawing_area_new();
  gtk_drawing_area_size(GTK_DRAWING_AREA(drawing_area), 370, 220);
  gtk_box_pack_start(GTK_BOX(vbox), drawing_area, TRUE, TRUE, 0);
  gtk_widget_show(drawing_area);

  /* connect to Elvin */
  elvin = elvin_connect(EC_NAMEDHOST, "localhost", 5678, 
			NULL, NULL, 
			NULL, NULL, 
			0);

  /* create weather model */
  w = weather_alloc();

  /* create weather view */
  wv = weather_view_alloc(drawing_area);

  /* paint initial view contents */
  gtk_widget_show(window);
  weather_view_update(wv, w);

  /* subscribe to weather updates */
  weather_sub = elvin_add_subscription(elvin,
				       "exists(org.elvin.weather)",
				       deliver,
				       NULL,
				       1);
  /* ok, go! */
  gdk_threads_enter();
  gtk_main();
  gdk_threads_leave();

  exit(0);
}


void deliver(elvin_t elvin, void *arg, uint32 sub_id, en_notify_t nfn)
{
  en_type_t  type;
  void       *value;

  g_print("deliver\n");
  if (! en_search(nfn, "temp", &type, &value)) {
    weather_set_temp(w, *(float *)value);
  }

  en_free(nfn);

  /* update GUI */
  weather_view_update(wv, w);

  return;
}


void weather_view_update(weather_view_t wv, weather_t w)
{
  GdkRectangle update_rect;
  char         buf[100];

  gdk_threads_enter();

  /* clear background */
  gdk_draw_rectangle(pixmap,
		     wv->drawing_area->style->white_gc,
		     TRUE,
		     0, 0,
		     wv->drawing_area->allocation.width,
		     wv->drawing_area->allocation.height);

  /* temperature */
  snprintf(buf, 4, "%2.0f\260", weather_get_temp(w));
  gdk_draw_string(pixmap, 
		  wv->temp->font, 
		  wv->drawing_area->style->black_gc, 
		  15, 74, buf);

  snprintf(buf, 10, "min %2.1f", weather_get_temp_min(w));
  gdk_draw_string(pixmap, 
		  wv->detail->font, 
		  wv->drawing_area->style->black_gc, 
		  110, 62, buf);

  snprintf(buf, 10, "max %2.1f", weather_get_temp_max(w));
  gdk_draw_string(pixmap, 
		  wv->detail->font, 
		  wv->drawing_area->style->black_gc, 
		  110, 74, buf);

  /* force redraw onto window */
  update_rect.x = 0;
  update_rect.y = 0;
  update_rect.width = wv->drawing_area->allocation.width;
  update_rect.height = wv->drawing_area->allocation.height;

  gtk_widget_draw(wv->drawing_area, &update_rect);

  gdk_threads_leave();

  return;
}


static gint expose_event(GtkWidget *widget, GdkEventExpose *event)
{
  /* copy the backing pixmap into the drawing area */
  gdk_draw_pixmap(widget->window,
		  widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
		  pixmap,
		  event->area.x, event->area.y,
		  event->area.x, event->area.y,
		  event->area.width, event->area.height);
  g_print("expose (copied pixmap to widget->window)\n");
  
  return FALSE;
}




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