Browse Source

docs: add window customization guide (#31054) (#31507)

* docs: add window customization guide

* fixes

* Update docs/api/browser-window.md

Co-authored-by: Mark Lee <[email protected]>

* Update docs/api/browser-window.md

Co-authored-by: Mark Lee <[email protected]>

* Update docs/fiddles/windows/manage-windows/frameless-window/index.html

Co-authored-by: Mark Lee <[email protected]>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <[email protected]>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <[email protected]>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <[email protected]>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <[email protected]>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <[email protected]>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <[email protected]>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <[email protected]>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <[email protected]>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <[email protected]>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <[email protected]>

* Update docs/tutorial/window-customization.md

Co-authored-by: Mark Lee <[email protected]>

* fix code fence

Co-authored-by: Mark Lee <[email protected]>

Co-authored-by: Mark Lee <[email protected]>
Erick Zhao 3 years ago
parent
commit
0db4d5add5

+ 6 - 5
docs/api/browser-window.md

@@ -17,10 +17,11 @@ win.loadURL('https://github.com')
 win.loadFile('index.html')
 ```
 
-## Frameless window
+## Window customization
 
-To create a window without chrome, or a transparent window in arbitrary shape,
-you can use the [Frameless Window](frameless-window.md) API.
+The `BrowserWindow` class exposes various ways to modify the look and behavior of
+your app's windows. For more details, see the [Window Customization](../tutorial/window-customization.md)
+tutorial.
 
 ## Showing the window gracefully
 
@@ -184,7 +185,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
     `true`.
   * `paintWhenInitiallyHidden` Boolean (optional) - Whether the renderer should be active when `show` is `false` and it has just been created.  In order for `document.visibilityState` to work correctly on first load with `show: false` you should set this to `false`.  Setting this to `false` will cause the `ready-to-show` event to not fire.  Default is `true`.
   * `frame` Boolean (optional) - Specify `false` to create a
-    [Frameless Window](frameless-window.md). Default is `true`.
+    [frameless window](../tutorial/window-customization.md#create-frameless-windows). Default is `true`.
   * `parent` BrowserWindow (optional) - Specify parent window. Default is `null`.
   * `modal` Boolean (optional) - Whether this is a modal window. This only works when the
     window is a child window. Default is `false`.
@@ -206,7 +207,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
     transparent) and 1.0 (fully opaque). This is only implemented on Windows and macOS.
   * `darkTheme` Boolean (optional) - Forces using dark theme for the window, only works on
     some GTK+3 desktop environments. Default is `false`.
-  * `transparent` Boolean (optional) - Makes the window [transparent](frameless-window.md#transparent-window).
+  * `transparent` Boolean (optional) - Makes the window [transparent](../tutorial/window-customization.md#create-transparent-windows).
     Default is `false`. On Windows, does not work unless the window is frameless.
   * `type` String (optional) - The type of window, default is normal window. See more about
     this below.

+ 0 - 221
docs/api/frameless-window.md

@@ -1,221 +0,0 @@
-# Frameless Window
-
-> Open a window without toolbars, borders, or other graphical "chrome".
-
-A frameless window is a window that has no
-[chrome](https://developer.mozilla.org/en-US/docs/Glossary/Chrome), the parts of
-the window, like toolbars, that are not a part of the web page. These are
-options on the [`BrowserWindow`](browser-window.md) class.
-
-## Create a frameless window
-
-To create a frameless window, you need to set `frame` to `false` in
-[BrowserWindow](browser-window.md)'s `options`:
-
-```javascript
-const { BrowserWindow } = require('electron')
-const win = new BrowserWindow({ width: 800, height: 600, frame: false })
-win.show()
-```
-
-### Alternatives
-
-There's an alternative way to specify a chromeless window on macOS and Windows.
-Instead of setting `frame` to `false` which disables both the titlebar and window controls,
-you may want to have the title bar hidden and your content extend to the full window size,
-yet still preserve the window controls ("traffic lights" on macOS) for standard window actions.
-You can do so by specifying the `titleBarStyle` option:
-
-#### `hidden`
-
-Results in a hidden title bar and a full size content window. On macOS, the title bar still has the standard window controls (“traffic lights”) in the top left.
-
-```javascript
-const { BrowserWindow } = require('electron')
-const win = new BrowserWindow({ titleBarStyle: 'hidden' })
-win.show()
-```
-
-### Alternatives on macOS
-
-#### `hiddenInset`
-
-Results in a hidden title bar with an alternative look where the traffic light buttons are slightly more inset from the window edge.
-
-```javascript
-const { BrowserWindow } = require('electron')
-const win = new BrowserWindow({ titleBarStyle: 'hiddenInset' })
-win.show()
-```
-
-#### `customButtonsOnHover`
-
-Uses custom drawn close, and miniaturize buttons that display
-when hovering in the top left of the window. The fullscreen button
-is not available due to restrictions of frameless windows as they
-interface with Apple's macOS window masks. These custom buttons prevent
-issues with mouse events that occur with the standard window toolbar buttons.
-This option is only applicable for frameless windows.
-
-```javascript
-const { BrowserWindow } = require('electron')
-const win = new BrowserWindow({ titleBarStyle: 'customButtonsOnHover', frame: false })
-win.show()
-```
-
-## Windows Control Overlay
-
-When using a frameless window in conjuction with `win.setWindowButtonVisibility(true)` on macOS, using one of the `titleBarStyle`s as described above so
-that the traffic lights are visible, or using `titleBarStyle: hidden` on Windows, you can access the Window Controls Overlay [JavaScript APIs][overlay-javascript-apis] and
-[CSS Environment Variables][overlay-css-env-vars] by setting the `titleBarOverlay` option to true. Specifying `true` will result in an overlay with default system colors.
-
-On Windows, you can also specify the color of the overlay and its symbols by setting `titleBarOverlay` to an object with the options `color` and `symbolColor`. If an option is not specified, the color will default to its system color for the window control buttons:
-
-```javascript
-const { BrowserWindow } = require('electron')
-const win = new BrowserWindow({
-  titleBarStyle: 'hidden',
-  titleBarOverlay: true
-})
-win.show()
-```
-
-```javascript
-const { BrowserWindow } = require('electron')
-const win = new BrowserWindow({
-  titleBarStyle: 'hidden',
-  titleBarOverlay: {
-    color: '#2f3241',
-    symbolColor: '#74b1be'
-  }
-})
-win.show()
-```
-
-## Transparent window
-
-By setting the `transparent` option to `true`, you can also make the frameless
-window transparent:
-
-```javascript
-const { BrowserWindow } = require('electron')
-const win = new BrowserWindow({ transparent: true, frame: false })
-win.show()
-```
-
-### Limitations
-
-* You can not click through the transparent area. We are going to introduce an
-  API to set window shape to solve this, see
-  [our issue](https://github.com/electron/electron/issues/1335) for details.
-* Transparent windows are not resizable. Setting `resizable` to `true` may make
-  a transparent window stop working on some platforms.
-* The `blur` filter only applies to the web page, so there is no way to apply
-  blur effect to the content below the window (i.e. other applications open on
-  the user's system).
-* The window will not be transparent when DevTools is opened.
-* On Windows operating systems,
-  * transparent windows will not work when DWM is
-  disabled.
-  * transparent windows can not be maximized using the Windows system menu or by double clicking the title bar. The reasoning behind this can be seen on [this pull request](https://github.com/electron/electron/pull/28207).
-* On Linux, users have to put `--enable-transparent-visuals --disable-gpu` in
-  the command line to disable GPU and allow ARGB to make transparent window,
-  this is caused by an upstream bug that [alpha channel doesn't work on some
-  NVidia drivers](https://bugs.chromium.org/p/chromium/issues/detail?id=369209) on
-  Linux.
-* On Mac, the native window shadow will not be shown on a transparent window.
-
-## Click-through window
-
-To create a click-through window, i.e. making the window ignore all mouse
-events, you can call the [win.setIgnoreMouseEvents(ignore)][ignore-mouse-events]
-API:
-
-```javascript
-const { BrowserWindow } = require('electron')
-const win = new BrowserWindow()
-win.setIgnoreMouseEvents(true)
-```
-
-### Forwarding
-
-Ignoring mouse messages makes the web page oblivious to mouse movement, meaning
-that mouse movement events will not be emitted. On Windows operating systems an
-optional parameter can be used to forward mouse move messages to the web page,
-allowing events such as `mouseleave` to be emitted:
-
-```javascript
-const { ipcRenderer } = require('electron')
-const el = document.getElementById('clickThroughElement')
-el.addEventListener('mouseenter', () => {
-  ipcRenderer.send('set-ignore-mouse-events', true, { forward: true })
-})
-el.addEventListener('mouseleave', () => {
-  ipcRenderer.send('set-ignore-mouse-events', false)
-})
-
-// Main process
-const { ipcMain } = require('electron')
-ipcMain.on('set-ignore-mouse-events', (event, ...args) => {
-  BrowserWindow.fromWebContents(event.sender).setIgnoreMouseEvents(...args)
-})
-```
-
-This makes the web page click-through when over `el`, and returns to normal
-outside it.
-
-## Draggable region
-
-By default, the frameless window is non-draggable. Apps need to specify
-`-webkit-app-region: drag` in CSS to tell Electron which regions are draggable
-(like the OS's standard titlebar), and apps can also use
-`-webkit-app-region: no-drag` to exclude the non-draggable area from the
- draggable region. Note that only rectangular shapes are currently supported.
-
-Note: `-webkit-app-region: drag` is known to have problems while the developer tools are open. See this [GitHub issue](https://github.com/electron/electron/issues/3647) for more information including a workaround.
-
-To make the whole window draggable, you can add `-webkit-app-region: drag` as
-`body`'s style:
-
-```html
-<body style="-webkit-app-region: drag">
-</body>
-```
-
-And note that if you have made the whole window draggable, you must also mark
-buttons as non-draggable, otherwise it would be impossible for users to click on
-them:
-
-```css
-button {
-  -webkit-app-region: no-drag;
-}
-```
-
-If you're only setting a custom titlebar as draggable, you also need to make all
-buttons in titlebar non-draggable.
-
-## Text selection
-
-In a frameless window the dragging behavior may conflict with selecting text.
-For example, when you drag the titlebar you may accidentally select the text on
-the titlebar. To prevent this, you need to disable text selection within a
-draggable area like this:
-
-```css
-.titlebar {
-  -webkit-user-select: none;
-  -webkit-app-region: drag;
-}
-```
-
-## Context menu
-
-On some platforms, the draggable area will be treated as a non-client frame, so
-when you right click on it a system menu will pop up. To make the context menu
-behave correctly on all platforms you should never use a custom context menu on
-draggable areas.
-
-[ignore-mouse-events]: browser-window.md#winsetignoremouseeventsignore-options
-[overlay-javascript-apis]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#javascript-apis
-[overlay-css-env-vars]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#css-environment-variables

+ 3 - 2
docs/fiddles/windows/manage-windows/frameless-window/index.html

@@ -59,8 +59,9 @@
 
           <p>
             For more details, see the
-            <a href="https://electronjs.org/docs/api/frameless-window/">
-              Frameless Window
+            <a href="https://electronjs.org/docs/tutorial/window-customization/">
+              Window Customization
+
             </a>
             documentation.
           </p>

+ 1 - 1
docs/tutorial/offscreen-rendering.md

@@ -17,7 +17,7 @@ the dirty area is passed to the `paint` event to be more efficient.
 losses with no benefits.
 * When nothing is happening on a webpage, no frames are generated.
 * An offscreen window is always created as a
-[Frameless Window](../api/frameless-window.md).
+[Frameless Window](../tutorial/window-customization.md)..
 
 ### Rendering Modes
 

+ 271 - 0
docs/tutorial/window-customization.md

@@ -0,0 +1,271 @@
+# Window Customization
+
+The `BrowserWindow` module is the foundation of your Electron application, and it exposes
+many APIs that can change the look and behavior of your browser windows. In this
+tutorial, we will be going over the various use-cases for window customization on
+macOS, Windows, and Linux.
+
+## Create frameless windows
+
+A frameless window is a window that has no [chrome]. Not to be confused with the Google
+Chrome browser, window _chrome_ refers to the parts of the window (e.g. toolbars, controls)
+that are not a part of the web page.
+
+To create a frameless window, you need to set `frame` to `false` in the `BrowserWindow`
+constructor.
+
+```javascript title='main.js'
+const { BrowserWindow } = require('electron')
+const win = new BrowserWindow({ frame: false })
+```
+
+## Apply custom title bar styles _macOS_ _Windows_
+
+Title bar styles allow you to hide most of a BrowserWindow's chrome while keeping the
+system's native window controls intact and can be configured with the `titleBarStyle`
+option in the `BrowserWindow` constructor.
+
+Applying the `hidden` title bar style results in a hidden title bar and a full-size
+content window.
+
+```javascript title='main.js'
+const { BrowserWindow } = require('electron')
+const win = new BrowserWindow({ titleBarStyle: 'hidden' })
+```
+
+### Control the traffic lights _macOS_
+
+On macOS, applying the `hidden` title bar style will still expose the standard window
+controls (“traffic lights”) in the top left.
+
+#### Customize the look of your traffic lights _macOS_
+
+The `customButtonsOnHover` title bar style will hide the traffic lights until you hover
+over them. This is useful if you want to create custom traffic lights in your HTML but still
+use the native UI to control the window.
+
+```javascript
+const { BrowserWindow } = require('electron')
+const win = new BrowserWindow({ titleBarStyle: 'customButtonsOnHover' })
+```
+
+#### Customize the traffic light position _macOS_
+
+To modify the position of the traffic light window controls, there are two configuration
+options available.
+
+Applying `hiddenInset` title bar style will shift the vertical inset of the traffic lights
+by a fixed amount.
+
+```javascript title='main.js'
+const { BrowserWindow } = require('electron')
+const win = new BrowserWindow({ titleBarStyle: 'hiddenInset' })
+```
+
+If you need more granular control over the positioning of the traffic lights, you can pass
+a set of coordinates to the `trafficLightPosition` option in the `BrowserWindow`
+constructor.
+
+```javascript title='main.js'
+const { BrowserWindow } = require('electron')
+const win = new BrowserWindow({
+  titleBarStyle: 'hidden',
+  trafficLightPosition: { x: 10, y: 10 }
+})
+```
+
+#### Show and hide the traffic lights programmatically _macOS_
+
+You can also show and hide the traffic lights programmatically from the main process.
+The `win.setWindowButtonVisibility` forces traffic lights to be show or hidden depending
+on the value of its boolean parameter.
+
+```javascript title='main.js'
+const { BrowserWindow } = require('electron')
+const win = new BrowserWindow()
+// hides the traffic lights
+win.setWindowButtonVisibility(false)
+```
+
+> Note: Given the number of APIs available, there are many ways of achieving this. For instance,
+> combining `frame: false` with `win.setWindowButtonVisibility(true)` will yield the same
+> layout outcome as setting `titleBarStyle: 'hidden'`.
+
+## Window Controls Overlay _macOS_ _Windows_
+
+The [Window Controls Overlay API] is a web standard that gives web apps the ability to
+customize their title bar region when installed on desktop. Electron exposes this API
+through the `BrowserWindow` constructor option `titleBarOverlay`.
+
+This option only works whenever a custom `titlebarStyle` is applied on macOS or Windows.
+When `titleBarOverlay` is enabled, the window controls become exposed in their default
+position, and DOM elements cannot use the area underneath this region.
+
+The `titleBarOverlay` option accepts two different value formats.
+
+Specifying `true` on either platform will result in an overlay region with default
+system colors:
+
+```javascript title='main.js'
+// on macOS or Windows
+const { BrowserWindow } = require('electron')
+const win = new BrowserWindow({
+  titleBarStyle: 'hidden',
+  titleBarOverlay: true
+})
+```
+
+On Windows, you can also specify the color of the overlay and its symbols by setting
+`titleBarOverlay` to an object with the `color` and `symbolColor` properties. If an option
+is not specified, the color will default to its system color for the window control buttons:
+
+```javascript title='main.js'
+// on Windows
+const { BrowserWindow } = require('electron')
+const win = new BrowserWindow({
+  titleBarStyle: 'hidden',
+  titleBarOverlay: {
+    color: '#2f3241',
+    symbolColor: '#74b1be'
+  }
+})
+```
+
+> Note: Once your title bar overlay is enabled from the main process, you can access the overlay's
+> color and dimension values from a renderer using a set of readonly
+> [JavaScript APIs][overlay-javascript-apis] and [CSS Environment Variables][overlay-css-env-vars].
+
+## Create transparent windows
+
+By setting the `transparent` option to `true`, you can make a fully transparent window.
+
+```javascript title='main.js'
+const { BrowserWindow } = require('electron')
+const win = new BrowserWindow({ transparent: true })
+```
+
+### Limitations
+
+* You cannot click through the transparent area. See
+  [#1335](https://github.com/electron/electron/issues/1335) for details.
+* Transparent windows are not resizable. Setting `resizable` to `true` may make
+  a transparent window stop working on some platforms.
+* The CSS [`blur()`] filter only applies to the window's web contents, so there is no way to apply
+  blur effect to the content below the window (i.e. other applications open on
+  the user's system).
+* The window will not be transparent when DevTools is opened.
+* On _Windows_:
+  * Transparent windows will not work when DWM is disabled.
+  * Transparent windows can not be maximized using the Windows system menu or by double
+  clicking the title bar. The reasoning behind this can be seen on
+  PR [#28207](https://github.com/electron/electron/pull/28207).
+* On _macOS_:
+  * The native window shadow will not be shown on a transparent window.
+
+## Create click-through windows
+
+To create a click-through window, i.e. making the window ignore all mouse
+events, you can call the [win.setIgnoreMouseEvents(ignore)][ignore-mouse-events]
+API:
+
+```javascript title='main.js'
+const { BrowserWindow } = require('electron')
+const win = new BrowserWindow()
+win.setIgnoreMouseEvents(true)
+```
+
+### Forward mouse events _macOS_ _Windows_
+
+Ignoring mouse messages makes the web contents oblivious to mouse movement,
+meaning that mouse movement events will not be emitted. On Windows and macOS, an
+optional parameter can be used to forward mouse move messages to the web page,
+allowing events such as `mouseleave` to be emitted:
+
+```javascript title='main.js'
+const { BrowserWindow, ipcMain } = require('electron')
+const path = require('path')
+
+const win = new BrowserWindow({
+  webPreferences: {
+    preload: path.join(__dirname, 'preload.js')
+  }
+})
+
+ipcMain.on('set-ignore-mouse-events', (event, ...args) => {
+  const win = BrowserWindow.fromWebContents(event.sender)
+  win.setIgnoreMouseEvents(...args)
+})
+```
+
+```javascript title='preload.js'
+window.addEventListener('DOMContentLoaded', () => {
+  const el = document.getElementById('clickThroughElement')
+  el.addEventListener('mouseenter', () => {
+    ipcRenderer.send('set-ignore-mouse-events', true, { forward: true })
+  })
+  el.addEventListener('mouseleave', () => {
+    ipcRenderer.send('set-ignore-mouse-events', false)
+  })
+})
+```
+
+This makes the web page click-through when over the `#clickThroughElement` element,
+and returns to normal outside it.
+
+## Set custom draggable region
+
+By default, the frameless window is non-draggable. Apps need to specify
+`-webkit-app-region: drag` in CSS to tell Electron which regions are draggable
+(like the OS's standard titlebar), and apps can also use
+`-webkit-app-region: no-drag` to exclude the non-draggable area from the
+ draggable region. Note that only rectangular shapes are currently supported.
+
+To make the whole window draggable, you can add `-webkit-app-region: drag` as
+`body`'s style:
+
+```css title='styles.css'
+body {
+  -webkit-app-region: drag;
+}
+```
+
+And note that if you have made the whole window draggable, you must also mark
+buttons as non-draggable, otherwise it would be impossible for users to click on
+them:
+
+```css title='styles.css'
+button {
+  -webkit-app-region: no-drag;
+}
+```
+
+If you're only setting a custom titlebar as draggable, you also need to make all
+buttons in titlebar non-draggable.
+
+### Tip: disable text selection
+
+When creating a draggable region, the dragging behavior may conflict with text selection.
+For example, when you drag the titlebar, you may accidentally select its text contents.
+To prevent this, you need to disable text selection within a draggable area like this:
+
+```css
+.titlebar {
+  -webkit-user-select: none;
+  -webkit-app-region: drag;
+}
+```
+
+### Tip: disable context menus
+
+On some platforms, the draggable area will be treated as a non-client frame, so
+when you right click on it, a system menu will pop up. To make the context menu
+behave correctly on all platforms, you should never use a custom context menu on
+draggable areas.
+
+[`blur()`]: https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/blur()
+[`BrowserWindow`]: ../api/browser-window.md
+[chrome]: https://developer.mozilla.org/en-US/docs/Glossary/Chrome
+[ignore-mouse-events]: ../api/browser-window.md#winsetignoremouseeventsignore-options
+[overlay-css-env-vars]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#css-environment-variables
+[overlay-javascript-apis]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#javascript-apis
+[Window Controls Overlay API]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md

+ 0 - 1
filenames.auto.gni

@@ -23,7 +23,6 @@ auto_filenames = {
     "docs/api/environment-variables.md",
     "docs/api/extensions.md",
     "docs/api/file-object.md",
-    "docs/api/frameless-window.md",
     "docs/api/global-shortcut.md",
     "docs/api/in-app-purchase.md",
     "docs/api/incoming-message.md",