Conversation
This commit removes the old input grab interface. In its place, plugins can use the input-grab helper in plugins/common, or reimplement that logic if they need to customize it in any way. Fixes #1320.
Each plugin now gets one instance by default. Plugins that want to have per-output tracking can do so by using the per-output-plugin helpers. The API remains almost the same as in previous versions.
1929716 to
fe3a36f
Compare
With this change, oswitch no longer needs per-output instances.
This interface is no longer used for input grabs, which means its name is no longer accurate.
Should fix the CI.
|
In this PR I have refactored the existing IPC used for tests in a more general-purpose IPC framework. A demo plugin utilizing it is the demo-ipc.cpp. Unfortunately, there is nothing too exciting for users as of yet. Anyway, how it works:
Currently, there is a demo ipc plugin which is a proof-of-concept of how this works together. It provides just 4 IPC calls - watch (register the IPC client so that it can get view-mapped events over IPC), get view info, get output info, set view geometry. The IPC client in itself, together with the message parsing logic (in python, but could be any other language) can be found below. What it does is center each view when it becomes mapped, essentially place's center mode (but it also sets the view size to half the output size, even though that can obviously be changed by everybody). import socket
import json as js
def get_msg_template():
# Create generic message template
message = {}
message["data"] = {}
return message
class WayfireSocket:
def __init__(self, socket_name: str):
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()
message["method"] = "demo-ipc/watch"
return self.send_json(message)
def get_view_info(self, id):
message = get_msg_template()
message["method"] = "demo-ipc/view-info"
message["data"]["id"] = id
return self.send_json(message)
def get_output_info(self, id):
message = get_msg_template()
message["method"] = "demo-ipc/output-info"
message["data"]["id"] = id
return self.send_json(message)
def set_view_geometry(self, id, x, y, w, h):
message = get_msg_template()
message["method"] = "demo-ipc/view-set-geometry"
message["data"]["id"] = id
message["data"]["geometry"] = {}
message["data"]["geometry"]["x"] = x
message["data"]["geometry"]["y"] = y
message["data"]["geometry"]["width"] = w
message["data"]["geometry"]["height"] = h
return self.send_json(message)
inbound_socket = WayfireSocket('/tmp/wayfire.socket')
outbound_socket = WayfireSocket('/tmp/wayfire.socket')
inbound_socket.watch()
while True:
msg = inbound_socket.read_message()
output = msg["view"]["output"]
output_info = outbound_socket.get_output_info(output)
print(output_info)
geometry = {}
w = output_info["info"]["geometry"]["width"]
h = output_info["info"]["geometry"]["height"]
print(outbound_socket.set_view_geometry(msg["view"]["id"], w // 4, h // 4, w // 2, h // 2))The long-term plans are to add many more commands in a dedicated IPC plugin, the current one is just a demo to ensure that what I imagine is feasible. PS. The ipc plugin by default sets the Wayfire socket to PS 2: The demo client currently uses 2 sockets, one for listening to events, one for sending commands to Wayfire. This is done to avoid mixing replies and events from Wayfire. |
|
Porting guide for plugins:
|
Currently, plugins necessarily have one instance per output. While this makes sense for many plugins, it is an artificial restriction which is sometimes bypassed with the singleton plugin class. Nonetheless, it would make far more sense to have a single instance of each plugin, and then have the plugins create per-output objects if they need to do so. This makes a lot of sense especially with plugins like IPC, idle or oswitch. Not to mention that things like bindings are currently artifically constrained to a single output, but they should actually be global state, just like every other input state.
This PR aims to do the following:
Fixes #1320