After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 412882 - gdkwindow should support the concept of "composited"
gdkwindow should support the concept of "composited"
Status: RESOLVED FIXED
Product: gtk+
Classification: Platform
Component: Backend: X11
unspecified
Other Linux
: Normal normal
: ---
Assigned To: Allison Karlitskaya (desrt)
gtk-bugs
Depends on:
Blocks:
 
 
Reported: 2007-02-28 01:31 UTC by Allison Karlitskaya (desrt)
Modified: 2007-11-28 23:14 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
xcomposite support in gdk (16.47 KB, patch)
2007-03-18 02:21 UTC, Allison Karlitskaya (desrt)
needs-work Details | Review
xcomposite support in gdk (21.09 KB, patch)
2007-03-20 04:24 UTC, Allison Karlitskaya (desrt)
needs-work Details | Review
xcomposite support in gdk (19.85 KB, patch)
2007-04-03 00:26 UTC, Allison Karlitskaya (desrt)
none Details | Review
test case for the new patch (2.03 KB, text/plain)
2007-04-03 00:32 UTC, Allison Karlitskaya (desrt)
  Details
xcomposite support in gdk (19.96 KB, patch)
2007-04-03 03:40 UTC, Allison Karlitskaya (desrt)
none Details | Review
updated test case (2.48 KB, text/plain)
2007-04-03 03:41 UTC, Allison Karlitskaya (desrt)
  Details
xcomposite support in gdk (clean) (16.85 KB, patch)
2007-04-03 04:16 UTC, Allison Karlitskaya (desrt)
none Details | Review
example application screenshot (6.37 KB, image/png)
2007-05-23 00:17 UTC, Allison Karlitskaya (desrt)
  Details
composite example code (4.09 KB, text/plain)
2007-05-23 00:19 UTC, Allison Karlitskaya (desrt)
  Details
my patch (26.71 KB, patch)
2007-06-01 04:29 UTC, Matthias Clasen
committed Details | Review

Description Allison Karlitskaya (desrt) 2007-02-28 01:31:20 UTC
if you take a look at gdk_window_invalidate_maybe_recurse() it contains code to clip the invalidate region when child windows overlap it.

the logic goes like this:

if the child window is not input-only:
  subtract the area that the child overlaps the parent from the redraw region
  if (recurse)
    emit expose event on the child for this region

of course, when a child is composited, we really want the expose event to go to the parent and not at all to the child.

for this reason, gdkwindows should support the concept of being "composited".  for now, all i really need is for this to be a flag that can be flipped on and off.  no support is required for making the XComposite calls, but perhaps this could be added too.

the exact semantics of this is that the logic in gdk_window_invalidate_maybe_recurse would treat composited windows _exactly_ as it treats input-only windows.

specifically:
1) the parts of child windows overlapping their parent would not be clipped from the expose region for the parent

2) the child windows would never receive expose events as a result of their parent window being invalidated.


point 1 really needs to be done.  point 2 is a bit more up for debate.

some comments on 2:
a) the child doesn't need these expose events since it is composited (and therefore pixmap-backed).  chances are that people who are playing around with composited windows will be quite aware of exactly what they want to do with them and can therefore send these events themselves, if need be.

b) if you send the child expose events it causes the child to redraw itself.  this causes damage notification which will cause the parent to want to invalidate itself again (to recomposite the child's contents).  in the best case this leads to extra processing and if you're not careful it can cause infinite loops.

c) on the other hand, if the user calls invalidate with recurse set to TRUE it's probably because they want their child windows to receive expose events.

the real problem in this debate, of course, is that gtk internally generates invalidates.  when the user calls invalidate, they can just do what they want to do -- but they might get angry at what gtk does.
Comment 1 Allison Karlitskaya (desrt) 2007-02-28 01:40:04 UTC
oh.  i forgot to address an issue:

you might say something like the following:

"if the invalidate recurses to children then the child windows will receive expose events and redraw themselves, generating damage notifications.  the code watching for these notifications could then use _this_ notification to draw the updated image."

this fails to be true when the entire body of the composited window is overlapped by a non-composited window like a GtkPlug in another process.  the draw will be entirely clipped by the opaque sub-child window (as it should be).  even if the draw occured, it would be obscured by the window.

then you say "well.  that's fine, since the child will cause the invalidate on the parent to be obscured but the child will receive the event and draw itself!"

of course, in the case of a GtkPlug, the window belongs to another process so there is no way to even propagate the invalidate to it (without sending synthetic expose events or something -- but this is _REALLY_ the wrong solution).
Comment 2 Owen Taylor 2007-03-15 21:21:28 UTC
Not sure what the concrete API proposal is here. In terms of:

 2) the child windows would never receive expose events as a result of their
parent window being invalidated.

This is a misunderstanding of what the invalidate_children flag to
gdk_window_invalidate_rect(). The only reason anybody would ever invalidate
descendants is because the *contents* of the descendants changed. That is
unaffected by whether we are compositing those descendants or not.

