window.ts 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318
  1. // Copyright 2019-2021 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. /**
  5. * Provides APIs to create windows, communicate with other windows and manipulate the current window.
  6. *
  7. * This package is also accessible with `window.__TAURI__.window` when `tauri.conf.json > build > withGlobalTauri` is set to true.
  8. *
  9. * The APIs must be allowlisted on `tauri.conf.json`:
  10. * ```json
  11. * {
  12. * "tauri": {
  13. * "allowlist": {
  14. * "window": {
  15. * "all": true, // enable all window APIs
  16. * "create": true, // enable window creation
  17. * "center": true,
  18. * "requestUserAttention": true,
  19. * "setResizable": true,
  20. * "setTitle": true,
  21. * "maximize": true,
  22. * "unmaximize": true,
  23. * "minimize": true,
  24. * "unminimize": true,
  25. * "show": true,
  26. * "hide": true,
  27. * "close": true,
  28. * "setDecorations": true,
  29. * "setAlwaysOnTop": true,
  30. * "setSize": true,
  31. * "setMinSize": true,
  32. * "setMaxSize": true,
  33. * "setPosition": true,
  34. * "setFullscreen": true,
  35. * "setFocus": true,
  36. * "setIcon": true,
  37. * "setSkipTaskbar": true,
  38. * "startDragging": true,
  39. * "print": true
  40. * }
  41. * }
  42. * }
  43. * }
  44. * ```
  45. * It is recommended to allowlist only the APIs you use for optimal bundle size and security.
  46. *
  47. * # Window events
  48. *
  49. * Events can be listened using `appWindow.listen`:
  50. * ```typescript
  51. * import { appWindow } from '@tauri-apps/api/window'
  52. * appWindow.listen('tauri://move', ({ event, payload }) => {
  53. * const { x, y } = payload // payload here is a `PhysicalPosition`
  54. * })
  55. * ```
  56. *
  57. * Window-specific events emitted by the backend:
  58. *
  59. * #### 'tauri://resize'
  60. * Emitted when the size of the window has changed.
  61. * *EventPayload*:
  62. * ```typescript
  63. * type ResizePayload = PhysicalSize
  64. * ```
  65. *
  66. * #### 'tauri://move'
  67. * Emitted when the position of the window has changed.
  68. * *EventPayload*:
  69. * ```typescript
  70. * type MovePayload = PhysicalPosition
  71. * ```
  72. *
  73. * #### 'tauri://close-requested'
  74. * Emitted when the user requests the window to be closed.
  75. * If a listener is registered for this event, Tauri won't close the window so you must call `appWindow.close()` manually.
  76. *
  77. * #### 'tauri://focus'
  78. * Emitted when the window gains focus.
  79. *
  80. * #### 'tauri://blur'
  81. * Emitted when the window loses focus.
  82. *
  83. * #### 'tauri://scale-change'
  84. * Emitted when the window's scale factor has changed.
  85. * The following user actions can cause DPI changes:
  86. * - Changing the display's resolution.
  87. * - Changing the display's scale factor (e.g. in Control Panel on Windows).
  88. * - Moving the window to a display with a different scale factor.
  89. * *Event payload*:
  90. * ```typescript
  91. * interface ScaleFactorChanged {
  92. * scaleFactor: number
  93. * size: PhysicalSize
  94. * }
  95. * ```
  96. *
  97. * #### 'tauri://menu'
  98. * Emitted when a menu item is clicked.
  99. * *EventPayload*:
  100. * ```typescript
  101. * type MenuClicked = string
  102. * ```
  103. *
  104. * @module
  105. */
  106. import { invokeTauriCommand } from './helpers/tauri'
  107. import type { EventName, EventCallback, UnlistenFn } from './event'
  108. import { emit, listen, once } from './helpers/event'
  109. /** Allows you to retrieve information about a given monitor. */
  110. interface Monitor {
  111. /** Human-readable name of the monitor */
  112. name: string | null
  113. /** The monitor's resolution. */
  114. size: PhysicalSize
  115. /** the Top-left corner position of the monitor relative to the larger full screen area. */
  116. position: PhysicalPosition
  117. /** The scale factor that can be used to map physical pixels to logical pixels. */
  118. scaleFactor: number
  119. }
  120. /** A size represented in logical pixels. */
  121. class LogicalSize {
  122. type = 'Logical'
  123. width: number
  124. height: number
  125. constructor(width: number, height: number) {
  126. this.width = width
  127. this.height = height
  128. }
  129. }
  130. /** A size represented in physical pixels. */
  131. class PhysicalSize {
  132. type = 'Physical'
  133. width: number
  134. height: number
  135. constructor(width: number, height: number) {
  136. this.width = width
  137. this.height = height
  138. }
  139. /** Converts the physical size to a logical one. */
  140. toLogical(scaleFactor: number): LogicalSize {
  141. return new LogicalSize(this.width / scaleFactor, this.height / scaleFactor)
  142. }
  143. }
  144. /** A position represented in logical pixels. */
  145. class LogicalPosition {
  146. type = 'Logical'
  147. x: number
  148. y: number
  149. constructor(x: number, y: number) {
  150. this.x = x
  151. this.y = y
  152. }
  153. }
  154. /** A position represented in physical pixels. */
  155. class PhysicalPosition {
  156. type = 'Physical'
  157. x: number
  158. y: number
  159. constructor(x: number, y: number) {
  160. this.x = x
  161. this.y = y
  162. }
  163. /** Converts the physical position to a logical one. */
  164. toLogical(scaleFactor: number): LogicalPosition {
  165. return new LogicalPosition(this.x / scaleFactor, this.y / scaleFactor)
  166. }
  167. }
  168. /** @ignore */
  169. interface WindowDef {
  170. label: string
  171. }
  172. /** @ignore */
  173. declare global {
  174. interface Window {
  175. __TAURI_METADATA__: {
  176. __windows: WindowDef[]
  177. __currentWindow: WindowDef
  178. }
  179. }
  180. }
  181. /** Attention type to request on a window. */
  182. enum UserAttentionType {
  183. /**
  184. * #### Platform-specific
  185. * - **macOS:** Bounces the dock icon until the application is in focus.
  186. * - **Windows:** Flashes both the window and the taskbar button until the application is in focus.
  187. */
  188. Critical = 1,
  189. /**
  190. * #### Platform-specific
  191. * - **macOS:** Bounces the dock icon once.
  192. * - **Windows:** Flashes the taskbar button until the application is in focus.
  193. */
  194. Informational
  195. }
  196. /**
  197. * Get an instance of `WebviewWindow` for the current webview window.
  198. *
  199. * @return The current WebviewWindow.
  200. */
  201. function getCurrent(): WebviewWindow {
  202. return new WebviewWindow(window.__TAURI_METADATA__.__currentWindow.label, {
  203. // @ts-expect-error
  204. skip: true
  205. })
  206. }
  207. /**
  208. * Gets an instance of `WebviewWindow` for all available webview windows.
  209. *
  210. * @return The list of WebviewWindow.
  211. */
  212. function getAll(): WebviewWindow[] {
  213. return window.__TAURI_METADATA__.__windows.map(
  214. (w) =>
  215. new WebviewWindow(w.label, {
  216. // @ts-expect-error
  217. skip: true
  218. })
  219. )
  220. }
  221. /** @ignore */
  222. // events that are emitted right here instead of by the created webview
  223. const localTauriEvents = ['tauri://created', 'tauri://error']
  224. /** @ignore */
  225. export type WindowLabel = string
  226. /**
  227. * A webview window handle allows emitting and listening to events from the backend that are tied to the window.
  228. */
  229. class WebviewWindowHandle {
  230. /** The window label. It is a unique identifier for the window, can be used to reference it later. */
  231. label: WindowLabel
  232. /** Local event listeners. */
  233. listeners: { [key: string]: Array<EventCallback<any>> }
  234. constructor(label: WindowLabel) {
  235. this.label = label
  236. // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
  237. this.listeners = Object.create(null)
  238. }
  239. /**
  240. * Listen to an event emitted by the backend that is tied to the webview window.
  241. *
  242. * @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
  243. * @param handler Event handler.
  244. * @returns A promise resolving to a function to unlisten to the event.
  245. */
  246. async listen<T>(
  247. event: EventName,
  248. handler: EventCallback<T>
  249. ): Promise<UnlistenFn> {
  250. if (this._handleTauriEvent(event, handler)) {
  251. return Promise.resolve(() => {
  252. // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, security/detect-object-injection
  253. const listeners = this.listeners[event]
  254. listeners.splice(listeners.indexOf(handler), 1)
  255. })
  256. }
  257. return listen(event, this.label, handler)
  258. }
  259. /**
  260. * Listen to an one-off event emitted by the backend that is tied to the webview window.
  261. *
  262. * @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
  263. * @param handler Event handler.
  264. * @returns A promise resolving to a function to unlisten to the event.
  265. */
  266. async once<T>(event: string, handler: EventCallback<T>): Promise<UnlistenFn> {
  267. if (this._handleTauriEvent(event, handler)) {
  268. return Promise.resolve(() => {
  269. // eslint-disable-next-line security/detect-object-injection
  270. const listeners = this.listeners[event]
  271. listeners.splice(listeners.indexOf(handler), 1)
  272. })
  273. }
  274. return once(event, this.label, handler)
  275. }
  276. /**
  277. * Emits an event to the backend, tied to the webview window.
  278. *
  279. * @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
  280. * @param payload Event payload.
  281. */
  282. async emit(event: string, payload?: unknown): Promise<void> {
  283. if (localTauriEvents.includes(event)) {
  284. // eslint-disable-next-line
  285. for (const handler of this.listeners[event] || []) {
  286. handler({ event, id: -1, windowLabel: this.label, payload })
  287. }
  288. return Promise.resolve()
  289. }
  290. return emit(event, this.label, payload)
  291. }
  292. _handleTauriEvent<T>(event: string, handler: EventCallback<T>): boolean {
  293. if (localTauriEvents.includes(event)) {
  294. if (!(event in this.listeners)) {
  295. // eslint-disable-next-line
  296. this.listeners[event] = [handler]
  297. } else {
  298. // eslint-disable-next-line
  299. this.listeners[event].push(handler)
  300. }
  301. return true
  302. }
  303. return false
  304. }
  305. }
  306. /**
  307. * Manage the current window object.
  308. */
  309. class WindowManager extends WebviewWindowHandle {
  310. // Getters
  311. /** The scale factor that can be used to map physical pixels to logical pixels. */
  312. async scaleFactor(): Promise<number> {
  313. return invokeTauriCommand({
  314. __tauriModule: 'Window',
  315. message: {
  316. cmd: 'manage',
  317. data: {
  318. label: this.label,
  319. cmd: {
  320. type: 'scaleFactor'
  321. }
  322. }
  323. }
  324. })
  325. }
  326. /** The position of the top-left hand corner of the window's client area relative to the top-left hand corner of the desktop. */
  327. async innerPosition(): Promise<PhysicalPosition> {
  328. return invokeTauriCommand<{ x: number; y: number }>({
  329. __tauriModule: 'Window',
  330. message: {
  331. cmd: 'manage',
  332. data: {
  333. label: this.label,
  334. cmd: {
  335. type: 'innerPosition'
  336. }
  337. }
  338. }
  339. }).then(({ x, y }) => new PhysicalPosition(x, y))
  340. }
  341. /** The position of the top-left hand corner of the window relative to the top-left hand corner of the desktop. */
  342. async outerPosition(): Promise<PhysicalPosition> {
  343. return invokeTauriCommand<{ x: number; y: number }>({
  344. __tauriModule: 'Window',
  345. message: {
  346. cmd: 'manage',
  347. data: {
  348. label: this.label,
  349. cmd: {
  350. type: 'outerPosition'
  351. }
  352. }
  353. }
  354. }).then(({ x, y }) => new PhysicalPosition(x, y))
  355. }
  356. /**
  357. * The physical size of the window's client area.
  358. * The client area is the content of the window, excluding the title bar and borders.
  359. */
  360. async innerSize(): Promise<PhysicalSize> {
  361. return invokeTauriCommand<{ width: number; height: number }>({
  362. __tauriModule: 'Window',
  363. message: {
  364. cmd: 'manage',
  365. data: {
  366. label: this.label,
  367. cmd: {
  368. type: 'innerSize'
  369. }
  370. }
  371. }
  372. }).then(({ width, height }) => new PhysicalSize(width, height))
  373. }
  374. /**
  375. * The physical size of the entire window.
  376. * These dimensions include the title bar and borders. If you don't want that (and you usually don't), use inner_size instead.
  377. */
  378. async outerSize(): Promise<PhysicalSize> {
  379. return invokeTauriCommand<{ width: number; height: number }>({
  380. __tauriModule: 'Window',
  381. message: {
  382. cmd: 'manage',
  383. data: {
  384. label: this.label,
  385. cmd: {
  386. type: 'outerSize'
  387. }
  388. }
  389. }
  390. }).then(({ width, height }) => new PhysicalSize(width, height))
  391. }
  392. /** Gets the window's current fullscreen state. */
  393. async isFullscreen(): Promise<boolean> {
  394. return invokeTauriCommand({
  395. __tauriModule: 'Window',
  396. message: {
  397. cmd: 'manage',
  398. data: {
  399. label: this.label,
  400. cmd: {
  401. type: 'isFullscreen'
  402. }
  403. }
  404. }
  405. })
  406. }
  407. /** Gets the window's current maximized state. */
  408. async isMaximized(): Promise<boolean> {
  409. return invokeTauriCommand({
  410. __tauriModule: 'Window',
  411. message: {
  412. cmd: 'manage',
  413. data: {
  414. label: this.label,
  415. cmd: {
  416. type: 'isMaximized'
  417. }
  418. }
  419. }
  420. })
  421. }
  422. /** Gets the window's current decorated state. */
  423. async isDecorated(): Promise<boolean> {
  424. return invokeTauriCommand({
  425. __tauriModule: 'Window',
  426. message: {
  427. cmd: 'manage',
  428. data: {
  429. label: this.label,
  430. cmd: {
  431. type: 'isDecorated'
  432. }
  433. }
  434. }
  435. })
  436. }
  437. /** Gets the window's current resizable state. */
  438. async isResizable(): Promise<boolean> {
  439. return invokeTauriCommand({
  440. __tauriModule: 'Window',
  441. message: {
  442. cmd: 'manage',
  443. data: {
  444. label: this.label,
  445. cmd: {
  446. type: 'isResizable'
  447. }
  448. }
  449. }
  450. })
  451. }
  452. /** Gets the window's current visible state. */
  453. async isVisible(): Promise<boolean> {
  454. return invokeTauriCommand({
  455. __tauriModule: 'Window',
  456. message: {
  457. cmd: 'manage',
  458. data: {
  459. label: this.label,
  460. cmd: {
  461. type: 'isVisible'
  462. }
  463. }
  464. }
  465. })
  466. }
  467. // Setters
  468. /**
  469. * Centers the window.
  470. *
  471. * @param resizable
  472. * @returns A promise indicating the success or failure of the operation.
  473. */
  474. async center(): Promise<void> {
  475. return invokeTauriCommand({
  476. __tauriModule: 'Window',
  477. message: {
  478. cmd: 'manage',
  479. data: {
  480. label: this.label,
  481. cmd: {
  482. type: 'center'
  483. }
  484. }
  485. }
  486. })
  487. }
  488. /**
  489. * Requests user attention to the window, this has no effect if the application
  490. * is already focused. How requesting for user attention manifests is platform dependent,
  491. * see `UserAttentionType` for details.
  492. *
  493. * Providing `null` will unset the request for user attention. Unsetting the request for
  494. * user attention might not be done automatically by the WM when the window receives input.
  495. *
  496. * #### Platform-specific
  497. *
  498. * - **macOS:** `null` has no effect.
  499. * - **Linux:** Urgency levels have the same effect.
  500. *
  501. * @param resizable
  502. * @returns A promise indicating the success or failure of the operation.
  503. */
  504. async requestUserAttention(
  505. requestType: UserAttentionType | null
  506. ): Promise<void> {
  507. let requestType_ = null
  508. if (requestType) {
  509. if (requestType === UserAttentionType.Critical) {
  510. requestType_ = { type: 'Critical' }
  511. } else {
  512. requestType_ = { type: 'Informational' }
  513. }
  514. }
  515. return invokeTauriCommand({
  516. __tauriModule: 'Window',
  517. message: {
  518. cmd: 'manage',
  519. data: {
  520. label: this.label,
  521. cmd: {
  522. type: 'requestUserAttention',
  523. payload: requestType_
  524. }
  525. }
  526. }
  527. })
  528. }
  529. /**
  530. * Updates the window resizable flag.
  531. *
  532. * @param resizable
  533. * @returns A promise indicating the success or failure of the operation.
  534. */
  535. async setResizable(resizable: boolean): Promise<void> {
  536. return invokeTauriCommand({
  537. __tauriModule: 'Window',
  538. message: {
  539. cmd: 'manage',
  540. data: {
  541. label: this.label,
  542. cmd: {
  543. type: 'setResizable',
  544. payload: resizable
  545. }
  546. }
  547. }
  548. })
  549. }
  550. /**
  551. * Sets the window title.
  552. *
  553. * @param title The new title
  554. * @returns A promise indicating the success or failure of the operation.
  555. */
  556. async setTitle(title: string): Promise<void> {
  557. return invokeTauriCommand({
  558. __tauriModule: 'Window',
  559. message: {
  560. cmd: 'manage',
  561. data: {
  562. label: this.label,
  563. cmd: {
  564. type: 'setTitle',
  565. payload: title
  566. }
  567. }
  568. }
  569. })
  570. }
  571. /**
  572. * Maximizes the window.
  573. *
  574. * @returns A promise indicating the success or failure of the operation.
  575. */
  576. async maximize(): Promise<void> {
  577. return invokeTauriCommand({
  578. __tauriModule: 'Window',
  579. message: {
  580. cmd: 'manage',
  581. data: {
  582. label: this.label,
  583. cmd: {
  584. type: 'maximize'
  585. }
  586. }
  587. }
  588. })
  589. }
  590. /**
  591. * Unmaximizes the window.
  592. *
  593. * @returns A promise indicating the success or failure of the operation.
  594. */
  595. async unmaximize(): Promise<void> {
  596. return invokeTauriCommand({
  597. __tauriModule: 'Window',
  598. message: {
  599. cmd: 'manage',
  600. data: {
  601. label: this.label,
  602. cmd: {
  603. type: 'unmaximize'
  604. }
  605. }
  606. }
  607. })
  608. }
  609. /**
  610. * Toggles the window maximized state.
  611. *
  612. * @returns A promise indicating the success or failure of the operation.
  613. */
  614. async toggleMaximize(): Promise<void> {
  615. return invokeTauriCommand({
  616. __tauriModule: 'Window',
  617. message: {
  618. cmd: 'manage',
  619. data: {
  620. label: this.label,
  621. cmd: {
  622. type: 'toggleMaximize'
  623. }
  624. }
  625. }
  626. })
  627. }
  628. /**
  629. * Minimizes the window.
  630. *
  631. * @returns A promise indicating the success or failure of the operation.
  632. */
  633. async minimize(): Promise<void> {
  634. return invokeTauriCommand({
  635. __tauriModule: 'Window',
  636. message: {
  637. cmd: 'manage',
  638. data: {
  639. label: this.label,
  640. cmd: {
  641. type: 'minimize'
  642. }
  643. }
  644. }
  645. })
  646. }
  647. /**
  648. * Unminimizes the window.
  649. *
  650. * @returns A promise indicating the success or failure of the operation.
  651. */
  652. async unminimize(): Promise<void> {
  653. return invokeTauriCommand({
  654. __tauriModule: 'Window',
  655. message: {
  656. cmd: 'manage',
  657. data: {
  658. label: this.label,
  659. cmd: {
  660. type: 'unminimize'
  661. }
  662. }
  663. }
  664. })
  665. }
  666. /**
  667. * Sets the window visibility to true.
  668. *
  669. * @returns A promise indicating the success or failure of the operation.
  670. */
  671. async show(): Promise<void> {
  672. return invokeTauriCommand({
  673. __tauriModule: 'Window',
  674. message: {
  675. cmd: 'manage',
  676. data: {
  677. label: this.label,
  678. cmd: {
  679. type: 'show'
  680. }
  681. }
  682. }
  683. })
  684. }
  685. /**
  686. * Sets the window visibility to false.
  687. *
  688. * @returns A promise indicating the success or failure of the operation.
  689. */
  690. async hide(): Promise<void> {
  691. return invokeTauriCommand({
  692. __tauriModule: 'Window',
  693. message: {
  694. cmd: 'manage',
  695. data: {
  696. label: this.label,
  697. cmd: {
  698. type: 'hide'
  699. }
  700. }
  701. }
  702. })
  703. }
  704. /**
  705. * Closes the window.
  706. *
  707. * @returns A promise indicating the success or failure of the operation.
  708. */
  709. async close(): Promise<void> {
  710. return invokeTauriCommand({
  711. __tauriModule: 'Window',
  712. message: {
  713. cmd: 'manage',
  714. data: {
  715. label: this.label,
  716. cmd: {
  717. type: 'close'
  718. }
  719. }
  720. }
  721. })
  722. }
  723. /**
  724. * Whether the window should have borders and bars.
  725. *
  726. * @param decorations Whether the window should have borders and bars.
  727. * @returns A promise indicating the success or failure of the operation.
  728. */
  729. async setDecorations(decorations: boolean): Promise<void> {
  730. return invokeTauriCommand({
  731. __tauriModule: 'Window',
  732. message: {
  733. cmd: 'manage',
  734. data: {
  735. label: this.label,
  736. cmd: {
  737. type: 'setDecorations',
  738. payload: decorations
  739. }
  740. }
  741. }
  742. })
  743. }
  744. /**
  745. * Whether the window should always be on top of other windows.
  746. *
  747. * @param alwaysOnTop Whether the window should always be on top of other windows or not.
  748. * @returns A promise indicating the success or failure of the operation.
  749. */
  750. async setAlwaysOnTop(alwaysOnTop: boolean): Promise<void> {
  751. return invokeTauriCommand({
  752. __tauriModule: 'Window',
  753. message: {
  754. cmd: 'manage',
  755. data: {
  756. label: this.label,
  757. cmd: {
  758. type: 'setAlwaysOnTop',
  759. payload: alwaysOnTop
  760. }
  761. }
  762. }
  763. })
  764. }
  765. /**
  766. * Resizes the window with a new inner size.
  767. * @example
  768. * ```typescript
  769. * import { appWindow, LogicalSize } from '@tauri-apps/api/window'
  770. * await appWindow.setSize(new LogicalSize(600, 500))
  771. * ```
  772. *
  773. * @param size The logical or physical inner size.
  774. * @returns A promise indicating the success or failure of the operation.
  775. */
  776. async setSize(size: LogicalSize | PhysicalSize): Promise<void> {
  777. if (!size || (size.type !== 'Logical' && size.type !== 'Physical')) {
  778. throw new Error(
  779. 'the `size` argument must be either a LogicalSize or a PhysicalSize instance'
  780. )
  781. }
  782. return invokeTauriCommand({
  783. __tauriModule: 'Window',
  784. message: {
  785. cmd: 'manage',
  786. data: {
  787. label: this.label,
  788. cmd: {
  789. type: 'setSize',
  790. payload: {
  791. type: size.type,
  792. data: {
  793. width: size.width,
  794. height: size.height
  795. }
  796. }
  797. }
  798. }
  799. }
  800. })
  801. }
  802. /**
  803. * Sets the window minimum inner size. If the `size` argument is not provided, the constraint is unset.
  804. * @example
  805. * ```typescript
  806. * import { appWindow, PhysicalSize } from '@tauri-apps/api/window'
  807. * await appWindow.setMinSize(new PhysicalSize(600, 500))
  808. * ```
  809. *
  810. * @param size The logical or physical inner size, or `null` to unset the constraint.
  811. * @returns A promise indicating the success or failure of the operation.
  812. */
  813. async setMinSize(
  814. size: LogicalSize | PhysicalSize | null | undefined
  815. ): Promise<void> {
  816. if (size && size.type !== 'Logical' && size.type !== 'Physical') {
  817. throw new Error(
  818. 'the `size` argument must be either a LogicalSize or a PhysicalSize instance'
  819. )
  820. }
  821. return invokeTauriCommand({
  822. __tauriModule: 'Window',
  823. message: {
  824. cmd: 'manage',
  825. data: {
  826. label: this.label,
  827. cmd: {
  828. type: 'setMinSize',
  829. payload: size
  830. ? {
  831. type: size.type,
  832. data: {
  833. width: size.width,
  834. height: size.height
  835. }
  836. }
  837. : null
  838. }
  839. }
  840. }
  841. })
  842. }
  843. /**
  844. * Sets the window maximum inner size. If the `size` argument is undefined, the constraint is unset.
  845. * @example
  846. * ```typescript
  847. * import { appWindow, LogicalSize } from '@tauri-apps/api/window'
  848. * await appWindow.setMaxSize(new LogicalSize(600, 500))
  849. * ```
  850. *
  851. * @param size The logical or physical inner size, or `null` to unset the constraint.
  852. * @returns A promise indicating the success or failure of the operation.
  853. */
  854. async setMaxSize(
  855. size: LogicalSize | PhysicalSize | null | undefined
  856. ): Promise<void> {
  857. if (size && size.type !== 'Logical' && size.type !== 'Physical') {
  858. throw new Error(
  859. 'the `size` argument must be either a LogicalSize or a PhysicalSize instance'
  860. )
  861. }
  862. return invokeTauriCommand({
  863. __tauriModule: 'Window',
  864. message: {
  865. cmd: 'manage',
  866. data: {
  867. label: this.label,
  868. cmd: {
  869. type: 'setMaxSize',
  870. payload: size
  871. ? {
  872. type: size.type,
  873. data: {
  874. width: size.width,
  875. height: size.height
  876. }
  877. }
  878. : null
  879. }
  880. }
  881. }
  882. })
  883. }
  884. /**
  885. * Sets the window outer position.
  886. * @example
  887. * ```typescript
  888. * import { appWindow, LogicalPosition } from '@tauri-apps/api/window'
  889. * await appWindow.setPosition(new LogicalPosition(600, 500))
  890. * ```
  891. *
  892. * @param position The new position, in logical or physical pixels.
  893. * @returns A promise indicating the success or failure of the operation.
  894. */
  895. async setPosition(
  896. position: LogicalPosition | PhysicalPosition
  897. ): Promise<void> {
  898. if (
  899. !position ||
  900. (position.type !== 'Logical' && position.type !== 'Physical')
  901. ) {
  902. throw new Error(
  903. 'the `position` argument must be either a LogicalPosition or a PhysicalPosition instance'
  904. )
  905. }
  906. return invokeTauriCommand({
  907. __tauriModule: 'Window',
  908. message: {
  909. cmd: 'manage',
  910. data: {
  911. label: this.label,
  912. cmd: {
  913. type: 'setPosition',
  914. payload: {
  915. type: position.type,
  916. data: {
  917. x: position.x,
  918. y: position.y
  919. }
  920. }
  921. }
  922. }
  923. }
  924. })
  925. }
  926. /**
  927. * Sets the window fullscreen state.
  928. *
  929. * @param fullscreen Whether the window should go to fullscreen or not.
  930. * @returns A promise indicating the success or failure of the operation.
  931. */
  932. async setFullscreen(fullscreen: boolean): Promise<void> {
  933. return invokeTauriCommand({
  934. __tauriModule: 'Window',
  935. message: {
  936. cmd: 'manage',
  937. data: {
  938. label: this.label,
  939. cmd: {
  940. type: 'setFullscreen',
  941. payload: fullscreen
  942. }
  943. }
  944. }
  945. })
  946. }
  947. /**
  948. * Bring the window to front and focus.
  949. *
  950. * @returns A promise indicating the success or failure of the operation.
  951. */
  952. async setFocus(): Promise<void> {
  953. return invokeTauriCommand({
  954. __tauriModule: 'Window',
  955. message: {
  956. cmd: 'manage',
  957. data: {
  958. label: this.label,
  959. cmd: {
  960. type: 'setFocus'
  961. }
  962. }
  963. }
  964. })
  965. }
  966. /**
  967. * Sets the window icon.
  968. *
  969. * Note that you need the `icon-ico` or `icon-png` Cargo features to use this API.
  970. * To enable it, change your Cargo.toml file:
  971. * ```toml
  972. * [dependencies]
  973. * tauri = { version = "...", features = ["...", "icon-png"] }
  974. * ```
  975. *
  976. * @param icon Icon bytes or path to the icon file.
  977. * @returns A promise indicating the success or failure of the operation.
  978. */
  979. async setIcon(icon: string | Uint8Array): Promise<void> {
  980. return invokeTauriCommand({
  981. __tauriModule: 'Window',
  982. message: {
  983. cmd: 'manage',
  984. data: {
  985. label: this.label,
  986. cmd: {
  987. type: 'setIcon',
  988. payload: {
  989. // correctly serialize Uint8Arrays
  990. icon: typeof icon === 'string' ? icon : Array.from(icon)
  991. }
  992. }
  993. }
  994. }
  995. })
  996. }
  997. /**
  998. * Whether to show the window icon in the task bar or not.
  999. *
  1000. * @param skip true to hide window icon, false to show it.
  1001. * @returns A promise indicating the success or failure of the operation.
  1002. */
  1003. async setSkipTaskbar(skip: boolean): Promise<void> {
  1004. return invokeTauriCommand({
  1005. __tauriModule: 'Window',
  1006. message: {
  1007. cmd: 'manage',
  1008. data: {
  1009. label: this.label,
  1010. cmd: {
  1011. type: 'setSkipTaskbar',
  1012. payload: skip
  1013. }
  1014. }
  1015. }
  1016. })
  1017. }
  1018. /**
  1019. * Starts dragging the window.
  1020. *
  1021. * @return A promise indicating the success or failure of the operation.
  1022. */
  1023. async startDragging(): Promise<void> {
  1024. return invokeTauriCommand({
  1025. __tauriModule: 'Window',
  1026. message: {
  1027. cmd: 'manage',
  1028. data: {
  1029. label: this.label,
  1030. cmd: {
  1031. type: 'startDragging'
  1032. }
  1033. }
  1034. }
  1035. })
  1036. }
  1037. }
  1038. /**
  1039. * Create new webview windows and get a handle to existing ones.
  1040. *
  1041. * Windows are identified by a *label* a unique identifier that can be used to reference it later.
  1042. * It may only contain alphanumeric characters `a-zA-Z` plus the following special characters `-`, `/`, `:` and `_`.
  1043. *
  1044. * @example
  1045. * ```typescript
  1046. * // loading embedded asset:
  1047. * const webview = new WebviewWindow('theUniqueLabel', {
  1048. * url: 'path/to/page.html'
  1049. * })
  1050. * // alternatively, load a remote URL:
  1051. * const webview = new WebviewWindow('theUniqueLabel', {
  1052. * url: 'https://github.com/tauri-apps/tauri'
  1053. * })
  1054. *
  1055. * webview.once('tauri://created', function () {
  1056. * // webview window successfully created
  1057. * })
  1058. * webview.once('tauri://error', function (e) {
  1059. * // an error happened creating the webview window
  1060. * })
  1061. *
  1062. * // emit an event to the backend
  1063. * await webview.emit("some event", "data")
  1064. * // listen to an event from the backend
  1065. * const unlisten = await webview.listen("event name", e => {})
  1066. * unlisten()
  1067. * ```
  1068. */
  1069. class WebviewWindow extends WindowManager {
  1070. /**
  1071. * Creates a new WebviewWindow.
  1072. * * @param label The unique webview window label. Must be alphanumeric: `a-zA-Z-/:_`.
  1073. * @returns The WebviewWindow instance to communicate with the webview.
  1074. */
  1075. constructor(label: WindowLabel, options: WindowOptions = {}) {
  1076. super(label)
  1077. // @ts-expect-error
  1078. if (!options?.skip) {
  1079. invokeTauriCommand({
  1080. __tauriModule: 'Window',
  1081. message: {
  1082. cmd: 'createWebview',
  1083. data: {
  1084. options: {
  1085. label,
  1086. ...options
  1087. }
  1088. }
  1089. }
  1090. })
  1091. .then(async () => this.emit('tauri://created'))
  1092. .catch(async (e: string) => this.emit('tauri://error', e))
  1093. }
  1094. }
  1095. /**
  1096. * Gets the WebviewWindow for the webview associated with the given label.
  1097. *
  1098. * @param label The webview window label.
  1099. * @returns The WebviewWindow instance to communicate with the webview or null if the webview doesn't exist.
  1100. */
  1101. static getByLabel(label: string): WebviewWindow | null {
  1102. if (getAll().some((w) => w.label === label)) {
  1103. // @ts-expect-error
  1104. return new WebviewWindow(label, { skip: true })
  1105. }
  1106. return null
  1107. }
  1108. }
  1109. /** The WebviewWindow for the current window. */
  1110. let appWindow
  1111. if ('__TAURI_METADATA__' in window) {
  1112. appWindow = new WebviewWindow(
  1113. window.__TAURI_METADATA__.__currentWindow.label,
  1114. {
  1115. // @ts-expect-error
  1116. skip: true
  1117. }
  1118. )
  1119. } else {
  1120. console.warn(
  1121. `Could not find "window.__TAURI_METADATA__". The "appWindow" value will reference the "main" window label.\nNote that this is not an issue if running this frontend on a browser instead of a Tauri window.`
  1122. )
  1123. appWindow = new WebviewWindow('main', {
  1124. // @ts-expect-error
  1125. skip: true
  1126. })
  1127. }
  1128. /** Configuration for the window to create. */
  1129. interface WindowOptions {
  1130. /**
  1131. * Remote URL or local file path to open.
  1132. *
  1133. * - URL such as `https://github.com/tauri-apps` is opened directly on a Tauri window.
  1134. * - data: URL such as `data:text/html,<html>...` is only supported with the `window-data-url` Cargo feature for the `tauri` dependency.
  1135. * - local file path or route such as `/path/to/page.html` or `/users` is appended to the application URL (the devServer URL on development, or `tauri://localhost/` and `https://tauri.localhost/` on production).
  1136. */
  1137. url?: string
  1138. /** Show window in the center of the screen.. */
  1139. center?: boolean
  1140. /** The initial vertical position. Only applies if `y` is also set. */
  1141. x?: number
  1142. /** The initial horizontal position. Only applies if `x` is also set. */
  1143. y?: number
  1144. /** The initial width. */
  1145. width?: number
  1146. /** The initial height. */
  1147. height?: number
  1148. /** The minimum width. Only applies if `minHeight` is also set. */
  1149. minWidth?: number
  1150. /** The minimum height. Only applies if `minWidth` is also set. */
  1151. minHeight?: number
  1152. /** The maximum width. Only applies if `maxHeight` is also set. */
  1153. maxWidth?: number
  1154. /** The maximum height. Only applies if `maxWidth` is also set. */
  1155. maxHeight?: number
  1156. /** Whether the window is resizable or not. */
  1157. resizable?: boolean
  1158. /** Window title. */
  1159. title?: string
  1160. /** Whether the window is in fullscreen mode or not. */
  1161. fullscreen?: boolean
  1162. /** Whether the window will be initially hidden or focused. */
  1163. focus?: boolean
  1164. /**
  1165. * Whether the window is transparent or not.
  1166. * Note that on `macOS` this requires the `macos-private-api` feature flag, enabled under `tauri.conf.json > tauri > macosPrivateApi`.
  1167. * WARNING: Using private APIs on `macOS` prevents your application from being accepted for the `App Store`.
  1168. */
  1169. transparent?: boolean
  1170. /** Whether the window should be maximized upon creation or not. */
  1171. maximized?: boolean
  1172. /** Whether the window should be immediately visible upon creation or not. */
  1173. visible?: boolean
  1174. /** Whether the window should have borders and bars or not. */
  1175. decorations?: boolean
  1176. /** Whether the window should always be on top of other windows or not. */
  1177. alwaysOnTop?: boolean
  1178. /** Whether or not the window icon should be added to the taskbar. */
  1179. skipTaskbar?: boolean
  1180. /**
  1181. * Whether the file drop is enabled or not on the webview. By default it is enabled.
  1182. *
  1183. * Disabling it is required to use drag and drop on the frontend on Windows.
  1184. */
  1185. fileDropEnabled?: boolean
  1186. }
  1187. /**
  1188. * Returns the monitor on which the window currently resides.
  1189. * Returns `null` if current monitor can't be detected.
  1190. */
  1191. async function currentMonitor(): Promise<Monitor | null> {
  1192. return invokeTauriCommand({
  1193. __tauriModule: 'Window',
  1194. message: {
  1195. cmd: 'manage',
  1196. data: {
  1197. cmd: {
  1198. type: 'currentMonitor'
  1199. }
  1200. }
  1201. }
  1202. })
  1203. }
  1204. /**
  1205. * Returns the primary monitor of the system.
  1206. * Returns `null` if it can't identify any monitor as a primary one.
  1207. */
  1208. async function primaryMonitor(): Promise<Monitor | null> {
  1209. return invokeTauriCommand({
  1210. __tauriModule: 'Window',
  1211. message: {
  1212. cmd: 'manage',
  1213. data: {
  1214. cmd: {
  1215. type: 'primaryMonitor'
  1216. }
  1217. }
  1218. }
  1219. })
  1220. }
  1221. /** Returns the list of all the monitors available on the system. */
  1222. async function availableMonitors(): Promise<Monitor[]> {
  1223. return invokeTauriCommand({
  1224. __tauriModule: 'Window',
  1225. message: {
  1226. cmd: 'manage',
  1227. data: {
  1228. cmd: {
  1229. type: 'availableMonitors'
  1230. }
  1231. }
  1232. }
  1233. })
  1234. }
  1235. export {
  1236. WebviewWindow,
  1237. WebviewWindowHandle,
  1238. WindowManager,
  1239. getCurrent,
  1240. getAll,
  1241. appWindow,
  1242. LogicalSize,
  1243. PhysicalSize,
  1244. LogicalPosition,
  1245. PhysicalPosition,
  1246. UserAttentionType,
  1247. currentMonitor,
  1248. primaryMonitor,
  1249. availableMonitors
  1250. }
  1251. export type { Monitor, WindowOptions }