38

I've been trying to move a frameless window on false but now I want to move the whole window just by dragging one element (the title bar), I've tried -webkit-app-region: drag; but it doesn't seem to work, I've also tried https://www.npmjs.com/package/electron-drag but it does't work either.

Zooly
  • 4,736
  • 4
  • 34
  • 54
speed437
  • 409
  • 1
  • 4
  • 3
  • Please read the help section on how to ask a question – StudioTime Jun 29 '17 at 07:09
  • 5
    What? the question is clear, what was so hard about "I cant move a frameless window on Electron" wtf – speed437 Jun 29 '17 at 07:11
  • 1
    This tutorial shows how to create a draggable titlebar and it uses the -webkit-app-region: drag; css attribute, you may be doing something wrong: http://ourcodeworld.com/articles/read/287/how-to-create-a-custom-frameless-window-without-title-bar-with-minimize-maximize-and-close-controls-in-electron-framework – Carlos Delgado Jun 29 '17 at 07:11
  • It even says that -webkit-app-region doesnt even exist http://prntscr.com/fpguhc – speed437 Jun 29 '17 at 07:16
  • 1
    The point is if you show what you've tried, instead of one random line, then we may see something else which might help you – StudioTime Jun 29 '17 at 07:20
  • Well now because of you I am not able to ask any more questions so I guess I'll just ask here. Why does my Webstorm editor (and browser) say http://prntscr.com/fpgx7r . (All settings are default) – speed437 Jun 29 '17 at 07:27
  • 1
    Only because webstorm does not know this property it still can be valid. – Hans Koch Jun 29 '17 at 11:21

5 Answers5

72

Since your windows are frameless you can use the property -webkit-app-region which is valid even though your IDE says it's not. You just should forbid the text selection and drag on buttons inside of your title bar too out of UX concerns.

.titlebar {
  -webkit-user-select: none;
  -webkit-app-region: drag;
}

.titlebar-button {
  -webkit-app-region: no-drag;
}

The API documentation mentions this too https://github.com/electron/electron/blob/master/docs/api/frameless-window.md#draggable-region

Hans Koch
  • 4,283
  • 22
  • 33
17

First create your app window with the frame option set to false on your main.js file:

mainWindow = new BrowserWindow({
...
frame: false
})

Then in your renderer.js file create an HTML element (Ex. ) with the -webkit-app-region propperty set to drag.

var windowTopBar = document.createElement('div')
windowTopBar.style.width = "100%"
windowTopBar.style.height = "32px"
windowTopBar.style.backgroundColor = "#000"
windowTopBar.style.position = "absolute"
windowTopBar.style.top = windowTopBar.style.left = 0
windowTopBar.style.webkitAppRegion = "drag"
document.body.appendChild(windowTopBar)
Pelayo Méndez
  • 389
  • 4
  • 10
  • from vuejs app, insert that into index.html file into script tag html in begin of body. It works perfectly. – miltone Nov 17 '20 at 23:08
  • Will it always shows the close + minimize + fullscreen buttons ? It works on osx, but will it also preserve these buttons on window? – DoneDeal0 Jan 26 '23 at 21:11
3

I had the same problem. I realized that you must have property focusable of BrowserWindow to false.

Example:

    let auxWindow = new BrowserWindow({
        frame: false,
        transparent: false,
        alwaysOnTop: true,
        focusable: false, //THIS IS THE KEY
        closable: true,
        fullscreenable: false,
        maximizable: false,
        resizable: false,
        webPreferences: {
          preload: join(app.getAppPath(), 'build', 'src', 'preload.js'),
        },
        parent: mainWindow
      });

Then, in your aux window, you only need to put a button with class="draggable":

<img src="move-outline.svg" width="15" height="15" alt="move" class="draggable">

And set in your CSS -webkit-app-region: drag;:

.draggable {
  -webkit-app-region: drag;
}
Miguel
  • 188
  • 5
1

I had the same problem and after opening the Developer Tools Window (Ctrl+Shift+I) I noticed that inline code was being blocked by a Content Security Policy.

The solution was to move css into an external file

index.html

<link rel="stylesheet" type="text/css" href="style.css"/>