See the usage in gtk/ for examples.
Comment 3 Allison Karlitskaya (desrt) 2007-03-18 02:21:27 UTC
Created attachment 84812 [details] [review]
xcomposite support in gdk

while talking with owen it was decided that it would be better to implement the actual composite/damage stuff in gdk itself.

this first crack at a patch does that.

feedback is welcome.
Comment 4 Matthias Clasen 2007-03-18 03:07:34 UTC
Looks reasonable at first glance.
No need to update the linux-fb backend though.
Do you have a simple example using this ?
Comment 5 Matthias Clasen 2007-03-19 01:56:59 UTC
Putting one more comment from IRC here:

it may be better to handle the damage events in gdk_event_translate 
instead of adding an event filter for each composited window.
Comment 6 Matthias Clasen 2007-03-20 01:38:53 UTC
Another thing that is really needed here is an example in the api docs that shows how to handle a composited child window in an expose handler.
Comment 7 Allison Karlitskaya (desrt) 2007-03-20 04:24:51 UTC
Created attachment 84934 [details] [review]
xcomposite support in gdk

changed the following things:

  - no longer modify linux-fb

  - erased the filter func

  - moved that code to the gdk_event_translate function (using the example of how xkb and xfixes events are handled there)

as for the docs -- it's not really possible to implement a proper expose event handler until the cairo patch lands: http://bugs.freedesktop.org/show_bug.cgi?id=10329
Comment 8 Allison Karlitskaya (desrt) 2007-03-20 04:35:01 UTC
heh.  please ignore that business about the trayicon.  :)

