First commit

This commit is contained in:
Fierelier 2023-04-24 20:17:48 +02:00
commit 401f005e42
6 changed files with 213 additions and 0 deletions

5
modules.txt Normal file
View File

@ -0,0 +1,5 @@
proc
cgroup
xorg
#wayland
main

23
modules/cgroup.py Normal file
View File

@ -0,0 +1,23 @@
import os
cg = "/sys/fs/cgroup"
def addControllers(cname,*names):
controllers = open(cg+ "/" +cname+ "/cgroup.subtree_control").read().split(" ")
for name in names:
if not name in controllers: open("/sys/fs/cgroup/" +cname+ "/cgroup.subtree_control","a").write("+" +name+ "\n")
def create(name):
if not os.path.isdir(cg+ "/" +name):
os.makedirs(cg+ "/" +name)
def setProp(name,prop,value):
open(cg+ "/" +name+ "/" +prop,"w").write(value)
def setGroup(pid,name):
print("Setting cgroup of " +pid+ " to: '" +name+ "'")
open(cg+ "/" +name+ "/cgroup.procs","w").write(pid)
def getProcs(name):
return open(cg+ "/" +name+ "/cgroup.procs").read().split("\n")
_g.cgroup = globals()

89
modules/main.py Normal file
View File

@ -0,0 +1,89 @@
handlerGroups = { # The first group that takes control of a process has priority
"firefox": {
"idents": ["binSimple:firefox","binSimple:firefox-esr"],
"unhookUnmatchedChildren": True,
"propsFocused": {
"memory.high": "256M"
},
"propsUnfocused": {
"memory.high": "256M",
"cpu.weight": "1"
}
}
}
import fnmatch
for group in handlerGroups:
if not "propsFocused" in handlerGroups[group]: handlerGroups[group]["propsFocused"] = {}
if not "propsUnfocused" in handlerGroups[group]: handlerGroups[group]["propsUnfocused"] = {}
requiredControllers = []
for group in handlerGroups: # Figure out the required controllers
for ptype in ["propsFocused","propsUnfocused"]:
for controller in handlerGroups[group][ptype]:
controller = controller.split(".",1)[0]
if not controller in requiredControllers:
requiredControllers.append(controller)
_g.cgroup.create("window-cg")
_g.cgroup.addControllers("window-cg",*requiredControllers)
# Create cgroups
for group in handlerGroups:
_g.cgroup.create("window-cg/" +group+ ".focused")
_g.cgroup.addControllers("window-cg/" +group+ ".focused",*requiredControllers)
_g.cgroup.create("window-cg/" +group+ ".unfocused")
_g.cgroup.addControllers("window-cg/" +group+ ".unfocused",*requiredControllers)
def doesProcMatch(proc,group):
for ident in group["idents"]:
iSplit = ident.split(":",1)
if fnmatch.fnmatch(proc[iSplit[0]],iSplit[1]):
return True
return False
def windowChanged(window):
pid = _g.windowSystem.getWindowPID(window)
procs = _g.proc.getList()
focusedGroup = None
for group in handlerGroups:
try:
if doesProcMatch(procs[pid],handlerGroups[group]):
focusedGroup = group
break
except Exception:
pass
print("Focused group: " +str(focusedGroup))
for group in handlerGroups:
unhook = handlerGroups[group].get("unhookUnmatchedChildren",True)
if unhook:
groupProcs = _g.cgroup.getProcs("window-cg/" + group + ".focused") + _g.cgroup.getProcs("window-cg/" + group + ".unfocused")
for proc in list(procs):
match = False
try:
match = doesProcMatch(procs[proc],handlerGroups[group])
except Exception:
pass
if unhook:
try:
if not match and proc in groupProcs:
_g.cgroup.setGroup(proc,"")
except Exception:
pass
try:
if not match: continue
pproc = procs[proc]
del procs[proc]
if focusedGroup == group:
_g.cgroup.setGroup(pproc["pid"],"window-cg/" + group + ".focused")
else:
_g.cgroup.setGroup(pproc["pid"],"window-cg/" + group + ".unfocused")
except Exception:
pass

23
modules/proc.py Normal file
View File

@ -0,0 +1,23 @@
import os
def getList():
procs = {}
for root,dirs,files in os.walk("/proc"):
for file in dirs:
try:
pid = (root + "/" + file).replace("/proc/","",1)
for char in pid:
if not (char in "0123456789"):
pid = None
break
if pid == None: continue
info = {}
info["pid"] = pid
info["bin"] = os.path.realpath("/proc/" +pid+ "/exe")
info["binSimple"] = info["bin"].rsplit(os.path.sep,1)[-1]
procs[pid] = info
except Exception:
pass
break
return procs
_g.proc = globals()

28
modules/xorg.py Normal file
View File

@ -0,0 +1,28 @@
import gi
gi.require_version("Gtk","3.0")
gi.require_version("Wnck","3.0")
from gi.repository import Gtk, Wnck
import traceback
def init():
wnck_scr = Wnck.Screen.get_default()
wnck_scr.force_update()
wnck_scr.connect("active-window-changed",sWindowChanged)
sWindowChanged(wnck_scr,None)
Gtk.main()
def sWindowChanged(screen, previous_window):
window = screen.get_active_window()
for module in _g.modules:
try:
module["windowChanged"](window)
except Exception:
print(traceback.format_exc())
def getWindowPID(window):
try:
return str(window.get_pid())
except:
return "0"
_g.windowSystem = globals()

45
window-cg Executable file
View File

@ -0,0 +1,45 @@
#!/usr/bin/env python3
import sys
import os
p = os.path.join
pUp = os.path.dirname
s = False
if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'):
s = os.path.realpath(sys.executable)
else:
s = os.path.realpath(__file__)
sp = pUp(s)
import munch
_g = munch.Munch()
_g.modules = []
def loadModules():
moduleID = 0
moduleText = open(p(sp,"modules.txt")).read()
moduleText = moduleText.replace("\r","")
moduleText = moduleText.strip("\n")
moduleText = moduleText.split("\n")
for line in moduleText:
line = line.split("#",1)[0]
line = line.strip(" \t")
if line == "": continue
g = munch.Munch()
g._g = _g
_g.modules.append(g)
code = compile(
open(p(sp,"modules",line + ".py")).read(),
p(sp,"modules",line + ".py"),
"exec"
)
exec(code,_g.modules[moduleID])
if not "windowChanged" in _g.modules[moduleID]:
del _g.modules[moduleID]
continue
moduleID += 1
def main():
loadModules()
_g.windowSystem.init()
main()