Skip to content

Complete macOS compatibility, update to Zig 0.15.2, fix bugs, etc.#121

Open
pmarreck wants to merge 19 commits intocapy-ui:masterfrom
pmarreck:master
Open

Complete macOS compatibility, update to Zig 0.15.2, fix bugs, etc.#121
pmarreck wants to merge 19 commits intocapy-ui:masterfrom
pmarreck:master

Conversation

@pmarreck
Copy link

See what you think. Enjoy. ;) Works on my macOS setup. May need additional alignment refinement, but most of the functionality I've manually tested works.

- Fix flake.nix: replace hardcoded Linux Zig with zig-overlay, add
  conditional platform packages (Linux: GTK/mesa/etc, macOS: AppKit
  frameworks), conditional shellHook for PKG_CONFIG_PATH/LD_LIBRARY_PATH
- Update build.zig.zon: minimum_zig_version to 0.15.2, update zig-objc
  and zigimg dependency hashes
- Build system migration: addExecutable/addTest/addLibrary now use
  .root_module = b.createModule(...) pattern
- Replace all pub usingnamespace with explicit const forwarding across
  all components, backends, and examples (56 forwarded declarations per
  widget from internal.All mixin, 10-12 per backend Events mixin)
- ArrayList migration: .init(allocator) -> .empty, methods now take
  allocator parameter (append, deinit, appendSlice, etc.)
- I/O overhaul: std.io.Reader/Writer -> std.Io.Reader/Writer vtable
  types, readByte->takeByte, readInt->takeInt, readNoEof->readSliceAll
- Replace std.io.StreamSource with zigimg.io.ReadStream
- Type reflection tags: .Pointer->.pointer, .One->.one, .Slice->.slice
- Format string: {} -> {any} for types with format methods
- Remove std.atomic.Value compat shim, rewrite src/async.zig for 0.15
- Add macOS backend stubs for all widget types (TextField, TextArea,
  CheckBox, Slider, ScrollView, Canvas, TabContainer, etc.)
- Add macOS Monitor, Window, AudioGenerator stub methods
- Fix macOS Button.getLabel return type, Canvas DrawContextImpl stubs

103 files changed, 61/61 build steps pass, 65/74 tests pass (9 skipped)
macOS backend (Phase 3):
- Event system: CapyEventView/CapyCanvasView custom NSView subclasses
  with mouse, keyboard, scroll, and resize event handling via ObjC runtime
- Form widgets: TextField (NSTextField), TextArea (NSTextView in
  NSScrollView), CheckBox (NSButton Switch), Slider (NSSlider),
  Dropdown (NSPopUpButton) with real AppKit controls and event wiring
- Canvas: DrawContextImpl backed by CoreGraphics (rectangles, ellipses,
  rounded rects, lines, gradients, text via CoreText)
- Containers: ScrollView (NSScrollView), TabContainer (NSTabView),
  NavigationSidebar (basic NSScrollView)
- Button: wired click events via CapyActionTarget target/action pattern
- Monitor: real NSScreen-based implementation with DPI/scaling support
- Window: default menu bar with Quit/Cmd+Q, setContentSize for correct
  content area sizing, auto-expand to fit content, resize notifications
  via CapyWindowDelegate
- AppKit.zig: added NSEventType, NSTrackingAreaOptions, NSAlertStyle,
  NSButtonType, NSBezelStyle, CoreGraphics/CoreText/CoreFoundation externs

Cross-platform layout fix:
- Added saturatingFloatToU32 to prevent @intFromFloat panics when layout
  computes sizes exceeding u32 range (e.g. during preferred size computation
  with fakeSize returning floatMax)
- Fixed fakeResMove u32 overflow by widening x+w/y+h to u64 before cast
- Fixes runtime panics in demo, entry, and other Row-layout examples
- Update Zig version target from 0.14.1 to 0.15.2
- Change macOS platform status from planned to experimental
- Mark newly implemented macOS widgets as experimental: Canvas,
  CheckBox, Dropdown, NavigationSidebar, Scrollable, Slider, Tabs,
  TextArea, TextField
