Skip to main content

window-grabber

Monitor processes

from window_capture import Match, WindowMonitor, Target, recommended_capture_mode

with WindowMonitor(
    [Target(process_name="example.exe"),
     Target(process_name=Match.glob("agent*.exe", ignore_case=True))],
    mode=recommended_capture_mode(),
) as monitor:
    events = monitor.poll()

recommended_capture_mode() selects an initial policy without starting workers:

Executing host Recommended mode
Windows 7/8/8.1 and Windows 10 before build 19041 controlled_desktop
Windows 10 build 19041 (2004) or later, including Windows 11 isolated
Linux isolated

Other platforms raise RuntimeError. This is an OS recommendation, not a capability probe or a guarantee that a particular window can be captured. The Windows boundary includes the cursor-exclusion API required by default capture options. Capture failures never change the selected mode. Omitting mode keeps the existing default policy; using this helper explicitly permits desktop changes on older Windows.

For RPyC, evaluate the helper and construct objects through the remote module:

wc = conn.modules["window_capture"]
monitor = wc.WindowMonitor(
    wc.Target(process_name="example.exe"),
    mode=wc.recommended_capture_mode(),
)
try:
    events = monitor.poll()
finally:
    monitor.close()

Install the package on the remote machine and run the capture process in the target user's interactive Windows session. The helper evaluates that remote host; complete monitor-over-RPyC integration has not yet been qualified.

Use mode="isolated" for source-isolated capture without desktop changes. Controlled desktop mode manages temporary visibility, topmost placement and Windows popup separation, then restores the windows. It disables explicit foreground activation to avoid cross-process input-state changes. Add allow_resize=True only if layout-changing resizing is acceptable. Each popup has its own screenshot.

Target fields combine with AND, target lists with OR; matching windows are captured once. Names, paths, classes and window_title accept literal strings, Match.regex(...), or Match.glob(...). Patterns match the whole value; glob supports * and ?. The original flags remain available for advanced callers. See revision nine for matching, mode conflicts, shared discovery deadlines and platform limits.

A typed Python API backed by precompiled, isolated Rust helpers. The coordinator owns desktop admission and recovery records. Native acquisition and potentially blocking window operations stay outside the caller's Python process.

from window_capture import CaptureSession, Target

with CaptureSession(mode="controlled_desktop") as session:
    result = session.capture(Target(process_name="viewer.exe"))
    if result.accepted:
        result.require_image().save("viewer.png")
    else:
        print(result.reason, result.message, result.recovery)
    for event in session.events.poll():
        print(event.kind, event.reason)

All supplied selectors use AND semantics; ambiguity fails. The default total budget is 2,000 ms, including startup, queueing, fallback, encoding and restoration. Desktop changes require controlled mode or explicit advanced desktop permission. PNG encoding is timed; explicitly saving the returned image is separate file I/O. RGBA output contains immutable straight-alpha bytes and must be encoded explicitly before saving.

image.save(destination) accepts a path, BytesIO, or an open binary file:

from io import BytesIO

buffer = BytesIO()
event.require_image().save(buffer)
png_bytes = buffer.getvalue()

with open("capture.png", "wb") as output:
    event.require_image().save(output)

Saving writes the existing PNG at the stream's current position. Caller-owned streams are not closed, flushed or rewound; call buffer.seek(0) before reading with read(). RGBA images still require explicit encoding. Write errors propagate and can leave partial output.

With RPyC, a path is opened on the host executing save(). A stream proxy writes to the host owning that stream. For example, if remote_event is a remote event:

buffer = BytesIO()  # Lives on this client.
remote_event.require_image().save(buffer)
png_bytes = buffer.getvalue()  # Screenshot transferred to this client.

The connection must permit the remote save call and callback access to the stream's write method. A restricted service can expose a dedicated writer object instead. Saving uses bounded byte chunks and supports short writes; it does not change connection permissions or initiate another capture. RPyC remains optional.

Process monitoring

Each visible top-level window has its own capture and change history. Owned popups are discovered and captured separately at their full size; their pixels are never composited onto the owner's screenshot. Child controls remain part of their window.

from pathlib import Path
import time
from window_capture import ChangeOptions, WindowMonitor, Target

