Skip to content

feat(niri): add niri service #118

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

packetverse
Copy link

This pull request introduces a set of new widgets for use with the Niri window manager.

⚙️ Service
A completely new service has been created to handle interactions between Niri and its widgets, enabling IPC communication and real-time updates.

✨ Features

  • Language widget
    Displays the current keyboard layout using data from KeyboardLayoutsChanged and KeyboardLayoutSwitched events.

  • ActiveWindow widget
    Shows the title and app ID of the currently focused window, updating in real-time.

  • Workspaces widget
    Interactive workspace buttons reflecting the state of Niri's workspaces.
    Supports:

    • Active workspace highlighting
    • Urgency indication (not finished)
    • Scrollable workspace switching (not finished)

📌 Note
The code is not the cleanest and is mainly based on the Hyprland service, modified to work with Niri. It may need some refactoring and structural improvements, but it works well with no issues so far during testing.

@packetverse
Copy link
Author

Fixed scroll handler so you can scroll to switch workspaces.

@its-darsh its-darsh self-assigned this Jun 23, 2025
@its-darsh its-darsh added enhancement New feature or request good first issue Good for newcomers help wanted Extra attention is needed labels Jun 23, 2025
@its-darsh
Copy link
Contributor

Testing is needed...

@Dan7h3x
Copy link

Dan7h3x commented Jul 6, 2025

@packetverse Great work. Try using idx instead of id in sync_workspace and click for having currect workspace tags in bar.

@its-darsh
Copy link
Contributor

After reading this myself I've found that some rough edges need to be smoothed out. Also, it doesn't really match our way of writing code, even though this is a modified version of the Hyprland (and friends) service.

I'll try to point you to the mentioned manner through comments. If found no response from you I'll need to close this and maybe reimplement it the right way.

super().__init__(**kwargs)
self._ready = False

self.socket_path = os.getenv("NIRI_SOCKET")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You define the socket_path here.

response = {}
try:
client = Gio.SocketClient()
address = Gio.UnixSocketAddress.new(os.getenv("NIRI_SOCKET"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While you're not using the socket_path already defined above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get it that this is a @staticmethod but why not use the same way we cache the socket path in Hyprland?

**kwargs: P.kwargs,
) -> None:
client = Gio.SocketClient()
address = Gio.UnixSocketAddress.new(os.getenv("NIRI_SOCKET"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above...

event_name = next(iter(event_data))
event_obj = NiriEvent(name=event_name, data=event_data[event_name], raw=raw_str)

# logger.debug(f"Emitting event: {event_name} with data: {event_data}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a lot of commented code in this file...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once the service is ready this file is going to be nuked for a much smaller one in footprint making use of the new abstracted window manager specific premade widgets.

@its-darsh its-darsh added the On Hold On hold, usually in wait for a PR to be merged. or something... label Jul 9, 2025
@packetverse
Copy link
Author

The service is very poorly coded and I was definitely rushing, I'll see what I can do, give me a couple of weeks or so.

@packetverse
Copy link
Author

I have to add that the widgets are also very poorly coded, I'll start off by refactoring the service and let you review that before getting started on the widgets as well.

@its-darsh
Copy link
Contributor

I have to add that the widgets are also very poorly coded, I'll start off by refactoring the service and let you review that before getting started on the widgets as well.

It's fine. Would be better to get rid of the widgets and work only on a service. I'll take care of the widgets.

@packetverse
Copy link
Author

Did some refactoring, but needs testing.

@packetverse packetverse requested a review from its-darsh July 20, 2025 17:32
Comment on lines +54 to +55
# if not self.socket_path or not os.path.exists(self.socket_path):
# raise NiriSocketNotFoundError("NIRI_SOCKET not found or invalid.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left overs...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does that thing even functions? I doubt really...

def __init__(self, commands_only: bool = False, **kwargs):
super().__init__(**kwargs)
self._ready = False
self.lookup_socket()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method returns a cached socket path, however is it not being used...

Comment on lines +65 to +68
@staticmethod
def lookup_socket() -> str:
if not os.path.exists(os.getenv("NIRI_SOCKET")):
raise NiriSocketNotFoundError("NIRI_SOCKET not found or invalid.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you check if the niri socket path was present in environment variables. However, you never return anything back as described in the method signature.

Comment on lines +83 to +84
# ostream = conn.get_output_stream()
# istream = Gio.DataInputStream.new(conn.get_input_stream())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left overs...

A Fabric-compatible service to interact with the Niri window manager via its IPC socket.
"""

SOCKET_PATH = ""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to have a look at how we handle loading and caching the socket path. See Hyprland.

@its-darsh
Copy link
Contributor

Generally, This needs testing by the author.

@packetverse
Copy link
Author

Yeah, I'll set up a machine with Niri so I can improve the code and test it out as soon as possible.

@its-darsh its-darsh changed the title feat(niri): Add Niri service and widgets for keyboard layout, active window, and workspaces feat(niri): add niri service Jul 28, 2025
@its-darsh
Copy link
Contributor

Stale?

@nurly3
Copy link

nurly3 commented Aug 15, 2025

I need to make my own pr for niri service I believe

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request good first issue Good for newcomers help wanted Extra attention is needed On Hold On hold, usually in wait for a PR to be merged. or something...
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants