creating_applications.rst 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. .. _doc_creating_applications:
  2. Creating applications
  3. =====================
  4. Godot features an extensive built-in UI system, and its small distribution
  5. size can make it a suitable alternative to frameworks like Electron or Qt.
  6. This page provides guidelines for creating non-game applications with Godot,
  7. as well as instructions on performing common tasks to improve desktop integration.
  8. .. note::
  9. Godot is a game engine first and foremost. This means that creating
  10. applications with Godot is a byproduct of its feature set, and not its
  11. primary focus of development.
  12. .. seealso::
  13. Check out `Material Maker <https://github.com/RodZill4/material-maker>`__ and
  14. `Pixelorama <https://github.com/Orama-Interactive/Pixelorama>`__ for examples of
  15. open source applications made with Godot.
  16. Performing common tasks
  17. -----------------------
  18. Spawning multiple windows
  19. ^^^^^^^^^^^^^^^^^^^^^^^^^
  20. *This is only supported on Windows, macOS, and Linux (X11/XWayland only,
  21. not in native Wayland mode).*
  22. Additional windows can be created using the :ref:`class_Window` node.
  23. Windows can be moved, resized, minimized, and closed independently
  24. from the main application window.
  25. However, if you close the main window, all other windows will also be closed
  26. since closing the main window ends the process. You can avoid this by
  27. minimizing the main window, setting its :ref:`unfocusable <class_Window_property_unfocusable>`
  28. property to ``true`` (to hide it from the taskbar and task switcher),
  29. then creating additional Window nodes immediately on startup. Remember
  30. to provide an alternative means of exiting the application in this case,
  31. such as a :ref:`tray icon <doc_creating_applications_tray_icon>`.
  32. Constraining the window size
  33. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  34. Most applications can only render correctly starting from a certain minimum
  35. window size. For more specific use cases, it may also be desired to force
  36. a maximum window size.
  37. Size limits can be enforced using the :ref:`min_size <class_Window_property_min_size>`
  38. and :ref:`max_size <class_Window_property_max_size>` properties on a Window node.
  39. Remember to multiply these size limits according to the application's scale factor
  40. (see :ref:`doc_creating_applications_scaling_to_hidpi_displays` for details).
  41. .. tip::
  42. As a reminder, you can retrieve the root Window node to set properties
  43. on it using :ref:`get_window() <class_Node_method_get_window>` on any Node.
  44. Using native file dialogs
  45. ^^^^^^^^^^^^^^^^^^^^^^^^^
  46. *This is only supported on Windows, macOS, Linux, and Android.*
  47. By default, Godot uses its own :ref:`class_FileDialog` implementation for file dialogs.
  48. However, you can use the operating system's native file dialogs instead. This is
  49. generally preferred by users, as native file dialogs better integrate with the
  50. desktop environment and provide a more familiar experience.
  51. You can opt into native file dialogs by
  52. enabling the :ref:`use_native_dialog <class_FileDialog_property_use_native_dialog>`
  53. property on the FileDialog node. This must be done on each FileDialog node
  54. used in the project, as there is no project setting to control this behavior
  55. globally.
  56. .. figure:: img/creating_applications_native_file_dialog.webp
  57. :align: center
  58. :alt: Comparison between standard FileDialog (left) and native file dialog (right) on macOS
  59. Comparison between standard FileDialog (left) and native file dialog (right) on macOS
  60. .. note::
  61. See the :ref:`property description <class_FileDialog_property_use_native_dialog>`
  62. for details on platform support.
  63. Additionally, on macOS, native file dialogs are not supported when game embedding
  64. is enabled in the editor. To test this functionality when running the project,
  65. make sure you disable game embedding by switching to the :menu:`Game` screen,
  66. clicking the 3 vertical dots and unchecking :menu:`Embed Game on Next Play`.
  67. .. _doc_creating_applications_tray_icon:
  68. Creating an icon in the system tray
  69. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  70. *This is only supported on Windows and macOS.*
  71. You can create one or more icons in the system tray (also known as the
  72. notification area) using a :ref:`class_StatusIndicator` node.
  73. In addition to a tooltip, this node can have a :ref:`class_PopupMenu` node assigned,
  74. so that a dropdown can be shown when clicking the icon.
  75. StatusIndicator also has a :ref:`pressed <class_StatusIndicator_signal_pressed>`
  76. signal that is emitted when the icon is clicked. Use this to perform an action
  77. without making a dropdown show up, or perform different actions depending on
  78. which mouse button was pressed.
  79. After creating a tray icon, you may also want to implement "minimize on close"
  80. behavior. This means that when the user attempts to close the application using
  81. the window manager X button, it will minimize to the tray instead. To do so,
  82. attach this script to an :ref:`Autoload <doc_singletons_autoload>`
  83. *scene* with a StatusIndicator as the root node:
  84. ::
  85. extends StatusIndicator
  86. # Disable this behavior when running from the editor with game embedding,
  87. # as it doesn't cooperate well.
  88. var tray_icon_supported = (
  89. DisplayServer.has_feature(DisplayServer.FEATURE_STATUS_INDICATOR)
  90. and not Engine.is_embedded_in_editor()
  91. )
  92. func _ready():
  93. visible = false
  94. if tray_icon_supported:
  95. get_tree().auto_accept_quit = false
  96. get_window().focus_entered.connect(
  97. func():
  98. # Hide the tray icon when the window gains focus,
  99. # which means it was restored from its minimized state.
  100. visible = false
  101. )
  102. pressed.connect(
  103. func(_mouse_button, _position):
  104. # Restore the application when the tray icon is clicked.
  105. get_window().mode = Window.MODE_WINDOWED
  106. )
  107. func _notification(what):
  108. if not tray_icon_supported:
  109. return
  110. match what:
  111. NOTIFICATION_WM_CLOSE_REQUEST:
  112. get_window().mode = Window.MODE_MINIMIZED
  113. # Show the tray icon.
  114. visible = true
  115. See :ref:`doc_handling_quit_requests` for details on overriding the behavior
  116. when the user tries to close the application. This is important to handle
  117. when the user has unsaved changes to avoid data loss.
  118. .. note::
  119. When multiple StatusIndicator nodes are present, their order in the
  120. system tray is determined by the order in which they are added
  121. to the scene tree.
  122. Using the global menu
  123. ^^^^^^^^^^^^^^^^^^^^^
  124. *This is only supported on macOS.*
  125. On macOS, applications can use the system's global menu bar instead of displaying
  126. a menu bar inside the application window. This is also referred to as a *native menu*
  127. in Godot.
  128. .. figure:: img/creating_applications_native_menu.webp
  129. :align: center
  130. :alt: Comparison between standard MenuBar (left), MenuBar with native popups (middle), and native menu (right) on macOS
  131. Comparison between standard MenuBar (left), MenuBar with native popups (middle), and native menu (right) on macOS
  132. Godot supports creating menus through the :ref:`class_MenuBar` node, which displays
  133. its :ref:`class_PopupMenu` children as menus. You can enable the global menu
  134. support on a given MenuBar node by enabling its
  135. :ref:`prefer_global_menu <class_MenuBar_property_prefer_global_menu>` property
  136. in the inspector. On macOS, this will cause the MenuBar node to disappear and take
  137. no space, with its menus being displayed in the system's global menu bar instead.
  138. If this property is disabled, the MenuBar node will display its menus inside the
  139. application window as usual, but native popups are still used when supported by
  140. the operating system.
  141. .. note::
  142. The app menu (with the project name in bold), as well as the :menu:`Window` and
  143. :menu:`Help` menus are always present on macOS. You should not add these
  144. to the global menu manually.
  145. In Godot 4.6 and later, you can add new items within these menus by
  146. changing the :ref:`system_menu_id <class_PopupMenu_property_system_menu_id>`
  147. property on the PopupMenu node. You can choose between **Application Menu**
  148. (the first menu with the application name in bold), **Window Menu**,
  149. **Help Menu** and **Dock** (shown when right-clicking the icon in the Dock).
  150. Standard menu items that are already present in those menus will be preserved:
  151. .. figure:: img/creating_applications_native_menu_window.webp
  152. :align: center
  153. :alt: Custom options added to the system Window menu on macOS
  154. Custom options added to the system Window menu on macOS
  155. A project can have multiple MenuBar nodes. If multiple MenuBar nodes have the
  156. **Prefer Global Menu** property enabled, the menu options will be added at the
  157. index defined by the **Start Index** property when the MenuBar node is added to the
  158. scene tree. This allows putting context-specific menus at the end of the menu bar,
  159. so that the first menu options stay in place when the additional menu bar is
  160. added or removed.
  161. For more advanced use cases, you can also use the :ref:`class_NativeMenu` singleton
  162. directly without using the MenuBar node.
  163. .. note::
  164. Global menu integration is not supported when game embedding
  165. is enabled in the editor. To test this functionality when running the project,
  166. make sure you disable game embedding by switching to the :menu:`Game` screen,
  167. clicking the 3 vertical dots and unchecking :menu:`Embed Game on Next Play`.
  168. Using client-side decorations
  169. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  170. *This is only supported on macOS.*
  171. Many modern applications use *client-side decorations* (CSD) instead of relying
  172. on the operating system's window manager to draw the title bar and window borders
  173. (server-side decorations). This allows for a more customizable appearance and
  174. better integration with the application's UI.
  175. Godot currently only supports client-side decorations on macOS. This can be used
  176. by enabling the
  177. :ref:`display/window/size/extend_to_title <class_ProjectSettings_property_display/window/size/extend_to_title>`
  178. project setting.
  179. .. figure:: img/creating_applications_client_side_decoration.webp
  180. :align: center
  181. :alt: Comparison between standard window decorations (top) and client-side decorations (bottom) on macOS
  182. Comparison between standard window decorations (top) and client-side decorations (bottom) on macOS
  183. After enabling client-side decorations, the window border will no longer display,
  184. and minimize/maximize/close buttons will show as an overlay to the application.
  185. You need to make sure the application provides enough of a margin at the top for
  186. the buttons to display comfortably, while also displaying the window title using
  187. a Label node or similar.
  188. To conditionally adapt your UI according to whether client-side decorations
  189. are enabled, use :ref:`DisplayServer.has_feature <class_DisplayServer_method_has_feature>`
  190. and also check the current value of
  191. :ref:`Window.extend_to_title <class_Window_property_extend_to_title>`
  192. (which is what the project setting changes):
  193. ::
  194. func _ready():
  195. if DisplayServer.has_feature(FEATURE_EXTEND_TO_TITLE) and get_window().extend_to_title:
  196. # Adjust UI for client-side decorations (a MarginContainer node
  197. # can be useful here). Also set the window title to be displayed
  198. # according to the native window title.
  199. $WindowTitle.visible = true
  200. $WindowTitle.text = get_window().title
  201. if OS.is_debug_build():
  202. $WindowTitle.text += " (DEBUG)"
  203. To correctly position the window title, consider using
  204. :ref:`DisplayServer.window_get_safe_title_margins() <class_DisplayServer_method_window_get_safe_title_margins>`
  205. which returns a Vector3 where ``x`` is the left margin, ``y`` is the right
  206. margin (will increase when the system uses right-to-left typesetting),
  207. and ``z`` is the height. Additionally, you can call
  208. :ref:`DisplayServer.window_set_window_buttons_offset() <class_DisplayServer_method_window_set_window_buttons_offset>`
  209. to adjust the position of the close/minimize/maximize buttons (usually to
  210. vertically center them).
  211. .. figure:: img/creating_applications_client_side_decoration_margins.webp
  212. :align: center
  213. :alt: Safe title margins when using client-side decorations on macOS
  214. Safe title margins when using client-side decorations on macOS
  215. .. note::
  216. On macOS, client-side decorations are not supported when game embedding
  217. is enabled in the editor. To test this functionality when running the project,
  218. make sure you disable game embedding by switching to the :menu:`Game` screen,
  219. clicking the 3 vertical dots and unchecking :menu:`Embed Game on Next Play`.
  220. Sending desktop notifications
  221. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  222. Godot currently does not have native support for sending desktop notifications.
  223. However, on macOS and Linux, you can use the ``osascript`` and ``notify-send``
  224. command line utilities respectively to send desktop notifications:
  225. ::
  226. func send_notification(title, message):
  227. var app_name = ProjectSettings.get_setting("application/config/name")
  228. if app_name.is_empty():
  229. app_name = "Unnamed Project"
  230. if OS.has_feature("macos") and not OS.is_sandboxed():
  231. # Note that this will not work if the project is exported in sandbox mode
  232. # (e.g. for the Mac App Store).
  233. OS.execute("osascript", [
  234. "-e",
  235. 'display notification \\"%s\\" with title \\"%s\\" subtitle \\"%s\\"' % [
  236. message,
  237. app_name,
  238. title,
  239. ]
  240. ])
  241. elif OS.has_feature("linuxbsd"):
  242. OS.execute("notify-send", ["--app-name", app_name, title, message])
  243. func _ready():
  244. send_notification("Success", "Operation completed successfully.")
  245. Unfortunately, there is no equivalent that's available out of the box on
  246. Windows.
  247. Remembering window position and size across sessions
  248. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  249. Godot doesn't have built-in support for remembering window position
  250. and size across sessions, but it can be manually implemented using a script.
  251. A basic example that supports multi-monitor setups would be an
  252. :ref:`Autoload <doc_singletons_autoload>` with this script:
  253. ::
  254. extends Node
  255. # Use a dedicated configuration file for the window state.
  256. # This way, the application's other configuration files are left
  257. # untouched and can be put in version control without unnecessary diffs
  258. # being produced.
  259. const CONFIG_WINDOW_PATH = "user://window.ini"
  260. var config_file = ConfigFile.new()
  261. func _enter_tree():
  262. config_file.load(CONFIG_WINDOW_PATH)
  263. # Do not restore previous window state if running from the editor
  264. # with game embedding enabled.
  265. if not Engine.is_embedded_in_editor():
  266. var window_screen = config_file.get_value("main", "screen", -1)
  267. if window_screen is int:
  268. get_window().current_screen = window_screen
  269. var window_mode = config_file.get_value("main", "mode", -1)
  270. if window_mode is Window.Mode:
  271. get_window().mode = window_mode
  272. var window_position = config_file.get_value("main", "position", -1)
  273. if window_position is Vector2i:
  274. get_window().position = window_position
  275. var window_size = config_file.get_value("main", "size", -1)
  276. if window_size is Vector2i:
  277. get_window().size = window_size
  278. func _exit_tree():
  279. # Save the current window state when the application is quit normally.
  280. # In a real world scenario, it's recommended to also save this information
  281. # regularly (e.g. with a Timer node), so that the window state can be
  282. # restored after a crash or when terminated externally.
  283. config_file.set_value("main", "screen", get_window().current_screen)
  284. config_file.set_value("main", "mode", get_window().mode)
  285. config_file.set_value("main", "position", get_window().position)
  286. config_file.set_value("main", "size", get_window().size)
  287. config_file.save(CONFIG_WINDOW_PATH)
  288. .. note::
  289. The above example only tracks the main window's position.
  290. In applications that spawn multiple windows, you will need
  291. to save and load each window position's and size separately.
  292. Hiding the window during the splash screen
  293. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  294. For some applications, it may be preferred to hide the splash screen
  295. to draw a custom splash screen with a progress bar instead (or even
  296. no splash screen at all, if the application boots quickly).
  297. Godot lacks native support for hiding the window during the splash screen,
  298. but you can achieve this by using a very small transparent window in the
  299. project settings, then resizing the window and disabling transparency once
  300. the main scene is loaded.
  301. To do so, project settings should be configured as follows:
  302. - :ref:`application/boot_splash/bg_color <class_ProjectSettings_property_application/boot_splash/bg_color>`
  303. set to a transparent black color (RGBA: 0, 0, 0, 0).
  304. - :ref:`application/boot_splash/show_image <class_ProjectSettings_property_application/boot_splash/show_image>`
  305. disabled.
  306. - :ref:`display/window/size/borderless <class_ProjectSettings_property_display/window/size/borderless>`
  307. enabled.
  308. - :ref:`display/window/size/no_focus <class_ProjectSettings_property_display/window/size/no_focus>`
  309. enabled.
  310. - :ref:`display/window/size/window_width_override <class_ProjectSettings_property_display/window/size/window_width_override>`
  311. set to ``1``.
  312. - :ref:`display/window/size/window_height_override <class_ProjectSettings_property_display/window/size/window_height_override>`
  313. set to ``1``.
  314. - :ref:`display/window/per_pixel_transparency/allowed <class_ProjectSettings_property_display/window/per_pixel_transparency/allowed>`
  315. enabled.
  316. - :ref:`display/window/size/transparent <class_ProjectSettings_property_display/window/size/transparent>`
  317. enabled.
  318. - :ref:`rendering/viewport/transparent_background <class_ProjectSettings_property_rendering/viewport/transparent_background>`
  319. enabled.
  320. This script can be used as an :ref:`Autoload <doc_singletons_autoload>`
  321. to restore original settings once the splash screen is done displaying:
  322. ::
  323. extends Node
  324. func _enter_tree():
  325. # Wait a frame to be rendered before restoring the window properties.
  326. # Otherwise, properties will be restored too early and the window border
  327. # will show up around a transparent window.
  328. await get_tree().process_frame
  329. get_viewport().transparent_bg = false
  330. get_window().transparent = false
  331. get_window().borderless = false
  332. get_window().size = Vector2i(1152, 648)
  333. Displaying the application as an overlay
  334. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  335. It is possible to display the application window as an overlay that stays
  336. on top of other windows. This can be useful for applications like
  337. widgets or system monitors.
  338. To do so, enable **all** the following project settings:
  339. - :ref:`display/window/size/borderless <class_ProjectSettings_property_display/window/size/borderless>`
  340. - :ref:`display/window/per_pixel_transparency/allowed <class_ProjectSettings_property_display/window/per_pixel_transparency/allowed>`
  341. - :ref:`display/window/size/transparent <class_ProjectSettings_property_display/window/size/transparent>`
  342. - :ref:`rendering/viewport/transparent_background <class_ProjectSettings_property_rendering/viewport/transparent_background>`
  343. - :ref:`display/window/size/always_on_top <class_ProjectSettings_property_display/window/size/always_on_top>`
  344. - :ref:`display/window/size/no_focus <class_ProjectSettings_property_display/window/size/no_focus>`
  345. - This prevents the overlay from receiving keyboard input,
  346. and also hides from the taskbar and task switcher. Mouse input
  347. can still be received by the overlay (see below).
  348. Remember to poosition and resize the window using scripts,
  349. as a borderless window can generally not be moved by the user.
  350. To allow mouse input to pass through to the background application,
  351. set the :ref:`mouse_passthrough <class_Window_property_mouse_passthrough>`
  352. property to ``true`` on the Window that is being drawn as an overlay.
  353. You can also define a polygon in
  354. :ref:`mouse_passthrough_polygon <class_Window_property_mouse_passthrough_polygon>`,
  355. so that certain areas can still intercept mouse input on the overlay.
  356. Additionally, you may want to set the
  357. :ref:`exclude_from_capture <class_Window_property_exclude_from_capture>`
  358. property to ``true`` to prevent the overlay from appearing in screenshots or recordings.
  359. This hint is implemented on Windows and macOS only, and it is on a best-effort
  360. basis, so it should not be used as an absolute security measure or DRM.
  361. .. note::
  362. Displaying as an overlay is not supported when game embedding
  363. is enabled in the editor. To test this functionality
  364. when running the project, make sure you disable game embedding by
  365. switching to the :menu:`Game` screen, clicking the 3 vertical dots
  366. and unchecking :menu:`Embed Game on Next Play`.
  367. Additionally, keep in mind overlays cannot be shown on top
  368. of another application if the application in question uses
  369. exclusive fullscreen. Borderless fullscreen must be used
  370. instead for overlays to be visible.
  371. There are also `known issues <https://github.com/godotengine/godot/issues/76167>`__
  372. with transparent window display on Windows with hybrid GPU setups
  373. (such as NVIDIA Optimus). Switching renderers may
  374. help resolve the issue.
  375. On Linux with X11, transparency will not work if the user
  376. has disabled compositing in the window manager settings.
  377. .. _doc_creating_applications_scaling_to_hidpi_displays:
  378. Scaling to hiDPI displays
  379. ^^^^^^^^^^^^^^^^^^^^^^^^^
  380. Modern displays vary a lot in terms of pixel density, which means
  381. a different scaling factor is often needed to ensure UI elements
  382. are readable. The scaling factor can also be provided as a manual
  383. adjustment for the user, so that the application remains comfortable
  384. to use.
  385. Godot's multiple resolutions support is well-suited
  386. to scaling applications when configured correctly. Follow the
  387. instructions in the
  388. :ref:`non-game application section of the Multiple resolutions documentation <doc_multiple_resolutions_non_game_application>`.
  389. .. note::
  390. Godot currently only supports reading the screen scale factor
  391. from the OS settings on macOS, Android, and Linux (Wayland only).
  392. On Linux (X11) and Windows, you will need to provide a manual
  393. scaling option for the user to adjust the UI scale as needed.
  394. Screen reader integration
  395. ^^^^^^^^^^^^^^^^^^^^^^^^^
  396. Screen readers allow visually impaired people to use an application
  397. by reading out the UI elements and providing navigation controls.
  398. Braille displays are another approach that also rely on accessibility
  399. information to function properly.
  400. Godot automatically enables screen reader support if a screen reader
  401. is detected as running. This can be configured in the Project Settings
  402. using :ref:`accessibility/general/accessibility_support <class_ProjectSettings_property_accessibility/general/accessibility_support>`
  403. to disable it in situations where it is not desired. It can also be
  404. forcibly enabled, which is useful when using accessibility debugging
  405. tools that are not recognized as screen readers by Godot.
  406. Godot uses the `AccessKit <https://accesskit.dev/>`__ library
  407. for screen reader integration.
  408. .. tip::
  409. Since screen reader support uses the screen reader application itself
  410. to play audio (rather than the Godot project), it will work
  411. even if the audio driver is set to ``Dummy`` in the project settings
  412. as described below.
  413. It's strongly recommended to test your application with popular screen
  414. readers on your target platforms to ensure a good user experience for
  415. visually impaired users. Examples include
  416. `NVDA <https://www.nvaccess.org/download/>`__ on Windows,
  417. `VoiceOver <https://www.apple.com/accessibility/features/?vision>`__
  418. on macOS, and `Orca <https://help.gnome.org/orca/>`__ on Linux.
  419. To get screen reader support to a good level of usability, significant
  420. amounts of work are required. You need to define accessibility labels
  421. using the :ref:`Control.accessibility_name <class_Control_property_accessibility_name>`
  422. and :ref:`Control.accessibility_description <class_Control_property_accessibility_description>`
  423. properties, and ensure the UI flows in a logical order when read by a screen reader.
  424. .. seealso::
  425. See also :ref:`doc_text_to_speech` for text-to-speech functionality
  426. that is separate from screen readers.
  427. Recommended project settings
  428. ----------------------------
  429. Desktop integration
  430. ^^^^^^^^^^^^^^^^^^^
  431. To allow the application to better integrate with the desktop environment,
  432. you can set these project settings as follows:
  433. - Enable :ref:`application/config/use_custom_user_dir <class_ProjectSettings_property_application/config/use_custom_user_dir>`
  434. and set :ref:`application/config/custom_user_dir_name <class_ProjectSettings_property_application/config/custom_user_dir_name>`
  435. to a suitable name for your application. This ensures user settings and
  436. files are stored in a dedicated folder instead of the
  437. :ref:`default Godot folder <doc_data_paths_accessing_persistent_user_data>`.
  438. By convention, it's a good idea to use normal case on Windows
  439. (e.g. ``Application Name``) and kebab-case (e.g. ``application-name``)
  440. on macOS and Linux.
  441. - Configure native icons that match the operating system's design guidelines
  442. using :ref:`application/config/windows_native_icon <class_ProjectSettings_property_application/config/windows_native_icon>`
  443. (in ICO format) and
  444. :ref:`application/config/macos_native_icon <class_ProjectSettings_property_application/config/macos_native_icon>`
  445. (in ICNS format). By default, Godot will automatically generate native icons
  446. based on the project icon, but this is not always optimal.
  447. - On Windows, using a manually designed ICO file allows you to use different
  448. icons for different resolutions. This can be used to create a special design
  449. at lower resolutions for better readability.
  450. - macOS has `app icon guidelines <https://developer.apple.com/design/human-interface-guidelines/app-icons/>`__
  451. that differ significantly from other platforms.
  452. Using a tailored native icon design ensures the application better fits in
  453. its desktop environment.
  454. - Disable
  455. :ref:`display/window/subwindows/embed_subwindows <class_ProjectSettings_property_display/window/subwindows/embed_subwindows>`,
  456. so that additional windows use the operating system theming and are
  457. seen as native operating system windows.
  458. Performance
  459. ^^^^^^^^^^^
  460. Here are some project settings you can use to reduce CPU, GPU, and memory utilization:
  461. - Use the Compatibility renderer if you don't need features that are exclusive
  462. to Forward+ or Mobile. The Compatibility renderer has lower hardware requirements
  463. and generally launches faster, which makes it a better option for applications.
  464. Creating new windows is also faster with this renderer.
  465. - Enable :ref:`application/run/low_processor_mode <class_ProjectSettings_property_application/run/low_processor_mode>`
  466. to decrease CPU and GPU usage. This makes the project only render a frame
  467. if something on screen has changed.
  468. - Note that in certain cases, the project
  469. has to redraw continuously (e.g. if an animation or shader using ``TIME``
  470. is visible). This will result in significant power draw if done for
  471. a long time, which leads to reduced battery life and increased fan noise.
  472. To troubleshoot situations where the project redraws continuously,
  473. you can enable :menu:`Debug > Debug Canvas Item Redraws` at the top of
  474. the editor, then run the project. Areas that are redrawn will be highlighted
  475. in red for a second. The highlighting color and duration can be adjusted
  476. using the :ref:`debug/canvas_items/debug_redraw_time <class_ProjectSettings_property_debug/canvas_items/debug_redraw_time>`
  477. and :ref:`debug/canvas_items/debug_redraw_color <class_ProjectSettings_property_debug/canvas_items/debug_redraw_color>`
  478. project settings.
  479. - The maximum framerate at which the application can draw is determined by
  480. :ref:`application/run/low_processor_mode_sleep_usec <class_ProjectSettings_property_application/run/low_processor_mode_sleep_usec>`.
  481. This value is expressed in microseconds per frame, so the maximum FPS
  482. can be obtained using the formula ``1000000.0 / sleep_usec``. By default,
  483. this is set to ``6900``, which corresponds to a maximum of approximately
  484. 145 FPS. You can increase this value to further reduce CPU and GPU usage,
  485. at the cost of a less smooth experience.
  486. - Disable :ref:`display/window/energy_saving/keep_screen_on <class_ProjectSettings_property_display/window/energy_saving/keep_screen_on>`,
  487. so that the screen can turn off according to the operating system's power
  488. settings when the application is idle. This behavior is normally not desired
  489. in a game (e.g. when watching cutscenes), but in applications, we want the
  490. screen to turn off to save power when the user is not actively using the application.
  491. - Set :ref:`audio/driver/driver <class_ProjectSettings_property_audio/driver/driver>` to ``Dummy`` *(case-sensitive)*
  492. if your application does not require audio output or input. This prevents the audio
  493. server from starting, which saves some CPU and memory resources. This also
  494. prevents the application from showing up in the list of applications playing
  495. audio in the operating system's audio mixer. On macOS, this also ensures the
  496. application does not prevent the device from sleeping.
  497. - Set :ref:`physics/2d/physics_engine <class_ProjectSettings_property_physics/2d/physics_engine>`
  498. and :ref:`physics/3d/physics_engine <class_ProjectSettings_property_physics/3d/physics_engine>` to
  499. ``Dummy`` if your application does not require physics simulation (including
  500. object picking). This prevents the physics servers from starting,
  501. which saves CPU and memory resources. This also allows the
  502. :ref:`engine compilation configuration editor <doc_engine_compilation_configuration_editor>`
  503. to automatically detect the fact that the project doesn't use physics.
  504. - Consider setting :ref:`display/window/vsync/vsync_mode <class_ProjectSettings_property_display/window/vsync/vsync_mode>`
  505. to **Disabled** to reduce input lag. This is particularly helpful in
  506. latency-sensitive projects such as drawing applications.
  507. This may increase power usage and cause screen tearing, so it's recommended
  508. to provide an option for the user to toggle V-Sync as needed.
  509. Check out `Material Maker <https://github.com/RodZill4/material-maker>`__ and
  510. `Pixelorama <https://github.com/Orama-Interactive/Pixelorama>`__ for examples of
  511. open source applications made with Godot.
  512. Mobile
  513. ^^^^^^
  514. When designing an application for mobile platforms, there are several settings
  515. you can enable to improve usability:
  516. **Android:**
  517. - Enable :ref:`input_devices/pointing/android/enable_long_press_as_right_click <class_ProjectSettings_property_input_devices/pointing/android/enable_long_press_as_right_click>`
  518. to allow users to perform right-click actions using a long press gesture.
  519. - Enable :ref:`input_devices/pointing/android/enable_pan_and_scale_gestures <class_ProjectSettings_property_input_devices/pointing/android/enable_pan_and_scale_gestures>`
  520. to allow users to pan and zoom using touch gestures. This will emulate
  521. :ref:`class_InputEventPanGesture` and :ref:`class_InputEventMagnifyGesture`
  522. events, which can be handled in your project's code and are normally
  523. emitted by laptop trackpads.
  524. - Disable :menu:`Screen > Immersive Mode` in the Android export preset
  525. to show the system status and navigation bars while the application is active.
  526. Additionally, enable :menu:`Screen > Edge to Edge` to make status bars and
  527. navigation icons translucent and draw on top of the application. If you do so,
  528. make sure your application leaves enough space available for the status bar
  529. and navigation icons. You can use
  530. :ref:`DisplayServer.get_display_safe_area <class_DisplayServer_method_get_display_safe_area>`
  531. and :ref:`DisplayServer.get_display_cutouts <class_DisplayServer_method_get_display_cutouts>`
  532. to query the area in which your application can safely draw.
  533. **iOS:**
  534. - Disable :ref:`display/window/ios/hide_home_indicator <class_ProjectSettings_property_display/window/ios/hide_home_indicator>`
  535. to show the home indicator on top of the application.
  536. - Disable :ref:`display/window/ios/hide_status_bar <class_ProjectSettings_property_display/window/ios/hide_status_bar>`
  537. to keep the status bar visible when the application is active.
  538. - Disable :ref:`display/window/ios/suppress_ui_gesture <class_ProjectSettings_property_display/window/ios/suppress_ui_gesture>`
  539. to allow UI gestures to work immediately, without requiring them
  540. to be done twice.
  541. Adding unit tests
  542. -----------------
  543. In an application, there is often more value in having
  544. a `unit testing <https://en.wikipedia.org/wiki/Unit_testing>`__
  545. setup compared to a game. This can be used to catch regressions
  546. in an automated manner, which tends to be easier to do in an
  547. application scenario where logic can be cleanly separated.
  548. GDScript does not feature an integrated unit testing framework,
  549. but several plugins for unit testing maintained by the community exist:
  550. - `Gut <https://github.com/bitwes/Gut>`__
  551. - `GdUnit4 <https://github.com/godot-gdunit-labs/gdUnit4>`__ (also supports C#)
  552. With C# and GDExtension (C++, Rust, etc.), you can use standard testing frameworks
  553. such as NUnit or `doctest <https://github.com/doctest/doctest>`__.
  554. Optimizing distribution size
  555. ----------------------------
  556. Since non-game applications generally avoid using large parts of the engine,
  557. such as audio or 3D functionality, you can compile an optimized export template
  558. to reduce its file size. This will also improve startup times,
  559. especially on the web platform where binary size is directly linked to
  560. initialization speeds.
  561. The size reduction is often significant (relative to the project's size),
  562. since applications contain fewer large assets compared to games.
  563. See :ref:`doc_optimizing_for_size` for more information on how to do this.
  564. Creating installers
  565. -------------------
  566. While games are typically installed through launchers such as Steam or downloaded
  567. as a ZIP, applications are often distributed as installers for better desktop
  568. integration. The installer can perform actions like adding shortcuts to the
  569. Start Menu or desktop, setting up file associations, and more. Installers
  570. can also be run automatically through the command line, which makes them
  571. more desirable for corporate environments.
  572. Godot does not have built-in support for creating installers for exported projects.
  573. However, it is still possible to create your own installers using third-party tools.
  574. Here is a non-exhaustive list of tools that can be used to create installers:
  575. - **Windows:** `Inno Setup <https://jrsoftware.org/isinfo.php>`__,
  576. `NSIS <https://nsis.sourceforge.io/Main_Page>`__
  577. - If you have a code signing certificate, remember to sign *both*
  578. the installer and project executable. To do so,
  579. :ref:`sign the exported project executable <doc_exporting_for_windows_code_signing>`,
  580. create the installer containing the exported project, then manually
  581. sign the installer that you just created.
  582. - **macOS:** `create-dmg <https://github.com/create-dmg/create-dmg>`__
  583. - **Linux:** `Flatpak <https://docs.flatpak.org/en/latest/first-build.html>`__
  584. - There is a `Godot BaseApp <https://github.com/flathub/org.godotengine.Godot.BaseApp>`__
  585. that can be used as a base for creating Flatpak packages for Godot projects.
  586. See `the Pixelorama Flatpak <https://github.com/flathub/com.orama_interactive.Pixelorama>`__
  587. for an example Flatpak that makes use of this BaseApp.
  588. Resources
  589. ---------
  590. These pages cover tasks commonly performed in non-game applications:
  591. - :ref:`doc_runtime_loading_and_saving`
  592. - :ref:`doc_http_request_class`
  593. - :ref:`class_ConfigFile` (used to save user preferences)