gstreamer-python 1.27.90__cp39-cp39-win32.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.
- gstreamer_python/Lib/girepository-1.0/GdkPixbuf-2.0.typelib +0 -0
- gstreamer_python/Lib/girepository-1.0/HarfBuzz-0.0.typelib +0 -0
- gstreamer_python/Lib/girepository-1.0/Json-1.0.typelib +0 -0
- gstreamer_python/Lib/girepository-1.0/Pango-1.0.typelib +0 -0
- gstreamer_python/Lib/girepository-1.0/PangoCairo-1.0.typelib +0 -0
- gstreamer_python/Lib/girepository-1.0/Soup-3.0.typelib +0 -0
- gstreamer_python/Lib/gstreamer-1.0/gstpython.dll +0 -0
- gstreamer_python/Lib/site-packages/PyGObject-3.50.2.dist-info/METADATA +21 -0
- gstreamer_python/Lib/site-packages/cairo/__init__.py +25 -0
- gstreamer_python/Lib/site-packages/cairo/__init__.pyi +5889 -0
- gstreamer_python/Lib/site-packages/cairo/_cairo.cp39-win32.pyd +0 -0
- gstreamer_python/Lib/site-packages/cairo/include/py3cairo.h +266 -0
- gstreamer_python/Lib/site-packages/cairo/py.typed +0 -0
- gstreamer_python/Lib/site-packages/gi/__init__.py +197 -0
- gstreamer_python/Lib/site-packages/gi/_constants.py +47 -0
- gstreamer_python/Lib/site-packages/gi/_error.py +55 -0
- gstreamer_python/Lib/site-packages/gi/_gi.cp39-win32.pyd +0 -0
- gstreamer_python/Lib/site-packages/gi/_gi_cairo.cp39-win32.pyd +0 -0
- gstreamer_python/Lib/site-packages/gi/_gtktemplate.py +307 -0
- gstreamer_python/Lib/site-packages/gi/_option.py +379 -0
- gstreamer_python/Lib/site-packages/gi/_ossighelper.py +275 -0
- gstreamer_python/Lib/site-packages/gi/_propertyhelper.py +402 -0
- gstreamer_python/Lib/site-packages/gi/_signalhelper.py +249 -0
- gstreamer_python/Lib/site-packages/gi/docstring.py +205 -0
- gstreamer_python/Lib/site-packages/gi/events.py +674 -0
- gstreamer_python/Lib/site-packages/gi/importer.py +153 -0
- gstreamer_python/Lib/site-packages/gi/module.py +269 -0
- gstreamer_python/Lib/site-packages/gi/overrides/GES.py +94 -0
- gstreamer_python/Lib/site-packages/gi/overrides/GIMarshallingTests.py +72 -0
- gstreamer_python/Lib/site-packages/gi/overrides/GLib.py +882 -0
- gstreamer_python/Lib/site-packages/gi/overrides/GObject.py +692 -0
- gstreamer_python/Lib/site-packages/gi/overrides/Gdk.py +444 -0
- gstreamer_python/Lib/site-packages/gi/overrides/GdkPixbuf.py +53 -0
- gstreamer_python/Lib/site-packages/gi/overrides/Gio.py +655 -0
- gstreamer_python/Lib/site-packages/gi/overrides/Gst.py +1273 -0
- gstreamer_python/Lib/site-packages/gi/overrides/GstAnalytics.py +106 -0
- gstreamer_python/Lib/site-packages/gi/overrides/GstApp.py +50 -0
- gstreamer_python/Lib/site-packages/gi/overrides/GstAudio.py +18 -0
- gstreamer_python/Lib/site-packages/gi/overrides/GstPbutils.py +99 -0
- gstreamer_python/Lib/site-packages/gi/overrides/GstVideo.py +17 -0
- gstreamer_python/Lib/site-packages/gi/overrides/Gtk.py +1707 -0
- gstreamer_python/Lib/site-packages/gi/overrides/Pango.py +58 -0
- gstreamer_python/Lib/site-packages/gi/overrides/__init__.py +357 -0
- gstreamer_python/Lib/site-packages/gi/overrides/_gi_gst.cp39-win32.pyd +0 -0
- gstreamer_python/Lib/site-packages/gi/overrides/_gi_gst_analytics.cp39-win32.pyd +0 -0
- gstreamer_python/Lib/site-packages/gi/overrides/keysyms.py +53 -0
- gstreamer_python/Lib/site-packages/gi/pygtkcompat.py +26 -0
- gstreamer_python/Lib/site-packages/gi/repository/__init__.py +28 -0
- gstreamer_python/Lib/site-packages/gi/types.py +350 -0
- gstreamer_python/Lib/site-packages/pycairo-1.27.0.dist-info/METADATA +9 -0
- gstreamer_python/__init__.py +32 -0
- gstreamer_python-1.27.90.dist-info/METADATA +26 -0
- gstreamer_python-1.27.90.dist-info/RECORD +55 -0
- gstreamer_python-1.27.90.dist-info/WHEEL +5 -0
- gstreamer_python-1.27.90.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# Copyright 2017 Christoph Reiter
|
|
2
|
+
#
|
|
3
|
+
# This library is free software; you can redistribute it and/or
|
|
4
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
5
|
+
# License as published by the Free Software Foundation; either
|
|
6
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This library is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
11
|
+
# Lesser General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU Lesser General Public
|
|
14
|
+
# License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
15
|
+
|
|
16
|
+
from __future__ import print_function
|
|
17
|
+
|
|
18
|
+
import os
|
|
19
|
+
import socket
|
|
20
|
+
import signal
|
|
21
|
+
import asyncio
|
|
22
|
+
import threading
|
|
23
|
+
from contextlib import closing, contextmanager
|
|
24
|
+
|
|
25
|
+
from . import _gi
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def ensure_socket_not_inheritable(sock):
|
|
29
|
+
"""Ensures that the socket is not inherited by child processes
|
|
30
|
+
|
|
31
|
+
Raises:
|
|
32
|
+
EnvironmentError
|
|
33
|
+
NotImplementedError: With Python <3.4 on Windows
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
if hasattr(sock, "set_inheritable"):
|
|
37
|
+
sock.set_inheritable(False)
|
|
38
|
+
else:
|
|
39
|
+
try:
|
|
40
|
+
import fcntl
|
|
41
|
+
except ImportError:
|
|
42
|
+
raise NotImplementedError(
|
|
43
|
+
"Not implemented for older Python on Windows")
|
|
44
|
+
else:
|
|
45
|
+
fd = sock.fileno()
|
|
46
|
+
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
|
|
47
|
+
fcntl.fcntl(fd, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
_wakeup_fd_is_active = False
|
|
51
|
+
"""Since we can't check if set_wakeup_fd() is already used for nested event
|
|
52
|
+
loops without introducing a race condition we keep track of it globally.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@contextmanager
|
|
57
|
+
def wakeup_on_signal():
|
|
58
|
+
"""A decorator for functions which create a glib event loop to keep
|
|
59
|
+
Python signal handlers working while the event loop is idling.
|
|
60
|
+
|
|
61
|
+
In case an OS signal is received will wake the default event loop up
|
|
62
|
+
shortly so that any registered Python signal handlers registered through
|
|
63
|
+
signal.signal() can run.
|
|
64
|
+
|
|
65
|
+
In case the wrapped function is not called from the main thread it will be
|
|
66
|
+
called as is and it will not wake up the default loop for signals.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
global _wakeup_fd_is_active
|
|
70
|
+
|
|
71
|
+
if _wakeup_fd_is_active:
|
|
72
|
+
yield
|
|
73
|
+
return
|
|
74
|
+
|
|
75
|
+
from gi.repository import GLib
|
|
76
|
+
|
|
77
|
+
read_socket, write_socket = socket.socketpair()
|
|
78
|
+
with closing(read_socket), closing(write_socket):
|
|
79
|
+
|
|
80
|
+
for sock in [read_socket, write_socket]:
|
|
81
|
+
sock.setblocking(False)
|
|
82
|
+
ensure_socket_not_inheritable(sock)
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
orig_fd = signal.set_wakeup_fd(write_socket.fileno())
|
|
86
|
+
except ValueError:
|
|
87
|
+
# Raised in case this is not the main thread -> give up.
|
|
88
|
+
yield
|
|
89
|
+
return
|
|
90
|
+
else:
|
|
91
|
+
_wakeup_fd_is_active = True
|
|
92
|
+
|
|
93
|
+
def signal_notify(source, condition):
|
|
94
|
+
if condition & GLib.IO_IN:
|
|
95
|
+
try:
|
|
96
|
+
return bool(read_socket.recv(1))
|
|
97
|
+
except EnvironmentError as e:
|
|
98
|
+
print(e)
|
|
99
|
+
return False
|
|
100
|
+
return True
|
|
101
|
+
else:
|
|
102
|
+
return False
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
if os.name == "nt":
|
|
106
|
+
channel = GLib.IOChannel.win32_new_socket(
|
|
107
|
+
read_socket.fileno())
|
|
108
|
+
else:
|
|
109
|
+
channel = GLib.IOChannel.unix_new(read_socket.fileno())
|
|
110
|
+
|
|
111
|
+
source_id = GLib.io_add_watch(
|
|
112
|
+
channel,
|
|
113
|
+
GLib.PRIORITY_DEFAULT,
|
|
114
|
+
(GLib.IOCondition.IN | GLib.IOCondition.HUP |
|
|
115
|
+
GLib.IOCondition.NVAL | GLib.IOCondition.ERR),
|
|
116
|
+
signal_notify)
|
|
117
|
+
try:
|
|
118
|
+
yield
|
|
119
|
+
finally:
|
|
120
|
+
GLib.source_remove(source_id)
|
|
121
|
+
finally:
|
|
122
|
+
write_fd = signal.set_wakeup_fd(orig_fd)
|
|
123
|
+
if write_fd != write_socket.fileno():
|
|
124
|
+
# Someone has called set_wakeup_fd while func() was active,
|
|
125
|
+
# so let's re-revert again.
|
|
126
|
+
signal.set_wakeup_fd(write_fd)
|
|
127
|
+
_wakeup_fd_is_active = False
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
PyOS_getsig = _gi.pyos_getsig
|
|
131
|
+
PyOS_setsig = _gi.pyos_setsig
|
|
132
|
+
|
|
133
|
+
# We save the signal pointer so we can detect if glib has changed the
|
|
134
|
+
# signal handler behind Python's back (GLib.unix_signal_add)
|
|
135
|
+
if signal.getsignal(signal.SIGINT) is signal.default_int_handler:
|
|
136
|
+
startup_sigint_ptr = PyOS_getsig(signal.SIGINT)
|
|
137
|
+
else:
|
|
138
|
+
# Something has set the handler before import, we can't get a ptr
|
|
139
|
+
# for the default handler so make sure the pointer will never match.
|
|
140
|
+
startup_sigint_ptr = -1
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def sigint_handler_is_default():
|
|
144
|
+
"""Returns if on SIGINT the default Python handler would be called"""
|
|
145
|
+
|
|
146
|
+
return (signal.getsignal(signal.SIGINT) is signal.default_int_handler and
|
|
147
|
+
PyOS_getsig(signal.SIGINT) == startup_sigint_ptr)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@contextmanager
|
|
151
|
+
def sigint_handler_set_and_restore_default(handler):
|
|
152
|
+
"""Context manager for saving/restoring the SIGINT handler default state.
|
|
153
|
+
|
|
154
|
+
Will only restore the default handler again if the handler is not changed
|
|
155
|
+
while the context is active.
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
assert sigint_handler_is_default()
|
|
159
|
+
|
|
160
|
+
signal.signal(signal.SIGINT, handler)
|
|
161
|
+
sig_ptr = PyOS_getsig(signal.SIGINT)
|
|
162
|
+
try:
|
|
163
|
+
yield
|
|
164
|
+
finally:
|
|
165
|
+
if signal.getsignal(signal.SIGINT) is handler and \
|
|
166
|
+
PyOS_getsig(signal.SIGINT) == sig_ptr:
|
|
167
|
+
signal.signal(signal.SIGINT, signal.default_int_handler)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def is_main_thread():
|
|
171
|
+
"""Returns True in case the function is called from the main thread"""
|
|
172
|
+
|
|
173
|
+
return threading.current_thread().name == "MainThread"
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
_callback_stack = []
|
|
177
|
+
_sigint_called = False
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
@contextmanager
|
|
181
|
+
def register_sigint_fallback(callback):
|
|
182
|
+
"""Installs a SIGINT signal handler in case the default Python one is
|
|
183
|
+
active which calls 'callback' in case the signal occurs.
|
|
184
|
+
|
|
185
|
+
Only does something if called from the main thread.
|
|
186
|
+
|
|
187
|
+
In case of nested context managers the signal handler will be only
|
|
188
|
+
installed once and the callbacks will be called in the reverse order
|
|
189
|
+
of their registration.
|
|
190
|
+
|
|
191
|
+
The old signal handler will be restored in case no signal handler is
|
|
192
|
+
registered while the context is active.
|
|
193
|
+
"""
|
|
194
|
+
|
|
195
|
+
# To handle multiple levels of event loops we need to call the last
|
|
196
|
+
# callback first, wait until the inner most event loop returns control
|
|
197
|
+
# and only then call the next callback, and so on... until we
|
|
198
|
+
# reach the outer most which manages the signal handler and raises
|
|
199
|
+
# in the end
|
|
200
|
+
|
|
201
|
+
global _callback_stack, _sigint_called
|
|
202
|
+
|
|
203
|
+
if not is_main_thread():
|
|
204
|
+
yield
|
|
205
|
+
return
|
|
206
|
+
|
|
207
|
+
if not sigint_handler_is_default():
|
|
208
|
+
if _callback_stack:
|
|
209
|
+
# This is an inner event loop, append our callback
|
|
210
|
+
# to the stack so the parent context can call it.
|
|
211
|
+
_callback_stack.append(callback)
|
|
212
|
+
try:
|
|
213
|
+
yield
|
|
214
|
+
finally:
|
|
215
|
+
cb = _callback_stack.pop()
|
|
216
|
+
if _sigint_called:
|
|
217
|
+
cb()
|
|
218
|
+
else:
|
|
219
|
+
# There is a signal handler set by the user, just do nothing
|
|
220
|
+
yield
|
|
221
|
+
return
|
|
222
|
+
|
|
223
|
+
_sigint_called = False
|
|
224
|
+
|
|
225
|
+
def sigint_handler(sig_num, frame):
|
|
226
|
+
global _callback_stack, _sigint_called
|
|
227
|
+
|
|
228
|
+
if _sigint_called:
|
|
229
|
+
return
|
|
230
|
+
_sigint_called = True
|
|
231
|
+
_callback_stack.pop()()
|
|
232
|
+
|
|
233
|
+
_callback_stack.append(callback)
|
|
234
|
+
try:
|
|
235
|
+
with sigint_handler_set_and_restore_default(sigint_handler):
|
|
236
|
+
yield
|
|
237
|
+
finally:
|
|
238
|
+
if _sigint_called:
|
|
239
|
+
signal.default_int_handler(signal.SIGINT, None)
|
|
240
|
+
else:
|
|
241
|
+
_callback_stack.pop()
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
class DummyEventLoop():
|
|
245
|
+
@classmethod
|
|
246
|
+
@contextmanager
|
|
247
|
+
def paused(cls):
|
|
248
|
+
yield
|
|
249
|
+
|
|
250
|
+
@classmethod
|
|
251
|
+
@contextmanager
|
|
252
|
+
def running(cls, quit_func):
|
|
253
|
+
with wakeup_on_signal():
|
|
254
|
+
yield
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def get_event_loop(ctx):
|
|
258
|
+
"""Return the correct GLibEventLoop or a dummy that just registers the
|
|
259
|
+
signal wakeup mechanism."""
|
|
260
|
+
|
|
261
|
+
# Try to use the running loop. If there is none, get the policy and
|
|
262
|
+
# try getting one in the hope that this will give us an event loop for the
|
|
263
|
+
# correct context.
|
|
264
|
+
loop = asyncio._get_running_loop()
|
|
265
|
+
if loop is None:
|
|
266
|
+
try:
|
|
267
|
+
loop = asyncio.get_event_loop_policy().get_event_loop_for_context(ctx)
|
|
268
|
+
except:
|
|
269
|
+
pass
|
|
270
|
+
|
|
271
|
+
if loop and hasattr(loop, '_context'):
|
|
272
|
+
if ctx is not None and hash(loop._context) == hash(ctx):
|
|
273
|
+
return loop
|
|
274
|
+
|
|
275
|
+
return DummyEventLoop
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
# -*- Mode: Python; py-indent-offset: 4 -*-
|
|
2
|
+
# pygobject - Python bindings for the GObject library
|
|
3
|
+
# Copyright (C) 2007 Johan Dahlin
|
|
4
|
+
#
|
|
5
|
+
# gi/_propertyhelper.py: GObject property wrapper/helper
|
|
6
|
+
#
|
|
7
|
+
# This library is free software; you can redistribute it and/or
|
|
8
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
9
|
+
# License as published by the Free Software Foundation; either
|
|
10
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
11
|
+
#
|
|
12
|
+
# This library is distributed in the hope that it will be useful,
|
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
15
|
+
# Lesser General Public License for more details.
|
|
16
|
+
#
|
|
17
|
+
# You should have received a copy of the GNU Lesser General Public
|
|
18
|
+
# License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
19
|
+
|
|
20
|
+
from . import _gi
|
|
21
|
+
from ._constants import \
|
|
22
|
+
TYPE_NONE, TYPE_INTERFACE, TYPE_CHAR, TYPE_UCHAR, \
|
|
23
|
+
TYPE_BOOLEAN, TYPE_INT, TYPE_UINT, TYPE_LONG, \
|
|
24
|
+
TYPE_ULONG, TYPE_INT64, TYPE_UINT64, TYPE_ENUM, TYPE_FLAGS, \
|
|
25
|
+
TYPE_FLOAT, TYPE_DOUBLE, TYPE_STRING, \
|
|
26
|
+
TYPE_POINTER, TYPE_BOXED, TYPE_PARAM, TYPE_OBJECT, \
|
|
27
|
+
TYPE_PYOBJECT, TYPE_GTYPE, TYPE_STRV, TYPE_VARIANT
|
|
28
|
+
|
|
29
|
+
G_MAXFLOAT = _gi.G_MAXFLOAT
|
|
30
|
+
G_MAXDOUBLE = _gi.G_MAXDOUBLE
|
|
31
|
+
G_MININT = _gi.G_MININT
|
|
32
|
+
G_MAXINT = _gi.G_MAXINT
|
|
33
|
+
G_MAXUINT = _gi.G_MAXUINT
|
|
34
|
+
G_MINLONG = _gi.G_MINLONG
|
|
35
|
+
G_MAXLONG = _gi.G_MAXLONG
|
|
36
|
+
G_MAXULONG = _gi.G_MAXULONG
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class Property(object):
|
|
40
|
+
"""Creates a new Property which when used in conjunction with
|
|
41
|
+
GObject subclass will create a Python property accessor for the
|
|
42
|
+
GObject ParamSpec.
|
|
43
|
+
|
|
44
|
+
:param callable getter:
|
|
45
|
+
getter to get the value of the property
|
|
46
|
+
:param callable setter:
|
|
47
|
+
setter to set the value of the property
|
|
48
|
+
:param type type:
|
|
49
|
+
type of property
|
|
50
|
+
:param default:
|
|
51
|
+
default value, must match the property type.
|
|
52
|
+
:param str nick:
|
|
53
|
+
short description
|
|
54
|
+
:param str blurb:
|
|
55
|
+
long description
|
|
56
|
+
:param GObject.ParamFlags flags:
|
|
57
|
+
parameter flags
|
|
58
|
+
:keyword minimum:
|
|
59
|
+
minimum allowed value (int, float, long only)
|
|
60
|
+
:keyword maximum:
|
|
61
|
+
maximum allowed value (int, float, long only)
|
|
62
|
+
|
|
63
|
+
.. code-block:: python
|
|
64
|
+
|
|
65
|
+
class MyObject(GObject.Object):
|
|
66
|
+
prop = GObject.Property(type=str)
|
|
67
|
+
|
|
68
|
+
obj = MyObject()
|
|
69
|
+
obj.prop = 'value'
|
|
70
|
+
|
|
71
|
+
obj.prop # now is 'value'
|
|
72
|
+
|
|
73
|
+
The API is similar to the builtin :py:func:`property`:
|
|
74
|
+
|
|
75
|
+
.. code-block:: python
|
|
76
|
+
|
|
77
|
+
class AnotherObject(GObject.Object):
|
|
78
|
+
value = 0
|
|
79
|
+
|
|
80
|
+
@GObject.Property
|
|
81
|
+
def prop(self):
|
|
82
|
+
'Read only property.'
|
|
83
|
+
return 1
|
|
84
|
+
|
|
85
|
+
@GObject.Property(type=int)
|
|
86
|
+
def propInt(self):
|
|
87
|
+
'Read-write integer property.'
|
|
88
|
+
return self.value
|
|
89
|
+
|
|
90
|
+
@propInt.setter
|
|
91
|
+
def propInt(self, value):
|
|
92
|
+
self.value = value
|
|
93
|
+
"""
|
|
94
|
+
_type_from_pytype_lookup = {
|
|
95
|
+
int: TYPE_INT,
|
|
96
|
+
bool: TYPE_BOOLEAN,
|
|
97
|
+
float: TYPE_DOUBLE,
|
|
98
|
+
str: TYPE_STRING,
|
|
99
|
+
object: TYPE_PYOBJECT,
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
_min_value_lookup = {
|
|
103
|
+
TYPE_UINT: 0,
|
|
104
|
+
TYPE_ULONG: 0,
|
|
105
|
+
TYPE_UINT64: 0,
|
|
106
|
+
# Remember that G_MINFLOAT and G_MINDOUBLE are something different.
|
|
107
|
+
TYPE_FLOAT: -G_MAXFLOAT,
|
|
108
|
+
TYPE_DOUBLE: -G_MAXDOUBLE,
|
|
109
|
+
TYPE_INT: G_MININT,
|
|
110
|
+
TYPE_LONG: G_MINLONG,
|
|
111
|
+
TYPE_INT64: -2 ** 63,
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
_max_value_lookup = {
|
|
115
|
+
TYPE_UINT: G_MAXUINT,
|
|
116
|
+
TYPE_ULONG: G_MAXULONG,
|
|
117
|
+
TYPE_INT64: 2 ** 63 - 1,
|
|
118
|
+
TYPE_UINT64: 2 ** 64 - 1,
|
|
119
|
+
TYPE_FLOAT: G_MAXFLOAT,
|
|
120
|
+
TYPE_DOUBLE: G_MAXDOUBLE,
|
|
121
|
+
TYPE_INT: G_MAXINT,
|
|
122
|
+
TYPE_LONG: G_MAXLONG,
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
_default_lookup = {
|
|
126
|
+
TYPE_INT: 0,
|
|
127
|
+
TYPE_UINT: 0,
|
|
128
|
+
TYPE_LONG: 0,
|
|
129
|
+
TYPE_ULONG: 0,
|
|
130
|
+
TYPE_INT64: 0,
|
|
131
|
+
TYPE_UINT64: 0,
|
|
132
|
+
TYPE_STRING: '',
|
|
133
|
+
TYPE_FLOAT: 0.0,
|
|
134
|
+
TYPE_DOUBLE: 0.0,
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
class __metaclass__(type):
|
|
138
|
+
def __repr__(self):
|
|
139
|
+
return "<class 'GObject.Property'>"
|
|
140
|
+
|
|
141
|
+
def __init__(self, getter=None, setter=None, type=None, default=None,
|
|
142
|
+
nick='', blurb='', flags=_gi.PARAM_READWRITE,
|
|
143
|
+
minimum=None, maximum=None):
|
|
144
|
+
self.name = None
|
|
145
|
+
|
|
146
|
+
if type is None:
|
|
147
|
+
type = object
|
|
148
|
+
self.type = self._type_from_python(type)
|
|
149
|
+
self.default = self._get_default(default)
|
|
150
|
+
self._check_default()
|
|
151
|
+
|
|
152
|
+
if not isinstance(nick, str):
|
|
153
|
+
raise TypeError("nick must be a string")
|
|
154
|
+
self.nick = nick
|
|
155
|
+
|
|
156
|
+
if not isinstance(blurb, str):
|
|
157
|
+
raise TypeError("blurb must be a string")
|
|
158
|
+
self.blurb = blurb
|
|
159
|
+
# Always clobber __doc__ with blurb even if blurb is empty because
|
|
160
|
+
# we don't want the lengthy Property class documentation showing up
|
|
161
|
+
# on instances.
|
|
162
|
+
self.__doc__ = blurb
|
|
163
|
+
self.flags = flags
|
|
164
|
+
|
|
165
|
+
# Call after setting blurb for potential __doc__ usage.
|
|
166
|
+
if getter and not setter:
|
|
167
|
+
setter = self._readonly_setter
|
|
168
|
+
elif setter and not getter:
|
|
169
|
+
getter = self._writeonly_getter
|
|
170
|
+
elif not setter and not getter:
|
|
171
|
+
getter = self._default_getter
|
|
172
|
+
setter = self._default_setter
|
|
173
|
+
self.getter(getter)
|
|
174
|
+
# do not call self.setter() here, as this defines the property name
|
|
175
|
+
# already
|
|
176
|
+
self.fset = setter
|
|
177
|
+
|
|
178
|
+
if minimum is not None:
|
|
179
|
+
if minimum < self._get_minimum():
|
|
180
|
+
raise TypeError(
|
|
181
|
+
"Minimum for type %s cannot be lower than %d" %
|
|
182
|
+
(self.type, self._get_minimum()))
|
|
183
|
+
else:
|
|
184
|
+
minimum = self._get_minimum()
|
|
185
|
+
self.minimum = minimum
|
|
186
|
+
if maximum is not None:
|
|
187
|
+
if maximum > self._get_maximum():
|
|
188
|
+
raise TypeError(
|
|
189
|
+
"Maximum for type %s cannot be higher than %d" %
|
|
190
|
+
(self.type, self._get_maximum()))
|
|
191
|
+
else:
|
|
192
|
+
maximum = self._get_maximum()
|
|
193
|
+
self.maximum = maximum
|
|
194
|
+
|
|
195
|
+
self._exc = None
|
|
196
|
+
|
|
197
|
+
def __repr__(self):
|
|
198
|
+
return '<GObject Property %s (%s)>' % (
|
|
199
|
+
self.name or '(uninitialized)',
|
|
200
|
+
self.type.name)
|
|
201
|
+
|
|
202
|
+
def __get__(self, instance, klass):
|
|
203
|
+
if instance is None:
|
|
204
|
+
return self
|
|
205
|
+
|
|
206
|
+
self._exc = None
|
|
207
|
+
value = self.fget(instance)
|
|
208
|
+
if self._exc:
|
|
209
|
+
exc = self._exc
|
|
210
|
+
self._exc = None
|
|
211
|
+
raise exc
|
|
212
|
+
|
|
213
|
+
return value
|
|
214
|
+
|
|
215
|
+
def __set__(self, instance, value):
|
|
216
|
+
if instance is None:
|
|
217
|
+
raise TypeError
|
|
218
|
+
|
|
219
|
+
self._exc = None
|
|
220
|
+
instance.set_property(self.name, value)
|
|
221
|
+
if self._exc:
|
|
222
|
+
exc = self._exc
|
|
223
|
+
self._exc = None
|
|
224
|
+
raise exc
|
|
225
|
+
|
|
226
|
+
def __call__(self, fget):
|
|
227
|
+
"""Allows application of the getter along with init arguments."""
|
|
228
|
+
return self.getter(fget)
|
|
229
|
+
|
|
230
|
+
def getter(self, fget):
|
|
231
|
+
"""Set the getter function to fget. For use as a decorator."""
|
|
232
|
+
if fget.__doc__:
|
|
233
|
+
# Always clobber docstring and blurb with the getter docstring.
|
|
234
|
+
self.blurb = fget.__doc__
|
|
235
|
+
self.__doc__ = fget.__doc__
|
|
236
|
+
self.fget = fget
|
|
237
|
+
return self
|
|
238
|
+
|
|
239
|
+
def setter(self, fset):
|
|
240
|
+
"""Set the setter function to fset. For use as a decorator."""
|
|
241
|
+
self.fset = fset
|
|
242
|
+
# with a setter decorator, we must ignore the name of the method in
|
|
243
|
+
# install_properties, as this does not need to be a valid property name
|
|
244
|
+
# and does not define the property name. So set the name here.
|
|
245
|
+
if not self.name:
|
|
246
|
+
self.name = self.fget.__name__
|
|
247
|
+
return self
|
|
248
|
+
|
|
249
|
+
def _type_from_python(self, type_):
|
|
250
|
+
if type_ in self._type_from_pytype_lookup:
|
|
251
|
+
return self._type_from_pytype_lookup[type_]
|
|
252
|
+
elif (isinstance(type_, type) and
|
|
253
|
+
issubclass(type_, (_gi.GObject,
|
|
254
|
+
_gi.GEnum,
|
|
255
|
+
_gi.GFlags,
|
|
256
|
+
_gi.GBoxed,
|
|
257
|
+
_gi.GInterface))):
|
|
258
|
+
return type_.__gtype__
|
|
259
|
+
elif type_ in (TYPE_NONE, TYPE_INTERFACE, TYPE_CHAR, TYPE_UCHAR,
|
|
260
|
+
TYPE_INT, TYPE_UINT, TYPE_BOOLEAN, TYPE_LONG,
|
|
261
|
+
TYPE_ULONG, TYPE_INT64, TYPE_UINT64,
|
|
262
|
+
TYPE_FLOAT, TYPE_DOUBLE, TYPE_POINTER,
|
|
263
|
+
TYPE_BOXED, TYPE_PARAM, TYPE_OBJECT, TYPE_STRING,
|
|
264
|
+
TYPE_PYOBJECT, TYPE_GTYPE, TYPE_STRV, TYPE_VARIANT):
|
|
265
|
+
return type_
|
|
266
|
+
else:
|
|
267
|
+
raise TypeError("Unsupported type: %r" % (type_,))
|
|
268
|
+
|
|
269
|
+
def _get_default(self, default):
|
|
270
|
+
if default is not None:
|
|
271
|
+
return default
|
|
272
|
+
return self._default_lookup.get(self.type, None)
|
|
273
|
+
|
|
274
|
+
def _check_default(self):
|
|
275
|
+
ptype = self.type
|
|
276
|
+
default = self.default
|
|
277
|
+
if (ptype == TYPE_BOOLEAN and (default not in (True, False))):
|
|
278
|
+
raise TypeError(
|
|
279
|
+
"default must be True or False, not %r" % (default,))
|
|
280
|
+
elif ptype == TYPE_PYOBJECT:
|
|
281
|
+
if default is not None:
|
|
282
|
+
raise TypeError("object types does not have default values")
|
|
283
|
+
elif ptype == TYPE_GTYPE:
|
|
284
|
+
if default is not None:
|
|
285
|
+
raise TypeError("GType types does not have default values")
|
|
286
|
+
elif ptype.is_a(TYPE_ENUM):
|
|
287
|
+
if default is None:
|
|
288
|
+
raise TypeError("enum properties needs a default value")
|
|
289
|
+
elif not _gi.GType(default).is_a(ptype):
|
|
290
|
+
raise TypeError("enum value %s must be an instance of %r" %
|
|
291
|
+
(default, ptype))
|
|
292
|
+
elif ptype.is_a(TYPE_FLAGS):
|
|
293
|
+
if not _gi.GType(default).is_a(ptype):
|
|
294
|
+
raise TypeError("flags value %s must be an instance of %r" %
|
|
295
|
+
(default, ptype))
|
|
296
|
+
elif ptype.is_a(TYPE_STRV) and default is not None:
|
|
297
|
+
if not isinstance(default, list):
|
|
298
|
+
raise TypeError("Strv value %s must be a list" % repr(default))
|
|
299
|
+
for val in default:
|
|
300
|
+
if type(val) not in (str, bytes):
|
|
301
|
+
raise TypeError("Strv value %s must contain only strings" % str(default))
|
|
302
|
+
elif ptype.is_a(TYPE_VARIANT) and default is not None:
|
|
303
|
+
if not hasattr(default, '__gtype__') or not _gi.GType(default).is_a(TYPE_VARIANT):
|
|
304
|
+
raise TypeError("variant value %s must be an instance of %r" %
|
|
305
|
+
(default, ptype))
|
|
306
|
+
|
|
307
|
+
def _get_minimum(self):
|
|
308
|
+
return self._min_value_lookup.get(self.type, None)
|
|
309
|
+
|
|
310
|
+
def _get_maximum(self):
|
|
311
|
+
return self._max_value_lookup.get(self.type, None)
|
|
312
|
+
|
|
313
|
+
#
|
|
314
|
+
# Getter and Setter
|
|
315
|
+
#
|
|
316
|
+
|
|
317
|
+
def _default_setter(self, instance, value):
|
|
318
|
+
setattr(instance, '_property_helper_' + self.name, value)
|
|
319
|
+
|
|
320
|
+
def _default_getter(self, instance):
|
|
321
|
+
return getattr(instance, '_property_helper_' + self.name, self.default)
|
|
322
|
+
|
|
323
|
+
def _readonly_setter(self, instance, value):
|
|
324
|
+
self._exc = TypeError("%s property of %s is read-only" % (
|
|
325
|
+
self.name, type(instance).__name__))
|
|
326
|
+
|
|
327
|
+
def _writeonly_getter(self, instance):
|
|
328
|
+
self._exc = TypeError("%s property of %s is write-only" % (
|
|
329
|
+
self.name, type(instance).__name__))
|
|
330
|
+
|
|
331
|
+
#
|
|
332
|
+
# Public API
|
|
333
|
+
#
|
|
334
|
+
|
|
335
|
+
def get_pspec_args(self):
|
|
336
|
+
ptype = self.type
|
|
337
|
+
if ptype in (TYPE_INT, TYPE_UINT, TYPE_LONG, TYPE_ULONG,
|
|
338
|
+
TYPE_INT64, TYPE_UINT64, TYPE_FLOAT, TYPE_DOUBLE):
|
|
339
|
+
args = self.minimum, self.maximum, self.default
|
|
340
|
+
elif (ptype == TYPE_STRING or ptype == TYPE_BOOLEAN or
|
|
341
|
+
ptype.is_a(TYPE_ENUM) or ptype.is_a(TYPE_FLAGS) or
|
|
342
|
+
ptype.is_a(TYPE_VARIANT)):
|
|
343
|
+
args = (self.default,)
|
|
344
|
+
elif ptype in (TYPE_PYOBJECT, TYPE_GTYPE):
|
|
345
|
+
args = ()
|
|
346
|
+
elif ptype.is_a(TYPE_OBJECT) or ptype.is_a(TYPE_BOXED):
|
|
347
|
+
args = ()
|
|
348
|
+
else:
|
|
349
|
+
raise NotImplementedError(ptype)
|
|
350
|
+
|
|
351
|
+
return (self.type, self.nick, self.blurb) + args + (self.flags,)
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def install_properties(cls):
|
|
355
|
+
"""
|
|
356
|
+
Scans the given class for instances of Property and merges them
|
|
357
|
+
into the classes __gproperties__ dict if it exists or adds it if not.
|
|
358
|
+
"""
|
|
359
|
+
gproperties = cls.__dict__.get('__gproperties__', {})
|
|
360
|
+
|
|
361
|
+
props = []
|
|
362
|
+
for name, prop in cls.__dict__.items():
|
|
363
|
+
if isinstance(prop, Property): # not same as the built-in
|
|
364
|
+
# if a property was defined with a decorator, it may already have
|
|
365
|
+
# a name; if it was defined with an assignment (prop = Property(...))
|
|
366
|
+
# we set the property's name to the member name
|
|
367
|
+
if not prop.name:
|
|
368
|
+
prop.name = name
|
|
369
|
+
# we will encounter the same property multiple times in case of
|
|
370
|
+
# custom setter methods
|
|
371
|
+
if prop.name in gproperties:
|
|
372
|
+
if gproperties[prop.name] == prop.get_pspec_args():
|
|
373
|
+
continue
|
|
374
|
+
raise ValueError('Property %s was already found in __gproperties__' % prop.name)
|
|
375
|
+
gproperties[prop.name] = prop.get_pspec_args()
|
|
376
|
+
props.append(prop)
|
|
377
|
+
|
|
378
|
+
if not props:
|
|
379
|
+
return
|
|
380
|
+
|
|
381
|
+
cls.__gproperties__ = gproperties
|
|
382
|
+
|
|
383
|
+
if 'do_get_property' in cls.__dict__ or 'do_set_property' in cls.__dict__:
|
|
384
|
+
for prop in props:
|
|
385
|
+
if prop.fget != prop._default_getter or prop.fset != prop._default_setter:
|
|
386
|
+
raise TypeError(
|
|
387
|
+
"GObject subclass %r defines do_get/set_property"
|
|
388
|
+
" and it also uses a property with a custom setter"
|
|
389
|
+
" or getter. This is not allowed" %
|
|
390
|
+
(cls.__name__,))
|
|
391
|
+
|
|
392
|
+
def obj_get_property(self, pspec):
|
|
393
|
+
name = pspec.name.replace('-', '_')
|
|
394
|
+
return getattr(self, name, None)
|
|
395
|
+
cls.do_get_property = obj_get_property
|
|
396
|
+
|
|
397
|
+
def obj_set_property(self, pspec, value):
|
|
398
|
+
name = pspec.name.replace('-', '_')
|
|
399
|
+
prop = getattr(cls, name, None)
|
|
400
|
+
if prop:
|
|
401
|
+
prop.fset(self, value)
|
|
402
|
+
cls.do_set_property = obj_set_property
|