[WIP] feat(ptk): add preliminary Wayland backend implementation - #322
Draft
wineee wants to merge 66 commits into
Draft
[WIP] feat(ptk): add preliminary Wayland backend implementation#322wineee wants to merge 66 commits into
wineee wants to merge 66 commits into
Conversation
BREAKING CHANGE: lcui_app_get_fps -> lcui_get_fps, lcui_app_set_frame_rate_cap -> lcui_set_fps_cap, settings.frame_rate_cap -> settings.fps_cap. lcui_app_init, lcui_app_destroy, lcui_app_process_events removed from public header — use lcui_init, lcui_destroy, lcui_run instead.
Multiple unbounded strcpy() calls in lib/css/src/selector
Introduce ctest_suite_t, ctest_parse_args, ctest_run_suites and CTEST_MAIN macro to standardize test binary entry points. Support --grep / --grep= / --list / --interactive / --help. Add lib/ctest/tests/ for self-tests covering str converters and grep filter logic.
Restructure the test infrastructure with these changes: * Extend libctest with ctest_suite_t, ctest_parse_args, ctest_run_suites and CTEST_MAIN macro to standardize test entry points; support --grep / --grep= / --list / --interactive flags; add ctest-tests for self-tests. * Regroup tests by lib boundary: sink unit tests into lib/<name>/tests/ with <lib>_<topic> entry function names, move fixtures into lib/<name>/tests/fixtures/, rename top-level tests/cases/ to tests/integration/ for cross-lib integration tests. * Add tests/scenes/ for reusable widget tree builders shared by integration cases and visual preview binaries; add tests/previews/ with 4 diagnostic binaries (flex_layout, block_layout, widget_opacity, scrollbar). * Rewrite all describe/equal description strings using 'should ...' style or noun topic names; drop redundant lcui_quit/lcui_main calls from integration cases. * Integrate xmake test via add_tests(\default\) and a shared tests.runnable rule defined in the root xmake.lua; the rule wraps the test binary with drmemory (Windows) or valgrind (Linux) when option memcheck=y. * Drop the lcui-tests aggregation: lcui-tests now contains only integration cases and scenes, not the union of lib tests. Use xmake test to run everything across libs. * Fix .clang-format: InsertNewlineAtEndOfFile -> InsertNewlineAtEOF (correct key for clang-format 16+). * Update AGENTS.md with the new test layout, naming rules, description style and run commands. * Update CI to use xmake test and xmake f --memcheck=y instead of per-lib runs.
Create lib/ui-router/ as a thin UI binding layer between libui and librouter, exposing the router-link and router-view widgets under <ui_router/...>.
* Move src/widgets/router_{link,view}.c and the matching public headers into lib/ui-router/src and lib/ui-router/include.
* Drop include/LCUI/widgets/router_{link,view}.h and the corresponding entries in include/LCUI/widgets.h; src/lcui_widgets.c now pulls registrations from <ui_router.h>.
* Wire libui-router into the root xmake.lua add_includedirs and lcui add_deps chain; libui-router depends on yutil + libui + librouter only.
* tests/integration/test_router.c stays at the integration layer (router widgets exercise text inheritance and other libui internals); only its #include set is updated to use <ui_router.h>.
* Bump CHANGELOG and add bilingual lib/ui-router/README.
Pulls in yutil c91be801 which sets the yutil-tests rundir to scriptdir, fixing the Windows execv error 267 reported by xmake run yutil-tests.
Add actions/cache step covering xmake package and repository directories on both Linux and Windows runners. Cache key is keyed by runner OS, build mode (coverage on Linux, release on Windows) and the hashes of root and examples xmake-requires.lock so coverage and release artifacts do not pollute each other and examples deps share the same cache. Bump actions/checkout to v4 with submodules: recursive (replacing the manual submodule update step), upload-artifact to v4 and download-artifact to v4.
pd_text_delete_ex - Use-after-free: in same-line branch, pd_text_delete_line(end_y) was followed by pd_text_line_set_length / pd_text_update_line_size on the freed line. Now returns immediately after delete_line in that path. - Off-by-one: cross-line merge used j = end_x + 1, dropping one char when end_x is mid-line. Now j = end_x, and the line-tail special case resets end_x to 0 explicitly. - OOB read: prev_line = text->lines[char_y - 1] without bounds check. Now guarded with char_y > 0 ? ... : NULL. - Memory leak: chars in the deleted range were never freed and ownership transfer between lines could double-free on delete_line. pd_text_line_set_length - realloc-grown slots were not zeroed, leaving uninitialized pointer values that could be misread as live pd_char_t *. pd_text_dump - col was not reset when advancing to the next line, so output was truncated at the first line's length. - Did not emit the line-ending characters recorded in line->eol, so multi-line text was concatenated without separators. Helpers - Extract pd_text_line_erase / pd_text_line_move to centralize char ownership transfer; reused in pd_text_merge_line. Tests - Add lib/pandagl/tests/test_text_edit.c with 11 cases covering the original crash scenarios (backspace at last empty line, delete at line end), boundary cases, and dump behavior. Closes lc-soft#270
The previous naming conflated multiple levels of the font model:
pd_font_t actually owned a single typeface resource (FT_Face), while
pd_font_bitmap_t represented a per-glyph bitmap. The pd_font_library_*
prefix was redundant under the pd_font_ namespace and resulted in
verbose call sites (up to 34 chars).
Type renames
- pd_font_t -> pd_font_face_t
- pd_font_bitmap_t -> pd_glyph_bitmap_t
- font_engine_t -> pd_font_engine_t
- struct tags updated to match the typedef names.
API renames (grouped by sub-object)
- Face lifecycle: pd_font_create/destroy -> pd_font_face_create/destroy
- Face registry: pd_font_library_add_font -> pd_font_register
pd_font_library_get_font -> pd_font_get
pd_font_library_get_font_id -> pd_font_get_id
pd_font_library_query -> pd_font_query
pd_font_library_load_file -> pd_font_load_file
pd_font_library_get_font_path-> pd_font_find_path
pd_font_library_get_default_font -> pd_font_get_default
pd_font_library_set_default_font -> pd_font_set_default
pd_font_library_set_font_family_alias
-> pd_font_family_set_alias
pd_font_library_update_font_weight
-> pd_font_replace_weight
pd_font_library_update_font_style
-> pd_font_replace_style
- Parsing helpers: pd_font_library_detect_weight -> pd_font_parse_weight
pd_font_library_detect_style -> pd_font_parse_style
- Glyph rendering: pd_font_library_render_bitmap -> pd_font_render_glyph
pd_canvas_mix_font_bitmap -> pd_canvas_mix_glyph_bitmap
pd_font_bitmap_init/destroy -> pd_glyph_bitmap_init/destroy
- Glyph cache: pd_font_library_add_bitmap -> pd_font_cache_add_bitmap
pd_font_library_get_bitmap -> pd_font_cache_get_bitmap
pd_font_library_init/destroy are kept as the module lifecycle entry
points, matching the FT_Init_FreeType / FT_Done_FreeType convention.
All call sites in lib/pandagl, lib/ui, lib/ui-xml, src/, tests/ and
examples/ are updated accordingly.
The previous bitmap cache was a three-level rbtree keyed by (wchar_t, font_id, size), which had two problems: 1. The wchar_t key collapses Unicode codepoints that map to the same glyph in a given face into separate cache slots, missing real reuse opportunities and bloating memory under text-heavy workloads. 2. There was no upper bound; long-running apps would grow the cache without limit until pd_font_library_destroy. Replace it with a flat hash table keyed by a packed 64-bit (face_id, glyph_index, size) tuple, plus a doubly-linked LRU list for O(1) eviction. - pd_font_engine gets a new get_glyph_index hook; FreeType maps via FT_Get_Char_Index, the in-core engine treats codepoints as identity (no cmap). - pd_font_cache_add_bitmap / pd_font_cache_get_bitmap now resolve the glyph index via the engine before keying the cache, so the same glyph reused across composed sequences hits the same entry. - pd_font_cache_set_capacity / pd_font_cache_count expose the LRU bound (default 8192 entries, 0 = unlimited) for runtime tuning and tests. Shrinking the capacity evicts immediately. - list_t is used with append at tail / evict from head so the yutil tail.prev pointer stays consistent (list_link does not update it). Adds lib/pandagl/tests/test_font_cache.c covering hit identity, size differentiation, unknown-codepoint fallback, and LRU eviction.
Split lib/pandagl/src/text/text.c into four cohesive units backed
by a library-private header:
- text.c : type lifecycle, line storage, geometry,
dirty-rect bookkeeping, top-level update
- text_typeset.c : line breaking, merging, autowrap, alignment
- text_render.c : per-char bitmap refresh and drawing
- text_edit.c : caret, insert/delete/backspace, text I/O
- text_internal.h : library-private cross-file helpers
(not installed)
Drop the 'insert' overload that conflated 'cursor' with 'insertion
point' and align the field/API names with the cursor concept used
in mainstream GUI toolkits:
insert_x, insert_y -> caret.x, caret.y
(new pd_text_caret_t sub-struct)
pd_text_set_insert_position -> pd_text_set_caret
pd_text_set_insert_pixel_position -> pd_text_set_caret_pixel
pd_text_get_insert_pixel_position -> pd_text_get_caret_pixel
pd_text_get_char_pixel_position -> pd_text_get_char_pixel
Make text I/O symmetric and intent-revealing:
pd_text_dump -> pd_text_read
(mirrors pd_text_write)
pd_text_empty -> pd_text_clear
(the previous static helper
is renamed to pd_text_reset_lines)
pd_text_set_typeset_task -> pd_text_request_typeset
Add pd_text_to_wcs(text), which allocates and returns the full
buffer contents including line endings. It complements the
range-based pd_text_read for callers that just want the whole
text as a wide string.
Fix the mulitiline_enabled -> multiline_enabled typo while at it.
All call sites in lib/pandagl, src/widgets and the tests are
updated. test_text_edit.c gains two cases for pd_text_to_wcs
covering full-text round-trip and the empty-text edge case.
- Remove per-lib set_project() calls that overrode the global lcui
project name; xmake show now correctly reports the project as lcui.
- Move per-lib set_version() into the corresponding target() block so
each sub-library keeps an independent version usable for standalone
packaging.
- Add set_default(false) and set_group(examples) to all pandagl
examples so they are no longer picked up by xmake package.
- Rename targets to use dashes for consistency:
pandagl_cairo_example -> pandagl-cairo-example
preview_block_layout -> preview-block-layout
preview_flex_layout -> preview-flex-layout
preview_scrollbar -> preview-scrollbar
preview_widget_opacity -> preview-widget-opacity
- Bump yutil submodule to drop its set_project() call as well.
The %ls format in logger_error went through UCRT's wide-to-multibyte path, which triggered a debug assertion in mbstowcs.cpp under non-UTF-8 locales and also produced unreadable output when the console code page was GBK. Switch the tree drawing to UTF-8 byte literals so the log path stays purely narrow, and temporarily set the console output code page to CP_UTF8 around the dump so the box-drawing characters render correctly.
The visible property check was missing '== 0', so any non-visible property change incorrectly set update_visible to true, while actual visible mutations were ignored. This caused the window to never receive ptk_window_show on Windows.
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Liu <lc-soft@live.cn>
…-soft#327) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Liu <lc-soft@live.cn>
- charset module renamed to encoding (decode/encode kept)
- time: get_time_ms → y_gettime, sleep_ms → y_sleep
- time: delete get_time_us, get_time_delta, sleep_s
- string: strdup2 → y_strdup, wcsdup2 → y_wcsdup
- string: strtolower → y_strlower, strtrim → y_strtrim
- string: wcstrim → y_wcstrim, strhash → y_strhash
- string: strreplace → y_strreplace, strsplit → y_strsplit
- string: delete wcsreplace, cmdsplit
- math: delete y_iround, y_pow2
- timer module migrated from yutil to ptk as internal timer_scheduler
- WinMain simplified to use __argc/__argv instead of cmdsplit
BREAKING CHANGE: all renamed yutil public APIs require downstream
to update function names. Deleted APIs require code changes:
- get_time_us: use y_gettime() for ms timestamps
- get_time_delta: use y_gettime() - start instead
- sleep_s: use y_sleep(ms) with millisecond argument
- wcsreplace: no replacement, had zero callers
- cmdsplit: WinMain now uses __argc/__argv from CRT
- timer_list_*: migrated to ptk timer_scheduler_*;
ptk_reset_timer still available for external use
wineee
force-pushed
the
wayland
branch
2 times, most recently
from
July 29, 2026 03:04
b6e3366 to
ac5e535
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #322 +/- ##
===========================================
- Coverage 64.22% 62.31% -1.91%
===========================================
Files 221 225 +4
Lines 21137 21787 +650
Branches 2938 3051 +113
===========================================
+ Hits 13575 13577 +2
- Misses 6467 7113 +646
- Partials 1095 1097 +2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Update xmake-repo source from gitee mirror to github/gitlab upstream, refresh dependency versions and add new transitive dependencies.
Check WAYLAND_DISPLAY for wayland, DISPLAY for x11, and fallback to framebuffer. Log warnings when preferred backend is not compiled in.
Add missing PTK_HAS_WAYLAND template in config.h.in so the macro is actually defined in generated config.h. Include ptk.h before the #if guard in wayland source files so the macro is visible at the preprocessor check. Move ptk_waylandapp_destroy() before ptk_waylandapp_init() to resolve forward declaration warning. Fix cursor scaling on HiDPI: load cursor theme at logical size (32) instead of physical size (32*output_scale) and remove redundant hotspot division by output_scale, avoiding double scaling via wl_surface_set_buffer_scale. Only compile wayland source files when the wayland package is available.
…e space Store wnd->width/height as logical pixels (matching xdg_toplevel configure), allocate buffer at logical size, and let buffer_scale handle the upscaling to physical pixels. This eliminates the physical/logical coordinate mismatch that caused content to render in only a quarter of the window on HiDPI displays. Size events send physical dimensions (logical * scale) so the upper layer correctly divides by DPI scale. Size hints pass logical values directly to the Wayland protocol as it expects.
- Allocate SHM buffer at physical pixel dimensions (logical * scale) - Scale pointer coordinates to physical pixels in mouse events - Return physical pixel dimensions from screen and window size getters - Convert physical pixels to logical in set_size and size hints - Post size event on output_scale change to trigger layout refresh
Add wp_viewporter and wp_fractional_scale_v1 protocol support to handle non-integer HiDPI scaling on Wayland. - Bind viewporter and fractional-scale manager from registry - Create wp_viewport per window with source following buffer size - Use wp_fractional_scale_v1 to receive per-window scale from compositor - Fall back to wl_surface_set_buffer_scale when viewporter unavailable - Change output_scale from int to double, use lround for int conversions - Fix initial window size by setting xdg_surface window geometry - Use per-window scale for input coordinate conversion - Reuse ptk_waylandwindow_destroy in app destroy to avoid resource leak
Call xdg_surface_set_window_geometry before each surface commit so that SSD decorations track resize correctly.
lc-soft
force-pushed
the
develop
branch
3 times, most recently
from
August 5, 2026 15:36
70a8c84 to
873971f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
仍然是草稿