Skip to content

Commit

Permalink
Add obs plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
soreau committed Nov 9, 2023
1 parent 0bf18d4 commit 13887a1
Show file tree
Hide file tree
Showing 9 changed files with 634 additions and 3 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
container: alpine:edge
steps:
- run: apk --no-cache add git gcc g++ binutils pkgconf meson ninja musl-dev wayland-dev wayland-protocols libinput-dev libevdev-dev libxkbcommon-dev pixman-dev glm-dev libdrm-dev mesa-dev cairo-dev pango-dev eudev-dev libxml2-dev glibmm-dev libseat-dev hwdata
- run: apk --no-cache add git gcc g++ binutils pkgconf meson ninja musl-dev wayland-dev wayland-protocols libinput-dev libevdev-dev libxkbcommon-dev pixman-dev glm-dev libdrm-dev mesa-dev cairo-dev pango-dev eudev-dev libxml2-dev glibmm-dev libseat-dev hwdata nlohmann-json
- name: Wayfire
uses: actions/checkout@v2
with:
Expand All @@ -24,7 +24,7 @@ jobs:
runs-on: ubuntu-latest
container: alpine:edge
steps:
- run: apk --no-cache add git gcc g++ binutils pkgconf meson ninja musl-dev wayland-dev wayland-protocols libinput-dev libevdev-dev libxkbcommon-dev pixman-dev glm-dev libdrm-dev mesa-dev cairo-dev pango-dev eudev-dev libxml2-dev glibmm-dev libseat-dev libxcb-dev xcb-util-wm-dev xwayland hwdata
- run: apk --no-cache add git gcc g++ binutils pkgconf meson ninja musl-dev wayland-dev wayland-protocols libinput-dev libevdev-dev libxkbcommon-dev pixman-dev glm-dev libdrm-dev mesa-dev cairo-dev pango-dev eudev-dev libxml2-dev glibmm-dev libseat-dev libxcb-dev xcb-util-wm-dev xwayland hwdata nlohmann-json
- name: Wayfire
uses: actions/checkout@v2
with:
Expand Down
30 changes: 30 additions & 0 deletions ipc-scripts/set-obs-effect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/python3
#
# This is a simple script which demonstrates how to use the Wayfire OBS plugin using the IPC socket with the wayfire_socket.py helper.
# To use this, make sure that the ipc plugin is first in the plugin list, so that the WAYFIRE_SOCKET environment
# variable propagates to all processes, including autostarted processes. Also make sure to enable stipc and obs plugins.
#
# This script can be run from a terminal to change the opacity, brightness and saturation of views.
# Usage: ./script.py <app-id> <effect> <value> <duration>
# where <effect> is one of opacity, brightness or saturation, <value> is in the range 0-1 and <duration> is the animation duration in milliseconds

import os
import sys
from wayfire_socket import *

addr = os.getenv('WAYFIRE_SOCKET')

# Important: we connect to Wayfire's IPC two times. The one socket is used for reading events (view-mapped, view-focused, etc).
# The other is used for sending commands and querying Wayfire.
# We could use the same socket, but this would complicate reading responses, as events and query responses would be mixed with just one socket.
commands_sock = WayfireSocket(addr)

for v in commands_sock.list_views():
if v["app-id"] == sys.argv[1]:
if sys.argv[2] == "opacity":
commands_sock.set_view_opacity(v["id"], float(sys.argv[3]), int(sys.argv[4]))
elif sys.argv[2] == "brightness":
commands_sock.set_view_brightness(v["id"], float(sys.argv[3]), int(sys.argv[4]))
elif sys.argv[2] == "saturation":
commands_sock.set_view_saturation(v["id"], float(sys.argv[3]), int(sys.argv[4]))

40 changes: 40 additions & 0 deletions ipc-scripts/trailfocus.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/python3

import os
import sys
from wayfire_socket import *

addr = os.getenv('WAYFIRE_SOCKET')

commands_sock = WayfireSocket(addr)
commands_sock.watch()

