Window management
Overview
cloudWindow manages the current window: state, APIs for control, and messaging.
Import
import cloudWindow from '@ugreen-nas/core/cloudWindow'Messaging concepts
Messages
Sent via send / sendTo; the target listens with cloudWindow.listenWindowData. Callbacks receive the source for every message/event.
Note: When using send(data, event), sendTo(winId, data, event), etc., custom event names must not collide with built-in window events listed in this doc (e.g. load-finish, close, focus). Otherwise the Promise is rejected with an error.
Events
cloudWindow.on('xxx', (data, from) => {
// data: payload
// from: source
})Window events
Windows created with cloudWindowMgr.create() expose the following events.
load-finish
Fires when the window finishes loading.
Callback arguments:
| Name | Type | Description |
|---|---|---|
| url | string | Loaded URL |
load-error
Fires when loading fails.
| Name | Type | Description |
|---|---|---|
| url | string | URL that failed |
focus
Fires when the window gains focus.
Note: No payload.
blur
Fires when the window loses focus.
Note: No payload.
move
Fires when the window finishes moving.
| Name | Type | Description |
|---|---|---|
| x | number | Window x |
| y | number | Window y |
| width | number | Width |
| height | number | Height |
moving
Fires continuously while the window is moving.
| Name | Type | Description |
|---|---|---|
| x | number | Window x |
| y | number | Window y |
| width | number | Width |
| height | number | Height |
resizing
Fires continuously while resizing (drag).
| Name | Type | Description |
|---|---|---|
| x | number | Window x |
| y | number | Window y |
| width | number | Width |
| height | number | Height |
resize
Fires when resize completes.
| Name | Type | Description |
|---|---|---|
| x | number | Window x |
| y | number | Window y |
| width | number | Width |
| height | number | Height |
maximize
Fires when maximized.
| Name | Type | Description |
|---|---|---|
| x | number | Window x |
| y | number | Window y |
| width | number | Width |
| height | number | Height |
un-maximize
Fires when leaving maximized state.
| Name | Type | Description |
|---|---|---|
| x | number | Window x |
| y | number | Window y |
| width | number | Width |
| height | number | Height |
minimize
Fires when minimized.
Note: No payload.
restore
Fires when restored from minimized.
Note: No payload.
close
Fires after the window closes; cannot be cancelled.
| Name | Type | Description |
|---|---|---|
| data | { fake: boolean } | fake === true means hide/keep-alive; false means real close/destroy |
before-close
Fires before close; call preventDefault() to cancel.
| Name | Type | Description |
|---|---|---|
| e | Event | Native event; e.preventDefault() blocks close |
hostChange
Fires when the requested BaseUrl changes (e.g. device address).
| Name | Type | Description |
|---|---|---|
| data | any | Change details (e.g. new URL) |
always-on-top-changed
Fires when always-on-top changes.
| Name | Type | Description |
|---|---|---|
| value | boolean | Current always-on-top state |
mouse-enter
Fires when the pointer enters the window.
| Name | Type | Description |
|---|---|---|
| x | number | Window x |
| y | number | Window y |
| width | number | Width |
| height | number | Height |
| top | boolean | Whether window is top-most |
mouse-leave
Fires when the pointer leaves the window.
| Name | Type | Description |
|---|---|---|
| x | number | Window x |
| y | number | Window y |
| width | number | Width |
| height | number | Height |
| top | boolean | Whether window is top-most |
before-help
Fires when the help button is clicked; preventDefault can block default behavior.
| Name | Type | Description |
|---|---|---|
| e | BeforeHelpEvent | CustomEvent; e.detail.message is help URL, e.detail.version may be null |
| url | string | undefined | Help URL (shortcut matching e.detail.message) |
before-show
Fires before a keep-alive window is shown/activated.
Note: No payload.
show
Fires when the window becomes visible (from hidden or show becomes true).
Note: No payload.
hide
Fires when hidden (show becomes false).
Note: No payload.
will-show
Fires before transitioning from hidden to visible (host cloudWindowMgr.show() sets config.show to true after this synchronous channel).
| Name | Type | Description |
|---|---|---|
| e | Event | preventDefault() can block this show; window stays hidden |
message
Fires when another window uses sendTo or the desktop uses send.
| Name | Type | Description |
|---|---|---|
| data | any | Payload |
| from | string | Sender window id or source |
wsData
In-window event from desktop WebSocket downlink.
| Name | Type | Description |
|---|---|---|
| data | object | WebSocket packet |
Example backend payload shape:
{
"app_id": "com.xxxx",
"data": {
"body": {},
"event": "xxxx"
},
"role": "",
"type": "app-event"
}Drag-and-drop events
Based on HTML5 Drag and Drop:
- Drag files from the OS into the window
- Drag elements to other windows
- Drag from browser into the window
- Cross-window drags
Order
Normal flow:
dragEnter → dragOver (repeats) → drop/dragEnd → dragLeaveCross-window:
Window A: dragEnter → dragOver → dragLeave
Window B: dragEnter → dragOver → drop/dragEnd → dragLeavedragEnter
Fires when a drag enters the window.
When:
- External files/content enter the window
- Another window drags into this one
- Child element drags over parent in the same window
Callback arguments:
| Name | Type | Description |
|---|---|---|
| data | DragData | any | undefined | Drag payload |
Sources
- Browser
DataTransfer— if no custom payload, a standardDragDataobject - Empty drag — neither custom data nor
dataTransfer.types→undefined
DragData shape:
interface DragData {
files?: File[]
items?: DataTransferItemList
types?: string[]
effectAllowed?: string
dropEffect?: string
text?: string
[key: string]: any
}Notes:
files: files only, not folder contentsitems: lower-level API;webkitGetAsEntry()can recurse folders
Example:
cloudWindow.on('dragEnter', (data) => {
if (!data) {
console.log('Empty drag')
return
}
if (typeof data === 'object' && !data.types) {
console.log('Custom payload:', data)
}
if (data.files) {
console.log('Files:', data.files)
}
if (data.text) {
console.log('Text:', data.text)
}
})dragOver
Fires continuously while dragging over the window.
| Name | Type | Description |
|---|---|---|
| data | DragData | any | undefined | Same as dragEnter |
dragEnd
Fires when the drag is released (drop) in the window.
| Name | Type | Description |
|---|---|---|
| data | DragData | any | undefined | Same as dragEnter |
When:
- Mouse released inside the window
- Released on empty chrome not swallowed by a child
drop
Note: If a child calls e.stopPropagation(), dragEnd may not fire; dragEnd is a bubbling fallback.
Example:
cloudWindow.on('dragEnd', (data) => {
if (data?.files) {
console.log('Files:', data.files)
} else if (data) {
console.log('Custom:', data)
}
})dragLeave
Fires when the drag leaves the window.
Note: Counter-based to avoid spurious child-boundary events. No payload.
Drag scenarios
Scenario 1: cross-window custom data
Sender: in dragstart, use dataTransfer (setData / effectAllowed) or your pipeline.
function startDrag(e: DragEvent) {
if (!e.dataTransfer) return
e.dataTransfer.setData('text/plain', JSON.stringify({ id: 123, name: 'Item from test2' }))
e.dataTransfer.effectAllowed = 'copy'
}Receiver (JSON in text/plain → parse data.text):
cloudWindow.on('dragEnd', (data) => {
if (data?.text) {
try {
const payload = JSON.parse(data.text)
console.log('Cross-window payload:', payload)
} catch {
/* treat as plain text */
}
}
})Scenario 2: custom drop zone
Use native HTML5 on a zone (e.g. upload box):
<template>
<div
class="drop-zone"
@dragenter="handleDragEnter"
@dragleave="handleDragLeave"
@dragover.prevent="handleDragOver"
@drop.prevent.stop="handleDrop"
>
Drop files here
</div>
</template>
<script>
export default {
methods: {
handleDrop(e) {
// Stop bubbling so cloudWindow dragEnd does not fire
e.stopPropagation()
const files = e.dataTransfer.files
console.log('Drop zone files:', files)
}
}
}
</script>Note: Custom zones should call e.preventDefault() and e.stopPropagation(); the latter prevents bubbling to cloudWindow’s dragEnd.
Drag notes
Payload may be:
undefined— empty/invalid dragDragData— standard browser payload- Any custom object — from internal drag plumbing if present
Suggested handling:
cloudWindow.on('dragEnd', (data) => {
if (!data) {
console.log('Invalid drag')
return
}
if (data.files) {
// handle files
} else if (data.id) {
// handle custom payload
}
})Static properties
cloudWindow.winId
Read-only unique id of the current window.
Type: string
Methods
Child windows
createSubWin()
Creates a child window; options match Window configuration.
Only with explicit belowGroup: null is it treated as non-subordinate (and may inherit icon); otherwise belowGroup and parent are set to this window’s winId.
Returns: Promise<string> resolving to the child options.name
Size and position
getSize()
Current window size.
Returns: Promise<{ width: number; height: number }>
setSize()
Sets width/height. If maximized, exits maximize first.
| Name | Type | Required | Description |
|---|---|---|---|
| width | number | Yes | Width |
| height | number | Yes | Height |
Returns: Promise<void>
getSizeInfo()
Full geometry.
Returns: Promise<SizeInfo>
interface SizeInfo {
x: number
y: number
width: number
height: number
maxHeight: number
maxWidth: number
minHeight: number
minWidth: number
radius: number
}setMinSize()
Minimum width/height.
| Name | Type | Required | Description |
|---|---|---|---|
| width | number | Yes | Min width |
| height | number | Yes | Min height |
Returns: Promise<void>
setMaximumSize()
Max dimensions; maximize respects these instead of full screen.
| Name | Type | Required | Description |
|---|---|---|---|
| width | number | Yes | Max width; 0 or negative = unlimited |
| height | number | Yes | Max height; 0 or negative = unlimited |
Returns: Promise<void>
getPosition()
Returns: Promise<{ x: number; y: number }>
setPosition()
| Name | Type | Required | Description |
|---|---|---|---|
| x | number | Yes | x |
| y | number | Yes | y |
Returns: Promise<void>
center()
Center in the work area.
Returns: Promise<void>
getRelativePos()
Maps pageX/pageY to system-relative coordinates.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| event | object | Yes | — | Object with pageX, pageY |
| offset | { x: number; y: number } | No | { x: 0, y: 0 } | Offset |
| reserve | boolean | No | false | Invert mode |
Returns: Promise<{ pageX: number; pageY: number }>
Window state
maximize()
Returns: Promise<void>
unmaximize()
Returns: Promise<void>
isMaximized()
Returns: Promise<boolean>
minimize()
Returns: Promise<void>
restore()
Bring to front and exit minimize (not the same as the title-bar restore toggle for maximize).
Returns: Promise<void>
isMinimized()
Returns: Promise<boolean>
show()
Sets show to true; fires show when becoming visible.
Returns: Promise<void>
hide()
Sets show to false; window stays in memory.
Returns: Promise<void>
Window control
close()
Triggers before-close (cancellable) then close.
Returns: void
loadUrl()
| Name | Type | Required | Description |
|---|---|---|---|
| url | string | Yes | URL to load |
Returns: Promise<void>
damaged()
Marks the window broken and clears cache-related state.
Returns: Promise<void>
Note: sets cacheTime to 0 and hideOnClose to false; use when content is corrupted and must reload.
cloudWindow.damaged()
cloudWindow.close()setMovable()
| Name | Type | Required | Description |
|---|---|---|---|
| state | boolean | Yes | Allow drag-move |
Returns: Promise<void>
setResizable()
| Name | Type | Required | Description |
|---|---|---|---|
| resizable | boolean | Yes | Allow resize |
Returns: Promise<void>
setMinimizable()
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| open | boolean | Yes | — | Allow minimize |
| showIcon | boolean | No | false | Still show minimize icon when not allowed |
Returns: Promise<void>
setMaximizable()
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| open | boolean | Yes | — | Allow maximize |
| showIcon | boolean | No | false | Still show maximize icon when not allowed |
Returns: Promise<void>
setClosable()
| Name | Type | Required | Description |
|---|---|---|---|
| closeable | boolean | Yes | Allow close |
Returns: Promise<void>
setAlwaysOnTop()
| Name | Type | Required | Description |
|---|---|---|---|
| val | boolean | Yes | Always on top |
Returns: Promise<void>
isAlwaysOnTop()
Returns: Promise<boolean>
focus()
Returns: Promise<void>
blur()
Returns: Promise<void>
isFocus()
Returns: Promise<boolean>
Appearance
getTitle()
Returns: Promise<string>
setTitle()
Sets title bar (and taskbar title). Not available on desktop shell in some builds.
| Name | Type | Required | Description |
|---|---|---|---|
| title | string | Yes | Title |
Returns: Promise<void>
getIcon()
Returns: Promise<string | null> — icon from create options
setBackgroundColor()
| Name | Type | Required | Description |
|---|---|---|---|
| color | string | Yes | CSS color; transparent for transparent |
Returns: Promise<void>
setShadowColor()
| Name | Type | Required | Description |
|---|---|---|---|
| color | string | boolean | Yes | Shadow CSS; true default; false none |
Returns: Promise<void>
setRadius()
| Name | Type | Required | Description |
|---|---|---|---|
| radius | number | Yes | Corner radius (px) |
Returns: Promise<void>
setStyle()
Custom styles on the window element; numeric values get px.
| Name | Type | Required | Description |
|---|---|---|---|
| obj | Record<string, string | number> | Yes | Style map |
Returns: Promise<void>
Blocked properties (layout/shell protection): width, height, left, top, bottom, right, position, padding, margin, z-index, background, background-image, box-shadow, border-radius, display
await cloudWindow.setStyle({
border: '2px solid #409eff',
borderStyle: 'dashed'
})
await cloudWindow.setStyle({
opacity: 0.95,
transition: 'all 0.3s ease'
})registerHeader()
Registers a custom drag/title region; forces frame = false; unregistering does not restore frame.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| handle | HTMLElement | Element | Yes | — | Drag handle element |
| focus | boolean | No | false | Replace previous handle |
Returns: Promise<Function | 0> — usually a cleanup function; 0 in legacy-compat paths
setActionPosition()
Custom control-button position; forces frame = false.
| Name | Type | Required | Description |
|---|---|---|---|
| y | number | Yes | Button Y |
| x | number | No | Button X (Mac only) |
Returns: Promise<number> — 1 on success
setActionVisible()
Show/hide window chrome buttons.
| Name | Type | Required | Description |
|---|---|---|---|
| actionRange | Array<'mini' | 'close' | 'restore' | 'help'> | Yes | Which buttons |
| state | boolean | Yes | true show |
Returns: Promise<void>
await cloudWindow.setActionVisible(['mini', 'help'], false)
await cloudWindow.setActionVisible(['mini', 'close', 'restore', 'help'], true)setHelpInfo()
Update help button; undefined hides it.
| Name | Type | Required | Description |
|---|---|---|---|
| info | string | undefined | Yes | Help URL or text |
Returns: Promise<void>
Messaging
listenWindowData()
Listen for create data and send payloads.
| Name | Type | Required | Description |
|---|---|---|---|
| callback | (message: any, from: string) => void | Yes | Handler |
Returns: disposer function
send()
Send data to the desktop shell.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| data | any | Yes | — | Payload |
| event | string | No | '' | Custom event name; must not clash with built-ins |
Returns: Promise<void>
sendEvent()
Send an event to the shell.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| event | string | Yes | — | Custom event name |
| data | any | No | undefined | Payload |
Returns: Promise<void>
sendTo()
Send to a window; target listens with on('message', ...).
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| winId | string | Yes | — | Target id |
| data | any | No | undefined | Payload |
| event | string | No | '' | Custom event name |
Returns: Promise<void>
sendEventTo()
Send event to a window; target uses on(event, ...).
| Name | Type | Required | Description |
|---|---|---|---|
| winId | string | Yes | Target |
| event | string | Yes | Custom event name |
| data | any | No | Payload |
Returns: Promise<void>
sendEventToGroup()
Broadcast to windows sharing config.group. Use carefully.
| Name | Type | Required | Description |
|---|---|---|---|
| group | string | string[] | Yes | Group name(s) |
| event | string | Yes | Custom event name |
| data | any | No | Payload |
Returns: Promise<number> — windows actually notified
sendEventToMyGroup()
Same as group broadcast but for the current window’s group (excludes self count semantics per implementation).
| Name | Type | Required | Description |
|---|---|---|---|
| event | string | Yes | Custom event name |
| data | any | No | Payload |
Returns: Promise<number> — number of other windows in the group (same as sendEventTo dispatch count)
useCapacity()
Desktop open capabilities — see Desktop open capabilities.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| capName | string | Yes | — | Capability name |
| data | any | No | — | Arguments |
| timeout | number | No | 0 | ms; 0 = no timeout |
Returns: Promise<any>
Window groups
getGroup()
Returns: Promise<string> — '' if none
getGroupList()
Peers in the same group excluding this window.
Returns: Promise<string[]>
getGroupPosition()
Index in the full member list (includes self); unlike getGroupList().
Returns: Promise<number> — -1 if N/A
queryIsExist()
Whether a named window exists in a group.
| Name | Type | Required | Description |
|---|---|---|---|
| group | string | Yes | Group |
| winName | string | Yes | Window name |
Returns: Promise<boolean>
const exists = await cloudWindow.queryIsExist('main-group', 'settings-window')
if (exists) {
console.log('Settings window already open')
} else {
// ...
}