screenoverlay 0.2.1__py3-none-any.whl → 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- screenoverlay/__init__.py +1 -1
- screenoverlay/overlay.py +26 -120
- {screenoverlay-0.2.1.dist-info → screenoverlay-0.3.0.dist-info}/METADATA +24 -57
- screenoverlay-0.3.0.dist-info/RECORD +7 -0
- screenoverlay-0.2.1.dist-info/RECORD +0 -7
- {screenoverlay-0.2.1.dist-info → screenoverlay-0.3.0.dist-info}/WHEEL +0 -0
- {screenoverlay-0.2.1.dist-info → screenoverlay-0.3.0.dist-info}/licenses/LICENSE +0 -0
- {screenoverlay-0.2.1.dist-info → screenoverlay-0.3.0.dist-info}/top_level.txt +0 -0
screenoverlay/__init__.py
CHANGED
screenoverlay/overlay.py
CHANGED
|
@@ -8,11 +8,6 @@ import tkinter as tk
|
|
|
8
8
|
import platform
|
|
9
9
|
import sys
|
|
10
10
|
import os
|
|
11
|
-
import threading
|
|
12
|
-
from multiprocessing import Process, Queue
|
|
13
|
-
import time
|
|
14
|
-
import atexit
|
|
15
|
-
import signal
|
|
16
11
|
|
|
17
12
|
|
|
18
13
|
class NativeBlurOverlay:
|
|
@@ -56,124 +51,37 @@ class NativeBlurOverlay:
|
|
|
56
51
|
|
|
57
52
|
self.root = None
|
|
58
53
|
self._timer_id = None
|
|
59
|
-
self._process = None
|
|
60
|
-
self._command_queue = None
|
|
61
|
-
|
|
62
|
-
# Register cleanup on exit to prevent orphaned processes
|
|
63
|
-
atexit.register(self._cleanup_on_exit)
|
|
64
|
-
|
|
65
|
-
def _cleanup_on_exit(self):
|
|
66
|
-
"""Cleanup overlay process on program exit"""
|
|
67
|
-
if self._process is not None and self._process.is_alive():
|
|
68
|
-
try:
|
|
69
|
-
# Try graceful stop first
|
|
70
|
-
if self._command_queue is not None:
|
|
71
|
-
try:
|
|
72
|
-
self._command_queue.put('stop')
|
|
73
|
-
except:
|
|
74
|
-
pass
|
|
75
|
-
|
|
76
|
-
# Wait briefly
|
|
77
|
-
self._process.join(timeout=0.5)
|
|
78
|
-
|
|
79
|
-
# Force kill if still alive
|
|
80
|
-
if self._process.is_alive():
|
|
81
|
-
self._process.terminate()
|
|
82
|
-
self._process.join(timeout=0.5)
|
|
83
|
-
|
|
84
|
-
# Last resort - force kill
|
|
85
|
-
if self._process.is_alive():
|
|
86
|
-
self._process.kill()
|
|
87
|
-
except:
|
|
88
|
-
pass
|
|
89
54
|
|
|
90
55
|
def start(self):
|
|
91
56
|
"""
|
|
92
|
-
Start the overlay
|
|
93
|
-
Call this once at app startup.
|
|
57
|
+
Start the overlay indefinitely (non-blocking, runs until stop() is called)
|
|
94
58
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
overlay.show() # Show overlay (instant)
|
|
102
|
-
time.sleep(2)
|
|
103
|
-
overlay.hide() # Hide overlay (instant)
|
|
104
|
-
overlay.show() # Show again
|
|
105
|
-
|
|
106
|
-
overlay.stop() # Cleanup when done
|
|
59
|
+
For ScreenStop integration, run this in a separate process:
|
|
60
|
+
from multiprocessing import Process
|
|
61
|
+
p = Process(target=overlay.start)
|
|
62
|
+
p.start()
|
|
63
|
+
# Later: p.terminate()
|
|
107
64
|
"""
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
self._command_queue = Queue()
|
|
112
|
-
self._process = Process(target=self._run_process, args=(self._command_queue,), daemon=True)
|
|
113
|
-
self._process.start()
|
|
114
|
-
|
|
115
|
-
# Wait a bit for process to initialize
|
|
116
|
-
time.sleep(0.3)
|
|
117
|
-
|
|
118
|
-
def show(self):
|
|
119
|
-
"""Show the overlay (instant, ~1ms)"""
|
|
120
|
-
if self._command_queue is not None:
|
|
121
|
-
self._command_queue.put('show')
|
|
122
|
-
|
|
123
|
-
def hide(self):
|
|
124
|
-
"""Hide the overlay (instant, ~1ms)"""
|
|
125
|
-
if self._command_queue is not None:
|
|
126
|
-
self._command_queue.put('hide')
|
|
65
|
+
self._create_window()
|
|
66
|
+
self.root.mainloop()
|
|
127
67
|
|
|
128
68
|
def stop(self):
|
|
129
|
-
"""Stop and
|
|
130
|
-
if self.
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
self._create_window()
|
|
146
|
-
self.root.withdraw() # Start hidden
|
|
147
|
-
|
|
148
|
-
# Process commands from queue
|
|
149
|
-
def check_commands():
|
|
150
|
-
try:
|
|
151
|
-
while not command_queue.empty():
|
|
152
|
-
cmd = command_queue.get_nowait()
|
|
153
|
-
if cmd == 'show':
|
|
154
|
-
self.root.deiconify()
|
|
155
|
-
self.root.lift()
|
|
156
|
-
elif cmd == 'hide':
|
|
157
|
-
self.root.withdraw()
|
|
158
|
-
elif cmd == 'stop':
|
|
159
|
-
self.root.quit()
|
|
160
|
-
return
|
|
161
|
-
except:
|
|
162
|
-
pass
|
|
163
|
-
|
|
164
|
-
# Check again in 10ms
|
|
165
|
-
self.root.after(10, check_commands)
|
|
166
|
-
|
|
167
|
-
# Start command checker
|
|
168
|
-
check_commands()
|
|
169
|
-
|
|
170
|
-
# Run mainloop
|
|
171
|
-
self.root.mainloop()
|
|
172
|
-
|
|
173
|
-
except Exception as e:
|
|
174
|
-
print(f"Overlay process error: {e}")
|
|
175
|
-
finally:
|
|
176
|
-
os._exit(0)
|
|
69
|
+
"""Stop and close the overlay"""
|
|
70
|
+
if self._timer_id is not None:
|
|
71
|
+
try:
|
|
72
|
+
self.root.after_cancel(self._timer_id)
|
|
73
|
+
self._timer_id = None
|
|
74
|
+
except:
|
|
75
|
+
pass
|
|
76
|
+
if self.root is not None:
|
|
77
|
+
try:
|
|
78
|
+
self.root.quit()
|
|
79
|
+
self.root.destroy()
|
|
80
|
+
except:
|
|
81
|
+
pass
|
|
82
|
+
self.root = None
|
|
83
|
+
# Exit the process cleanly
|
|
84
|
+
os._exit(0)
|
|
177
85
|
|
|
178
86
|
def _create_window(self):
|
|
179
87
|
"""Internal method to create and configure the Tkinter window"""
|
|
@@ -346,7 +254,7 @@ class NativeBlurOverlay:
|
|
|
346
254
|
print(f"Linux blur effect hint failed: {e}")
|
|
347
255
|
|
|
348
256
|
def kill_completely(self):
|
|
349
|
-
"""Exit the overlay completely
|
|
257
|
+
"""Exit the overlay completely"""
|
|
350
258
|
try:
|
|
351
259
|
if self.root:
|
|
352
260
|
self.root.quit()
|
|
@@ -354,9 +262,7 @@ class NativeBlurOverlay:
|
|
|
354
262
|
except:
|
|
355
263
|
pass
|
|
356
264
|
|
|
357
|
-
|
|
358
|
-
if self._timer_id is not None:
|
|
359
|
-
os._exit(0)
|
|
265
|
+
os._exit(0)
|
|
360
266
|
|
|
361
267
|
|
|
362
268
|
if __name__ == "__main__":
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: screenoverlay
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Cross-platform screen overlay with blur, black, white, and custom modes
|
|
5
5
|
Home-page: https://github.com/pekay-ai/screenoverlay
|
|
6
6
|
Author: Pekay
|
|
@@ -109,33 +109,27 @@ Overlay(mode='custom', color_tint=(255, 100, 100), opacity=0.7).activate()
|
|
|
109
109
|
|
|
110
110
|
Press `ESC` to dismiss the overlay early.
|
|
111
111
|
|
|
112
|
-
###
|
|
112
|
+
### Manual Start/Stop Control
|
|
113
113
|
|
|
114
|
-
For
|
|
114
|
+
For apps that need to control overlay lifetime (like ScreenStop):
|
|
115
115
|
|
|
116
116
|
```python
|
|
117
117
|
from screenoverlay import Overlay
|
|
118
|
-
import
|
|
119
|
-
|
|
120
|
-
# Initialize once (one-time ~300ms setup)
|
|
121
|
-
overlay = Overlay(mode='blur', blur_strength=4)
|
|
122
|
-
overlay.start()
|
|
118
|
+
from multiprocessing import Process
|
|
123
119
|
|
|
124
|
-
|
|
125
|
-
overlay
|
|
126
|
-
|
|
127
|
-
overlay.hide() # Overlay disappears instantly
|
|
120
|
+
def run_overlay():
|
|
121
|
+
overlay = Overlay(mode='blur', blur_strength=4)
|
|
122
|
+
overlay.start() # Runs indefinitely
|
|
128
123
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
124
|
+
# Start overlay in separate process
|
|
125
|
+
overlay_process = Process(target=run_overlay)
|
|
126
|
+
overlay_process.start()
|
|
132
127
|
|
|
133
|
-
#
|
|
134
|
-
|
|
128
|
+
# Later, stop it
|
|
129
|
+
overlay_process.terminate()
|
|
130
|
+
overlay_process.join()
|
|
135
131
|
```
|
|
136
132
|
|
|
137
|
-
**Performance:** `show()` and `hide()` take **~0.1ms** - virtually instant! Perfect for real-time control.
|
|
138
|
-
|
|
139
133
|
**See [`examples/`](examples/) folder for more use cases!**
|
|
140
134
|
|
|
141
135
|
---
|
|
@@ -249,45 +243,32 @@ overlay.activate(duration=5)
|
|
|
249
243
|
|
|
250
244
|
**Note:** Press `ESC` to dismiss early.
|
|
251
245
|
|
|
252
|
-
### `start()` Method
|
|
246
|
+
### `start()` Method
|
|
253
247
|
|
|
254
|
-
|
|
248
|
+
Start overlay indefinitely (runs until stopped).
|
|
255
249
|
|
|
256
250
|
```python
|
|
257
251
|
overlay.start()
|
|
258
252
|
```
|
|
259
253
|
|
|
260
|
-
**Important:**
|
|
261
|
-
|
|
262
|
-
### `show()` Method ⭐ **NEW**
|
|
263
|
-
|
|
264
|
-
Show the overlay instantly (~0.1ms).
|
|
265
|
-
|
|
266
|
-
```python
|
|
267
|
-
overlay.show()
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
**Performance:** Virtually instant - no subprocess creation, just a queue message.
|
|
271
|
-
|
|
272
|
-
### `hide()` Method ⭐ **NEW**
|
|
273
|
-
|
|
274
|
-
Hide the overlay instantly (~0.1ms).
|
|
254
|
+
**Important:** This is blocking and runs `mainloop()`. For app integration, run in a separate process:
|
|
275
255
|
|
|
276
256
|
```python
|
|
277
|
-
|
|
257
|
+
from multiprocessing import Process
|
|
258
|
+
p = Process(target=overlay.start)
|
|
259
|
+
p.start()
|
|
260
|
+
# Later: p.terminate()
|
|
278
261
|
```
|
|
279
262
|
|
|
280
|
-
**Performance:** Even faster than `show()` - typically <0.1ms.
|
|
281
|
-
|
|
282
263
|
### `stop()` Method
|
|
283
264
|
|
|
284
|
-
Stop and
|
|
265
|
+
Stop and close the overlay.
|
|
285
266
|
|
|
286
267
|
```python
|
|
287
268
|
overlay.stop()
|
|
288
269
|
```
|
|
289
270
|
|
|
290
|
-
**Note:**
|
|
271
|
+
**Note:** Usually called from within the overlay process, or use `process.terminate()` from parent.
|
|
291
272
|
|
|
292
273
|
---
|
|
293
274
|
|
|
@@ -374,25 +355,12 @@ Overlay(
|
|
|
374
355
|
|
|
375
356
|
## ⚡ Performance
|
|
376
357
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
- **activate() (duration-based):** <50ms startup
|
|
380
|
-
- **start() (one-time init):** ~300ms (creates subprocess)
|
|
381
|
-
- **show() / hide():** **~0.1ms** (virtually instant!)
|
|
382
|
-
|
|
383
|
-
### How It Works
|
|
384
|
-
|
|
358
|
+
- **Startup Latency:** <50ms
|
|
385
359
|
- **Method:** Native OS window effects (no screen capture)
|
|
386
360
|
- **Permissions:** None required (works without screen recording access)
|
|
387
361
|
- **Memory:** Minimal footprint
|
|
388
|
-
- **Process Model:** Separate process with queue-based messaging
|
|
389
|
-
|
|
390
|
-
**Why so fast?** Unlike traditional screen capture approaches (400-1000ms), we use:
|
|
391
|
-
1. Native OS-level window blur effects (no image processing)
|
|
392
|
-
2. Persistent subprocess with `withdraw()`/`deiconify()` toggling
|
|
393
|
-
3. Queue-based messaging for instant communication
|
|
394
362
|
|
|
395
|
-
|
|
363
|
+
**Why so fast?** Unlike traditional screen capture approaches (400-1000ms), we use native OS-level window blur effects, eliminating the need to capture, process, and re-render the screen.
|
|
396
364
|
|
|
397
365
|
---
|
|
398
366
|
|
|
@@ -452,7 +420,6 @@ Check out the [`examples/`](examples/) directory for complete working examples:
|
|
|
452
420
|
|
|
453
421
|
- **`basic_duration.py`** - Simple blur overlay with fixed duration
|
|
454
422
|
- **`black_screen.py`** - Privacy blackout screen
|
|
455
|
-
- **`show_hide_control.py`** ⭐ **NEW** - Instant show/hide toggling (~0.1ms)
|
|
456
423
|
- **`start_stop_control.py`** - Manual control with multiprocessing
|
|
457
424
|
- **`custom_color.py`** - Custom colored overlay
|
|
458
425
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
screenoverlay/__init__.py,sha256=3Dj4hc8poOLtYXw3boa_wl7SC5mQ31OPocfz7uOAGkE,256
|
|
2
|
+
screenoverlay/overlay.py,sha256=vqf516zJKzUuslGPIhljKxSVBIIWHkVJSXMRjK4sgA0,10956
|
|
3
|
+
screenoverlay-0.3.0.dist-info/licenses/LICENSE,sha256=QlEjK4tuMjNEYVlvzaIhxfsCeU8hcGZyuT85cm1YChE,1084
|
|
4
|
+
screenoverlay-0.3.0.dist-info/METADATA,sha256=5A3RMRlGyi6JTGfb0fByhEv55usJp5q-6huXPf6kN5o,13861
|
|
5
|
+
screenoverlay-0.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
6
|
+
screenoverlay-0.3.0.dist-info/top_level.txt,sha256=kfPL07o_kJ-mlb14Ps2zp_tIYnD8GfsSXlbDxDF6Eic,14
|
|
7
|
+
screenoverlay-0.3.0.dist-info/RECORD,,
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
screenoverlay/__init__.py,sha256=OtIWzvmSmIj6XuMw-JzQmuYb44A_8Z4xKSUFYTa1ZqU,256
|
|
2
|
-
screenoverlay/overlay.py,sha256=f5NlalqC81tm5c1g9FEfZhCqgwaJzFDvO5dNPT1uNJU,14326
|
|
3
|
-
screenoverlay-0.2.1.dist-info/licenses/LICENSE,sha256=QlEjK4tuMjNEYVlvzaIhxfsCeU8hcGZyuT85cm1YChE,1084
|
|
4
|
-
screenoverlay-0.2.1.dist-info/METADATA,sha256=f3AvURDIQXS_mt0H3qPjug5sf7CcM6mtxhXrgKk_lFQ,14888
|
|
5
|
-
screenoverlay-0.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
6
|
-
screenoverlay-0.2.1.dist-info/top_level.txt,sha256=kfPL07o_kJ-mlb14Ps2zp_tIYnD8GfsSXlbDxDF6Eic,14
|
|
7
|
-
screenoverlay-0.2.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|