output = Path("captures")
output.mkdir(exist_ok=True)
with WindowMonitor(
    Target(process_name="viewer.exe"),
    changes=ChangeOptions(channel_tolerance=3, min_changed_pixels=1),
) as monitor:
    while True:
        started = time.monotonic()
        for event in monitor.poll():
            if event.image is not None:
                handle = event.window.hwnd or event.window.x11_window_id
                event.image.save(output / f"{handle}-{event.result.request_id}.png")
            elif event.result is not None:
                print(event.kind, event.result.reason)
        time.sleep(max(0, 5 - (time.monotonic() - started)))

poll() returns opened, changed, geometry_changed, disappeared, capture_failed, and capture_recovered events. Repeated failures with the same reason are suppressed, while capture retries continue every poll. A changed reason emits another failure. Recovery emits metadata even when pixels are unchanged; event.image is None for recovery events. Changed images are delivered separately. See revision ten. An absent process produces no images; a newly visible popup gets its own opened event. Disappearance includes hiding and no longer matching the selector. Failed captures expose no image and preserve the last good baseline. Failed discovery raises CaptureError and preserves the previous window set.

Comparison uses decoded RGBA pixels, independent of PNG compression. A pixel counts as changed when any channel differs by more than 3 on the 0–255 scale. The default reports even one such pixel to preserve small text and indicators. Increase min_changed_pixels to suppress isolated speckles, accepting that equally small real changes will also be ignored. Comparisons use the last reported image, so cumulative drift is detected. Use poll(sink=...) to commit comparison history only after successful batch saving. It does not use a whole-image percentage rule.

Default monitoring enforces source_isolated acquisition and returns per-window capture failures instead of raising them. Controlled desktop mode explicitly permits observed-clear desktop captures. Each window receives its own capture deadline; a full poll also includes discovery and comparison. The caller schedules polls and file writes. Defaults limit discovery to 64 windows and retained RGBA baselines to 128 MiB; transient captures, decoding buffers and caller-held images require additional memory. Wayland portals do not provide this process-enumeration API.

WGC can refuse a popup that Windows does not expose as a capturable item, including the non-Alt+Tab popup in our Server 2022 fixture. The default monitor then tries PrintWindow for that popup. A GPU-rendered popup that neither route can capture remains an explicit failure; the engine cannot promise coverage of every renderer.

Capture routes

Platform Implemented routes Capability boundaries
Modern Windows Windows Graphics Capture, PrintWindow, DXGI Desktop Duplication, GDI desktop WGC isolates a window surface and supports cursor/alpha options. DXGI and GDI require permitted desktop control and report observed visibility.
Windows 7 SP1 build target PrintWindow and GDI desktop, separate x86/x64 helpers Modern WinRT/DXGI capture imports are excluded. Physical Windows 7 runtime and GPU qualification remain release gates.
Linux X11 Composite named pixmap and controlled root-desktop capture Local X11, opaque SDR TrueColor; client and child content. Reparented window-manager decorations are refused for whole-window capture.
Linux Wayland Explicit portal window selection and a persistent PipeWire stream Requires the packaged portal helper, system PipeWire and a ScreenCast portal. Complete selected window, hidden cursor, opaque BGRx; permission is prepared separately.

Windows supports HWND/PID, executable name/path, class and title selectors. X11 supports XID/PID, executable name/path, class and title selectors where local process identity can be established. Wayland uses a source selected by the user:

from window_capture import CaptureSession, Target

with CaptureSession() as session:
    source = session.select_window()  # interactive; separate from capture's deadline
    result = session.capture(Target(portal_source=source))

Prepared sources belong to that session and native process. Closure, worker death, idle expiry or stream loss invalidates a source; capture never silently reconnects or opens another selection dialog. select_window(timeout_ms=...) can bound the interaction. prepare() probes capabilities and warms the coordinator process; individual Windows acquisition processes still create fresh devices/frame pools.

Evidence and safety

CAPTURED means the candidate met the requested policy and required restoration completed. source_isolated describes acquisition scope; it is not independent pixel verification. Desktop routes report at most no_overlap_observed, because window events and geometry checks cannot atomically lock out unrelated programs. Suspicious uniform regions produce INDETERMINATE, including legitimate content that a generic capture engine cannot explain. Rejected pixels are never exposed as an accepted image.

The implementation separates configuration, IPC, process ownership, selection, mutation, pixel acquisition, validation and encoding. Resources have scoped owners; OS-specific unsafe code stays in native boundary modules. Pull-based diagnostic events have bounded capacity and overflow counts, with no user callbacks in the request path and no screenshots in diagnostic events or object representations. Process-monitor events deliberately expose accepted new/changed images to callers.

