CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pyglet

Cross-platform windowing and multimedia library for Python with OpenGL graphics, event handling, and audio/video playback

Overview
Eval results
Files

windowing.mddocs/

Windowing and Display

Cross-platform window creation, management, and event handling.

Window Class

class pyglet.window.Window:
    """Platform-independent application window with OpenGL context"""

    __init__(width=None, height=None, caption=None, resizable=False,
             style=WINDOW_STYLE_DEFAULT, fullscreen=False, visible=True,
             vsync=True, display=None, screen=None, config=None, context=None,
             mode=None, file_drops=False)

Properties

PropertyTypeDescription
captionstrWindow title
width, heightintWindow dimensions (pixels)
resizableboolCan be resized by user
fullscreenboolFullscreen mode
visibleboolWindow visibility
vsyncboolVertical sync
displayDisplayDisplay device (read-only)
contextContextOpenGL context (read-only)
configConfigOpenGL config (read-only)
screenScreenScreen for fullscreen (read-only)
scalefloatDPI scale factor (read-only)
dpiintDPI value (read-only)
sizetuple(width, height) (read-only)
aspect_ratiofloatwidth/height (read-only)
projectionMat4Projection matrix (read-only)
viewMat4View matrix (read-only)
viewporttuple(x, y, width, height) (read-only)
invalidboolNeeds redraw flag

Core Methods

# Window control
def close()
def switch_to()  # Make GL context current
def flip()  # Swap buffers
def clear()  # Clear with background
def draw(dt)  # Full draw cycle (switch_to + on_draw + on_refresh + flip)

# Configuration
def set_caption(caption: str)
def set_size(width: int, height: int)
def set_location(x: int, y: int)
def get_size() -> tuple  # (width, height)
def get_location() -> tuple  # (x, y)
def get_framebuffer_size() -> tuple  # HiDPI may differ from window size
def get_pixel_ratio() -> float  # framebuffer/window size ratio
def set_minimum_size(width: int, height: int)
def set_maximum_size(width: int, height: int)
def set_visible(visible: bool = True)
def set_fullscreen(fullscreen: bool = True, screen=None, mode=None, width=None, height=None)
def minimize()
def maximize()
def activate()  # Bring to foreground

# Display settings
def set_vsync(vsync: bool)
def set_icon(*images)  # Set window icon

# Mouse
def set_mouse_visible(visible: bool = True)
def set_mouse_cursor(cursor=None)  # None for default
def get_system_mouse_cursor(name: str) -> MouseCursor
def set_mouse_platform_visible(platform_visible=None)
def set_mouse_passthrough(state: bool)  # Click-through window
def set_exclusive_mouse(exclusive: bool = True)  # Hide and constrain

# Keyboard
def set_exclusive_keyboard(exclusive: bool = True)  # Capture shortcuts

# Clipboard
def get_clipboard_text() -> str
def set_clipboard_text(text: str)

# Events
def dispatch_events()  # For custom event loops (use pyglet.app.run() instead)
def push_handlers(*args, **kwargs)
def pop_handlers()
def remove_handlers(*args, **kwargs)
def set_handler(name: str, handler: callable)
def set_handlers(*args, **kwargs)
def remove_handler(name: str, handler: callable)

Window Events

Register with @window.event decorator or window.push_handlers():

EventSignatureDescription
on_activate()Window gained focus
on_close()Close requested (return False to prevent)
on_context_lost()OpenGL context lost
on_context_state_lost()OpenGL state lost
on_deactivate()Window lost focus
on_draw()Window needs redraw
on_expose()Window uncovered
on_hide()Window hidden
on_show()Window shown
on_move(x: int, y: int)Window moved
on_resize(width: int, height: int)Window resized
on_refresh(dt: float)Window refreshed (after on_draw)
on_scale(scale: float, dpi: int)DPI changed
on_key_press(symbol: int, modifiers: int)Key pressed
on_key_release(symbol: int, modifiers: int)Key released
on_text(text: str)Unicode text entered
on_text_motion(motion: int)Text cursor motion
on_text_motion_select(motion: int)Text cursor motion with selection
on_mouse_enter(x: int, y: int)Mouse entered window
on_mouse_leave(x: int, y: int)Mouse left window
on_mouse_motion(x: int, y: int, dx: int, dy: int)Mouse moved
on_mouse_drag(x: int, y: int, dx: int, dy: int, buttons: int, modifiers: int)Mouse dragged
on_mouse_press(x: int, y: int, button: int, modifiers: int)Mouse button pressed
on_mouse_release(x: int, y: int, button: int, modifiers: int)Mouse button released
on_mouse_scroll(x: int, y: int, scroll_x: float, scroll_y: float)Mouse wheel scrolled
on_file_drop(x: int, y: int, paths: list)Files dropped (requires file_drops=True)

