-
-
Save ibash/2c9894a8038b71456aeabe413e532c19 to your computer and use it in GitHub Desktop.
// electron-panel-window/index.js from whatsapp electron desktop app | |
// @flow strict | |
const { BrowserWindow } = require('electron'); | |
const NativeExtension = require('bindings')('NativeExtension'); | |
const isDarwin = process.platform === 'darwin'; | |
const isWindows = process.platform === 'win32'; | |
class Panel { | |
_isPanel = false; | |
_browserWindow = null; | |
constructor(options) { | |
const _options = { focusable: true, ...options, show: false }; | |
this._browserWindow = new BrowserWindow(_options); | |
NativeExtension.MakeControls(this.getNativeWindowHandle()); | |
NativeExtension.MakeVibrant(this.getNativeWindowHandle()); | |
this.setFocusable(_options.focusable); | |
if (options.show) { | |
this.show(); | |
} | |
} | |
get webContents() { | |
return this._browserWindow.webContents; | |
} | |
getBrowserWindow() { | |
return this._browserWindow; | |
} | |
getNativeWindowHandle() { | |
return this._browserWindow.getNativeWindowHandle(); | |
} | |
getBounds() { | |
return this._browserWindow.getBounds(); | |
} | |
on(...args) { | |
this._browserWindow.on(...args); | |
} | |
once(...args) { | |
this._browserWindow.once(...args); | |
} | |
removeListener(...args) { | |
this._browserWindow.removeListener(...args); | |
} | |
loadURL(...args) { | |
return this._browserWindow.loadURL(...args); | |
} | |
show(animate) { | |
animate = animate || false; | |
if (isDarwin) { | |
NativeExtension.Show(this.getNativeWindowHandle(), animate); | |
} else { | |
this._browserWindow.show(); | |
} | |
} | |
hide(animate) { | |
animate = animate || false; | |
if (isDarwin) { | |
NativeExtension.Hide(this.getNativeWindowHandle(), animate); | |
} else { | |
this._browserWindow.hide(); | |
} | |
} | |
close(animate) { | |
animate = animate || false; | |
if (this._isPanel) { | |
NativeExtension.ClosePanel(this.getNativeWindowHandle(), animate); | |
} else { | |
this._browserWindow.close(); | |
} | |
} | |
minimize() { | |
return this._browserWindow.minimize(); | |
} | |
maximize() { | |
return this._browserWindow.maximize(); | |
} | |
unmaximize() { | |
return this._browserWindow.unmaximize(); | |
} | |
isFullScreen() { | |
return this._browserWindow.isFullScreen(); | |
} | |
setFullScreen(value) { | |
return this._browserWindow.setFullScreen(value); | |
} | |
isAlwaysOnTop() { | |
return this._browserWindow.isAlwaysOnTop(); | |
} | |
setAlwaysOnTop(value) { | |
this._browserWindow.setAlwaysOnTop(value); | |
if (this._isPanel) { | |
NativeExtension.SyncPanel(this.getNativeWindowHandle(), false); | |
} | |
} | |
isMinimizable() { | |
return this._browserWindow.isMinimizable(); | |
} | |
isMinimized() { | |
return this._browserWindow.isMinimized(); | |
} | |
isMaximized() { | |
return this._browserWindow.isMaximized(); | |
} | |
setMinimizable(value) { | |
return this._browserWindow.setMinimizable(value); | |
} | |
setMaximizable(value) { | |
return this._browserWindow.setMaximizable(value); | |
} | |
setFullScreenable(value) { | |
return this._browserWindow.setFullScreenable(value); | |
} | |
restore() { | |
return this._browserWindow.restore(); | |
} | |
destroy() { | |
if (this._isPanel) { | |
NativeExtension.ClosePanel(this.getNativeWindowHandle(), false); | |
} | |
this._browserWindow.destroy(); | |
} | |
isDestroyed() { | |
return this._browserWindow.isDestroyed(); | |
} | |
setBounds(bounds, animate) { | |
animate = animate || false; | |
// Electron window is pushed down to the top of the screen border if negative Y coordinate is provided in MacOS, but not in Windows. | |
// Make sure that negative Y coordinate is never set, so window is not positioned too high and part of the content is not hidden. | |
const windowBounds = { | |
...bounds, | |
}; | |
if (windowBounds.y != null && windowBounds.y < 0) { | |
windowBounds.y = 0; | |
} | |
this._browserWindow.setBounds(windowBounds, animate && !this._isPanel); | |
if (this._isPanel) { | |
NativeExtension.SyncPanel(this.getNativeWindowHandle(), animate); | |
} | |
} | |
setPosition(x, y, animate) { | |
animate = animate || false; | |
// Electron window is pushed down to the top of the screen border if negative Y coordinate is provided in MacOS, but not in Windows. | |
// Make sure that negative Y coordinate is never set, so window is not positioned too high and part of the content is not hidden. | |
let yCoord = y; | |
if (yCoord != null && yCoord < 0) { | |
yCoord = 0; | |
} | |
this._browserWindow.setPosition(x, yCoord, animate && !this._isPanel); | |
if (this._isPanel) { | |
NativeExtension.SyncPanel(this.getNativeWindowHandle(), animate); | |
} | |
} | |
setSize(w, h, animate) { | |
animate = animate || false; | |
this._browserWindow.setSize(w, h, animate && !this._isPanel); | |
if (this._isPanel) { | |
NativeExtension.SyncPanel(this.getNativeWindowHandle(), animate); | |
} | |
} | |
setMinimumSize(minWidth, minHeight) { | |
this._browserWindow.setMinimumSize(minWidth, minHeight); | |
if (this._isPanel) { | |
NativeExtension.SyncPanel(this.getNativeWindowHandle(), false); | |
} | |
} | |
setResizable(value) { | |
this._browserWindow.setResizable(value); | |
if (this._isPanel) { | |
NativeExtension.SyncPanel(this.getNativeWindowHandle(), false); | |
} | |
if (isWindows && value) { | |
// Fixes window style to make it snappable again. | |
NativeExtension.MakeResizable(this.getNativeWindowHandle()); | |
} | |
} | |
setAspectRatio(value) { | |
this._browserWindow.setAspectRatio(value); | |
if (this._isPanel) { | |
NativeExtension.SyncPanel(this.getNativeWindowHandle(), false); | |
} | |
} | |
setFocusable(value) { | |
this._browserWindow.setFocusable(value); | |
if (!isDarwin) { | |
return; | |
} | |
if (!value && !this._isPanel) { | |
// converting to a native Panel to make the window non-focusable and non-activating on mac | |
NativeExtension.MakePanel(this.getNativeWindowHandle()); | |
this._isPanel = true; | |
} else if (value && this._isPanel) { | |
// converting to a native Window to make the window focusable and activating on mac | |
NativeExtension.MakeWindow(this.getNativeWindowHandle()); | |
this._isPanel = false; | |
} | |
} | |
setVisibleOnAllWorkspaces(...args) { | |
this._browserWindow.setVisibleOnAllWorkspaces(...args); | |
} | |
setAppDetails(options) { | |
this._browserWindow.setAppDetails(options); | |
} | |
initiateWindowMove() { | |
if (isWindows) { | |
NativeExtension.InitiateWindowMove(this.getNativeWindowHandle()); | |
} | |
} | |
orderBack() { | |
NativeExtension.OrderBack(this.getNativeWindowHandle()); | |
} | |
} | |
module.exports = { Panel }; |
@castroCrea I do not, and I haven't found a good solution to this yet. The code above I pulled out of the WhatsApp desktop client, but I'm not even sure how it's used. You can do the same with:
npx asar extract /Applications/WhatsApp.app/Contents/Resources/app.asar unpacked
and then look through unpacked for the. code above.
@ibash find it thanks
@ibash I make it work but it behave like a regular browser window, so sad
I create a Feature request in electron electron/electron#26596
dang, yeah. If I come across a solution I'll let you know.
thanks 👍 same
Hack!
Hey guys was able to solve this issue.
Make sure that you add this flag to your browser window when creating it .
this._electronWindow = new electron.BrowserWindow({ ...this.createOptions, titleBarStyle: 'customButtonsOnHover' });
@yarinsa
I tried adding titleBarStyle: 'customButtonsOnHover'
but that did not fix the issue for me. I'm on Big Sur on a M1 MBP.
Could you share you setup? Thanks
For who are fining solution here:
Nowadays, electron has supported create NSPanel directly by passing type:'panel' in BrowserWindow config.
Hi,
Do you have the functions_mac.cc also ?
I try to find an alternative to make NsPanel work again.
I found your solution here goabstract/electron-panel-window#6 but there is missing part the file functions_mac.cc
Did you found any other good solution ?
Thank you