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
|
@@ -2,20 +2,20 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import Sequence
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
import pyglet
|
|
7
6
|
# from pyglet.window import key
|
|
8
7
|
# from pyglet.window import mouse
|
|
9
8
|
from pyglet.event import EventDispatcher
|
|
10
|
-
from pyglet.libs.egl import
|
|
9
|
+
from pyglet.libs.egl import (
|
|
10
|
+
eglCreatePbufferSurface,
|
|
11
|
+
EGLint,
|
|
12
|
+
EGL_WIDTH,
|
|
13
|
+
EGL_HEIGHT,
|
|
14
|
+
EGL_NONE,
|
|
15
|
+
eglDestroySurface,
|
|
16
|
+
)
|
|
11
17
|
from pyglet.window import (
|
|
12
18
|
BaseWindow,
|
|
13
|
-
DefaultMouseCursor, # noqa: F401
|
|
14
|
-
ImageMouseCursor, # noqa: F401
|
|
15
|
-
MouseCursor, # noqa: F401
|
|
16
|
-
MouseCursorException, # noqa: F401
|
|
17
|
-
NoSuchDisplayException, # noqa: F401
|
|
18
|
-
WindowException, # noqa: F401
|
|
19
19
|
_PlatformEventHandler,
|
|
20
20
|
_ViewEventHandler,
|
|
21
21
|
)
|
|
@@ -26,11 +26,13 @@ ViewEventHandler = _ViewEventHandler
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
class HeadlessWindow(BaseWindow):
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
egl_display_connection = None
|
|
30
|
+
egl_surface = None
|
|
31
31
|
|
|
32
32
|
def _recreate(self, changes: Sequence[str]) -> None:
|
|
33
|
-
|
|
33
|
+
if 'fullscreen' in changes:
|
|
34
|
+
self.dispatch_event('_on_internal_resize', self._width, self._height)
|
|
35
|
+
self.dispatch_event('on_expose')
|
|
34
36
|
|
|
35
37
|
def flip(self) -> None:
|
|
36
38
|
if self.context:
|
|
@@ -40,6 +42,10 @@ class HeadlessWindow(BaseWindow):
|
|
|
40
42
|
if self.context:
|
|
41
43
|
self.context.set_current()
|
|
42
44
|
|
|
45
|
+
def before_draw(self) -> None:
|
|
46
|
+
if self.context:
|
|
47
|
+
self.context.before_draw()
|
|
48
|
+
|
|
43
49
|
def set_caption(self, caption: str) -> None:
|
|
44
50
|
pass
|
|
45
51
|
|
|
@@ -65,7 +71,12 @@ class HeadlessWindow(BaseWindow):
|
|
|
65
71
|
pass
|
|
66
72
|
|
|
67
73
|
def set_visible(self, visible: bool = True) -> None:
|
|
68
|
-
|
|
74
|
+
if visible:
|
|
75
|
+
self.dispatch_event('_on_internal_resize', self._width, self._height)
|
|
76
|
+
self.dispatch_event('on_show')
|
|
77
|
+
self.dispatch_event('on_expose')
|
|
78
|
+
else:
|
|
79
|
+
self.dispatch_event('on_hide')
|
|
69
80
|
|
|
70
81
|
def minimize(self) -> None:
|
|
71
82
|
pass
|
|
@@ -76,7 +87,7 @@ class HeadlessWindow(BaseWindow):
|
|
|
76
87
|
def set_vsync(self, vsync: bool) -> None:
|
|
77
88
|
pass
|
|
78
89
|
|
|
79
|
-
def
|
|
90
|
+
def set_mouse_cursor_platform_visible(self, platform_visible: bool | None = None) -> None:
|
|
80
91
|
pass
|
|
81
92
|
|
|
82
93
|
def set_exclusive_mouse(self, exclusive: bool = True) -> None:
|
|
@@ -96,20 +107,25 @@ class HeadlessWindow(BaseWindow):
|
|
|
96
107
|
pass
|
|
97
108
|
|
|
98
109
|
def _create(self) -> None:
|
|
99
|
-
self.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
pbuffer_attribs = (
|
|
103
|
-
pbuffer_attrib_array = (
|
|
104
|
-
self.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
self.context.attach(self
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
self.egl_display_connection = self.display._display_connection # noqa: SLF001
|
|
111
|
+
if pyglet.options.backend and not self.egl_surface and not self._shadow:
|
|
112
|
+
self._assign_config()
|
|
113
|
+
pbuffer_attribs = (EGL_WIDTH, self._width, EGL_HEIGHT, self._height, EGL_NONE)
|
|
114
|
+
pbuffer_attrib_array = (EGLint * len(pbuffer_attribs))(*pbuffer_attribs)
|
|
115
|
+
self.egl_surface = eglCreatePbufferSurface(self.egl_display_connection,
|
|
116
|
+
self.config._egl_config, # noqa: SLF001
|
|
117
|
+
pbuffer_attrib_array)
|
|
118
|
+
|
|
119
|
+
if not self.egl_surface:
|
|
120
|
+
raise Exception("Failed to create EGL Surface.")
|
|
121
|
+
self.context.attach(self)
|
|
122
|
+
|
|
123
|
+
def close(self) -> None:
|
|
124
|
+
super().close()
|
|
125
|
+
if self.egl_surface:
|
|
126
|
+
eglDestroySurface(self.egl_display_connection, self.egl_surface)
|
|
127
|
+
self.egl_surface = None
|
|
128
|
+
self.egl_display_connection = None
|
|
113
129
|
|
|
114
130
|
|
|
115
131
|
__all__ = ['HeadlessWindow']
|
pyglet/window/key.py
CHANGED
pyglet/window/mouse.py
CHANGED
|
@@ -47,7 +47,7 @@ class MouseStateHandler:
|
|
|
47
47
|
"""
|
|
48
48
|
|
|
49
49
|
def __init__(self) -> None: # noqa: D107
|
|
50
|
-
self.data = {
|
|
50
|
+
self.data: dict[int | str, int | bool] = {
|
|
51
51
|
'x': 0,
|
|
52
52
|
'y': 0,
|
|
53
53
|
}
|
|
@@ -69,7 +69,7 @@ class MouseStateHandler:
|
|
|
69
69
|
self.data['x'] = x
|
|
70
70
|
self.data['y'] = y
|
|
71
71
|
|
|
72
|
-
def __getitem__(self, key: str) -> int | bool:
|
|
72
|
+
def __getitem__(self, key: str | int) -> int | bool:
|
|
73
73
|
return self.data.get(key, False)
|
|
74
74
|
|
|
75
75
|
def __getattr__(self, item: str) -> int:
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import ctypes
|
|
4
|
+
import mmap
|
|
5
|
+
import os
|
|
6
|
+
from ctypes import create_string_buffer
|
|
7
|
+
from typing import Sequence
|
|
8
|
+
|
|
9
|
+
import pyglet
|
|
10
|
+
|
|
11
|
+
from pyglet.event import EventDispatcher
|
|
12
|
+
from pyglet.libs.linux.egl import egl
|
|
13
|
+
from pyglet.libs.linux.wayland import xkbcommon
|
|
14
|
+
from pyglet.window import BaseWindow, _PlatformEventHandler, _ViewEventHandler, key, mouse
|
|
15
|
+
from pyglet.libs.linux.wayland.client import Client, Interface
|
|
16
|
+
from pyglet.libs.linux.wayland.wayland_egl import *
|
|
17
|
+
|
|
18
|
+
# Platform event data is single item, so use platform event handler directly.
|
|
19
|
+
WaylandEventHandler = _PlatformEventHandler
|
|
20
|
+
ViewEventHandler = _ViewEventHandler
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# symbol,ctrl -> motion mapping
|
|
24
|
+
_motion_map: dict[tuple[int, bool], int] = {
|
|
25
|
+
(key.UP, False): key.MOTION_UP,
|
|
26
|
+
(key.RIGHT, False): key.MOTION_RIGHT,
|
|
27
|
+
(key.DOWN, False): key.MOTION_DOWN,
|
|
28
|
+
(key.LEFT, False): key.MOTION_LEFT,
|
|
29
|
+
(key.RIGHT, True): key.MOTION_NEXT_WORD,
|
|
30
|
+
(key.LEFT, True): key.MOTION_PREVIOUS_WORD,
|
|
31
|
+
(key.HOME, False): key.MOTION_BEGINNING_OF_LINE,
|
|
32
|
+
(key.END, False): key.MOTION_END_OF_LINE,
|
|
33
|
+
(key.PAGEUP, False): key.MOTION_PREVIOUS_PAGE,
|
|
34
|
+
(key.PAGEDOWN, False): key.MOTION_NEXT_PAGE,
|
|
35
|
+
(key.HOME, True): key.MOTION_BEGINNING_OF_FILE,
|
|
36
|
+
(key.END, True): key.MOTION_END_OF_FILE,
|
|
37
|
+
(key.BACKSPACE, False): key.MOTION_BACKSPACE,
|
|
38
|
+
(key.DELETE, False): key.MOTION_DELETE,
|
|
39
|
+
(key.C, True): key.MOTION_COPY,
|
|
40
|
+
(key.V, True): key.MOTION_PASTE,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
_modifier_map: dict[int, int] = {
|
|
44
|
+
key.LCTRL: key.MOD_CTRL, key.RCTRL: key.MOD_CTRL,
|
|
45
|
+
key.LSHIFT: key.MOD_SHIFT, key.RSHIFT: key.MOD_SHIFT,
|
|
46
|
+
key.LALT: key.MOD_ALT, key.RALT: key.MOD_ALT,
|
|
47
|
+
key.LWINDOWS: key.MOD_WINDOWS, key.RWINDOWS: key.MOD_WINDOWS,
|
|
48
|
+
key.CAPSLOCK: key.MOD_CAPSLOCK,
|
|
49
|
+
key.NUMLOCK: key.MOD_NUMLOCK,
|
|
50
|
+
key.SCROLLLOCK: key.MOD_SCROLLLOCK,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class WaylandWindow(BaseWindow):
|
|
55
|
+
|
|
56
|
+
egl_display_connection = None
|
|
57
|
+
egl_surface = None
|
|
58
|
+
|
|
59
|
+
_protocols = ['/usr/share/wayland/wayland.xml', '/usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml']
|
|
60
|
+
client: Client = None
|
|
61
|
+
wl_compositor: Interface
|
|
62
|
+
wl_surface: Interface
|
|
63
|
+
xdg_wm_base: Interface
|
|
64
|
+
wdg_surface: Interface
|
|
65
|
+
xdg_toplevel: Interface
|
|
66
|
+
wl_pointer: Interface
|
|
67
|
+
|
|
68
|
+
def __init__(self, *args, **kwargs) -> None: # noqa: ANN002, ANN003
|
|
69
|
+
self._mouse_buttons = 0
|
|
70
|
+
self._key_modifiers = 0
|
|
71
|
+
self._has_keyboard_focus = False
|
|
72
|
+
|
|
73
|
+
self.xkb_context = xkbcommon.xkb_context_new(xkbcommon.enum_xkb_context_flags(xkbcommon.XKB_CONTEXT_NO_FLAGS))
|
|
74
|
+
self.xkb_keymap = None
|
|
75
|
+
self.xkb_state_withmod = None # updated when modifiers are pressed
|
|
76
|
+
self.xkb_state_default = None # never gets updated (for reference)
|
|
77
|
+
self._text_buffer = create_string_buffer(4)
|
|
78
|
+
super().__init__(*args, **kwargs)
|
|
79
|
+
|
|
80
|
+
def _recreate(self, changes: Sequence[str]) -> None:
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
def flip(self) -> None:
|
|
84
|
+
if self.context:
|
|
85
|
+
self.context.flip()
|
|
86
|
+
|
|
87
|
+
def switch_to(self) -> None:
|
|
88
|
+
if self.context:
|
|
89
|
+
self.context.set_current()
|
|
90
|
+
|
|
91
|
+
def set_caption(self, caption: str) -> None:
|
|
92
|
+
pass
|
|
93
|
+
|
|
94
|
+
def set_minimum_size(self, width: int, height: int) -> None:
|
|
95
|
+
pass
|
|
96
|
+
|
|
97
|
+
def set_maximum_size(self, width: int, height: int) -> None:
|
|
98
|
+
pass
|
|
99
|
+
|
|
100
|
+
def set_size(self, width: int, height: int) -> None:
|
|
101
|
+
pass
|
|
102
|
+
|
|
103
|
+
def get_size(self) -> tuple[int, int]:
|
|
104
|
+
return self._width, self._height
|
|
105
|
+
|
|
106
|
+
def set_location(self, x: int, y: int) -> None:
|
|
107
|
+
pass
|
|
108
|
+
|
|
109
|
+
def get_location(self) -> None:
|
|
110
|
+
pass
|
|
111
|
+
|
|
112
|
+
def activate(self) -> None:
|
|
113
|
+
pass
|
|
114
|
+
|
|
115
|
+
def set_visible(self, visible: bool = True) -> None:
|
|
116
|
+
pass
|
|
117
|
+
|
|
118
|
+
def minimize(self) -> None:
|
|
119
|
+
pass
|
|
120
|
+
|
|
121
|
+
def maximize(self) -> None:
|
|
122
|
+
pass
|
|
123
|
+
|
|
124
|
+
def set_vsync(self, vsync: bool) -> None:
|
|
125
|
+
pass
|
|
126
|
+
|
|
127
|
+
def set_mouse_platform_visible(self, platform_visible: bool | None = None) -> None:
|
|
128
|
+
pass
|
|
129
|
+
|
|
130
|
+
def set_exclusive_mouse(self, exclusive: bool = True) -> None:
|
|
131
|
+
pass
|
|
132
|
+
|
|
133
|
+
def set_exclusive_keyboard(self, exclusive: bool = True) -> None:
|
|
134
|
+
pass
|
|
135
|
+
|
|
136
|
+
def get_system_mouse_cursor(self, name: str) -> None:
|
|
137
|
+
pass
|
|
138
|
+
|
|
139
|
+
def dispatch_events(self) -> None:
|
|
140
|
+
while self._event_queue:
|
|
141
|
+
EventDispatcher.dispatch_event(self, *self._event_queue.pop(0))
|
|
142
|
+
|
|
143
|
+
def dispatch_pending_events(self) -> None:
|
|
144
|
+
pass
|
|
145
|
+
|
|
146
|
+
def before_draw(self) -> None:
|
|
147
|
+
pass
|
|
148
|
+
|
|
149
|
+
def _create(self) -> None:
|
|
150
|
+
self.egl_display_connection = self.display.display_connection
|
|
151
|
+
|
|
152
|
+
self._dpi = self._screen.get_dpi()
|
|
153
|
+
self._scale = self._screen.get_scale() if pyglet.options.dpi_scaling == "stretch" else 1.0
|
|
154
|
+
|
|
155
|
+
# if self._fullscreen:
|
|
156
|
+
# width, height = self.screen.width, self.screen.height
|
|
157
|
+
# else:
|
|
158
|
+
# width, height = self._width, self._height
|
|
159
|
+
# self._view_x = self._view_y = 0
|
|
160
|
+
# if pyglet.options.dpi_scaling in ("scaled", "stretch"):
|
|
161
|
+
# w, h = self.get_requested_size()
|
|
162
|
+
# self._width = width = int(w * self.scale)
|
|
163
|
+
# self._height = height = int(h * self.scale)
|
|
164
|
+
self.client = self.display.client
|
|
165
|
+
self.client.sync()
|
|
166
|
+
|
|
167
|
+
self.wl_compositor = self.client.protocol_dict['wayland'].bind_interface('wl_compositor')
|
|
168
|
+
|
|
169
|
+
self.wl_surface = self.wl_compositor.create_surface(next(self.client.oid_pool))
|
|
170
|
+
self.wl_surface.set_handler('preferred_buffer_scale', self.wl_surface_preferred_buffer_scale_handler)
|
|
171
|
+
|
|
172
|
+
self.xdg_wm_base = self.client.protocol_dict['xdg_shell'].bind_interface('xdg_wm_base')
|
|
173
|
+
self.xdg_wm_base.set_handler('ping', self.xdg_base_ping_handler)
|
|
174
|
+
|
|
175
|
+
self.xdg_surface = self.xdg_wm_base.get_xdg_surface(next(self.client.oid_pool), self.wl_surface)
|
|
176
|
+
self.xdg_surface.set_handler('configure', self.xdg_surface_configure_handler)
|
|
177
|
+
|
|
178
|
+
self.xdg_toplevel = self.xdg_surface.get_toplevel(next(self.client.oid_pool))
|
|
179
|
+
self.xdg_toplevel.set_handlers(
|
|
180
|
+
configure=self.xdg_toplevel_configure_handler,
|
|
181
|
+
configure_bounds=self.xdg_toplevel_configure_bounds,
|
|
182
|
+
close=self.xdg_toplevel_close_handler,
|
|
183
|
+
)
|
|
184
|
+
self.xdg_toplevel.set_parent(None)
|
|
185
|
+
self.xdg_toplevel.set_app_id(self._caption)
|
|
186
|
+
|
|
187
|
+
self.wl_seat = self.client.protocol_dict['wayland'].bind_interface('wl_seat')
|
|
188
|
+
self.wl_pointer = self.wl_seat.get_pointer(next(self.client.oid_pool))
|
|
189
|
+
self.wl_pointer.set_handlers(motion=self.wl_pointer_motion_handler,
|
|
190
|
+
button=self.wl_pointer_button_handler,
|
|
191
|
+
axis_value120=self.wl_pointer_axis_value120_handler,
|
|
192
|
+
enter=self.wl_pointer_enter_handler,
|
|
193
|
+
leave=self.wl_pointer_leave_handler)
|
|
194
|
+
# frame', self.wl_pointer_frame_handler)
|
|
195
|
+
|
|
196
|
+
self.wl_keyboard = self.wl_seat.get_keyboard(next(self.client.oid_pool))
|
|
197
|
+
self.wl_keyboard.set_handlers(
|
|
198
|
+
keymap=self.wl_keyboard_keymap_handler,
|
|
199
|
+
modifiers=self.wl_keyboard_modifiers_handler,
|
|
200
|
+
key=self.wl_keyboard_key_handler,
|
|
201
|
+
enter=self.wl_keyboard_enter_handler,
|
|
202
|
+
leave=self.wl_keyboard_leave_handler,
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
# Used for software render?
|
|
206
|
+
# import os, tempfile
|
|
207
|
+
# fd, name = tempfile.mkstemp()
|
|
208
|
+
# _data_size = self._width * self._height * 4 # width x height x rgba
|
|
209
|
+
# os.write(fd, b'\xee\x33\x33\xee' * self._width * self._height) # BGRA
|
|
210
|
+
#
|
|
211
|
+
# wl_shm = self.client.protocol_dict['wayland'].bind_interface('wl_shm')
|
|
212
|
+
# wl_shm_pool = wl_shm.create_pool(next(self.client.oid_pool), fd, _data_size)
|
|
213
|
+
# wl_buffer = wl_shm_pool.create_buffer(next(self.client.oid_pool), 0, self._width, self._height,
|
|
214
|
+
# self._width * 4, 0)
|
|
215
|
+
# self.wl_surface.attach(wl_buffer.oid, 0, 0)
|
|
216
|
+
|
|
217
|
+
if not self.egl_surface and not self._shadow:
|
|
218
|
+
# An EGL window needs to be created from a Wayland surface,
|
|
219
|
+
egl_window = wl_egl_window_create(self.wl_surface._proxy, self._width, self._height)
|
|
220
|
+
|
|
221
|
+
if not egl_window:
|
|
222
|
+
err = egl.eglGetError()
|
|
223
|
+
msg = f"Failed to create EGL wayland window. Error: 0x{err:04x}"
|
|
224
|
+
raise Exception(msg)
|
|
225
|
+
|
|
226
|
+
self._assign_config()
|
|
227
|
+
|
|
228
|
+
self.egl_surface = egl.eglCreateWindowSurface(
|
|
229
|
+
self.egl_display_connection,
|
|
230
|
+
self.config._egl_config,
|
|
231
|
+
egl_window,
|
|
232
|
+
None,
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
if not self.egl_surface:
|
|
236
|
+
err = egl.eglGetError()
|
|
237
|
+
msg = f"Failed to create egl surface. Error: 0x{err:04x}"
|
|
238
|
+
raise Exception(msg)
|
|
239
|
+
|
|
240
|
+
# self.canvas = WaylandCanvas(self.display, self.egl_surface)
|
|
241
|
+
self.context.attach(self)
|
|
242
|
+
self.dispatch_event('_on_internal_resize', self._width, self._height)
|
|
243
|
+
|
|
244
|
+
# Start Wayland event handlers
|
|
245
|
+
|
|
246
|
+
def xdg_base_ping_handler(self, serial):
|
|
247
|
+
"""Keep-alive response to the ping event"""
|
|
248
|
+
self.xdg_wm_base.pong(serial)
|
|
249
|
+
|
|
250
|
+
def wl_surface_preferred_buffer_scale_handler(self, factor):
|
|
251
|
+
print(f" --> wl_surface scaling: {factor}")
|
|
252
|
+
|
|
253
|
+
def xdg_toplevel_configure_handler(self, width, height, states):
|
|
254
|
+
print(" --> xdg_toplevel configure event", width, height, states)
|
|
255
|
+
|
|
256
|
+
def xdg_toplevel_configure_bounds(self, width, height):
|
|
257
|
+
print(" --> xdg_toplevel_configure_bounds event", width, height)
|
|
258
|
+
|
|
259
|
+
def xdg_toplevel_close_handler(self):
|
|
260
|
+
self.dispatch_event('on_close')
|
|
261
|
+
|
|
262
|
+
def xdg_surface_configure_handler(self, *args):
|
|
263
|
+
print(" --> xdg_surface configure event", args)
|
|
264
|
+
self.xdg_surface.ack_configure(args[0])
|
|
265
|
+
|
|
266
|
+
def wl_pointer_button_handler(self, serial, time, button, state):
|
|
267
|
+
mouse_button = {0x110: mouse.LEFT,
|
|
268
|
+
0x111: mouse.RIGHT,
|
|
269
|
+
0x112: mouse.MIDDLE,
|
|
270
|
+
0x113: mouse.MOUSE4,
|
|
271
|
+
0x114: mouse.MOUSE5}[button]
|
|
272
|
+
|
|
273
|
+
if self.wl_pointer.enums['button_state'][state].name == 'pressed':
|
|
274
|
+
self._mouse_buttons |= mouse_button
|
|
275
|
+
self.dispatch_event('on_mouse_press', self._mouse_x, self._mouse_y, mouse_button, self._key_modifiers)
|
|
276
|
+
|
|
277
|
+
elif self.wl_pointer.enums['button_state'][state].name == 'released':
|
|
278
|
+
self._mouse_buttons &= ~mouse_button
|
|
279
|
+
self.dispatch_event('on_mouse_release', self._mouse_x, self._mouse_y, mouse_button, self._key_modifiers)
|
|
280
|
+
|
|
281
|
+
def wl_pointer_motion_handler(self, time, surface_x, surface_y):
|
|
282
|
+
x = surface_x / self._scale
|
|
283
|
+
# TODO: isolate flipped-Y to a single value
|
|
284
|
+
y = self.height - surface_y / self._scale
|
|
285
|
+
dx = x - self._mouse_x
|
|
286
|
+
dy = y - self._mouse_y
|
|
287
|
+
self._mouse_x = x
|
|
288
|
+
self._mouse_y = y
|
|
289
|
+
|
|
290
|
+
if self._mouse_buttons:
|
|
291
|
+
self.dispatch_event('on_mouse_drag', x, y, dx, dy, self._mouse_buttons, self._key_modifiers)
|
|
292
|
+
else:
|
|
293
|
+
self.dispatch_event('on_mouse_motion', x, y, dx, dy)
|
|
294
|
+
|
|
295
|
+
def wl_pointer_axis_value120_handler(self, axis, value120):
|
|
296
|
+
# TODO: combine discreet events & dispatch with wl_pointer frame event.
|
|
297
|
+
# 0: vertical axis, 1: horizontal axis
|
|
298
|
+
axis = self.wl_pointer.enums['axis'][axis].value
|
|
299
|
+
scroll_x, scroll_y = {0: (0, -1), 1: (-1, 0)}[axis]
|
|
300
|
+
scroll_x *= (value120 / 120)
|
|
301
|
+
scroll_y *= (value120 / 120)
|
|
302
|
+
self.dispatch_event('on_mouse_scroll', self._mouse_x, self._mouse_y, scroll_x, scroll_y)
|
|
303
|
+
|
|
304
|
+
# def wl_pointer_frame_handler(self):
|
|
305
|
+
# print("end of pointer frame")
|
|
306
|
+
|
|
307
|
+
def wl_pointer_enter_handler(self, serial, surface, surface_x, surface_y):
|
|
308
|
+
# TODO: make sure it's the main app surface
|
|
309
|
+
self._mouse_in_window = True
|
|
310
|
+
self.dispatch_event('on_mouse_enter', surface_x, surface_y)
|
|
311
|
+
|
|
312
|
+
def wl_pointer_leave_handler(self, serial, surface):
|
|
313
|
+
# TODO: make sure it's the main app surface
|
|
314
|
+
self._mouse_in_window = False
|
|
315
|
+
self.dispatch_event('on_mouse_leave', self._mouse_x, self._mouse_y)
|
|
316
|
+
|
|
317
|
+
def wl_keyboard_enter_handler(self, serial, surface, keys):
|
|
318
|
+
# TODO: process held keys?
|
|
319
|
+
self._has_keyboard_focus = True
|
|
320
|
+
|
|
321
|
+
def wl_keyboard_leave_handler(self, serial, surface):
|
|
322
|
+
self._has_keyboard_focus = False
|
|
323
|
+
|
|
324
|
+
def wl_keyboard_keymap_handler(self, fmt, fd, size):
|
|
325
|
+
# Does not work reliably without mapping:
|
|
326
|
+
mmap_obj = mmap.mmap(fd, size, prot=mmap.PROT_READ, flags=mmap.MAP_PRIVATE)
|
|
327
|
+
data = ctypes.create_string_buffer(mmap_obj.read())
|
|
328
|
+
os.close(fd)
|
|
329
|
+
|
|
330
|
+
# Note: There is only one format, so no need to check:
|
|
331
|
+
# fmt = self.wl_keyboard.enums['keymap_format'][fmt].name
|
|
332
|
+
fmt = xkbcommon.enum_xkb_keymap_format(xkbcommon.XKB_KEYMAP_FORMAT_TEXT_V1)
|
|
333
|
+
flags = xkbcommon.enum_xkb_keymap_compile_flags(xkbcommon.XKB_KEYMAP_COMPILE_NO_FLAGS)
|
|
334
|
+
if xkb_keymap := xkbcommon.xkb_keymap_new_from_string(self.xkb_context, data, fmt, flags):
|
|
335
|
+
self.xkb_keymap = xkb_keymap
|
|
336
|
+
self.xkb_state_withmod = xkbcommon.xkb_state_new(self.xkb_keymap)
|
|
337
|
+
self.xkb_state_default = xkbcommon.xkb_state_new(self.xkb_keymap)
|
|
338
|
+
|
|
339
|
+
def wl_keyboard_modifiers_handler(self, serial, mods_depressed, mods_latched, mods_locked, group):
|
|
340
|
+
xkbcommon.xkb_state_update_mask(
|
|
341
|
+
self.xkb_state_withmod, mods_depressed, mods_latched, mods_locked, group, group, group)
|
|
342
|
+
|
|
343
|
+
def wl_keyboard_key_handler(self, serial, time, keycode, state):
|
|
344
|
+
keycode += 8 # xkbcommon expects +8
|
|
345
|
+
symbol = xkbcommon.xkb_state_key_get_one_sym(self.xkb_state_default, keycode)
|
|
346
|
+
modifier = _modifier_map.get(symbol, 0)
|
|
347
|
+
|
|
348
|
+
# released 0, pressed 1, repeated 2
|
|
349
|
+
state_name = self.wl_keyboard.enums['key_state'][state].name
|
|
350
|
+
|
|
351
|
+
if state_name == 'pressed':
|
|
352
|
+
_size = xkbcommon.xkb_state_key_get_utf8(self.xkb_state_withmod, keycode, self._text_buffer, 4)
|
|
353
|
+
character = self._text_buffer[:_size].decode()
|
|
354
|
+
|
|
355
|
+
self.dispatch_event('on_text', character)
|
|
356
|
+
self.dispatch_event('on_key_press', symbol, self._key_modifiers)
|
|
357
|
+
self._key_modifiers |= modifier
|
|
358
|
+
|
|
359
|
+
if self._key_modifiers & key.MOD_ALT:
|
|
360
|
+
return
|
|
361
|
+
|
|
362
|
+
ctrl = self._key_modifiers & key.MOD_CTRL != 0
|
|
363
|
+
shft = self._key_modifiers & key.MOD_SHIFT != 0
|
|
364
|
+
if motion := _motion_map.get((symbol, ctrl), None):
|
|
365
|
+
if shft:
|
|
366
|
+
self.dispatch_event('on_text_motion_select', motion)
|
|
367
|
+
else:
|
|
368
|
+
self.dispatch_event('on_text_motion', motion)
|
|
369
|
+
|
|
370
|
+
if state_name == 'released':
|
|
371
|
+
self.dispatch_event('on_key_release', symbol, self._key_modifiers)
|
|
372
|
+
self._key_modifiers &= ~modifier
|
|
373
|
+
|
|
374
|
+
# End Wayland event handlers
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
__all__ = ['WaylandWindow']
|