style.css

.draggable {
   -webkit-user-select: none;
   user-select: none;
   -webkit-app-region: drag;
}

now anything with the draggable class is draggable and prevents the text from being selected

Josh McGee
  • 443
  • 6
  • 16
0

I was looking for something similar for my project, even though you should be good with webkit region for your use but It's not the answer you demanded, and If someone facing the issue below they can also use the code.

Im using frameless window, making the whole window element as draggable makes the program to ignore click events.

Worry Not, Im here to you a lot of "mehnat".

Rendering/front end side:

//elem = the element you want to use to drag the whole window.
//In my case, elem was the element covering the whole window. (100vh + 100 vw)
//longmousedown variable tells us if mouse been clicked for a long time, 200ms in my case.
//When longmousedown is true, I use this to ignore click event functions using if/else. (It feels better if click functions doesn't do anything while you trying to drag your window)

let longmousedowntimout;
let longmousedown = false;
let is_mousedownvid = false;
let earlymouseX,earlymouseY;
elem.addEventListener("mousedown", function(event){
    longmousedowntimout = setTimeout(function(){longmousedown = true},200)
    is_mousedownvid = true;
    earlymouseX = event.screenX;
    earlymouseY = event.screenY;
});
elem.addEventListener("mouseup", function(event){
    clearTimeout(longmousedowntimout)
    is_mousedownvid = false;
    ipcRenderer.invoke('settlenewpos', {x:(event.screenX - earlymouseX),y:(event.screenY - earlymouseY)})
});
elem.addEventListener("mousemove", dragMouse);
elem.addEventListener("mouseleave", ()=>{
    if(is_mousedownvid){
        is_mousedownvid = false;
        ipcRenderer.send("settlemergency")
    }
});
function dragMouse(e){
  if(is_mousedownvid){
    e = e || window.event;
    e.preventDefault();
    ipcRenderer.invoke('setnewpos', {x:(e.screenX - earlymouseX),y:(e.screenY - earlymouseY)})
}}

Main.js side (the side where electron runs) :

(don't copy paste the below, read it once)

let earlyX, earlyY;
let newX, newY;
const createWindow = () => {
    let display = screen.getPrimaryDisplay();
    let widtho = display.bounds.width;
    let heighto = display.bounds.height;
    let wind_height = 330;
    let wind_width = 0;
    let minusX = 608;
    let minusY = 376;
    const mainWindow = new BrowserWindow({
      icon: `${__dirname}/resources/icons/yt logo hd 2.png`,
      show: false,
      height: wind_height,
      frame:false,
      minimizable: true,
      skipTaskbar:true,
      webPreferences: {
        preload: path.join(__dirname, 'preload.js'),
        nodeIntegration:true,
        contextIsolation: false,
      },
    });
    earlyX = widtho - minusX;
    earlyY = heighto - minusY;
    mainWindow.setBounds({
      width: mainWindow.getSize()[0],
      height: mainWindow.getSize()[1],
      x: earlyX,
      y: earlyY
    });
    mainWindow.setAspectRatio(16/9);
    ipcMain.handle('setnewpos', async (event, someArgument) => {
       mainWindow.setBounds({
         width: wind_width || mainWindow.getSize()[0],
         height: wind_height,
         x: earlyX+someArgument.x,
         y: earlyY+someArgument.y
       });
       newX = earlyX+someArgument.x;
       newY = earlyY+someArgument.y;
       if(wind_width == 0) wind_width = Math.ceil(parseInt(wind_height)*16/9)
    })
    ipcMain.handle('settlenewpos', async (event, someArgument) => {
      earlyX=earlyX+someArgument.x; 
      earlyY=earlyY+someArgument.y;
      newX = earlyX;
      newY = earlyY;
     })
    ipcMain.on('settlemergency', () => {
        earlyX = newX;
        earlyY= newY;
    })
    mainWindow.on("will-resize",(event, newBounds)=>{
      earlyX = newBounds.x;
      earlyY = newBounds.y;
      newX = earlyX;
      newY = earlyY;
      wind_height= newBounds.height
      wind_width = newBounds.width
    })
}
iharshraj
  • 11
  • 3