window.ts 38 KB

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