pyglet 2.1.6__py3-none-any.whl → 2.1.8__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 +27 -42
- pyglet/app/base.py +2 -2
- pyglet/clock.py +1 -1
- pyglet/display/base.py +31 -21
- pyglet/display/cocoa.py +25 -1
- pyglet/display/headless.py +1 -1
- pyglet/display/win32.py +134 -18
- pyglet/display/xlib.py +285 -70
- pyglet/event.py +17 -1
- pyglet/experimental/README.md +1 -1
- pyglet/experimental/jobs.py +1 -1
- pyglet/experimental/multitexture_sprite.py +2 -2
- pyglet/font/__init__.py +1 -1
- pyglet/font/base.py +8 -5
- pyglet/font/dwrite/__init__.py +13 -8
- pyglet/font/dwrite/dwrite_lib.py +1 -1
- pyglet/font/user.py +1 -1
- pyglet/gl/base.py +8 -4
- pyglet/gl/cocoa.py +4 -0
- pyglet/gl/gl.py +4 -3
- pyglet/gl/gl.pyi +2320 -0
- pyglet/gl/gl_compat.py +7 -18
- pyglet/gl/gl_compat.pyi +3097 -0
- pyglet/gl/xlib.py +24 -0
- pyglet/graphics/vertexbuffer.py +1 -1
- pyglet/gui/frame.py +2 -2
- pyglet/gui/widgets.py +1 -1
- pyglet/image/__init__.py +3 -3
- pyglet/image/buffer.py +3 -3
- pyglet/input/base.py +8 -8
- pyglet/input/linux/evdev.py +1 -1
- pyglet/libs/darwin/cocoapy/cocoalibs.py +3 -1
- pyglet/libs/win32/__init__.py +12 -0
- pyglet/libs/win32/constants.py +4 -0
- pyglet/libs/win32/types.py +97 -0
- pyglet/libs/x11/xrandr.py +166 -0
- pyglet/libs/x11/xrender.py +43 -0
- pyglet/libs/x11/xsync.py +43 -0
- pyglet/math.py +40 -49
- pyglet/media/buffered_logger.py +1 -1
- pyglet/media/codecs/ffmpeg.py +18 -34
- pyglet/media/codecs/gstreamer.py +3 -3
- pyglet/media/codecs/pyogg.py +1 -1
- pyglet/media/codecs/wave.py +6 -0
- pyglet/media/codecs/wmf.py +33 -7
- pyglet/media/devices/win32.py +1 -1
- pyglet/media/drivers/base.py +1 -1
- pyglet/media/drivers/directsound/interface.py +4 -0
- pyglet/media/drivers/listener.py +2 -2
- pyglet/media/drivers/xaudio2/interface.py +6 -2
- pyglet/media/drivers/xaudio2/lib_xaudio2.py +1 -1
- pyglet/media/instrumentation.py +2 -2
- pyglet/media/player.py +2 -2
- pyglet/media/player_worker_thread.py +1 -1
- pyglet/media/synthesis.py +1 -1
- pyglet/model/codecs/gltf.py +1 -1
- pyglet/shapes.py +1 -1
- pyglet/sprite.py +1 -1
- pyglet/text/caret.py +44 -5
- pyglet/text/layout/base.py +3 -3
- pyglet/util.py +1 -1
- pyglet/window/__init__.py +54 -14
- pyglet/window/cocoa/__init__.py +27 -0
- pyglet/window/mouse.py +11 -1
- pyglet/window/win32/__init__.py +40 -14
- pyglet/window/xlib/__init__.py +21 -7
- {pyglet-2.1.6.dist-info → pyglet-2.1.8.dist-info}/METADATA +1 -1
- {pyglet-2.1.6.dist-info → pyglet-2.1.8.dist-info}/RECORD +70 -66
- {pyglet-2.1.6.dist-info → pyglet-2.1.8.dist-info}/LICENSE +0 -0
- {pyglet-2.1.6.dist-info → pyglet-2.1.8.dist-info}/WHEEL +0 -0
pyglet/gl/xlib.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import warnings
|
|
4
|
+
from _ctypes import _Pointer
|
|
4
5
|
from ctypes import POINTER, byref, c_int, c_uint, cast
|
|
5
6
|
from typing import TYPE_CHECKING, NoReturn
|
|
6
7
|
|
|
@@ -13,6 +14,8 @@ from pyglet.gl import lib
|
|
|
13
14
|
from pyglet.gl.base import Config, DisplayConfig, Context
|
|
14
15
|
|
|
15
16
|
from pyglet.display.xlib import XlibCanvas
|
|
17
|
+
from pyglet.libs.x11 import xlib
|
|
18
|
+
from pyglet.libs.x11.xrender import XRenderFindVisualFormat
|
|
16
19
|
|
|
17
20
|
if TYPE_CHECKING:
|
|
18
21
|
from pyglet.libs.x11.xlib import Display
|
|
@@ -52,6 +55,10 @@ class XlibConfig(Config): # noqa: D101
|
|
|
52
55
|
|
|
53
56
|
result = [XlibDisplayConfig(canvas, info, c, self) for c in configs]
|
|
54
57
|
|
|
58
|
+
# If we intend to have a transparent framebuffer.
|
|
59
|
+
if self.transparent_framebuffer:
|
|
60
|
+
result = [fb_cf for fb_cf in result if fb_cf.transparent]
|
|
61
|
+
|
|
55
62
|
# Can't free array until all XlibGLConfig's are GC'd. Too much
|
|
56
63
|
# hassle, live with leak. XXX
|
|
57
64
|
# xlib.XFree(configs)
|
|
@@ -102,6 +109,7 @@ class XlibDisplayConfig(DisplayConfig): # noqa: D101
|
|
|
102
109
|
|
|
103
110
|
self.glx_info = info
|
|
104
111
|
self.fbconfig = fbconfig
|
|
112
|
+
self.transparent = False
|
|
105
113
|
|
|
106
114
|
for name, attr in self.attribute_ids.items():
|
|
107
115
|
value = c_int()
|
|
@@ -110,6 +118,22 @@ class XlibDisplayConfig(DisplayConfig): # noqa: D101
|
|
|
110
118
|
if result >= 0:
|
|
111
119
|
setattr(self, name, value.value)
|
|
112
120
|
|
|
121
|
+
# If user intends for a transparent framebuffer, the visual info needs to be
|
|
122
|
+
# queried for it. Even if a config supports alpha_size 8 and depth_size 32, there is no
|
|
123
|
+
# guarantee the visual info supports that same configuration.
|
|
124
|
+
if config.transparent_framebuffer:
|
|
125
|
+
xvi_ptr = glx.glXGetVisualFromFBConfig(canvas.display._display, self.fbconfig) # noqa: SLF001
|
|
126
|
+
if xvi_ptr:
|
|
127
|
+
self.transparent = self._is_visual_transparent(xvi_ptr.contents.visual) # noqa: SLF001
|
|
128
|
+
xlib.XFree(xvi_ptr)
|
|
129
|
+
|
|
130
|
+
def _is_visual_transparent(self, visual: _Pointer[xlib.Visual]) -> bool:
|
|
131
|
+
if not XRenderFindVisualFormat:
|
|
132
|
+
return False
|
|
133
|
+
|
|
134
|
+
xrender_format = XRenderFindVisualFormat(self.canvas.display._display, visual)
|
|
135
|
+
return xrender_format and xrender_format.contents.direct.alphaMask != 0
|
|
136
|
+
|
|
113
137
|
def get_visual_info(self) -> glx.XVisualInfo:
|
|
114
138
|
return glx.glXGetVisualFromFBConfig(self.canvas.display._display, self.fbconfig).contents # noqa: SLF001
|
|
115
139
|
|
pyglet/graphics/vertexbuffer.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""OpenGL Buffer Objects.
|
|
2
2
|
|
|
3
|
-
:py:class:`~BufferObject` and a :py:class:`~BackedBufferObject` are
|
|
3
|
+
:py:class:`~BufferObject` and a :py:class:`~BackedBufferObject` are provided.
|
|
4
4
|
The first is a lightweight abstraction over an OpenGL buffer, as created
|
|
5
5
|
with ``glGenBuffers``. The backed buffer object is similar, but provides a
|
|
6
6
|
full mirror of the data in CPU memory. This allows for delayed uploading of
|
pyglet/gui/frame.py
CHANGED
|
@@ -24,7 +24,7 @@ class Frame:
|
|
|
24
24
|
|
|
25
25
|
Args:
|
|
26
26
|
window:
|
|
27
|
-
The SpatialHash will
|
|
27
|
+
The SpatialHash will receive events from this Window.
|
|
28
28
|
Appropriate events will be passed on to all added Widgets.
|
|
29
29
|
enable:
|
|
30
30
|
Whether to enable frame.
|
|
@@ -168,7 +168,7 @@ class MovableFrame(Frame):
|
|
|
168
168
|
|
|
169
169
|
Args:
|
|
170
170
|
window:
|
|
171
|
-
The SpatialHash will
|
|
171
|
+
The SpatialHash will receive events from this Window.
|
|
172
172
|
Appropriate events will be passed on to all added Widgets.
|
|
173
173
|
enable:
|
|
174
174
|
Whether to enable frame.
|
pyglet/gui/widgets.py
CHANGED
|
@@ -601,7 +601,7 @@ class TextEntry(WidgetBase):
|
|
|
601
601
|
self._caret.on_text_motion_select(motion)
|
|
602
602
|
|
|
603
603
|
def on_commit(self, widget: TextEntry, text: str) -> None:
|
|
604
|
-
"""Event: dispatches the current text when
|
|
604
|
+
"""Event: dispatches the current text when committed via Enter/Return key."""
|
|
605
605
|
|
|
606
606
|
|
|
607
607
|
TextEntry.register_event_type('on_commit')
|
pyglet/image/__init__.py
CHANGED
|
@@ -556,7 +556,7 @@ class ImageData(AbstractImage):
|
|
|
556
556
|
Note:
|
|
557
557
|
Conversion to another format is done on the CPU, and can be
|
|
558
558
|
somewhat costly for larger images. Consider performing conversion
|
|
559
|
-
at load time for framerate sensitive
|
|
559
|
+
at load time for framerate sensitive applications.
|
|
560
560
|
"""
|
|
561
561
|
fmt = fmt or self._desired_format
|
|
562
562
|
pitch = pitch or self._current_pitch
|
|
@@ -1201,7 +1201,7 @@ class Texture(AbstractImage):
|
|
|
1201
1201
|
layer: int = 0, access: int = GL_READ_WRITE, fmt: int = GL_RGBA32F):
|
|
1202
1202
|
"""Bind as an ImageTexture for use with a :py:class:`~pyglet.shader.ComputeShaderProgram`.
|
|
1203
1203
|
|
|
1204
|
-
.. note:: OpenGL 4.3, or 4.2 with the GL_ARB_compute_shader
|
|
1204
|
+
.. note:: OpenGL 4.3, or 4.2 with the GL_ARB_compute_shader extension is required.
|
|
1205
1205
|
"""
|
|
1206
1206
|
glBindImageTexture(unit, self.id, level, layered, layer, access, fmt)
|
|
1207
1207
|
|
|
@@ -1211,7 +1211,7 @@ class Texture(AbstractImage):
|
|
|
1211
1211
|
fmt: int = GL_RGBA, blank_data: bool = True) -> Texture:
|
|
1212
1212
|
"""Create a Texture
|
|
1213
1213
|
|
|
1214
|
-
Create a Texture with the specified
|
|
1214
|
+
Create a Texture with the specified dimensions, target and format.
|
|
1215
1215
|
On return, the texture will be bound.
|
|
1216
1216
|
|
|
1217
1217
|
Args:
|
pyglet/image/buffer.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""OpenGL Framebuffer abstractions.
|
|
2
2
|
|
|
3
3
|
This module provides classes for working with Framebuffers & Renderbuffers
|
|
4
|
-
and their attachments.
|
|
4
|
+
and their attachments. Attachments can be pyglet Texture objects, which allows
|
|
5
5
|
easily accessing their data, saving to disk, etc. Renderbuffers can be used
|
|
6
6
|
if you don't need to access their data at a later time. For example::
|
|
7
7
|
|
|
@@ -40,7 +40,7 @@ if TYPE_CHECKING:
|
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
def get_max_color_attachments() -> int:
|
|
43
|
-
"""Get the maximum allow Framebuffer Color
|
|
43
|
+
"""Get the maximum allow Framebuffer Color attachments."""
|
|
44
44
|
number = GLint()
|
|
45
45
|
glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, number)
|
|
46
46
|
return number.value
|
|
@@ -144,7 +144,7 @@ class Framebuffer:
|
|
|
144
144
|
|
|
145
145
|
Unbind should be called to prevent further rendering
|
|
146
146
|
to the framebuffer, or if you wish to access data
|
|
147
|
-
from its Texture
|
|
147
|
+
from its Texture attachments.
|
|
148
148
|
"""
|
|
149
149
|
glBindFramebuffer(self.target, 0)
|
|
150
150
|
|
pyglet/input/base.py
CHANGED
|
@@ -71,7 +71,7 @@ class Device:
|
|
|
71
71
|
Args:
|
|
72
72
|
window:
|
|
73
73
|
Optional window to associate with the device. The behaviour
|
|
74
|
-
of this parameter is device and operating system
|
|
74
|
+
of this parameter is device and operating system dependent.
|
|
75
75
|
It can usually be omitted for most devices.
|
|
76
76
|
exclusive:
|
|
77
77
|
If ``True`` the device will be opened exclusively so that no
|
|
@@ -103,7 +103,7 @@ class Device:
|
|
|
103
103
|
string. This is generated from the hardware identifiers,
|
|
104
104
|
and is in the same format as was popularized by SDL2.
|
|
105
105
|
GUIDs differ between platforms, but are generally 32
|
|
106
|
-
|
|
106
|
+
hexadecimal characters.
|
|
107
107
|
"""
|
|
108
108
|
raise NotImplementedError('abstract')
|
|
109
109
|
|
|
@@ -506,7 +506,7 @@ class Controller(EventDispatcher):
|
|
|
506
506
|
"""
|
|
507
507
|
|
|
508
508
|
def __init__(self, device: Device, mapping: dict):
|
|
509
|
-
"""Create a Controller
|
|
509
|
+
"""Create a Controller instance mapped to a Device.
|
|
510
510
|
|
|
511
511
|
.. versionadded:: 2.0
|
|
512
512
|
"""
|
|
@@ -575,7 +575,7 @@ class Controller(EventDispatcher):
|
|
|
575
575
|
A string, currently one of "PS", "XB", or "GENERIC".
|
|
576
576
|
"""
|
|
577
577
|
product_id = None
|
|
578
|
-
# TODO: add more checks for
|
|
578
|
+
# TODO: add more checks for vendor hardware ids.
|
|
579
579
|
|
|
580
580
|
# Windows
|
|
581
581
|
if self.name == 'XINPUTCONTROLLER':
|
|
@@ -672,7 +672,7 @@ class Controller(EventDispatcher):
|
|
|
672
672
|
def _bind_dedicated_hat(self, relation: Relation, control: AbsoluteAxis) -> None:
|
|
673
673
|
# 8-directional hat encoded as a single control (Windows/Mac)
|
|
674
674
|
_vecs = (Vec2(0.0, 1.0), Vec2(1.0, 1.0), Vec2(1.0, 0.0), Vec2(1.0, -1.0), # n, ne, e, se
|
|
675
|
-
|
|
675
|
+
Vec2(0.0, -1.0), Vec2(-1.0, -1.0), Vec2(-1.0, 0.0), Vec2(-1.0, 1.0)) # s, sw, w, nw
|
|
676
676
|
_input_map = {key: val for key, val in zip(range(int(control.min), int(control.max + 1)), _vecs)}
|
|
677
677
|
|
|
678
678
|
# For some Directinput devices:
|
|
@@ -730,8 +730,8 @@ class Controller(EventDispatcher):
|
|
|
730
730
|
|
|
731
731
|
self._bind_axis_control(relation, control, dpname)
|
|
732
732
|
|
|
733
|
-
except IndexError:
|
|
734
|
-
warnings.warn(f"Could not map '{relation}' to '{name}'")
|
|
733
|
+
except (IndexError, AttributeError, KeyError):
|
|
734
|
+
warnings.warn(f"Could not map physical Control '{relation}' to '{name}'")
|
|
735
735
|
continue
|
|
736
736
|
|
|
737
737
|
def open(self, window: None | BaseWindow = None, exclusive: bool = False) -> None:
|
|
@@ -1096,7 +1096,7 @@ class ControllerManager(EventDispatcher):
|
|
|
1096
1096
|
|
|
1097
1097
|
def on_connect(self, controller) -> Controller:
|
|
1098
1098
|
"""A Controller has been connected. If this is
|
|
1099
|
-
a previously
|
|
1099
|
+
a previously disconnected Controller that is
|
|
1100
1100
|
being re-connected, the same Controller instance
|
|
1101
1101
|
will be returned.
|
|
1102
1102
|
"""
|
pyglet/input/linux/evdev.py
CHANGED
|
@@ -471,7 +471,7 @@ class EvdevControllerManager(ControllerManager, XlibSelectDevice):
|
|
|
471
471
|
if controller := self._controllers.get(name, _create_controller(device)):
|
|
472
472
|
self._controllers[name] = controller
|
|
473
473
|
# Dispatch event in main thread:
|
|
474
|
-
|
|
474
|
+
self.post_event('on_connect', controller)
|
|
475
475
|
|
|
476
476
|
def select(self):
|
|
477
477
|
"""Triggered whenever the devices_file changes."""
|
|
@@ -232,6 +232,8 @@ NSDeviceSize = c_void_p.in_dll(appkit, 'NSDeviceSize')
|
|
|
232
232
|
NSDeviceResolution = c_void_p.in_dll(appkit, 'NSDeviceResolution')
|
|
233
233
|
NSDragOperationGeneric = 4
|
|
234
234
|
|
|
235
|
+
NSStatusWindowLevel = 25
|
|
236
|
+
|
|
235
237
|
|
|
236
238
|
# /System/Library/Frameworks/AppKit.framework/Headers/NSEvent.h
|
|
237
239
|
NSAnyEventMask = 0xFFFFFFFF # NSUIntegerMax
|
|
@@ -336,7 +338,7 @@ NSOpenGLProfileVersion3_2Core = 0x3200 # choose an OpenGL 3.2 Core Implementa
|
|
|
336
338
|
NSOpenGLProfileVersion4_1Core = 0x4100 # choose an OpenGL 4.1 Core Implementation
|
|
337
339
|
|
|
338
340
|
NSOpenGLCPSwapInterval = 222
|
|
339
|
-
|
|
341
|
+
NSOpenGLCPSurfaceOpacity = 236
|
|
340
342
|
|
|
341
343
|
# /System/Library/Frameworks/ApplicationServices.framework/Frameworks/...
|
|
342
344
|
# CoreGraphics.framework/Headers/CGImage.h
|
pyglet/libs/win32/__init__.py
CHANGED
|
@@ -114,6 +114,8 @@ _user32.DestroyWindow.restype = BOOL
|
|
|
114
114
|
_user32.DestroyWindow.argtypes = [HWND]
|
|
115
115
|
_user32.DispatchMessageW.restype = LRESULT
|
|
116
116
|
_user32.DispatchMessageW.argtypes = [LPMSG]
|
|
117
|
+
_user32.EnumDisplayDevicesW.restype = BOOL
|
|
118
|
+
_user32.EnumDisplayDevicesW.argtypes = [LPCWSTR, DWORD, POINTER(DISPLAY_DEVICEW), DWORD]
|
|
117
119
|
_user32.EnumDisplayMonitors.restype = BOOL
|
|
118
120
|
_user32.EnumDisplayMonitors.argtypes = [HDC, LPRECT, MONITORENUMPROC, LPARAM]
|
|
119
121
|
_user32.EnumDisplaySettingsW.restype = BOOL
|
|
@@ -131,6 +133,8 @@ _user32.GetDesktopWindow.restype = HWND
|
|
|
131
133
|
_user32.GetDesktopWindow.argtypes = []
|
|
132
134
|
_user32.GetKeyState.restype = c_short
|
|
133
135
|
_user32.GetKeyState.argtypes = [c_int]
|
|
136
|
+
_user32.GetLayeredWindowAttributes.restype = BOOL
|
|
137
|
+
_user32.GetLayeredWindowAttributes.argtypes = [HWND, POINTER(COLORREF), POINTER(BYTE), POINTER(DWORD)]
|
|
134
138
|
_user32.GetMessageW.restype = BOOL
|
|
135
139
|
_user32.GetMessageW.argtypes = [LPMSG, HWND, UINT, UINT]
|
|
136
140
|
_user32.GetMonitorInfoW.restype = BOOL
|
|
@@ -139,6 +143,8 @@ _user32.GetQueueStatus.restype = DWORD
|
|
|
139
143
|
_user32.GetQueueStatus.argtypes = [UINT]
|
|
140
144
|
_user32.GetSystemMetrics.restype = c_int
|
|
141
145
|
_user32.GetSystemMetrics.argtypes = [c_int]
|
|
146
|
+
_user32.GetWindowLongW.restype = LONG
|
|
147
|
+
_user32.GetWindowLongW.argtypes = [HWND, c_int]
|
|
142
148
|
_user32.LoadCursorW.restype = HCURSOR
|
|
143
149
|
_user32.LoadCursorW.argtypes = [HINSTANCE, c_wchar_p]
|
|
144
150
|
_user32.LoadIconW.restype = HICON
|
|
@@ -183,6 +189,8 @@ _user32.SetFocus.restype = HWND
|
|
|
183
189
|
_user32.SetFocus.argtypes = [HWND]
|
|
184
190
|
_user32.SetForegroundWindow.restype = BOOL
|
|
185
191
|
_user32.SetForegroundWindow.argtypes = [HWND]
|
|
192
|
+
_user32.SetLayeredWindowAttributes.restype = BOOL
|
|
193
|
+
_user32.SetLayeredWindowAttributes.argtypes = [HWND, COLORREF, BYTE, DWORD]
|
|
186
194
|
_user32.SetTimer.restype = UINT_PTR
|
|
187
195
|
_user32.SetTimer.argtypes = [HWND, UINT_PTR, UINT, TIMERPROC]
|
|
188
196
|
_user32.KillTimer.restype = UINT_PTR
|
|
@@ -249,6 +257,10 @@ _dwmapi.DwmIsCompositionEnabled.restype = c_int
|
|
|
249
257
|
_dwmapi.DwmIsCompositionEnabled.argtypes = [POINTER(INT)]
|
|
250
258
|
_dwmapi.DwmFlush.restype = c_int
|
|
251
259
|
_dwmapi.DwmFlush.argtypes = []
|
|
260
|
+
_dwmapi.DwmGetColorizationColor.restype = HRESULT
|
|
261
|
+
_dwmapi.DwmGetColorizationColor.argtypes = [POINTER(DWORD), POINTER(BOOL)]
|
|
262
|
+
_dwmapi.DwmEnableBlurBehindWindow.restype = HRESULT
|
|
263
|
+
_dwmapi.DwmEnableBlurBehindWindow.argtypes = [HWND, POINTER(DWM_BLURBEHIND)]
|
|
252
264
|
|
|
253
265
|
# _shell32
|
|
254
266
|
_shell32.DragAcceptFiles.restype = c_void
|
pyglet/libs/win32/constants.py
CHANGED
|
@@ -5083,3 +5083,7 @@ DEVICE_NOTIFY_WINDOW_HANDLE = 0
|
|
|
5083
5083
|
DEVICE_NOTIFY_SERVICE_HANDLE = 1
|
|
5084
5084
|
|
|
5085
5085
|
USER_DEFAULT_SCREEN_DPI = 96
|
|
5086
|
+
|
|
5087
|
+
QDC_ONLY_ACTIVE_PATHS = 0x00000002
|
|
5088
|
+
DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 0x00000001
|
|
5089
|
+
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 0x00000002
|
pyglet/libs/win32/types.py
CHANGED
|
@@ -676,3 +676,100 @@ class DEV_BROADCAST_DEVICEINTERFACE(Structure):
|
|
|
676
676
|
('dbcc_classguid', com.GUID),
|
|
677
677
|
('dbcc_name', ctypes.c_wchar * 256)
|
|
678
678
|
)
|
|
679
|
+
|
|
680
|
+
|
|
681
|
+
class DISPLAY_DEVICEW(ctypes.Structure):
|
|
682
|
+
_fields_ = [
|
|
683
|
+
('cb', DWORD),
|
|
684
|
+
('DeviceName', WCHAR * 32),
|
|
685
|
+
('DeviceString', WCHAR * 128),
|
|
686
|
+
('StateFlags', DWORD),
|
|
687
|
+
('DeviceID', WCHAR * 128),
|
|
688
|
+
('DeviceKey', WCHAR * 128),
|
|
689
|
+
]
|
|
690
|
+
|
|
691
|
+
|
|
692
|
+
# Structures below are to retrieve a monitor name...
|
|
693
|
+
class LUID(ctypes.Structure):
|
|
694
|
+
_fields_ = [('LowPart', DWORD), ('HighPart', LONG)]
|
|
695
|
+
|
|
696
|
+
|
|
697
|
+
class _SourceInfoStruct(ctypes.Structure):
|
|
698
|
+
_fields_ = [('cloneGroupId', UINT32, 16), ('sourceModeInfoIdx', UINT32, 16)]
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
class _DisplayUnion(ctypes.Union):
|
|
702
|
+
_fields_ = [('modeInfoIdx', UINT32), ('DUMMYSTRUCTNAME', _SourceInfoStruct)]
|
|
703
|
+
|
|
704
|
+
|
|
705
|
+
class DISPLAYCONFIG_PATH_SOURCE_INFO(ctypes.Structure):
|
|
706
|
+
_fields_ = [('adapterId', LUID), ('id', UINT32), ('DUMMYUNIONNAME', _DisplayUnion), ('statusFlags', UINT32)]
|
|
707
|
+
|
|
708
|
+
|
|
709
|
+
class _DummyStructTarget(ctypes.Structure):
|
|
710
|
+
_fields_ = [
|
|
711
|
+
('desktopModeInfoIdx', UINT32, 16),
|
|
712
|
+
('targetModeInfoIdx', UINT32, 16),
|
|
713
|
+
]
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
class _DummyUnionTarget(ctypes.Union):
|
|
717
|
+
_fields_ = [('modeInfoIdx', UINT32), ('DUMMYSTRUCTNAME', _DummyStructTarget)]
|
|
718
|
+
|
|
719
|
+
|
|
720
|
+
class DISPLAYCONFIG_RATIONAL(ctypes.Structure):
|
|
721
|
+
_fields_ = [('Numerator', UINT32), ('Denominator', UINT32)]
|
|
722
|
+
|
|
723
|
+
def __repr__(self):
|
|
724
|
+
return f"DISPLAYCONFIG_RATIONAL(num={self.Numerator}, denom={self.Denominator})"
|
|
725
|
+
|
|
726
|
+
|
|
727
|
+
class DISPLAYCONFIG_PATH_TARGET_INFO(ctypes.Structure):
|
|
728
|
+
_fields_ = [
|
|
729
|
+
('adapterId', LUID),
|
|
730
|
+
('id', UINT32),
|
|
731
|
+
('DUMMYUNIONNAME', _DummyUnionTarget),
|
|
732
|
+
('outputTechnology', UINT32),
|
|
733
|
+
('rotation', UINT32),
|
|
734
|
+
('scaling', UINT32),
|
|
735
|
+
('refreshRate', DISPLAYCONFIG_RATIONAL),
|
|
736
|
+
('scanLineOrdering', UINT32),
|
|
737
|
+
('targetAvailable', BOOL),
|
|
738
|
+
('statusFlags', UINT32),
|
|
739
|
+
]
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
class DISPLAYCONFIG_PATH_INFO(ctypes.Structure):
|
|
743
|
+
_fields_ = [
|
|
744
|
+
('sourceInfo', DISPLAYCONFIG_PATH_SOURCE_INFO),
|
|
745
|
+
('targetInfo', DISPLAYCONFIG_PATH_TARGET_INFO),
|
|
746
|
+
('flags', UINT32),
|
|
747
|
+
]
|
|
748
|
+
|
|
749
|
+
|
|
750
|
+
class DISPLAYCONFIG_DEVICE_INFO_HEADER(ctypes.Structure):
|
|
751
|
+
_fields_ = [('type', UINT32),
|
|
752
|
+
('size', UINT32),
|
|
753
|
+
('adapterId', LUID),
|
|
754
|
+
('id', UINT32)
|
|
755
|
+
]
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
class DISPLAYCONFIG_SOURCE_DEVICE_NAME(ctypes.Structure):
|
|
759
|
+
_fields_ = [
|
|
760
|
+
('header', DISPLAYCONFIG_DEVICE_INFO_HEADER),
|
|
761
|
+
('viewGdiDeviceName', WCHAR * 32)
|
|
762
|
+
]
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
class DISPLAYCONFIG_TARGET_DEVICE_NAME(ctypes.Structure):
|
|
766
|
+
_fields_ = [
|
|
767
|
+
('header', DISPLAYCONFIG_DEVICE_INFO_HEADER),
|
|
768
|
+
('flags', UINT32),
|
|
769
|
+
('outputTechnology', UINT32),
|
|
770
|
+
('edidManufactureId', UINT16),
|
|
771
|
+
('edidProductCodeId', UINT16),
|
|
772
|
+
('connectorInstance', UINT32),
|
|
773
|
+
('monitorFriendlyDeviceName', WCHAR * 64),
|
|
774
|
+
('monitorDevicePath', WCHAR * 128),
|
|
775
|
+
]
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
from ctypes import c_ulong, c_int, POINTER, Structure, c_char_p, c_uint, c_ushort
|
|
3
|
+
|
|
4
|
+
import pyglet
|
|
5
|
+
from pyglet.libs.x11.xlib import (
|
|
6
|
+
Time,
|
|
7
|
+
Window,
|
|
8
|
+
Display,
|
|
9
|
+
XCloseDisplay,
|
|
10
|
+
XDefaultRootWindow,
|
|
11
|
+
XOpenDisplay,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
lib = None
|
|
15
|
+
try:
|
|
16
|
+
lib = pyglet.lib.load_library("Xrandr")
|
|
17
|
+
except ImportError:
|
|
18
|
+
if pyglet.options.debug_lib:
|
|
19
|
+
warnings.warn("Xrandr could not be loaded.")
|
|
20
|
+
raise ImportError
|
|
21
|
+
|
|
22
|
+
RRCrtc = c_ulong # typedef XID
|
|
23
|
+
RROutput = c_ulong # typedef XID
|
|
24
|
+
RRMode = c_ulong # typedef XID
|
|
25
|
+
Connection = c_ushort # Connection in Xrandr.h
|
|
26
|
+
SubpixelOrder = c_ushort # SubpixelOrder in Xrandr.h
|
|
27
|
+
XRRModeFlags = c_ulong
|
|
28
|
+
|
|
29
|
+
class XRRModeInfo(Structure):
|
|
30
|
+
_fields_ = [
|
|
31
|
+
("id", RRMode), # mode ID
|
|
32
|
+
("width", c_uint), # horizontal resolution
|
|
33
|
+
("height", c_uint), # vertical resolution
|
|
34
|
+
("dotClock", c_ulong), # pixel clock (in Hz)
|
|
35
|
+
("hSyncStart", c_uint),
|
|
36
|
+
("hSyncEnd", c_uint),
|
|
37
|
+
("hTotal", c_uint),
|
|
38
|
+
("hSkew", c_uint),
|
|
39
|
+
("vSyncStart", c_uint),
|
|
40
|
+
("vSyncEnd", c_uint),
|
|
41
|
+
("vTotal", c_uint),
|
|
42
|
+
("name", c_char_p),
|
|
43
|
+
("nameLength", c_uint),
|
|
44
|
+
("modeFlags", XRRModeFlags),
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class XRRScreenResources(Structure):
|
|
49
|
+
_fields_ = [
|
|
50
|
+
("timestamp", Time),
|
|
51
|
+
("configTimestamp", Time),
|
|
52
|
+
("ncrtc", c_int),
|
|
53
|
+
("crtcs", POINTER(RRCrtc)),
|
|
54
|
+
("noutput", c_int),
|
|
55
|
+
("outputs", POINTER(RROutput)),
|
|
56
|
+
("nmode", c_int),
|
|
57
|
+
("modes", POINTER(XRRModeInfo)),
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class XRROutputInfo(Structure):
|
|
62
|
+
_fields_ = [
|
|
63
|
+
("timestamp", Time),
|
|
64
|
+
("crtc", RRCrtc),
|
|
65
|
+
("name", c_char_p),
|
|
66
|
+
("nameLen", c_int),
|
|
67
|
+
("mm_width", c_ulong),
|
|
68
|
+
("mm_height", c_ulong),
|
|
69
|
+
("connection", Connection),
|
|
70
|
+
("subpixel_order", SubpixelOrder),
|
|
71
|
+
("ncrtc", c_int),
|
|
72
|
+
("crtcs", POINTER(RRCrtc)),
|
|
73
|
+
("nclone", c_int),
|
|
74
|
+
("clones", POINTER(RROutput)),
|
|
75
|
+
("nmode", c_int),
|
|
76
|
+
("npreferred", c_int),
|
|
77
|
+
("modes", POINTER(RRMode)),
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
class XRRCrtcInfo(Structure):
|
|
81
|
+
_fields_ = [
|
|
82
|
+
("timestamp", Time),
|
|
83
|
+
("x", c_int),
|
|
84
|
+
("y", c_int),
|
|
85
|
+
("width", c_uint),
|
|
86
|
+
("height", c_uint),
|
|
87
|
+
("mode", RRMode),
|
|
88
|
+
("rotation", c_int),
|
|
89
|
+
("noutput", c_int),
|
|
90
|
+
("outputs", POINTER(RROutput)),
|
|
91
|
+
("rotations", c_ushort),
|
|
92
|
+
("npossible", c_int),
|
|
93
|
+
("possible", POINTER(RROutput)),
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
if lib:
|
|
98
|
+
XRRQueryVersion = lib.XRRQueryVersion
|
|
99
|
+
XRRQueryVersion.argtypes = [POINTER(Display), POINTER(c_int), POINTER(c_int)]
|
|
100
|
+
XRRQueryVersion.restype = c_int
|
|
101
|
+
|
|
102
|
+
XRRGetScreenResources = lib.XRRGetScreenResources
|
|
103
|
+
XRRGetScreenResources.argtypes = [POINTER(Display), Window]
|
|
104
|
+
XRRGetScreenResources.restype = POINTER(XRRScreenResources)
|
|
105
|
+
|
|
106
|
+
XRRGetOutputPrimary = lib.XRRGetOutputPrimary
|
|
107
|
+
XRRGetOutputPrimary.argtypes = [POINTER(Display), Window]
|
|
108
|
+
XRRGetOutputPrimary.restype = RROutput
|
|
109
|
+
|
|
110
|
+
XRRGetScreenResourcesCurrent = lib.XRRGetScreenResourcesCurrent
|
|
111
|
+
XRRGetScreenResourcesCurrent.argtypes = [POINTER(Display), Window]
|
|
112
|
+
XRRGetScreenResourcesCurrent.restype = POINTER(XRRScreenResources)
|
|
113
|
+
|
|
114
|
+
XRRFreeScreenResources = lib.XRRFreeScreenResources
|
|
115
|
+
XRRFreeScreenResources.argtypes = [POINTER(XRRScreenResources)]
|
|
116
|
+
XRRFreeScreenResources.restype = None
|
|
117
|
+
|
|
118
|
+
XRRGetOutputInfo = lib.XRRGetOutputInfo
|
|
119
|
+
XRRGetOutputInfo.argtypes = [POINTER(Display), POINTER(XRRScreenResources), RROutput]
|
|
120
|
+
XRRGetOutputInfo.restype = POINTER(XRROutputInfo)
|
|
121
|
+
|
|
122
|
+
XRRFreeOutputInfo = lib.XRRFreeOutputInfo
|
|
123
|
+
XRRFreeOutputInfo.argtypes = [POINTER(XRROutputInfo)]
|
|
124
|
+
XRRFreeOutputInfo.restype = None
|
|
125
|
+
|
|
126
|
+
XRRGetCrtcInfo = lib.XRRGetCrtcInfo
|
|
127
|
+
XRRGetCrtcInfo.argtypes = [POINTER(Display), POINTER(XRRScreenResources), RRCrtc]
|
|
128
|
+
XRRGetCrtcInfo.restype = POINTER(XRRCrtcInfo)
|
|
129
|
+
|
|
130
|
+
XRRSetCrtcConfig = lib.XRRSetCrtcConfig
|
|
131
|
+
XRRSetCrtcConfig.argtypes = argtypes = [POINTER(Display), POINTER(XRRScreenResources), RRCrtc, Time, c_int, c_int, RRMode, c_int, POINTER(RROutput), c_int]
|
|
132
|
+
XRRSetCrtcConfig.restype = c_int
|
|
133
|
+
|
|
134
|
+
XRRFreeCrtcInfo = lib.XRRFreeCrtcInfo
|
|
135
|
+
XRRFreeCrtcInfo.argtypes = [POINTER(XRRCrtcInfo)]
|
|
136
|
+
XRRFreeCrtcInfo.restype = None
|
|
137
|
+
|
|
138
|
+
def list_connected_outputs():
|
|
139
|
+
dpy = XOpenDisplay(None)
|
|
140
|
+
if not dpy:
|
|
141
|
+
raise RuntimeError("Cannot open DISPLAY")
|
|
142
|
+
|
|
143
|
+
root = XDefaultRootWindow(dpy)
|
|
144
|
+
res_p = XRRGetScreenResources(dpy, root)
|
|
145
|
+
if not res_p:
|
|
146
|
+
XCloseDisplay(dpy)
|
|
147
|
+
raise RuntimeError("Failed to get screen resources")
|
|
148
|
+
|
|
149
|
+
res = res_p.contents
|
|
150
|
+
outputs = []
|
|
151
|
+
for i in range(res.noutput):
|
|
152
|
+
out_id = res.outputs[i]
|
|
153
|
+
info_p = XRRGetOutputInfo(dpy, res_p, out_id)
|
|
154
|
+
if info_p:
|
|
155
|
+
info = info_p.contents
|
|
156
|
+
if info.connection == 0: # Connected.
|
|
157
|
+
outputs.append(info.name.decode())
|
|
158
|
+
XRRFreeOutputInfo(info_p)
|
|
159
|
+
|
|
160
|
+
XRRFreeScreenResources(res_p)
|
|
161
|
+
XCloseDisplay(dpy)
|
|
162
|
+
return outputs
|
|
163
|
+
|
|
164
|
+
if __name__ == "__main__":
|
|
165
|
+
for name in list_connected_outputs():
|
|
166
|
+
print(name)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import warnings
|
|
4
|
+
from ctypes import Structure, c_ushort, c_ulong, c_int, c_void_p, POINTER
|
|
5
|
+
import pyglet.lib
|
|
6
|
+
from pyglet.libs.x11.xlib import Visual
|
|
7
|
+
|
|
8
|
+
lib = None
|
|
9
|
+
try:
|
|
10
|
+
lib = pyglet.lib.load_library("Xrender")
|
|
11
|
+
except ImportError:
|
|
12
|
+
if pyglet.options.debug_lib:
|
|
13
|
+
warnings.warn("XRender could not be loaded.")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class XRenderDirectFormat(Structure):
|
|
17
|
+
_fields_ = [
|
|
18
|
+
('red', c_ushort),
|
|
19
|
+
('redMask', c_ushort),
|
|
20
|
+
('green', c_ushort),
|
|
21
|
+
('greenMask', c_ushort),
|
|
22
|
+
('blue', c_ushort),
|
|
23
|
+
('blueMask', c_ushort),
|
|
24
|
+
('alpha', c_ushort),
|
|
25
|
+
('alphaMask', c_ushort),
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
class XRenderPictFormat(Structure):
|
|
29
|
+
_fields_ = [
|
|
30
|
+
('id', c_ulong),
|
|
31
|
+
('type', c_int),
|
|
32
|
+
('depth', c_int),
|
|
33
|
+
('direct', XRenderDirectFormat),
|
|
34
|
+
('colormap', c_ulong),
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
# XRenderFindVisualFormat(Display *dpy, Visual *visual)
|
|
38
|
+
try:
|
|
39
|
+
XRenderFindVisualFormat = lib.XRenderFindVisualFormat
|
|
40
|
+
XRenderFindVisualFormat.argtypes = [c_void_p, POINTER(Visual)]
|
|
41
|
+
XRenderFindVisualFormat.restype = POINTER(XRenderPictFormat)
|
|
42
|
+
except ValueError:
|
|
43
|
+
XRenderFindVisualFormat = None
|
pyglet/libs/x11/xsync.py
CHANGED
|
@@ -406,6 +406,49 @@ XSyncGetPriority = _lib.XSyncGetPriority
|
|
|
406
406
|
XSyncGetPriority.restype = c_int
|
|
407
407
|
XSyncGetPriority.argtypes = [POINTER(Display), XID, POINTER(c_int)]
|
|
408
408
|
|
|
409
|
+
# Shape kind
|
|
410
|
+
ShapeBounding = 0
|
|
411
|
+
ShapeClip = 1
|
|
412
|
+
ShapeInput = 2
|
|
413
|
+
|
|
414
|
+
# Shape operation
|
|
415
|
+
ShapeSet = 0
|
|
416
|
+
ShapeUnion = 1
|
|
417
|
+
ShapeIntersect = 2
|
|
418
|
+
ShapeSubtract = 3
|
|
419
|
+
ShapeInvert = 4
|
|
420
|
+
|
|
421
|
+
XShapeCombineRegion = _lib.XShapeCombineRegion
|
|
422
|
+
XShapeCombineRegion.argtypes = [
|
|
423
|
+
POINTER(Display),
|
|
424
|
+
c_void_p,
|
|
425
|
+
ctypes.c_int, # shape kind
|
|
426
|
+
ctypes.c_int, ctypes.c_int, # x, y offset
|
|
427
|
+
c_void_p,
|
|
428
|
+
ctypes.c_int # ShapeOp
|
|
429
|
+
]
|
|
430
|
+
|
|
431
|
+
XShapeCombineMask = _lib.XShapeCombineMask
|
|
432
|
+
XShapeCombineMask.argtypes = [
|
|
433
|
+
Display, # *display
|
|
434
|
+
c_void_p, # dest window
|
|
435
|
+
ctypes.c_int, # shape_kind (e.g., ShapeInput)
|
|
436
|
+
ctypes.c_int, # x offset
|
|
437
|
+
ctypes.c_int, # y offset
|
|
438
|
+
ctypes.c_ulong, # Pixmap (can be 0 for None)
|
|
439
|
+
ctypes.c_int # ShapeOp (e.g., ShapeSet)
|
|
440
|
+
]
|
|
441
|
+
XShapeCombineMask.restype = None
|
|
442
|
+
|
|
443
|
+
XShapeQueryExtension = _lib.XShapeQueryExtension
|
|
444
|
+
XShapeQueryExtension.argtypes = [Display, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)]
|
|
445
|
+
XShapeQueryExtension.restype = Bool
|
|
446
|
+
|
|
447
|
+
def has_shape_support(display: Display) -> bool:
|
|
448
|
+
event_base = ctypes.c_int()
|
|
449
|
+
error_base = ctypes.c_int()
|
|
450
|
+
return XShapeQueryExtension(display, ctypes.byref(event_base), ctypes.byref(error_base))
|
|
451
|
+
|
|
409
452
|
|
|
410
453
|
__all__ = ['SYNC_MAJOR_VERSION', 'SYNC_MINOR_VERSION', 'X_SyncInitialize',
|
|
411
454
|
'X_SyncListSystemCounters', 'X_SyncCreateCounter', 'X_SyncSetCounter',
|