使用Python管理多个x11窗口
我正在尝试创建一个类似于微软Fancyzone的基于Python的窗口管理器。此管理器的任务之一是允许用户创建窗口,作为windows可以“捕捉”到的区域的模板。我的想法是,我可以只允许用户创建多个窗口,在“保存”时,模块将缓存窗口几何图形,以便稍后捕捉。我遇到的问题是管理多个窗口。在我的程序中,“add”关键字使一个线程旋转起来,该线程处理单个窗口及其后续事件循环。一个线程就可以了-我们可以在需要的时候缓存几何体。但是,多个线程最终会使程序陷入困境使用Python管理多个x11窗口,python,python-multithreading,x11,xorg,Python,Python Multithreading,X11,Xorg,我正在尝试创建一个类似于微软Fancyzone的基于Python的窗口管理器。此管理器的任务之一是允许用户创建窗口,作为windows可以“捕捉”到的区域的模板。我的想法是,我可以只允许用户创建多个窗口,在“保存”时,模块将缓存窗口几何图形,以便稍后捕捉。我遇到的问题是管理多个窗口。在我的程序中,“add”关键字使一个线程旋转起来,该线程处理单个窗口及其后续事件循环。一个线程就可以了-我们可以在需要的时候缓存几何体。但是,多个线程最终会使程序陷入困境 Q:是否有一个我在这里遗漏的设计范例可以让它
Q:
是否有一个我在这里遗漏的设计范例可以让它得以实现
import json
import os
import sys
import threading
from Xlib import X
from Xlib.display import Display
from Xlib.error import XError, ConnectionClosedError
HERE = os.path.abspath(os.path.dirname(__file__))
def active_window(display, window_id=None):
if not window_id:
window_id = display.screen().root.get_full_property(
display.intern_atom('_NET_ACTIVE_WINDOW'), X.AnyPropertyType
).value[0]
try:
return display.create_resource_object('window', window_id)
except XError:
return None
class Window:
def __init__(self, display, msg):
self.display = display
self.msg = msg
self.screen = self.display.screen()
self.window = self.screen.root.create_window(
10, 10, 500, 250, 1,
self.screen.root_depth,
background_pixel=self.screen.black_pixel,
event_mask=X.ExposureMask | X.KeyPressMask,
)
self.gc = self.window.create_gc(
background = self.screen.black_pixel,
)
self.window.map()
def loop(self):
while True:
try:
e = self.display.next_event()
if e.type == X.Expose:
self.window.draw_text(self.gc, 10, 50, self.msg)
elif e.type == X.KeyPress:
raise SystemExit
except ConnectionClosedError:
# raised when X button is pressed
#
# TODO: figure out way to allow exit of single window without
# having to kill the entire application (currently get a
# "socket_error" if you try to add a window after exiting
# an already made window)
#
# for now, just kill everything
os._exit(1)
@property
def _id(self):
return self.window.id
class ZoneBuilder:
def __init__(self) -> None:
self.zones = []
self.display = Display()
self.screen = self.display.screen()
def _main_action(self):
return input(
'specify action:\n$ '
)
def main(self):
action = self._main_action()
if action == "add":
self.add
elif action == "done":
self.done
elif action == "exit":
self.terminate()
self.main()
@property
def done(self):
results = []
for zone, _ in self.zones:
window = active_window(self.display, zone._id)
pg = window.query_tree().parent.query_tree().parent.get_geometry()
results.append({
"x": pg.x,
"y": pg.y,
"width": pg.width,
"height": pg.height
})
self._write(results)
self.terminate()
@property
def add(self):
window = Window(self.display, f"Zone {len(self.zones) + 1}")
thread = threading.Thread(target=window.loop)
thread.daemon = True
thread.start()
self.zones.append([window, thread])
def _read(self, path = os.path.join(HERE, "zones.json")):
with open(path, 'r') as f:
return json.loads(f.read())
def _write(self, results, path = os.path.join(HERE, "zones.json")):
with open(path, 'w') as f:
f.write(json.dumps(results, indent=2, sort_keys=True))
def terminate(self):
sys.exit()
if __name__ == "__main__":
zb = ZoneBuilder()
zb.main()