gpuijs

Native shell

Window

The shell API follows Electron's, with Window in place of BrowserWindow. If you know Electron, you already know it. The host carries out each call with native AppKit windows through GPUI.

import { Window, render } from "@gpuijs/core/react" // or gpuijs/vue, gpuijs/solid

const win = new Window({
  width: 1200,
  height: 800,
  minWidth: 720,
  minHeight: 480,
  title: "Notes",
  titleBarStyle: "hiddenInset",
})

win.on("focus", () => console.log("focused"))
render(<App />) // renders into win

Warning

An app has one window for now. A second new Window() throws gpuijs: an app has one Window for now.

#Creating the window

Create the Window before rendering or touching document. Anything that needs the window first (render, document.body, a ResizeObserver) opens a default one, and a new Window(options) after that throws:

gpuijs: create the Window before rendering or touching the document

Importing the entry point doesn't open the window, so import { Window } from "@gpuijs/core/vue" (or react, solid) before new Window() is fine.

If the app never creates one, render opens a default window: 1024×768, centered, resizable, with a standard title bar titled with the app's name.

#Options

OptionTypeDefaultDescription
widthnumber1024Content width in points
heightnumber768Content height in points
minWidthnumbernoneMinimum width while resizing
minHeightnumbernoneMinimum height while resizing
titlestringapp nameThe title shown in the title bar and Window menu
resizablebooleantrueWhether the user can resize the window
minimizablebooleantrueWhether the window can be minimized
titleBarStyle"default" | "hidden" | "hiddenInset""default"hidden removes the title bar and runs content under the traffic lights. hiddenInset does the same with the traffic lights moved in to (20, 20).
trafficLightPosition{ x, y }noneWhere the traffic lights sit with a hidden title bar

The window opens centered on the main display. GPUIJS_WINDOW_SIZE=WxH overrides width and height, which is useful for screenshots and benchmarks.

#Methods

MethodDescription
render(element)React only: renders a React element into the window, like the render export (Electron's loadURL, for gpuijs). Vue and Solid apps use their entry point's render.
setTitle(title)Sets the title
getTitle()The current title
minimize()Minimizes the window to the Dock
maximize()Zooms the window, if it isn't already maximized
unmaximize()Un-zooms the window, if it's maximized
isMaximized()Whether it's maximized
setFullScreen(flag)Enters or leaves full screen
isFullScreen()Whether it's in full screen
focus()Brings the window to the front and focuses it
isFocused()Whether it's the key window
close()Closes the window, which quits the app
getBounds(){ x, y, width, height }
getSize()[width, height]
setSize(width, height)Resizes the content area

State queries (isMaximized, isFullScreen, isFocused, getBounds, getSize) answer from the state the host last reported, so they're synchronous and cheap. They're current as of the last window event.

#Static methods

MethodDescription
Window.getAllWindows()[win], or [] before a window exists
Window.getFocusedWindow()The window if it's focused, else null
Window.fromId(id)The window for id (always 1), else null

win.id is always 1.

#Events

Window is a Node EventEmitter. Use on, once and off.

EventWhen
ready-to-showThe window has opened
focusThe window became key
blurThe window stopped being key
resizeThe window's size or position changed
maximize, unmaximizeThe maximized state changed
enter-full-screen, leave-full-screenFull screen was entered or left
closeThe window is closing. The listener gets an event with a no-op preventDefault(), because closing can't be cancelled yet.
closedRight after close
win.on("resize", () => {
  const { width, height } = win.getBounds()
  saveWindowSize(width, height)
})

Focus and blur also emit browser-window-focus and browser-window-blur on app.

#Window lifetime

Closing the window quits the app. The host quits when its window closes, which closes the socket to the JavaScript process, which then exits. Likewise, if the JavaScript process exits or crashes, the host quits.

#Visibility

When the window is minimized, fully covered or on another Space, document.visibilityState becomes "hidden" and document hears visibilitychange. requestAnimationFrame callbacks pause until the window shows again, as browsers pause background tabs. See visibilityState().

  • Custom title bars: drawing your own title bar with titleBarStyle: "hidden" and app-region: drag.
  • Menus: the menu bar, Dock menu and context menus.
  • Dialogs and app: open and save panels, message boxes, and the app object.