window.ts 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314
  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. * @example
  1041. * ```typescript
  1042. * // loading embedded asset:
  1043. * const webview = new WebviewWindow('theUniqueLabel', {
  1044. * url: 'path/to/page.html'
  1045. * })
  1046. * // alternatively, load a remote URL:
  1047. * const webview = new WebviewWindow('theUniqueLabel', {
  1048. * url: 'https://github.com/tauri-apps/tauri'
  1049. * })
  1050. *
  1051. * webview.once('tauri://created', function () {
  1052. * // webview window successfully created
  1053. * })
  1054. * webview.once('tauri://error', function (e) {
  1055. * // an error happened creating the webview window
  1056. * })
  1057. *
  1058. * // emit an event to the backend
  1059. * await webview.emit("some event", "data")
  1060. * // listen to an event from the backend
  1061. * const unlisten = await webview.listen("event name", e => {})
  1062. * unlisten()
  1063. * ```
  1064. */
  1065. class WebviewWindow extends WindowManager {
  1066. /**
  1067. * Creates a new WebviewWindow.
  1068. * * @param label The webview window label, a unique identifier that can be used to reference it later. It must be alphanumeric.
  1069. * @returns The WebviewWindow instance to communicate with the webview.
  1070. */
  1071. constructor(label: WindowLabel, options: WindowOptions = {}) {
  1072. super(label)
  1073. // @ts-expect-error
  1074. if (!options?.skip) {
  1075. invokeTauriCommand({
  1076. __tauriModule: 'Window',
  1077. message: {
  1078. cmd: 'createWebview',
  1079. data: {
  1080. options: {
  1081. label,
  1082. ...options
  1083. }
  1084. }
  1085. }
  1086. })
  1087. .then(async () => this.emit('tauri://created'))
  1088. .catch(async (e: string) => this.emit('tauri://error', e))
  1089. }
  1090. }
  1091. /**
  1092. * Gets the WebviewWindow for the webview associated with the given label.
  1093. *
  1094. * @param label The webview window label.
  1095. * @returns The WebviewWindow instance to communicate with the webview or null if the webview doesn't exist.
  1096. */
  1097. static getByLabel(label: string): WebviewWindow | null {
  1098. if (getAll().some((w) => w.label === label)) {
  1099. // @ts-expect-error
  1100. return new WebviewWindow(label, { skip: true })
  1101. }
  1102. return null
  1103. }
  1104. }
  1105. /** The WebviewWindow for the current window. */
  1106. let appWindow
  1107. if ('__TAURI_METADATA__' in window) {
  1108. appWindow = new WebviewWindow(
  1109. window.__TAURI_METADATA__.__currentWindow.label,
  1110. {
  1111. // @ts-expect-error
  1112. skip: true
  1113. }
  1114. )
  1115. } else {
  1116. console.warn(
  1117. `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.`
  1118. )
  1119. appWindow = new WebviewWindow('main', {
  1120. // @ts-expect-error
  1121. skip: true
  1122. })
  1123. }
  1124. /** Configuration for the window to create. */
  1125. interface WindowOptions {
  1126. /**
  1127. * Remote URL or local file path to open.
  1128. *
  1129. * - URL such as `https://github.com/tauri-apps` is opened directly on a Tauri window.
  1130. * - data: URL such as `data:text/html,<html>...` is only supported with the `window-data-url` Cargo feature for the `tauri` dependency.
  1131. * - 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).
  1132. */
  1133. url?: string
  1134. /** Show window in the center of the screen.. */
  1135. center?: boolean
  1136. /** The initial vertical position. Only applies if `y` is also set. */
  1137. x?: number
  1138. /** The initial horizontal position. Only applies if `x` is also set. */
  1139. y?: number
  1140. /** The initial width. */
  1141. width?: number
  1142. /** The initial height. */
  1143. height?: number
  1144. /** The minimum width. Only applies if `minHeight` is also set. */
  1145. minWidth?: number
  1146. /** The minimum height. Only applies if `minWidth` is also set. */
  1147. minHeight?: number
  1148. /** The maximum width. Only applies if `maxHeight` is also set. */
  1149. maxWidth?: number
  1150. /** The maximum height. Only applies if `maxWidth` is also set. */
  1151. maxHeight?: number
  1152. /** Whether the window is resizable or not. */
  1153. resizable?: boolean
  1154. /** Window title. */
  1155. title?: string
  1156. /** Whether the window is in fullscreen mode or not. */
  1157. fullscreen?: boolean
  1158. /** Whether the window will be initially hidden or focused. */
  1159. focus?: boolean
  1160. /**
  1161. * Whether the window is transparent or not.
  1162. * Note that on `macOS` this requires the `macos-private-api` feature flag, enabled under `tauri.conf.json > tauri > macosPrivateApi`.
  1163. * WARNING: Using private APIs on `macOS` prevents your application from being accepted for the `App Store`.
  1164. */
  1165. transparent?: boolean
  1166. /** Whether the window should be maximized upon creation or not. */
  1167. maximized?: boolean
  1168. /** Whether the window should be immediately visible upon creation or not. */
  1169. visible?: boolean
  1170. /** Whether the window should have borders and bars or not. */
  1171. decorations?: boolean
  1172. /** Whether the window should always be on top of other windows or not. */
  1173. alwaysOnTop?: boolean
  1174. /** Whether or not the window icon should be added to the taskbar. */
  1175. skipTaskbar?: boolean
  1176. /**
  1177. * Whether the file drop is enabled or not on the webview. By default it is enabled.
  1178. *
  1179. * Disabling it is required to use drag and drop on the frontend on Windows.
  1180. */
  1181. fileDropEnabled?: boolean
  1182. }
  1183. /**
  1184. * Returns the monitor on which the window currently resides.
  1185. * Returns `null` if current monitor can't be detected.
  1186. */
  1187. async function currentMonitor(): Promise<Monitor | null> {
  1188. return invokeTauriCommand({
  1189. __tauriModule: 'Window',
  1190. message: {
  1191. cmd: 'manage',
  1192. data: {
  1193. cmd: {
  1194. type: 'currentMonitor'
  1195. }
  1196. }
  1197. }
  1198. })
  1199. }
  1200. /**
  1201. * Returns the primary monitor of the system.
  1202. * Returns `null` if it can't identify any monitor as a primary one.
  1203. */
  1204. async function primaryMonitor(): Promise<Monitor | null> {
  1205. return invokeTauriCommand({
  1206. __tauriModule: 'Window',
  1207. message: {
  1208. cmd: 'manage',
  1209. data: {
  1210. cmd: {
  1211. type: 'primaryMonitor'
  1212. }
  1213. }
  1214. }
  1215. })
  1216. }
  1217. /** Returns the list of all the monitors available on the system. */
  1218. async function availableMonitors(): Promise<Monitor[]> {
  1219. return invokeTauriCommand({
  1220. __tauriModule: 'Window',
  1221. message: {
  1222. cmd: 'manage',
  1223. data: {
  1224. cmd: {
  1225. type: 'availableMonitors'
  1226. }
  1227. }
  1228. }
  1229. })
  1230. }
  1231. export {
  1232. WebviewWindow,
  1233. WebviewWindowHandle,
  1234. WindowManager,
  1235. getCurrent,
  1236. getAll,
  1237. appWindow,
  1238. LogicalSize,
  1239. PhysicalSize,
  1240. LogicalPosition,
  1241. PhysicalPosition,
  1242. UserAttentionType,
  1243. currentMonitor,
  1244. primaryMonitor,
  1245. availableMonitors
  1246. }
  1247. export type { Monitor, WindowOptions }