Display & Screen

# Get display
display = pyglet.display.get_display(name=None)  # None for default
screens = display.get_screens()  # list of Screen
default_screen = display.get_default_screen()
windows = display.get_windows()  # list of Window

# Screen properties
screen.x, screen.y  # Position
screen.width, screen.height  # Dimensions
screen.xdpi, screen.ydpi  # DPI

# Screen methods
modes = screen.get_modes()  # Available ScreenMode objects
mode = screen.get_mode()  # Current mode
screen.set_mode(mode)
screen.restore_mode()
dpi = screen.get_dpi()
scale = screen.get_scale()  # 1.0 standard, 2.0 for 2x scaling
display_id = screen.get_display_id()
name = screen.get_monitor_name()

# ScreenMode properties
mode.width, mode.height  # Resolution
mode.depth  # Color depth (bits)
mode.rate  # Refresh rate (Hz)

Input State Tracking

from pyglet.window import key, mouse

# Keyboard state
keys = key.KeyStateHandler()
window.push_handlers(keys)
if keys[key.LEFT]:  # Check if key is pressed
    # Move left

# Mouse state
buttons = mouse.MouseStateHandler()
window.push_handlers(buttons)
if buttons[mouse.LEFT]:  # Check if button is pressed
    # Handle mouse button

FPS Display

class pyglet.window.FPSDisplay:
    """Frame rate counter display"""

    __init__(window, color=(127,127,127,127), samples=240)

    update_period: float = 0.25  # Update frequency
    label: pyglet.text.Label  # Display label

    def update()  # Update FPS (called automatically)
    def draw()  # Draw counter

# Usage
fps_display = pyglet.window.FPSDisplay(window)

@window.event
def on_draw():
    window.clear()
    # ... draw game
    fps_display.draw()

Window Styles

pyglet.window.WINDOW_STYLE_DEFAULT  # Standard with title bar
pyglet.window.WINDOW_STYLE_DIALOG  # Dialog style
pyglet.window.WINDOW_STYLE_TOOL  # Tool window
pyglet.window.WINDOW_STYLE_BORDERLESS  # No borders
pyglet.window.WINDOW_STYLE_TRANSPARENT  # Transparent, interactable
pyglet.window.WINDOW_STYLE_OVERLAY  # Transparent, topmost, click-through

Mouse Cursors

# System cursors
cursor = window.get_system_mouse_cursor(name)
window.set_mouse_cursor(cursor)

# Cursor constants
CURSOR_DEFAULT, CURSOR_CROSSHAIR, CURSOR_HAND, CURSOR_HELP, CURSOR_NO,
CURSOR_SIZE, CURSOR_SIZE_UP, CURSOR_SIZE_UP_RIGHT, CURSOR_SIZE_RIGHT,
CURSOR_SIZE_DOWN_RIGHT, CURSOR_SIZE_DOWN, CURSOR_SIZE_DOWN_LEFT,
CURSOR_SIZE_LEFT, CURSOR_SIZE_UP_LEFT, CURSOR_SIZE_UP_DOWN,
CURSOR_SIZE_LEFT_RIGHT, CURSOR_TEXT, CURSOR_WAIT, CURSOR_WAIT_ARROW

# Custom cursor
from pyglet.window import ImageMouseCursor
image = pyglet.image.load('cursor.png')
cursor = ImageMouseCursor(image, hot_x=0, hot_y=0)
window.set_mouse_cursor(cursor)

Keyboard Constants

from pyglet.window import key

# Letters: key.A through key.Z
# Numbers: key._0 through key._9 (top row)
# Numpad: key.NUM_0 through key.NUM_9
# Function: key.F1 through key.F24

# Special keys
key.ENTER, key.ESCAPE, key.SPACE, key.TAB, key.BACKSPACE, key.DELETE,
key.INSERT, key.HOME, key.END, key.PAGEUP, key.PAGEDOWN

# Arrows
key.LEFT, key.RIGHT, key.UP, key.DOWN

# Modifiers (bitwise flags for checking)
key.MOD_SHIFT, key.MOD_CTRL, key.MOD_ALT, key.MOD_CAPSLOCK,
key.MOD_NUMLOCK, key.MOD_SCROLLLOCK, key.MOD_COMMAND, key.MOD_OPTION,
key.MOD_WINDOWS, key.MOD_FUNCTION
key.MOD_ACCEL  # Ctrl on Windows/Linux, Command on macOS