i was experimenting and it's included by accident.
Comment 9 Owen Taylor 2007-03-20 17:43:08 UTC
+  if (!gdk_display_supports_composite (display) && composited)
+  {

Indentation problem?

Slightly more importantly, the docs for set_composited() should
be written in abstract terms, and not talk about X.

 - Describe what a composited window is (drawn to an offscreen
   buffer, application is responsible for painting on the 
   parent)

 - Say that it isn't universally supported on all window systems
   or window system versions and how to check
 
 - Mention that it only works for child windows

But my main comment would be on the local case; right now, it's a
round-trip to propagate changes to a child owned by the same GDK
process. It would be cool to short-circuit that. I think that 
consists of:

 - Automatically generating invalidations on end_paint() for the
   child (I wouldn't bother with non double-buffered operations)
 - When process updates for a window or all windows, process 
   composited children before parents
 - Remove invalidations from Damage events with the anti-expose
   queue the same way we remove invalidations for expose events.

Comment 10 Allison Karlitskaya (desrt) 2007-04-03 00:26:06 UTC
Created attachment 85736 [details] [review]
xcomposite support in gdk

new patch
Comment 11 Allison Karlitskaya (desrt) 2007-04-03 00:32:11 UTC
Created attachment 85737 [details]
test case for the new patch

owen: here is a test case for the new patch (which i've added a bunch of debug output to for demonstration purposes).

here is what should happen:

0. application requests a redraw (for example, when you mouseover the button)
1. gdk window paint begin on the affected area
2. blah blah blah
3. gdk window paint end
4. i report expose event on the parent window for the painted area _only_ (some subset of the area covered by the composited window)
5. gdk queues antiexpose for this region
6. gdk emits expose event on the parent for this region
7. blah blah blah
8. gdk goes to sleep

9. xdamage event comes in from the server
10. antiexpose area is subtracted from it
11. region is now empty so we don't redraw.

in reality, though, by the time we get to 11 the region is _not_ empty.  the X server appears to over-report damage.  specifically, in this case, it reports that the entire composited window has been damaged when really only a subset of it has been.

this means that the region is non-empty even after the antiexpose is subtracted from it and an expose event still gets dispatched on the parent (for the part of the child that was not affected by the gdk window end paint).

maybe i've just made a mistake, though.
Comment 12 Allison Karlitskaya (desrt) 2007-04-03 00:40:05 UTC
one more thing: i can't figure out a way to get the damage region from the server (as opposed to the bounding rect) and even if i could, it would be an extra round-trip.....
Comment 13 Allison Karlitskaya (desrt) 2007-04-03 03:40:29 UTC
Created attachment 85745 [details] [review]
xcomposite support in gdk

when using the NonEmpty trigger for damage reports the X server sends a null region as the damage event.  it appears that this gets clipped to the window (or something... i don't really fully understand it).

in any case, we can work around this and get X to report the actual area by registering with a BoundingBox trigger.  doing this requires that we are a little bit more careful with respect to reporting which areas we will be repairing so the subtract code is changed a bit too.
Comment 14 Allison Karlitskaya (desrt) 2007-04-03 03:41:34 UTC
Created attachment 85746 [details]
updated test case

here is a better test case.  it draws a small rectangle "dot" once per second to test that draws outside of doublebuffering work too.
Comment 15 Allison Karlitskaya (desrt) 2007-04-03 04:16:30 UTC
Created attachment 85748 [details] [review]
xcomposite support in gdk (clean)

this is the version of the patch that i would commit.

it differs from the other version:
  - all debugging output is removed
  - style fixups (i had a lot of spaces instead of tabs)
  - slight rework of the for loop in the backing store commit code
Comment 16 Matthias Clasen 2007-04-03 04:46:30 UTC
Patch looks good to me, although I can't really test it, since it requires a 
patched X server. It would be good to check for a new enough version of
the composite extension once the X patch actually makes it into a release.

I still think that the docs for set_composited() need an 
example that shows in what way the contents of the redirected child can be
merged into the parent.
Comment 17 Matthias Clasen 2007-04-28 13:10:57 UTC
Ryan, did I recently see a mail by keithp saying that he committed the X server 
change that this requires ? I think he also mentioned bumping the minor version of
the composite extension, so you may want to update your patch to check for that.
Comment 18 Allison Karlitskaya (desrt) 2007-05-23 00:17:55 UTC
Created attachment 88645 [details]
example application screenshot
Comment 19 Allison Karlitskaya (desrt) 2007-05-23 00:19:08 UTC
Created attachment 88646 [details]
composite example code

this is the example code that i propose including.

it's small, simple, self-contained and documented.  you can compile it on its own with no extra code and it works.
Comment 20 Allison Karlitskaya (desrt) 2007-05-23 01:13:12 UTC
prefix the example with the following explanation:

/* An example application showing a possible use of composited GDK
 * windows in a GTK application.
 *
 * In the example, a button is placed inside of an event box inside of
 * a window.  The event box is set as 'composited' and therefore is no
 * longer automatically drawn to the screen.
 *
 * When the contents of the event box change, an expose event is
 * generated on its parent window (which, in this case, belongs to
 * the toplevel GtkWindow).  The expose handler for this widget is
 * responsible for merging the changes back on the screen in the way
 * that it wishes.
 *
 * In our case, we merge the contents with a 50% transparency.  We
 * also set the background colour of the window to red.  The effect is
 * that the background shows through the button.
 *
 * We set the background of the event box to be fully-transparent so
 * that the default GTK background colour from the event box isn't
 * composited along with the button (think: if the current theme draws
 * non-rectangular buttons).
 */
Comment 21 Matthias Clasen 2007-06-01 04:28:03 UTC
Here is an integrated patch; looks ok ?
Comment 22 Matthias Clasen 2007-06-01 04:29:31 UTC
Created attachment 89156 [details] [review]
my patch
Comment 23 Allison Karlitskaya (desrt) 2007-06-01 07:17:18 UTC
looks good to me.  we can add the version-check stuff later once we hear back from keith -- probably just a one-off g_warning when you try to set your first window as composited.


thanks for the gtktest work.


want me to write up a changelog and commit or would you prefer to?
Comment 24 Allison Karlitskaya (desrt) 2007-06-01 07:23:08 UTC
about calling set_composited on a toplevel: it works.

if you setup your own Damage, it might even be a meaningful thing to do...

i really can't think of how i'd use it, though.

of course, things may become confused if you set it, then xcompmgr sets it then you unset it, ...

we could add a check to proscribe people from doing it, but i think it's ok.  i was careful in the double-buffer commit code to make sure that windows with NULL parents didn't cause problems...
Comment 25 Allison Karlitskaya (desrt) 2007-06-01 07:26:34 UTC
oh.  and maybe a note in the demo code that merging the content of your child if your child has children of its own only works properly with (unreleased) cairo 1.6 :)
Comment 26 Matthias Clasen 2007-06-01 12:55:18 UTC
2007-06-01  Matthias Clasen  <mclasen@redhat.com>

        Add support for composited child windows.  (#412882, Ryan Lortie)

        * gdk/gdk.symbols:
        * gdk/gdkdisplay.h:
        * gdk/gdkinternals.h:
        * gdk/gdkwindow.[hc]: Add gdk_display_supports_composite() and
        gdk_window_set_composited().

        * gdk/x11/gdkevents-x11.c:
        * gdk/x11/gdkdisplay-x11.[hc]:
        * gdk/x11/gdkwindow-x11.[hc]: X11 implementation.

        * gdk/win32/gdkdisplay-win32.c:
        * gdk/win32/gdkwindow-win32.c: Dummy win32 implementration.

        * gdk/quartz/gdkdisplay-quartz.c:
        * gdk/quartz/gdkwindow-quartz.c: Dummy Quartz implementation.

        * gdk/directfb/gdkdisplay-directfb.c:
        * gdk/directfb/gdkwindow-directfb.c: Dummy DirectFB implementation.
Comment 27 Allison Karlitskaya (desrt) 2007-06-01 16:38:17 UTC
thanks so much for sticking with this one for so long :)

cheers
Comment 28 Mirco Müller 2007-11-28 23:14:14 UTC
Folks this is sweet stuff. Have a look at the slick things we can do now...
http://macslow.thepimp.net/?p=147 code-example will follow soon.