… crash

- Implement setMenuBar() with NSMenu/NSMenuItem hierarchy and CapyMenuTarget
  ObjC class for dispatching menu item callbacks
- Implement DrawContextImpl.image() using CGContextDrawImage for image rendering
- Fix TextArea.setMonospaced() to restore system font when toggled off
- Fix asset loading crash: toRawMaybeAlloc() result must not be freed (use
  toRaw() with stack buffer instead)
- Fix Image.draw() early return after successful load that prevented rendering
- Update README: macOS Image, Menu, Navigation support status
Replace the skeleton stub with a full canvas-based slide viewer featuring
5 slides with colored backgrounds, Zig logo on the title slide, centered
title/subtitle text, navigation dots, prev/next buttons with proper
enable/disable, slide counter, and fullscreen toggle.
- ImageData.fromFile: verify PNG loads with valid dimensions and stride
- ImageData.fromFile: verify missing file returns FileNotFound
- Asset URI: verify asset:// scheme loads file and reads PNG magic bytes
- Asset URI: verify triple-slash normalization (the fix for SIGABRT crash)
- Asset URI: verify unsupported scheme returns error
- Backend: verify ImageData.from creates image from raw RGBA bytes
- Backend: verify Canvas creation
- Backend: verify TextLayout measures non-empty text with non-zero size
- Backend: verify TextLayout returns zero size for empty string
feat: implement ListAtom.map in src/data.zig

fix: image loading lifetimes - duplicate pixel data and defer deinit

fix: macOS backend - CGContextRelease(ctx) and binding in AppKit.zig

chore: add architecture/docs files (ARCHITECTURE.md, SUMMARY_OF_MASSIVE_PR_CHANGES.md, ZIG_RECENT_API_CHANGES_2025.md)

refactor: fuzz.zig format signatures and deinit compatibility
…and widget-catalog

Add RadioButton component with macOS/GTK/Win32 backends for mutual-exclusive
selection groups. Add slider tick marks and snap-to-ticks across all platforms.

Implement full keyboard navigation on macOS via CapyWindow (NSWindow subclass)
that intercepts key events in sendEvent: to provide Tab/Shift-Tab cycling
through interactive controls, Space/Enter activation, and arrow key adjustment
of focused sliders — all without requiring macOS Full Keyboard Access.

Also includes: window centering on macOS, TextField/TextArea dangling pointer
fixes (NSString UTF8String returns temporary buffer), and a widget-catalog
example app exercising all widget types.
Add cross-platform event simulator (src/event_simulator.zig) that injects
events at the component level by calling handler function pointers directly
on EventUserData, bypassing native event machinery. Supports click, drag,
scroll, keyPress, typeText, and native-level stubs for future implementation.

Add state logger (src/state_logger.zig) that outputs JSON Lines of widget
property changes to stdout/stderr/file via CAPY_UI_STATE_CHANGES_TO env var.
Together these enable a simulate-then-observe testing loop for automated
test verification.

Also exports getEventUserData from GTK backend and src/backend.zig for
cross-platform access to event dispatch internals.
…tion tests

Add keyReleaseHandler to the event handler infrastructure across all
backends (macOS, GTK, Win32, Android, Wasm), the internal plumbing
(Events, Handlers, setupEvents), and the component re-export layer.

Add fireTextChanged() helper to event_simulator for simulating native
text change notifications. Add 3 integration tests that verify the full
native-to-component-to-atom propagation chain:
- TextField text input updates atom via fireTextChanged
- CheckBox click toggles checked atom via simulated click
- addKeyReleaseHandler fires on simulated keyUp

Fix missing addKeyReleaseHandler re-export in TextField component.
…d testing infrastructure

