window.ts 31 KB

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