Capture admission currently serializes native acquisitions. Windows scopes it to the session/window station/desktop. Linux conservatively shares one local-host scope across X11, XWayland and Wayland, so environment aliases cannot create competing leases. Cross-account access fails unless a shared service is supplied; remote X11 capture is not coordinated by this package.

Unconfirmed mutation or restoration leaves a durable journal and quarantines new captures. An abandoned OS lock or elapsed timeout does not clear it. See recovery and limitations before operating a quarantined desktop.

Wheels and development

End-user installation needs no Rust, Cargo, C/C++ compiler or first-use downloads:

python -m pip install --no-index --find-links=dist --only-binary=:all: window-grabber
window-grabber --probe

Each Windows wheel includes architecture-matched modern and legacy executables; the Python facade selects the legacy binary on pre-Windows-10 systems. Linux wheels include separate X11 and optional portal executables, so absent PipeWire libraries do not prevent the X11 helper from starting. The current Linux CI build baseline is Ubuntu 24.04 x86_64; these are Linux platform wheels, not a claim of compatibility with every glibc baseline. PipeWire's shared library is an explicit system runtime dependency for the portal helper.

Maintainer builds use the pinned toolchains and Cargo.lock. The complete combined wheel commands live in .github/workflows/tests.yml. For local logic checks:

cargo test --locked --workspace
cargo fmt --all --check
cargo clippy --locked --workspace --all-targets -- -D warnings
python -m ruff check src tests scripts setup.py
python -m ruff format --check src tests scripts setup.py
PYTHONPATH=src python -m pytest tests -m "not windows and not linux"

CI tests installed wheels outside the source tree, with offline installation and Windows build tools removed from PATH. The desktop tests compare every pixel of independent GDI/child/OpenGL fixtures, test fallback/timeouts and concurrency, and verify restoration. Xvfb exercises installed X11 routes. Portal unit tests and installed-helper startup checks do not establish compositor interoperability.

Production qualification

Version 0.1.0 is the first production release of the documented capture routes. Unsupported operations continue to return explicit outcomes. Hosted CI does not establish physical Windows 7 GPU support, HDR/alpha accuracy, real compositor behavior, antivirus compatibility, or the proposed 99.5% success-within-two-seconds gate. Group movement of visible popups, Vulkan hooks and generic application adapters remain unavailable. No automatic privilege escalation or endpoint-policy changes are performed. Releases publish precompiled Windows wheels to PyPI; source distributions are disabled.

Opt-in renderer hooks

The experimental renderer_hook backend attaches to already-running, matching x86/x64 processes. It supports OpenGL 1.x/2.x compatibility contexts with a static executable SwapBuffers import, Direct3D 9 primary Present, and Direct3D 11 DXGI Present/Present1, plus experimental Direct3D 12 readback using a queue observed inside DXGI presentation. Each captures one client surface; select popups separately by HWND. Direct3D formats and state are deliberately restricted, including no MSAA. Direct3D 11 requires existing multithread protection and rejects partial updates. Direct3D 12 requires D3D11On12, IDXGISwapChain3 and an unambiguous observed queue; it does not guess from unrelated submissions. Vulkan readback remains unsupported.

result = capture(
    Target(hwnd=hwnd),
    options=CaptureOptions(
        allow_injection=True,
        backend_order=("renderer_hook", "print_window_full", "print_window"),
        content=ContentOptions(area="client", include_children=False),
    ),
)

The precompiled DLL is packaged with the Windows wheel. The hook is never enabled by a preset. It remains loaded and its presentation interception remains installed until the target exits, but readback requires an active request. Readback executes on the target's render thread and can stall it; the caller deadline cannot preempt that driver call. Hook errors are recorded without assuming antivirus caused them. An exclusion for Python does not establish that the DLL is permitted.

See revision sixteen for the compatibility limits, lifetime rules and tests. Hardware GPU and Windows 7 runtime qualification remain outstanding.

Use the qualification guide to measure required deployments. The runner separates failures from accepted latency and requires an independent reference to pass a scenario. Exact commit results are recorded in GitHub Actions.

Revision five defines separate-window capture and process monitoring, superseding earlier popup-composition behavior. Revision four records the underlying implementation; revision two retains the remaining intended contract and production gates. Earlier proposals remain history.

