0

I was working on writing a screenshot thing, and found this excellent topic for Mac: How can I get screenshot from all displays on MAC?

I was wondering if anyone has the equivalent for x11 library? To get all the monitors and then screenshot them all?

I had found this topic: https://stackoverflow.com/a/5293559/1828637

But the code linked from there is not as easy to follow for a novice like me.

Will RootWindow(3) get the area of all the monitors combined? Then I can go through and get the monitors dimensions then XGetImage those sections on the return of RootWindow?

I had come across this topic: How do take a screenshot correctly with xlib? But I'm not sure if it has multi-monitor support. I do this in ctypes so I cant test that code easily without going through the grueling task of writing it first. So I was wondering if this is correct or how would I modify it to handle multi mon please?

Edit

The poster there shared his code, it is seen here: https://github.com/Lalaland/ScreenCap/blob/master/src/screenCapturerImpl.cpp#L96 but it's complicated and I don't understand it. It uses functions like XFixesGetCursorImage which I can't find in the documentation, and I don't see how the multi monitors work there. Author of that topic warned he doesn't remember the code and it may not work with modern Linux.

halfer
  • 19,824
  • 17
  • 99
  • 186
Noitidart
  • 35,443
  • 37
  • 154
  • 323
  • 1
    depending on how you have X configured ( with or without Xinerama ) you might have it as multiple root windows or one large window. If one large: use XRandR to get vieport positions within that large window and after that continue as usual – Andrey Sidorov Jun 19 '15 at 07:06
  • Thanks very much @AndreySidorov can you please point me in direction for the usual part :) – Noitidart Jun 19 '15 at 15:06
  • Reason I ask is because I wrote the GTK version however Ive been trying for a month now but I cant get this code to run from a thread that is not the main-thread: https://gist.github.com/yajd/78f134beab856ff3e5e7 so im thinking of switching to X and trying it. – Noitidart Jun 19 '15 at 15:17
  • Hey there @AndreySidorov is this the usual way? http://stackoverflow.com/questions/10284858/taking-screenshot-with-libx11 is there any node-x11 screenshot scritps out there i couldnt find one – Noitidart Jun 20 '15 at 05:21
  • 1
    yes, just XGetImage to grab content of the window – Andrey Sidorov Jun 20 '15 at 11:50
  • Thanks @AndreySidorov ill try it out! :) – Noitidart Jun 20 '15 at 21:48
  • 1
    take a look at https://github.com/sidorares/node-x11/blob/master/examples/screenshot.js , but not sure if that example worked or not – Andrey Sidorov Jun 21 '15 at 00:30
  • Thanks @AndreySidorov ill check it out! :) – Noitidart Jun 21 '15 at 03:11
  • 1
    it does not just call XGetImage on a window but walks windows tree from bottom to top and overlays content as it walk. Not sure if that is necessary, maybe GetImage on a root window is enough – Andrey Sidorov Jun 22 '15 at 01:23
  • Thanks @Andrey ! I have some life stuff to deal with so im a bit swamped but eager to do this. As soon as im back ill update you on how it goes thanks so much for that comment it will help me lots ive looked at this tuff in past but it didnt make full sense. – Noitidart Jun 22 '15 at 04:38

1 Answers1

1

This is not a perfect answer to the question, but the following code could be modified to get a very fast version of your desired end result: https://github.com/Clodo76/vr-desktop-mirror/blob/master/DesktopCapture/main.cpp

The DesktopCapturePlugin_Initialize method converts all the displays into objects:

UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API DesktopCapturePlugin_Initialize()
{   
    DesksClean();

    g_needReinit = 0;


    IDXGIFactory1* factory;
    CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&factory));

    IDXGIAdapter1* adapter;
    for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
    {
        IDXGIOutput* output;
        for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); j++)
        {
            DXGI_OUTPUT_DESC outputDesc;
            output->GetDesc(&outputDesc);

            MONITORINFOEX monitorInfo;
            monitorInfo.cbSize = sizeof(MONITORINFOEX);
            GetMonitorInfo(outputDesc.Monitor, &monitorInfo);

            // Maybe in future add a function to identify the primary monitor.
            //if (monitorInfo.dwFlags == MONITORINFOF_PRIMARY)
            {
                int iDesk = DeskAdd();

                g_desks[iDesk].g_width = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;                  
                g_desks[iDesk].g_height = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;

                auto device = g_unity->Get<IUnityGraphicsD3D11>()->GetDevice();
                IDXGIOutput1* output1;
                output1 = reinterpret_cast<IDXGIOutput1*>(output);
                output1->DuplicateOutput(device, &g_desks[iDesk].g_deskDupl);
            }

            output->Release();
        }
        adapter->Release();
    }

    factory->Release();
}

Then the OnRenderEvent method copies a frame from the display into a texture (provided by unity in this case):

void UNITY_INTERFACE_API OnRenderEvent(int eventId)
{
    for (int iDesk = 0; iDesk < g_nDesks; iDesk++)
    {
        if (g_desks[iDesk].g_deskDupl == nullptr || g_desks[iDesk].g_texture == nullptr)
        {
            g_needReinit++;
            return;
        }

        IDXGIResource* resource = nullptr;

        const UINT timeout = 0; // ms
        HRESULT resultAcquire = g_desks[iDesk].g_deskDupl->AcquireNextFrame(timeout, &g_desks[iDesk].g_frameInfo, &resource);
        if (resultAcquire != S_OK)
        {
            g_needReinit++;
            return;
        }

        g_desks[iDesk].g_isPointerVisible = (g_desks[iDesk].g_frameInfo.PointerPosition.Visible == TRUE);
        g_desks[iDesk].g_pointerX = g_desks[iDesk].g_frameInfo.PointerPosition.Position.x;
        g_desks[iDesk].g_pointerY = g_desks[iDesk].g_frameInfo.PointerPosition.Position.y;

        ID3D11Texture2D* texture;
        HRESULT resultQuery = resource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&texture));
        resource->Release();

        if (resultQuery != S_OK)
        {
            g_needReinit++;
            return;
        }

        ID3D11DeviceContext* context;
        auto device = g_unity->Get<IUnityGraphicsD3D11>()->GetDevice();
        device->GetImmediateContext(&context);
        context->CopyResource(g_desks[iDesk].g_texture, texture);

        g_desks[iDesk].g_deskDupl->ReleaseFrame();
    }

    g_needReinit = 0;
}
Brandon D
  • 151
  • 3