screenoverlay 0.3.1__py3-none-any.whl → 0.4.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 +106 -16
- {screenoverlay-0.3.1.dist-info → screenoverlay-0.4.0.dist-info}/METADATA +6 -2
- screenoverlay-0.4.0.dist-info/RECORD +7 -0
- screenoverlay-0.3.1.dist-info/RECORD +0 -7
- {screenoverlay-0.3.1.dist-info → screenoverlay-0.4.0.dist-info}/WHEEL +0 -0
- {screenoverlay-0.3.1.dist-info → screenoverlay-0.4.0.dist-info}/licenses/LICENSE +0 -0
- {screenoverlay-0.3.1.dist-info → screenoverlay-0.4.0.dist-info}/top_level.txt +0 -0
screenoverlay/__init__.py
CHANGED
screenoverlay/overlay.py
CHANGED
|
@@ -14,6 +14,13 @@ import time
|
|
|
14
14
|
import atexit
|
|
15
15
|
import signal
|
|
16
16
|
|
|
17
|
+
# Try to import screeninfo for multi-monitor support
|
|
18
|
+
try:
|
|
19
|
+
from screeninfo import get_monitors
|
|
20
|
+
HAS_SCREENINFO = True
|
|
21
|
+
except ImportError:
|
|
22
|
+
HAS_SCREENINFO = False
|
|
23
|
+
|
|
17
24
|
|
|
18
25
|
class NativeBlurOverlay:
|
|
19
26
|
def __init__(self, mode='blur', blur_strength=3, opacity=0.85, color_tint=(136, 136, 136)):
|
|
@@ -55,6 +62,7 @@ class NativeBlurOverlay:
|
|
|
55
62
|
self.apply_blur = True
|
|
56
63
|
|
|
57
64
|
self.root = None
|
|
65
|
+
self.windows = [] # List to hold multiple windows for multi-monitor
|
|
58
66
|
self._timer_id = None
|
|
59
67
|
self._process = None
|
|
60
68
|
self._command_queue = None
|
|
@@ -141,9 +149,12 @@ class NativeBlurOverlay:
|
|
|
141
149
|
def _run_process(self, command_queue):
|
|
142
150
|
"""Run overlay in separate process with command queue"""
|
|
143
151
|
try:
|
|
144
|
-
# Create
|
|
145
|
-
self.
|
|
146
|
-
|
|
152
|
+
# Create windows for all monitors
|
|
153
|
+
self._create_windows()
|
|
154
|
+
|
|
155
|
+
# Hide all windows initially
|
|
156
|
+
for win in self.windows:
|
|
157
|
+
win.withdraw()
|
|
147
158
|
|
|
148
159
|
# Process commands from queue
|
|
149
160
|
def check_commands():
|
|
@@ -151,10 +162,12 @@ class NativeBlurOverlay:
|
|
|
151
162
|
while not command_queue.empty():
|
|
152
163
|
cmd = command_queue.get_nowait()
|
|
153
164
|
if cmd == 'show':
|
|
154
|
-
self.
|
|
155
|
-
|
|
165
|
+
for win in self.windows:
|
|
166
|
+
win.deiconify()
|
|
167
|
+
win.lift()
|
|
156
168
|
elif cmd == 'hide':
|
|
157
|
-
self.
|
|
169
|
+
for win in self.windows:
|
|
170
|
+
win.withdraw()
|
|
158
171
|
elif cmd == 'stop':
|
|
159
172
|
self.root.quit()
|
|
160
173
|
return
|
|
@@ -175,6 +188,67 @@ class NativeBlurOverlay:
|
|
|
175
188
|
finally:
|
|
176
189
|
os._exit(0)
|
|
177
190
|
|
|
191
|
+
def _get_monitors(self):
|
|
192
|
+
"""Get information about all monitors"""
|
|
193
|
+
if HAS_SCREENINFO:
|
|
194
|
+
try:
|
|
195
|
+
monitors = get_monitors()
|
|
196
|
+
return [(m.x, m.y, m.width, m.height) for m in monitors]
|
|
197
|
+
except:
|
|
198
|
+
pass
|
|
199
|
+
|
|
200
|
+
# Fallback: assume single primary monitor
|
|
201
|
+
root = tk.Tk()
|
|
202
|
+
root.withdraw()
|
|
203
|
+
width = root.winfo_screenwidth()
|
|
204
|
+
height = root.winfo_screenheight()
|
|
205
|
+
root.destroy()
|
|
206
|
+
return [(0, 0, width, height)]
|
|
207
|
+
|
|
208
|
+
def _create_windows(self):
|
|
209
|
+
"""Create overlay windows for all monitors"""
|
|
210
|
+
monitors = self._get_monitors()
|
|
211
|
+
|
|
212
|
+
# Create primary root window
|
|
213
|
+
self.root = tk.Tk()
|
|
214
|
+
self.root.overrideredirect(True)
|
|
215
|
+
self.root.attributes('-topmost', True)
|
|
216
|
+
|
|
217
|
+
# Configure primary window for first monitor
|
|
218
|
+
if monitors:
|
|
219
|
+
x, y, width, height = monitors[0]
|
|
220
|
+
self._configure_window(self.root, x, y, width, height)
|
|
221
|
+
self.windows.append(self.root)
|
|
222
|
+
|
|
223
|
+
# Create additional windows for other monitors
|
|
224
|
+
for x, y, width, height in monitors[1:]:
|
|
225
|
+
win = tk.Toplevel(self.root)
|
|
226
|
+
win.overrideredirect(True)
|
|
227
|
+
win.attributes('-topmost', True)
|
|
228
|
+
self._configure_window(win, x, y, width, height)
|
|
229
|
+
self.windows.append(win)
|
|
230
|
+
|
|
231
|
+
def _configure_window(self, window, x, y, width, height):
|
|
232
|
+
"""Configure a window with overlay settings"""
|
|
233
|
+
# Set background color (tint)
|
|
234
|
+
bg_color = f'#{self.color_tint[0]:02x}{self.color_tint[1]:02x}{self.color_tint[2]:02x}'
|
|
235
|
+
window.configure(bg=bg_color)
|
|
236
|
+
|
|
237
|
+
# Set opacity
|
|
238
|
+
window.attributes('-alpha', self.opacity)
|
|
239
|
+
|
|
240
|
+
# Position and size
|
|
241
|
+
window.geometry(f"{width}x{height}+{x}+{y}")
|
|
242
|
+
|
|
243
|
+
# Apply native blur effect based on OS (only if mode is 'blur')
|
|
244
|
+
if self.apply_blur:
|
|
245
|
+
self._apply_native_blur_to_window(window)
|
|
246
|
+
|
|
247
|
+
# Bind escape key to exit (only on primary window)
|
|
248
|
+
if window == self.root:
|
|
249
|
+
window.bind('<Escape>', lambda e: self.kill_completely())
|
|
250
|
+
window.focus_set()
|
|
251
|
+
|
|
178
252
|
def _create_window(self):
|
|
179
253
|
"""Internal method to create and configure the Tkinter window"""
|
|
180
254
|
self.root = tk.Tk()
|
|
@@ -214,25 +288,33 @@ class NativeBlurOverlay:
|
|
|
214
288
|
self.root.mainloop()
|
|
215
289
|
|
|
216
290
|
def _apply_native_blur(self):
|
|
217
|
-
"""Apply OS-native backdrop blur effect"""
|
|
291
|
+
"""Apply OS-native backdrop blur effect to root window (legacy method)"""
|
|
292
|
+
self._apply_native_blur_to_window(self.root)
|
|
293
|
+
|
|
294
|
+
def _apply_native_blur_to_window(self, window):
|
|
295
|
+
"""Apply OS-native backdrop blur effect to a specific window"""
|
|
218
296
|
system = platform.system()
|
|
219
297
|
|
|
220
298
|
if system == 'Darwin': # macOS
|
|
221
|
-
self.
|
|
299
|
+
self._apply_macos_blur_to_window(window)
|
|
222
300
|
elif system == 'Windows':
|
|
223
|
-
self.
|
|
301
|
+
self._apply_windows_blur_to_window(window)
|
|
224
302
|
elif system == 'Linux':
|
|
225
|
-
self.
|
|
303
|
+
self._apply_linux_blur_to_window(window)
|
|
226
304
|
|
|
227
305
|
def _apply_macos_blur(self):
|
|
228
|
-
"""Apply macOS NSVisualEffectView blur"""
|
|
306
|
+
"""Apply macOS NSVisualEffectView blur (legacy method)"""
|
|
307
|
+
self._apply_macos_blur_to_window(self.root)
|
|
308
|
+
|
|
309
|
+
def _apply_macos_blur_to_window(self, window):
|
|
310
|
+
"""Apply macOS NSVisualEffectView blur to a specific window"""
|
|
229
311
|
try:
|
|
230
312
|
from Cocoa import NSView, NSVisualEffectView
|
|
231
313
|
from Cocoa import NSVisualEffectBlendingModeBehindWindow, NSVisualEffectMaterialDark
|
|
232
314
|
import objc
|
|
233
315
|
|
|
234
316
|
# Get the Tk window's NSWindow
|
|
235
|
-
window_id =
|
|
317
|
+
window_id = window.winfo_id()
|
|
236
318
|
|
|
237
319
|
# Create NSVisualEffectView
|
|
238
320
|
# Note: This requires pyobjc-framework-Cocoa
|
|
@@ -270,7 +352,11 @@ class NativeBlurOverlay:
|
|
|
270
352
|
print(f"macOS blur effect failed: {e}")
|
|
271
353
|
|
|
272
354
|
def _apply_windows_blur(self):
|
|
273
|
-
"""Apply Windows Acrylic/Blur effect"""
|
|
355
|
+
"""Apply Windows Acrylic/Blur effect (legacy method)"""
|
|
356
|
+
self._apply_windows_blur_to_window(self.root)
|
|
357
|
+
|
|
358
|
+
def _apply_windows_blur_to_window(self, window):
|
|
359
|
+
"""Apply Windows Acrylic/Blur effect to a specific window"""
|
|
274
360
|
try:
|
|
275
361
|
import ctypes
|
|
276
362
|
from ctypes import wintypes
|
|
@@ -278,10 +364,10 @@ class NativeBlurOverlay:
|
|
|
278
364
|
# Get window handle - try multiple methods
|
|
279
365
|
try:
|
|
280
366
|
# Method 1: Direct window ID
|
|
281
|
-
hwnd =
|
|
367
|
+
hwnd = window.winfo_id()
|
|
282
368
|
except:
|
|
283
369
|
# Method 2: Get parent window
|
|
284
|
-
hwnd = ctypes.windll.user32.GetParent(
|
|
370
|
+
hwnd = ctypes.windll.user32.GetParent(window.winfo_id())
|
|
285
371
|
|
|
286
372
|
if not hwnd:
|
|
287
373
|
print("Could not get window handle for blur effect")
|
|
@@ -332,7 +418,11 @@ class NativeBlurOverlay:
|
|
|
332
418
|
print("Overlay will work but without native blur effect")
|
|
333
419
|
|
|
334
420
|
def _apply_linux_blur(self):
|
|
335
|
-
"""Apply Linux compositor blur (X11/Wayland)"""
|
|
421
|
+
"""Apply Linux compositor blur (X11/Wayland) (legacy method)"""
|
|
422
|
+
self._apply_linux_blur_to_window(self.root)
|
|
423
|
+
|
|
424
|
+
def _apply_linux_blur_to_window(self, window):
|
|
425
|
+
"""Apply Linux compositor blur (X11/Wayland) to a specific window"""
|
|
336
426
|
try:
|
|
337
427
|
# Linux blur depends on compositor (KWin, Mutter, etc.)
|
|
338
428
|
# Most compositors respect window transparency and apply blur automatically
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: screenoverlay
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.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
|
|
@@ -25,6 +25,7 @@ Requires-Python: >=3.7
|
|
|
25
25
|
Description-Content-Type: text/markdown
|
|
26
26
|
License-File: LICENSE
|
|
27
27
|
Requires-Dist: pyobjc-framework-Cocoa; platform_system == "Darwin"
|
|
28
|
+
Requires-Dist: screeninfo
|
|
28
29
|
Provides-Extra: dev
|
|
29
30
|
Requires-Dist: pytest; extra == "dev"
|
|
30
31
|
Requires-Dist: twine; extra == "dev"
|
|
@@ -70,6 +71,7 @@ We're releasing it as **open-source (MIT)** because we believe privacy tools sho
|
|
|
70
71
|
|
|
71
72
|
- 🎭 **4 Overlay Modes** - blur, black, white, custom colors
|
|
72
73
|
- ⚡ **Ultra Fast** - <50ms startup, native OS blur effects
|
|
74
|
+
- 🖥️ **Multi-Monitor Support** - Automatically blurs ALL screens simultaneously
|
|
73
75
|
- 🔒 **No Permissions** - No screen recording access required
|
|
74
76
|
- 🌍 **Cross-Platform** - macOS, Windows, Linux
|
|
75
77
|
- 🎯 **Simple API** - One line of code to activate
|
|
@@ -384,13 +386,15 @@ Overlay(
|
|
|
384
386
|
|
|
385
387
|
- **Method:** Native OS window effects (no screen capture)
|
|
386
388
|
- **Permissions:** None required (works without screen recording access)
|
|
387
|
-
- **Memory:** Minimal footprint
|
|
389
|
+
- **Memory:** Minimal footprint (~10 MB per screen)
|
|
388
390
|
- **Process Model:** Separate process with queue-based messaging
|
|
391
|
+
- **Multi-Monitor:** Automatically detects and covers all screens
|
|
389
392
|
|
|
390
393
|
**Why so fast?** Unlike traditional screen capture approaches (400-1000ms), we use:
|
|
391
394
|
1. Native OS-level window blur effects (no image processing)
|
|
392
395
|
2. Persistent subprocess with `withdraw()`/`deiconify()` toggling
|
|
393
396
|
3. Queue-based messaging for instant communication
|
|
397
|
+
4. One window per monitor (all controlled simultaneously)
|
|
394
398
|
|
|
395
399
|
This makes `show()` and `hide()` nearly **10,000x faster** than recreating the overlay each time!
|
|
396
400
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
screenoverlay/__init__.py,sha256=NX7qDYscRGygfi9p6HJC_gT876L8wNpX1f01sS1mxPc,256
|
|
2
|
+
screenoverlay/overlay.py,sha256=h3z8tl33oB-i4q91Zoc7-mqjypnbYOtZNi5fQKmeoI8,17843
|
|
3
|
+
screenoverlay-0.4.0.dist-info/licenses/LICENSE,sha256=QlEjK4tuMjNEYVlvzaIhxfsCeU8hcGZyuT85cm1YChE,1084
|
|
4
|
+
screenoverlay-0.4.0.dist-info/METADATA,sha256=6XJrI12_VPcULWDkiq69itu6THJW9dhCXD3jAEz63v4,15143
|
|
5
|
+
screenoverlay-0.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
6
|
+
screenoverlay-0.4.0.dist-info/top_level.txt,sha256=kfPL07o_kJ-mlb14Ps2zp_tIYnD8GfsSXlbDxDF6Eic,14
|
|
7
|
+
screenoverlay-0.4.0.dist-info/RECORD,,
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
screenoverlay/__init__.py,sha256=29uNmyZ483sH3HLk6u-yJ4v5beNOEjbvd5s7SRtKsE0,256
|
|
2
|
-
screenoverlay/overlay.py,sha256=f5NlalqC81tm5c1g9FEfZhCqgwaJzFDvO5dNPT1uNJU,14326
|
|
3
|
-
screenoverlay-0.3.1.dist-info/licenses/LICENSE,sha256=QlEjK4tuMjNEYVlvzaIhxfsCeU8hcGZyuT85cm1YChE,1084
|
|
4
|
-
screenoverlay-0.3.1.dist-info/METADATA,sha256=Kxip-tXj48r2tN_Ihu5gLMrbU9P6ULX7PQZQYvB8diw,14888
|
|
5
|
-
screenoverlay-0.3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
6
|
-
screenoverlay-0.3.1.dist-info/top_level.txt,sha256=kfPL07o_kJ-mlb14Ps2zp_tIYnD8GfsSXlbDxDF6Eic,14
|
|
7
|
-
screenoverlay-0.3.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|