Scheduled process recording

python -m window_capture --monitor --process-name example.exe --interval-seconds 5 --output captures

Each popup is saved independently. Complete batch-* directories contain PNGs and a manifest; incomplete pending-* directories are not recordings. A failed save does not advance comparison baselines. The interval is a wait after each finished poll. Restarting records fresh baselines, so duplicate images are possible. The default 1 GiB limit covers new output per recorder instance; arrange archive retention separately. See revision six for API usage, code-review scope, GPU evidence and remaining production gates.

Crowded desktops and popup foreground capture

Enable DesktopOptions(enabled=True, separate_owned_popups=True, resize_to_fit=True) to permit temporary parent resizing when popups cannot be moved aside, and to raise an owned popup independently for its own screenshot. The complete owner group is journaled and restored. Resizing can change layout and hide content. The monitor reports different image dimensions as geometry_changed, with a fresh baseline, rather than treating them as pixel content changes.

CLI: --desktop --separate-owned-popups --resize-to-fit. See design revision eight.

External VM screenshots after a capture failure

A Windows monitor event offers an explicit desktop transaction:

if event.result is not None and not event.result.accepted:
    with event.bring_to_top(max_hold_ms=10000) as presented:
        # Your own vCenter client call; obtain a fresh VM screenshot here.
        screenshot = take_vm_screenshot()
    # Only publish after exit confirms restoration and observation checks.
    save_vm_screenshot(screenshot, guest_bounds=presented.bounds)

take_vm_screenshot and save_vm_screenshot are caller-provided functions. The context manager uses the event's complete window identity, separates owned popups, temporarily makes the target topmost, and restores journaled state. It holds the same desktop lock as normal captures. allow_resize=True explicitly permits layout changes when needed. A custom coordinator must match the monitor's configuration. This operation explicitly permits desktop changes even when the monitor uses isolated mode.

The hold limit is 100–60000 ms; setup and restoration have separate bounded budgets. Context exit, caller-pipe closure, and native hold expiry initiate restoration. A crashed/hung native transaction can leave a recovery journal and quarantine; restoration errors are raised, never silently treated as success. Expiry or observed window changes also raise, even if restoration completed.

presented.bounds uses guest desktop pixels. Map these to the vCenter image using its resolution/display arrangement; do not assume a multi-monitor VM screenshot shares that origin. Success reports observation and restoration, not external image freshness, completeness, or atomic freedom from overlap. The external image never changes the monitor baseline or automatically marks capture as recovered.

With RPyC, call bring_to_top() on the remote event and keep the context open while the local caller requests the vCenter screenshot. The native hold timer remains active if that connection is lost. Full vCenter/RPyC integration is not qualified.

Capture fallback and confidence

The default Windows order is WGC, print_window_full, print_window, desktop DXGI, then desktop GDI. The default attempt limit is five; caller limits and the single shared deadline still apply. Desktop backends are eligible only when the selected policy permits them. Full-content PrintWindow uses PW_RENDERFULLCONTENT on Windows 8.1 or newer; ordinary PrintWindow remains a separate fallback. Neither method is a universal GPU-content guarantee.

WGC uses cursor control when the interface exists. Older WGC can retain its default cursor inclusion when requested, but cannot satisfy cursor exclusion; that produces CURSOR_CONTROL_UNAVAILABLE. The recommended mode therefore uses Windows 10 2004 as its boundary for default cursor-free capture.

Suspicious uniform regions trigger fallback. If later attempts also fail, the suspicious result is preserved as CONTENT_UNCERTAIN, with the attempt history and an optional diagnostic candidate image. The cause remains unknown; matching black outputs do not prove that the application intended black content. Restoration failures remain authoritative. content_evidence describes checks and suspicious regions; completeness="not_established" explicitly distinguishes these checks from proof that all application content was rendered. pixel_assurance="checked" means the configured checks ran, not reference-image verification.

Monitor baselines retain their backend and occlusion evidence. A change in capture source emits capture_source_changed with an image and starts a new baseline, even if pixels are identical. Geometry changes retain their existing event type. An uncertain result never replaces either baseline pixels or baseline source.

Release automation

Merges to main run final tests, create a version tag and GitHub release, then publish the tested Windows wheels to PyPI. See the release guide for version bumps, Trusted Publisher setup, Linux distribution, and failed-job retries.

