Page 1 of 1
Windows API / XDamage equivalent?
Posted: Thu Sep 30, 2010 12:04 am
by Jeff250
I'm unfortunately naive when it comes to the Windows API. Unix/X11 has an API extension called XDamage that you can use to listen for \"damage\" events from other windows to get notified when a region has been changed. For example, one possible use case is to improve the performance of video screen capture. Instead of copying the entire contents of the window to a buffer on some interval, you can just keep a copy of the window in a buffer and only update damaged regions. In a case where all that is happening is a small cursor blinking, you can see how this would be a huge performance optimization, since you would just have to copy the region of the cursor every time it appeared/disappeared. (There are rare cases that you can imagine where this would be a pessimization too, but it's not too hard to detect when this is happening.) Does anyone know if the Windows API have an equivalent? I'm sure it does, but it's hard to google for, since they usually use terminology that I wouldn't have anticipated. Thanks in advance.
Posted: Thu Sep 30, 2010 1:53 am
by Sirius
There's stuff about what's called an \"update region\" in subsections of the WM_PAINT article under GDI:
http://msdn.microsoft.com/en-us/library ... 85%29.aspx
I think that's about the best I can find on short notice. Long story short I'm not sure this clips other windows out of the update region - there is probably a way to do it though, it just might be a bit more complex.
Posted: Thu Sep 30, 2010 12:04 pm
by Foil
x2, you're looking for WM_PAINT messages.
For Vista/7, you'll probably also want to look into Desktop Composition (
MSDN link).
Posted: Thu Sep 30, 2010 12:45 pm
by Jeff250
Thanks--WM_PAINT looks close, but I'm not sure if this is what I want. These events look like what is sent to the client when part of the window becomes invalidated and needs to be repainted. So, for example, if you move window Y so that it partially overlaps window X, and then close Window Y, then X needs to know that the rectangle where Y overlapped is now invalidated (unless you are using desktop compositing) and that it should repaint that region (if it is sensible) so that you can see that part of X again. But to clarify, I'm not really interested when a client is notified to repaint because of an invalidated region. I would like to be notified if and when Window X paints anything, maybe after it repaints an invalidated region, or maybe after each change of frame of an animated image, or maybe after it blinks a cursor, and so on. (This is what the X11 API calls \"damage,\" which may be an unfortunate term...) Preferably, I would like for one client to listen in on these events of another. Is this still WM_PAINT?
I don't think that desktop composition will be useful for me. I need to have a buffer in CPU memory so that I can do things like save it to disk or send it over the network. So whether the model is the classic one where all windows are drawn to some common frame in video memory or whether each window is drawn to its own texture in video memory, I would think that copying a rectangle the size of the window from video to CPU memory is equally expensive in both cases.
Re:
Posted: Thu Sep 30, 2010 1:59 pm
by Foil
Jeff250 wrote:I would like to be notified if and when Window X paints anything, maybe after it repaints an invalidated region, or maybe after each change of frame of an animated image, or maybe after it blinks a cursor, and so on.
Ah, understood.
I believe you're correct. WM_PAINT messages from the OS may not necessarily catch all of those, particularly if the app is handling some painting outside the message handler.
Off the top of my head, I don't know of anything exposed in the API which covers every single paint action.
That said, I'd suggest looking into the InvalidateRect and/or InvalidateRgn window functions; they generate quite a few WM_PAINTs, and might provide a way to catch most of the "rest" of the paints.
Jeff250 wrote:Preferably, I would like for one client to listen in on these events of another. Is this still WM_PAINT?
8 or 9 years ago, I had an app watching for messages sent to remote windows (via a dll hook at that time). I'm sure it's still possible. Spy++ (a Visual Studio tool) is an example of an app which can give you the messages handled by a given window. [Plus, it's pretty handy at times!]
Jeff250 wrote:I don't think that desktop composition will be useful for me. ... I would think that copying a rectangle the size of the window from video to CPU memory is equally expensive in both cases.
Understood, you're probably correct. I've seen some issues with desktop comp (our OpenGL/Direct3D app doesn't play nicely with it sometimes), but I haven't seen a performance difference.
Posted: Thu Sep 30, 2010 7:04 pm
by Jeff250
I'd prefer robustness over efficiency, so if there's nothing sure-fire, then I'll just copy the entire window on some interval for the Windows-specific code. Although before that, if no one knows of anything, I'll probably spend some time this weekend finding and digging through some open source Windows VNC or desktop recording type apps and see if they know about something we don't.
Foil wrote:I believe you're correct. WM_PAINT messages from the OS may not necessarily catch all of those, particularly if the app is handling some painting outside the message handler.
In fact, in a desktop compositing environment, I'm hard-pressed to think of a reason for a WM_PAINT event to be sent after the window has been created, although I'm sure this is my lack of imagination.
Foil wrote:That said, I'd suggest looking into the InvalidateRect and/or InvalidateRgn window functions; they generate quite a few WM_PAINTs, and might provide a way to catch most of the "rest" of the paints.
I'm not sure if I follow. How would I know which regions in the window to invalidate? It seems like if I knew enough to do this, then I wouldn't have to.
Posted: Fri Oct 01, 2010 12:44 am
by Sirius
I'd be surprised if there aren't tools for detecting the window messages sent to a window - was thinking for a minute that I'd used one for UI testing but it was actually MSAA events, which are slightly different (basically fired by the application updating its UI, rather than being told to).
Re:
Posted: Fri Oct 01, 2010 1:29 am
by Jeff250
Sirius wrote:basically fired by the application updating its UI
But this is what I want--or at least it's the closest mentioned so far! Any time application Y paints anything, whether it's a WinForms button or a pink rectangle via GDI or something via some Windows API I've never heard of, I'd like application X to know!
When I google MSAA, all I get is a reference to "Microsoft Active Accessibility" though.
Posted: Fri Oct 01, 2010 4:10 am
by Sirius
I see. Hmm.
You do have the correct meaning of MSAA by the way. The issue is that it will only pick up events that are exposed to MSAA, and I don't think that includes raw GDI paint operations - though there might be something out there that does.
I think the tool in question was AccEvent, which is mentioned here (along with installation instructions):
http://blogs.msdn.com/b/winuiautomation ... s-sdk.aspx
Now, something that detects
any draw by another program... that might be possible, especially if you can trap any kind of GDI call (not sure whether comctl stuff uses GDI, but it has to draw buttons somehow). Don't know for sure whether anyone's done it though, and you'd pretty much have to run the application in administrator mode for it to have access to that kind of thing.
Re:
Posted: Fri Oct 01, 2010 2:11 pm
by Foil
Jeff250 wrote:In fact, in a desktop compositing environment, I'm hard-pressed to think of a reason for a WM_PAINT event to be sent after the window has been created...
Anytime any part of the window gets invalidated (another window is moved over it, etc.), it will get a WM_PAINT/WM_NCPAINT. This happens pretty often; if you watch a Spy++ log for a given window, you see those messages pretty frequently.
For example, one of my apps constantly invalidates its own 3D-views. Every new frame is redrawn by intentionally invalidating the view area, which creates a WM_PAINT, and then the WM_PAINT handler does the drawing.
Jeff250 wrote:Any time application Y paints anything, whether it's a WinForms button or a pink rectangle via GDI or something via some Windows API I've never heard of, I'd like application X to know!
Hm. I wonder if you can catch anything from
device contexts. Every draw mode I use goes through them.
For example, I for my 3D views I use
CView-based windows which draw to the DCs. Whether I'm using OpenGL or Direct3D or regular GDI functions, they all draw to DCs.
Jeff250 wrote:Foil wrote:That said, I'd suggest looking into the InvalidateRect and/or InvalidateRgn ...
I'm not sure if I follow. How would I know which regions in the window to invalidate?
I should have clarified. I didn't mean that you would actively invalidate areas; I was thinking you might be able to catch the invalidation events (though I don't remember ever seeing them exposed).
Sirius wrote:I'd be surprised if there aren't tools for detecting the window messages sent to a window
Spy++ is a developer tool which does that, and I've done it with dll hooks (which duplicated the message and sent it to my app) as well.
Re:
Posted: Fri Oct 01, 2010 8:33 pm
by Jeff250
Sirius wrote:The issue is that it will only pick up events that are exposed to MSAA, and I don't think that includes raw GDI paint operations - though there might be something out there that does.
I think the tool in question was AccEvent, which is mentioned here (along with installation instructions):
http://blogs.msdn.com/b/winuiautomation ... s-sdk.aspx
Yeah, it doesn't pick up on me drawing in MSPaint, which is about as close to arbitrary GDI operations as I can think of.
Sirius wrote:you'd pretty much have to run the application in administrator mode for it to have access to that kind of thing.
Unfortunately, that would make it untenable.
Foil wrote:Jeff250 wrote:In fact, in a desktop compositing environment, I'm hard-pressed to think of a reason for a WM_PAINT event to be sent after the window has been created...
Anytime any part of the window gets invalidated (another window is moved over it, etc.), it will get a WM_PAINT/WM_NCPAINT. This happens pretty often; if you watch a Spy++ log for a given window, you see those messages pretty frequently.
But in a desktop compositing environment, I'm hard-pressed to think of a reason for a region of the window to be invalidated. Unless this is different on Windows, when the overlapping window is closed, the window manager should just be able to pull out the texture of the entire overlapped window from video memory without asking the overlapped window to repaint anything. edit: In fact, it's probably doing this anyways, and if there's an overlapping window, then its texture just gets drawn on top of it.
Foil wrote:Spy++ is a developer tool which does that, and I've done it with dll hooks (which duplicated the message and sent it to my app) as well.
I don't have Visual Studio (I'm using MinGW), but some googling suggests that there are imitating standalone tools that could do the same.
Posted: Fri Oct 01, 2010 9:08 pm
by Sirius
Spy++ is stand-alone (well, it's distributed as part of the Windows Platform SDK, but you can choose which parts to download and it doesn't need VS to run).
I just want to check what you're trying to do again to be sure: you're drawing the contents of a window, but want to know which parts of the window are occluded so you know not to draw those? I don't know of an ideal way to do that off the top of my head, especially because windows are not forced to be any particular shape (some applications I've seen, like media player skins, aren't even vaguely rectangular). They also aren't forced to be opaque from Windows 2000 onward.
Sniffing out GDI events would be a very complicated way of doing this, as you'd need to use them to build up a picture of the shape of the overlapping window. If it were possible to get a \"mask\" for the window, it might work better. Either way, getting information about other windows that don't belong to your application isn't something you can do without process elevation for security reasons.
Posted: Fri Oct 01, 2010 9:46 pm
by Jeff250
No, I'm looking to know when a part of a window changes and what region was changed so that I can efficiently maintain a copy of the window in a buffer in CPU memory. Again, think of the use case where you are writing a video screen capture application where you want to record what a user is doing in a window. The naive way to do this is to copy the entire window into a buffer on some interval. I'm looking for a more sophisticated approach a la XDamage where I can listen in on events that signify changes in the window.
Posted: Wed Oct 06, 2010 9:19 pm
by Jeff250
RealVNC has a GPL'd version of their software that I've briefly looked at. It looks like they use three different screen capture strategies that you can choose from, with varying tradeoffs:
1. They offer a virtual video driver that you can install that alerts the VNC server whenever something changes on screen. This is the ugliest from a design standpoint but is both robust and efficient. This is outside the scope of anything I want to hack up for this project, and I don't want to require that people have root privileges.
2. They offer using some GDI hooks. These apparently can't capture everything, such as OpenGL or, weirdly, the Windows terminal (RealVNC will treat the Windows terminal as a special case and use polling for it). More importantly, these lack the promise of an actual API like XDamage to actually report all changes to you. But apparently it's good enough for most purposes. So this seems somewhat more elegant, less robust but about as efficient. To trade off some efficiency for more robustness, RealVNC will occasionally poll the screen, to get anything that might have fallen through the cracks. I might look into this approach if I have time to see what kind of hooks they are using exactly (hopefully nothing that requires root privileges).
3. They offer traditional polling. From a design standpoint, this is elegant to implement, is very robust, but it's not very fast. I'll probably implement this first, and then see how awful this is.
Thanks everyone for your input.
Posted: Mon Oct 11, 2010 3:27 pm
by Foil
Any results? I'm curious.
Posted: Mon Oct 11, 2010 10:45 pm
by Jeff250
Hopefully this weekend I will have some time to at least hack together the polling option. Regardless, I'll report back when I'm done.
Re:
Posted: Sun Oct 17, 2010 1:08 am
by Jeff250
Jeff250 wrote:They offer traditional polling. From a design standpoint, this is elegant to implement, is very robust, but it's not very fast. I'll probably implement this first, and then see how awful this is.
Foil wrote:Any results? I'm curious.
Turns out it's not so awful--I can smoothly capture my 1280x1024 desktop showing only 5% of my Core 2 Duo 3.0GHz CPU in the Windows task manager plus running some bilinear downscaling code (I don't recall if this is means 5% of one core or if it divides by two). Maybe my XDamage code for Unix was a premature optimization. Probably not though--the IPC overhead involved in X's client/server model probably makes it worth it, especially since the client and server aren't even necessarily on the same machine!