Skip to content
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

[RFC] Move window rules to IPC scripts #1821

Merged
merged 8 commits into from
Jul 7, 2023
Merged

Conversation

ammen99
Copy link
Member

@ammen99 ammen99 commented Jul 4, 2023

Window-rules are currently limited to whatever we implement in core, and use a weird custom syntax.

It is possible to move window-rules to an IPC script, as this PR demonstrates. The question is, do people prefer the old or the new approach? Let me know what you think.
Here are some of my arguments why the one or the other:

Pros of the old approach:

  • The custom syntax window-rules lets us have the configuration in one file, wayfire.ini.
  • The custom syntax rules are applied immediately, with IPC there is a slight delay until the changes are applied (a frame or two at most).
  • You don't need to know Python or a similar language (but you have to learn quirky custom syntax ...)

Pros of the IPC approach:

  • Different plugins can add different IPC commands, so we do not need window-rules to support everything
  • Using a language of the user's choice (IPC can be used from every language) allows much more complex and flexible configuration
  • No quirky syntax
  • IPC in general will have a few more areas of application aside from simple window-rules, e.g. one can implement something like swaymsg but for Wayfire.

All in all, I think IPC is a better choice for the future, what do others think? Is there a need for the old window-rules?

Here is a demo in Python how to use the IPC:

#!/usr/bin/python3

import os
from wayfire_socket import *

addr = os.getenv('WAYFIRE_SOCKET')
sock = WayfireSocket(addr)

print(sock.watch())

while True:
    msg = sock.read_message()
    print(msg)

    if "event" in msg and msg["event"] == "view-mapped":
        view = msg["view"]
        if view["app-id"] == "gedit":
            output_data = sock.query_output(view["output"])
            workarea = output_data["workarea"]

            x = 200
            y = 200
            w = workarea['width'] // 2
            h = workarea['height'] // 2

            print(sock.configure_view(view["id"], x, y, w, h))
            # print(sock.assign_slot(view["id"], "slot_br"))
            print(sock.set_always_on_top(view["id"], True))
            print(sock.set_view_alpha(view["id"], 0.5))

and here is wayfire_socket.py (which the user does not have to write themselves, we can figure out some way to distribute this with pip or similar):

import socket
import json as js

def get_msg_template(method: str):
    # Create generic message template
    message = {}
    message["method"] = method
    message["data"] = {}
    return message

def geometry_to_json(x: int, y: int, w: int, h: int):
    geometry = {}
    geometry["x"] = x
    geometry["y"] = y
    geometry["width"] = w
    geometry["height"] = h
    return geometry

class WayfireSocket:
    def __init__(self, socket_name):
        self.client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        self.client.connect(socket_name)

    def read_exact(self, n):
        response = bytes()
        while n > 0:
            read_this_time = self.client.recv(n)
            if not read_this_time:
                raise Exception("Failed to read anything from the socket!")
            n -= len(read_this_time)
            response += read_this_time

        return response

    def read_message(self):
        rlen = int.from_bytes(self.read_exact(4), byteorder="little")
        response_message = self.read_exact(rlen)
        return js.loads(response_message)

    def send_json(self, msg):
        data = js.dumps(msg).encode('utf8')
        header = len(data).to_bytes(4, byteorder="little")
        self.client.send(header)
        self.client.send(data)
        return self.read_message()

    def watch(self):
        message = get_msg_template("window-rules/events/watch")
        return self.send_json(message)

    def query_output(self, output_id: int):
        message = get_msg_template("window-rules/output-info")
        message["data"]["id"] = output_id
        return self.send_json(message)

    def configure_view(self, view_id: int, x: int, y: int, w: int, h: int):
        message = get_msg_template("window-rules/configure-view")
        message["data"]["id"] = view_id
        message["data"]["geometry"] = geometry_to_json(x, y, w, h)
        print(message)
        return self.send_json(message)

    def assign_slot(self, view_id: int, slot: str):
        message = get_msg_template("grid/" + slot)
        message["data"]["view_id"] = view_id
        return self.send_json(message)

    def set_always_on_top(self, view_id: int, always_on_top: bool):
        message = get_msg_template("wm-actions/set-always-on-top")
        message["data"]["view_id"] = view_id
        message["data"]["state"] = always_on_top
        return self.send_json(message)

    def set_view_alpha(self, view_id: int, alpha: float):
        message = get_msg_template("wf/alpha/set-view-alpha")
        message["method"] = "wf/alpha/set-view-alpha"
        message["data"] = {}
        message["data"]["view-id"] = view_id
        message["data"]["alpha"] = alpha
        return self.send_json(message)

@ammen99 ammen99 force-pushed the replace-window-rules-with-ipc branch 2 times, most recently from 17996aa to e912123 Compare July 4, 2023 08:33
@mark-herbert42
Copy link

Python is a slow resource-eating piece of... Will not the wayfire become slowpoke if the rules will be processed by python? I am not an expert so maybe I am wrong - but as I imagine window rules are applied frequently, and ideaaly window rules should look like in compiz - where the matching rules can be applied to every single thing. choose animations, decorations, placement, transparency etc by type, class or app name etc. If a lot of such rules are in place and they are processed in pyhon - will it be better?

@ammen99
Copy link
Member Author

ammen99 commented Jul 4, 2023

Python is a slow resource-eating piece of... Will not the wayfire become slowpoke if the rules will be processed by python? I am not an expert so maybe I am wrong - but as I imagine window rules are applied frequently, and ideaaly window rules should look like in compiz - where the matching rules can be applied to every single thing. choose animations, decorations, placement, transparency etc by type, class or app name etc. If a lot of such rules are in place and they are processed in pyhon - will it be better?

