Skip to content

Commit

Permalink
[proxy] call descructor on __del__
Browse files Browse the repository at this point in the history
  • Loading branch information
aslpavel committed Sep 29, 2024
1 parent b307f0a commit 15d6602
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 6 deletions.
9 changes: 7 additions & 2 deletions wayland/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,7 @@ class Proxy:
"_connection",
"_is_attached",
"_is_detached",
"_is_destroyed",
"_handlers",
"_futures",
]
Expand All @@ -746,10 +747,14 @@ def __init__(
self._id: Id = id
self._interface: Interface = interface
self._connection: Connection = connection
self._is_attached: bool = False
self._is_detached: bool = False
self._handlers: list[EventHandler | None] = [None] * len(interface.events)
self._futures: WeakSet[Future[Any]] = WeakSet()
# `new_id` has been send to the other side
self._is_attached: bool = False
# release by the other side and will no longer be identified by its id
self._is_detached: bool = False
# destructor has been called
self._is_destroyed: bool = False

def __call__(self, name: str, *args: Any) -> None:
if not self._is_attached or self._is_detached:
Expand Down
21 changes: 18 additions & 3 deletions wayland/codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,18 @@ def generate_client(
for opcode, request in enumerate(interface.requests):
if request.destructor and not request.args:
destructor = request.name
_generate_request(module, opcode, request)
_generate_request(module, opcode, request, request.destructor)

# destroy scope
if destructor:
print(
f" def __enter__(self) -> {class_name}:\n"
f" return self\n"
" return self\n"
"\n"
f" def __exit__(self, *_: Any) -> None:\n"
" def __exit__(self, *_: Any) -> None:\n"
f" self.{destructor}()\n"
"\n"
" def __del__(self) -> None:\n"
f" self.{destructor}()\n",
file=module,
)
Expand Down Expand Up @@ -156,6 +159,7 @@ def _generate_request(
module: io.StringIO,
opcode: int,
request: WRequest,
is_destructor: bool,
) -> None:
results_desc: list[ArgNewId] = []
args_types: list[str] = []
Expand Down Expand Up @@ -201,6 +205,17 @@ def _generate_request(
if request.summary:
print(f' """{request.summary}"""', file=module)

if is_destructor:
# no-op for disconnected destructor
# fmt: off
print(
" if self._is_destroyed or self._is_detached or self._connection.is_terminated:\n"
" return None\n"
" self._is_destroyed = True",
file=module,
)
# fmt: on

# proxies
result_vals: list[str] = []
for result_desc in results_desc:
Expand Down
90 changes: 90 additions & 0 deletions wayland/protocol/wayland.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ def create_buffer(self, offset: int, width: int, height: int, stride: int, forma

def destroy(self) -> None:
"""destroy the pool"""
if self._is_destroyed or self._is_detached or self._connection.is_terminated:
return None
self._is_destroyed = True
self._call(OpCode(1), tuple())
return None

Expand All @@ -249,6 +252,9 @@ def __enter__(self) -> WlShmPool:
def __exit__(self, *_: Any) -> None:
self.destroy()

def __del__(self) -> None:
self.destroy()

PROXIES["wl_shm_pool"] = WlShmPool

class WlShm(Proxy):
Expand Down Expand Up @@ -414,6 +420,9 @@ def create_pool(self, fd: Fd, size: int) -> WlShmPool:

def release(self) -> None:
"""release the shm object"""
if self._is_destroyed or self._is_detached or self._connection.is_terminated:
return None
self._is_destroyed = True
self._call(OpCode(1), tuple())
return None

Expand All @@ -423,6 +432,9 @@ def __enter__(self) -> WlShm:
def __exit__(self, *_: Any) -> None:
self.release()

def __del__(self) -> None:
self.release()

def on_format(self, handler: Callable[[Format], bool]) -> Callable[[Format], bool] | None:
"""pixel format description"""
_opcode = OpCode(0)
Expand Down Expand Up @@ -589,6 +601,9 @@ def __init__(self, id: Id, connection: Connection) -> None:

def destroy(self) -> None:
"""destroy a buffer"""
if self._is_destroyed or self._is_detached or self._connection.is_terminated:
return None
self._is_destroyed = True
self._call(OpCode(0), tuple())
return None

Expand All @@ -598,6 +613,9 @@ def __enter__(self) -> WlBuffer:
def __exit__(self, *_: Any) -> None:
self.destroy()

def __del__(self) -> None:
self.destroy()

def on_release(self, handler: Callable[[], bool]) -> Callable[[], bool] | None:
"""compositor releases buffer"""
_opcode = OpCode(0)
Expand Down Expand Up @@ -651,6 +669,9 @@ def receive(self, mime_type: str, fd: Fd) -> None:

def destroy(self) -> None:
"""destroy data offer"""
if self._is_destroyed or self._is_detached or self._connection.is_terminated:
return None
self._is_destroyed = True
self._call(OpCode(2), tuple())
return None

Expand All @@ -670,6 +691,9 @@ def __enter__(self) -> WlDataOffer:
def __exit__(self, *_: Any) -> None:
self.destroy()

def __del__(self) -> None:
self.destroy()

def on_offer(self, handler: Callable[[str], bool]) -> Callable[[str], bool] | None:
"""advertise offered mime type"""
_opcode = OpCode(0)
Expand Down Expand Up @@ -741,6 +765,9 @@ def offer(self, mime_type: str) -> None:

def destroy(self) -> None:
"""destroy the data source"""
if self._is_destroyed or self._is_detached or self._connection.is_terminated:
return None
self._is_destroyed = True
self._call(OpCode(1), tuple())
return None

Expand All @@ -755,6 +782,9 @@ def __enter__(self) -> WlDataSource:
def __exit__(self, *_: Any) -> None:
self.destroy()

def __del__(self) -> None:
self.destroy()

def on_target(self, handler: Callable[[str], bool]) -> Callable[[str], bool] | None:
"""a target accepts an offered mime type"""
_opcode = OpCode(0)
Expand Down Expand Up @@ -847,6 +877,9 @@ def set_selection(self, source: WlDataSource | None, serial: int) -> None:

def release(self) -> None:
"""destroy data device"""
if self._is_destroyed or self._is_detached or self._connection.is_terminated:
return None
self._is_destroyed = True
self._call(OpCode(2), tuple())
return None

Expand All @@ -856,6 +889,9 @@ def __enter__(self) -> WlDataDevice:
def __exit__(self, *_: Any) -> None:
self.release()

def __del__(self) -> None:
self.release()

def on_data_offer(self, handler: Callable[[WlDataOffer], bool]) -> Callable[[WlDataOffer], bool] | None:
"""introduce a new wl_data_offer"""
_opcode = OpCode(0)
Expand Down Expand Up @@ -1201,6 +1237,9 @@ def __init__(self, id: Id, connection: Connection) -> None:

def destroy(self) -> None:
"""delete surface"""
if self._is_destroyed or self._is_detached or self._connection.is_terminated:
return None
self._is_destroyed = True
self._call(OpCode(0), tuple())
return None

Expand Down Expand Up @@ -1261,6 +1300,9 @@ def __enter__(self) -> WlSurface:
def __exit__(self, *_: Any) -> None:
self.destroy()

def __del__(self) -> None:
self.destroy()

def on_enter(self, handler: Callable[[WlOutput], bool]) -> Callable[[WlOutput], bool] | None:
"""surface enters an output"""
_opcode = OpCode(0)
Expand Down Expand Up @@ -1357,6 +1399,9 @@ def get_touch(self) -> WlTouch:

def release(self) -> None:
"""release the seat object"""
if self._is_destroyed or self._is_detached or self._connection.is_terminated:
return None
self._is_destroyed = True
self._call(OpCode(3), tuple())
return None

Expand All @@ -1366,6 +1411,9 @@ def __enter__(self) -> WlSeat:
def __exit__(self, *_: Any) -> None:
self.release()

def __del__(self) -> None:
self.release()

def on_capabilities(self, handler: Callable[[Capability], bool]) -> Callable[[Capability], bool] | None:
"""seat capabilities changed"""
_opcode = OpCode(0)
Expand Down Expand Up @@ -1468,6 +1516,9 @@ def set_cursor(self, serial: int, surface: WlSurface | None, hotspot_x: int, hot

def release(self) -> None:
"""release the pointer object"""
if self._is_destroyed or self._is_detached or self._connection.is_terminated:
return None
self._is_destroyed = True
self._call(OpCode(1), tuple())
return None

Expand All @@ -1477,6 +1528,9 @@ def __enter__(self) -> WlPointer:
def __exit__(self, *_: Any) -> None:
self.release()

def __del__(self) -> None:
self.release()

def on_enter(self, handler: Callable[[int, WlSurface, float, float], bool]) -> Callable[[int, WlSurface, float, float], bool] | None:
"""enter event"""
_opcode = OpCode(0)
Expand Down Expand Up @@ -1619,6 +1673,9 @@ def __init__(self, id: Id, connection: Connection) -> None:

def release(self) -> None:
"""release the keyboard object"""
if self._is_destroyed or self._is_detached or self._connection.is_terminated:
return None
self._is_destroyed = True
self._call(OpCode(0), tuple())
return None

Expand All @@ -1628,6 +1685,9 @@ def __enter__(self) -> WlKeyboard:
def __exit__(self, *_: Any) -> None:
self.release()

def __del__(self) -> None:
self.release()

def on_keymap(self, handler: Callable[[KeymapFormat, Fd, int], bool]) -> Callable[[KeymapFormat, Fd, int], bool] | None:
"""keyboard mapping"""
_opcode = OpCode(0)
Expand Down Expand Up @@ -1708,6 +1768,9 @@ def __init__(self, id: Id, connection: Connection) -> None:

def release(self) -> None:
"""release the touch object"""
if self._is_destroyed or self._is_detached or self._connection.is_terminated:
return None
self._is_destroyed = True
self._call(OpCode(0), tuple())
return None

Expand All @@ -1717,6 +1780,9 @@ def __enter__(self) -> WlTouch:
def __exit__(self, *_: Any) -> None:
self.release()

def __del__(self) -> None:
self.release()

def on_down(self, handler: Callable[[int, int, WlSurface, int, float, float], bool]) -> Callable[[int, int, WlSurface, int, float, float], bool] | None:
"""touch down event and beginning of a touch sequence"""
_opcode = OpCode(0)
Expand Down Expand Up @@ -1818,6 +1884,9 @@ def __init__(self, id: Id, connection: Connection) -> None:

def release(self) -> None:
"""release the output object"""
if self._is_destroyed or self._is_detached or self._connection.is_terminated:
return None
self._is_destroyed = True
self._call(OpCode(0), tuple())
return None

Expand All @@ -1827,6 +1896,9 @@ def __enter__(self) -> WlOutput:
def __exit__(self, *_: Any) -> None:
self.release()

def __del__(self) -> None:
self.release()

def on_geometry(self, handler: Callable[[int, int, int, int, Subpixel, str, str, Transform], bool]) -> Callable[[int, int, int, int, Subpixel, str, str, Transform], bool] | None:
"""properties of the output"""
_opcode = OpCode(0)
Expand Down Expand Up @@ -1918,6 +1990,9 @@ def __init__(self, id: Id, connection: Connection) -> None:

def destroy(self) -> None:
"""destroy region"""
if self._is_destroyed or self._is_detached or self._connection.is_terminated:
return None
self._is_destroyed = True
self._call(OpCode(0), tuple())
return None

Expand All @@ -1937,6 +2012,9 @@ def __enter__(self) -> WlRegion:
def __exit__(self, *_: Any) -> None:
self.destroy()

def __del__(self) -> None:
self.destroy()

PROXIES["wl_region"] = WlRegion

class WlSubcompositor(Proxy):
Expand Down Expand Up @@ -1966,6 +2044,9 @@ def __init__(self, id: Id, connection: Connection) -> None:

def destroy(self) -> None:
"""unbind from the subcompositor interface"""
if self._is_destroyed or self._is_detached or self._connection.is_terminated:
return None
self._is_destroyed = True
self._call(OpCode(0), tuple())
return None

Expand All @@ -1981,6 +2062,9 @@ def __enter__(self) -> WlSubcompositor:
def __exit__(self, *_: Any) -> None:
self.destroy()

def __del__(self) -> None:
self.destroy()

class Error(Enum):
BAD_SURFACE = 0
BAD_PARENT = 1
Expand Down Expand Up @@ -2023,6 +2107,9 @@ def __init__(self, id: Id, connection: Connection) -> None:

def destroy(self) -> None:
"""remove sub-surface interface"""
if self._is_destroyed or self._is_detached or self._connection.is_terminated:
return None
self._is_destroyed = True
self._call(OpCode(0), tuple())
return None

Expand Down Expand Up @@ -2057,6 +2144,9 @@ def __enter__(self) -> WlSubsurface:
def __exit__(self, *_: Any) -> None:
self.destroy()

def __del__(self) -> None:
self.destroy()

class Error(Enum):
BAD_SURFACE = 0

Expand Down
Loading

0 comments on commit 15d6602

Please sign in to comment.