Inspecting windows

Use the existing find_windows() API with or without a Target:

from window_capture import DiscoveryOptions, find_windows, Target

windows = find_windows(best_effort=True)  # visible top-level windows
app_windows = find_windows(
    Target(pid=1234),
    discovery=DiscoveryOptions(include_children=True, include_hidden=True),
)
for window in app_windows:
    print(window.hwnd, window.kind, window.process_path)

On Windows, each fully inspected record contains the existing stable identity (HWND, PID, TID, process creation time, class, root and owner), plus title, process_name, process_path, parent_hwnd, bounds, visible, minimized, maximized, foreground, cloaked, is_child, is_popup, and kind. kind is a structural classification: child, dialog (class #32770), owned popup, or top-level. It does not identify an application's semantic UI role. foreground means the foreground HWND; visibility does not establish that a window is unobscured or capturable. Enumeration covers the caller's desktop, not other sessions, secure desktops, or message-only windows.

DiscoveryOptions.include_children also searches descendants of enumerated top-level windows. For an explicit HWND, inspection remains limited to that HWND. An explicit HWND can be inspected even when hidden. include_hidden, disabling include_minimized, and best_effort currently require Windows; Linux X11 retains its existing identity records and strict selection. Wayland does not provide general desktop window enumeration.

Optional fields may be null with a reason in inspection_errors; for example, cloaking information is unavailable on Windows 7. Strict discovery is the default. With best_effort=True, inaccessible or disappearing candidates can instead produce a partial record containing hwnd, inspection_error, and matches_filter=None. Such records are not confirmed matches: missing identity or process data must never be treated as proof of unique selection. Deadlines and enumeration/response limits still fail the call, rather than silently returning a truncated inventory. All returned records are immutable.

Window state is sampled, not an atomic desktop snapshot. A window can disappear immediately after discovery; capture independently resolves and revalidates its target. Discovery does not activate, move, resize, or capture windows.

Window context in capture events

On Windows, CaptureResult.window contains the same description sampled after unique target resolution, before any capture-related desktop changes. It is also available on CaptureEvent.window, including capture failures after resolution. If inspection detects a changed identity, optional sampled fields are discarded and inspection_errors.identity reports TARGET_CHANGED. This context does not replace identity_evidence or prove capture succeeded.

result.requested_target and event.requested_target retain the requested selectors even when no window could be resolved or the worker failed. In that case window is None. Portal tokens are excluded. Discovery, capture and monitor events include titles and full process paths whenever readable. Window details and requested selectors are omitted from object representations and can be marked {"truncated": True} to preserve the metadata budget. Events retain metadata only, without images.

Poll every window, capture selected windows

WindowMonitor separates discovery from capture through capture_when. Omit the target to poll all visible top-level windows, or supply the usual process selectors to narrow discovery:

from window_capture import DiscoveryOptions, WindowMonitor

with WindowMonitor(
    discovery=DiscoveryOptions(include_hidden=True, include_children=True),
    max_windows=512,
    capture_when=lambda window: (window.process_name or "").lower() == "myapp.exe",
) as monitor:
    for event in monitor.poll():  # schedule subsequent polls in your application
        print(event.kind, event.window.hwnd, event.window.pid)
        if event.image is not None:
            event.image.save("capture-{}.png".format(event.window.hwnd))

The predicate receives an immutable window description and must return bool. It runs once per discovered window per poll, on the caller's thread. All decisions are evaluated before any capture starts; an exception or invalid return leaves history unchanged and starts no captures. Predicate execution is outside native capture deadlines. Title/path-based predicates receive readable metadata automatically.

A False decision performs no pixel acquisition for that window. It still emits opened, metadata_changed, and disappeared events with result=None and image=None. Unchanged windows produce no repeated event. Switching from capture to observation emits capture_skipped and releases that window's pixel baseline; selecting it again starts a fresh baseline. Predicate decisions and observation history commit only after the sink succeeds, matching the existing retry contract.

max_windows bounds all discovered windows, including those excluded from capture. Discovery remains strict: an unreadable candidate can fail the poll even if your predicate would have excluded it. This avoids false disappearance events from an incomplete inventory. For ad hoc inspection that tolerates partial records, use find_windows(best_effort=True).

Minimized windows and owned popups are already included in Windows top-level inventory when their visible flag is set. include_minimized=True is the default; set it to False to exclude minimized windows. include_hidden=True includes windows whose visible flag is unset, and include_children=True includes nested controls/rendering windows. These same DiscoveryOptions apply to find_windows() and WindowMonitor. Observing a minimized or hidden window does not establish that a requested capture backend can acquire its pixels.

WindowMonitor accepts any native Target selector, a sequence of selectors, or no selector. ProcessMonitor remains an alias for existing callers; new code can use the clearer WindowMonitor name. Capture options still control how pixels are acquired; discovery options only control which windows are observed.

Typed windows, events, and images

find_windows() returns immutable Pydantic Window models. WindowEvent, CaptureEvent, CaptureResult, CapturedImage, CapabilityReport, and CloseReport are Pydantic models too. Use attributes such as window.pid, window.process_path, and window.bounds.left; unknown or unreadable window fields are None. Constructors use named arguments. .schema() exposes types and field descriptions; .dict() and .json() serialize models. Image bytes are excluded from model serialization and object representations. Window.metadata() serializes supplied fields only, preserving omitted fields.

For example, choose specific executables and save only available screenshots:

from window_capture import WindowMonitor

paths = {r"C:\Apps\First.exe", r"C:\Apps\Second.exe"}
with WindowMonitor(
    capture_when=lambda window: window.process_path in paths,
) as monitor:
    for event in monitor.poll():
        if event.image is not None:
            event.image.save("capture-{}.png".format(event.window.hwnd))
        else:
            print(event.kind, event.window.pid)

Membership above compares exact strings; normalize spelling/case explicitly if that is your desired policy. Target(process_path=...) remains the native file-identity selector when aliases/junctions must resolve to the same file.

event.require_image().save("capture.png") is the explicit alternative when an image is required. It returns the existing screenshot and never starts another capture. It raises CaptureNotRequested when event.result is None, CaptureError (with .result) when capture failed, or ImageUnavailable for a metadata-only recovery notification. Merely polling an excluded window raises nothing; event.image is None. The metadata-only CaptureEvents buffer does not retain images; use WindowMonitor image events or the returned CaptureResult.

Models use Pydantic's v1-compatible API (also provided by Pydantic 2). Python 3.8 installations require Pydantic 1.x, avoiding the newer pydantic-core binary's Windows 7 import incompatibility. Options such as Target, DiscoveryOptions, and CaptureOptions remain immutable dataclasses. Model updates are revalidated by the library; Pydantic's ordinary copy(update=...) is not a validation boundary.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

window_grabber-0.2.0-py3-none-win_amd64.whl (2.6 MB view details)

Uploaded Python 3Windows x86-64

window_grabber-0.2.0-py3-none-win32.whl (2.4 MB view details)

Uploaded Python 3Windows x86

File details

Details for the file window_grabber-0.2.0-py3-none-win_amd64.whl.

File metadata

File hashes

Hashes for window_grabber-0.2.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 1b9aaefd3a32b172e88bd8ef8a8dc146105282f55758d0cbc4dd7aad95a4b63c
MD5 e54bbcf7475ae536b442718687eca0c1
BLAKE2b-256 96ca4054a688c6359932828575773c48819f889946d2d0dd84e1c3556571f43f

See more details on using hashes here.

Provenance

The following attestation bundles were made for window_grabber-0.2.0-py3-none-win_amd64.whl:

Publisher: release.yml on Heknon/window-grabber

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file window_grabber-0.2.0-py3-none-win32.whl.

File metadata

  • Download URL: window_grabber-0.2.0-py3-none-win32.whl
  • Upload date:
  • Size: 2.4 MB
  • Tags: Python 3, Windows x86
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for window_grabber-0.2.0-py3-none-win32.whl
Algorithm Hash digest
SHA256 f79bbd6dfd3d5fb35e6843b22fbe3116bf9330b228452f793b5766cc6d2860cb
MD5 6328c0cae8a85862bfe615deaad7c2e7
BLAKE2b-256 7778ae9e3cd5fc4b04b78afea5f9cffe08115a47567a372d477b123b20fa1529

See more details on using hashes here.

Provenance

The following attestation bundles were made for window_grabber-0.2.0-py3-none-win32.whl:

Publisher: release.yml on Heknon/window-grabber

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.2.3

2 files

0.2.2

2 files

0.2.1

2 files

This release

0.2.0 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page