GNOME Bugzilla – Bug 679144
Gdk doesn't properly find the child area with alpha
Last modified: 2012-08-23 14:45:02 UTC
With latest gnome-themes-standard there is a very nasty flash whenever you click on the toolbar.
Created attachment 217627 [details] [review] Fix nasty flashing when clicking on toolbar The spice widget is non-double-buffered, which interacts poorly with transparent windows. What happens in this case is that the EvenBox that the spice widet is inside is transparent, but its parent (the window is not). When drawing the window gdk believes the area under the EventBox is transparent, so its drawn by the window, and then not drawn as transparent by the EventBox. When we get to the non-double buffered spice widget we need to flush the current double buffer pixmap which temporarily shows the window background before drawing the spice contents. The fix here is to make the EventBox get a solid background. However, I don't believe this should be necessary. Gdk should know that the spice widgets window is opaque and fully covers the evenbox, so it should not have to paint the window background under the eventbox. I believe this should be fixable in Gtk+.
Comment on attachment 217627 [details] [review] Fix nasty flashing when clicking on toolbar Attachment 217627 [details] pushed as 493b670 - Fix nasty flashing when clicking on toolbar
Refiling against Gtk+. We should really fix this in Gdk, so that when a child window has_alpha_background we should not always make all that area layered, if it has opaque children.
This is still causing some pretty nasty flashing in gnome-boxes (due to the Spice Widget disabling double buffering). We have a (simplified) hierarchy something like this:. A - GtkWindow window | +-> B - Transparent GdkWindow | +> C - Solid GdkWindow with double buffering disabled When drawing A we fill in (into the double-buffer) the background color. Historically this would have not cleared any area that had a child window in it, but with the new alpha bg support we only clip out children that are fully opaque. So, in this case we will clear the bg under B. This will also cover the area where C will later overdraw, which is not typically a problem apart from some unnecessary drawing. However, In this case C is drawn without double buffering, which means we have to "flush" the current double-buffer data before drawing it. We then copy the currently rendered data there (the bg from A) to the window (so that the window has the correct data so far), and then the non-double-buffered rendering in C happens. This guarantees the correct rendering even in cases where the expose handler in C draws things with alpha, or if it somehow mixes double buffered drawing with direct rendering. But it also creates a flash, as the A background is temporarily visible on the screen. The "correct" solution for this would be to fully track the child region such that in a case like the above the region for C would be clipped out when you render to C. However, calculating clip regions like that is extremely expensive as it means any change in window positions/size/order can propagate to changes in the whole window hierarchy. A more reasonable fix is to avoid the flush operation on C copying the partially drawn background to the window, thus avoiding the flash. This would make it buggy to have a non-double-buffered expose handler draw with opacity, which isn't really a big deal imho. It would also mean that you can't mix double buffering with direct drawing. Today this means calling any of: gdk_window_flush, _raise, _lower, _move, _resize, _scroll inside the expose handler of a double buffered widget. We do have some code that handles this currently, by automatically flushing as per above if you call any of these. But that would break if we disable the copy-partial-double-buffer-contents-to-window operation. However, it seems to me that moving windows etc in an expose handler is pretty fringe and we should be able to ignore that in order to get the "typical" non-db case (widgets that already have a double buffered pixbuf and just draws it in expose) without flickering.
Created attachment 222228 [details] [review] Fix flashing in non-double-buffered widgets Avoid copying back partially drawn double-buffer data when flushing to avoid flicker. This means non double buffered widgets must draw opaque pixels in its expose handlers, and that you are not allowed to use direct rendering (or modify GdkWindow pos/size/order) from inside the expose handler of a double buffered widget. See https://bugzilla.gnome.org/show_bug.cgi?id=679144 for more details
Created attachment 222229 [details] [review] Remove gdk_window_flush_if_exposing as its not needed anymore We no longer support modifying GdkWindow hierarchies during expose events. This is not working anymore anyway as the flush operation now does not push already rendered pixels in the flushed window from the double buffer to the window.
Attachment 222229 [details] pushed as 29a4208 - Remove gdk_window_flush_if_exposing as its not needed anymore