git clone https://git.lucas.co/hou-control.git
python3.11libs/hc/hcwindowwatcher.py (2.9K)
1 import hou
2 from PySide6.QtCore import QEvent, QObject
3
4
5 class HCWindowWatcher(QObject):
6 EVENT_MAP = {
7 QEvent.Enter: "enter",
8 QEvent.Leave: "leave",
9 QEvent.WindowActivate: "focus",
10 QEvent.WindowDeactivate: "unfocus",
11 }
12
13 def __init__(self):
14 super().__init__(hou.qt.mainWindow())
15 self._installed = False
16 self._watched = []
17 self._in_window = False
18 self._counts = {name: 0 for name in self.EVENT_MAP.values()}
19 self._callbacks = {name: [] for name in self.EVENT_MAP.values()}
20
21 def _targets(self):
22 from PySide6.QtWidgets import QWidget
23 main = hou.qt.mainWindow()
24 targets = [main]
25 gl = main.findChild(QWidget, "RE_GLDrawableWrapper")
26 if gl is not None:
27 targets.append(gl)
28 return targets
29
30 def start(self):
31 if self._installed:
32 return
33 self._watched = self._targets()
34 for t in self._watched:
35 t.installEventFilter(self)
36 self._installed = True
37
38 def stop(self):
39 if not self._installed:
40 return
41 for t in self._watched:
42 t.removeEventFilter(self)
43 self._watched = []
44 self._installed = False
45
46 def toggle(self):
47 if self._installed:
48 self.stop()
49 else:
50 self.start()
51
52 def isRunning(self):
53 return self._installed
54
55 def counts(self):
56 return dict(self._counts)
57
58 def on(self, name, callback):
59 if name not in self._callbacks:
60 raise ValueError(f"unknown event: {name}")
61 if callback not in self._callbacks[name]:
62 self._callbacks[name].append(callback)
63
64 def off(self, name, callback):
65 if name in self._callbacks and callback in self._callbacks[name]:
66 self._callbacks[name].remove(callback)
67
68 def _fire(self, name):
69 for cb in self._callbacks[name]:
70 try:
71 cb()
72 except Exception as e:
73 print(f"[HCWindowWatcher] {name} callback error: {e!r}")
74
75 def _cursorInsideMain(self):
76 main = hou.qt.mainWindow()
77 pos = main.mapFromGlobal(main.cursor().pos())
78 return main.rect().contains(pos)
79
80 def eventFilter(self, obj, event):
81 et = event.type()
82 if et == QEvent.Enter:
83 if not self._in_window:
84 self._in_window = True
85 self._counts["enter"] += 1
86 self._fire("enter")
87 elif et == QEvent.Leave:
88 if self._in_window and not self._cursorInsideMain():
89 self._in_window = False
90 self._counts["leave"] += 1
91 self._fire("leave")
92 elif et == QEvent.WindowActivate:
93 self._counts["focus"] += 1
94 self._fire("focus")
95 elif et == QEvent.WindowDeactivate:
96 self._counts["unfocus"] += 1
97 self._fire("unfocus")
98 return False