Window rules are applied on certain events, like when a new view is opened. The events are sent over asynchronuous IPC mechanism, so the main process (Wayfire) is not blocked even if the IPC script needs some time to process the events, therefore I do not expect significant overhead.

Plus, python is slow if you are doing something compute-heavy. These rules definitely are not compute heavy, and I don't think you open windows that often for it to matter (it would become a problem if you were opening a hundred new windows per second ... do you do that? xD)

EDIT: forgot to mention, the python code is on the IPC client side. Since IPC is language-agnostic, if you care too much about performance, you can always implement the same IPC in C/C++/Rust/whatever.

@mark-herbert42
Copy link

Open window not so often - but things like tooltip or menu - are they also windows from this sence?

In fact there is a terrible buggy behavior of wayfire with toolips. On panels or things like Gimp tool buttons - tooltip start fashing like mad when mouse hoover. You put mouse over it - and sometimes it works like it should - tooltip just open. But sometmes it do crazy flashing. appear-disppear, appear-disappear....
The idea to use somethng better than python - is tempting.

@ammen99
Copy link
Member Author

ammen99 commented Jul 4, 2023

Open window not so often - but things like tooltip or menu - are they also windows from this sence?

Yes, they are. But even those are not opened too frequently - most computers from the last 15 years are fast enough to handle hundreds of them being opened each second with the IPC script. And I doubt there are actually hundreds of tooltips opened each second ..

Not to mention we can filter tooltips out, because I suspect they won't be useful for window-rules anyway.

The bug with tooltips flickering is a separate issue though, I'd encourage you to open a new issue with exact steps to reproduce. Which apps have the problem, Xwayland or native wayland, etc.

@marcusbritanicus
Copy link
Contributor

marcusbritanicus commented Jul 5, 2023

@ammen99 Who will be responsible for running this python script, that is, will the IPC plugin automatically start this script? Also, what would happen if this script crashed for some reason?

Apart from this main concern, my other objection to moving window rules to IPC is mainly that most normal users would not like to learn a programming language (however easy) to move a window to the top-right corner and resize it to cover the left half of the screen.

(In our physics department, we have around 100 PhD scholars, and at least 30 are in theoretical/computational physics. They are the ones who "know" a programming language. You'll be surprised to know that more than half will not even attempt to learn a new language!! The rest will learn only if their life depended on it. You can imagine how reluctant lay-people will be to learn python to move a window.)

Apart from these two concerns I would prefer that we switched to IPC.

Of course, I have a solution for handling this issue of learning python. We could develop this IPC-window-rules script such that users can simply install different rules in the form of plugins (basically tiny python modules), and enable/disable them in a config file. Also, if we have a python script, we can always support the existing style of window rules. That way, we will not have to choose between either of them.

@ammen99
Copy link
Member Author

ammen99 commented Jul 5, 2023

@marcusbritanicus The script can be started and restarted at any point, I imagine it would be trivial to write a bash command to do that from the autostart plugin for example.

As for learning a new language, I believe that copy-pasting an existing script + adjusting a few ifs should not be too hard. It is also of course possible to develop a framework which supports the old window-rules syntax, if you think that it is simpler than python ;)

@marcusbritanicus
Copy link
Contributor

@ammen99 Thanks for clarifying the first point (regarding start/restart of the script).

As for python, I've always felt copy-pasting usually leads to syntax errors on python (indentation issues - I'm sure you've faced it at one point or another), and we'll have to write a short note on the topic. If we could build "plugins" to do most of the work, then it would be much better than copy-pasting.

For example, you have a master script that simply looks at the config and "loads" (read: import) the "plugins" (read: modules)..
These plugins would contain most of the repetitive code which perform the actual work. The top of the plugin file could contain the necessary data in lists or dicts, which the user could modify, without having to learn a shred of python. This would satisfy most users. We could provide a bunch of most common plugins along with wayfire_socket.py. Move views, open view in workspace, open maximized, set size, set output, yada yada yada...

PS: It would be trivial to support the existing rules syntax esp, if we are using python scripts.

@mark-herbert42
Copy link

Just idea maybe crazy - if we can implemeht current window rules code as IPC module parsing old rules? The code is there - so you stil can use old nice way to make rules using the pre-build module. But if you like to do python - ok, here you are. IPC is nice because it gives more freedom to develop, wit a transparent API. Python in this case is bad and ugly - for programmers it looks like everyone know python as it is a shit language anyone knows. But when you go outside of programmers community - oh python, it is a supernatural language of AI , onle to geeks know it.

If wayfire is designed for IT experts only is OK looks fine, but if we want to get our "market share" - not ant all.
And also - xfce prject is aiming wayfire as a target compositor for wayland, so seems a good idea to join efforts. Sorry for stupid comments of an old man....

@ammen99
Copy link
Member Author

ammen99 commented Jul 6, 2023

Looking at the comments, seems like maybe not everyone in the world knows Python .. I guess I am living in a bubble :)

I will keep the old window-rules plugin as-is, but in a maintenance mode only, no new features. Everything new and fancy will go into IPC, until I or someone else reimplements the old syntax into an IPC plugin (or until everybody switches to IPC, heh).

@ammen99 ammen99 force-pushed the replace-window-rules-with-ipc branch from e912123 to a5bcd87 Compare July 7, 2023 07:51
@ammen99 ammen99 merged commit f933d00 into master Jul 7, 2023
8 checks passed
@ammen99 ammen99 deleted the replace-window-rules-with-ipc branch July 7, 2023 09:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants