frontengine 1.0.32__tar.gz → 1.0.33__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. {frontengine-1.0.32 → frontengine-1.0.33}/PKG-INFO +1 -1
  2. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/pet/desktop_pet.py +24 -93
  3. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/text/draw_text.py +12 -1
  4. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/main_ui.py +10 -3
  5. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/menu/preset_menu.py +21 -0
  6. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/menu/settings_menu.py +37 -0
  7. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/control_center/control_center_ui.py +27 -2
  8. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/user_setting/user_setting_file.py +3 -0
  9. frontengine-1.0.33/frontengine/utils/autostart/autostart_service.py +172 -0
  10. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/multi_language/english.py +5 -0
  11. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/multi_language/traditional_chinese.py +5 -0
  12. frontengine-1.0.33/frontengine/utils/platform_info/platform_info.py +303 -0
  13. frontengine-1.0.33/frontengine/utils/power_mode/power_mode.py +29 -0
  14. frontengine-1.0.33/frontengine/utils/theme_schedule/__init__.py +0 -0
  15. frontengine-1.0.33/frontengine/utils/weather/__init__.py +0 -0
  16. frontengine-1.0.33/frontengine/worker/__init__.py +0 -0
  17. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine.egg-info/PKG-INFO +1 -1
  18. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine.egg-info/SOURCES.txt +6 -0
  19. {frontengine-1.0.32 → frontengine-1.0.33}/pyproject.toml +1 -1
  20. {frontengine-1.0.32 → frontengine-1.0.33}/LICENSE +0 -0
  21. {frontengine-1.0.32 → frontengine-1.0.33}/README.md +0 -0
  22. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/__init__.py +0 -0
  23. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/__main__.py +0 -0
  24. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/__init__.py +0 -0
  25. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/base_widget.py +0 -0
  26. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/gif/__init__.py +0 -0
  27. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/gif/paint_gif.py +0 -0
  28. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/image/__init__.py +0 -0
  29. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/image/paint_image.py +0 -0
  30. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/load/__init__.py +0 -0
  31. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/load/load_someone_make_ui.py +0 -0
  32. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/overlay_factory.py +0 -0
  33. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/particle/__init__.py +0 -0
  34. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/particle/particle_ui.py +0 -0
  35. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/pet/__init__.py +0 -0
  36. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/presentation/__init__.py +0 -0
  37. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/presentation/annotation_overlay.py +0 -0
  38. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/presentation/cursor_effects.py +0 -0
  39. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/presentation/keystroke_display.py +0 -0
  40. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/presentation/magnifier.py +0 -0
  41. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/scene/__init__.py +0 -0
  42. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/scene/extend_graphic_scene.py +0 -0
  43. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/scene/extend_graphic_view.py +0 -0
  44. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/scene/scene.py +0 -0
  45. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/screen_care/__init__.py +0 -0
  46. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/screen_care/screen_filter.py +0 -0
  47. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/sound_player/__init__.py +0 -0
  48. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/sound_player/sound_effect.py +0 -0
  49. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/sound_player/sound_player.py +0 -0
  50. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/text/__init__.py +0 -0
  51. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/video/__init__.py +0 -0
  52. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/video/video_player.py +0 -0
  53. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/web/__init__.py +0 -0
  54. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/web/webview.py +0 -0
  55. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/show/window_helpers.py +0 -0
  56. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/system_tray/__init__.py +0 -0
  57. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/system_tray/extend_system_tray.py +0 -0
  58. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/__init__.py +0 -0
  59. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/color/__init__.py +0 -0
  60. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/color/global_color.py +0 -0
  61. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/dialog/__init__.py +0 -0
  62. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/dialog/choose_file_dialog.py +0 -0
  63. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/dialog/hotkey_settings_dialog.py +0 -0
  64. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/dialog/save_file_dialog.py +0 -0
  65. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/menu/__init__.py +0 -0
  66. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/menu/help_menu.py +0 -0
  67. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/menu/how_to_menu.py +0 -0
  68. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/menu/language_menu.py +0 -0
  69. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/__init__.py +0 -0
  70. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/control_center/__init__.py +0 -0
  71. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/gif/__init__.py +0 -0
  72. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/gif/gif_setting_ui.py +0 -0
  73. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/image/__init__.py +0 -0
  74. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/image/image_setting_ui.py +0 -0
  75. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/particle/__init__.py +0 -0
  76. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/particle/particle_setting_ui.py +0 -0
  77. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/pet/__init__.py +0 -0
  78. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/pet/pet_setting_ui.py +0 -0
  79. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/presentation/__init__.py +0 -0
  80. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/presentation/presentation_setting_ui.py +0 -0
  81. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/scene_setting/__init__.py +0 -0
  82. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/scene_setting/scene_manager.py +0 -0
  83. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/scene_setting/scene_page/__init__.py +0 -0
  84. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/scene_setting/scene_page/base_scene_page.py +0 -0
  85. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/scene_setting/scene_page/gif.py +0 -0
  86. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/scene_setting/scene_page/image.py +0 -0
  87. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/scene_setting/scene_page/registry.py +0 -0
  88. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/scene_setting/scene_page/sound.py +0 -0
  89. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/scene_setting/scene_page/text.py +0 -0
  90. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/scene_setting/scene_page/video.py +0 -0
  91. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/scene_setting/scene_page/web.py +0 -0
  92. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/scene_setting/scene_setting_ui.py +0 -0
  93. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/screen_care/__init__.py +0 -0
  94. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/screen_care/screen_care_setting_ui.py +0 -0
  95. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/sound_player/__init__.py +0 -0
  96. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/sound_player/sound_player_setting_ui.py +0 -0
  97. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/text/__init__.py +0 -0
  98. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/text/text_setting_ui.py +0 -0
  99. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/utils.py +0 -0
  100. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/video/__init__.py +0 -0
  101. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/video/video_setting_ui.py +0 -0
  102. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/web/__init__.py +0 -0
  103. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/ui/page/web/web_setting_ui.py +0 -0
  104. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/user_setting/__init__.py +0 -0
  105. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/user_setting/preset_repository.py +0 -0
  106. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/user_setting/scene_setting.py +0 -0
  107. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/__init__.py +0 -0
  108. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/audio_meter/__init__.py +0 -0
  109. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/audio_meter/audio_envelope.py +0 -0
  110. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/audio_meter/screen_audio.py +0 -0
  111. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/audio_meter/system_audio_meter.py +0 -0
  112. {frontengine-1.0.32/frontengine/utils/break_reminder → frontengine-1.0.33/frontengine/utils/autostart}/__init__.py +0 -0
  113. {frontengine-1.0.32/frontengine/utils/browser → frontengine-1.0.33/frontengine/utils/break_reminder}/__init__.py +0 -0
  114. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/break_reminder/break_reminder.py +0 -0
  115. {frontengine-1.0.32/frontengine/utils/critical_exit → frontengine-1.0.33/frontengine/utils/browser}/__init__.py +0 -0
  116. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/browser/browser.py +0 -0
  117. {frontengine-1.0.32/frontengine/utils/file → frontengine-1.0.33/frontengine/utils/critical_exit}/__init__.py +0 -0
  118. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/critical_exit/check_key_is_press.py +0 -0
  119. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/critical_exit/critical_exit.py +0 -0
  120. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/critical_exit/win32_vk.py +0 -0
  121. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/exception/__init__.py +0 -0
  122. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/exception/exception_tags.py +0 -0
  123. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/exception/exceptions.py +0 -0
  124. {frontengine-1.0.32/frontengine/utils/focus_timer → frontengine-1.0.33/frontengine/utils/file}/__init__.py +0 -0
  125. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/file/open/__init__.py +0 -0
  126. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/file/open/open_file.py +0 -0
  127. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/file/save/__init__.py +0 -0
  128. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/file/save/save_file.py +0 -0
  129. {frontengine-1.0.32/frontengine/utils/hotkey → frontengine-1.0.33/frontengine/utils/focus_timer}/__init__.py +0 -0
  130. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/focus_timer/focus_timer.py +0 -0
  131. {frontengine-1.0.32/frontengine/utils/input_watch → frontengine-1.0.33/frontengine/utils/hotkey}/__init__.py +0 -0
  132. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/hotkey/hotkey_service.py +0 -0
  133. {frontengine-1.0.32/frontengine/utils/json → frontengine-1.0.33/frontengine/utils/input_watch}/__init__.py +0 -0
  134. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/input_watch/input_watch_service.py +0 -0
  135. {frontengine-1.0.32/frontengine/utils/logging → frontengine-1.0.33/frontengine/utils/json}/__init__.py +0 -0
  136. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/json/json_file.py +0 -0
  137. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/json/json_repository.py +0 -0
  138. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/json_format/__init__.py +0 -0
  139. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/json_format/json_process.py +0 -0
  140. {frontengine-1.0.32/frontengine/utils/multi_language → frontengine-1.0.33/frontengine/utils/logging}/__init__.py +0 -0
  141. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/logging/loggin_instance.py +0 -0
  142. {frontengine-1.0.32/frontengine/utils/pet_chat → frontengine-1.0.33/frontengine/utils/multi_language}/__init__.py +0 -0
  143. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/multi_language/france.py +0 -0
  144. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/multi_language/germany.py +0 -0
  145. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/multi_language/italy.py +0 -0
  146. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/multi_language/language_wrapper.py +0 -0
  147. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/multi_language/russian.py +0 -0
  148. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/multi_language/simplified_chinese.py +0 -0
  149. {frontengine-1.0.32/frontengine/utils/preset_schedule → frontengine-1.0.33/frontengine/utils/pet_chat}/__init__.py +0 -0
  150. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/pet_chat/pet_chat_service.py +0 -0
  151. {frontengine-1.0.32/frontengine/utils/redirect_manager → frontengine-1.0.33/frontengine/utils/platform_info}/__init__.py +0 -0
  152. {frontengine-1.0.32/frontengine/utils/smart_pause → frontengine-1.0.33/frontengine/utils/power_mode}/__init__.py +0 -0
  153. {frontengine-1.0.32/frontengine/utils/system_stats → frontengine-1.0.33/frontengine/utils/preset_schedule}/__init__.py +0 -0
  154. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/preset_schedule/preset_schedule_service.py +0 -0
  155. {frontengine-1.0.32/frontengine/utils/text_source → frontengine-1.0.33/frontengine/utils/redirect_manager}/__init__.py +0 -0
  156. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/redirect_manager/redirect_manager_class.py +0 -0
  157. {frontengine-1.0.32/frontengine/utils/theme_schedule → frontengine-1.0.33/frontengine/utils/smart_pause}/__init__.py +0 -0
  158. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/smart_pause/smart_pause_service.py +0 -0
  159. {frontengine-1.0.32/frontengine/utils/weather → frontengine-1.0.33/frontengine/utils/system_stats}/__init__.py +0 -0
  160. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/system_stats/system_stats.py +0 -0
  161. {frontengine-1.0.32/frontengine/worker → frontengine-1.0.33/frontengine/utils/text_source}/__init__.py +0 -0
  162. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/text_source/text_source.py +0 -0
  163. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/theme_schedule/theme_schedule_service.py +0 -0
  164. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/weather/weather_service.py +0 -0
  165. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/utils/web_url.py +0 -0
  166. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine/worker/qthread_worker.py +0 -0
  167. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine.egg-info/dependency_links.txt +0 -0
  168. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine.egg-info/entry_points.txt +0 -0
  169. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine.egg-info/requires.txt +0 -0
  170. {frontengine-1.0.32 → frontengine-1.0.33}/frontengine.egg-info/top_level.txt +0 -0
  171. {frontengine-1.0.32 → frontengine-1.0.33}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frontengine
