Skip to content

Instantly share code, notes, and snippets.

@xiangwan
Forked from StickyCube/index.html
Created July 16, 2016 17:23
Show Gist options
  • Save xiangwan/c95549295517d98fe29c43e62fd3eddd to your computer and use it in GitHub Desktop.
Save xiangwan/c95549295517d98fe29c43e62fd3eddd to your computer and use it in GitHub Desktop.

Revisions

  1. Will Knowles created this gist Jun 27, 2016.
    96 changes: 96 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,96 @@
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Test App</title>
    </head>

    <style>
    html, body {
    height: 100%;
    }

    body {
    margin: 0px;
    box-sizing: border-box;
    }

    #mount {
    width: 100%;
    height: 100%;
    }
    </style>

    <body>
    <div id="mount"></div>

    <script src="./node_modules/react/dist/react.js"></script>
    <script src="./node_modules/react-dom/dist/react-dom.js"></script>
    <scriot src="./node_modules/es6-shim/es6-shim.js"></script>
    <script src="./node_modules/babel-standalone/babel.js"></script>

    <script type="text/babel">
    const { Component } = React;
    const { render } = ReactDOM;
    const { ipcRenderer } = require('electron');
    const mount = document.getElementById('mount');

    const containerStyle = {
    width: '100%',
    height: '100%',
    backgroundColor: 'white',
    textAlign: 'center',
    padding: '10px',
    boxSizing: 'border-box'
    };

    class App extends Component {
    constructor () {
    super(...arguments);
    this.state = { counter: 0 };
    }

    onClick () {
    this.setState({
    counter: this.state.counter + 1
    });
    }

    setChildCss (rule) {
    ipcRenderer.send(
    'ClickableRegion::set-child-css',
    `body { ${rule} !important; }`
    );
    }

    render () {
    return (
    <div style={containerStyle}>
    <p>This window has setIgnoreMouseEvents(true)</p>
    <h1>{ this.state.counter }</h1>
    {
    /**
    * One drawback here is that :hover css pseudoclass is not picked up
    * setChildCss is a hacky workaround which sets { cursor: pointer }
    * on the body of the transparent child
    */
    }
    <button
    onClick={ () => this.onClick() }
    onMouseEnter={ () => this.setChildCss('cursor:pointer') }
    onMouseLeave={ () => this.setChildCss('cursor:initial') }
    >
    Click me
    </button>
    </div>
    );
    }
    }

    render(
    <App/>,
    mount
    );
    </script>
    </body>
    </html>
    94 changes: 94 additions & 0 deletions index.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,94 @@
    const { app, BrowserWindow, ipcMain } = require('electron');
    const path = require('path');

    const INDEX_HTML = path.join('file://', __dirname, 'index.html');
    const TRANSPARENT_HTML = path.join('file://', __dirname, 'transparent.html');
    const CHILD_PADDING = 50;

    const addClickableRegion = options => {
    const { parent } = options;
    const parentBounds = parent.getBounds();
    const {
    width = parentBounds.width,
    height = parentBounds.height,
    x = 0,
    y = 0
    } = options;

    // create a child window, setting the position based on the parent's bounds
    const childWindow = new BrowserWindow({
    parent,
    x: parentBounds.x + x,
    y: parentBounds.y + y,
    width: width || parentBounds.width,
    height: height || parentBounds.height,
    // disable pretty much everything
    transparent: true,
    frame: false,
    skipTaskbar: true,
    movable: false,
    resizable: false,
    maximizable: false,
    minimizable: false
    });

    // this is a dirty workaround to set the cursor style when hovering over the button
    ipcMain.on(
    'ClickableRegion::set-child-css',
    (e, css) => childWindow.webContents.insertCSS(css)
    );

    // When the transpoarent child captures a mouse event, it is forwarded to the parent
    // and mapped to it's coordinates
    ipcMain.on(
    'ClickableRegion::mouse-event',
    (e, data) => {
    parent.webContents.sendInputEvent(Object.assign(
    data,
    {
    x: x + data.x,
    y: y + data.y
    }
    ));
    }
    );

    childWindow.loadURL(TRANSPARENT_HTML);
    };

    const onAppReady = function () {
    let parent = new BrowserWindow({
    width: 300,
    height: 300,
    show: false,
    resizable: false,
    transparent: true,
    frame: false
    });

    // make the parent window ignore all mouse events so we can click through it
    parent.setIgnoreMouseEvents(true);

    parent.once('close', () => {
    parent = null;
    });

    parent.webContents.once('did-finish-load', () => {
    // add a transparent clickable child window to capture the mouse events
    addClickableRegion({
    parent,
    x: CHILD_PADDING,
    y: CHILD_PADDING,
    width: 200,
    height: 200
    });

    // could do this in index.html
    parent.webContents.insertCSS(`body { padding:${CHILD_PADDING}px !important; }`);
    parent.show();
    });

    parent.loadURL(INDEX_HTML);
    };

    app.on('ready', onAppReady);
    18 changes: 18 additions & 0 deletions package.json
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,18 @@
    {
    "name": "window-resize-issue",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
    "app": "npm install && node_modules/.bin/electron --disable-gpu --enable-transparent-visuals ."
    },
    "author": "stickycube",
    "license": "ISC",
    "dependencies": {
    "babel-standalone": "^6.10.3",
    "electron-prebuilt": "1.2.5",
    "es6-shim": "^0.35.1",
    "react": "^15.1.0",
    "react-dom": "^15.1.0"
    }
    }
    59 changes: 59 additions & 0 deletions transparent.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,59 @@
    <!DOCTYPE html>
    <html>
    <head>
    <style>
    html, body {
    margin: 0px;
    width: 100%;
    height: 100%;
    }
    </style>
    </head>
    <!-- handlers for supported mouse events on body -->
    <body
    onmouseup="onEvent('mouseUp', event)"
    onmousedown="onEvent('mouseDown', event)"
    onmouseenter="onEvent('mouseEnter', event)"
    onmouseleave="onEvent('mouseLeave', event)"
    onmousemove="onEvent('mouseMove', event)"
    >
    <script>
    const {ipcRenderer} = require('electron');

    const getEventModifiers = evt => [
    { field: 'ctrlKey', name: 'control' },
    { field: 'shiftKey', name: 'shift' },
    { field: 'altKey', name: 'alt' },
    { field: 'metaKey', name: 'meta' }
    ].filter(elm => evt[elm.field]).map(elm => elm.name);

    const getEventButton = evt => {
    switch (evt.button) {
    case 2:
    return 'right';
    case 1:
    return 'middle';
    case 0:
    default:
    return 'left';
    }
    }

    window.onEvent = function (type, evt) {
    // send the event to ipcMain
    return ipcRenderer.send('ClickableRegion::mouse-event', {
    type,
    modifiers: getEventModifiers(evt),
    button: getEventButton(evt),
    x: evt.clientX,
    y: evt.clientY,
    globalX: evt.screenX,
    globalY: evt.screenY,
    movementX: evt.movementX,
    movementY: evt.movementY,
    clickCount: evt.detail,
    });
    }
    </script>
    </body>
    </html>