frontengine 1.0.44__tar.gz → 1.0.46__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.
- {frontengine-1.0.44 → frontengine-1.0.46}/PKG-INFO +23 -1
- {frontengine-1.0.44 → frontengine-1.0.46}/README.md +22 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/base_widget.py +6 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/focus_shield/focus_shield_widget.py +3 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/particle/particle_ui.py +30 -31
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/pet/desktop_pet.py +93 -61
- frontengine-1.0.46/frontengine/ui/dialog/screen_privacy_dialog.py +98 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/main_ui.py +26 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/menu/settings_menu.py +7 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/control_center/control_center_ui.py +45 -2
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/user_setting/user_setting_file.py +3 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/multi_language/english.py +9 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/multi_language/traditional_chinese.py +9 -0
- frontengine-1.0.46/frontengine/utils/screen_privacy/capture_affinity.py +120 -0
- frontengine-1.0.46/frontengine/utils/screen_privacy/share_watch.py +128 -0
- frontengine-1.0.46/frontengine/worker/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine.egg-info/PKG-INFO +23 -1
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine.egg-info/SOURCES.txt +4 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/pyproject.toml +1 -1
- {frontengine-1.0.44 → frontengine-1.0.46}/LICENSE +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/__main__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/camera/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/camera/camera_widget.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/capture/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/capture/region_capture.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/focus_shield/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/gaming/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/gaming/crosshair_widget.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/gif/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/gif/paint_gif.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/image/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/image/paint_image.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/load/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/load/load_someone_make_ui.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/measure/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/measure/measure_widget.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/monitor/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/monitor/monitor_widget.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/notes/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/notes/sticky_note_widget.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/overlay_factory.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/particle/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/pet/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/presentation/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/presentation/annotation_overlay.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/presentation/cursor_effects.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/presentation/keystroke_display.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/presentation/magnifier.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/scene/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/scene/extend_graphic_scene.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/scene/extend_graphic_view.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/scene/scene.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/screen_care/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/screen_care/color_vision_widget.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/screen_care/screen_filter.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/sound_player/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/sound_player/sound_effect.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/sound_player/sound_player.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/spectrum/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/spectrum/spectrum_widget.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/teleprompter/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/teleprompter/teleprompter_widget.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/text/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/text/draw_text.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/toast/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/toast/toast_widget.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/video/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/video/video_player.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/wallpaper/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/wallpaper/wallpaper_widget.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/web/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/web/webview.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/window_helpers.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/system_tray/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/system_tray/extend_system_tray.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/color/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/color/global_color.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/dialog/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/dialog/app_profile_dialog.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/dialog/choose_file_dialog.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/dialog/clipboard_dialog.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/dialog/hotkey_settings_dialog.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/dialog/reminder_dialog.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/dialog/save_file_dialog.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/dialog/screen_text_dialog.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/dialog/smart_pause_dialog.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/dialog/usage_report_dialog.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/dialog/window_pin_dialog.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/menu/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/menu/help_menu.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/menu/how_to_menu.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/menu/language_menu.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/menu/preset_menu.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/control_center/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/focus/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/focus/focus_setting_ui.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/gif/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/gif/gif_setting_ui.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/image/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/image/image_setting_ui.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/particle/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/particle/particle_setting_ui.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/pet/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/pet/pet_setting_ui.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/presentation/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/presentation/presentation_setting_ui.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/scene_setting/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/scene_setting/scene_manager.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/scene_setting/scene_page/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/scene_setting/scene_page/base_scene_page.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/scene_setting/scene_page/gif.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/scene_setting/scene_page/image.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/scene_setting/scene_page/registry.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/scene_setting/scene_page/sound.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/scene_setting/scene_page/text.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/scene_setting/scene_page/video.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/scene_setting/scene_page/web.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/scene_setting/scene_setting_ui.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/screen_care/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/screen_care/screen_care_setting_ui.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/sound_player/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/sound_player/sound_player_setting_ui.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/stream/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/stream/stream_setting_ui.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/text/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/text/text_setting_ui.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/tools/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/tools/tools_setting_ui.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/utils.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/video/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/video/video_setting_ui.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/wallpaper/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/wallpaper/wallpaper_setting_ui.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/web/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/web/web_setting_ui.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/widgets/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/widgets/widgets_setting_ui.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/user_setting/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/user_setting/preset_repository.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/user_setting/scene_setting.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/app_profile/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/app_profile/app_profile_service.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/audio_meter/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/audio_meter/audio_envelope.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/audio_meter/loopback_capture.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/audio_meter/screen_audio.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/audio_meter/spectrum_analyzer.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/audio_meter/system_audio_meter.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/autostart/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/autostart/autostart_service.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/break_reminder/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/break_reminder/break_reminder.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/browser/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/browser/browser.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/clipboard/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/clipboard/clipboard_history.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/clipboard/clipboard_watcher.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/color_vision/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/color_vision/color_vision.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/critical_exit/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/critical_exit/check_key_is_press.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/critical_exit/critical_exit.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/critical_exit/win32_vk.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/exception/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/exception/exception_tags.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/exception/exceptions.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/file/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/file/open/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/file/open/open_file.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/file/save/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/file/save/save_file.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/focus_shield/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/focus_shield/focus_shield.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/focus_timer/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/focus_timer/focus_timer.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/hotkey/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/hotkey/hotkey_service.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/input_watch/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/input_watch/input_watch_service.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/json/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/json/json_file.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/json/json_repository.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/json_format/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/json_format/json_process.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/logging/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/logging/loggin_instance.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/measure/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/measure/measure.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/multi_language/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/multi_language/france.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/multi_language/germany.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/multi_language/italy.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/multi_language/language_wrapper.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/multi_language/russian.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/multi_language/simplified_chinese.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/now_playing/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/now_playing/now_playing.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/obs/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/obs/obs_client.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/obs/obs_protocol.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/obs/websocket_frames.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/pet_chat/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/pet_chat/pet_chat_service.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/platform_info/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/platform_info/platform_info.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/playlist/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/playlist/playlist.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/plugins/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/plugins/plugin_loader.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/power_mode/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/power_mode/power_mode.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/preset_schedule/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/preset_schedule/preset_schedule_service.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/recording/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/recording/frame_recorder.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/recording/gif_writer.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/redirect_manager/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/redirect_manager/redirect_manager_class.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/reminder/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/reminder/reminder_service.py +0 -0
- {frontengine-1.0.44/frontengine/utils/screen_text → frontengine-1.0.46/frontengine/utils/screen_privacy}/__init__.py +0 -0
- {frontengine-1.0.44/frontengine/utils/smart_pause → frontengine-1.0.46/frontengine/utils/screen_text}/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/screen_text/screen_text_service.py +0 -0
- {frontengine-1.0.44/frontengine/utils/soundboard → frontengine-1.0.46/frontengine/utils/smart_pause}/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/smart_pause/pause_rules.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/smart_pause/smart_pause_service.py +0 -0
- {frontengine-1.0.44/frontengine/utils/system_stats → frontengine-1.0.46/frontengine/utils/soundboard}/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/soundboard/soundboard.py +0 -0
- {frontengine-1.0.44/frontengine/utils/text_source → frontengine-1.0.46/frontengine/utils/system_stats}/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/system_stats/system_stats.py +0 -0
- {frontengine-1.0.44/frontengine/utils/theme_schedule → frontengine-1.0.46/frontengine/utils/text_source}/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/text_source/text_source.py +0 -0
- {frontengine-1.0.44/frontengine/utils/usage_tracking → frontengine-1.0.46/frontengine/utils/theme_schedule}/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/theme_schedule/theme_schedule_service.py +0 -0
- {frontengine-1.0.44/frontengine/utils/weather → frontengine-1.0.46/frontengine/utils/usage_tracking}/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/usage_tracking/usage_service.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/usage_tracking/usage_tracker.py +0 -0
- {frontengine-1.0.44/frontengine/utils/window_pin → frontengine-1.0.46/frontengine/utils/weather}/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/weather/weather_service.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/web_url.py +0 -0
- {frontengine-1.0.44/frontengine/utils/workshop → frontengine-1.0.46/frontengine/utils/window_pin}/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/window_pin/window_layout.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/window_pin/window_pin.py +0 -0
- {frontengine-1.0.44/frontengine/worker → frontengine-1.0.46/frontengine/utils/workshop}/__init__.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/workshop/workshop_content.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine/worker/qthread_worker.py +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine.egg-info/dependency_links.txt +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine.egg-info/entry_points.txt +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine.egg-info/requires.txt +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/frontengine.egg-info/top_level.txt +0 -0
- {frontengine-1.0.44 → frontengine-1.0.46}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: frontengine
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.46
|
|
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
|
|
@@ -196,6 +196,28 @@ Four things on the **Stream** tab, for playing and for going live:
|
|
|
196
196
|
|
|
197
197
|
---
|
|
198
198
|
|
|
199
|
+
## Screen-sharing privacy
|
|
200
|
+
|
|
201
|
+
Your overlays are for you, not for the people you are sharing with. From
|
|
202
|
+
**Settings → Screen-sharing privacy**, FrontEngine can take them out of the
|
|
203
|
+
capture while a meeting app is open:
|
|
204
|
+
|
|
205
|
+
- **They stay on your own screen.** Only the captured copy is blank — this uses
|
|
206
|
+
Windows' `WDA_EXCLUDEFROMCAPTURE`, an OS-level flag that conferencing apps and
|
|
207
|
+
recorders honour.
|
|
208
|
+
- **Masks are the exception.** A distraction mask exists to cover something, so
|
|
209
|
+
it deliberately stays visible in the capture.
|
|
210
|
+
- **The trigger is your list.** Windows has no dependable "am I being captured"
|
|
211
|
+
API, so it watches for window titles you name — which also catches a meeting
|
|
212
|
+
held in a browser tab, where the executable is just the browser.
|
|
213
|
+
|
|
214
|
+
There is a manual **Hide from capture** button in the control center too.
|
|
215
|
+
|
|
216
|
+
> This is privacy, not security: it defeats the ordinary capture path, and it
|
|
217
|
+
> never hides anything from the person sitting at the desk. Windows only.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
199
221
|
## Screen time, clipboard and layouts
|
|
200
222
|
|
|
201
223
|
Three things that remember, all of them **off until you switch them on** and
|
|
@@ -172,6 +172,28 @@ Four things on the **Stream** tab, for playing and for going live:
|
|
|
172
172
|
|
|
173
173
|
---
|
|
174
174
|
|
|
175
|
+
## Screen-sharing privacy
|
|
176
|
+
|
|
177
|
+
Your overlays are for you, not for the people you are sharing with. From
|
|
178
|
+
**Settings → Screen-sharing privacy**, FrontEngine can take them out of the
|
|
179
|
+
capture while a meeting app is open:
|
|
180
|
+
|
|
181
|
+
- **They stay on your own screen.** Only the captured copy is blank — this uses
|
|
182
|
+
Windows' `WDA_EXCLUDEFROMCAPTURE`, an OS-level flag that conferencing apps and
|
|
183
|
+
recorders honour.
|
|
184
|
+
- **Masks are the exception.** A distraction mask exists to cover something, so
|
|
185
|
+
it deliberately stays visible in the capture.
|
|
186
|
+
- **The trigger is your list.** Windows has no dependable "am I being captured"
|
|
187
|
+
API, so it watches for window titles you name — which also catches a meeting
|
|
188
|
+
held in a browser tab, where the executable is just the browser.
|
|
189
|
+
|
|
190
|
+
There is a manual **Hide from capture** button in the control center too.
|
|
191
|
+
|
|
192
|
+
> This is privacy, not security: it defeats the ordinary capture path, and it
|
|
193
|
+
> never hides anything from the person sitting at the desk. Windows only.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
175
197
|
## Screen time, clipboard and layouts
|
|
176
198
|
|
|
177
199
|
Three things that remember, all of them **off until you switch them on** and
|
|
@@ -33,6 +33,12 @@ class BaseWidget(QWidget):
|
|
|
33
33
|
# 畫質檔位:影響更新頻率上限與算圖縮放(見 utils/power_mode)
|
|
34
34
|
# Quality tier: caps the refresh rate and scales rendering (see utils/power_mode).
|
|
35
35
|
self.quality_tier: str = DEFAULT_TIER
|
|
36
|
+
# 分享畫面時要不要一起藏起來。遮蔽用的覆蓋層要留在畫面上——
|
|
37
|
+
# 那正是它存在的理由,藏了就等於沒遮。
|
|
38
|
+
# Whether this hides along with the others while sharing. A masking
|
|
39
|
+
# overlay must stay visible in the capture: hiding it would defeat
|
|
40
|
+
# the only thing it is for.
|
|
41
|
+
self.keep_in_capture: bool = False
|
|
36
42
|
self._drag_origin = None
|
|
37
43
|
self._geometry_restored = False
|
|
38
44
|
|
{frontengine-1.0.44 → frontengine-1.0.46}/frontengine/show/focus_shield/focus_shield_widget.py
RENAMED
|
@@ -118,6 +118,9 @@ class DistractionMaskWidget(BaseWidget):
|
|
|
118
118
|
f"[DistractionMaskWidget] Init | region={region}, percent={percent}")
|
|
119
119
|
super().__init__()
|
|
120
120
|
self.opacity = 1.0
|
|
121
|
+
# 這一層是拿來遮住東西的,分享畫面時必須留在擷取結果裡
|
|
122
|
+
# This layer exists to cover something, so it stays in the capture.
|
|
123
|
+
self.keep_in_capture = True
|
|
121
124
|
self.region = region
|
|
122
125
|
self.percent = clamp_percent(percent)
|
|
123
126
|
self.mask_color = QColor(color) if QColor(color).isValid() else QColor("#101010")
|
|
@@ -107,40 +107,39 @@ class ParticleOpenGLWidget(QOpenGLWidget):
|
|
|
107
107
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
|
|
108
108
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
|
|
109
109
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
elif self.particle_direction == "up":
|
|
120
|
-
y += self.particle_speed
|
|
121
|
-
if y > 1:
|
|
122
|
-
y = -1
|
|
123
|
-
x = random.uniform(-1, 1)
|
|
124
|
-
|
|
125
|
-
elif self.particle_direction == "left":
|
|
126
|
-
x -= self.particle_speed
|
|
127
|
-
if x < -1:
|
|
128
|
-
x = 1
|
|
129
|
-
y = random.uniform(-1, 1)
|
|
130
|
-
|
|
131
|
-
elif self.particle_direction == "right":
|
|
132
|
-
x += self.particle_speed
|
|
133
|
-
if x > 1:
|
|
134
|
-
x = -1
|
|
135
|
-
y = random.uniform(-1, 1)
|
|
136
|
-
|
|
137
|
-
# 你可以自行擴充其他方向
|
|
138
|
-
|
|
139
|
-
p[0] = x
|
|
140
|
-
p[1] = y
|
|
110
|
+
# 每個方向:(要移動的軸, 每步的位移正負, 越過哪一邊算離場)
|
|
111
|
+
# Per direction: which axis moves, the sign of each step, and which edge
|
|
112
|
+
# counts as leaving the screen.
|
|
113
|
+
_DIRECTIONS = {
|
|
114
|
+
"down": (1, -1, -1.0),
|
|
115
|
+
"up": (1, +1, +1.0),
|
|
116
|
+
"left": (0, -1, -1.0),
|
|
117
|
+
"right": (0, +1, +1.0),
|
|
118
|
+
}
|
|
141
119
|
|
|
120
|
+
def update_particles(self):
|
|
121
|
+
"""把每個粒子往設定的方向推一步,離開畫面的就從對面重新進場。"""
|
|
122
|
+
movement = self._DIRECTIONS.get(self.particle_direction)
|
|
123
|
+
if movement is None:
|
|
124
|
+
self.update()
|
|
125
|
+
return
|
|
126
|
+
axis, sign, edge = movement
|
|
127
|
+
other = 1 - axis
|
|
128
|
+
for particle in self.particles:
|
|
129
|
+
particle[axis] += sign * self.particle_speed
|
|
130
|
+
if self._left_the_screen(particle[axis], sign, edge):
|
|
131
|
+
# 從對面邊緣回來,另一軸重新隨機,看起來才像源源不絕
|
|
132
|
+
# Re-enter from the opposite edge with a fresh position on the
|
|
133
|
+
# other axis, so the stream never looks like a repeating loop.
|
|
134
|
+
particle[axis] = -edge
|
|
135
|
+
particle[other] = random.uniform(-1, 1) # nosec B311 - visual only
|
|
142
136
|
self.update()
|
|
143
137
|
|
|
138
|
+
@staticmethod
|
|
139
|
+
def _left_the_screen(value: float, sign: int, edge: float) -> bool:
|
|
140
|
+
"""這個粒子是不是已經越過它前進方向的那一邊。"""
|
|
141
|
+
return value < edge if sign < 0 else value > edge
|
|
142
|
+
|
|
144
143
|
def paintGL(self):
|
|
145
144
|
glClearColor(0, 0, 0, 0)
|
|
146
145
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
|
|
@@ -806,7 +806,15 @@ class PetMotion:
|
|
|
806
806
|
if self.surface != SURFACE_FLOOR:
|
|
807
807
|
return self._step_climb(left, top, right, bottom, floor_y)
|
|
808
808
|
|
|
809
|
-
|
|
809
|
+
return self._walk_on_floor(left, right, floor_y)
|
|
810
|
+
|
|
811
|
+
def _walk_on_floor(self, left, right, floor_y) -> Tuple[int, int]:
|
|
812
|
+
"""
|
|
813
|
+
站在螢幕地板上:隨機在走路與發呆之間切換,走到左右邊緣時有機會改成
|
|
814
|
+
爬牆,否則就轉頭。
|
|
815
|
+
Grounded on the screen floor: alternate between walking and idling, and
|
|
816
|
+
on reaching an edge either grab the wall or turn around.
|
|
817
|
+
"""
|
|
810
818
|
self.y = float(floor_y)
|
|
811
819
|
if self._state_ticks <= 0:
|
|
812
820
|
self._new_state()
|
|
@@ -816,20 +824,20 @@ class PetMotion:
|
|
|
816
824
|
self.x += self.vx
|
|
817
825
|
if self.x <= left:
|
|
818
826
|
self.x = float(left)
|
|
819
|
-
|
|
820
|
-
self.surface = SURFACE_LEFT
|
|
821
|
-
self.vy = float(-self.speed)
|
|
822
|
-
else:
|
|
823
|
-
self.vx = abs(self.vx)
|
|
827
|
+
self._turn_or_climb(SURFACE_LEFT, turned_vx=abs(self.vx))
|
|
824
828
|
elif self.x + self.width >= right:
|
|
825
829
|
self.x = float(right - self.width)
|
|
826
|
-
|
|
827
|
-
self.surface = SURFACE_RIGHT
|
|
828
|
-
self.vy = float(-self.speed)
|
|
829
|
-
else:
|
|
830
|
-
self.vx = -abs(self.vx)
|
|
830
|
+
self._turn_or_climb(SURFACE_RIGHT, turned_vx=-abs(self.vx))
|
|
831
831
|
return int(self.x), int(self.y)
|
|
832
832
|
|
|
833
|
+
def _turn_or_climb(self, wall: str, turned_vx: float) -> None:
|
|
834
|
+
"""走到邊緣了:抓上牆去爬,或是掉頭往回走。"""
|
|
835
|
+
if self.climb and self._rng.random() < self.CLIMB_CHANCE:
|
|
836
|
+
self.surface = wall
|
|
837
|
+
self.vy = float(-self.speed)
|
|
838
|
+
else:
|
|
839
|
+
self.vx = turned_vx
|
|
840
|
+
|
|
833
841
|
def _step_fall(self, left, top, right, bottom, _floor_y) -> Tuple[int, int]:
|
|
834
842
|
"""落下:撞牆/天花板反彈,並在越過視窗平台或螢幕地板時落地。"""
|
|
835
843
|
prev_feet = self.y + self.height
|
|
@@ -948,42 +956,49 @@ class PetMotion:
|
|
|
948
956
|
return int(self.x), int(self.y)
|
|
949
957
|
|
|
950
958
|
if self.surface == SURFACE_RIGHT:
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
self.surface = SURFACE_CEILING
|
|
956
|
-
self.vx = float(-self.speed)
|
|
957
|
-
elif self.vy > 0 and self.y >= floor_y: # climbed back down
|
|
958
|
-
self.y = float(floor_y)
|
|
959
|
-
self.surface = SURFACE_FLOOR
|
|
960
|
-
self.vx = float(-self.speed)
|
|
961
|
-
self._new_state(force_walk=True)
|
|
959
|
+
# 右牆:貼著右緣上下爬,離開時往左走
|
|
960
|
+
# Right wall: hug the right edge, and leave it heading left.
|
|
961
|
+
self._climb_wall(x=float(right - self.width), top=top, floor_y=floor_y,
|
|
962
|
+
leave_vx=float(-self.speed))
|
|
962
963
|
elif self.surface == SURFACE_LEFT:
|
|
963
|
-
self.x
|
|
964
|
-
|
|
965
|
-
if self.vy < 0 and self.y <= top:
|
|
966
|
-
self.y = float(top)
|
|
967
|
-
self.surface = SURFACE_CEILING
|
|
968
|
-
self.vx = float(self.speed)
|
|
969
|
-
elif self.vy > 0 and self.y >= floor_y:
|
|
970
|
-
self.y = float(floor_y)
|
|
971
|
-
self.surface = SURFACE_FLOOR
|
|
972
|
-
self.vx = float(self.speed)
|
|
973
|
-
self._new_state(force_walk=True)
|
|
964
|
+
self._climb_wall(x=float(left), top=top, floor_y=floor_y,
|
|
965
|
+
leave_vx=float(self.speed))
|
|
974
966
|
elif self.surface == SURFACE_CEILING:
|
|
975
|
-
self.
|
|
976
|
-
self.x += self.vx
|
|
977
|
-
if self.vx < 0 and self.x <= left: # corner -> climb down the left wall
|
|
978
|
-
self.x = float(left)
|
|
979
|
-
self.surface = SURFACE_LEFT
|
|
980
|
-
self.vy = float(self.speed)
|
|
981
|
-
elif self.vx > 0 and self.x + self.width >= right:
|
|
982
|
-
self.x = float(right - self.width)
|
|
983
|
-
self.surface = SURFACE_RIGHT
|
|
984
|
-
self.vy = float(self.speed)
|
|
967
|
+
self._crawl_ceiling(left, top, right)
|
|
985
968
|
return int(self.x), int(self.y)
|
|
986
969
|
|
|
970
|
+
def _climb_wall(self, x: float, top: float, floor_y: float, leave_vx: float) -> None:
|
|
971
|
+
"""
|
|
972
|
+
沿著一面牆上下爬。左右兩面牆的規則一模一樣,只差「離開時往哪走」,
|
|
973
|
+
所以由呼叫端把那個方向帶進來。
|
|
974
|
+
Climb one wall. Both walls follow identical rules and differ only in
|
|
975
|
+
which way the pet leaves, so the caller passes that in.
|
|
976
|
+
"""
|
|
977
|
+
self.x = x
|
|
978
|
+
self.y += self.vy
|
|
979
|
+
if self.vy < 0 and self.y <= top: # 到天花板,改成橫著爬
|
|
980
|
+
self.y = float(top)
|
|
981
|
+
self.surface = SURFACE_CEILING
|
|
982
|
+
self.vx = leave_vx
|
|
983
|
+
elif self.vy > 0 and self.y >= floor_y: # 爬回地面,恢復走路
|
|
984
|
+
self.y = float(floor_y)
|
|
985
|
+
self.surface = SURFACE_FLOOR
|
|
986
|
+
self.vx = leave_vx
|
|
987
|
+
self._new_state(force_walk=True)
|
|
988
|
+
|
|
989
|
+
def _crawl_ceiling(self, left, top, right) -> None:
|
|
990
|
+
"""在天花板上橫著爬,到角落就轉成往下爬那面牆。"""
|
|
991
|
+
self.y = float(top)
|
|
992
|
+
self.x += self.vx
|
|
993
|
+
if self.vx < 0 and self.x <= left:
|
|
994
|
+
self.x = float(left)
|
|
995
|
+
self.surface = SURFACE_LEFT
|
|
996
|
+
self.vy = float(self.speed)
|
|
997
|
+
elif self.vx > 0 and self.x + self.width >= right:
|
|
998
|
+
self.x = float(right - self.width)
|
|
999
|
+
self.surface = SURFACE_RIGHT
|
|
1000
|
+
self.vy = float(self.speed)
|
|
1001
|
+
|
|
987
1002
|
def _new_state(self, force_walk: bool = False) -> None:
|
|
988
1003
|
if force_walk or self._rng.random() < 0.65:
|
|
989
1004
|
self.state = "walk"
|
|
@@ -1245,25 +1260,42 @@ class DesktopPetWidget(BaseWidget):
|
|
|
1245
1260
|
self._peer_greeted = False
|
|
1246
1261
|
self.motion.clear_follow()
|
|
1247
1262
|
return
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1263
|
+
self._approach_peer(peer, distance)
|
|
1264
|
+
self._greet_peer(peer, distance, my_center)
|
|
1265
|
+
|
|
1266
|
+
def _approach_peer(self, peer, distance: float) -> None:
|
|
1267
|
+
"""在地板上的寵物看到不遠的同伴時,有機會走過去玩。"""
|
|
1268
|
+
if self.motion.behaviour != BEHAVIOUR_FLOOR:
|
|
1269
|
+
return
|
|
1270
|
+
if self.MEET_DISTANCE < distance <= self.PLAY_RANGE:
|
|
1271
|
+
already_walking = self.motion.follow_target_x is not None
|
|
1272
|
+
if already_walking or self._chatter_rng.random() < self.PLAY_CHANCE:
|
|
1273
|
+
self.motion.set_follow(peer[0])
|
|
1274
|
+
elif distance > self.PLAY_RANGE:
|
|
1257
1275
|
self.motion.clear_follow()
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1276
|
+
|
|
1277
|
+
def _greet_peer(self, peer, distance: float, my_center) -> None:
|
|
1278
|
+
"""
|
|
1279
|
+
走到夠近就轉頭打個招呼,一次接近只打一次;離開夠遠之後才會重新算一次
|
|
1280
|
+
(這段遲滯是為了避免在邊界來回時一直重複講話)。
|
|
1281
|
+
Close enough: turn to face them and say hello, once per approach. The
|
|
1282
|
+
flag only resets once they are well clear again, which stops a pet
|
|
1283
|
+
hovering at the boundary from repeating itself.
|
|
1284
|
+
"""
|
|
1285
|
+
if distance > self.MEET_DISTANCE:
|
|
1286
|
+
if distance > self.MEET_DISTANCE * 1.6:
|
|
1287
|
+
self._peer_greeted = False
|
|
1288
|
+
return
|
|
1289
|
+
self.motion.clear_follow()
|
|
1290
|
+
if not self._talk or self._peer_greeted:
|
|
1291
|
+
return
|
|
1292
|
+
self._peer_greeted = True
|
|
1293
|
+
self._gain_affection(3)
|
|
1294
|
+
self.motion.vx = (abs(self.motion.vx) if peer[0] >= my_center[0]
|
|
1295
|
+
else -abs(self.motion.vx))
|
|
1296
|
+
pool = self._messages.get("meet") or []
|
|
1297
|
+
if pool:
|
|
1298
|
+
self.say(pool[self._chatter_rng.randrange(len(pool))])
|
|
1267
1299
|
|
|
1268
1300
|
def _load_sprite(self, path: str):
|
|
1269
1301
|
"""載入一張精靈;檔案損毀或格式不支援時回傳 None。"""
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""
|
|
2
|
+
螢幕分享隱私設定:偵測到會議程式時,自動把覆蓋層藏出擷取畫面。
|
|
3
|
+
|
|
4
|
+
Windows 沒有可靠的「我正在被擷取嗎」API,所以判斷依據是使用者自己列出的
|
|
5
|
+
會議程式有沒有開著視窗。這是刻意的:與其猜錯,不如讓使用者說了算。
|
|
6
|
+
|
|
7
|
+
Screen-sharing privacy: hide the overlays from the capture when a meeting app
|
|
8
|
+
turns up.
|
|
9
|
+
|
|
10
|
+
Windows offers no dependable "am I being captured" API, so the trigger is
|
|
11
|
+
whether one of the apps the user listed has a window open. That is deliberate -
|
|
12
|
+
better their list than our guess.
|
|
13
|
+
"""
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from typing import Any, Dict, Optional
|
|
17
|
+
|
|
18
|
+
from PySide6.QtWidgets import (
|
|
19
|
+
QCheckBox, QDialog, QDialogButtonBox, QGridLayout, QLabel, QLineEdit, QWidget,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
from frontengine.user_setting.user_setting_file import user_setting_dict, write_user_setting
|
|
23
|
+
from frontengine.utils.logging.loggin_instance import front_engine_logger
|
|
24
|
+
from frontengine.utils.multi_language.language_wrapper import language_wrapper
|
|
25
|
+
from frontengine.utils.screen_privacy import capture_affinity
|
|
26
|
+
from frontengine.utils.screen_privacy.share_watch import DEFAULT_SHARING_APPS
|
|
27
|
+
from frontengine.utils.smart_pause.pause_rules import parse_app_list
|
|
28
|
+
|
|
29
|
+
SETTING_KEY = "screen_share_privacy"
|
|
30
|
+
DEFAULT_SETTINGS: Dict[str, Any] = {"enabled": False, "apps": list(DEFAULT_SHARING_APPS)}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _t(key: str, fallback: str) -> str:
|
|
34
|
+
return language_wrapper.language_word_dict.get(key, fallback)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def current_settings() -> Dict[str, Any]:
|
|
38
|
+
"""目前的分享隱私設定(缺項目補預設值)。"""
|
|
39
|
+
stored = user_setting_dict.get(SETTING_KEY)
|
|
40
|
+
settings = dict(DEFAULT_SETTINGS)
|
|
41
|
+
if isinstance(stored, dict):
|
|
42
|
+
settings.update({key: stored[key] for key in DEFAULT_SETTINGS if key in stored})
|
|
43
|
+
settings["apps"] = parse_app_list(settings.get("apps")) or list(DEFAULT_SHARING_APPS)
|
|
44
|
+
return settings
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class ScreenPrivacyDialog(QDialog):
|
|
48
|
+
"""設定哪些程式算是「正在分享」,以及要不要自動隱藏。"""
|
|
49
|
+
|
|
50
|
+
def __init__(self, parent: Optional[QWidget] = None) -> None:
|
|
51
|
+
front_engine_logger.info("[ScreenPrivacyDialog] Init")
|
|
52
|
+
super().__init__(parent)
|
|
53
|
+
self.setWindowTitle(_t("screen_privacy_title", "Screen-sharing privacy"))
|
|
54
|
+
settings = current_settings()
|
|
55
|
+
|
|
56
|
+
self.enable_checkbox = QCheckBox(
|
|
57
|
+
_t("screen_privacy_enable", "Hide overlays while one of these apps is open"))
|
|
58
|
+
self.enable_checkbox.setChecked(bool(settings.get("enabled")))
|
|
59
|
+
self.apps_label = QLabel(_t("screen_privacy_apps_label", "Meeting and capture apps:"))
|
|
60
|
+
self.apps_edit = QLineEdit(", ".join(settings.get("apps", [])))
|
|
61
|
+
self.apps_edit.setPlaceholderText("zoom, teams, discord")
|
|
62
|
+
self.hint_label = QLabel(
|
|
63
|
+
_t("screen_privacy_hint",
|
|
64
|
+
"Matched against window titles, so a meeting held in a browser tab is caught "
|
|
65
|
+
"too. Your overlays stay on your own screen - only the capture is blank. "
|
|
66
|
+
"Masks stay visible, since covering something is what they are for.")
|
|
67
|
+
if capture_affinity.available() else
|
|
68
|
+
_t("screen_privacy_unsupported",
|
|
69
|
+
"Hiding overlays from screen capture is Windows only."))
|
|
70
|
+
self.hint_label.setWordWrap(True)
|
|
71
|
+
|
|
72
|
+
self.button_box = QDialogButtonBox(
|
|
73
|
+
QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel)
|
|
74
|
+
self.button_box.accepted.connect(self.accept)
|
|
75
|
+
self.button_box.rejected.connect(self.reject)
|
|
76
|
+
|
|
77
|
+
layout = QGridLayout(self)
|
|
78
|
+
layout.addWidget(self.enable_checkbox, 0, 0, 1, 2)
|
|
79
|
+
layout.addWidget(self.apps_label, 1, 0, 1, 2)
|
|
80
|
+
layout.addWidget(self.apps_edit, 2, 0, 1, 2)
|
|
81
|
+
layout.addWidget(self.hint_label, 3, 0, 1, 2)
|
|
82
|
+
layout.addWidget(self.button_box, 4, 0, 1, 2)
|
|
83
|
+
for widget in (self.enable_checkbox, self.apps_edit):
|
|
84
|
+
widget.setEnabled(capture_affinity.available())
|
|
85
|
+
|
|
86
|
+
def settings(self) -> Dict[str, Any]:
|
|
87
|
+
"""對話框上目前的設定。"""
|
|
88
|
+
return {
|
|
89
|
+
"enabled": self.enable_checkbox.isChecked(),
|
|
90
|
+
"apps": parse_app_list(self.apps_edit.text()) or list(DEFAULT_SHARING_APPS),
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
def accept(self) -> None:
|
|
94
|
+
settings = self.settings()
|
|
95
|
+
user_setting_dict[SETTING_KEY] = settings
|
|
96
|
+
write_user_setting()
|
|
97
|
+
front_engine_logger.info(f"[ScreenPrivacyDialog] saved | {settings}")
|
|
98
|
+
super().accept()
|
|
@@ -49,7 +49,9 @@ from frontengine.utils.logging.loggin_instance import front_engine_logger
|
|
|
49
49
|
from frontengine.utils.multi_language.language_wrapper import language_wrapper
|
|
50
50
|
from frontengine.utils.plugins.plugin_loader import load_plugins
|
|
51
51
|
from frontengine.utils.preset_schedule.preset_schedule_service import PresetScheduleService
|
|
52
|
+
from frontengine.ui.dialog.screen_privacy_dialog import current_settings as current_privacy_settings
|
|
52
53
|
from frontengine.ui.dialog.smart_pause_dialog import current_rules
|
|
54
|
+
from frontengine.utils.screen_privacy.share_watch import ShareWatchService
|
|
53
55
|
from frontengine.utils.app_profile.app_profile_service import AppProfileService
|
|
54
56
|
from frontengine.utils.clipboard.clipboard_history import DEFAULT_LIMIT, ClipboardHistory
|
|
55
57
|
from frontengine.utils.clipboard.clipboard_watcher import ClipboardWatcher
|
|
@@ -209,6 +211,12 @@ class FrontEngineMainUI(QMainWindow):
|
|
|
209
211
|
)
|
|
210
212
|
self.app_profile_service.start()
|
|
211
213
|
|
|
214
|
+
# 分享畫面時把覆蓋層藏出擷取結果(自己仍看得到)
|
|
215
|
+
# Hide the overlays from the capture while sharing; they stay on screen here.
|
|
216
|
+
self.share_watch_service = ShareWatchService(config_provider=current_privacy_settings)
|
|
217
|
+
self.share_watch_service.sharing_changed.connect(self._on_sharing_changed)
|
|
218
|
+
self.share_watch_service.start()
|
|
219
|
+
|
|
212
220
|
# 使用時間統計:預設關閉,只寫本機檔案,使用者可隨時清除
|
|
213
221
|
# Usage tracking: off by default, local file only, clearable at any time.
|
|
214
222
|
self.usage_tracker = UsageTracker(JsonRepository(Path(getcwd()) / USAGE_FILE))
|
|
@@ -460,6 +468,22 @@ class FrontEngineMainUI(QMainWindow):
|
|
|
460
468
|
self.control_center_ui.show_all()
|
|
461
469
|
self._smart_pause_hid = False
|
|
462
470
|
|
|
471
|
+
def _on_sharing_changed(self, sharing: bool, match: str) -> None:
|
|
472
|
+
"""
|
|
473
|
+
偵測到會議程式開著/關掉時,自動把覆蓋層藏出擷取結果或放回去。
|
|
474
|
+
遮蔽用的覆蓋層不受影響——它們本來就是要被看到的。
|
|
475
|
+
Hide the overlays from the capture when a meeting app appears, and put
|
|
476
|
+
them back when it goes. Masking overlays are left alone: being seen is
|
|
477
|
+
the whole point of them.
|
|
478
|
+
"""
|
|
479
|
+
front_engine_logger.info(
|
|
480
|
+
f"[MainUI] screen sharing={sharing}" + (f" | {match}" if match else ""))
|
|
481
|
+
self.control_center_ui.set_hide_from_capture(sharing)
|
|
482
|
+
if sharing:
|
|
483
|
+
self._last_toast = show_toast(
|
|
484
|
+
language_wrapper.language_word_dict.get(
|
|
485
|
+
"screen_privacy_toast", "Overlays hidden from screen capture"))
|
|
486
|
+
|
|
463
487
|
def _show_reminder(self, label: str) -> None:
|
|
464
488
|
"""提醒到期:在畫面上方顯示一張會自己消失的提示卡。"""
|
|
465
489
|
front_engine_logger.info(f"[MainUI] reminder | {label}")
|
|
@@ -526,6 +550,8 @@ class FrontEngineMainUI(QMainWindow):
|
|
|
526
550
|
self.tools_setting_ui.stop_camera()
|
|
527
551
|
if getattr(self, "stream_setting_ui", None) is not None:
|
|
528
552
|
self.stream_setting_ui.soundboard.stop_all()
|
|
553
|
+
if getattr(self, "share_watch_service", None) is not None:
|
|
554
|
+
self.share_watch_service.stop()
|
|
529
555
|
if getattr(self, "reminder_service", None) is not None:
|
|
530
556
|
self.reminder_service.stop()
|
|
531
557
|
if getattr(self, "app_profile_service", None) is not None:
|
|
@@ -10,6 +10,7 @@ from frontengine.ui.dialog.app_profile_dialog import AppProfileDialog
|
|
|
10
10
|
from frontengine.ui.dialog.clipboard_dialog import ClipboardDialog
|
|
11
11
|
from frontengine.ui.dialog.hotkey_settings_dialog import HotkeySettingsDialog
|
|
12
12
|
from frontengine.ui.dialog.reminder_dialog import ReminderDialog
|
|
13
|
+
from frontengine.ui.dialog.screen_privacy_dialog import ScreenPrivacyDialog
|
|
13
14
|
from frontengine.ui.dialog.smart_pause_dialog import SmartPauseDialog
|
|
14
15
|
from frontengine.ui.dialog.usage_report_dialog import UsageReportDialog
|
|
15
16
|
from frontengine.user_setting.user_setting_file import (
|
|
@@ -87,6 +88,12 @@ def build_settings_menu(ui: "FrontEngineMainUI") -> None:
|
|
|
87
88
|
menu.addAction(reminder_action)
|
|
88
89
|
ui.reminder_action = reminder_action
|
|
89
90
|
|
|
91
|
+
privacy_action = QAction(
|
|
92
|
+
_t("settings_menu_screen_privacy", "Screen-sharing privacy..."), menu)
|
|
93
|
+
privacy_action.triggered.connect(lambda: _open_dialog(ui, ScreenPrivacyDialog))
|
|
94
|
+
menu.addAction(privacy_action)
|
|
95
|
+
ui.screen_privacy_action = privacy_action
|
|
96
|
+
|
|
90
97
|
usage_action = QAction(_t("settings_menu_usage", "Screen time..."), menu)
|
|
91
98
|
usage_action.triggered.connect(lambda: _open_usage_dialog(ui))
|
|
92
99
|
menu.addAction(usage_action)
|
{frontengine-1.0.44 → frontengine-1.0.46}/frontengine/ui/page/control_center/control_center_ui.py
RENAMED
|
@@ -16,6 +16,7 @@ from frontengine.ui.page.web.web_setting_ui import WEBSettingUI
|
|
|
16
16
|
from frontengine.user_setting.user_setting_file import clear_overlay_geometry
|
|
17
17
|
from frontengine.utils.logging.loggin_instance import front_engine_logger
|
|
18
18
|
from frontengine.utils.multi_language.language_wrapper import language_wrapper
|
|
19
|
+
from frontengine.utils.screen_privacy import capture_affinity
|
|
19
20
|
from frontengine.utils.power_mode.power_mode import (
|
|
20
21
|
TIER_BALANCED, TIER_HIGH, TIER_SAVER, normalize_tier,
|
|
21
22
|
)
|
|
@@ -94,6 +95,10 @@ class ControlCenterUI(QWidget):
|
|
|
94
95
|
self._extra_overlay_sources: list = []
|
|
95
96
|
self.low_power_button = self._create_button(
|
|
96
97
|
"control_center_low_power_on", self.toggle_low_power)
|
|
98
|
+
self._hidden_from_capture = False
|
|
99
|
+
self.capture_button = self._create_button(
|
|
100
|
+
"control_center_hide_from_capture", self.toggle_hide_from_capture)
|
|
101
|
+
self.capture_button.setEnabled(capture_affinity.available())
|
|
97
102
|
self.clear_all_button = self._create_button("control_center_close_all", self.clear_all)
|
|
98
103
|
|
|
99
104
|
# 畫質檔位:比省電模式更細,一次套用到所有覆蓋層
|
|
@@ -135,8 +140,9 @@ class ControlCenterUI(QWidget):
|
|
|
135
140
|
self.grid_layout.addWidget(self.low_power_button, 13, 0)
|
|
136
141
|
self.grid_layout.addWidget(self.quality_label, 14, 0)
|
|
137
142
|
self.grid_layout.addWidget(self.quality_combobox, 15, 0)
|
|
138
|
-
self.grid_layout.addWidget(self.
|
|
139
|
-
self.grid_layout.addWidget(self.
|
|
143
|
+
self.grid_layout.addWidget(self.capture_button, 16, 0)
|
|
144
|
+
self.grid_layout.addWidget(self.clear_all_button, 17, 0)
|
|
145
|
+
self.grid_layout.addWidget(self.log_panel_scroll_area, 0, 1, 18, 1) # rowSpan covers every button
|
|
140
146
|
self.setLayout(self.grid_layout)
|
|
141
147
|
|
|
142
148
|
# Redirect
|
|
@@ -353,6 +359,43 @@ class ControlCenterUI(QWidget):
|
|
|
353
359
|
)
|
|
354
360
|
)
|
|
355
361
|
|
|
362
|
+
def set_hide_from_capture(self, hidden: bool) -> int:
|
|
363
|
+
"""
|
|
364
|
+
分享畫面時把覆蓋層藏起來(自己看得到、對方看不到)。標了
|
|
365
|
+
keep_in_capture 的覆蓋層不會被藏——遮蔽層本來就是要被看到的。
|
|
366
|
+
Hide the overlays from screen capture: still visible here, blank for the
|
|
367
|
+
people you are sharing with. Overlays marked keep_in_capture are left
|
|
368
|
+
alone, since a mask is meant to be seen.
|
|
369
|
+
"""
|
|
370
|
+
self._hidden_from_capture = bool(hidden)
|
|
371
|
+
applied = 0
|
|
372
|
+
|
|
373
|
+
def apply(widget) -> None:
|
|
374
|
+
nonlocal applied
|
|
375
|
+
if getattr(widget, "keep_in_capture", False):
|
|
376
|
+
capture_affinity.apply_to_widget(widget, False)
|
|
377
|
+
return
|
|
378
|
+
if capture_affinity.apply_to_widget(widget, self._hidden_from_capture):
|
|
379
|
+
applied += 1
|
|
380
|
+
|
|
381
|
+
self._for_each_overlay(apply)
|
|
382
|
+
front_engine_logger.info(
|
|
383
|
+
f"ControlCenterUI set_hide_from_capture | hidden={hidden}, applied={applied}")
|
|
384
|
+
self.capture_button.setText(
|
|
385
|
+
language_wrapper.language_word_dict.get(
|
|
386
|
+
"control_center_show_in_capture" if self._hidden_from_capture
|
|
387
|
+
else "control_center_hide_from_capture",
|
|
388
|
+
"Show in capture" if self._hidden_from_capture else "Hide from capture"))
|
|
389
|
+
return applied
|
|
390
|
+
|
|
391
|
+
def toggle_hide_from_capture(self) -> None:
|
|
392
|
+
"""切換分享時是否隱藏覆蓋層。"""
|
|
393
|
+
self.set_hide_from_capture(not self._hidden_from_capture)
|
|
394
|
+
|
|
395
|
+
@property
|
|
396
|
+
def hidden_from_capture(self) -> bool:
|
|
397
|
+
return self._hidden_from_capture
|
|
398
|
+
|
|
356
399
|
def toggle_low_power(self) -> None:
|
|
357
400
|
"""切換省電模式 / Toggle low-power mode."""
|
|
358
401
|
self.set_low_power(not getattr(self, "_low_power", False))
|
|
@@ -54,6 +54,9 @@ user_setting_dict: Dict[str, Any] = {
|
|
|
54
54
|
# Sticky note contents and positions, and whether to reopen them on launch.
|
|
55
55
|
"sticky_notes": [],
|
|
56
56
|
"sticky_notes_restore": False,
|
|
57
|
+
# 分享畫面時自動把覆蓋層藏出擷取結果(預設關閉)
|
|
58
|
+
# Hide overlays from the capture while sharing; off by default.
|
|
59
|
+
"screen_share_privacy": {"enabled": False, "apps": []},
|
|
57
60
|
# 使用時間統計(只寫本機檔案、預設關閉)
|
|
58
61
|
# Usage tracking: local file only, off by default.
|
|
59
62
|
"usage_tracking": False,
|
|
@@ -542,4 +542,13 @@ english_word_dict = {
|
|
|
542
542
|
"stream_obs_record": 'Toggle recording',
|
|
543
543
|
"stream_obs_stream": 'Toggle streaming',
|
|
544
544
|
"stream_hint": 'The crosshair is only drawn on top - no game is modified. OBS control uses its own WebSocket; the password is kept in your local settings.',
|
|
545
|
+
"control_center_hide_from_capture": 'Hide from capture',
|
|
546
|
+
"control_center_show_in_capture": 'Show in capture',
|
|
547
|
+
"settings_menu_screen_privacy": 'Screen-sharing privacy...',
|
|
548
|
+
"screen_privacy_title": 'Screen-sharing privacy',
|
|
549
|
+
"screen_privacy_enable": 'Hide overlays while one of these apps is open',
|
|
550
|
+
"screen_privacy_apps_label": 'Meeting and capture apps:',
|
|
551
|
+
"screen_privacy_hint": 'Matched against window titles, so a meeting held in a browser tab is caught too. Your overlays stay on your own screen - only the capture is blank. Masks stay visible, since covering something is what they are for.',
|
|
552
|
+
"screen_privacy_unsupported": 'Hiding overlays from screen capture is Windows only.',
|
|
553
|
+
"screen_privacy_toast": 'Overlays hidden from screen capture',
|
|
545
554
|
}
|
{frontengine-1.0.44 → frontengine-1.0.46}/frontengine/utils/multi_language/traditional_chinese.py
RENAMED
|
@@ -541,4 +541,13 @@ traditional_chinese_word_dict = {
|
|
|
541
541
|
"stream_obs_record": '切換錄影',
|
|
542
542
|
"stream_obs_stream": '切換直播',
|
|
543
543
|
"stream_hint": '準星只是疊在畫面上的一層,不會更動任何遊戲。OBS 控制走它自己的 WebSocket,密碼只留在本機設定檔裡。',
|
|
544
|
+
"control_center_hide_from_capture": '分享時隱藏',
|
|
545
|
+
"control_center_show_in_capture": '分享時顯示',
|
|
546
|
+
"settings_menu_screen_privacy": '螢幕分享隱私…',
|
|
547
|
+
"screen_privacy_title": '螢幕分享隱私',
|
|
548
|
+
"screen_privacy_enable": '這些程式開著時,把覆蓋層藏出擷取畫面',
|
|
549
|
+
"screen_privacy_apps_label": '會議與擷取程式:',
|
|
550
|
+
"screen_privacy_hint": '比對的是視窗標題,所以在瀏覽器分頁裡開的會議也抓得到。覆蓋層仍會顯示在你自己的螢幕上,只有擷取畫面那一份是空的。遮蔽層不會被藏起來——遮住東西正是它存在的理由。',
|
|
551
|
+
"screen_privacy_unsupported": '把覆蓋層藏出螢幕擷取僅支援 Windows。',
|
|
552
|
+
"screen_privacy_toast": '已把覆蓋層藏出螢幕擷取',
|
|
544
553
|
}
|