3
- Version: 1.0.32
3
+ Version: 1.0.33
4
4
  Summary: FrontEngine is use-define frontview or only use like screen saver
5
5
  Author-email: JE-Chen <jechenmailman@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/Intergration-Automation-Testing/FrontEngine
@@ -16,6 +16,12 @@ from frontengine.show.window_helpers import apply_overlay_window_flags
16
16
  from frontengine.user_setting.user_setting_file import user_setting_dict
17
17
  from frontengine.utils.audio_meter.audio_envelope import AudioEnvelope
18
18
  from frontengine.utils.logging.loggin_instance import front_engine_logger
19
+ from frontengine.utils.power_mode.power_mode import scaled_interval
20
+ from frontengine.utils.platform_info.platform_info import (
21
+ idle_seconds as platform_idle_seconds,
22
+ read_battery as platform_read_battery,
23
+ standable_windows,
24
+ )
19
25
  from frontengine.utils.multi_language.language_wrapper import language_wrapper
20
26
 
21
27
  # 行為模式 / Behaviour modes
@@ -212,75 +218,17 @@ def derive_visual_state(dragging: bool, airborne: bool, surface: str, motion_sta
212
218
  return STATE_WALK
213
219
 
214
220
 
215
- # 列舉可站立視窗時要略過的外殼視窗類別
216
- # Shell window classes skipped when enumerating standable windows.
217
- _PLATFORM_SKIP_CLASSES = {"WorkerW", "Progman", "Shell_TrayWnd", "Button"}
218
-
219
-
220
221
  def windows_platforms(exclude_hwnds=()) -> list:
221
222
  """
222
- 回傳目前可見頂層視窗的上緣做為可站立平台 (left, right, top_y)。僅 Windows
223
- 有效,其餘平台或發生錯誤時回傳空清單。
224
- Return the top edges of visible top-level windows as standable platforms
225
- (left, right, top_y). Windows only; returns [] elsewhere or on error.
223
+ 回傳目前可站立的視窗上緣 (left, right, top_y);各平台實作見 platform_info。
224
+ Standable window top edges; per-platform implementations live in platform_info.
226
225
  """
227
- if sys.platform != "win32":
228
- return []
229
- try:
230
- import ctypes
231
- from ctypes import wintypes
232
-
233
- user32 = ctypes.windll.user32
234
- exclude = {int(h) for h in exclude_hwnds}
235
- platforms: list = []
236
-
237
- @ctypes.WINFUNCTYPE(wintypes.BOOL, wintypes.HWND, wintypes.LPARAM)
238
- def _collect(hwnd, _lparam):
239
- if int(hwnd) in exclude or not user32.IsWindowVisible(hwnd):
240
- return True
241
- rect = wintypes.RECT()
242
- if not user32.GetWindowRect(hwnd, ctypes.byref(rect)):
243
- return True
244
- width = rect.right - rect.left
245
- height = rect.bottom - rect.top
246
- if width < 80 or height < 40:
247
- return True
248
- class_buffer = ctypes.create_unicode_buffer(64)
249
- user32.GetClassNameW(hwnd, class_buffer, 64)
250
- if class_buffer.value in _PLATFORM_SKIP_CLASSES:
251
- return True
252
- platforms.append((rect.left, rect.right, rect.top))
253
- return True
254
-
255
- user32.EnumWindows(_collect, 0)
256
- return platforms
257
- except Exception as error: # pragma: no cover - Win32 boundary
258
- front_engine_logger.warning(f"[windows_platforms] error: {error!r}")
259
- return []
226
+ return standable_windows(exclude_hwnds)
260
227
 
261
228
 
262
229
  def idle_seconds():
263
- """
264
- 回傳使用者未操作的秒數;無法取得時回傳 None。僅 Windows 實作。
265
- Seconds since the last user input, or None when unavailable (Windows only).
266
- """
267
- if sys.platform != "win32":
268
- return None
269
- try:
270
- import ctypes
271
-
272
- class _LASTINPUTINFO(ctypes.Structure):
273
- _fields_ = [("cbSize", ctypes.c_uint), ("dwTime", ctypes.c_uint)]
274
-
275
- info = _LASTINPUTINFO()
276
- info.cbSize = ctypes.sizeof(info)
277
- if not ctypes.windll.user32.GetLastInputInfo(ctypes.byref(info)):
278
- return None
279
- elapsed_ms = ctypes.windll.kernel32.GetTickCount() - info.dwTime
280
- return max(0.0, elapsed_ms / 1000.0)
281
- except Exception as error: # pragma: no cover - Win32 boundary
282
- front_engine_logger.warning(f"[idle_seconds] error: {error!r}")
283
- return None
230
+ """使用者未操作的秒數;取不到回傳 None(跨平台,見 platform_info)。"""
231
+ return platform_idle_seconds()
284
232
 
285
233
 
286
234
  class PetTimeline:
@@ -335,35 +283,8 @@ def pop_due_reminders(now, reminders):
335
283
 
336
284
 
337
285
  def read_battery():
338
- """
339
- 回傳 (電量百分比, 是否充電中);無法取得時回傳 None。僅 Windows 實作。
340
- Return (percent, charging) or None when unavailable. Windows only.
341
- """
342
- if sys.platform != "win32":
343
- return None
344
- try:
345
- import ctypes
346
-
347
- class _SPS(ctypes.Structure):
348
- _fields_ = [
349
- ("ACLineStatus", ctypes.c_byte),
350
- ("BatteryFlag", ctypes.c_byte),
351
- ("BatteryLifePercent", ctypes.c_byte),
352
- ("SystemStatusFlag", ctypes.c_byte),
353
- ("BatteryLifeTime", ctypes.c_ulong),
354
- ("BatteryFullLifeTime", ctypes.c_ulong),
355
- ]
356
-
357
- status = _SPS()
358
- if not ctypes.windll.kernel32.GetSystemPowerStatus(ctypes.byref(status)):
359
- return None
360
- percent = status.BatteryLifePercent & 0xFF
361
- if percent == 255: # unknown / no battery
362
- return None
363
- return (int(percent), status.ACLineStatus == 1)
364
- except Exception as error: # pragma: no cover - Win32 boundary
365
- front_engine_logger.warning(f"[read_battery] error: {error!r}")
366
- return None
286
+ """回傳 (電量百分比, 是否充電中);沒有電池或取不到回傳 None(跨平台)。"""
287
+ return platform_read_battery()
367
288
 
368
289
 
369
290
  def nearest_peer(center, peers):
@@ -1147,6 +1068,9 @@ class DesktopPetWidget(BaseWidget):
1147
1068
 
1148
1069
  self._timer = QTimer(self)
1149
1070
  self._timer.timeout.connect(self._on_tick)
1071
+ # 省電模式與原始更新間隔 / Low-power state and the base tick interval
1072
+ self._low_power = False
1073
+ self._tick_interval_ms = 33
1150
1074
 
1151
1075
  # Speech bubbles / chatter / mood
1152
1076
  self._talk = bool(talk)
@@ -1417,6 +1341,12 @@ class DesktopPetWidget(BaseWidget):
1417
1341
  painter.drawPixmap(
1418
1342
  QRect((self.width() - width) // 2, self.height() - height, width, height), pixmap)
1419
1343
 
1344
+ def set_low_power(self, enabled: bool) -> None:
1345
+ """省電模式:把移動更新拉慢(畫面較不順,但省電)。"""
1346
+ self._low_power = bool(enabled)
1347
+ if self._timer.isActive():
1348
+ self._timer.start(scaled_interval(self._tick_interval_ms, self._low_power))
1349
+
1420
1350
  def start_moving(self, bounds: Tuple[int, int, int, int], interval_ms: int = 33) -> None:
1421
1351
  front_engine_logger.info(f"[DesktopPetWidget] start_moving | bounds={bounds}")
1422
1352
  left, top, right, bottom = bounds
@@ -1424,7 +1354,8 @@ class DesktopPetWidget(BaseWidget):
1424
1354
  self.motion.x = float(left)
1425
1355
  self.motion.y = float(bottom - self.pet_size)
1426
1356
  self.move(int(self.motion.x), int(self.motion.y))
1427
- self._timer.start(max(10, int(interval_ms)))
1357
+ self._tick_interval_ms = max(10, int(interval_ms))
1358
+ self._timer.start(scaled_interval(self._tick_interval_ms, self._low_power))
1428
1359
  self._schedule_chatter()
1429
1360
  self._reminder_timer.start(10000)
1430
1361
  if self._timeline_start is None:
@@ -3,6 +3,7 @@ from PySide6.QtGui import QPainter, QFont, QColor, QFontMetrics
3
3
 
4
4
  from frontengine.show.base_widget import BaseWidget
5
5
  from frontengine.utils.logging.loggin_instance import front_engine_logger
6
+ from frontengine.utils.power_mode.power_mode import scaled_interval
6
7
 
7
8
 
8
9
  _ALIGNMENT_MAP = {
@@ -35,6 +36,7 @@ class TextWidget(BaseWidget):
35
36
  self.draw_font = QFont(self.font().family(), self.font_size)
36
37
 
37
38
  # Marquee (horizontal scroll) state
39
+ self.low_power: bool = False
38
40
  self.marquee: bool = False
39
41
  self.marquee_speed: int = 4
40
42
  self.marquee_offset: int = 0
@@ -83,7 +85,7 @@ class TextWidget(BaseWidget):
83
85
  self.marquee_speed = 4
84
86
  if self.marquee:
85
87
  self.marquee_offset = self.width()
86
- self._marquee_timer.start(30)
88
+ self._marquee_timer.start(scaled_interval(30, self.low_power))
87
89
  else:
88
90
  self._marquee_timer.stop()
89
91
 
@@ -116,6 +118,15 @@ class TextWidget(BaseWidget):
116
118
  self.text = text
117
119
  self.update()
118
120
 
121
+ def set_low_power(self, enabled: bool) -> None:
122
+ """省電模式:拉慢文字來源與跑馬燈的更新,降低重繪次數。"""
123
+ self.low_power = bool(enabled)
124
+ if self._source_timer.isActive() and self.text_source is not None:
125
+ self._source_timer.start(scaled_interval(
126
+ getattr(self.text_source, "refresh_interval_ms", 1000), self.low_power))
127
+ if self._marquee_timer.isActive():
128
+ self._marquee_timer.start(scaled_interval(30, self.low_power))
129
+
119
130
  def _tick_marquee(self) -> None:
120
131
  text_width = QFontMetrics(self.draw_font).horizontalAdvance(self.text)
121
132
  self.marquee_offset -= self.marquee_speed
@@ -12,7 +12,10 @@ from frontengine.system_tray.extend_system_tray import ExtendSystemTray
12
12
  from frontengine.ui.menu.help_menu import build_help_menu
13
13
  from frontengine.ui.menu.how_to_menu import build_how_to_menu
14
14
  from frontengine.ui.menu.language_menu import build_language_menu
15
- from frontengine.ui.menu.preset_menu import apply_named_preset, apply_startup_preset, build_preset_menu
15
+ from frontengine.ui.menu.preset_menu import (
16
+ apply_named_preset, apply_startup_preset, build_preset_menu, restore_last_session,
17
+ save_last_session,
18
+ )
16
19
  from frontengine.ui.menu.settings_menu import build_settings_menu
17
20
  from frontengine.ui.page.control_center.control_center_ui import ControlCenterUI
18
21
  from frontengine.ui.page.gif.gif_setting_ui import GIFSettingUI
@@ -184,8 +187,10 @@ class FrontEngineMainUI(QMainWindow):
184
187
  )
185
188
  self.preset_schedule_service.start()
186
189
 
187
- # 套用啟動預設集(若有設定)
188
- # Apply the configured startup preset, if any
190
+ # 還原上次工作階段(若有開啟),再套用啟動預設集
191
+ # Restore the last session when enabled, then apply the startup preset.
192
+ if user_setting_dict.get("restore_last_session"):
193
+ restore_last_session(self)
189
194
  apply_startup_preset(self)
190
195
 
191
196
  # Debug 模式下自動關閉
@@ -348,6 +353,8 @@ class FrontEngineMainUI(QMainWindow):
348
353
 
349
354
  def close(self) -> None:
350
355
  """關閉程式並清理資源 / Close application and clear resources"""
356
+ if user_setting_dict.get("restore_last_session"):
357
+ save_last_session(self)
351
358
  if getattr(self, "preset_schedule_service", None) is not None:
352
359
  self.preset_schedule_service.stop()
353
360
  if getattr(self, "theme_schedule_service", None) is not None:
@@ -225,6 +225,27 @@ def apply_named_preset(ui: "FrontEngineMainUI", name: str) -> bool:
225
225
  return True
226
226
 
227
227
 
228
+ LAST_SESSION_PRESET = "__last_session__"
229
+
230
+
231
+ def save_last_session(ui: "FrontEngineMainUI") -> bool:
232
+ """
233
+ 把目前各頁面的設定存成「上次工作階段」預設集(關閉程式時呼叫)。
234
+ Store the current page settings as the last-session preset on exit.
235
+ """
236
+ try:
237
+ PresetRepository().save(LAST_SESSION_PRESET, _collect_state(ui))
238
+ return True
239
+ except (OSError, ValueError) as error:
240
+ front_engine_logger.warning(f"[PresetMenu] save_last_session failed: {error!r}")
241
+ return False
242
+
243
+
244
+ def restore_last_session(ui: "FrontEngineMainUI") -> bool:
245
+ """啟動時還原上次的設定;沒存過或讀不到就跳過。"""
246
+ return apply_named_preset(ui, LAST_SESSION_PRESET)
247
+
248
+
228
249
  def apply_startup_preset(ui: "FrontEngineMainUI") -> None:
229
250
  """
230
251
  啟動時套用設定的預設集;缺失或損毀時僅記錄警告,不影響啟動。
@@ -13,6 +13,7 @@ from frontengine.user_setting.user_setting_file import (
13
13
  user_setting_dict,
14
14
  write_user_setting,
15
15
  )
16
+ from frontengine.utils.autostart import autostart_service
16
17
  from frontengine.utils.logging.loggin_instance import front_engine_logger
17
18
  from frontengine.utils.multi_language.language_wrapper import language_wrapper
18
19
 
@@ -44,6 +45,20 @@ def build_settings_menu(ui: "FrontEngineMainUI") -> None:
44
45
  menu.addAction(theme_schedule_action)
45
46
  ui.theme_schedule_action = theme_schedule_action
46
47
 
48
+ autostart_action = QAction(_t("settings_menu_autostart", "Start with the system"), menu)
49
+ autostart_action.setCheckable(True)
50
+ autostart_action.setChecked(autostart_service.is_enabled())
51
+ autostart_action.toggled.connect(lambda checked: _toggle_autostart(ui, checked))
52
+ menu.addAction(autostart_action)
53
+ ui.autostart_action = autostart_action
54
+
55
+ restore_action = QAction(_t("settings_menu_restore_session", "Restore last session"), menu)
56
+ restore_action.setCheckable(True)
57
+ restore_action.setChecked(bool(user_setting_dict.get("restore_last_session")))
58
+ restore_action.toggled.connect(lambda checked: _toggle_restore_session(checked))
59
+ menu.addAction(restore_action)
60
+ ui.restore_session_action = restore_action
61
+
47
62
  menu.addSeparator()
48
63
  export_action = QAction(_t("settings_menu_export", "Export settings..."), menu)
49
64
  export_action.triggered.connect(lambda: _export_settings(ui))
@@ -54,6 +69,28 @@ def build_settings_menu(ui: "FrontEngineMainUI") -> None:
54
69
  menu.addAction(import_action)
55
70
 
56
71
 
72
+ def _toggle_autostart(ui: "FrontEngineMainUI", enabled: bool) -> None:
73
+ """開關開機自動啟動;設定失敗時把勾選狀態改回去並告知使用者。"""
74
+ if autostart_service.set_enabled(enabled):
75
+ return
76
+ action = getattr(ui, "autostart_action", None)
77
+ if action is not None:
78
+ action.blockSignals(True)
79
+ action.setChecked(not enabled)
80
+ action.blockSignals(False)
81
+ QMessageBox.warning(
82
+ ui,
83
+ _t("settings_menu_autostart", "Start with the system"),
84
+ _t("settings_autostart_failed", "Could not change the autostart setting."),
85
+ )
86
+
87
+
88
+ def _toggle_restore_session(enabled: bool) -> None:
89
+ """開關「還原上次工作階段」。"""
90
+ user_setting_dict["restore_last_session"] = bool(enabled)
91
+ write_user_setting()
92
+
93
+
57
94
  def _toggle_theme_schedule(ui: "FrontEngineMainUI", enabled: bool) -> None:
58
95
  """啟用/停用排程主題並立即套用 / Enable/disable scheduled theme and apply now."""
59
96
  front_engine_logger.info(f"[SettingsMenu] toggle theme schedule | enabled={enabled}")
@@ -83,6 +83,9 @@ class ControlCenterUI(QWidget):
83
83
  self.chroma_key_button = self._create_button("control_center_chroma_key_on", self.toggle_chroma_key)
84
84
  self.reset_positions_button = self._create_button(
85
85
  "control_center_reset_positions", self.reset_overlay_positions)
86
+ self._low_power = False
87
+ self.low_power_button = self._create_button(
88
+ "control_center_low_power_on", self.toggle_low_power)
86
89
  self.clear_all_button = self._create_button("control_center_close_all", self.clear_all)
87
90
 
88
91
  # Log panel
@@ -108,8 +111,9 @@ class ControlCenterUI(QWidget):
108
111
  self.grid_layout.addWidget(self.lock_all_button, 10, 0)
109
112
  self.grid_layout.addWidget(self.chroma_key_button, 11, 0)
110
113
  self.grid_layout.addWidget(self.reset_positions_button, 12, 0)
111
- self.grid_layout.addWidget(self.clear_all_button, 13, 0)
112
- self.grid_layout.addWidget(self.log_panel_scroll_area, 0, 1, 14, 1) # 明確指定 rowSpan, colSpan=1
114
+ self.grid_layout.addWidget(self.low_power_button, 13, 0)
115
+ self.grid_layout.addWidget(self.clear_all_button, 14, 0)
116
+ self.grid_layout.addWidget(self.log_panel_scroll_area, 0, 1, 15, 1) # rowSpan covers every button
113
117
  self.setLayout(self.grid_layout)
114
118
 
115
119
  # Redirect
@@ -289,6 +293,27 @@ class ControlCenterUI(QWidget):
289
293
  """忘掉記住的覆蓋層位置,之後開的覆蓋層回到各自的預設顯示方式。"""
290
294
  front_engine_logger.info("ControlCenterUI reset_overlay_positions")
291
295
  clear_overlay_geometry()
296
+ def set_low_power(self, enabled: bool) -> None:
297
+ """省電模式:讓支援的覆蓋層把更新頻率調慢。"""
298
+ front_engine_logger.info(f"ControlCenterUI set_low_power | enabled={enabled}")
299
+ self._low_power = bool(enabled)
300
+
301
+ def apply(widget) -> None:
302
+ setter = getattr(widget, "set_low_power", None)
303
+ if setter is not None:
304
+ setter(self._low_power)
305
+
306
+ self._for_each_overlay(apply)
307
+ self.low_power_button.setText(
308
+ language_wrapper.language_word_dict.get(
309
+ "control_center_low_power_off" if self._low_power else "control_center_low_power_on",
310
+ "Low power off" if self._low_power else "Low power on",
311
+ )
312
+ )
313
+
314
+ def toggle_low_power(self) -> None:
315
+ """切換省電模式 / Toggle low-power mode."""
316
+ self.set_low_power(not getattr(self, "_low_power", False))
292
317
 
293
318
  def _sample_overlay_opacity(self) -> float:
294
319
  """取一個現有覆蓋層的不透明度作為起始值 / Seed from an existing overlay's opacity."""
@@ -38,6 +38,9 @@ user_setting_dict: Dict[str, Any] = {
38
38
  # 使用者拖曳過的覆蓋層位置:類別名稱 -> [x, y, 寬, 高]
39
39
  # Overlay positions the user dragged into place: class name -> [x, y, w, h]
40
40
  "overlay_geometry": {},
41
+ # 啟動時還原上次的頁面設定
42
+ # Restore the previous session's page settings on launch
43
+ "restore_last_session": False,
41
44
  # 桌面寵物心情值(0~100),跨工作階段保存
42
45
  # Desktop pet mood (0..100), persisted across sessions
43
46
  "pet_mood": 60,
@@ -0,0 +1,172 @@
1
+ """
2
+ 開機自動啟動:Windows 寫 HKCU 的 Run 登錄機碼,Linux 放 XDG autostart 的 .desktop,
3
+ macOS 放 LaunchAgents 的 plist。全部只碰目前使用者的設定,不需要管理員權限,
4
+ 也不新增相依套件;產生內容的部分是純函式,方便測試。
5
+
6
+ Start FrontEngine with the session: an HKCU Run value on Windows, an XDG
7
+ autostart .desktop on Linux, a LaunchAgent plist on macOS. Everything stays in
8
+ the current user's own configuration — no elevation, no new dependencies — and
9
+ the content builders are pure so they can be tested on any platform.
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import sys
14
+ from pathlib import Path
15
+ from typing import List, Optional
16
+
17
+ from frontengine.utils.logging.loggin_instance import front_engine_logger
18
+
19
+ APP_NAME = "FrontEngine"
20
+ LAUNCH_AGENT_LABEL = "com.frontengine.autostart"
21
+ _DESKTOP_FILE = "frontengine.desktop"
22
+
23
+
24
+ def escape_xml(text) -> str:
25
+ """
26
+ 跳脫 plist 需要的三個字元。這裡只產生輸出、不解析任何 XML,所以不引入
27
+ XML 解析器(也就沒有 XXE 那類疑慮)。
28
+ Escape the three characters a plist needs. This only writes XML — nothing
29
+ here parses it — so no XML parser is pulled in.
30
+ """
31
+ return str(text).replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
32
+
33
+
34
+ def launch_command() -> List[str]:
35
+ """
36
+ 回傳能重新啟動本程式的命令:打包成執行檔時就是執行檔本身,
37
+ 否則以目前的直譯器執行 `-m frontengine`。
38
+ The command that relaunches the app: the frozen executable when packaged,
39
+ otherwise the current interpreter running ``-m frontengine``.
40
+ """
41
+ if getattr(sys, "frozen", False):
42
+ return [sys.executable]
43
+ return [sys.executable, "-m", "frontengine"]
44
+
45
+
46
+ def quote_command(command: List[str]) -> str:
47
+ """把命令組成一行字串,含空白的項目加上引號。"""
48
+ parts = []
49
+ for part in command:
50
+ text = str(part)
51
+ parts.append(f'"{text}"' if " " in text and not text.startswith('"') else text)
52
+ return " ".join(parts)
53
+
54
+
55
+ def desktop_entry_text(command: List[str], app_name: str = APP_NAME) -> str:
56
+ """產生 XDG autostart 用的 .desktop 內容。"""
57
+ return (
58
+ "[Desktop Entry]\n"
59
+ "Type=Application\n"
60
+ f"Name={app_name}\n"
61
+ f"Exec={quote_command(command)}\n"
62
+ "X-GNOME-Autostart-enabled=true\n"
63
+ "Terminal=false\n"
64
+ )
65
+
66
+
67
+ def launch_agent_plist(command: List[str], label: str = LAUNCH_AGENT_LABEL) -> str:
68
+ """產生 macOS LaunchAgent 用的 plist 內容。"""
69
+ arguments = "".join(f" <string>{escape_xml(part)}</string>\n" for part in command)
70
+ return (
71
+ '<?xml version="1.0" encoding="UTF-8"?>\n'
72
+ '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" '
73
+ '"http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n'
74
+ '<plist version="1.0">\n'
75
+ "<dict>\n"
76
+ " <key>Label</key>\n"
77
+ f" <string>{escape_xml(label)}</string>\n"
78
+ " <key>ProgramArguments</key>\n"
79
+ " <array>\n"
80
+ f"{arguments}"
81
+ " </array>\n"
82
+ " <key>RunAtLoad</key>\n"
83
+ " <true/>\n"
84
+ "</dict>\n"
85
+ "</plist>\n"
86
+ )
87
+
88
+
89
+ def autostart_path() -> Optional[Path]:
90
+ """回傳本平台放置自動啟動設定的檔案路徑;Windows 用登錄檔,回傳 None。"""
91
+ if sys.platform == "win32":
92
+ return None
93
+ if sys.platform == "darwin":
94
+ return Path.home() / "Library" / "LaunchAgents" / f"{LAUNCH_AGENT_LABEL}.plist"
95
+ return Path.home() / ".config" / "autostart" / _DESKTOP_FILE
96
+
97
+
98
+ def is_enabled() -> bool:
99
+ """目前是否已設定開機自動啟動。"""
100
+ if sys.platform == "win32":
101
+ return _read_windows_run_value() is not None
102
+ path = autostart_path()
103
+ return bool(path and path.is_file())
104
+
105
+
106
+ def set_enabled(enabled: bool) -> bool:
107
+ """
108
+ 開啟或關閉開機自動啟動;成功回傳 True,失敗記錄後回傳 False(不丟例外)。
109
+ Enable or disable autostart. Returns False (logged) instead of raising.
110
+ """
111
+ front_engine_logger.info(f"[autostart] set_enabled | enabled={enabled}")
112
+ try:
113
+ if sys.platform == "win32":
114
+ return _set_windows(enabled)
115
+ return _set_file(enabled)
116
+ except (OSError, ValueError) as error:
117
+ front_engine_logger.warning(f"[autostart] failed: {error!r}")
118
+ return False
119
+
120
+
121
+ def _set_file(enabled: bool) -> bool:
122
+ path = autostart_path()
123
+ if path is None:
124
+ return False
125
+ if not enabled:
126
+ if path.is_file():
127
+ path.unlink()
128
+ return True
129
+ path.parent.mkdir(parents=True, exist_ok=True)
130
+ command = launch_command()
131
+ content = launch_agent_plist(command) if sys.platform == "darwin" else desktop_entry_text(command)
132
+ path.write_text(content, encoding="utf-8")
133
+ return True
134
+
135
+
136
+ def _run_key():
137
+ import winreg
138
+
139
+ return winreg.OpenKey(
140
+ winreg.HKEY_CURRENT_USER,
141
+ r"Software\Microsoft\Windows\CurrentVersion\Run",
142
+ 0,
143
+ winreg.KEY_READ | winreg.KEY_WRITE,
144
+ )
145
+
146
+
147
+ def _read_windows_run_value() -> Optional[str]:
148
+ try:
149
+ import winreg
150
+
151
+ with _run_key() as key:
152
+ value, _kind = winreg.QueryValueEx(key, APP_NAME)
153
+ return str(value)
154
+ except FileNotFoundError:
155
+ return None
156
+ except Exception as error: # pragma: no cover - registry boundary
157
+ front_engine_logger.debug(f"[autostart] registry read failed: {error!r}")
158
+ return None
159
+
160
+
161
+ def _set_windows(enabled: bool) -> bool:
162
+ import winreg
163
+
164
+ with _run_key() as key:
165
+ if enabled:
166
+ winreg.SetValueEx(key, APP_NAME, 0, winreg.REG_SZ, quote_command(launch_command()))
167
+ else:
168
+ try:
169
+ winreg.DeleteValue(key, APP_NAME)
170
+ except FileNotFoundError:
171
+ pass
172
+ return True
@@ -186,6 +186,11 @@ english_word_dict = {
186
186
  "control_center_chroma_key_off": "Chroma key off",
187
187
  "control_center_reset_positions": "Reset overlay positions",
188
188
  "hotkey_toggle_lock": "Lock / unlock overlays",
189
+ "settings_menu_autostart": "Start with the system",
190
+ "settings_menu_restore_session": "Restore last session",
191
+ "settings_autostart_failed": "Could not change the autostart setting.",
192
+ "control_center_low_power_on": "Low power on",
193
+ "control_center_low_power_off": "Low power off",
189
194
  "control_center_mute_all": "Mute all",
190
195
  "control_center_unmute_all": "Unmute all",
191
196
  # Recent files
@@ -187,6 +187,11 @@ traditional_chinese_word_dict = {
187
187
  "control_center_chroma_key_off": "關閉綠幕背景",
188
188
  "control_center_reset_positions": "重設覆蓋層位置",
189
189
  "hotkey_toggle_lock": "鎖定/解鎖覆蓋層",
190
+ "settings_menu_autostart": "開機時自動啟動",
191
+ "settings_menu_restore_session": "還原上次工作階段",
192
+ "settings_autostart_failed": "無法變更自動啟動設定。",
193
+ "control_center_low_power_on": "開啟省電模式",
194
+ "control_center_low_power_off": "關閉省電模式",
190
195
  "control_center_mute_all": "全部靜音",
191
196
  "control_center_unmute_all": "取消全部靜音",
192
197
  # Recent files