diff --git a/bar/main.py b/bar/main.py
index 955219a..5849389 100644
--- a/bar/main.py
+++ b/bar/main.py
@@ -5,7 +5,7 @@ from loguru import logger
from fabric import Application
from fabric.system_tray.widgets import SystemTray
from fabric.widgets.wayland import WaylandWindow as Window
-from .river.widgets import (
+from fabric.river.widgets import (
get_river_connection,
)
from fabric.utils import (
diff --git a/bar/modules/bar.py b/bar/modules/bar.py
index be6e14b..b8df86f 100644
--- a/bar/modules/bar.py
+++ b/bar/modules/bar.py
@@ -8,7 +8,7 @@ from bar.modules.player import Player
from bar.modules.vinyl import VinylButton
from fabric.widgets.wayland import WaylandWindow as Window
from fabric.system_tray.widgets import SystemTray
-from ..river.widgets import (
+from fabric.river.widgets import (
RiverWorkspaces,
RiverWorkspaceButton,
RiverActiveWindow,
diff --git a/bar/river/__init__.py b/bar/river/__init__.py
deleted file mode 100644
index ec4daab..0000000
--- a/bar/river/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from .service import River
-
-__all__ = ["River"]
diff --git a/bar/river/generated/__init__.py b/bar/river/generated/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/bar/river/generated/river_control_unstable_v1/__init__.py b/bar/river/generated/river_control_unstable_v1/__init__.py
deleted file mode 100644
index 3801d2e..0000000
--- a/bar/river/generated/river_control_unstable_v1/__init__.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# This file has been autogenerated by the pywayland scanner
-
-# Copyright 2020 The River Developers
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-from .zriver_command_callback_v1 import ZriverCommandCallbackV1 # noqa: F401
-from .zriver_control_v1 import ZriverControlV1 # noqa: F401
diff --git a/bar/river/generated/river_control_unstable_v1/zriver_command_callback_v1.py b/bar/river/generated/river_control_unstable_v1/zriver_command_callback_v1.py
deleted file mode 100644
index a6c264d..0000000
--- a/bar/river/generated/river_control_unstable_v1/zriver_command_callback_v1.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# This file has been autogenerated by the pywayland scanner
-
-# Copyright 2020 The River Developers
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-from __future__ import annotations
-
-from pywayland.protocol_core import (Argument, ArgumentType, Global, Interface,
- Proxy, Resource)
-
-
-class ZriverCommandCallbackV1(Interface):
- """Callback object
-
- This object is created by the run_command request. Exactly one of the
- success or failure events will be sent. This object will be destroyed by
- the compositor after one of the events is sent.
- """
-
- name = "zriver_command_callback_v1"
- version = 1
-
-
-class ZriverCommandCallbackV1Proxy(Proxy[ZriverCommandCallbackV1]):
- interface = ZriverCommandCallbackV1
-
-
-class ZriverCommandCallbackV1Resource(Resource):
- interface = ZriverCommandCallbackV1
-
- @ZriverCommandCallbackV1.event(
- Argument(ArgumentType.String),
- )
- def success(self, output: str) -> None:
- """Command successful
-
- Sent when the command has been successfully received and executed by
- the compositor. Some commands may produce output, in which case the
- output argument will be a non-empty string.
-
- :param output:
- the output of the command
- :type output:
- `ArgumentType.String`
- """
- self._post_event(0, output)
-
- @ZriverCommandCallbackV1.event(
- Argument(ArgumentType.String),
- )
- def failure(self, failure_message: str) -> None:
- """Command failed
-
- Sent when the command could not be carried out. This could be due to
- sending a non-existent command, no command, not enough arguments, too
- many arguments, invalid arguments, etc.
-
- :param failure_message:
- a message explaining why failure occurred
- :type failure_message:
- `ArgumentType.String`
- """
- self._post_event(1, failure_message)
-
-
-class ZriverCommandCallbackV1Global(Global):
- interface = ZriverCommandCallbackV1
-
-
-ZriverCommandCallbackV1._gen_c()
-ZriverCommandCallbackV1.proxy_class = ZriverCommandCallbackV1Proxy
-ZriverCommandCallbackV1.resource_class = ZriverCommandCallbackV1Resource
-ZriverCommandCallbackV1.global_class = ZriverCommandCallbackV1Global
diff --git a/bar/river/generated/river_control_unstable_v1/zriver_control_v1.py b/bar/river/generated/river_control_unstable_v1/zriver_control_v1.py
deleted file mode 100644
index 567c5e3..0000000
--- a/bar/river/generated/river_control_unstable_v1/zriver_control_v1.py
+++ /dev/null
@@ -1,111 +0,0 @@
-# This file has been autogenerated by the pywayland scanner
-
-# Copyright 2020 The River Developers
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-from __future__ import annotations
-
-from pywayland.protocol_core import (
- Argument,
- ArgumentType,
- Global,
- Interface,
- Proxy,
- Resource,
-)
-
-from pywayland.protocol.wayland import WlSeat
-from .zriver_command_callback_v1 import ZriverCommandCallbackV1
-
-
-class ZriverControlV1(Interface):
- """Run compositor commands
-
- This interface allows clients to run compositor commands and receive a
- success/failure response with output or a failure message respectively.
-
- Each command is built up in a series of add_argument requests and executed
- with a run_command request. The first argument is the command to be run.
-
- A complete list of commands should be made available in the man page of the
- compositor.
- """
-
- name = "zriver_control_v1"
- version = 1
-
-
-class ZriverControlV1Proxy(Proxy[ZriverControlV1]):
- interface = ZriverControlV1
-
- @ZriverControlV1.request()
- def destroy(self) -> None:
- """Destroy the river_control object
-
- This request indicates that the client will not use the river_control
- object any more. Objects that have been created through this instance
- are not affected.
- """
- self._marshal(0)
- self._destroy()
-
- @ZriverControlV1.request(
- Argument(ArgumentType.String),
- )
- def add_argument(self, argument: str) -> None:
- """Add an argument to the current command
-
- Arguments are stored by the server in the order they were sent until
- the run_command request is made.
-
- :param argument:
- the argument to add
- :type argument:
- `ArgumentType.String`
- """
- self._marshal(1, argument)
-
- @ZriverControlV1.request(
- Argument(ArgumentType.Object, interface=WlSeat),
- Argument(ArgumentType.NewId, interface=ZriverCommandCallbackV1),
- )
- def run_command(self, seat: WlSeat) -> Proxy[ZriverCommandCallbackV1]:
- """Run the current command
-
- Execute the command built up using the add_argument request for the
- given seat.
-
- :param seat:
- :type seat:
- :class:`~pywayland.protocol.wayland.WlSeat`
- :returns:
- :class:`~pywayland.protocol.river_control_unstable_v1.ZriverCommandCallbackV1`
- -- callback object
- """
- callback = self._marshal_constructor(2, ZriverCommandCallbackV1, seat)
- return callback
-
-
-class ZriverControlV1Resource(Resource):
- interface = ZriverControlV1
-
-
-class ZriverControlV1Global(Global):
- interface = ZriverControlV1
-
-
-ZriverControlV1._gen_c()
-ZriverControlV1.proxy_class = ZriverControlV1Proxy
-ZriverControlV1.resource_class = ZriverControlV1Resource
-ZriverControlV1.global_class = ZriverControlV1Global
diff --git a/bar/river/generated/river_status_unstable_v1/__init__.py b/bar/river/generated/river_status_unstable_v1/__init__.py
deleted file mode 100644
index 51d6f86..0000000
--- a/bar/river/generated/river_status_unstable_v1/__init__.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# This file has been autogenerated by the pywayland scanner
-
-# Copyright 2020 The River Developers
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-from .zriver_output_status_v1 import ZriverOutputStatusV1 # noqa: F401
-from .zriver_seat_status_v1 import ZriverSeatStatusV1 # noqa: F401
-from .zriver_status_manager_v1 import ZriverStatusManagerV1 # noqa: F401
diff --git a/bar/river/generated/river_status_unstable_v1/zriver_output_status_v1.py b/bar/river/generated/river_status_unstable_v1/zriver_output_status_v1.py
deleted file mode 100644
index 6cc53ce..0000000
--- a/bar/river/generated/river_status_unstable_v1/zriver_output_status_v1.py
+++ /dev/null
@@ -1,134 +0,0 @@
-# This file has been autogenerated by the pywayland scanner
-
-# Copyright 2020 The River Developers
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-from __future__ import annotations
-
-from pywayland.protocol_core import (Argument, ArgumentType, Global, Interface,
- Proxy, Resource)
-
-
-class ZriverOutputStatusV1(Interface):
- """Track output tags and focus
-
- This interface allows clients to receive information about the current
- windowing state of an output.
- """
-
- name = "zriver_output_status_v1"
- version = 4
-
-
-class ZriverOutputStatusV1Proxy(Proxy[ZriverOutputStatusV1]):
- interface = ZriverOutputStatusV1
-
- @ZriverOutputStatusV1.request()
- def destroy(self) -> None:
- """Destroy the river_output_status object
-
- This request indicates that the client will not use the
- river_output_status object any more.
- """
- self._marshal(0)
- self._destroy()
-
-
-class ZriverOutputStatusV1Resource(Resource):
- interface = ZriverOutputStatusV1
-
- @ZriverOutputStatusV1.event(
- Argument(ArgumentType.Uint),
- )
- def focused_tags(self, tags: int) -> None:
- """Focused tags of the output
-
- Sent once binding the interface and again whenever the tag focus of the
- output changes.
-
- :param tags:
- 32-bit bitfield
- :type tags:
- `ArgumentType.Uint`
- """
- self._post_event(0, tags)
-
- @ZriverOutputStatusV1.event(
- Argument(ArgumentType.Array),
- )
- def view_tags(self, tags: list) -> None:
- """Tag state of an output's views
-
- Sent once on binding the interface and again whenever the tag state of
- the output changes.
-
- :param tags:
- array of 32-bit bitfields
- :type tags:
- `ArgumentType.Array`
- """
- self._post_event(1, tags)
-
- @ZriverOutputStatusV1.event(
- Argument(ArgumentType.Uint),
- version=2,
- )
- def urgent_tags(self, tags: int) -> None:
- """Tags of the output with an urgent view
-
- Sent once on binding the interface and again whenever the set of tags
- with at least one urgent view changes.
-
- :param tags:
- 32-bit bitfield
- :type tags:
- `ArgumentType.Uint`
- """
- self._post_event(2, tags)
-
- @ZriverOutputStatusV1.event(
- Argument(ArgumentType.String),
- version=4,
- )
- def layout_name(self, name: str) -> None:
- """Name of the layout
-
- Sent once on binding the interface should a layout name exist and again
- whenever the name changes.
-
- :param name:
- layout name
- :type name:
- `ArgumentType.String`
- """
- self._post_event(3, name)
-
- @ZriverOutputStatusV1.event(version=4)
- def layout_name_clear(self) -> None:
- """Name of the layout
-
- Sent when the current layout name has been removed without a new one
- being set, for example when the active layout generator disconnects.
- """
- self._post_event(4)
-
-
-class ZriverOutputStatusV1Global(Global):
- interface = ZriverOutputStatusV1
-
-
-ZriverOutputStatusV1._gen_c()
-ZriverOutputStatusV1.proxy_class = ZriverOutputStatusV1Proxy
-ZriverOutputStatusV1.resource_class = ZriverOutputStatusV1Resource
-ZriverOutputStatusV1.global_class = ZriverOutputStatusV1Global
diff --git a/bar/river/generated/river_status_unstable_v1/zriver_seat_status_v1.py b/bar/river/generated/river_status_unstable_v1/zriver_seat_status_v1.py
deleted file mode 100644
index 2931b80..0000000
--- a/bar/river/generated/river_status_unstable_v1/zriver_seat_status_v1.py
+++ /dev/null
@@ -1,124 +0,0 @@
-# This file has been autogenerated by the pywayland scanner
-
-# Copyright 2020 The River Developers
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-from __future__ import annotations
-
-from pywayland.protocol.wayland import WlOutput
-from pywayland.protocol_core import (Argument, ArgumentType, Global, Interface,
- Proxy, Resource)
-
-
-class ZriverSeatStatusV1(Interface):
- """Track seat focus
-
- This interface allows clients to receive information about the current
- focus of a seat. Note that (un)focused_output events will only be sent if
- the client has bound the relevant
- :class:`~pywayland.protocol.wayland.WlOutput` globals.
- """
-
- name = "zriver_seat_status_v1"
- version = 3
-
-
-class ZriverSeatStatusV1Proxy(Proxy[ZriverSeatStatusV1]):
- interface = ZriverSeatStatusV1
-
- @ZriverSeatStatusV1.request()
- def destroy(self) -> None:
- """Destroy the river_seat_status object
-
- This request indicates that the client will not use the
- river_seat_status object any more.
- """
- self._marshal(0)
- self._destroy()
-
-
-class ZriverSeatStatusV1Resource(Resource):
- interface = ZriverSeatStatusV1
-
- @ZriverSeatStatusV1.event(
- Argument(ArgumentType.Object, interface=WlOutput),
- )
- def focused_output(self, output: WlOutput) -> None:
- """The seat focused an output
-
- Sent on binding the interface and again whenever an output gains focus.
-
- :param output:
- :type output:
- :class:`~pywayland.protocol.wayland.WlOutput`
- """
- self._post_event(0, output)
-
- @ZriverSeatStatusV1.event(
- Argument(ArgumentType.Object, interface=WlOutput),
- )
- def unfocused_output(self, output: WlOutput) -> None:
- """The seat unfocused an output
-
- Sent whenever an output loses focus.
-
- :param output:
- :type output:
- :class:`~pywayland.protocol.wayland.WlOutput`
- """
- self._post_event(1, output)
-
- @ZriverSeatStatusV1.event(
- Argument(ArgumentType.String),
- )
- def focused_view(self, title: str) -> None:
- """Information on the focused view
-
- Sent once on binding the interface and again whenever the focused view
- or a property thereof changes. The title may be an empty string if no
- view is focused or the focused view did not set a title.
-
- :param title:
- title of the focused view
- :type title:
- `ArgumentType.String`
- """
- self._post_event(2, title)
-
- @ZriverSeatStatusV1.event(
- Argument(ArgumentType.String),
- version=3,
- )
- def mode(self, name: str) -> None:
- """The active mode changed
-
- Sent once on binding the interface and again whenever a new mode is
- entered (e.g. with riverctl enter-mode foobar).
-
- :param name:
- name of the mode
- :type name:
- `ArgumentType.String`
- """
- self._post_event(3, name)
-
-
-class ZriverSeatStatusV1Global(Global):
- interface = ZriverSeatStatusV1
-
-
-ZriverSeatStatusV1._gen_c()
-ZriverSeatStatusV1.proxy_class = ZriverSeatStatusV1Proxy
-ZriverSeatStatusV1.resource_class = ZriverSeatStatusV1Resource
-ZriverSeatStatusV1.global_class = ZriverSeatStatusV1Global
diff --git a/bar/river/generated/river_status_unstable_v1/zriver_status_manager_v1.py b/bar/river/generated/river_status_unstable_v1/zriver_status_manager_v1.py
deleted file mode 100644
index 076450b..0000000
--- a/bar/river/generated/river_status_unstable_v1/zriver_status_manager_v1.py
+++ /dev/null
@@ -1,102 +0,0 @@
-# This file has been autogenerated by the pywayland scanner
-
-# Copyright 2020 The River Developers
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-from __future__ import annotations
-
-from pywayland.protocol.wayland import WlOutput, WlSeat
-from pywayland.protocol_core import (Argument, ArgumentType, Global, Interface,
- Proxy, Resource)
-
-from .zriver_output_status_v1 import ZriverOutputStatusV1
-from .zriver_seat_status_v1 import ZriverSeatStatusV1
-
-
-class ZriverStatusManagerV1(Interface):
- """Manage river status objects
-
- A global factory for objects that receive status information specific to
- river. It could be used to implement, for example, a status bar.
- """
-
- name = "zriver_status_manager_v1"
- version = 4
-
-
-class ZriverStatusManagerV1Proxy(Proxy[ZriverStatusManagerV1]):
- interface = ZriverStatusManagerV1
-
- @ZriverStatusManagerV1.request()
- def destroy(self) -> None:
- """Destroy the river_status_manager object
-
- This request indicates that the client will not use the
- river_status_manager object any more. Objects that have been created
- through this instance are not affected.
- """
- self._marshal(0)
- self._destroy()
-
- @ZriverStatusManagerV1.request(
- Argument(ArgumentType.NewId, interface=ZriverOutputStatusV1),
- Argument(ArgumentType.Object, interface=WlOutput),
- )
- def get_river_output_status(self, output: WlOutput) -> Proxy[ZriverOutputStatusV1]:
- """Create an output status object
-
- This creates a new river_output_status object for the given
- :class:`~pywayland.protocol.wayland.WlOutput`.
-
- :param output:
- :type output:
- :class:`~pywayland.protocol.wayland.WlOutput`
- :returns:
- :class:`~pywayland.protocol.river_status_unstable_v1.ZriverOutputStatusV1`
- """
- id = self._marshal_constructor(1, ZriverOutputStatusV1, output)
- return id
-
- @ZriverStatusManagerV1.request(
- Argument(ArgumentType.NewId, interface=ZriverSeatStatusV1),
- Argument(ArgumentType.Object, interface=WlSeat),
- )
- def get_river_seat_status(self, seat: WlSeat) -> Proxy[ZriverSeatStatusV1]:
- """Create a seat status object
-
- This creates a new river_seat_status object for the given
- :class:`~pywayland.protocol.wayland.WlSeat`.
-
- :param seat:
- :type seat:
- :class:`~pywayland.protocol.wayland.WlSeat`
- :returns:
- :class:`~pywayland.protocol.river_status_unstable_v1.ZriverSeatStatusV1`
- """
- id = self._marshal_constructor(2, ZriverSeatStatusV1, seat)
- return id
-
-
-class ZriverStatusManagerV1Resource(Resource):
- interface = ZriverStatusManagerV1
-
-
-class ZriverStatusManagerV1Global(Global):
- interface = ZriverStatusManagerV1
-
-
-ZriverStatusManagerV1._gen_c()
-ZriverStatusManagerV1.proxy_class = ZriverStatusManagerV1Proxy
-ZriverStatusManagerV1.resource_class = ZriverStatusManagerV1Resource
-ZriverStatusManagerV1.global_class = ZriverStatusManagerV1Global
diff --git a/bar/river/protocol/river-control-unstable-v1.xml b/bar/river/protocol/river-control-unstable-v1.xml
deleted file mode 100644
index aa5fc4d..0000000
--- a/bar/river/protocol/river-control-unstable-v1.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-
-
-
- Copyright 2020 The River Developers
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-
-
-
- This interface allows clients to run compositor commands and receive a
- success/failure response with output or a failure message respectively.
-
- Each command is built up in a series of add_argument requests and
- executed with a run_command request. The first argument is the command
- to be run.
-
- A complete list of commands should be made available in the man page of
- the compositor.
-
-
-
-
- This request indicates that the client will not use the
- river_control object any more. Objects that have been created
- through this instance are not affected.
-
-
-
-
-
- Arguments are stored by the server in the order they were sent until
- the run_command request is made.
-
-
-
-
-
-
- Execute the command built up using the add_argument request for the
- given seat.
-
-
-
-
-
-
-
-
- This object is created by the run_command request. Exactly one of the
- success or failure events will be sent. This object will be destroyed
- by the compositor after one of the events is sent.
-
-
-
-
- Sent when the command has been successfully received and executed by
- the compositor. Some commands may produce output, in which case the
- output argument will be a non-empty string.
-
-
-
-
-
-
- Sent when the command could not be carried out. This could be due to
- sending a non-existent command, no command, not enough arguments, too
- many arguments, invalid arguments, etc.
-
-
-
-
-
diff --git a/bar/river/protocol/river-status-unstable-v1.xml b/bar/river/protocol/river-status-unstable-v1.xml
deleted file mode 100644
index e9629dd..0000000
--- a/bar/river/protocol/river-status-unstable-v1.xml
+++ /dev/null
@@ -1,148 +0,0 @@
-
-
-
- Copyright 2020 The River Developers
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-
-
-
- A global factory for objects that receive status information specific
- to river. It could be used to implement, for example, a status bar.
-
-
-
-
- This request indicates that the client will not use the
- river_status_manager object any more. Objects that have been created
- through this instance are not affected.
-
-
-
-
-
- This creates a new river_output_status object for the given wl_output.
-
-
-
-
-
-
-
- This creates a new river_seat_status object for the given wl_seat.
-
-
-
-
-
-
-
-
- This interface allows clients to receive information about the current
- windowing state of an output.
-
-
-
-
- This request indicates that the client will not use the
- river_output_status object any more.
-
-
-
-
-
- Sent once binding the interface and again whenever the tag focus of
- the output changes.
-
-
-
-
-
-
- Sent once on binding the interface and again whenever the tag state
- of the output changes.
-
-
-
-
-
-
- Sent once on binding the interface and again whenever the set of
- tags with at least one urgent view changes.
-
-
-
-
-
-
- Sent once on binding the interface should a layout name exist and again
- whenever the name changes.
-
-
-
-
-
-
- Sent when the current layout name has been removed without a new one
- being set, for example when the active layout generator disconnects.
-
-
-
-
-
-
- This interface allows clients to receive information about the current
- focus of a seat. Note that (un)focused_output events will only be sent
- if the client has bound the relevant wl_output globals.
-
-
-
-
- This request indicates that the client will not use the
- river_seat_status object any more.
-
-
-
-
-
- Sent on binding the interface and again whenever an output gains focus.
-
-
-
-
-
-
- Sent whenever an output loses focus.
-
-
-
-
-
-
- Sent once on binding the interface and again whenever the focused
- view or a property thereof changes. The title may be an empty string
- if no view is focused or the focused view did not set a title.
-
-
-
-
-
-
- Sent once on binding the interface and again whenever a new mode
- is entered (e.g. with riverctl enter-mode foobar).
-
-
-
-
-
diff --git a/bar/river/service.py b/bar/river/service.py
deleted file mode 100644
index e73b005..0000000
--- a/bar/river/service.py
+++ /dev/null
@@ -1,356 +0,0 @@
-import os
-import time
-from dataclasses import dataclass, field
-from typing import Any, Dict, List, Optional, Set
-
-from fabric.core.service import Property, Service, Signal
-from fabric.utils.helpers import idle_add
-from gi.repository import GLib
-from loguru import logger
-
-# Import pywayland components - ensure these imports are correct
-from pywayland.client import Display
-from pywayland.protocol.wayland import WlOutput, WlSeat
-
-from .generated.river_control_unstable_v1 import ZriverControlV1
-from .generated.river_status_unstable_v1 import ZriverStatusManagerV1
-
-
-@dataclass
-class OutputInfo:
- """Information about a River output"""
-
- name: int
- output: WlOutput
- status: Any = None # ZriverOutputStatusV1
- tags_view: List[int] = field(default_factory=list)
- tags_focused: List[int] = field(default_factory=list)
- tags_urgent: List[int] = field(default_factory=list)
-
-
-@dataclass(frozen=True)
-class RiverEvent:
- """Event data from River compositor"""
-
- name: str
- data: List[Any]
- output_id: Optional[int] = None
-
-
-class River(Service):
- """Connection to River Wayland compositor via river-status protocol"""
-
- @Property(bool, "readable", "is-ready", default_value=False)
- def ready(self) -> bool:
- return self._ready
-
- @Property(str, "readable", "active-window", default_value="")
- def active_window(self) -> str:
- """Get the title of the currently active window"""
- return self._active_window_title
-
- @Signal
- def ready_signal(self):
- return self.notify("ready")
-
- @Signal("event", flags="detailed")
- def event(self, event: object): ...
-
- def __init__(self, **kwargs):
- """Initialize the River service"""
- super().__init__(**kwargs)
- self._ready = False
- self._active_window_title = ""
- self.outputs: Dict[int, OutputInfo] = {}
- self.river_status_mgr = None
- self.river_control = None
- self.seat = None
- self.seat_status = None
-
- # Start the connection in a separate thread
- self.river_thread = GLib.Thread.new(
- "river-status-service", self._river_connection_task
- )
-
- def _river_connection_task(self):
- """Main thread that connects to River and listens for events"""
- try:
- logger.info("[RiverService] Starting connection to River")
-
- logger.debug(
- f"[RiverService] XDG_RUNTIME_DIR={os.environ.get('XDG_RUNTIME_DIR', 'Not set')}"
- )
- logger.debug(
- f"[RiverService] WAYLAND_DISPLAY={os.environ.get('WAYLAND_DISPLAY', 'Not set')}"
- )
-
- display = Display()
- display.connect()
- logger.debug("[RiverService] Display connection created")
-
- # Get the registry
- registry = display.get_registry()
- logger.debug("[RiverService] Registry obtained")
-
- # Create state object to hold our data
- state = {
- "display": display,
- "registry": registry,
- "outputs": {},
- "river_status_mgr": None,
- "river_control": None,
- "seat": None,
- "seat_status": None,
- }
-
- def handle_global(registry, name, iface, version):
- logger.debug(
- f"[RiverService] Global: {iface} (v{version}, name={name})"
- )
- if iface == "zriver_status_manager_v1":
- state["river_status_mgr"] = registry.bind(
- name, ZriverStatusManagerV1, version
- )
- logger.info("[RiverService] Found river status manager")
- elif iface == "zriver_control_v1":
- state["river_control"] = registry.bind(
- name, ZriverControlV1, version
- )
- logger.info("[RiverService] Found river control interface")
- elif iface == "wl_output":
- output = registry.bind(name, WlOutput, version)
- state["outputs"][name] = OutputInfo(name=name, output=output)
- logger.info(f"[RiverService] Found output {name}")
- elif iface == "wl_seat":
- state["seat"] = registry.bind(name, WlSeat, version)
- logger.info("[RiverService] Found seat")
-
- def handle_global_remove(registry, name):
- if name in state["outputs"]:
- logger.info(f"[RiverService] Output {name} removed")
- del state["outputs"][name]
- idle_add(
- lambda: self.emit(
- "event::output_removed",
- RiverEvent("output_removed", [name]),
- )
- )
-
- # Set up the dispatchers
- registry.dispatcher["global"] = handle_global
- registry.dispatcher["global_remove"] = handle_global_remove
-
- # Discover globals
- logger.debug("[RiverService] Performing initial roundtrip")
- display.roundtrip()
-
- # Check if we found the river status manager
- if not state["river_status_mgr"]:
- logger.error("[RiverService] River status manager not found")
- return
-
- # Handle the window title updates through seat status
-
- if not state["river_control"]:
- logger.error(
- "[RiverService] River control interface not found - falling back to riverctl"
- )
- # You could still fall back to the old riverctl method here if needed
-
- def focused_view_handler(_, title):
- logger.debug(f"[RiverService] Focused view title: {title}")
- self._active_window_title = title
- idle_add(lambda: self._emit_active_window(title))
-
- # Get the seat status to track active window
-
- if state["seat"]:
- seat_status = state["river_status_mgr"].get_river_seat_status(
- state["seat"]
- )
- seat_status.dispatcher["focused_view"] = focused_view_handler
- state["seat_status"] = seat_status
- logger.info("[RiverService] Set up seat status for window tracking")
-
- # Create view tags and focused tags handlers
- def make_view_tags_handler(output_id):
- def handler(_, tags):
- decoded = self._decode_bitfields(tags)
- state["outputs"][output_id].tags_view = decoded
- logger.debug(
- f"[RiverService] Output {output_id} view tags: {decoded}"
- )
- idle_add(lambda: self._emit_view_tags(output_id, decoded))
-
- return handler
-
- def make_focused_tags_handler(output_id):
- def handler(_, tags):
- decoded = self._decode_bitfields(tags)
- state["outputs"][output_id].tags_focused = decoded
- logger.debug(
- f"[RiverService] Output {output_id} focused tags: {decoded}"
- )
- idle_add(lambda: self._emit_focused_tags(output_id, decoded))
-
- return handler
-
- def make_urgent_tags_handler(output_id):
- def handler(_, tags):
- decoded = self._decode_bitfields(tags)
- state["outputs"][output_id].tags_urgent = decoded
- logger.debug(
- f"[RiverService] Output {output_id} urgent tags: {decoded}"
- )
- idle_add(lambda: self._emit_urgent_tags(output_id, decoded))
-
- return handler
-
- # Bind output status listeners
- for name, info in list(state["outputs"].items()):
- status = state["river_status_mgr"].get_river_output_status(info.output)
- status.dispatcher["view_tags"] = make_view_tags_handler(name)
- status.dispatcher["focused_tags"] = make_focused_tags_handler(name)
- status.dispatcher["urgent_tags"] = make_urgent_tags_handler(name)
- info.status = status
- logger.info(f"[RiverService] Set up status for output {name}")
-
- # Initial data fetch
- logger.debug("[RiverService] Performing second roundtrip")
- display.roundtrip()
-
- # Update our outputs dictionary
- self.outputs.update(state["outputs"])
- self.river_status_mgr = state["river_status_mgr"]
- self.river_control = state["river_control"]
- self.seat = state["seat"]
- self.seat_status = state.get("seat_status")
- self._display = display
-
- # Mark service as ready
- idle_add(self._set_ready)
-
- # Main event loop
- logger.info("[RiverService] Entering main event loop")
- while True:
- display.dispatch(block=True)
- time.sleep(0.01) # Small sleep to prevent CPU spinning
-
- except Exception as e:
- logger.error(f"[RiverService] Error in River connection: {e}")
- import traceback
-
- logger.error(traceback.format_exc())
-
- return True
-
- def _set_ready(self):
- """Set the service as ready (called on main thread via idle_add)"""
- self._ready = True
- logger.info("[RiverService] Service ready")
- self.ready_signal.emit()
- return False # Don't repeat
-
- def _emit_view_tags(self, output_id, tags):
- """Emit view_tags events (called on main thread)"""
- event = RiverEvent("view_tags", tags, output_id)
- self.emit("event::view_tags", event)
- self.emit(f"event::view_tags::{output_id}", tags)
- return False # Don't repeat
-
- def _emit_focused_tags(self, output_id, tags):
- """Emit focused_tags events (called on main thread)"""
- event = RiverEvent("focused_tags", tags, output_id)
- self.emit("event::focused_tags", event)
- self.emit(f"event::focused_tags::{output_id}", tags)
- return False # Don't repeat
-
- def _emit_active_window(self, title):
- """Emit active window title events (called on main thread)"""
- event = RiverEvent("active_window", [title])
- self.emit("event::active_window", event)
- self.notify("active-window")
- return False # Don't repeat
-
- def _emit_urgent_tags(self, output_id, tags):
- """Emit urgent_tags events (called on main thread)"""
- event = RiverEvent("urgent_tags", tags, output_id)
- self.emit("event::urgent_tags", event)
- self.emit(f"event::urgent_tags::{output_id}", tags)
- return False # Don't repeat
-
- @staticmethod
- def _decode_bitfields(bitfields) -> List[int]:
- """Decode River's tag bitfields into a list of tag indices"""
- tags: Set[int] = set()
-
- # Ensure we have an iterable
- if not hasattr(bitfields, "__iter__"):
- bitfields = [bitfields]
-
- for bits in bitfields:
- for i in range(32):
- if bits & (1 << i):
- tags.add(i)
-
- return sorted(tags)
-
- def run_command(self, command, *args, callback=None):
- """Run a riverctl command"""
- if not self.river_control or not self.seat:
- logger.warning(
- "[RiverService] River control or seat not available, falling back to riverctl"
- )
- return self._run_command_fallback(command, *args)
-
- self.river_control.add_argument(command)
- for arg in args:
- self.river_control.add_argument(str(arg))
-
- # Execute the command
- command_callback = self.river_control.run_command(self.seat)
-
- # Set up callback handlers
- result = {"stdout": None, "stderr": None, "success": None}
-
- def handle_success(_, output):
- logger.debug(f"[RiverService] Command success: {output}")
- result["stdout"] = output
- result["success"] = True
- if callback:
- idle_add(lambda: callback(True, output, None))
-
- def handle_failure(_, failure_message):
- logger.debug(f"[RiverService] Command failure: {failure_message}")
- result["stderr"] = failure_message
- result["success"] = False
- if callback:
- idle_add(lambda: callback(False, None, failure_message))
-
- command_callback.dispatcher["success"] = handle_success
- command_callback.dispatcher["failure"] = handle_failure
-
- if hasattr(self, "_display"):
- self._display.flush()
-
- return True
-
- def _run_command_fallback(self, command, *args):
- """Fallback to riverctl"""
- import subprocess
-
- cmd = ["riverctl", command] + [str(arg) for arg in args]
- try:
- result = subprocess.run(cmd, capture_output=True, text=True, check=True)
- logger.info(f"[RiverService] Ran command: {' '.join(cmd)}")
- return result.stdout.strip()
- except subprocess.CalledProcessError as e:
- logger.error(
- f"[RiverService] Command failed: {' '.join(cmd)}, error: {e.stderr}"
- )
- return None
-
- def toggle_focused_tag(self, tag, callback=None):
- """Toggle a tag in the focused tags"""
- tag_mask = 1 << int(tag)
- self.run_command("set-focused-tags", str(tag_mask), callback=callback)
diff --git a/bar/river/widgets.py b/bar/river/widgets.py
deleted file mode 100644
index ca95e8d..0000000
--- a/bar/river/widgets.py
+++ /dev/null
@@ -1,284 +0,0 @@
-from fabric.core.service import Property
-from fabric.utils.helpers import bulk_connect
-from fabric.widgets.box import Box
-from fabric.widgets.button import Button
-from fabric.widgets.eventbox import EventBox
-from fabric.widgets.label import Label
-from gi.repository import Gdk
-from loguru import logger
-
-from .service import River
-
-_connection: River | None = None
-
-
-def get_river_connection() -> River:
- global _connection
- if not _connection:
- _connection = River()
- return _connection
-
-
-class RiverWorkspaceButton(Button):
- @Property(int, "readable")
- def id(self) -> int:
- return self._id
-
- @Property(bool, "read-write", default_value=False)
- def active(self) -> bool:
- return self._active
-
- @active.setter
- def active(self, value: bool):
- self._active = value
- (self.remove_style_class if not value else self.add_style_class)("active")
-
- @Property(bool, "read-write", default_value=False)
- def empty(self) -> bool:
- return self._empty
-
- @empty.setter
- def empty(self, value: bool):
- self._empty = value
- (self.remove_style_class if not value else self.add_style_class)("empty")
-
- @Property(bool, "read-write", default_value=False)
- def urgent(self) -> bool:
- return self._urgent
-
- @urgent.setter
- def urgent(self, value: bool):
- self._urgent = value
- self._update_style()
-
- def __init__(self, id: int, label: str = None, **kwargs):
- super().__init__(label or str(id), **kwargs)
- self._id = id
- self._active = False
- self._empty = True
- self._urgent = False
-
- def _update_style(self):
- """Update button styles based on states"""
- # Remove all state-related styles first
- self.remove_style_class("active")
- self.remove_style_class("empty")
- self.remove_style_class("urgent")
-
- # Then apply current states
- if self._active:
- self.add_style_class("active")
- if self._empty:
- self.add_style_class("empty")
- if self._urgent:
- self.add_style_class("urgent")
-
-
-class RiverWorkspaces(EventBox):
- def __init__(self, output_id, river_service=None, max_tags=9, **kwargs):
- super().__init__(events="scroll")
- self._box = Box(**kwargs)
- self.children = self._box
-
- if river_service:
- self.river = river_service
- else:
- self.river = get_river_connection()
-
- # Store output_id as received
- self.output_id = output_id
-
- self.max_tags = max_tags
- # Create buttons for tags 0 to max_tags-1 (to match River's 0-based tag indexing)
- self._buttons = {i: RiverWorkspaceButton(i) for i in range(max_tags)}
-
- for btn in self._buttons.values():
- btn.connect("clicked", self.on_workspace_click)
- self._box.add(btn)
-
- # Connect to service events
- self.river.connect("event::focused_tags", self.on_focus_change_general)
- self.river.connect("event::view_tags", self.on_view_change_general)
- self.river.connect("event::urgent_tags", self.on_urgent_change_general)
- self.river.connect("event::output_removed", self.on_output_removed)
-
- # Initial setup when service is ready
- if self.river.ready:
- self.on_ready(None)
- else:
- self.river.connect("event::ready", self.on_ready)
-
- self.connect("scroll-event", self.on_scroll)
-
- def on_ready(self, _):
- """Initialize widget state when service is ready"""
- logger.debug(
- f"[RiverWorkspaces] Service ready, outputs: {list(self.river.outputs.keys())}"
- )
-
- # If no output_id was specified, take the first one
- if self.output_id is None and self.river.outputs:
- self.output_id = next(iter(self.river.outputs.keys()))
- logger.info(f"[RiverWorkspaces] Selected output {self.output_id}")
-
- # Initialize state from selected output
- if self.output_id is not None and self.output_id in self.river.outputs:
- output_info = self.river.outputs[self.output_id]
-
- # Initialize buttons with current state
- # Access fields directly on the OutputInfo dataclass
- focused_tags = output_info.tags_focused
- view_tags = output_info.tags_view
- urgent_tags = output_info.tags_urgent
-
- logger.debug(
- f"[RiverWorkspaces] Initial state - focused: {focused_tags}, view: {view_tags}, urgent: {urgent_tags}"
- )
-
- for i, btn in self._buttons.items():
- btn.active = i in focused_tags
- btn.empty = i not in view_tags
- btn.urgent = i in urgent_tags
-
- def on_focus_change(self, _, tags):
- """Handle focused tags change for our specific output"""
- logger.debug(
- f"[RiverWorkspaces] Focus change on output {self.output_id}: {tags}"
- )
- for i, btn in self._buttons.items():
- btn.active = i in tags
-
- def on_view_change(self, _, tags):
- """Handle view tags change for our specific output"""
- logger.debug(
- f"[RiverWorkspaces] View change on output {self.output_id}: {tags}"
- )
- for i, btn in self._buttons.items():
- btn.empty = i not in tags
-
- def on_focus_change_general(self, _, event):
- """Handle general focused tags event"""
- # Only handle event if it's for our output
- if event.output_id == self.output_id:
- logger.debug(
- f"[RiverWorkspaces] General focus change for output {self.output_id}"
- )
- self.on_focus_change(_, event.data)
-
- def on_view_change_general(self, _, event):
- """Handle general view tags event"""
- # Only handle event if it's for our output
- if event.output_id == self.output_id:
- logger.debug(
- f"[RiverWorkspaces] General view change for output {self.output_id}"
- )
- self.on_view_change(_, event.data)
-
- def on_urgent_change(self, _, tags):
- """Handle urgent tags change for our specific output"""
- logger.debug(
- f"[RiverWorkspaces] Urgent change on output {self.output_id}: {tags}"
- )
- for i, btn in self._buttons.items():
- btn.urgent = i in tags
-
- def on_urgent_change_general(self, _, event):
- """Handle general urgent tags event"""
- # Only handle event if it's for our output
- if event.output_id == self.output_id:
- logger.debug(
- f"[RiverWorkspaces] General urgent change for output {self.output_id}"
- )
- self.on_urgent_change(_, event.data)
-
- def on_output_removed(self, _, event):
- """Handle output removal"""
- removed_id = event.data[0]
-
- if removed_id == self.output_id:
- logger.info(f"[RiverWorkspaces] Our output {self.output_id} was removed")
-
- # Try to find another output
- if self.river.outputs:
- self.output_id = next(iter(self.river.outputs.keys()))
- logger.info(f"[RiverWorkspaces] Switching to output {self.output_id}")
-
- # Update state for new output
- if self.output_id in self.river.outputs:
- output_info = self.river.outputs[self.output_id]
- # Access fields directly on the OutputInfo dataclass
- focused_tags = output_info.tags_focused
- view_tags = output_info.tags_view
-
- for i, btn in self._buttons.items():
- btn.active = i in focused_tags
- btn.empty = i not in view_tags
-
- def on_workspace_click(self, btn):
- """Handle workspace button click"""
- logger.info(f"[RiverWorkspaces] Clicked on workspace {btn.id}")
- self.river.toggle_focused_tag(btn.id)
-
- def on_scroll(self, _, event):
- """Handle scroll events"""
- direction = event.direction
- if direction == Gdk.ScrollDirection.DOWN:
- logger.info("[RiverWorkspaces] Scroll down - focusing next view")
- self.river.run_command("focus-view", "next")
- elif direction == Gdk.ScrollDirection.UP:
- logger.info("[RiverWorkspaces] Scroll up - focusing previous view")
- self.river.run_command("focus-view", "previous")
-
-
-class RiverActiveWindow(Label):
- """Widget to display the currently active window's title"""
-
- def __init__(self, max_length=None, ellipsize="end", river_service=None, **kwargs):
- super().__init__(**kwargs)
-
- if river_service:
- self.river = river_service
- else:
- self.river = get_river_connection()
-
- self.max_length = max_length
- self.ellipsize = ellipsize
-
- # Set initial state
- if self.river.ready:
- self.on_ready(None)
- else:
- self.river.connect("event::ready", self.on_ready)
-
- # Connect to active window changes
- self.river.connect("event::active_window", self.on_active_window_changed)
-
- def on_ready(self, _):
- """Initialize widget when service is ready"""
- logger.debug("[RiverActiveWindow] Service ready")
- self.update_title(self.river.active_window)
-
- def on_active_window_changed(self, _, event):
- """Update widget when active window changes"""
- title = event.data[0] if event.data else ""
- logger.debug(f"[RiverActiveWindow] Window changed to: {title}")
- self.update_title(title)
-
- def update_title(self, title):
- """Update the label with the window title"""
- if not title:
- self.label = ""
- self.set_label(self.label)
- return
-
- if self.max_length and len(title) > self.max_length:
- if self.ellipsize == "end":
- title = title[: self.max_length] + "..."
- elif self.ellipsize == "middle":
- half = (self.max_length - 3) // 2
- title = title[:half] + "..." + title[-half:]
- elif self.ellipsize == "start":
- title = "..." + title[-self.max_length :]
-
- self.label = title
- self.set_label(self.label)
diff --git a/flake.lock b/flake.lock
index ec2e6bd..73e5784 100644
--- a/flake.lock
+++ b/flake.lock
@@ -6,15 +6,15 @@
"utils": "utils"
},
"locked": {
- "lastModified": 1745289078,
- "narHash": "sha256-1dZTqsWPaHyWjZkX4MaJdwUAQoMXwr8hhHymxQIwFrY=",
- "owner": "Fabric-Development",
+ "lastModified": 1747045720,
+ "narHash": "sha256-2Z0F4hnluJZunwRfx80EQXpjGLhunV2wrseT42nzh7M=",
+ "owner": "Makesesama",
"repo": "fabric",
- "rev": "1831ced4d9bb9f4be3893be55a8d502b47bff29e",
+ "rev": "dae50c763e8bf2b4e5807b49b9e62425e0725cfa",
"type": "github"
},
"original": {
- "owner": "Fabric-Development",
+ "owner": "Makesesama",
"repo": "fabric",
"type": "github"
}
@@ -41,11 +41,11 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1746810718,
- "narHash": "sha256-VljtYzyttmvkWUKTVJVW93qAsJsrBbgAzy7DdnJaQfI=",
+ "lastModified": 1733261153,
+ "narHash": "sha256-eq51hyiaIwtWo19fPEeE0Zr2s83DYMKJoukNLgGGpek=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "0c0bf9c057382d5f6f63d54fd61f1abd5e1c2f63",
+ "rev": "b681065d0919f7eb5309a93cea2cfa84dec9aa88",
"type": "github"
},
"original": {
@@ -131,11 +131,11 @@
"systems": "systems"
},
"locked": {
- "lastModified": 1710146030,
- "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
+ "lastModified": 1731533236,
+ "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
- "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
+ "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
diff --git a/flake.nix b/flake.nix
index a27e6bc..8369b0b 100644
--- a/flake.nix
+++ b/flake.nix
@@ -5,7 +5,7 @@
nixpkgs.url = "github:NixOS/nixpkgs/24.11";
unstable.url = "github:NixOS/nixpkgs/nixos-unstable";
utils.url = "github:numtide/flake-utils";
- fabric.url = "github:Fabric-Development/fabric";
+ fabric.url = "github:Makesesama/fabric";
home-manager.url = "github:nix-community/home-manager";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
};