Skip to content

Commit

Permalink
Rudimentary example of session saving
Browse files Browse the repository at this point in the history
This script attempts to relaunch previously running gtk applications
by recording the app-id and launching them with gtk-launch. It uses
python pickle to serialize the data to ~/.config/wayfire.pickle and
also attempts to save/restore basic geometry for each window.
  • Loading branch information
soreau committed Feb 22, 2025
1 parent 1f7889c commit aad46c4
Showing 1 changed file with 123 additions and 0 deletions.
123 changes: 123 additions & 0 deletions scripts/session-save.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/usr/bin/python3

#
# Copyright (c) 2025 - Scott Moreau <[email protected]>
#
# Restart previously running gtk clients after wayfire restarts
#
# This script relies on gtk-launch to 'launch' .desktop files
# and gets this information from the application's identifier,
# which means it asserts that the app-id must be the same as
# its .desktop file name. If this is not the case, the app will
# not launch without mapping the app-id string to the .desktop
# file that launches it manually.
#
# Example usage:
#
# Autostart with autostart plugin.
# ~/.config/wayfire.ini:
# [autostart]
# a1 = sh -c 'sleep 1; python3 scripts/session-save.py'
#
# Kill the script before shutting down wayfire.
# ~/.config/wf-shell.ini:
# [panel]
# logout_command = sh -c 'pkill -f "session-save.py"; sleep 1; wayland-logout'
#

import os
import pickle
import subprocess
from wayfire import WayfireSocket

save_file = os.getenv("HOME") + "/.config/wayfire.pickle"

sock = WayfireSocket()
sock.watch()

class geometry:
def __init__(self, x, y, w, h):
self.x = x
self.y = y
self.w = w
self.h = h

def set_geometry(self, x, y, w, h):
self.x = x
self.y = y
self.w = w
self.h = h

class window(object):
def __init__(self, app_id, geometry):
self.app_id = app_id
self.geometry = geometry

def set_geometry(self, geometry):
self.geometry = geometry

window_list = []

try:
try:
with open(save_file, 'x') as file:
pass
except:
pass
with open(save_file, "rb") as file:
window_list = pickle.load(file)

for w in window_list:
subprocess.run(["gtk-launch", w.app_id])
except:
print("Failed to pickle")
pass

def serialize_to_file():
with open(save_file, "wb") as file:
pickle.dump(window_list, file)

while True:
try:
msg = sock.read_next_event()
if "event" in msg:
if "view" in msg:
if msg["view"] is None:
continue
elif msg["view"]["app-id"] == "":
continue
elif msg["event"] == "view-unmapped":
for w in window_list:
if msg["view"]["app-id"] == w.app_id:
window_list.remove(w)
break
serialize_to_file()
elif msg["event"] == "view-mapped":
found = False
for w in window_list:
if w.app_id == msg["view"]["app-id"]:
sock.configure_view(msg["view"]["id"], w.geometry.x, w.geometry.y, w.geometry.w, w.geometry.h)
sock.set_focus(msg["view"]["id"])
found = True
break
if not found:
g = geometry(msg["view"]["geometry"]["x"], msg["view"]["geometry"]["y"], msg["view"]["geometry"]["width"], msg["view"]["geometry"]["height"])
window_list.append(window(msg["view"]["app-id"], geometry(g.x, g.y, g.w, g.h)))
serialize_to_file()
elif msg["event"] == "view-geometry-changed":
if msg["view"] is not None and msg["view"]["type"] == "toplevel" and msg["view"]["mapped"]:
found = False
for w in window_list:
if w.app_id == msg["view"]["app-id"]:
found = True
current_window = w
break
g = geometry(msg["view"]["geometry"]["x"], msg["view"]["geometry"]["y"], msg["view"]["geometry"]["width"], msg["view"]["geometry"]["height"])
if found:
current_window.set_geometry(geometry(g.x, g.y, g.w, g.h))
else:
current_window = window(msg["view"]["app-id"], geometry(g.x, g.y, g.w, g.h))
window_list.append(current_window)
serialize_to_file()
except KeyboardInterrupt:
exit(0)

0 comments on commit aad46c4

Please sign in to comment.