pytron-kit 0.3.12__py3-none-win_amd64.whl
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.
- pytron/__init__.py +112 -0
- pytron/application.py +562 -0
- pytron/apputils/__init__.py +0 -0
- pytron/apputils/chrome_ipc.py +203 -0
- pytron/apputils/codegen.py +261 -0
- pytron/apputils/config.py +303 -0
- pytron/apputils/deadmansswitch.py +47 -0
- pytron/apputils/extras.py +76 -0
- pytron/apputils/native.py +148 -0
- pytron/apputils/shell.py +73 -0
- pytron/apputils/windows.py +286 -0
- pytron/cli.py +384 -0
- pytron/commands/__init__.py +0 -0
- pytron/commands/android.py +28 -0
- pytron/commands/build.py +26 -0
- pytron/commands/doctor.py +221 -0
- pytron/commands/engine.py +23 -0
- pytron/commands/frontend.py +60 -0
- pytron/commands/harvest.py +112 -0
- pytron/commands/helpers.py +239 -0
- pytron/commands/info.py +50 -0
- pytron/commands/init.py +521 -0
- pytron/commands/install.py +294 -0
- pytron/commands/login.py +130 -0
- pytron/commands/package.py +228 -0
- pytron/commands/plugin.py +442 -0
- pytron/commands/run.py +312 -0
- pytron/commands/scan.py +210 -0
- pytron/commands/show.py +23 -0
- pytron/commands/uninstall.py +150 -0
- pytron/commands/utils.py +42 -0
- pytron/commands/workflow.py +95 -0
- pytron/console.py +133 -0
- pytron/core.py +18 -0
- pytron/dependencies/WebView2Loader.dll +0 -0
- pytron/dependencies/__init__.py +1 -0
- pytron/dependencies/pytron_native.pyd +0 -0
- pytron/engines/chrome/adapter.py +445 -0
- pytron/engines/chrome/engine.py +576 -0
- pytron/engines/chrome/forge.py +147 -0
- pytron/engines/chrome/shell/package.json +8 -0
- pytron/engines/chrome/shell/preload.js +12 -0
- pytron/engines/chrome/shell/shell.js +534 -0
- pytron/exceptions.py +36 -0
- pytron/inspector.py +201 -0
- pytron/inspector_ui.py +512 -0
- pytron/installer/Installation.nsi +236 -0
- pytron/installer/header.bmp +0 -0
- pytron/installer/pytron.ico +0 -0
- pytron/installer/sidebar.bmp +0 -0
- pytron/llms.md +98 -0
- pytron/manifests/README.md +29 -0
- pytron/manifests/windows-utf8.manifest +44 -0
- pytron/menu.py +128 -0
- pytron/nsis-setup.exe +0 -0
- pytron/pack/__init__.py +0 -0
- pytron/pack/assets.py +131 -0
- pytron/pack/compilers.py +289 -0
- pytron/pack/crystal.py +297 -0
- pytron/pack/graph.py +377 -0
- pytron/pack/inference.py +157 -0
- pytron/pack/installers.py +402 -0
- pytron/pack/introspect.py +357 -0
- pytron/pack/metadata.py +213 -0
- pytron/pack/modules.py +618 -0
- pytron/pack/nuitka.py +108 -0
- pytron/pack/pipeline.py +107 -0
- pytron/pack/pyinstaller.py +176 -0
- pytron/pack/rust_engine.py +273 -0
- pytron/pack/secure.py +309 -0
- pytron/pack/secure_loader/bin/pytron_rust_bootloader.exe +0 -0
- pytron/pack/secure_loader/icon.ico +0 -0
- pytron/pack/utils.py +110 -0
- pytron/pack/virtual_root.py +124 -0
- pytron/platforms/__init__.py +0 -0
- pytron/platforms/android/__init__.py +3 -0
- pytron/platforms/android/android.py +103 -0
- pytron/platforms/android/builder.py +736 -0
- pytron/platforms/android/ops/build.py +79 -0
- pytron/platforms/android/ops/init.py +63 -0
- pytron/platforms/android/ops/run.py +79 -0
- pytron/platforms/android/ops/sync.py +770 -0
- pytron/platforms/android/ops/utils.py +8 -0
- pytron/platforms/android/shell/README.md +30 -0
- pytron/platforms/android/shell/app/build.gradle +64 -0
- pytron/platforms/android/shell/app/src/main/AndroidManifest.xml +29 -0
- pytron/platforms/android/shell/app/src/main/assets/python/main.py +86 -0
- pytron/platforms/android/shell/app/src/main/assets/python/python314.zip +0 -0
- pytron/platforms/android/shell/app/src/main/cpp/CMakeLists.txt +25 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/Python.h +155 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/abstract.h +915 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/audit.h +30 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/bltinmodule.h +14 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/boolobject.h +54 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/bytearrayobject.h +44 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/bytesobject.h +66 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/ceval.h +145 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/codecs.h +176 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/compile.h +22 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/complexobject.h +30 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/abstract.h +104 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/audit.h +8 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/bytearrayobject.h +38 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/bytesobject.h +42 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/cellobject.h +50 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/ceval.h +43 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/classobject.h +71 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/code.h +340 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/compile.h +50 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/complexobject.h +33 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/context.h +107 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/critical_section.h +154 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/descrobject.h +62 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/dictobject.h +105 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/fileobject.h +16 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/fileutils.h +16 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/floatobject.h +27 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/frameobject.h +35 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/funcobject.h +185 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/genobject.h +56 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/import.h +30 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/initconfig.h +334 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/listobject.h +53 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/lock.h +74 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/longintrepr.h +184 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/longobject.h +89 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/memoryobject.h +50 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/methodobject.h +66 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/modsupport.h +26 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/monitoring.h +269 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/object.h +493 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/objimpl.h +104 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/odictobject.h +43 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/picklebufobject.h +31 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pthread_stubs.h +105 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pyatomic.h +614 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pyatomic_gcc.h +615 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pyatomic_msc.h +1197 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pyatomic_std.h +1112 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pyctype.h +39 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pydebug.h +38 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pyerrors.h +132 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pyfpe.h +15 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pyframe.h +45 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pyhash.h +54 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pylifecycle.h +89 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pymem.h +84 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pystate.h +275 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pystats.h +194 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pythonrun.h +96 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pythread.h +43 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/pytime.h +27 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/setobject.h +71 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/traceback.h +13 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/tracemalloc.h +32 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/tupleobject.h +40 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/unicodeobject.h +773 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/warnings.h +20 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/cpython/weakrefobject.h +66 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/critical_section.h +16 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/datetime.h +267 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/descrobject.h +100 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/dictobject.h +108 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/dynamic_annotations.h +499 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/enumobject.h +17 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/errcode.h +45 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/exports.h +105 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/fileobject.h +41 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/fileutils.h +62 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/floatobject.h +54 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/frameobject.h +20 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/genericaliasobject.h +14 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/import.h +103 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/mimalloc/mimalloc/atomic.h +392 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/mimalloc/mimalloc/internal.h +969 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/mimalloc/mimalloc/prim.h +329 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/mimalloc/mimalloc/track.h +147 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/mimalloc/mimalloc/types.h +721 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/mimalloc/mimalloc.h +565 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_abstract.h +61 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_asdl.h +112 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_ast.h +945 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_ast_state.h +271 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_atexit.h +31 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_audit.h +35 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_backoff.h +133 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_bitutils.h +186 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_blocks_output_buffer.h +321 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_brc.h +73 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_bytes_methods.h +82 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_bytesobject.h +149 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_c_array.h +39 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_call.h +206 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_capsule.h +17 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_cell.h +75 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_ceval.h +390 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_ceval_state.h +48 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_code.h +671 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_codecs.h +76 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_compile.h +230 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_complexobject.h +34 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_condvar.h +93 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_context.h +59 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_critical_section.h +237 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_crossinterp.h +406 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_crossinterp_data_registry.h +41 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_debug_offsets.h +379 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_descrobject.h +28 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_dict.h +410 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_dict_state.h +28 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_dtoa.h +40 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_emscripten_signal.h +30 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_emscripten_trampoline.h +70 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_exceptions.h +40 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_faulthandler.h +100 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_fileutils.h +320 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_fileutils_windows.h +98 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_floatobject.h +49 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_flowgraph.h +47 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_format.h +27 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_frame.h +61 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_freelist.h +111 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_freelist_state.h +70 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_function.h +53 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_gc.h +378 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_genobject.h +43 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_getopt.h +22 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_gil.h +66 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_global_objects.h +34 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_global_objects_fini_generated.h +1592 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_global_strings.h +854 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_hamt.h +113 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_hashtable.h +150 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_import.h +141 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_importdl.h +139 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_index_pool.h +36 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_initconfig.h +197 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_instruction_sequence.h +83 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_instruments.h +127 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_interp.h +109 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_interp_structs.h +977 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_interpframe.h +401 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_interpframe_structs.h +95 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_interpolation.h +26 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_intrinsics.h +51 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_jit.h +29 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_list.h +81 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_llist.h +106 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_lock.h +236 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_long.h +319 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_magic_number.h +305 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_memoryobject.h +20 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_mimalloc.h +69 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_modsupport.h +99 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_moduleobject.h +62 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_namespace.h +21 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_object.h +1029 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_object_alloc.h +71 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_object_deferred.h +32 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_object_stack.h +95 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_object_state.h +49 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_obmalloc.h +702 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_obmalloc_init.h +66 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_opcode_metadata.h +2117 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_opcode_utils.h +90 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_optimizer.h +318 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_parking_lot.h +97 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_parser.h +78 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pathconfig.h +26 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pyarena.h +68 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pyatomic_ft_wrappers.h +174 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pybuffer.h +21 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pyerrors.h +213 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pyhash.h +91 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pylifecycle.h +136 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pymath.h +205 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pymem.h +145 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pymem_init.h +103 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pystate.h +339 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pystats.h +21 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pythonrun.h +68 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_pythread.h +172 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_qsbr.h +172 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_range.h +21 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_runtime.h +63 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_runtime_init.h +239 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_runtime_init_generated.h +1589 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_runtime_structs.h +310 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_semaphore.h +67 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_setobject.h +41 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_signal.h +108 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_sliceobject.h +20 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_stackref.h +791 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_stats.h +97 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_strhex.h +39 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_structs.h +88 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_structseq.h +40 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_symtable.h +201 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_sysmodule.h +32 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_template.h +26 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_time.h +334 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_token.h +110 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_traceback.h +111 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_tracemalloc.h +164 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_tstate.h +88 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_tuple.h +75 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_typedefs.h +18 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_typeobject.h +155 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_typevarobject.h +28 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_ucnhash.h +36 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_unicodeobject.h +308 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_unicodeobject_generated.h +3132 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_unionobject.h +26 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_uniqueid.h +57 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_uop_ids.h +335 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_uop_metadata.h +1204 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_warnings.h +21 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/internal/pycore_weakref.h +133 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/intrcheck.h +23 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/iterobject.h +24 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/listobject.h +55 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/lock.h +16 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/longobject.h +178 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/marshal.h +31 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/memoryobject.h +34 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/methodobject.h +146 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/modsupport.h +146 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/moduleobject.h +122 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/monitoring.h +18 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/object.h +828 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/objimpl.h +211 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/opcode.h +43 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/opcode_ids.h +259 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/osdefs.h +57 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/osmodule.h +17 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/patchlevel.h +49 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/py_curses.h +117 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pyatomic.h +16 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pybuffer.h +145 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pycapsule.h +58 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pyconfig.h +2088 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pydtrace.h +59 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pyerrors.h +335 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pyexpat.h +62 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pyframe.h +26 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pyhash.h +59 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pylifecycle.h +80 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pymacconfig.h +91 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pymacro.h +243 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pymath.h +65 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pymem.h +110 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pyport.h +710 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pystate.h +132 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pystats.h +28 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pystrcmp.h +23 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pystrtod.h +37 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pythonrun.h +42 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pythread.h +131 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/pytypedefs.h +30 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/rangeobject.h +27 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/refcount.h +555 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/setobject.h +49 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/sliceobject.h +69 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/structmember.h +56 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/structseq.h +46 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/sysmodule.h +27 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/traceback.h +26 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/tupleobject.h +46 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/typeslots.h +96 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/unicodeobject.h +1029 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/warnings.h +45 -0
- pytron/platforms/android/shell/app/src/main/cpp/include/weakrefobject.h +46 -0
- pytron/platforms/android/shell/app/src/main/cpp/pytron_bridge.cpp +224 -0
- pytron/platforms/android/shell/app/src/main/java/com/pytron/shell/MainActivity.kt +208 -0
- pytron/platforms/android/shell/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- pytron/platforms/android/shell/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- pytron/platforms/android/shell/build.gradle +11 -0
- pytron/platforms/android/shell/gradle/wrapper/gradle-wrapper.jar +0 -0
- pytron/platforms/android/shell/gradle/wrapper/gradle-wrapper.properties +5 -0
- pytron/platforms/android/shell/gradle.properties +2 -0
- pytron/platforms/android/shell/gradlew.bat +85 -0
- pytron/platforms/android/shell/settings.gradle +16 -0
- pytron/platforms/darwin.py +82 -0
- pytron/platforms/darwin_ops/libs.py +31 -0
- pytron/platforms/darwin_ops/system.py +182 -0
- pytron/platforms/darwin_ops/utils.py +85 -0
- pytron/platforms/darwin_ops/webview.py +5 -0
- pytron/platforms/darwin_ops/window.py +102 -0
- pytron/platforms/interface.py +152 -0
- pytron/platforms/linux.py +82 -0
- pytron/platforms/linux_ops/libs.py +49 -0
- pytron/platforms/linux_ops/system.py +316 -0
- pytron/platforms/linux_ops/utils.py +19 -0
- pytron/platforms/linux_ops/webview.py +5 -0
- pytron/platforms/linux_ops/window.py +115 -0
- pytron/platforms/windows.py +136 -0
- pytron/platforms/windows_ops/__init__.py +0 -0
- pytron/platforms/windows_ops/constants.py +126 -0
- pytron/platforms/windows_ops/system.py +518 -0
- pytron/platforms/windows_ops/utils.py +3 -0
- pytron/platforms/windows_ops/webview.py +5 -0
- pytron/platforms/windows_ops/window.py +361 -0
- pytron/plugin.py +467 -0
- pytron/rcedit-x64.exe +0 -0
- pytron/router.py +146 -0
- pytron/serializer.py +240 -0
- pytron/shortcuts.py +279 -0
- pytron/state.py +76 -0
- pytron/tray.py +399 -0
- pytron/updater.py +181 -0
- pytron/utf8_hook.py +112 -0
- pytron/utils.py +44 -0
- pytron/webview.py +722 -0
- pytron_kit-0.3.12.dist-info/METADATA +131 -0
- pytron_kit-0.3.12.dist-info/RECORD +419 -0
- pytron_kit-0.3.12.dist-info/WHEEL +5 -0
- pytron_kit-0.3.12.dist-info/entry_points.txt +2 -0
- pytron_kit-0.3.12.dist-info/licenses/LICENSE +201 -0
- pytron_kit-0.3.12.dist-info/top_level.txt +1 -0
pytron/webview.py
ADDED
|
@@ -0,0 +1,722 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import json
|
|
3
|
+
import time
|
|
4
|
+
import threading
|
|
5
|
+
import asyncio
|
|
6
|
+
import inspect
|
|
7
|
+
import pathlib
|
|
8
|
+
import platform
|
|
9
|
+
import mimetypes
|
|
10
|
+
import logging
|
|
11
|
+
import os
|
|
12
|
+
import base64
|
|
13
|
+
from collections import deque
|
|
14
|
+
|
|
15
|
+
# Import Native Engine
|
|
16
|
+
try:
|
|
17
|
+
from .dependencies import pytron_native
|
|
18
|
+
except ImportError:
|
|
19
|
+
# Fallback to check if it's in path
|
|
20
|
+
sys.path.append(os.path.join(os.path.dirname(__file__), "dependencies"))
|
|
21
|
+
try:
|
|
22
|
+
import pytron_native
|
|
23
|
+
except ImportError:
|
|
24
|
+
print("[CRITICAL] Could not load pytron_native engine.")
|
|
25
|
+
pytron_native = None
|
|
26
|
+
|
|
27
|
+
import urllib.parse
|
|
28
|
+
from .serializer import pytron_serialize
|
|
29
|
+
from .exceptions import ConfigError
|
|
30
|
+
|
|
31
|
+
IS_ANDROID = False
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# -------------------------------------------------------------------
|
|
35
|
+
# Browser wrapper (Native PyO3 Version)
|
|
36
|
+
# -------------------------------------------------------------------
|
|
37
|
+
class Webview:
|
|
38
|
+
def __init__(self, config):
|
|
39
|
+
if not pytron_native:
|
|
40
|
+
raise ImportError(
|
|
41
|
+
"Pytron Native Engine (pyd) is missing. Run build_engine.py."
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
self.config = config
|
|
45
|
+
self.logger = logging.getLogger("Pytron.Webview")
|
|
46
|
+
self.id = config.get("id") or str(int(time.time() * 1000))
|
|
47
|
+
|
|
48
|
+
# 1. Resolve Root
|
|
49
|
+
if getattr(sys, "frozen", False):
|
|
50
|
+
self._app_root = pathlib.Path(sys.executable).parent
|
|
51
|
+
if hasattr(sys, "_MEIPASS"):
|
|
52
|
+
self._app_root = pathlib.Path(sys._MEIPASS)
|
|
53
|
+
else:
|
|
54
|
+
self._app_root = pathlib.Path.cwd()
|
|
55
|
+
|
|
56
|
+
# 2. Performance Init
|
|
57
|
+
self.app = config.get("__app__")
|
|
58
|
+
if self.app:
|
|
59
|
+
self.thread_pool = self.app.thread_pool
|
|
60
|
+
else:
|
|
61
|
+
self.thread_pool = __import__(
|
|
62
|
+
"concurrent.futures"
|
|
63
|
+
).futures.ThreadPoolExecutor(max_workers=5)
|
|
64
|
+
|
|
65
|
+
self._bound_functions = {}
|
|
66
|
+
self._served_data = {}
|
|
67
|
+
|
|
68
|
+
# 3. Native Engine Initialization
|
|
69
|
+
# 3. Native Engine Initialization
|
|
70
|
+
# Logic to determine Root Path for Virtual Host (pytron://app/)
|
|
71
|
+
raw_url = config.get("url", "")
|
|
72
|
+
debug = config.get("debug", False)
|
|
73
|
+
|
|
74
|
+
root_path = str(self._app_root)
|
|
75
|
+
final_url = raw_url
|
|
76
|
+
|
|
77
|
+
# Check if URL looks like a local file path
|
|
78
|
+
if not raw_url.startswith(("http:", "https:", "pytron:")):
|
|
79
|
+
path_obj = pathlib.Path(raw_url)
|
|
80
|
+
if not path_obj.is_absolute():
|
|
81
|
+
path_obj = (self._app_root / path_obj).resolve()
|
|
82
|
+
|
|
83
|
+
if path_obj.exists():
|
|
84
|
+
# Valid local file found.
|
|
85
|
+
# Map its parent dir as the App Root.
|
|
86
|
+
root_path = str(path_obj.parent)
|
|
87
|
+
# URL becomes https://pytron.localhost/app/<filename>
|
|
88
|
+
final_url = (
|
|
89
|
+
f"https://pytron.localhost/app/{urllib.parse.quote(path_obj.name)}"
|
|
90
|
+
)
|
|
91
|
+
else:
|
|
92
|
+
# Fallback
|
|
93
|
+
root_path = str(path_obj.parent)
|
|
94
|
+
final_url = (
|
|
95
|
+
f"https://pytron.localhost/app/{urllib.parse.quote(path_obj.name)}"
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
self.root_path = root_path # Store for later navigations
|
|
99
|
+
self.logger.info(
|
|
100
|
+
f"Native Engine Init: URL={final_url}, VirtualRoot={root_path}"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
resizable = config.get("resizable", True)
|
|
104
|
+
frameless = config.get("frameless", False)
|
|
105
|
+
|
|
106
|
+
try:
|
|
107
|
+
# DELAYED NAVIGATION:
|
|
108
|
+
# We initialize with about:blank to ensure the window is created and
|
|
109
|
+
# bindings can be registered (via UserEvent::Bind) BEFORE the real app loads.
|
|
110
|
+
# This prevents race conditions where IPC calls happen before callbacks are ready.
|
|
111
|
+
self._start_url = final_url
|
|
112
|
+
self.native = pytron_native.NativeWebview(
|
|
113
|
+
debug,
|
|
114
|
+
"about:blank", # Start empty
|
|
115
|
+
root_path,
|
|
116
|
+
bool(resizable),
|
|
117
|
+
bool(frameless),
|
|
118
|
+
)
|
|
119
|
+
except TypeError:
|
|
120
|
+
# Fallback if pyd wasn't updated yet? No, we will rebuild.
|
|
121
|
+
raise ImportError("Native Engine signature mismatch. Please rebuild.")
|
|
122
|
+
|
|
123
|
+
# 4. Bindings
|
|
124
|
+
self._init_bindings()
|
|
125
|
+
|
|
126
|
+
# 5. Window Settings
|
|
127
|
+
self.set_title(config.get("title", "Pytron App"))
|
|
128
|
+
w, h = config.get("dimensions", [800, 600])
|
|
129
|
+
self.set_size(w, h)
|
|
130
|
+
|
|
131
|
+
# Apply strict window settings via Hacks/Bindings for properties not covered in Init
|
|
132
|
+
if config.get("always_on_top", False):
|
|
133
|
+
self.set_always_on_top(True)
|
|
134
|
+
|
|
135
|
+
if config.get("fullscreen", False):
|
|
136
|
+
self.set_fullscreen(True)
|
|
137
|
+
|
|
138
|
+
if config.get("start_maximized", False):
|
|
139
|
+
self.native.maximize()
|
|
140
|
+
|
|
141
|
+
if config.get("min_size") or config.get("max_size"):
|
|
142
|
+
self.logger.warning(
|
|
143
|
+
"Native Engine: min_size/max_size are not currently supported without rebuild. Ignoring."
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# 6. Platform Helpers (Windows)
|
|
147
|
+
self._platform = None
|
|
148
|
+
if platform.system() == "Windows":
|
|
149
|
+
try:
|
|
150
|
+
from .platforms.windows import WindowsImplementation
|
|
151
|
+
|
|
152
|
+
self._platform = WindowsImplementation()
|
|
153
|
+
except Exception as e:
|
|
154
|
+
self.logger.warning(f"Failed to load Windows Platform helpers: {e}")
|
|
155
|
+
|
|
156
|
+
if not config.get("start_hidden", False):
|
|
157
|
+
self.show()
|
|
158
|
+
|
|
159
|
+
# 7. Event Loop (Asyncio)
|
|
160
|
+
self.loop = asyncio.new_event_loop()
|
|
161
|
+
|
|
162
|
+
def start_loop():
|
|
163
|
+
asyncio.set_event_loop(self.loop)
|
|
164
|
+
self.loop.run_forever()
|
|
165
|
+
|
|
166
|
+
t = threading.Thread(target=start_loop, daemon=True)
|
|
167
|
+
t.start()
|
|
168
|
+
|
|
169
|
+
# 8. JS Init (Legacy shim)
|
|
170
|
+
init_js = f"""
|
|
171
|
+
(function() {{
|
|
172
|
+
window.pytron = window.pytron || {{}};
|
|
173
|
+
window.pytron.is_ready = true;
|
|
174
|
+
window.pytron.id = "{self.id}";
|
|
175
|
+
}})();
|
|
176
|
+
"""
|
|
177
|
+
self.eval(init_js)
|
|
178
|
+
|
|
179
|
+
# Apply UI settings (Context Menu, BG) for initial load
|
|
180
|
+
self._apply_ui_settings()
|
|
181
|
+
|
|
182
|
+
def start(self):
|
|
183
|
+
self.logger.info("Starting Native Event Loop...")
|
|
184
|
+
|
|
185
|
+
# Register Native Event Handlers (Direct Binding)
|
|
186
|
+
self.native.bind("pytron_on_close", self._on_close_requested)
|
|
187
|
+
self.native.bind("pytron_tray_click", self._on_tray_click)
|
|
188
|
+
|
|
189
|
+
# Configure Close Behavior
|
|
190
|
+
if self.config.get("close_to_tray", False):
|
|
191
|
+
self.logger.info("Enabling Close-to-Tray behavior.")
|
|
192
|
+
self.set_prevent_close(True)
|
|
193
|
+
|
|
194
|
+
# Trigger initial navigation now that bindings are (presumably) queued
|
|
195
|
+
if hasattr(self, "_start_url"):
|
|
196
|
+
self.logger.info(f"Navigating to start URL: {self._start_url}")
|
|
197
|
+
self.navigate(self._start_url)
|
|
198
|
+
|
|
199
|
+
self.native.run()
|
|
200
|
+
|
|
201
|
+
def _init_bindings(self):
|
|
202
|
+
# 1. CORE SYSTEM BINDINGS (Prefixed with pytron_ to avoid user collisions)
|
|
203
|
+
self.bind("pytron_set_title", self.set_title, run_in_thread=False)
|
|
204
|
+
self.bind("pytron_set_size", self.set_size, run_in_thread=False)
|
|
205
|
+
self.bind("pytron_close", self.close, run_in_thread=False)
|
|
206
|
+
self.bind("pytron_reload", self.reload, run_in_thread=False)
|
|
207
|
+
self.bind("pytron_toggle_maximize", self.toggle_maximize, run_in_thread=False)
|
|
208
|
+
self.bind("pytron_hide", self.hide, run_in_thread=False)
|
|
209
|
+
self.bind("pytron_show", self.show, run_in_thread=False)
|
|
210
|
+
self.bind("pytron_minimize", self.minimize, run_in_thread=False)
|
|
211
|
+
self.bind("pytron_maximize", self.maximize, run_in_thread=False)
|
|
212
|
+
self.bind("pytron_center", self.center, run_in_thread=False)
|
|
213
|
+
self.bind("pytron_sync_state", self._sync_state, run_in_thread=False)
|
|
214
|
+
self.bind("__pytron_vap_get", self._get_binary_asset, run_in_thread=True)
|
|
215
|
+
self.bind("pytron_serve_asset", self._serve_asset_callback, run_in_thread=False)
|
|
216
|
+
self.bind(
|
|
217
|
+
"pytron_set_slim_titlebar", self.set_slim_titlebar, run_in_thread=False
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
# 2. SYSTEM TOOLING / DIALOGS (Prefixed)
|
|
221
|
+
self.bind("pytron_dialog_open_file", self.dialog_open_file, run_in_thread=True)
|
|
222
|
+
self.bind("pytron_dialog_save_file", self.dialog_save_file, run_in_thread=True)
|
|
223
|
+
self.bind(
|
|
224
|
+
"pytron_dialog_open_folder", self.dialog_open_folder, run_in_thread=True
|
|
225
|
+
)
|
|
226
|
+
self.bind("pytron_message_box", self.message_box, run_in_thread=True)
|
|
227
|
+
self.bind(
|
|
228
|
+
"pytron_system_notification", self.system_notification, run_in_thread=True
|
|
229
|
+
)
|
|
230
|
+
self.bind(
|
|
231
|
+
"pytron_set_taskbar_progress", self.set_taskbar_progress, run_in_thread=True
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
# 3. CLEAN ALIASES (Convenience for JS users, but can be overwritten)
|
|
235
|
+
# Avoid logging for frequent state/asset syncs
|
|
236
|
+
self._spammy_methods = {
|
|
237
|
+
"pytron_sync_state",
|
|
238
|
+
"pytron_serve_asset",
|
|
239
|
+
"__pytron_vap_get",
|
|
240
|
+
}
|
|
241
|
+
self.bind("close", self.close, run_in_thread=False)
|
|
242
|
+
self.bind("hide", self.hide, run_in_thread=False)
|
|
243
|
+
self.bind("show", self.show, run_in_thread=False)
|
|
244
|
+
self.bind("minimize", self.minimize, run_in_thread=False)
|
|
245
|
+
self.bind("maximize", self.maximize, run_in_thread=False)
|
|
246
|
+
self.bind("center", self.center, run_in_thread=False)
|
|
247
|
+
self.bind("reload", self.reload, run_in_thread=False)
|
|
248
|
+
self.bind("toggle_maximize", self.toggle_maximize, run_in_thread=False)
|
|
249
|
+
self.bind("set_title", self.set_title, run_in_thread=False)
|
|
250
|
+
self.bind("set_size", self.set_size, run_in_thread=False)
|
|
251
|
+
self.bind("set_slim_titlebar", self.set_slim_titlebar, run_in_thread=False)
|
|
252
|
+
self.bind("dialog_open_file", self.dialog_open_file, run_in_thread=True)
|
|
253
|
+
self.bind("dialog_save_file", self.dialog_save_file, run_in_thread=True)
|
|
254
|
+
self.bind("dialog_open_folder", self.dialog_open_folder, run_in_thread=True)
|
|
255
|
+
self.bind("message_box", self.message_box, run_in_thread=True)
|
|
256
|
+
self.bind("system_notification", self.system_notification, run_in_thread=True)
|
|
257
|
+
self.bind("set_taskbar_progress", self.set_taskbar_progress, run_in_thread=True)
|
|
258
|
+
|
|
259
|
+
def _serve_asset_callback(self, key):
|
|
260
|
+
"""Called by Native Engine Protocol Handler to fetch VAP assets."""
|
|
261
|
+
if key in self._served_data:
|
|
262
|
+
data, mime = self._served_data[key]
|
|
263
|
+
return (data, mime)
|
|
264
|
+
return None
|
|
265
|
+
|
|
266
|
+
def set_slim_titlebar(self, enable=True):
|
|
267
|
+
if hasattr(self.native, "set_decorations"):
|
|
268
|
+
# enable slim -> disable decorations
|
|
269
|
+
self.native.set_decorations(not enable)
|
|
270
|
+
|
|
271
|
+
@property
|
|
272
|
+
def hwnd(self):
|
|
273
|
+
if hasattr(self.native, "get_hwnd"):
|
|
274
|
+
return self.native.get_hwnd()
|
|
275
|
+
return getattr(self, "_hwnd_cache", 0)
|
|
276
|
+
|
|
277
|
+
# ... Bindings Logic ... (omitted for brevity, assume existing)
|
|
278
|
+
def bind(self, name, python_func, run_in_thread=True, secure=False):
|
|
279
|
+
is_async = inspect.iscoroutinefunction(python_func)
|
|
280
|
+
|
|
281
|
+
# The Wrapper that Rust calls: (seq, args_json, ptr)
|
|
282
|
+
def _native_callback(seq, req, arg_ptr):
|
|
283
|
+
try:
|
|
284
|
+
args = json.loads(req) if req else []
|
|
285
|
+
except Exception:
|
|
286
|
+
args = []
|
|
287
|
+
|
|
288
|
+
# Internal logging
|
|
289
|
+
if not name.startswith("inspector_") and name not in self._spammy_methods:
|
|
290
|
+
self.logger.debug(f"IPC Call: {name}({args})")
|
|
291
|
+
|
|
292
|
+
# Result serializer
|
|
293
|
+
def _serialize_result(res):
|
|
294
|
+
return pytron_serialize(res, vap_provider=self.serve_data)
|
|
295
|
+
|
|
296
|
+
# Response Helper
|
|
297
|
+
def _respond(status, result):
|
|
298
|
+
res_str = json.dumps(result)
|
|
299
|
+
self.native.return_result(seq, status, res_str)
|
|
300
|
+
|
|
301
|
+
# Runner Logic
|
|
302
|
+
def _runner():
|
|
303
|
+
try:
|
|
304
|
+
res = python_func(*args)
|
|
305
|
+
_respond(0, _serialize_result(res))
|
|
306
|
+
except Exception as e:
|
|
307
|
+
self.logger.error(f"Error in {name}: {e}")
|
|
308
|
+
_respond(1, str(e))
|
|
309
|
+
|
|
310
|
+
async def _async_runner():
|
|
311
|
+
try:
|
|
312
|
+
res = await python_func(*args)
|
|
313
|
+
_respond(0, _serialize_result(res))
|
|
314
|
+
except Exception as e:
|
|
315
|
+
self.logger.error(f"Error in {name}: {e}")
|
|
316
|
+
_respond(1, str(e))
|
|
317
|
+
|
|
318
|
+
if is_async:
|
|
319
|
+
asyncio.run_coroutine_threadsafe(_async_runner(), self.loop)
|
|
320
|
+
else:
|
|
321
|
+
if run_in_thread:
|
|
322
|
+
self.thread_pool.submit(_runner)
|
|
323
|
+
else:
|
|
324
|
+
_runner()
|
|
325
|
+
|
|
326
|
+
# Register with Rust
|
|
327
|
+
self.native.bind(name, _native_callback)
|
|
328
|
+
|
|
329
|
+
# --- Core API ---
|
|
330
|
+
|
|
331
|
+
def navigate(self, url):
|
|
332
|
+
target = self._normalize_to_pytron(url)
|
|
333
|
+
self.config["url"] = target
|
|
334
|
+
self.native.navigate(target)
|
|
335
|
+
# Attempt to apply UI settings (Context Menu, BG) via JS for Native Engine
|
|
336
|
+
# Note: This might race with page load clearing scripts, but it's best effort.
|
|
337
|
+
self._apply_ui_settings()
|
|
338
|
+
|
|
339
|
+
def _normalize_to_pytron(self, url):
|
|
340
|
+
"""Ensures local file paths are converted to pytron://app/ URLs relative to root_path."""
|
|
341
|
+
if url.startswith(("http:", "https:", "pytron:")):
|
|
342
|
+
return url
|
|
343
|
+
|
|
344
|
+
path_obj = pathlib.Path(url)
|
|
345
|
+
if not path_obj.is_absolute():
|
|
346
|
+
# If relative, assuming relative to root_path or app_root?
|
|
347
|
+
# Usually relative to cwd.
|
|
348
|
+
path_obj = pathlib.Path.cwd() / path_obj
|
|
349
|
+
|
|
350
|
+
# Check if it resides within self.root_path
|
|
351
|
+
try:
|
|
352
|
+
root = pathlib.Path(self.root_path)
|
|
353
|
+
# relative_to throws ValueError if not relative
|
|
354
|
+
rel = path_obj.resolve().relative_to(root.resolve())
|
|
355
|
+
# Use forward slashes for URL
|
|
356
|
+
return f"https://pytron.localhost/app/{urllib.parse.quote(rel.as_posix())}"
|
|
357
|
+
except (ValueError, Exception):
|
|
358
|
+
# If outside root, we can't serve it via current pytron instance easily.
|
|
359
|
+
# But maybe the current logic allows it if we didn't lock protocol_root?
|
|
360
|
+
# (Native engine locks protocol_root).
|
|
361
|
+
self.logger.warning(
|
|
362
|
+
f"Navigate path {url} is outside protocol root {self.root_path}. Falling back to raw path (likely file://)."
|
|
363
|
+
)
|
|
364
|
+
return str(path_obj)
|
|
365
|
+
|
|
366
|
+
def serve_data(self, key, data, mime_type):
|
|
367
|
+
"""
|
|
368
|
+
Callback for serializing binary data used by plugins/VAP.
|
|
369
|
+
Stores the data in memory to be served via __pytron_vap_get.
|
|
370
|
+
"""
|
|
371
|
+
self._served_data[key] = (data, mime_type)
|
|
372
|
+
# Use HTTPS scheme for Windows/Native compatibility
|
|
373
|
+
return f"https://pytron.localhost/{key}"
|
|
374
|
+
|
|
375
|
+
def _apply_ui_settings(self):
|
|
376
|
+
"""Applies UI configuration via JavaScript injection."""
|
|
377
|
+
js = []
|
|
378
|
+
|
|
379
|
+
# 1. Background Color (Fallback for Native)
|
|
380
|
+
# bg = self.config.get("background_color")
|
|
381
|
+
# if bg:
|
|
382
|
+
# js.append(f"try {{ document.documentElement.style.backgroundColor = '{bg}'; document.body.style.backgroundColor = '{bg}'; }} catch(e) {{}}")
|
|
383
|
+
|
|
384
|
+
# 2. Context Menu
|
|
385
|
+
if self.config.get("default_context_menu") is False:
|
|
386
|
+
js.append(
|
|
387
|
+
"try { document.addEventListener('contextmenu', e => e.preventDefault()); } catch(e) {}"
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
if js:
|
|
391
|
+
# We use setTimeout to allow parsing to complete if called early
|
|
392
|
+
full_script = (
|
|
393
|
+
"(function(){ setTimeout(() => { " + " ".join(js) + " }, 100); })();"
|
|
394
|
+
)
|
|
395
|
+
self.eval(full_script)
|
|
396
|
+
|
|
397
|
+
def set_title(self, title):
|
|
398
|
+
self.native.set_title(title)
|
|
399
|
+
|
|
400
|
+
def set_size(self, w, h):
|
|
401
|
+
self.native.set_size(w, h, 0)
|
|
402
|
+
|
|
403
|
+
def eval(self, js):
|
|
404
|
+
self.native.eval(js)
|
|
405
|
+
|
|
406
|
+
def reload(self):
|
|
407
|
+
self.native.eval("location.reload()")
|
|
408
|
+
|
|
409
|
+
def close(self, force=False):
|
|
410
|
+
"""
|
|
411
|
+
Closes the window.
|
|
412
|
+
If 'close_to_tray' config is True and force is False, it just hides the window.
|
|
413
|
+
"""
|
|
414
|
+
if not force and self.config.get("close_to_tray", False):
|
|
415
|
+
self.hide()
|
|
416
|
+
# If we hide, we might want to notify or ensure tray exists?
|
|
417
|
+
# Assuming App deals with that.
|
|
418
|
+
return
|
|
419
|
+
|
|
420
|
+
self.native.terminate()
|
|
421
|
+
|
|
422
|
+
def emit(self, event, data=None):
|
|
423
|
+
"""
|
|
424
|
+
Emits a custom event to the frontend.
|
|
425
|
+
Frontend can listen via window.addEventListener(event, ...)
|
|
426
|
+
"""
|
|
427
|
+
import json
|
|
428
|
+
|
|
429
|
+
payload = json.dumps(data)
|
|
430
|
+
js = f"window.dispatchEvent(new CustomEvent('{event}', {{ detail: {payload} }}));"
|
|
431
|
+
self.eval(js)
|
|
432
|
+
|
|
433
|
+
# --- Asset Serving (VAP) ---
|
|
434
|
+
# serve_data is defined above to return the URL.
|
|
435
|
+
|
|
436
|
+
def _sync_state(self):
|
|
437
|
+
if self.app:
|
|
438
|
+
return self.app.state.to_dict()
|
|
439
|
+
return {}
|
|
440
|
+
|
|
441
|
+
# --- Path Normalizer ---
|
|
442
|
+
def normalize_path(self, config):
|
|
443
|
+
raw_url = config.get("url")
|
|
444
|
+
if not raw_url:
|
|
445
|
+
raise ConfigError("No URL Configured")
|
|
446
|
+
|
|
447
|
+
if raw_url.startswith(("http:", "https:", "pytron:")):
|
|
448
|
+
return
|
|
449
|
+
|
|
450
|
+
path_obj = pathlib.Path(raw_url)
|
|
451
|
+
if not path_obj.is_absolute():
|
|
452
|
+
path_obj = (self._app_root / path_obj).resolve()
|
|
453
|
+
|
|
454
|
+
# Convert to pytron://
|
|
455
|
+
# Use localhost as authority to prevent "Origin null" issues
|
|
456
|
+
config["url"] = path_obj.as_uri().replace("file:///", "pytron://localhost/")
|
|
457
|
+
|
|
458
|
+
# --- Native Mappings ---
|
|
459
|
+
def set_icon(self, icon_path):
|
|
460
|
+
if self._platform and self.hwnd:
|
|
461
|
+
self._platform.set_window_icon(self.hwnd, icon_path)
|
|
462
|
+
|
|
463
|
+
def minimize(self):
|
|
464
|
+
self.native.minimize()
|
|
465
|
+
|
|
466
|
+
def toggle_maximize(self):
|
|
467
|
+
# Native Toggle using HWND check because Native Engine is async state
|
|
468
|
+
if sys.platform == "win32" and self.hwnd:
|
|
469
|
+
import ctypes
|
|
470
|
+
|
|
471
|
+
is_maximized = ctypes.windll.user32.IsZoomed(self.hwnd)
|
|
472
|
+
if is_maximized:
|
|
473
|
+
self.restore()
|
|
474
|
+
else:
|
|
475
|
+
self.maximize()
|
|
476
|
+
else:
|
|
477
|
+
self.native.maximize()
|
|
478
|
+
|
|
479
|
+
def is_visible(self):
|
|
480
|
+
"""Checks if the window is currently visible."""
|
|
481
|
+
# Use simple platform check if possible
|
|
482
|
+
if sys.platform == "win32" and self.hwnd:
|
|
483
|
+
import ctypes
|
|
484
|
+
|
|
485
|
+
return bool(ctypes.windll.user32.IsWindowVisible(self.hwnd))
|
|
486
|
+
return True # Default fallback
|
|
487
|
+
|
|
488
|
+
def hide(self):
|
|
489
|
+
self.native.hide()
|
|
490
|
+
|
|
491
|
+
def start_drag(self):
|
|
492
|
+
self.native.start_drag()
|
|
493
|
+
|
|
494
|
+
def set_always_on_top(self, enable):
|
|
495
|
+
call_native = getattr(self.native, "set_always_on_top", None)
|
|
496
|
+
if call_native:
|
|
497
|
+
call_native(enable)
|
|
498
|
+
elif sys.platform == "win32" and self.hwnd:
|
|
499
|
+
import ctypes
|
|
500
|
+
|
|
501
|
+
HWND_TOPMOST = -1
|
|
502
|
+
HWND_NOTOPMOST = -2
|
|
503
|
+
SWP_NOMOVE = 0x0002
|
|
504
|
+
SWP_NOSIZE = 0x0001
|
|
505
|
+
z_order = HWND_TOPMOST if enable else HWND_NOTOPMOST
|
|
506
|
+
ctypes.windll.user32.SetWindowPos(
|
|
507
|
+
self.hwnd, z_order, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE
|
|
508
|
+
)
|
|
509
|
+
|
|
510
|
+
def set_resizable(self, enable):
|
|
511
|
+
call_native = getattr(self.native, "set_resizable", None)
|
|
512
|
+
if call_native:
|
|
513
|
+
call_native(enable)
|
|
514
|
+
|
|
515
|
+
def maximize(self):
|
|
516
|
+
self.native.maximize()
|
|
517
|
+
|
|
518
|
+
def unmaximize(self):
|
|
519
|
+
if hasattr(self.native, "unmaximize"):
|
|
520
|
+
self.native.unmaximize()
|
|
521
|
+
|
|
522
|
+
def restore(self):
|
|
523
|
+
self.unmaximize()
|
|
524
|
+
|
|
525
|
+
def show(self):
|
|
526
|
+
self.native.show()
|
|
527
|
+
|
|
528
|
+
def set_fullscreen(self, enable):
|
|
529
|
+
self.native.set_fullscreen(enable)
|
|
530
|
+
|
|
531
|
+
def center(self):
|
|
532
|
+
call_native = getattr(self.native, "center", None)
|
|
533
|
+
if call_native:
|
|
534
|
+
call_native()
|
|
535
|
+
elif self._platform and self.hwnd:
|
|
536
|
+
self._platform.center(self.hwnd)
|
|
537
|
+
|
|
538
|
+
# --- Dialogs ---
|
|
539
|
+
def dialog_open_file(self, *args, **kwargs):
|
|
540
|
+
# Native Engine Impl (preferred)
|
|
541
|
+
if hasattr(self.native, "dialog_open_file"):
|
|
542
|
+
# args mapping: title, default_path, file_types
|
|
543
|
+
# file_types in python: [("Images", "*.png;*.jpg"), ...]
|
|
544
|
+
# file_types in native: "Images:png,jpg;Text:txt"
|
|
545
|
+
|
|
546
|
+
title = kwargs.get("title") or (args[0] if args else "Open File")
|
|
547
|
+
default_path = kwargs.get("default_path") or (
|
|
548
|
+
args[1] if len(args) > 1 else None
|
|
549
|
+
)
|
|
550
|
+
file_types = kwargs.get("file_types") or (
|
|
551
|
+
args[2] if len(args) > 2 else None
|
|
552
|
+
)
|
|
553
|
+
|
|
554
|
+
filters_str = None
|
|
555
|
+
if file_types:
|
|
556
|
+
parts = []
|
|
557
|
+
for name_ft, pat in file_types:
|
|
558
|
+
# pat is like "*.png;*.jpg" -> "png,jpg"
|
|
559
|
+
exts = pat.replace("*.", "").replace(";", ",")
|
|
560
|
+
parts.append(f"{name_ft}:{exts}")
|
|
561
|
+
filters_str = ";".join(parts)
|
|
562
|
+
|
|
563
|
+
return self.native.dialog_open_file(title, default_path, filters_str)
|
|
564
|
+
|
|
565
|
+
if self._platform and self.hwnd:
|
|
566
|
+
return self._platform.open_file_dialog(self.hwnd, *args, **kwargs)
|
|
567
|
+
return []
|
|
568
|
+
|
|
569
|
+
def dialog_save_file(self, *args, **kwargs):
|
|
570
|
+
if hasattr(self.native, "dialog_save_file"):
|
|
571
|
+
title = kwargs.get("title", "Save File")
|
|
572
|
+
default_path = kwargs.get("default_path")
|
|
573
|
+
default_name = kwargs.get("default_name")
|
|
574
|
+
file_types = kwargs.get("file_types")
|
|
575
|
+
filters_str = None
|
|
576
|
+
if file_types:
|
|
577
|
+
parts = []
|
|
578
|
+
for name, pat in file_types:
|
|
579
|
+
exts = pat.replace("*.", "").replace(";", ",")
|
|
580
|
+
parts.append(f"{name}:{exts}")
|
|
581
|
+
filters_str = ";".join(parts)
|
|
582
|
+
|
|
583
|
+
return self.native.dialog_save_file(
|
|
584
|
+
title, default_path, default_name, filters_str
|
|
585
|
+
)
|
|
586
|
+
|
|
587
|
+
if self._platform and self.hwnd:
|
|
588
|
+
return self._platform.save_file_dialog(self.hwnd, *args, **kwargs)
|
|
589
|
+
return None
|
|
590
|
+
|
|
591
|
+
def dialog_open_folder(self, *args, **kwargs):
|
|
592
|
+
if hasattr(self.native, "dialog_open_folder"):
|
|
593
|
+
title = kwargs.get("title", "Select Folder")
|
|
594
|
+
default_path = kwargs.get("default_path")
|
|
595
|
+
return self.native.dialog_open_folder(title, default_path)
|
|
596
|
+
|
|
597
|
+
if self._platform and self.hwnd:
|
|
598
|
+
return self._platform.open_folder_dialog(self.hwnd, *args, **kwargs)
|
|
599
|
+
return None
|
|
600
|
+
|
|
601
|
+
def message_box(self, *args, **kwargs):
|
|
602
|
+
if hasattr(self.native, "message_box"):
|
|
603
|
+
title = kwargs.get("title") or (args[0] if args else "Message")
|
|
604
|
+
message = kwargs.get("message") or (args[1] if len(args) > 1 else "")
|
|
605
|
+
style = kwargs.get("style") or (args[2] if len(args) > 2 else 0)
|
|
606
|
+
|
|
607
|
+
# Map Windows MessageBox styles to Native levels
|
|
608
|
+
# 0x10 = MB_ICONERROR, 0x30 = MB_ICONWARNING, 0x40 = MB_ICONINFORMATION
|
|
609
|
+
level = "info"
|
|
610
|
+
if isinstance(style, int):
|
|
611
|
+
if style & 0x10:
|
|
612
|
+
level = "error"
|
|
613
|
+
elif style & 0x30:
|
|
614
|
+
level = "warning"
|
|
615
|
+
|
|
616
|
+
return self.native.message_box(title, message, level)
|
|
617
|
+
|
|
618
|
+
if self._platform and self.hwnd:
|
|
619
|
+
return self._platform.message_box(self.hwnd, *args, **kwargs)
|
|
620
|
+
return 0
|
|
621
|
+
|
|
622
|
+
def set_taskbar_progress(self, state="normal", value=0, max_value=100):
|
|
623
|
+
# State mapping: normal, error, paused, indeterminate, none
|
|
624
|
+
# Native Lib expects: 2=Normal, 4=Error, 8=Paused
|
|
625
|
+
|
|
626
|
+
# 1. Try Native Engine Implementation (if reliable) (Disabled until user confirms lib.rs update)
|
|
627
|
+
if hasattr(self.native, "set_taskbar_progress"):
|
|
628
|
+
s_map = {
|
|
629
|
+
"normal": 2,
|
|
630
|
+
"error": 4,
|
|
631
|
+
"paused": 8,
|
|
632
|
+
"indeterminate": 1,
|
|
633
|
+
"none": 0,
|
|
634
|
+
}
|
|
635
|
+
s_code = s_map.get(state, 0)
|
|
636
|
+
self.native.set_taskbar_progress(s_code, int(value), int(max_value))
|
|
637
|
+
return
|
|
638
|
+
|
|
639
|
+
# 2. Fallback to Platform Helper (needs valid HWND)
|
|
640
|
+
if self._platform and self.hwnd:
|
|
641
|
+
self._platform.set_taskbar_progress(self.hwnd, state, value, max_value)
|
|
642
|
+
|
|
643
|
+
def system_notification(self, title, message, icon=None):
|
|
644
|
+
if self._platform and self.hwnd:
|
|
645
|
+
if not icon:
|
|
646
|
+
icon = self.config.get("icon")
|
|
647
|
+
self._platform.notification(self.hwnd, title, message, icon)
|
|
648
|
+
|
|
649
|
+
# --- Native Tray & Close Handling ---
|
|
650
|
+
def create_tray(self, icon_path, tooltip="Pytron App"):
|
|
651
|
+
if hasattr(self.native, "create_tray"):
|
|
652
|
+
self.native.create_tray(icon_path, tooltip)
|
|
653
|
+
|
|
654
|
+
def set_prevent_close(self, prevent):
|
|
655
|
+
if hasattr(self.native, "set_prevent_close"):
|
|
656
|
+
self.native.set_prevent_close(prevent)
|
|
657
|
+
|
|
658
|
+
def _on_close_requested(self):
|
|
659
|
+
"""Called by Native Engine when X is clicked and prevent_close is True."""
|
|
660
|
+
if self.config.get("close_to_tray", False):
|
|
661
|
+
self.hide()
|
|
662
|
+
else:
|
|
663
|
+
# Should not happen if prevent_close logic is consistent, but fallback
|
|
664
|
+
self.native.terminate()
|
|
665
|
+
|
|
666
|
+
def _get_binary_asset(self, key):
|
|
667
|
+
"""
|
|
668
|
+
Retrieves an asset for the VAP bridge.
|
|
669
|
+
Returns {'raw': <binary_string>, 'mime': <mime_type>} or None.
|
|
670
|
+
"""
|
|
671
|
+
# 1. Check Memory Cache (_served_data)
|
|
672
|
+
if key in self._served_data:
|
|
673
|
+
data, mime = self._served_data[key]
|
|
674
|
+
# Convert bytes to "latin-1" string for JS binary interop
|
|
675
|
+
raw = data.decode("latin-1")
|
|
676
|
+
return {"raw": raw, "mime": mime}
|
|
677
|
+
|
|
678
|
+
# 2. Check File System (if key is a relative path)
|
|
679
|
+
try:
|
|
680
|
+
# Security: Prevent escaping root
|
|
681
|
+
possible_path = (self._app_root / key).resolve()
|
|
682
|
+
if (
|
|
683
|
+
str(possible_path).startswith(str(self._app_root))
|
|
684
|
+
and possible_path.exists()
|
|
685
|
+
and possible_path.is_file()
|
|
686
|
+
):
|
|
687
|
+
import mimetypes
|
|
688
|
+
|
|
689
|
+
mime, _ = mimetypes.guess_type(str(possible_path))
|
|
690
|
+
with open(possible_path, "rb") as f:
|
|
691
|
+
data = f.read()
|
|
692
|
+
raw = data.decode("latin-1")
|
|
693
|
+
return {"raw": raw, "mime": mime or "application/octet-stream"}
|
|
694
|
+
except Exception:
|
|
695
|
+
pass
|
|
696
|
+
|
|
697
|
+
return None
|
|
698
|
+
|
|
699
|
+
def _on_tray_click(self, menu_id):
|
|
700
|
+
"""Called by Native Engine when tray menu is clicked."""
|
|
701
|
+
self.logger.info(f"Tray Click: {menu_id}")
|
|
702
|
+
if str(menu_id) == "1001" or str(menu_id) == "Quit": # Approx
|
|
703
|
+
self.native.terminate()
|
|
704
|
+
elif str(menu_id) == "1000" or str(menu_id) == "Show": # Approx
|
|
705
|
+
self.show()
|
|
706
|
+
self.native.set_visible(True)
|
|
707
|
+
if sys.platform == "win32":
|
|
708
|
+
self.minimize() # Hack to restore? No, show() involves restore.
|
|
709
|
+
self.native.minimize()
|
|
710
|
+
self.native.show() # Force restore from minimize
|
|
711
|
+
|
|
712
|
+
# Redundant _init_bindings removed.
|
|
713
|
+
def expose(self, entity):
|
|
714
|
+
if callable(entity) and not isinstance(entity, type):
|
|
715
|
+
self.bind(entity.__name__, entity)
|
|
716
|
+
return entity
|
|
717
|
+
if isinstance(entity, type):
|
|
718
|
+
instance = entity()
|
|
719
|
+
for name in dir(instance):
|
|
720
|
+
if not name.startswith("_") and callable(getattr(instance, name)):
|
|
721
|
+
self.bind(name, getattr(instance, name))
|
|
722
|
+
return entity
|