diff --git a/i3ipc/__init__.py b/i3ipc/__init__.py index fbdf09e..1370a17 100644 --- a/i3ipc/__init__.py +++ b/i3ipc/__init__.py @@ -2,7 +2,7 @@ __author_email__, __license__, __copyright__) from .replies import (BarConfigReply, CommandReply, ConfigReply, OutputReply, TickReply, - VersionReply, WorkspaceReply, SeatReply, InputReply) + VersionReply, WorkspaceReply, SeatReply, InputReply, BindingStateReply) from .events import (BarconfigUpdateEvent, BindingEvent, BindingInfo, OutputEvent, ShutdownEvent, WindowEvent, TickEvent, ModeEvent, WorkspaceEvent, InputEvent, Event) from .con import Con diff --git a/i3ipc/_private/types.py b/i3ipc/_private/types.py index b6ae544..18c34dc 100644 --- a/i3ipc/_private/types.py +++ b/i3ipc/_private/types.py @@ -13,6 +13,7 @@ class MessageType(Enum): GET_BINDING_MODES = 8 GET_CONFIG = 9 SEND_TICK = 10 + GET_BINDING_STATE = 12 # sway-specific command types GET_INPUTS = 100 GET_SEATS = 101 @@ -30,6 +31,7 @@ class ReplyType(Enum): BINDING_MODES = 8 GET_CONFIG = 9 TICK = 10 + BINDING_STATE = 12 class EventType(Enum): diff --git a/i3ipc/aio/connection.py b/i3ipc/aio/connection.py index 4755853..c1029c9 100644 --- a/i3ipc/aio/connection.py +++ b/i3ipc/aio/connection.py @@ -1,6 +1,6 @@ from .._private import PubSub, MessageType, EventType, Synchronizer from ..replies import (BarConfigReply, CommandReply, ConfigReply, OutputReply, TickReply, - VersionReply, WorkspaceReply, SeatReply, InputReply) + VersionReply, WorkspaceReply, SeatReply, InputReply, BindingStateReply) from ..events import (IpcBaseEvent, BarconfigUpdateEvent, BindingEvent, OutputEvent, ShutdownEvent, WindowEvent, TickEvent, ModeEvent, WorkspaceEvent, InputEvent, Event) from .. import con @@ -682,6 +682,16 @@ async def send_tick(self, payload: str = "") -> TickReply: data = json.loads(data) return TickReply(data) + async def get_binding_state(self) -> BindingStateReply: + """Gets the name of the currently active binding mode. + + :returns: A class containing the name of the currently active binding mode. + :rtype: :class:`i3ipc.BindingStateReply` + """ + data = await self._message(MessageType.GET_BINDING_STATE, '') + data = json.loads(data) + return BindingStateReply(data) + async def get_inputs(self) -> List[InputReply]: """(sway only) Gets the inputs connected to the compositor. diff --git a/i3ipc/connection.py b/i3ipc/connection.py index 50d3d44..78bd5f5 100644 --- a/i3ipc/connection.py +++ b/i3ipc/connection.py @@ -2,7 +2,7 @@ from .con import Con from .replies import (BarConfigReply, CommandReply, ConfigReply, OutputReply, TickReply, - VersionReply, WorkspaceReply, SeatReply, InputReply) + VersionReply, WorkspaceReply, SeatReply, InputReply, BindingStateReply) from .events import (IpcBaseEvent, BarconfigUpdateEvent, BindingEvent, OutputEvent, ShutdownEvent, WindowEvent, TickEvent, ModeEvent, WorkspaceEvent, InputEvent, Event) from ._private import PubSub, MessageType, EventType, Synchronizer @@ -349,6 +349,16 @@ def send_tick(self, payload: str = "") -> TickReply: data = json.loads(data) return TickReply(data) + def get_binding_state(self) -> BindingStateReply: + """Gets the name of the currently active binding mode. + + :returns: A class containing the name of the currently active binding mode. + :rtype: :class:`i3ipc.BindingStateReply` + """ + data = self._message(MessageType.GET_BINDING_STATE, '') + data = json.loads(data) + return BindingStateReply(data) + def _subscribe(self, events): events_obj = [] if events & EventType.WORKSPACE.value: diff --git a/i3ipc/replies.py b/i3ipc/replies.py index 8a2fa6a..1dfc8bf 100644 --- a/i3ipc/replies.py +++ b/i3ipc/replies.py @@ -287,6 +287,21 @@ class TickReply(_BaseReply): ] +class BindingStateReply(_BaseReply): + """A reply to the ``GET_BINDING_STATE`` message. + + .. seealso:: https://i3wm.org/docs/ipc.html#_binding_state_reply + + :ivar name: Name of the currently active binding mode. + :vartype name: str + :ivar ipc_data: The raw data from the i3 ipc. + :vartype ipc_data: dict + """ + _members = [ + ('name', str), + ] + + class InputReply(_BaseReply): """(sway only) A reply to ``GET_INPUTS`` message. diff --git a/test/aio/test_get_binding_state.py b/test/aio/test_get_binding_state.py new file mode 100644 index 0000000..8ac68a3 --- /dev/null +++ b/test/aio/test_get_binding_state.py @@ -0,0 +1,18 @@ +from .ipctest import IpcTest +import i3ipc + +import pytest + + +class TestBindingState(IpcTest): + @pytest.mark.asyncio + async def test_binding_state(self, i3): + binding_state = await i3.get_binding_state() + assert isinstance(binding_state, i3ipc.BindingStateReply) + + await i3.command('mode default') + binding_state = await i3.get_binding_state() + assert binding_state.name == 'default' + await i3.command('mode resize') + binding_state = await i3.get_binding_state() + assert binding_state.name == 'resize' diff --git a/test/test_get_binding_state.py b/test/test_get_binding_state.py new file mode 100644 index 0000000..f9eaa5b --- /dev/null +++ b/test/test_get_binding_state.py @@ -0,0 +1,15 @@ +from ipctest import IpcTest +import i3ipc + + +class TestBindingState(IpcTest): + def test_binding_state(self, i3): + binding_state = i3.get_binding_state() + assert isinstance(binding_state, i3ipc.BindingStateReply) + + i3.command('mode "default"') + binding_state = i3.get_binding_state() + assert binding_state.name == 'default' + i3.command('mode "resize"') + binding_state = i3.get_binding_state() + assert binding_state.name == 'resize'