Search code examples
windowx11window-management

Embedding an X11 window, belonging to an independent process launched by me, into my own window?


Is there an easy way to do this? I've never seen this anywhere (apart from the Adobe/... plugins for Firefox), so I doubt it...

If not, is there a reliable, hacky way (such as hooking into that process's Xlib calls via LD_PRELOAD)?

If it matters, assume that the foreign process is mplayer, my programming language is C. I have a hunch that using Xlib directly is my best bet, but feel free to suggest other options. An mplayer-only solution won't suffice.


Solution

  • If you know window id of the window you want to embed you can just reparent it to your window ( using XReparentWindow ) even if it's created by another process.

    For mplayer there is "-wid" command line option. If you pass your window id to it, mplayer creates it's window as a child of wid automatically:

    −wid (also see −gui-wid) (X11, OpenGL and DirectX only)

    This tells MPlayer to attach to an existing window. Useful to embed MPlayer in a browser (e.g. the plugger extension). This option fills the given window completely, thus aspect scaling, panscan, etc are no longer handled by MPlayer but must be managed by the application that created the window.

    You can control mplayer by passing '-slave' flag and sending commands to stdin (or fifo)

    Example of embedding mplayer using node-x11:

    var x11 = require('x11');
    var spawn = require('child_process').spawn;
    x11.createClient(function(err, display) {
        var X = display.client;
        var wid = X.AllocID();
        X.CreateWindow(wid, display.screen[0].root, 100, 100, 400, 300, 0, 0, 0, 0, {eventMask: x11.eventMask.SubstructureNotify|x11.eventMask.StructureNotify});
        X.MapWindow(wid);
        var mplayer = spawn('mplayer', ['-wid', wid, './video.mp4']);
    
        function pause() {
          mplayer.stdin.write('pause\n');
          setTimeout(play, 1000);
        }
    
        function play() {
          mplayer.stdin.write('play\n');
          setTimeout(pause, 1000);
        }
    
        pause();
    
       
        var mpid;
        X.on('event', function(ev) {
            console.log(ev);
            if (ev.name == 'CreateNotify')
                mpid = ev.wid;
            if (ev.name == 'ConfigureNotify' && ev.wid == wid) {
                X.ResizeWindow(mpid, ev.width, ev.height);
            }
    
        });
    });