pyglet 2.1.13__py3-none-any.whl → 3.0.dev1__py3-none-any.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.
- pyglet/__init__.py +67 -61
- pyglet/__init__.pyi +15 -8
- pyglet/app/__init__.py +22 -13
- pyglet/app/async_app.py +212 -0
- pyglet/app/base.py +2 -1
- pyglet/app/{xlib.py → linux.py} +3 -3
- pyglet/config/__init__.py +101 -0
- pyglet/config/gl/__init__.py +30 -0
- pyglet/config/gl/egl.py +120 -0
- pyglet/config/gl/macos.py +262 -0
- pyglet/config/gl/windows.py +267 -0
- pyglet/config/gl/x11.py +142 -0
- pyglet/customtypes.py +43 -2
- pyglet/display/__init__.py +8 -6
- pyglet/display/base.py +3 -63
- pyglet/display/cocoa.py +12 -17
- pyglet/display/emscripten.py +39 -0
- pyglet/display/headless.py +23 -30
- pyglet/display/wayland.py +157 -0
- pyglet/display/win32.py +5 -21
- pyglet/display/xlib.py +19 -27
- pyglet/display/xlib_vidmoderestore.py +2 -2
- pyglet/enums.py +183 -0
- pyglet/event.py +0 -1
- pyglet/experimental/geoshader_sprite.py +15 -13
- pyglet/experimental/hidraw.py +6 -15
- pyglet/experimental/multitexture_sprite.py +31 -19
- pyglet/experimental/particles.py +13 -35
- pyglet/font/__init__.py +251 -85
- pyglet/font/base.py +116 -61
- pyglet/font/dwrite/__init__.py +349 -204
- pyglet/font/dwrite/dwrite_lib.py +27 -5
- pyglet/font/fontconfig.py +14 -6
- pyglet/font/freetype.py +138 -87
- pyglet/font/freetype_lib.py +19 -0
- pyglet/font/group.py +179 -0
- pyglet/font/harfbuzz/__init__.py +3 -3
- pyglet/font/pyodide_js.py +310 -0
- pyglet/font/quartz.py +319 -126
- pyglet/font/ttf.py +45 -3
- pyglet/font/user.py +14 -19
- pyglet/font/win32.py +45 -21
- pyglet/graphics/__init__.py +8 -787
- pyglet/graphics/allocation.py +115 -1
- pyglet/graphics/api/__init__.py +77 -0
- pyglet/graphics/api/base.py +299 -0
- pyglet/graphics/api/gl/__init__.py +58 -0
- pyglet/graphics/api/gl/base.py +24 -0
- pyglet/graphics/{vertexbuffer.py → api/gl/buffer.py} +104 -159
- pyglet/graphics/api/gl/cocoa/context.py +76 -0
- pyglet/graphics/api/gl/context.py +391 -0
- pyglet/graphics/api/gl/default_shaders.py +0 -0
- pyglet/graphics/api/gl/draw.py +627 -0
- pyglet/graphics/api/gl/egl/__init__.py +0 -0
- pyglet/graphics/api/gl/egl/context.py +92 -0
- pyglet/graphics/api/gl/enums.py +76 -0
- pyglet/graphics/api/gl/framebuffer.py +315 -0
- pyglet/graphics/api/gl/gl.py +5463 -0
- pyglet/graphics/api/gl/gl_info.py +188 -0
- pyglet/graphics/api/gl/global_opengl.py +226 -0
- pyglet/{gl → graphics/api/gl}/lib.py +34 -18
- pyglet/graphics/api/gl/shader.py +1476 -0
- pyglet/graphics/api/gl/shapes.py +55 -0
- pyglet/graphics/api/gl/sprite.py +102 -0
- pyglet/graphics/api/gl/state.py +219 -0
- pyglet/graphics/api/gl/text.py +190 -0
- pyglet/graphics/api/gl/texture.py +1526 -0
- pyglet/graphics/{vertexarray.py → api/gl/vertexarray.py} +11 -13
- pyglet/graphics/api/gl/vertexdomain.py +751 -0
- pyglet/graphics/api/gl/win32/__init__.py +0 -0
- pyglet/graphics/api/gl/win32/context.py +108 -0
- pyglet/graphics/api/gl/win32/wgl_info.py +24 -0
- pyglet/graphics/api/gl/xlib/__init__.py +0 -0
- pyglet/graphics/api/gl/xlib/context.py +174 -0
- pyglet/{gl → graphics/api/gl/xlib}/glx_info.py +26 -31
- pyglet/graphics/api/gl1/__init__.py +0 -0
- pyglet/{gl → graphics/api/gl1}/gl_compat.py +3 -2
- pyglet/graphics/api/gl2/__init__.py +0 -0
- pyglet/graphics/api/gl2/buffer.py +320 -0
- pyglet/graphics/api/gl2/draw.py +600 -0
- pyglet/graphics/api/gl2/global_opengl.py +122 -0
- pyglet/graphics/api/gl2/shader.py +200 -0
- pyglet/graphics/api/gl2/shapes.py +51 -0
- pyglet/graphics/api/gl2/sprite.py +79 -0
- pyglet/graphics/api/gl2/text.py +175 -0
- pyglet/graphics/api/gl2/vertexdomain.py +364 -0
- pyglet/graphics/api/webgl/__init__.py +233 -0
- pyglet/graphics/api/webgl/buffer.py +302 -0
- pyglet/graphics/api/webgl/context.py +234 -0
- pyglet/graphics/api/webgl/draw.py +590 -0
- pyglet/graphics/api/webgl/enums.py +76 -0
- pyglet/graphics/api/webgl/framebuffer.py +360 -0
- pyglet/graphics/api/webgl/gl.py +1537 -0
- pyglet/graphics/api/webgl/gl_info.py +130 -0
- pyglet/graphics/api/webgl/shader.py +1346 -0
- pyglet/graphics/api/webgl/shapes.py +92 -0
- pyglet/graphics/api/webgl/sprite.py +102 -0
- pyglet/graphics/api/webgl/state.py +227 -0
- pyglet/graphics/api/webgl/text.py +187 -0
- pyglet/graphics/api/webgl/texture.py +1227 -0
- pyglet/graphics/api/webgl/vertexarray.py +54 -0
- pyglet/graphics/api/webgl/vertexdomain.py +616 -0
- pyglet/graphics/api/webgl/webgl_js.pyi +307 -0
- pyglet/{image → graphics}/atlas.py +33 -32
- pyglet/graphics/base.py +10 -0
- pyglet/graphics/buffer.py +245 -0
- pyglet/graphics/draw.py +578 -0
- pyglet/graphics/framebuffer.py +26 -0
- pyglet/graphics/instance.py +178 -69
- pyglet/graphics/shader.py +267 -1553
- pyglet/graphics/state.py +83 -0
- pyglet/graphics/texture.py +703 -0
- pyglet/graphics/vertexdomain.py +695 -538
- pyglet/gui/ninepatch.py +10 -10
- pyglet/gui/widgets.py +120 -10
- pyglet/image/__init__.py +20 -1973
- pyglet/image/animation.py +12 -12
- pyglet/image/base.py +730 -0
- pyglet/image/codecs/__init__.py +9 -0
- pyglet/image/codecs/bmp.py +53 -30
- pyglet/image/codecs/dds.py +53 -31
- pyglet/image/codecs/gdiplus.py +38 -14
- pyglet/image/codecs/gdkpixbuf2.py +0 -2
- pyglet/image/codecs/js_image.py +99 -0
- pyglet/image/codecs/ktx2.py +161 -0
- pyglet/image/codecs/pil.py +1 -1
- pyglet/image/codecs/png.py +1 -1
- pyglet/image/codecs/wic.py +11 -2
- pyglet/info.py +26 -24
- pyglet/input/__init__.py +8 -0
- pyglet/input/base.py +163 -105
- pyglet/input/controller.py +13 -19
- pyglet/input/controller_db.py +39 -24
- pyglet/input/emscripten/__init__.py +18 -0
- pyglet/input/emscripten/gamepad_js.py +397 -0
- pyglet/input/linux/__init__.py +11 -5
- pyglet/input/linux/evdev.py +10 -11
- pyglet/input/linux/x11_xinput.py +2 -2
- pyglet/input/linux/x11_xinput_tablet.py +1 -1
- pyglet/input/macos/__init__.py +7 -2
- pyglet/input/macos/darwin_gc.py +559 -0
- pyglet/input/win32/__init__.py +1 -1
- pyglet/input/win32/directinput.py +34 -29
- pyglet/input/win32/xinput.py +11 -61
- pyglet/lib.py +3 -3
- pyglet/libs/__init__.py +1 -1
- pyglet/{gl → libs/darwin}/agl.py +1 -1
- pyglet/libs/darwin/cocoapy/__init__.py +2 -2
- pyglet/libs/darwin/cocoapy/cocoahelpers.py +181 -0
- pyglet/libs/darwin/cocoapy/cocoalibs.py +31 -0
- pyglet/libs/darwin/cocoapy/cocoatypes.py +27 -0
- pyglet/libs/darwin/cocoapy/runtime.py +81 -45
- pyglet/libs/darwin/coreaudio.py +4 -4
- pyglet/{gl → libs/darwin}/lib_agl.py +9 -8
- pyglet/libs/darwin/quartzkey.py +1 -3
- pyglet/libs/egl/__init__.py +2 -0
- pyglet/libs/egl/egl_lib.py +576 -0
- pyglet/libs/egl/eglext.py +51 -5
- pyglet/libs/linux/__init__.py +0 -0
- pyglet/libs/linux/egl/__init__.py +0 -0
- pyglet/libs/linux/egl/eglext.py +22 -0
- pyglet/libs/linux/glx/__init__.py +0 -0
- pyglet/{gl → libs/linux/glx}/glx.py +13 -14
- pyglet/{gl → libs/linux/glx}/glxext_arb.py +408 -192
- pyglet/{gl → libs/linux/glx}/glxext_mesa.py +1 -1
- pyglet/{gl → libs/linux/glx}/glxext_nv.py +345 -164
- pyglet/{gl → libs/linux/glx}/lib_glx.py +3 -2
- pyglet/libs/linux/wayland/__init__.py +0 -0
- pyglet/libs/linux/wayland/client.py +1068 -0
- pyglet/libs/linux/wayland/lib_wayland.py +207 -0
- pyglet/libs/linux/wayland/wayland_egl.py +38 -0
- pyglet/libs/{wayland → linux/wayland}/xkbcommon.py +26 -0
- pyglet/libs/{x11 → linux/x11}/xf86vmode.py +4 -4
- pyglet/libs/{x11 → linux/x11}/xinerama.py +2 -2
- pyglet/libs/{x11 → linux/x11}/xinput.py +10 -10
- pyglet/libs/linux/x11/xrandr.py +0 -0
- pyglet/libs/{x11 → linux/x11}/xrender.py +1 -1
- pyglet/libs/shared/__init__.py +0 -0
- pyglet/libs/shared/spirv/__init__.py +0 -0
- pyglet/libs/shared/spirv/lib_shaderc.py +85 -0
- pyglet/libs/shared/spirv/lib_spirv_cross.py +126 -0
- pyglet/libs/win32/__init__.py +28 -8
- pyglet/libs/win32/constants.py +59 -48
- pyglet/libs/win32/context_managers.py +20 -3
- pyglet/libs/win32/dinput.py +105 -88
- pyglet/{gl → libs/win32}/lib_wgl.py +52 -26
- pyglet/libs/win32/types.py +58 -23
- pyglet/{gl → libs/win32}/wgl.py +32 -25
- pyglet/{gl → libs/win32}/wglext_arb.py +364 -2
- pyglet/media/__init__.py +9 -10
- pyglet/media/codecs/__init__.py +12 -1
- pyglet/media/codecs/base.py +99 -96
- pyglet/media/codecs/ffmpeg.py +2 -2
- pyglet/media/codecs/ffmpeg_lib/libavformat.py +3 -8
- pyglet/media/codecs/webaudio_pyodide.py +111 -0
- pyglet/media/drivers/__init__.py +9 -4
- pyglet/media/drivers/base.py +4 -4
- pyglet/media/drivers/openal/__init__.py +1 -1
- pyglet/media/drivers/openal/adaptation.py +3 -3
- pyglet/media/drivers/pulse/__init__.py +1 -1
- pyglet/media/drivers/pulse/adaptation.py +3 -3
- pyglet/media/drivers/pyodide_js/__init__.py +8 -0
- pyglet/media/drivers/pyodide_js/adaptation.py +288 -0
- pyglet/media/drivers/xaudio2/adaptation.py +3 -3
- pyglet/media/player.py +276 -193
- pyglet/media/player_worker_thread.py +1 -1
- pyglet/model/__init__.py +39 -29
- pyglet/model/codecs/base.py +4 -4
- pyglet/model/codecs/gltf.py +3 -3
- pyglet/model/codecs/obj.py +71 -43
- pyglet/resource.py +129 -78
- pyglet/shapes.py +154 -194
- pyglet/sprite.py +47 -164
- pyglet/text/__init__.py +44 -54
- pyglet/text/caret.py +12 -7
- pyglet/text/document.py +19 -17
- pyglet/text/formats/html.py +2 -2
- pyglet/text/formats/structured.py +10 -40
- pyglet/text/layout/__init__.py +20 -13
- pyglet/text/layout/base.py +176 -287
- pyglet/text/layout/incremental.py +9 -10
- pyglet/text/layout/scrolling.py +7 -95
- pyglet/window/__init__.py +183 -172
- pyglet/window/cocoa/__init__.py +62 -51
- pyglet/window/cocoa/pyglet_delegate.py +2 -25
- pyglet/window/cocoa/pyglet_view.py +9 -8
- pyglet/window/dialog/__init__.py +184 -0
- pyglet/window/dialog/base.py +99 -0
- pyglet/window/dialog/darwin.py +121 -0
- pyglet/window/dialog/linux.py +72 -0
- pyglet/window/dialog/windows.py +194 -0
- pyglet/window/emscripten/__init__.py +779 -0
- pyglet/window/headless/__init__.py +44 -28
- pyglet/window/key.py +2 -0
- pyglet/window/mouse.py +2 -2
- pyglet/window/wayland/__init__.py +377 -0
- pyglet/window/win32/__init__.py +101 -46
- pyglet/window/xlib/__init__.py +104 -66
- {pyglet-2.1.13.dist-info → pyglet-3.0.dev1.dist-info}/METADATA +2 -3
- pyglet-3.0.dev1.dist-info/RECORD +322 -0
- {pyglet-2.1.13.dist-info → pyglet-3.0.dev1.dist-info}/WHEEL +1 -1
- pyglet/gl/__init__.py +0 -208
- pyglet/gl/base.py +0 -499
- pyglet/gl/cocoa.py +0 -309
- pyglet/gl/gl.py +0 -4625
- pyglet/gl/gl.pyi +0 -2320
- pyglet/gl/gl_compat.pyi +0 -3097
- pyglet/gl/gl_info.py +0 -190
- pyglet/gl/headless.py +0 -166
- pyglet/gl/wgl_info.py +0 -36
- pyglet/gl/wglext_nv.py +0 -1096
- pyglet/gl/win32.py +0 -268
- pyglet/gl/xlib.py +0 -295
- pyglet/image/buffer.py +0 -274
- pyglet/image/codecs/s3tc.py +0 -354
- pyglet/libs/x11/xrandr.py +0 -166
- pyglet-2.1.13.dist-info/RECORD +0 -234
- /pyglet/{libs/wayland → graphics/api/gl/cocoa}/__init__.py +0 -0
- /pyglet/libs/{egl → linux/egl}/egl.py +0 -0
- /pyglet/libs/{egl → linux/egl}/lib.py +0 -0
- /pyglet/libs/{ioctl.py → linux/ioctl.py} +0 -0
- /pyglet/libs/{wayland → linux/wayland}/gbm.py +0 -0
- /pyglet/libs/{x11 → linux/x11}/__init__.py +0 -0
- /pyglet/libs/{x11 → linux/x11}/cursorfont.py +0 -0
- /pyglet/libs/{x11 → linux/x11}/xlib.py +0 -0
- /pyglet/libs/{x11 → linux/x11}/xsync.py +0 -0
- {pyglet-2.1.13.dist-info/licenses → pyglet-3.0.dev1.dist-info}/LICENSE +0 -0
pyglet/__init__.py
CHANGED
|
@@ -7,15 +7,16 @@ from __future__ import annotations
|
|
|
7
7
|
import os
|
|
8
8
|
import sys
|
|
9
9
|
import warnings
|
|
10
|
-
|
|
11
|
-
from dataclasses import dataclass
|
|
12
|
-
from typing import TYPE_CHECKING, Literal
|
|
10
|
+
|
|
11
|
+
from dataclasses import dataclass, field
|
|
12
|
+
from typing import TYPE_CHECKING, Literal, Sequence
|
|
13
|
+
|
|
13
14
|
if TYPE_CHECKING:
|
|
14
15
|
from types import FrameType
|
|
15
16
|
from typing import Any, Callable, ItemsView, Sized
|
|
16
17
|
|
|
17
18
|
#: The release version
|
|
18
|
-
version = '
|
|
19
|
+
version = '3.0.dev1'
|
|
19
20
|
__version__ = version
|
|
20
21
|
|
|
21
22
|
MIN_PYTHON_VERSION = 3, 8
|
|
@@ -42,6 +43,18 @@ if compat_platform == "cygwin":
|
|
|
42
43
|
ctypes.HRESULT = ctypes.c_long
|
|
43
44
|
|
|
44
45
|
|
|
46
|
+
@dataclass
|
|
47
|
+
class PyodideOptions:
|
|
48
|
+
"""Dataclass for Pyodide related options."""
|
|
49
|
+
|
|
50
|
+
canvas_id: str = "pygletCanvas"
|
|
51
|
+
"""Pyglet will need to target a specific canvas ID to use for javascript canvas detection.
|
|
52
|
+
|
|
53
|
+
If the ID is not detected, a canvas will be created with the above. If you have a canvas already embedded in your
|
|
54
|
+
page, and do not want to alter your code, then modify this option.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
|
|
45
58
|
@dataclass
|
|
46
59
|
class Options:
|
|
47
60
|
"""Dataclass for global pyglet options."""
|
|
@@ -65,7 +78,7 @@ class Options:
|
|
|
65
78
|
debug_font: bool = False
|
|
66
79
|
"""If ``True``, will print more verbose information when :py:class:`~pyglet.font.base.Font`'s are loaded."""
|
|
67
80
|
|
|
68
|
-
|
|
81
|
+
debug_api: bool = True
|
|
69
82
|
"""If ``True``, all calls to OpenGL functions are checked afterwards for
|
|
70
83
|
errors using ``glGetError``. This will severely impact performance,
|
|
71
84
|
but provides useful exceptions at the point of failure. By default,
|
|
@@ -73,22 +86,22 @@ class Options:
|
|
|
73
86
|
with the -O option). It is disabled by default when pyglet is "frozen", such as
|
|
74
87
|
within pyinstaller or nuitka."""
|
|
75
88
|
|
|
76
|
-
|
|
89
|
+
debug_api_trace: bool = False
|
|
77
90
|
"""If ``True``, will print the names of OpenGL calls being executed. For example, ``glBlendFunc``"""
|
|
78
91
|
|
|
79
|
-
|
|
92
|
+
debug_api_trace_args: bool = False
|
|
80
93
|
"""If ``True``, in addition to printing the names of OpenGL calls, it will also print the arguments passed
|
|
81
94
|
into those calls. For example, ``glBlendFunc(770, 771)``
|
|
82
95
|
|
|
83
|
-
.. note:: Requires ``
|
|
96
|
+
.. note:: Requires ``debug_api_trace`` to be enabled."""
|
|
84
97
|
|
|
85
|
-
|
|
98
|
+
debug_api_shaders: bool = False
|
|
86
99
|
"""If ``True``, prints shader compilation information such as creation and deletion of shader's. Also includes
|
|
87
100
|
information on shader ID's, attributes, and uniforms."""
|
|
88
101
|
|
|
89
102
|
debug_graphics_batch: bool = False
|
|
90
103
|
"""If ``True``, prints batch information being drawn, including :py:class:`~pyglet.graphics.Group`'s, VertexDomains,
|
|
91
|
-
and :py:class:`~pyglet.
|
|
104
|
+
and :py:class:`~pyglet.graphics.Texture` information. This can be useful to see how many Group's are being
|
|
92
105
|
consolidated."""
|
|
93
106
|
|
|
94
107
|
debug_lib: bool = False
|
|
@@ -97,19 +110,11 @@ class Options:
|
|
|
97
110
|
debug_media: bool = False
|
|
98
111
|
"""If ``True``, prints more detailed media information for audio codecs and drivers. Will be very verbose."""
|
|
99
112
|
|
|
100
|
-
debug_texture: bool = False
|
|
101
|
-
"""If ``True``, prints information on :py:class:`~pyglet.image.Texture` size (in bytes) when they are allocated and
|
|
102
|
-
deleted."""
|
|
103
|
-
|
|
104
113
|
debug_trace: bool = False
|
|
105
114
|
debug_trace_args: bool = False
|
|
106
115
|
debug_trace_depth: int = 1
|
|
107
116
|
debug_trace_flush: bool = True
|
|
108
117
|
|
|
109
|
-
debug_com: bool = False
|
|
110
|
-
"""If ``True``, prints information on COM calls. This can potentially help narrow down issues with certain libraries
|
|
111
|
-
that utilize COM calls. Only applies to the Windows platform."""
|
|
112
|
-
|
|
113
118
|
debug_win32: bool = False
|
|
114
119
|
"""If ``True``, prints error messages related to Windows library calls. Usually gets information from
|
|
115
120
|
``Kernel32.GetLastError``. This information is output to a file called ``debug_win32.log``."""
|
|
@@ -121,21 +126,12 @@ class Options:
|
|
|
121
126
|
"""If ``True``, prints information related to Linux X11 calls. This can potentially help narrow down driver or
|
|
122
127
|
operating system issues."""
|
|
123
128
|
|
|
124
|
-
|
|
125
|
-
"""
|
|
126
|
-
pyglet.gl is imported. This allows resources to be loaded before
|
|
127
|
-
the application window is created, and permits GL objects to be
|
|
128
|
-
shared between windows even after they've been closed. You can
|
|
129
|
-
disable the creation of the shadow window by setting this option to
|
|
130
|
-
False.
|
|
131
|
-
|
|
132
|
-
Some OpenGL driver implementations may not support shared OpenGL
|
|
133
|
-
contexts and may require disabling the shadow window (and all resources
|
|
134
|
-
must be loaded after the window using them was created). Recommended
|
|
135
|
-
for advanced developers only.
|
|
129
|
+
debug_wayland: bool = False
|
|
130
|
+
"""If ``True``, prints information related to communications with the Wayland compositor."""
|
|
136
131
|
|
|
137
|
-
|
|
138
|
-
|
|
132
|
+
debug_com: bool = False
|
|
133
|
+
"""If ``True``, prints information on COM calls. This can potentially help narrow down issues with certain libraries
|
|
134
|
+
that utilize COM calls. Only applies to the Windows platform."""
|
|
139
135
|
|
|
140
136
|
vsync: bool | None = None
|
|
141
137
|
"""If set, the `pyglet.window.Window.vsync` property is ignored, and
|
|
@@ -187,7 +183,7 @@ class Options:
|
|
|
187
183
|
"""
|
|
188
184
|
|
|
189
185
|
headless_device: int = 0
|
|
190
|
-
"""If using ``headless`` mode (``pyglet.options
|
|
186
|
+
"""If using ``headless`` mode (``pyglet.options.headless = True``), this option allows you to set which
|
|
191
187
|
GPU to use. This is only useful on multi-GPU systems.
|
|
192
188
|
"""
|
|
193
189
|
|
|
@@ -255,41 +251,28 @@ class Options:
|
|
|
255
251
|
|
|
256
252
|
.. versionadded:: 2.0.5"""
|
|
257
253
|
|
|
258
|
-
dpi_scaling: Literal["
|
|
254
|
+
dpi_scaling: Literal["platform", "stretch"] = "platform"
|
|
259
255
|
"""For 'HiDPI' displays, Window behavior can differ between operating systems. Defaults to `'platform'`.
|
|
260
256
|
|
|
261
257
|
The current options are an attempt to create consistent behavior across all of the operating systems.
|
|
262
258
|
|
|
263
|
-
`'
|
|
264
|
-
|
|
265
|
-
|
|
259
|
+
`'platform'`: A DPI aware window is created. Framebuffer and window sizes are dictated by the platform the window
|
|
260
|
+
was created on. In most systems, the window size will be in DIPs (Device Independent Pixels). It is up to the user
|
|
261
|
+
to make any further adjustments to the framebuffer or window size for their application.
|
|
266
262
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
content to take advantage of the larger framebuffer. An 800x600 with a 150% DPI scaling would be changed to
|
|
270
|
-
1200x900 for both `window.get_size` and `window.get_framebuffer_size()`.
|
|
263
|
+
On Windows and X11, the framebuffer and the requested window size will always match 1:1. On MacOS, depending
|
|
264
|
+
on a Hi-DPI display, you may get a larger sized framebuffer than the window size.
|
|
271
265
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
`'stretch'`: Window is scaled based on the DPI ratio. However, content size matches original requested size of the
|
|
277
|
-
window, and is stretched to fit the full framebuffer. This mimics behavior of having no DPI scaling at all. No
|
|
278
|
-
rescaling and repositioning of content will be necessary, but at the cost of blurry content depending on the extent
|
|
279
|
-
of the stretch. For example, 800x600 at 150% DPI will be 800x600 for `window.get_size()` and 1200x900 for
|
|
266
|
+
`'stretch'`: This mimics behavior of having no DPI scaling at all. Window is scaled based on the DPI ratio.
|
|
267
|
+
However, content size matches original requested size of the window, and is stretched to fit the full framebuffer.
|
|
268
|
+
No rescaling and repositioning of content will be necessary, but at the cost of blurry content depending on the
|
|
269
|
+
extent of the stretch. For example, 800x600 at 150% DPI will be 800x600 for `window.get_size()` and 1200x900 for
|
|
280
270
|
`window.get_framebuffer_size()`.
|
|
281
|
-
|
|
282
|
-
`'platform'`: A DPI aware window is created, however window sizing and framebuffer sizing is not interfered with
|
|
283
|
-
by Pyglet. Final sizes are dictated by the platform the window was created on. It is up to the user to make any
|
|
284
|
-
platform adjustments themselves such as sizing on a platform, mouse coordinate adjustments, or framebuffer size
|
|
285
|
-
handling. On Windows and X11, the framebuffer and the requested window size will always match in pixels 1:1. On
|
|
286
|
-
MacOS, depending on a Hi-DPI display, you may get a different sized framebuffer than the window size. This option
|
|
287
|
-
does allow `window.dpi` and `window.scale` to return their respective values.
|
|
288
271
|
"""
|
|
289
272
|
|
|
290
273
|
shader_bind_management: bool = True
|
|
291
274
|
"""If ``True``, this will enable internal management of Uniform Block bindings for
|
|
292
|
-
:py:class:`~pyglet.graphics.
|
|
275
|
+
:py:class:`~pyglet.graphics.ShaderProgram`'s.
|
|
293
276
|
|
|
294
277
|
If ``False``, bindings will not be managed by Pyglet. The user will be responsible for either setting the binding
|
|
295
278
|
points through GLSL layouts (4.2 required) or manually through ``UniformBlock.set_binding``.
|
|
@@ -297,6 +280,27 @@ class Options:
|
|
|
297
280
|
.. versionadded:: 2.0.16
|
|
298
281
|
"""
|
|
299
282
|
|
|
283
|
+
wayland: bool = False
|
|
284
|
+
"""If ``True``, use Wayland instead of Xlib on Linux.
|
|
285
|
+
|
|
286
|
+
.. versionadded:: 3.0.0
|
|
287
|
+
"""
|
|
288
|
+
|
|
289
|
+
backend: Literal["opengl", "gl2", "gles3", "gles2", "webgl"] = "opengl"
|
|
290
|
+
"""Specify the graphics API backend."""
|
|
291
|
+
|
|
292
|
+
optimize_states: bool = True
|
|
293
|
+
"""Runs a second pass on the draw list to remove any redundant states.
|
|
294
|
+
|
|
295
|
+
This option is mostly meant for debugging, as this should not significantly impact the draw list creation time
|
|
296
|
+
or impact drawing states.
|
|
297
|
+
|
|
298
|
+
.. versionadded:: 3.0.0
|
|
299
|
+
"""
|
|
300
|
+
|
|
301
|
+
pyodide: PyodideOptions = field(default_factory=PyodideOptions)
|
|
302
|
+
"""Pyodide specific options."""
|
|
303
|
+
|
|
300
304
|
def get(self, item: str, default: Any = None) -> Any:
|
|
301
305
|
return self.__dict__.get(item, default)
|
|
302
306
|
|
|
@@ -323,7 +327,7 @@ for _option_name, _type_str in options.__annotations__.items():
|
|
|
323
327
|
setattr(options, _option_name, _value in ("true", "TRUE", "True", "1"))
|
|
324
328
|
elif 'int' in _type_str:
|
|
325
329
|
setattr(options, _option_name, int(_value))
|
|
326
|
-
elif 'Literal' in _type_str and _value in _type_str:
|
|
330
|
+
elif 'str' in _type_str or ('Literal' in _type_str and _value in _type_str):
|
|
327
331
|
setattr(options, _option_name, _value)
|
|
328
332
|
else:
|
|
329
333
|
warnings.warn(f"Invalid value '{_value}' for {_option_name}. Expecting {_type_str}")
|
|
@@ -434,7 +438,7 @@ class _ModuleProxy:
|
|
|
434
438
|
def __init__(self, name: str) -> None:
|
|
435
439
|
self.__dict__["_module_name"] = name
|
|
436
440
|
|
|
437
|
-
def __getattr__(self, name: str):
|
|
441
|
+
def __getattr__(self, name: str): # noqa: ANN204
|
|
438
442
|
try:
|
|
439
443
|
return getattr(self._module, name)
|
|
440
444
|
except AttributeError:
|
|
@@ -468,11 +472,12 @@ if TYPE_CHECKING:
|
|
|
468
472
|
from . import (
|
|
469
473
|
app,
|
|
470
474
|
clock,
|
|
475
|
+
config,
|
|
471
476
|
customtypes,
|
|
472
477
|
display,
|
|
478
|
+
enums,
|
|
473
479
|
event,
|
|
474
480
|
font,
|
|
475
|
-
gl,
|
|
476
481
|
graphics,
|
|
477
482
|
gui,
|
|
478
483
|
image,
|
|
@@ -489,12 +494,13 @@ if TYPE_CHECKING:
|
|
|
489
494
|
)
|
|
490
495
|
else:
|
|
491
496
|
app = _ModuleProxy("app") # type: ignore
|
|
497
|
+
config = _ModuleProxy("config") # type: ignore
|
|
492
498
|
clock = _ModuleProxy("clock") # type: ignore
|
|
493
499
|
customtypes = _ModuleProxy("customtypes") # type: ignore
|
|
494
500
|
display = _ModuleProxy("display") # type: ignore
|
|
501
|
+
enums = _ModuleProxy("enums") # type: ignore
|
|
495
502
|
event = _ModuleProxy("event") # type: ignore
|
|
496
503
|
font = _ModuleProxy("font") # type: ignore
|
|
497
|
-
gl = _ModuleProxy("gl") # type: ignore
|
|
498
504
|
graphics = _ModuleProxy("graphics") # type: ignore
|
|
499
505
|
gui = _ModuleProxy("gui") # type: ignore
|
|
500
506
|
image = _ModuleProxy("image") # type: ignore
|
pyglet/__init__.pyi
CHANGED
|
@@ -4,11 +4,11 @@ from typing import Any, ItemsView, Literal, Sequence
|
|
|
4
4
|
|
|
5
5
|
from . import app as app
|
|
6
6
|
from . import clock as clock
|
|
7
|
+
from . import config as config
|
|
7
8
|
from . import customtypes as customtypes
|
|
8
9
|
from . import display as display
|
|
9
10
|
from . import event as event
|
|
10
11
|
from . import font as font
|
|
11
|
-
from . import gl as gl
|
|
12
12
|
from . import graphics as graphics
|
|
13
13
|
from . import gui as gui
|
|
14
14
|
from . import image as image
|
|
@@ -30,18 +30,21 @@ compat_platform: str
|
|
|
30
30
|
env: str
|
|
31
31
|
value: str
|
|
32
32
|
|
|
33
|
+
@dataclass
|
|
34
|
+
class PyodideOptions:
|
|
35
|
+
canvas_id: str
|
|
36
|
+
|
|
33
37
|
@dataclass
|
|
34
38
|
class Options:
|
|
35
39
|
audio: Sequence[str]
|
|
36
40
|
debug_font: bool
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
debug_api: bool
|
|
42
|
+
debug_api_trace: bool
|
|
43
|
+
debug_api_trace_args: bool
|
|
44
|
+
debug_api_shaders: bool
|
|
41
45
|
debug_graphics_batch: bool
|
|
42
46
|
debug_lib: bool
|
|
43
47
|
debug_media: bool
|
|
44
|
-
debug_texture: bool
|
|
45
48
|
debug_trace: bool
|
|
46
49
|
debug_trace_args: bool
|
|
47
50
|
debug_trace_depth: int
|
|
@@ -49,8 +52,8 @@ class Options:
|
|
|
49
52
|
debug_win32: bool
|
|
50
53
|
debug_input: bool
|
|
51
54
|
debug_x11: bool
|
|
55
|
+
debug_wayland: bool
|
|
52
56
|
debug_com: bool
|
|
53
|
-
shadow_window: bool
|
|
54
57
|
vsync: bool | None
|
|
55
58
|
xsync: bool
|
|
56
59
|
xlib_fullscreen_override_redirect: bool
|
|
@@ -64,8 +67,12 @@ class Options:
|
|
|
64
67
|
win32_disable_xinput: bool
|
|
65
68
|
com_mta: bool
|
|
66
69
|
osx_alt_loop: bool
|
|
67
|
-
dpi_scaling: Literal["
|
|
70
|
+
dpi_scaling: Literal["platform", "stretch"]
|
|
68
71
|
shader_bind_management: bool
|
|
72
|
+
wayland: bool
|
|
73
|
+
backend: str | None
|
|
74
|
+
optimize_states: bool
|
|
75
|
+
pyodide: PyodideOptions
|
|
69
76
|
|
|
70
77
|
def get(self, item: str, default: Any = None) -> Any:
|
|
71
78
|
...
|
pyglet/app/__init__.py
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
Applications
|
|
4
4
|
------------
|
|
5
5
|
|
|
6
|
-
Most applications need only call :func:`run` after creating one or more
|
|
7
|
-
windows to begin processing events. For example, a simple application
|
|
6
|
+
Most applications need only call :func:`run` after creating one or more
|
|
7
|
+
windows to begin processing events. For example, a simple application
|
|
8
8
|
consisting of one window is::
|
|
9
9
|
|
|
10
10
|
import pyglet
|
|
@@ -28,18 +28,17 @@ default policy is to wait until all windows are closed)::
|
|
|
28
28
|
|
|
29
29
|
.. versionadded:: 1.1
|
|
30
30
|
"""
|
|
31
|
+
|
|
31
32
|
from __future__ import annotations
|
|
32
33
|
|
|
34
|
+
import platform
|
|
33
35
|
import sys
|
|
34
36
|
import weakref
|
|
35
|
-
import platform
|
|
36
37
|
|
|
37
38
|
import pyglet
|
|
38
|
-
|
|
39
39
|
from pyglet import compat_platform
|
|
40
40
|
from pyglet.app.base import EventLoop
|
|
41
41
|
|
|
42
|
-
|
|
43
42
|
_is_pyglet_doc_run = hasattr(sys, "is_pyglet_doc_run") and sys.is_pyglet_doc_run
|
|
44
43
|
|
|
45
44
|
if _is_pyglet_doc_run:
|
|
@@ -47,15 +46,16 @@ if _is_pyglet_doc_run:
|
|
|
47
46
|
else:
|
|
48
47
|
if compat_platform == 'darwin':
|
|
49
48
|
from pyglet.app.cocoa import CocoaPlatformEventLoop as PlatformEventLoop
|
|
50
|
-
from pyglet.libs.darwin.cocoapy.runtime import get_chip_model
|
|
51
49
|
|
|
52
|
-
|
|
53
|
-
if (platform.machine() == 'arm64' and "M1" in get_chip_model()) or pyglet.options.osx_alt_loop:
|
|
50
|
+
if platform.machine() == 'arm64' or pyglet.options.osx_alt_loop:
|
|
54
51
|
from pyglet.app.cocoa import CocoaAlternateEventLoop as EventLoop
|
|
55
52
|
elif compat_platform in ('win32', 'cygwin'):
|
|
56
53
|
from pyglet.app.win32 import Win32EventLoop as PlatformEventLoop
|
|
57
|
-
|
|
58
|
-
from pyglet.app.
|
|
54
|
+
elif compat_platform == 'linux':
|
|
55
|
+
from pyglet.app.linux import LinuxEventLoop as PlatformEventLoop
|
|
56
|
+
elif compat_platform == 'emscripten':
|
|
57
|
+
from pyglet.app.async_app import AsyncEventLoop as EventLoop
|
|
58
|
+
from pyglet.app.async_app import AsyncPlatformEventLoop as PlatformEventLoop
|
|
59
59
|
|
|
60
60
|
|
|
61
61
|
class AppException(Exception):
|
|
@@ -78,7 +78,11 @@ def run(interval: float | None = 1 / 60) -> None:
|
|
|
78
78
|
pyglet.app.event_loop.run(interval)
|
|
79
79
|
|
|
80
80
|
"""
|
|
81
|
-
|
|
81
|
+
if pyglet.compat_platform == "emscripten":
|
|
82
|
+
import asyncio
|
|
83
|
+
asyncio.create_task(event_loop.run(interval)) # noqa: RUF006
|
|
84
|
+
else:
|
|
85
|
+
event_loop.run(interval)
|
|
82
86
|
|
|
83
87
|
|
|
84
88
|
def exit() -> None:
|
|
@@ -93,11 +97,16 @@ def exit() -> None:
|
|
|
93
97
|
pyglet.app.event_loop.exit()
|
|
94
98
|
|
|
95
99
|
"""
|
|
96
|
-
|
|
100
|
+
if pyglet.compat_platform == "emscripten":
|
|
101
|
+
import asyncio
|
|
102
|
+
|
|
103
|
+
asyncio.create_task(event_loop.exit())
|
|
104
|
+
else:
|
|
105
|
+
event_loop.exit()
|
|
97
106
|
|
|
98
107
|
|
|
99
108
|
#: The global event loop. Applications can replace this
|
|
100
|
-
#: with their own subclass of :class:`EventLoop` before calling
|
|
109
|
+
#: with their own subclass of :class:`EventLoop` before calling
|
|
101
110
|
#: :meth:`EventLoop.run`.
|
|
102
111
|
event_loop = EventLoop()
|
|
103
112
|
|
pyglet/app/async_app.py
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import sys
|
|
5
|
+
from typing import Any, Callable, TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
import pyglet
|
|
8
|
+
from pyglet import app, clock, event
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from pyglet.event import EventDispatcher
|
|
12
|
+
from pyglet.window import BaseWindow
|
|
13
|
+
|
|
14
|
+
_is_pyglet_doc_run = hasattr(sys, "is_pyglet_doc_run") and sys.is_pyglet_doc_run
|
|
15
|
+
try:
|
|
16
|
+
from js import requestAnimationFrame, performance
|
|
17
|
+
from pyodide.ffi import create_proxy
|
|
18
|
+
except ImportError:
|
|
19
|
+
raise ImportError('Pyodide not available.')
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class AsyncEventLoop(event.EventDispatcher):
|
|
23
|
+
"""Asyncio-based event loop for Pyglet."""
|
|
24
|
+
|
|
25
|
+
def __init__(self) -> None:
|
|
26
|
+
self._has_exit_event = asyncio.Event()
|
|
27
|
+
# Change the default clock to use the javascript performance timer.
|
|
28
|
+
self.clock = clock.Clock(self._get_js_time)
|
|
29
|
+
pyglet.clock.set_default(self.clock)
|
|
30
|
+
self.is_running = False
|
|
31
|
+
self._interval = None
|
|
32
|
+
self._last_ts = 0.0
|
|
33
|
+
self._frame_dt = 0.0
|
|
34
|
+
|
|
35
|
+
self._frame_future = None
|
|
36
|
+
self._frame_proxy = create_proxy(self._frame_cb)
|
|
37
|
+
|
|
38
|
+
def _get_js_time(self) -> float:
|
|
39
|
+
"""Use Javascripts performance.now for the clock accuracy.
|
|
40
|
+
|
|
41
|
+
May not be needed, but just to be accurate.
|
|
42
|
+
"""
|
|
43
|
+
return performance.now() / 1000
|
|
44
|
+
|
|
45
|
+
@staticmethod
|
|
46
|
+
def _redraw_windows(dt: float) -> None:
|
|
47
|
+
# Redraw all windows
|
|
48
|
+
for window in app.windows:
|
|
49
|
+
window.draw(dt)
|
|
50
|
+
|
|
51
|
+
def _frame_cb(self, ts: float) -> None:
|
|
52
|
+
"""Callback for the requestAnimationFrame."""
|
|
53
|
+
now = ts / 1000.0
|
|
54
|
+
_frame_dt = now - self._last_ts
|
|
55
|
+
|
|
56
|
+
self._last_ts = now
|
|
57
|
+
|
|
58
|
+
if self._frame_future:
|
|
59
|
+
self._frame_future.set_result(_frame_dt)
|
|
60
|
+
self._frame_future = None
|
|
61
|
+
|
|
62
|
+
async def _next_animation_frame(self) -> float:
|
|
63
|
+
self._frame_future = asyncio.Future()
|
|
64
|
+
requestAnimationFrame(self._frame_proxy)
|
|
65
|
+
return await self._frame_future
|
|
66
|
+
|
|
67
|
+
async def draw_frame(self) -> None:
|
|
68
|
+
frame_dt = await self._next_animation_frame()
|
|
69
|
+
self._redraw_windows(frame_dt)
|
|
70
|
+
|
|
71
|
+
async def run(self, interval: float | None = 1/60) -> None:
|
|
72
|
+
try:
|
|
73
|
+
"""Begin processing events asynchronously."""
|
|
74
|
+
self._interval = interval
|
|
75
|
+
|
|
76
|
+
self._has_exit_event.clear()
|
|
77
|
+
platform_event_loop = app.platform_event_loop
|
|
78
|
+
|
|
79
|
+
await platform_event_loop.start()
|
|
80
|
+
self.dispatch_event('on_enter')
|
|
81
|
+
self.is_running = True
|
|
82
|
+
|
|
83
|
+
# Use the browser's requestAnimationFrame for the loop if None is used.
|
|
84
|
+
if self._interval is None:
|
|
85
|
+
while not self._has_exit_event.is_set():
|
|
86
|
+
await self.draw_frame()
|
|
87
|
+
self.idle() # Ticks clock and runs scheduled functions.
|
|
88
|
+
await platform_event_loop.dispatch_posted_events()
|
|
89
|
+
else:
|
|
90
|
+
_schedule_rate = self._interval / 1000.0
|
|
91
|
+
|
|
92
|
+
# Separate draw loop so clock timeout doesn't block rendering if it's slower.
|
|
93
|
+
async def _draw_loop() -> None:
|
|
94
|
+
while not self._has_exit_event.is_set():
|
|
95
|
+
await self.draw_frame()
|
|
96
|
+
|
|
97
|
+
asyncio.create_task(_draw_loop()) # noqa: RUF006
|
|
98
|
+
|
|
99
|
+
while not self._has_exit_event.is_set():
|
|
100
|
+
timeout = self.idle()
|
|
101
|
+
await platform_event_loop.dispatch_posted_events()
|
|
102
|
+
await asyncio.sleep(0 if timeout is None else timeout)
|
|
103
|
+
|
|
104
|
+
self.is_running = False
|
|
105
|
+
self.dispatch_event('on_exit')
|
|
106
|
+
await platform_event_loop.stop()
|
|
107
|
+
except Exception as err:
|
|
108
|
+
import traceback
|
|
109
|
+
print("Error in wrapped task", err)
|
|
110
|
+
traceback.print_exc()
|
|
111
|
+
|
|
112
|
+
async def enter_blocking(self) -> None:
|
|
113
|
+
"""Ensure `idle()` continues to be called during blocking operations."""
|
|
114
|
+
timeout = self.idle()
|
|
115
|
+
await app.platform_event_loop.set_timer(self._blocking_timer, timeout)
|
|
116
|
+
|
|
117
|
+
async def exit_blocking(self) -> None:
|
|
118
|
+
"""Stop the blocking timer."""
|
|
119
|
+
await app.platform_event_loop.set_timer(None, None)
|
|
120
|
+
|
|
121
|
+
async def _blocking_timer(self) -> None:
|
|
122
|
+
"""Called to process scheduled events during blocking operations."""
|
|
123
|
+
dt = self.clock.update_time()
|
|
124
|
+
self.clock.call_scheduled_functions(dt)
|
|
125
|
+
if self._interval is None:
|
|
126
|
+
self._redraw_windows(dt)
|
|
127
|
+
|
|
128
|
+
timeout = self.clock.get_sleep_time(True)
|
|
129
|
+
await app.platform_event_loop.set_timer(self._blocking_timer, timeout)
|
|
130
|
+
|
|
131
|
+
def idle(self) -> float | None:
|
|
132
|
+
"""Called each iteration to process events."""
|
|
133
|
+
dt = self.clock.update_time()
|
|
134
|
+
self.clock.call_scheduled_functions(dt)
|
|
135
|
+
return self.clock.get_sleep_time(True)
|
|
136
|
+
|
|
137
|
+
async def exit(self) -> None:
|
|
138
|
+
"""Exit the event loop asynchronously."""
|
|
139
|
+
self._has_exit_event.set()
|
|
140
|
+
app.platform_event_loop.notify()
|
|
141
|
+
|
|
142
|
+
async def sleep(self, timeout: float) -> bool:
|
|
143
|
+
"""Pause execution for a given time unless `exit()` is called."""
|
|
144
|
+
try:
|
|
145
|
+
await asyncio.wait_for(self._has_exit_event.wait(), timeout)
|
|
146
|
+
return True
|
|
147
|
+
except asyncio.TimeoutError:
|
|
148
|
+
return False
|
|
149
|
+
|
|
150
|
+
async def on_window_close(self, _window: BaseWindow) -> None:
|
|
151
|
+
"""Exit when the last window is closed."""
|
|
152
|
+
if len(app.windows) == 0:
|
|
153
|
+
await self.exit()
|
|
154
|
+
|
|
155
|
+
AsyncEventLoop.register_event_type('on_window_close')
|
|
156
|
+
AsyncEventLoop.register_event_type('on_enter')
|
|
157
|
+
AsyncEventLoop.register_event_type('on_exit')
|
|
158
|
+
|
|
159
|
+
class AsyncPlatformEventLoop:
|
|
160
|
+
"""An asyncio-based platform event loop."""
|
|
161
|
+
|
|
162
|
+
def __init__(self) -> None:
|
|
163
|
+
"""Initialize the event loop with an asyncio queue and event."""
|
|
164
|
+
self._event_queue = asyncio.Queue()
|
|
165
|
+
self._is_running = asyncio.Event()
|
|
166
|
+
|
|
167
|
+
def is_running(self) -> bool:
|
|
168
|
+
"""Check if the event loop is currently processing."""
|
|
169
|
+
return self._is_running.is_set()
|
|
170
|
+
|
|
171
|
+
async def post_event(self, dispatcher: EventDispatcher, event: str, *args: Any) -> None:
|
|
172
|
+
"""Post an event into the main application thread asynchronously."""
|
|
173
|
+
await self._event_queue.put((dispatcher, event, args))
|
|
174
|
+
self.notify()
|
|
175
|
+
|
|
176
|
+
async def dispatch_posted_events(self) -> None:
|
|
177
|
+
"""Dispatch all pending events asynchronously."""
|
|
178
|
+
while not self._event_queue.empty():
|
|
179
|
+
try:
|
|
180
|
+
dispatcher, evnt, args = await self._event_queue.get()
|
|
181
|
+
dispatcher.dispatch_event(evnt, *args)
|
|
182
|
+
except asyncio.CancelledError:
|
|
183
|
+
break
|
|
184
|
+
except ReferenceError:
|
|
185
|
+
# weakly-referenced object no longer exists
|
|
186
|
+
pass
|
|
187
|
+
|
|
188
|
+
def notify(self) -> None:
|
|
189
|
+
"""Trigger an iteration of the asyncio event loop."""
|
|
190
|
+
if self.is_running():
|
|
191
|
+
asyncio.create_task(self.dispatch_posted_events())
|
|
192
|
+
|
|
193
|
+
async def start(self) -> None:
|
|
194
|
+
"""Start the asyncio-based event loop."""
|
|
195
|
+
self._is_running.set()
|
|
196
|
+
|
|
197
|
+
async def step(self, timeout: float | None = None) -> None:
|
|
198
|
+
"""Run one iteration of the asyncio event loop with a timeout."""
|
|
199
|
+
try:
|
|
200
|
+
await asyncio.wait_for(self.dispatch_posted_events(), timeout)
|
|
201
|
+
except asyncio.TimeoutError:
|
|
202
|
+
pass
|
|
203
|
+
|
|
204
|
+
async def set_timer(self, func: Callable, interval: float) -> None:
|
|
205
|
+
"""Schedule a timer function asynchronously."""
|
|
206
|
+
while self.is_running():
|
|
207
|
+
await asyncio.sleep(interval)
|
|
208
|
+
func()
|
|
209
|
+
|
|
210
|
+
async def stop(self) -> None:
|
|
211
|
+
"""Stop the asyncio-based event loop."""
|
|
212
|
+
self._is_running.clear()
|
pyglet/app/base.py
CHANGED
|
@@ -152,7 +152,7 @@ class EventLoop(event.EventDispatcher):
|
|
|
152
152
|
|
|
153
153
|
# Dispatch pending events
|
|
154
154
|
for window in app.windows:
|
|
155
|
-
window.switch_to()
|
|
155
|
+
#window.switch_to()
|
|
156
156
|
window.dispatch_pending_events()
|
|
157
157
|
|
|
158
158
|
platform_event_loop = app.platform_event_loop
|
|
@@ -264,6 +264,7 @@ class EventLoop(event.EventDispatcher):
|
|
|
264
264
|
interrupted (see :py:meth:`sleep`).
|
|
265
265
|
"""
|
|
266
266
|
self.has_exit = True
|
|
267
|
+
self.clock.unschedule(self._redraw_windows)
|
|
267
268
|
app.platform_event_loop.notify()
|
|
268
269
|
|
|
269
270
|
def sleep(self, timeout: float) -> bool:
|
pyglet/app/{xlib.py → linux.py}
RENAMED
|
@@ -6,7 +6,7 @@ from pyglet import app
|
|
|
6
6
|
from pyglet.app.base import PlatformEventLoop
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class
|
|
9
|
+
class LinuxSelectDevice:
|
|
10
10
|
def fileno(self):
|
|
11
11
|
"""Get the file handle for ``select()`` for this device.
|
|
12
12
|
|
|
@@ -31,7 +31,7 @@ class XlibSelectDevice:
|
|
|
31
31
|
return False
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
class NotificationDevice(
|
|
34
|
+
class NotificationDevice(LinuxSelectDevice):
|
|
35
35
|
def __init__(self):
|
|
36
36
|
self._sync_file_read, self._sync_file_write = os.pipe()
|
|
37
37
|
self._event = threading.Event()
|
|
@@ -52,7 +52,7 @@ class NotificationDevice(XlibSelectDevice):
|
|
|
52
52
|
return self._event.is_set()
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
class
|
|
55
|
+
class LinuxEventLoop(PlatformEventLoop):
|
|
56
56
|
def __init__(self):
|
|
57
57
|
super().__init__()
|
|
58
58
|
self._notification_device = NotificationDevice()
|