# Text motion constants (for on_text_motion events)
key.MOTION_UP, key.MOTION_DOWN, key.MOTION_LEFT, key.MOTION_RIGHT,
key.MOTION_NEXT_WORD, key.MOTION_PREVIOUS_WORD,
key.MOTION_BEGINNING_OF_LINE, key.MOTION_END_OF_LINE,
key.MOTION_NEXT_PAGE, key.MOTION_PREVIOUS_PAGE,
key.MOTION_BEGINNING_OF_FILE, key.MOTION_END_OF_FILE,
key.MOTION_BACKSPACE, key.MOTION_DELETE,
key.MOTION_COPY, key.MOTION_PASTE

# Utility functions
key.symbol_string(symbol) -> str  # Get key name
key.modifiers_string(modifiers) -> str  # Get modifier names
key.motion_string(motion) -> str  # Get motion name
key.user_key(scancode) -> int  # Platform-specific key mapping

Mouse Constants

from pyglet.window import mouse

# Buttons
mouse.LEFT, mouse.MIDDLE, mouse.RIGHT, mouse.MOUSE4, mouse.MOUSE5

# Utility
mouse.buttons_string(buttons) -> str  # Get button names

Event Logger (Debugging)

from pyglet.window.event import WindowEventLogger

window = pyglet.window.Window()
logger = WindowEventLogger()  # Logs to stdout by default
window.push_handlers(logger)

# Or log to file
with open('events.log', 'w') as f:
    logger = WindowEventLogger(f)
    window.push_handlers(logger)

Common Patterns

Basic Window

window = pyglet.window.Window(800, 600, 'My App')

@window.event
def on_draw():
    window.clear()

pyglet.app.run()

Fullscreen Toggle

@window.event
def on_key_press(symbol, modifiers):
    if symbol == key.F and modifiers & key.MOD_CTRL:
        window.set_fullscreen(not window.fullscreen)
    elif symbol == key.ESCAPE:
        if window.fullscreen:
            window.set_fullscreen(False)
        else:
            pyglet.app.exit()

Multi-Monitor

display = pyglet.display.get_display()
screens = display.get_screens()
print(f"Found {len(screens)} screens")
for i, screen in enumerate(screens):
    print(f"Screen {i}: {screen.width}x{screen.height} @ ({screen.x},{screen.y})")

# Create window on specific screen
window = pyglet.window.Window(screen=screens[1])

Resizable Window with Aspect Ratio

window = pyglet.window.Window(800, 600, resizable=True)

@window.event
def on_resize(width, height):
    # Maintain 4:3 aspect ratio
    target_aspect = 4/3
    current_aspect = width/height
    if current_aspect > target_aspect:
        # Too wide
        new_width = int(height * target_aspect)
        window.set_size(new_width, height)
    elif current_aspect < target_aspect:
        # Too tall
        new_height = int(width / target_aspect)
        window.set_size(width, new_height)

Custom Cursor

# Hide system cursor and draw custom
window.set_mouse_visible(False)
cursor_sprite = pyglet.sprite.Sprite(cursor_img)

@window.event
def on_mouse_motion(x, y, dx, dy):
    cursor_sprite.position = (x, y)

@window.event
def on_draw():
    window.clear()
    # ... draw game
    cursor_sprite.draw()

Exclusive Mouse (FPS-style)

window.set_exclusive_mouse(True)

@window.event
def on_mouse_motion(x, y, dx, dy):
    # dx/dy are relative motion
    camera.rotate(dx * sensitivity, dy * sensitivity)

@window.event
def on_key_press(symbol, modifiers):
    if symbol == key.ESCAPE:
        window.set_exclusive_mouse(False)

Exceptions

class pyglet.window.WindowException(Exception):
    """Base window exception"""

class pyglet.window.NoSuchDisplayException(WindowException):
    """Display not found"""

class pyglet.window.NoSuchConfigException(WindowException):
    """OpenGL config not found"""

class pyglet.window.NoSuchScreenModeException(WindowException):
    """Screen mode cannot be set"""

class pyglet.window.MouseCursorException(WindowException):
    """Mouse cursor error"""

Performance Notes

  • Use vsync=True to limit frame rate to monitor refresh (default)
  • window.invalid flag controls when window needs redraw (batch operations)
  • Minimize window resizing operations (expensive)
  • Use on_refresh event for post-draw effects (dt parameter available)
  • HiDPI: Use get_framebuffer_size() for actual pixel count

Install with Tessl CLI

npx tessl i tessl/pypi-pyglet

docs

3d-models.md

app-clock.md

audio-video.md

graphics-rendering.md

gui.md

images-textures.md

index.md

input-devices.md

math.md

opengl.md

resource-management.md

sprites-shapes.md

text-rendering.md

windowing.md

tile.json