New canvas-based widgets (platform-independent, drawn via DrawContext):
- Divider, ProgressBar, Spinner, SegmentedControl, MenuButton
- Table (virtual scrolling, sorting, row selection)
- AlertDialog, FlyoutPanel, ContextMenu (overlay-based)

Cross-platform file dialog (openFileDialog) with file type filtering:
- macOS: NSOpenPanel with UTType filtering
- GTK: GtkFileDialog (4.10+) / GtkFileChooserNative fallback
- Win32: IFileOpenDialog COM API

Dark mode / semantic color system:
- isDarkMode() detection on macOS/GTK/Win32
- SystemColors module with ~20 semantic color functions
- All 9 canvas widgets use SystemColors for automatic light/dark adaptation
- Win32: dark title bar via DwmSetWindowAttribute

App icon support (-Dicon=path build option):
- Auto-detects assets/icon.png
- macOS: CGImage->NSImage, GTK: icon theme, Win32: CreateIconIndirect

Testing infrastructure (VirtualWindow):
- Widget tree queries, structural hashing, focus tracking
- 32+ new unit tests across all new components

Also: widget-showcase example, overlay utilities, Color.eql(),
suppress Nix CFLAGS warnings in flake.nix
Replace canvas-drawn Table and ProgressBar with native platform controls:
- Table: NSTableView (macOS), GtkTreeView (GTK), SysListView32 (Win32)
- ProgressBar: NSProgressIndicator (macOS), GtkProgressBar (GTK), msctls_progress32 (Win32)

Components conditionally use native peers when available, falling back to
canvas drawing on WASM/Android/GLES. Also fixes widget-showcase to use
native Dropdown instead of canvas MenuButton, and updates file dialog
result display.
…s the autosave name; center by default only if no saved frame is restored
Build system:
- Generate .app bundles on macOS with Info.plist and .icns icon
- ICNS wraps source PNG in ic09 slot (no image processing needed)
- Other platforms continue to install bare binaries

macOS backend fixes:
- requestDraw: dispatch to main thread when called from background
  threads (fixes balls demo animation freezing between interactions)
- Container.resize: propagate size to NSScrollView document view
  with two-phase layout (fixes hacker-news and other scroll content)

Examples:
- calculator: fix 4th column being double width (200px -> 100px)
- hacker-news: rewrite with real HN API data via std.http.Client,
  background fetch thread, stub data fallback for offline use
- Replace 64K occurrences of @import("std").os.windows.WINAPI with .winapi
- Remove 44K occurrences of callconv(.Inline) (removed in Zig 0.15.2)
- Fix std.os.windows.WINAPI references in Capy's win32 backend
- Fix utf8ToUtf16LeWithNull -> utf8ToUtf16LeAllocZ rename
- Fix utf16LeToUtf8ArrayList API change (2 args, not 3)
- Fix WIN32_ERROR comparison (use .NO_ERROR enum value)

Note: win32 backend still has remaining Zig 0.15.2 issues
(ArrayList API, WINDOW_STYLE type changes, missing ImageData, etc.)
…tion

WINDOW_STYLE/WINDOW_EX_STYLE are now packed structs (not enums),
replace _T with L for UNICODE-independent wide strings, fix ArrayList
Managed vs Aligned type mismatch, add postEmptyEvent and setStrokeWidth
stubs, gate ImageData.from on backend support, fix integer/float casts.

All 24 examples now cross-compile to .exe with -Dtarget=x86_64-windows-gnu.
WM_HSCROLL handler treated all messages as scrollbar events. When
lParam != 0 it's from a trackbar child — read position via TBM_GETPOS,
convert to float using stepSize, and fire propertyChangeHandler so
the Slider component's value Atom updates and change listeners fire.
Replace hardcoded fallback sizes (100x50 win32, 100x100 macOS) with
actual content-based measurement. Win32 widgets now measure text via
GetTextExtentPoint32W with proper font selection. macOS falls back to
NSView intrinsicContentSize. Also implements D2D Canvas drawing and
fixes ScrollView child sizing to match visible area.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant