window.ts 32 KB

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