Get a screenshot of a window that is cover or not visible or minimized with Xcomposite extension for X11
Asked Answered
A

1

5

I have the follow starting code to get a screenshot of a X window (the window can be covered, not visibled, or minimized).

#include <stdlib.h>
#include <stdio.h>

#include <X11/Xlib.h>
#include <X11/X.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xrender.h>

int
main ()
{
  Display *display = XOpenDisplay (NULL);
  XID xid = 90177543; // xdotool search --name "World of Warcraft" | head -1

  // Check if Composite extension is enabled
  int event_base_return;
  int error_base_return;
  if (XCompositeQueryExtension (display, &event_base_return, &error_base_return))
    printf ("COMPOSITE IS ENABLED!\n");

  // Requests the X server to direct the hierarchy starting at window to off-screen storage
  XCompositeRedirectWindow (display, xid, CompositeRedirectAutomatic);
  // Preventing the backing pixmap from being freed when the window is hidden/destroyed
  // If you want the window contents to still be available after the window has been destroyed,
  // or after the window has been resized (but not yet redrawn), you can increment the backing
  // pixmaps ref count to prevent it from being deallocated.
  Pixmap pixmap = XCompositeNameWindowPixmap (display, xid);

  // Get window attributes
  XWindowAttributes attr;
  Status s = XGetWindowAttributes (display, xid, &attr);
  if (s == 0)
    printf ("Fail to get window attributes!\n");

  // Extract the data
  XRenderPictFormat *format = XRenderFindVisualFormat (display, attr.visual);
  int width = attr.width;
  int height = attr.height;
  int depth = attr.depth;

  // What we need to do now is to create an XRender Picture for the window,
  // which we'll need to draw it with the Render extension.
  // A picture is a basically a handle to a server side struct with some
  // additional information about a drawable (in this case a window),
  // such as its format, which clipping region should be used when
  // drawing it (if any), whether it should be tiled etc.
  XRenderPictureAttributes pa;
  pa.subwindow_mode = IncludeInferiors;
  Picture picture = XRenderCreatePicture (display, xid, format, CPSubwindowMode, &pa);

  // We now have all the information we need in order to be able to draw the window
  // using the Xrender extension, and we've created and prepared a source picture
  // for the window for this purpose.
  // The Xrender function we'll use to draw the window is XRenderComposite().

  //XRenderComposite (display, PictOpSrc, picture, None, ???destination???, 0,0, 0,0, 0,0, width, height);

  XFreePixmap (display, pixmap);
  XCompositeUnredirectWindow (display, xid, CompositeRedirectAutomatic);

  return 0;
}

[Compile the code with gcc file.c -lX11 -lXcomposite -lXrender and run with ./a.out]

[You can get a valid XID of a window of your Desktop with the command xdotool search --name "Title of a window" | head -1]

Now I have two problem:

  1. I get a BadMatch (invalid parameter attributes) error when I call the XRenderFindVisualFormat function. I dont know why. The window with XID 90177543 exists.
  2. I don't know how to get the buffer of the Picture picture to save it as a PNG image. I don't want use QT library to do this.

Can you help me?

Advance answered 2/2, 2014 at 15:13 Comment(7)
1. Please post error messages you are getting in full and without editing (major opcode, whatever). 2. Use libpng.Christie
2) use XGetImage to get pixels of Pixmap. If your Picture already have pixmap associated with it just use that pixmap, otherwise draw Picture content on another pixmap using XRenderComposite and after that use XGetImage on that pixmapHydrastinine
Yeah, I can use libpng, but Picture is a XID, how can I get the buffer of this picture to use with libpng?Advance
Sorry I have misread your second bullet point. To get the pixels do just like @AndreySidorov says, to save them use libpng.Christie
cvsweb.xfree86.org/cvsweb/xc/programs/xwd/xwd.c?rev=HEADBufford
Have you been able to make this work? Those this solution work for taking screenshots of not currently visible windows?Seismo
I just posted a question based on your question and realized I should have just asked you here in comments :(. Can you answer the question. If you wouldn't mind taking a look? #68011628Fictionalize
A
2

I am able to reproduce your error as follows:

$ ./xidtest 
COMPOSITE IS ENABLED!
X Error of failed request:  BadWindow (invalid Window parameter)
  Major opcode of failed request:  142 (Composite)
  Minor opcode of failed request:  1 ()
  Resource id in failed request:  0x5600007
  Serial number of failed request:  9
  Current serial number in output stream:  12

When set using a window id I knew to exist (0x440000B or 71303179, found using xwininfo), I received no error:

$ ./xidtest 
COMPOSITE IS ENABLED!

I conclude that the error is the window id you have provided is invalid.

Alena answered 14/6, 2014 at 7:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.