Re: Muffling widget repaints
BTW, I'm writing towards GTK+ 2.4. On Sat, Aug 21, 2004 at 02:16:52PM -0400, Stephen Bach wrote: > Hello, > > I have a container which periodically loses some of its widgets and gains > others, sometimes on the order of hundreds. The changeover happens all at > once (i.e. there's a big loop which does all the adding and destroying), but > it's still pretty ugly and slow because sometimes many repaints are done. I > only care about the final repaint. > > Is there some way that I can prevent the intervening repaints from happening? > I've tested hiding and reshowing the container, and it is indeed much faster, > but of course I don't want the user to see the container disappear. Ideally > I'd have the "before" painting sit until the widget switch-over is done, and > then display the "after" painting. > > I was hoping gdk_window_freeze_updates() and gdk_window_thaw_updates() would > help, but they don't seem to do anything. As a test I even tried freezing > the root gdk window right before calling gtk_main() (and after showing its > widget), but the program proceeded normally. Maybe I'm not understanding > what these functions are for. > > Any insight would be very welcome. > > Thanks > > ___ > 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
Re: Muffling widget repaints
>I have a container which periodically loses some of its widgets and gains >others, sometimes on the order of hundreds. The changeover happens all at >once (i.e. there's a big loop which does all the adding and destroying), but >it's still pretty ugly and slow because sometimes many repaints are done. I >only care about the final repaint. by "repaint" do you mean an "expose" signal? you should only be drawing within an expose handler (there is one exception: drawing into an off-screen drawable, typically a pixmap). drawing at any other time is just not the correct model. --p ___ gtk-list mailing list [EMAIL PROTECTED] http://mail.gnome.org/mailman/listinfo/gtk-list
Re: Muffling widget repaints
When I say "repaint" I just mean that the there is a visible change in the widget. I guess I'm not using the word in its conventional GTK sense. FWIW, I did connect to the expose signal of the container and found that it's only called once, after the widget switchover is finished. Which I guess is ideal. But the container still appears to be being updated ("repainted" in my incorrect terminology) many times during the switchover. For example, I can sometimes see the the container's children repositioning themselves. On Sat, Aug 21, 2004 at 02:22:56PM -0400, Paul Davis wrote: > >I have a container which periodically loses some of its widgets and gains > >others, sometimes on the order of hundreds. The changeover happens all at > >once (i.e. there's a big loop which does all the adding and destroying), but > >it's still pretty ugly and slow because sometimes many repaints are done. I > >only care about the final repaint. > > by "repaint" do you mean an "expose" signal? you should only be > drawing within an expose handler (there is one exception: drawing into > an off-screen drawable, typically a pixmap). drawing at any other time > is just not the correct model. > > --p > > ___ gtk-list mailing list [EMAIL PROTECTED] http://mail.gnome.org/mailman/listinfo/gtk-list
Re: Muffling widget repaints
I've come up with an acceptable solution to my problem, which I'll post here for posterity. First my observations: - The expose signal for the container was emitted only once, and after all the widgets had been added/removed. This is good and means GTK is being smart, and that gdk_window_freeze_updates() wouldn't help me. - If I left the container showing, a changeover involving 2000 widgets took about 30 seconds, with X cpu usage hovering at about 85% and the program's cpu usage at about 15% (i.e. all of it). During the switchover, I could see widgets in the container shifting periodically, but the container never fully redrew itself during the switchover (and expose-event was not emitted). - If I hid the container immediately before the changeover and showed it directly afterwards, the changeover took only about 3 seconds, and X cpu usage only seemed to reach about 40% and the program's about the same. Eventually I found that most of the processing was because of (or related to) size negotiations. The container received size-request and size-allocate signals for each widget added/removed. Since only the final size-request/size-allocate pair was relevant, I took out the gtk_widget_queue_resize() calls from the pack and remove functions of the container. This worked great for the removal, but for the packing I'd still get the size negotiation thrashing as soon as I gtk_widget_show'd the new children (whether I did so before adding them or after they were all added). So I connected to the size-request signal of the container and added a condition to prevent signal propagation if it was during a switchover. This works okay -- it takes about 8 seconds for a changeover. Certainly there's a more complete solution, and hopefully something a little more elegant (insight welcome), but it'll do for now. ___ gtk-list mailing list [EMAIL PROTECTED] http://mail.gnome.org/mailman/listinfo/gtk-list
Re: Muffling widget repaints
Hi, This sounds like a very similar problem I'm having. I'm curious if you have some test case code that you could post? thanks, Todd Stephen Bach wrote: I've come up with an acceptable solution to my problem, which I'll post here for posterity. First my observations: - The expose signal for the container was emitted only once, and after all the widgets had been added/removed. This is good and means GTK is being smart, and that gdk_window_freeze_updates() wouldn't help me. - If I left the container showing, a changeover involving 2000 widgets took about 30 seconds, with X cpu usage hovering at about 85% and the program's cpu usage at about 15% (i.e. all of it). During the switchover, I could see widgets in the container shifting periodically, but the container never fully redrew itself during the switchover (and expose-event was not emitted). - If I hid the container immediately before the changeover and showed it directly afterwards, the changeover took only about 3 seconds, and X cpu usage only seemed to reach about 40% and the program's about the same. Eventually I found that most of the processing was because of (or related to) size negotiations. The container received size-request and size-allocate signals for each widget added/removed. Since only the final size-request/size-allocate pair was relevant, I took out the gtk_widget_queue_resize() calls from the pack and remove functions of the container. This worked great for the removal, but for the packing I'd still get the size negotiation thrashing as soon as I gtk_widget_show'd the new children (whether I did so before adding them or after they were all added). So I connected to the size-request signal of the container and added a condition to prevent signal propagation if it was during a switchover. This works okay -- it takes about 8 seconds for a changeover. Certainly there's a more complete solution, and hopefully something a little more elegant (insight welcome), but it'll do for now. ___ 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
Re: Muffling widget repaints
Hi Todd, > This sounds like a very similar problem I'm having. I'm curious if you > have some test case code that you could > post? My testing was all done within the context of my program, but I can try. The containers in question are WrapBox, which I've based on the GtkWrapBox class from Gimp 2.0, and its subclass FileBox. Here's most of the packing function, with the relevant changes commented. Both this and the removal function are called with do_resize == FALSE during the changeover. void wrap_box_pack_pos(WrapBox* wbox, GtkWidget* child, guint pos, gboolean do_resize) { /* This variable added. */ WrapBoxChild* child_info; g_return_if_fail(IS_WRAP_BOX (wbox)); g_return_if_fail(GTK_IS_WIDGET (child)); g_return_if_fail(child->parent == NULL); child_info = g_new(WrapBoxChild, 1); child_info->widget = child; /* snipping out irrelevant child insertion code */ gtk_widget_set_parent(child, GTK_WIDGET(wbox)); if (GTK_WIDGET_REALIZED(wbox)) gtk_widget_realize(child); if (GTK_WIDGET_VISIBLE(wbox) && GTK_WIDGET_VISIBLE(child)) { if (GTK_WIDGET_MAPPED(wbox)) gtk_widget_map(child); if (do_resize) /* This conditional added. */ gtk_widget_queue_resize (child); } } And the removal function with a similar change: void wrap_box_remove(GtkContainer* container, GtkWidget* widget, gboolean do_resize) { /* This variable added. */ WrapBox* wbox = WRAP_BOX(container); WrapBoxChild *child, *last = NULL; child = wbox->children; while (child) { if (child->widget == widget) { gboolean was_visible; was_visible = GTK_WIDGET_VISIBLE(widget); gtk_widget_unparent(widget); if (last) last->next = child->next; else wbox->children = child->next; g_free(child); wbox->n_children--; if (was_visible && do_resize) /* && do_resize added here */ gtk_widget_queue_resize(GTK_WIDGET (container)); break; } last = child; child = last->next; } } In the initialization of the subclass object: static void file_box_init(FileBox *fbox) { GTK_WIDGET_SET_FLAGS (fbox, GTK_NO_WINDOW); fbox->optimal_width = 0; fbox->show_hidden_files = FALSE; fbox->n_files = 0; fbox->file_max = 32767; fbox->file_display_limit = DEFAULT_FILE_DISPLAY_LIMIT; fbox->fi_slist = NULL; /* This class variable and the next line added. */ fbox->eat_size_requests = FALSE; g_signal_connect(fbox, "size-request", G_CALLBACK(size_request_kludge), NULL); } And the callback function: static gboolean size_request_kludge(GtkWidget* widget, GtkRequisition* requisition, gpointer data) { FileBox* fbox = FILE_BOX(widget); return fbox->eat_size_requests; } Then before entering the add/remove loop, this function is called with FALSE, and then with TRUE afterward: static void file_box_allow_size_requests(FileBox* fbox, gboolean allow) { if (fbox->eat_size_requests != allow) return; if (allow) { fbox->eat_size_requests = FALSE; gtk_widget_queue_resize(GTK_WIDGET(fbox)); /* ^^^ This is the final size request, and the only one to go through. */ } else fbox->eat_size_requests = TRUE; } Hopefully that's clear and of some use. ___ gtk-list mailing list [EMAIL PROTECTED] http://mail.gnome.org/mailman/listinfo/gtk-list