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?

Pioz
  • 6,051
  • 4
  • 48
  • 67
  • 1. Please post error messages you are getting in full and without editing (major opcode, whatever). 2. Use `libpng`. – n. m. could be an AI Feb 02 '14 at 17:25
  • 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 pixmap – Andrey Sidorov Feb 03 '14 at 02:20
  • Yeah, I can use libpng, but Picture is a XID, how can I get the buffer of this picture to use with libpng? – Pioz Feb 03 '14 at 16:06
  • Sorry I have misread your second bullet point. To get the pixels do just like @AndreySidorov says, to save them use libpng. – n. m. could be an AI Feb 03 '14 at 16:38
  • http://cvsweb.xfree86.org/cvsweb/xc/programs/xwd/xwd.c?rev=HEAD – technosaurus Jun 14 '14 at 08:04
  • Have you been able to make this work? Those this solution work for taking screenshots of not currently visible windows? – Damir Porobic Oct 31 '16 at 13:43
  • 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? https://stackoverflow.com/questions/68011128/where-to-find-usr-include-x11-extensions-xcomposite-h – WinEunuuchs2Unix Jun 16 '21 at 23:27

1 Answers1

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.

user3733083
  • 419
  • 4
  • 6