Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to attach an Electron window to an application screen and resize dynamically

I am currently writing a program that uses a mix of Electron and React-Redux to create an overlay window on top of screens/applications. I managed to successfully create the transparent overlay window and list all the valid media streams. But I can't figure out how I can have this new overlay window match the size/location of the selected stream and dynamically resize. On top of that, I would like the overlay to be on top of the selected stream alone.

Any tips are welcome :)

// In MainProcess

ipcMain.on(ELECTRON_CREATE_OVERLAY_WINDOW, (event, windowSettings) => {
  if (overlayWindow !== null) {
    console.error('Trying to create an Overlay window when there is already one!')
    return
  }

  console.log('Creating the Overlay window')
  overlayWindow = new BrowserWindow({
    width: windowSettings.width,
    height: windowSettings.height,
    webPreferences: {
      nodeIntegration: true,
      enableRemoteModule: true,
    },
    transparent: true,
    frame: false,
    alwaysOnTop: true,
  });

  overlayWindow.setIgnoreMouseEvents(true);
  overlayWindow.loadURL("http://localhost:3000/overlay");

  overlayWindow.on('closed', () => {
    console.log('Overlay window closed')
    overlayWindow = null
  })

});
// In React page / RendererProcess

React.useEffect(async () => {
    desktopCapturer
      .getSources({
        types: ["window", "screen"],
      })
      .then((inputSources) => {
        for (let i = 0; i < inputSources.length; i++) {
          let source = inputSources[i];
          const constraints = {
            audio: false,
            video: {
              mandatory: {
                chromeMediaSource: "desktop",
                chromeMediaSourceId: source.id,
              },
            },
          };

          navigator.mediaDevices.getUserMedia(constraints).then((stream) => {
            inputSources[i].stream = stream;
            console.log('stream', stream)
            // When we got all streams, update the state
            if (i == inputSources.length - 1) {
              setSources([...inputSources]);
            }
          });
        }
      });
  }, []);

...

const launchOverlay = (source) => {
  const streamSettings = source.stream.getVideoTracks()[0].getSettings();
  console.log(source)
  console.log(source.stream)
  console.log(streamSettings)
  createOverlayWindow({ width: streamSettings.width, height: streamSettings.height })
};
like image 684
AggressiveCube Avatar asked Nov 06 '22 03:11

AggressiveCube


1 Answers

You can use electron-overlay-window package for it.

Readme says it supports Windows and Linux

It tracks target windows by its title and keeps your app window right over it. It also re-attaches itself if you restart the target app/game. The only downside - it's not very documented. But the basic demo is simple.

// ...
import { overlayWindow as OW } from 'electron-overlay-window'

// ...
const win = new BrowserWindow({
  ...OW.WINDOW_OPTS, // pay attention here
  width: 800,
  height: 600,
  resizable: false,
  webPreferences: {
    nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
  },
})

// ... when ready
OW.attachTo(window, 'Untitled - Notepad')

// listen for lifecycle events
OW.on('attach', ev => { console.log('WO: attach', ev) })
OW.on('detach', ev => { console.log('WO: detach', ev) })
OW.on('blur', ev => { console.log('WO: blur', ev)})
OW.on('focus', ev => { console.log('WO: focus', ev)})
OW.on('fullscreen', ev => console.log('WO: fullscreen', ev))
OW.on('moveresize', ev => console.log('WO: fullscreen', ev))

You can look up more examples here:

  • Ender-O for Elite Dangerous written in JS (demo video)
  • Awaken PoE Trade for Path of Exile written in TS
  • Simple demo from author written in TS (I recommend starting with this example)
like image 63
vovchisko Avatar answered Nov 12 '22 15:11

vovchisko