Skip to content

Commit 4d28e2d

Browse files
authored
Merge pull request #34 from Textualize/app-focus
app focus
2 parents b23e4b9 + 5a0ab50 commit 4d28e2d

File tree

3 files changed

+133
-3
lines changed

3 files changed

+133
-3
lines changed

src/textual_web/app_session.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,8 @@ async def read_stderr() -> None:
236236
await on_data(data)
237237
elif type_bytes == META:
238238
meta_data = json.loads(data)
239-
if meta_data.get("type") == "exit":
240-
await self.send_meta({"type": "exit"})
239+
if meta_data.get("type") in {"exit", "blur", "focus"}:
240+
await self.send_meta({"type": meta_data["type"]})
241241
else:
242242
await on_meta(json.loads(data))
243243

src/textual_web/ganglion_client.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
from .exit_poller import ExitPoller
1818
from .identity import generate
1919
from .packets import (
20+
Blur,
21+
Focus,
2022
PACKET_MAP,
2123
Handlers,
2224
NotifyTerminalSize,
@@ -418,3 +420,19 @@ async def on_notify_terminal_size(self, packet: NotifyTerminalSize) -> None:
418420

419421
async def on_route_ping(self, packet: RoutePing) -> None:
420422
await self.send(RoutePong(packet.route_key, packet.data))
423+
424+
async def on_focus(self, packet: Focus) -> None:
425+
"""The remote app was focused."""
426+
session_process = self.session_manager.get_session_by_route_key(
427+
RouteKey(packet.route_key)
428+
)
429+
if session_process is not None:
430+
await session_process.send_meta({"type": "focus"})
431+
432+
async def on_blur(self, packet: Blur) -> None:
433+
"""The remote app lost focus."""
434+
session_process = self.session_manager.get_session_by_route_key(
435+
RouteKey(packet.route_key)
436+
)
437+
if session_process is not None:
438+
await session_process.send_meta({"type": "blur"})

src/textual_web/packets.py

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""
22
This file is auto-generated from packets.yml and packets.py.template
33
4-
Time: Sun Aug 27 07:38:29 2023
4+
Time: Tue Nov 28 13:57:53 2023
55
Version: 1
66
77
To regenerate run `make packets.py` (in src directory)
@@ -67,6 +67,12 @@ class PacketType(IntEnum):
6767
# Notify the client that the terminal has change dimensions.
6868
NOTIFY_TERMINAL_SIZE = 11 # See NotifyTerminalSize()
6969

70+
# App has focus.
71+
FOCUS = 12 # See Focus()
72+
73+
# App was blurred.
74+
BLUR = 13 # See Blur()
75+
7076

7177
class Packet(tuple):
7278
"""Base class for a packet.
@@ -777,6 +783,100 @@ def height(self) -> int:
777783
return self[3]
778784

779785

786+
# PacketType.FOCUS (12)
787+
class Focus(Packet):
788+
"""App has focus.
789+
790+
Args:
791+
route_key (str): Route key.
792+
793+
"""
794+
795+
sender: ClassVar[str] = "both"
796+
"""Permitted sender, should be "client", "server", or "both"."""
797+
handler_name: ClassVar[str] = "on_focus"
798+
"""Name of the method used to handle this packet."""
799+
type: ClassVar[PacketType] = PacketType.FOCUS
800+
"""The packet type enumeration."""
801+
802+
_attributes: ClassVar[list[tuple[str, Type]]] = [
803+
("route_key", str),
804+
]
805+
_attribute_count = 1
806+
_get_handler = attrgetter("on_focus")
807+
808+
def __new__(cls, route_key: str) -> "Focus":
809+
return tuple.__new__(cls, (PacketType.FOCUS, route_key))
810+
811+
@classmethod
812+
def build(cls, route_key: str) -> "Focus":
813+
"""Build and validate a packet from its attributes."""
814+
if not isinstance(route_key, str):
815+
raise TypeError(
816+
f'packets.Focus Type of "route_key" incorrect; expected str, found {type(route_key)}'
817+
)
818+
return tuple.__new__(cls, (PacketType.FOCUS, route_key))
819+
820+
def __repr__(self) -> str:
821+
_type, route_key = self
822+
return f"Focus({abbreviate_repr(route_key)})"
823+
824+
def __rich_repr__(self) -> rich.repr.Result:
825+
yield "route_key", self.route_key
826+
827+
@property
828+
def route_key(self) -> str:
829+
"""Route key."""
830+
return self[1]
831+
832+
833+
# PacketType.BLUR (13)
834+
class Blur(Packet):
835+
"""App was blurred.
836+
837+
Args:
838+
route_key (str): Route key.
839+
840+
"""
841+
842+
sender: ClassVar[str] = "both"
843+
"""Permitted sender, should be "client", "server", or "both"."""
844+
handler_name: ClassVar[str] = "on_blur"
845+
"""Name of the method used to handle this packet."""
846+
type: ClassVar[PacketType] = PacketType.BLUR
847+
"""The packet type enumeration."""
848+
849+
_attributes: ClassVar[list[tuple[str, Type]]] = [
850+
("route_key", str),
851+
]
852+
_attribute_count = 1
853+
_get_handler = attrgetter("on_blur")
854+
855+
def __new__(cls, route_key: str) -> "Blur":
856+
return tuple.__new__(cls, (PacketType.BLUR, route_key))
857+
858+
@classmethod
859+
def build(cls, route_key: str) -> "Blur":
860+
"""Build and validate a packet from its attributes."""
861+
if not isinstance(route_key, str):
862+
raise TypeError(
863+
f'packets.Blur Type of "route_key" incorrect; expected str, found {type(route_key)}'
864+
)
865+
return tuple.__new__(cls, (PacketType.BLUR, route_key))
866+
867+
def __repr__(self) -> str:
868+
_type, route_key = self
869+
return f"Blur({abbreviate_repr(route_key)})"
870+
871+
def __rich_repr__(self) -> rich.repr.Result:
872+
yield "route_key", self.route_key
873+
874+
@property
875+
def route_key(self) -> str:
876+
"""Route key."""
877+
return self[1]
878+
879+
780880
# A mapping of the packet id on to the packet class
781881
PACKET_MAP: dict[int, type[Packet]] = {
782882
1: Ping,
@@ -790,6 +890,8 @@ def height(self) -> int:
790890
9: RoutePing,
791891
10: RoutePong,
792892
11: NotifyTerminalSize,
893+
12: Focus,
894+
13: Blur,
793895
}
794896

795897
# A mapping of the packet name on to the packet class
@@ -805,6 +907,8 @@ def height(self) -> int:
805907
"routeping": RoutePing,
806908
"routepong": RoutePong,
807909
"notifyterminalsize": NotifyTerminalSize,
910+
"focus": Focus,
911+
"blur": Blur,
808912
}
809913

810914

@@ -865,6 +969,14 @@ async def on_notify_terminal_size(self, packet: NotifyTerminalSize) -> None:
865969
"""Notify the client that the terminal has change dimensions."""
866970
await self.on_default(packet)
867971

972+
async def on_focus(self, packet: Focus) -> None:
973+
"""App has focus."""
974+
await self.on_default(packet)
975+
976+
async def on_blur(self, packet: Blur) -> None:
977+
"""App was blurred."""
978+
await self.on_default(packet)
979+
868980
async def on_default(self, packet: Packet) -> None:
869981
"""Called when a packet is not handled."""
870982

0 commit comments

Comments
 (0)