while True:
try:
msg = commands_sock.read_message()
except KeyboardInterrupt:
for v in commands_sock.list_views():
commands_sock.set_view_opacity(v["id"], 1.0, 500)
commands_sock.set_view_brightness(v["id"], 1.0, 500)
commands_sock.set_view_saturation(v["id"], 1.0, 500)
exit(0)

if "event" in msg and msg["event"] == "view-focused":
i = 0
for v in commands_sock.list_views():
if v["app-id"] == "$unfocus panel" or v["app-id"] == "gtk-layer-shell":
continue
if v["state"] != {} and v["state"]["minimized"]:
continue
i += 1
step = 0.7 / i
value = 0.3
for v in commands_sock.list_views()[::-1]:
if v["app-id"] == "$unfocus panel" or v["app-id"] == "gtk-layer-shell":
continue
if v["state"] != {} and v["state"]["minimized"]:
continue
value += step
commands_sock.set_view_opacity(v["id"], value, 1000)
commands_sock.set_view_brightness(v["id"], value, 1000)
commands_sock.set_view_saturation(v["id"], value, 1000)
69 changes: 69 additions & 0 deletions ipc-scripts/wayfire_socket.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import socket
import json as js

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

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 set_view_opacity(self, view_id: int, opacity: float, duration: int):
message = get_msg_template("wf/obs/set-view-opacity")
message["data"] = {}
message["data"]["view-id"] = view_id
message["data"]["opacity"] = opacity
message["data"]["duration"] = duration
return self.send_json(message)

def set_view_brightness(self, view_id: int, brightness: float, duration: int):
message = get_msg_template("wf/obs/set-view-brightness")
message["data"] = {}
message["data"]["view-id"] = view_id
message["data"]["brightness"] = brightness
message["data"]["duration"] = duration
return self.send_json(message)

def set_view_saturation(self, view_id: int, saturation: float, duration: int):
message = get_msg_template("wf/obs/set-view-saturation")
message["data"] = {}
message["data"]["view-id"] = view_id
message["data"]["saturation"] = saturation
message["data"]["duration"] = duration
return self.send_json(message)

def list_views(self):
message = get_msg_template("stipc/list_views")
return self.send_json(message)
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ giomm = dependency('giomm-2.4', required: false)
wayland_protos = dependency('wayland-protocols', version: '>=1.12')
wayland_server = dependency('wayland-server')
evdev = dependency('libevdev')
json = dependency('nlohmann_json', required: false)

if get_option('enable_windecor') == true
windecor = subproject('windecor')
Expand Down
2 changes: 1 addition & 1 deletion metadata/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ install_data('autorotate-iio.xml', install_dir: wayfire.get_variable(pkgconfig:
install_data('background-view.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
install_data('bench.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
install_data('crosshair.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
install_data('focus-steal-prevent.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
install_data('follow-focus.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
install_data('force-fullscreen.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
install_data('hide-cursor.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
install_data('join-views.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
install_data('keycolor.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
install_data('mag.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
install_data('obs.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
install_data('showrepaint.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
install_data('view-shot.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
install_data('water.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
Expand Down
8 changes: 8 additions & 0 deletions metadata/obs.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0"?>
<wayfire>
<plugin name="obs">
<_short>OBS</_short>
<_long>Change the opacity, brightness and saturation of windows using ipc scripts</_long>
<category>Effects</category>
</plugin>
</wayfire>
6 changes: 6 additions & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ magnifier = shared_module('mag', 'mag.cpp',
dependencies: [wayfire],
install: true, install_dir: join_paths(get_option('libdir'), 'wayfire'))

if json.found()
obs = shared_module('obs', 'obs.cpp',
dependencies: [wayfire, json],
install: true, install_dir: join_paths(get_option('libdir'), 'wayfire'))
endif

showrepaint = shared_module('showrepaint', 'showrepaint.cpp',
dependencies: [wayfire],
install: true, install_dir: join_paths(get_option('libdir'), 'wayfire'))
Expand Down
Loading

0 comments on commit 13887a1

Please sign in to comment.