:py:mod:`pixel_forge`
=====================

.. py:module:: pixel_forge


Module Contents
---------------

Classes
~~~~~~~

.. autoapisummary::

   pixel_forge.Window
   pixel_forge.Monitor
   pixel_forge.Capture



Functions
~~~~~~~~~

.. autoapisummary::

   pixel_forge.enumerate_windows
   pixel_forge.foreground_window
   pixel_forge.primary_monitor
   pixel_forge.enumerate_monitors



.. py:function:: enumerate_windows() -> list[Window]

   Create a list of all windows that are currently available.

   :returns: The list of all windows.

   :raises RuntimeError: If the window enumeration fails.


.. py:function:: foreground_window() -> Window

   Get the current foreground window.

   :returns: The foreground window.

   :raises RuntimeError: No foreground window was found.


.. py:class:: Window(name: str)


   Window abstraction for the Windows operating system.

   Windows can be used as capture target for the :class:`.Capture` class.

   .. py:property:: valid
      :type: bool

      True if the window is still valid (i.e., open), else False.

   .. py:property:: name
      :type: str

      The window name.


.. py:function:: primary_monitor() -> Monitor

   Get the primary monitor.

   :returns: The primary monitor.


.. py:function:: enumerate_monitors() -> list[Monitor]

   Create a list of all monitors.

   :returns: The list of all monitors.


.. py:class:: Monitor(id: int | None = None)


   Monitor abstraction the Windows operating system.

   .. py:property:: width
      :type: int

      The monitor pixel width.

   .. py:property:: height
      :type: int

      The monitor pixel height.

   .. py:property:: index
      :type: int

      The monitor index.

   .. py:property:: refresh_rate
      :type: int

      The monitor refresh rate in Hz.

   .. py:property:: device_name
      :type: str

      The monitor device name.

   .. py:property:: device_string
      :type: str

      The monitor device string.


.. py:class:: Capture


   Capture class to capture frames from a monitor or a window.

   The idea is to get either a :class:`.Monitor` or a :class:`.Window` as target, create a Capture
   object, and then start a capture thread that will update the internal frame of the Capture
   object whenever a new frame is available. Frames are only materialized, converted to NumPy
   arrays and passed over to Python when the user requests it to avoid unnecessary copies.

   .. py:property:: active
      :type: bool

      True if the capture thread is running, False otherwise.

   .. py:method:: start(capture_target: Monitor | Window, await_first_frame: bool = True) -> None

      Start the capture.

      This registeres an event handler that automatically updates the latest frame whenever a new
      frame is available. The frame can be accessed using :meth:`frame`. Since the event handler
      runs in a separate thread, the first frame might not be available immediately. To ensure a
      frame is available before continuing, set ``await_first_frame`` to True. This will block the
      main thread until the first frame is available.

      :param capture_target: The monitor or window to capture.
      :param await_first_frame: Waits for the first frame to arrive if True.


   .. py:method:: stop() -> None

      Stop the capture thread, wait for it to join and invalidate the last frame.

      This method is also called automatically when the object is garbage collected.


   .. py:method:: frame() -> numpy.ndarray

      Convert the latest frame to an array and return it.

      :returns: The frame as a 3D NumPy array with dimensions [h w 4] (height x width x RGBA).

      :raises RuntimeError: If the capture thread has not yet picked up a frame.



