Some random notes follow.
Transparent grab window
The rectangular area is defined by a grab window, which consists only of a frame (drawn by the window manager). The window itself must be completely transparent such that mouse clicks are sent to the window below. This is realized using the X11 Shape extension:
The grab window can be moved and resized to define the grabbing area. This is more convenient than entering coordinates manually. After a resize, the plugin must be reopened because the image size of a gmerlin video stream cannot change within the processing loop.
Make the window sticky and always on top
Depending on the configuration the grab window can always be on top of the other windows. There is also a sticky option making the window appear on all desktops. This is done with the collowing code, which must be called each time before the window is mapped:
if(flags & (WIN_ONTOP|WIN_STICKY))
int num_props = 0;
Atom wm_state = XInternAtom(dpy, "_NET_WM_STATE", False);
if(flags & WIN_ONTOP)
XInternAtom(dpy, "_NET_WM_STATE_ABOVE", False);
if(flags & WIN_STICKY)
XInternAtom(dpy, "_NET_WM_STATE_STICKY", False);
XChangeProperty(dpy, win, wm_state, XA_ATOM, 32,
(unsigned char *)wm_states, num_props);
The grabbing itself is done on the root window only. This will grab all other windows inside the grab area. The easiest method is
XGetImage, but that allocates a new image with each call.
malloc()/free()cycles within the processing loop should be avoided whenever possible.
XGetSubImage()allows to pass an allocated image. Much better of course is
XShmGetImage(). It was roughly 3 times faster than
XGetSubImage()in my tests.
If parts of the grabbing rectangle are outside the root window, you'll get a
BadMatcherror (usually exiting the program), no matter which function you use for grabbing. You must handle this case and correct the coordinates to stay within the root window.
Grabbing works for everything displayed on the screen (including XVideo overlays) except the mouse cursor. It must be obtained and drawn "manually" onto the grabbed image. Coordinates are read with
XQueryPointer(). The cursor image can be obtained if the XFixes extension is available. First we request cursor change events for the whole screen with
If the cursor changed and is within the grabbing rectangle we get the image with
The resulting cursor image is then converted to a
im = XFixesGetCursorImage(dpy);
gavl_overlay_tand blended onto the grabbed image with a
Not done (yet)
Other grabbing programs deliver images only when something has changed (resulting in a variable framerate stream). This can be achieved with the XDamage extension. Since the XDamage extension is (like many other X11 extensions) poorly documented, I didn't bother to implement this yet.
One alternative is to use gmerlins decimate video filter, which compares the images in memory. The result will be the same, but CPU usage will be slightly increased.