From d5c9df401aeaaad4e62a16b9c9909ef6d422be5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Fri, 7 Aug 2026 11:58:32 -0400 Subject: [PATCH 1/8] Added compile-time warning for GUIX deprecated string API (#167) When GX_DISABLE_DEPRECATED_STRING_API is not defined (i.e., the pre-5.6 GX_CHAR* API is still enabled), gx_api.h now emits a #pragma message directing developers to define GX_DISABLE_DEPRECATED_STRING_API and migrate to the GX_STRING-based replacement functions. The deprecated functions omit a string length and cannot safely handle non-NUL-terminated strings or prevent buffer overruns. All new applications should use the _ext() replacement variants. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- common/inc/gx_api.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/inc/gx_api.h b/common/inc/gx_api.h index 7e3e4e94a..e78d1e911 100644 --- a/common/inc/gx_api.h +++ b/common/inc/gx_api.h @@ -132,6 +132,10 @@ typedef struct GX_STRING_STRUCT #ifndef GX_DISABLE_DEPRECATED_STRING_API #define GX_ENABLE_DEPRECATED_STRING_API +#pragma message("GUIX deprecated string API is enabled. The pre-5.6 char* string " \ + "functions do not carry a length and are unsafe with non-NUL-terminated " \ + "buffers. Define GX_DISABLE_DEPRECATED_STRING_API and migrate to the " \ + "GX_STRING-based (_ext) variants.") #endif #if defined(GX_THREADX_BINDING) From c179c19bcfa5eb77c099ce35ce0d74cef69bc660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Tue, 25 Aug 2026 13:10:32 -0400 Subject: [PATCH 2/8] Fixed Screen Flow code generation with GX_ANIMATION_POOL_SIZE = 0 (#173) * Fixed Screen Flow code generation with GX_ANIMATION_POOL_SIZE = 0 GUIX Studio emitted five static helper functions in the generated specification file as soon as a project used Screen Flow. Two of them, gx_studio_action_parent_find() and gx_studio_animation_execute(), are reachable only from the GX_ACTION_TYPE_ANIMATION handler and reference the GUIX animation API, which is compiled out when the animation pool is empty: - gx_system_animation_get() is only defined under "#if (GX_ANIMATION_POOL_SIZE > 0)" in gx_api.h. - The body of _gx_animation_start() is guarded the same way in gx_animation_start.c, so the reference does not resolve at link time either. A project that defined GX_ANIMATION_POOL_SIZE as 0 in gx_user.h to save resources therefore failed to build even when it used no animation action at all. GCC 14 rejects the implicit declaration outright, and MSVC fails on the unresolved external. The screen generator now wraps both helpers and the two GX_ACTION_TYPE_ANIMATION dispatch sites in "#if (GX_ANIMATION_POOL_SIZE > 0)". Every other action type keeps working with an empty pool, and an animation action simply becomes a no-op at runtime. The generator also emits forward prototypes for the four static screen flow helpers, which addresses the secondary request in the issue. Note that MISRA C:2012 Rule 8.1 covers explicitly specified types and Rule 8.4 applies to objects and functions with external linkage, so static helpers without a visible prototype were not a deviation. The prototypes are still worth having and match the declaration the generator already emits for gx_studio_nested_widget_create(). All the checked-in generated specification files were regenerated so that they stay in sync with the generator, including the golden files of the Studio view test. Added test/guix_studio_test/test_demo/test_animation_pool_size.py as a regression test, registered in the demo compile CTest project. It verifies that every checked-in Screen Flow specification file guards the animation helpers, then compiles them all with GX_ANIMATION_POOL_SIZE set to 0, promoting the MSVC implicit declaration warning to an error so the failure mode above is caught. Fixes #172 Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) * Added hotfix letter support to the release version scripts The release tooling could not express a hotfix version. Two gaps: - Get-StudioReleaseVersion rejected anything that was not major.minor.patch.build, and update_studio_release_version.ps1 hard-coded GUIX_HOTFIX_VERSION as ' '. The documented path to build a hotfix installer was therefore unusable, and running the script after a manual edit would have reset the hotfix constant. - prepare_release.sh looked for gx_port.h under ports only, so it never updated the version string of the GUIX Studio Win32 port in guix_studio/ports/gx_port.h. Get-StudioReleaseVersion now accepts an optional trailing hotfix letter and exposes it as Hotfix and HotfixDefine. The Win32 and MSIX version formats are strictly numeric and cannot carry the letter, so the revision is offset by the position of the letter in the alphabet instead: 6.5.1.202602 keeps revision 2, and 6.5.1.202602a becomes revision 3. That keeps the hotfix installer recognizable as the newer build for Windows upgrade detection and for the Store. Versions without a hotfix letter resolve exactly as before. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) * Updated version number constants to 6.5.1.202602a Prepares the emergency hotfix release that carries the Screen Flow fix for GX_ANIMATION_POOL_SIZE = 0. Produced by scripts/update_studio_release_version.ps1 -Version 6.5.1.202602a: - gx_api.h: GUIX_HOTFIX_VERSION is now 'a'. The major, minor, patch and build constants are unchanged, as is the 6.5.1 banner. - studiox.rc: FileVersion and ProductVersion strings are 6.5.1.202602a, FILEVERSION and PRODUCTVERSION are 6,5,1,3. - guix_installer_release.iss: StudioFullVersion is 6.5.1.202602a and StudioVersionInfoVersion is 6.5.1.3, so the installer is named guix_studio_setup_version_6.5.1.202602a.exe. - Package.appxmanifest: the MSIX identity version is 6.5.1.03. STUDIOX_VERSION_NUMBER stays at 202602. It stamps the Studio version into .gxp project files, and a hotfix does not change the project file format. Verified against a rebuilt guix_studio.exe, which reports FileVersion 6.5.1.202602a with a numeric file version of 6.5.1.3, matching what verify_studio_installer.ps1 expects. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) * Updated port version strings to 6.5.1.202602a Updated the _gx_version_id string in all 47 gx_port.h files for the emergency hotfix release, using the same substitution that prepare_release.sh performs. This includes guix_studio/ports/gx_port.h, the GUIX Studio Win32 port, which the release script previously missed because it only searched the ports directory. That gap is fixed in the preceding commit, so a future release picks the file up automatically. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) --------- Co-authored-by: Claude Opus 5 (1M context) --- common/inc/gx_api.h | 2 +- .../msix_package_project/Package.appxmanifest | 2 +- .../installer/guix_installer_release.iss | 4 +- guix_studio/ports/gx_port.h | 2 +- guix_studio/screen_generator.cpp | 30 ++- guix_studio/studiox.rc | 8 +- ports/arc_em/metaware/inc/gx_port.h | 2 +- ports/arc_hs/metaware/inc/gx_port.h | 2 +- ports/arm9/ac5/inc/gx_port.h | 2 +- ports/arm9/gnu/inc/gx_port.h | 2 +- ports/arm9/iar/inc/gx_port.h | 2 +- ports/c667x/ccs/inc/gx_port.h | 2 +- ports/ccrx/inc/gx_port.h | 2 +- ports/cortex_a15/gnu/inc/gx_port.h | 2 +- ports/cortex_a5/ac5/inc/gx_port.h | 2 +- ports/cortex_a5/gnu/inc/gx_port.h | 2 +- ports/cortex_a5/iar/inc/gx_port.h | 2 +- ports/cortex_a5x/ac6/inc/gx_port.h | 2 +- ports/cortex_a7/ac5/inc/gx_port.h | 2 +- ports/cortex_a7/gnu/inc/gx_port.h | 2 +- ports/cortex_a7/iar/inc/gx_port.h | 2 +- ports/cortex_a8/ac5/inc/gx_port.h | 2 +- ports/cortex_a8/gnu/inc/gx_port.h | 2 +- ports/cortex_a8/iar/inc/gx_port.h | 2 +- ports/cortex_a9/ac5/inc/gx_port.h | 2 +- ports/cortex_a9/gnu/inc/gx_port.h | 2 +- ports/cortex_a9/iar/inc/gx_port.h | 2 +- ports/cortex_m0/ac5/inc/gx_port.h | 2 +- ports/cortex_m0/gnu/inc/gx_port.h | 2 +- ports/cortex_m0/iar/inc/gx_port.h | 2 +- ports/cortex_m3/ac5/inc/gx_port.h | 2 +- ports/cortex_m3/gnu/inc/gx_port.h | 2 +- ports/cortex_m3/iar/inc/gx_port.h | 2 +- ports/cortex_m3/keil/inc/gx_port.h | 2 +- ports/cortex_m4/ac5/inc/gx_port.h | 2 +- ports/cortex_m4/gnu/inc/gx_port.h | 2 +- ports/cortex_m4/iar/inc/gx_port.h | 2 +- ports/cortex_m4/keil/inc/gx_port.h | 2 +- ports/cortex_m7/ac5/inc/gx_port.h | 2 +- ports/cortex_m7/gnu/inc/gx_port.h | 2 +- ports/cortex_m7/iar/inc/gx_port.h | 2 +- ports/cortex_r4/ac5/inc/gx_port.h | 2 +- ports/cortex_r4/ac6/inc/gx_port.h | 2 +- ports/cortex_r4/gnu/inc/gx_port.h | 2 +- ports/cortex_r4/iar/inc/gx_port.h | 2 +- ports/cortex_r5/ac5/inc/gx_port.h | 2 +- ports/cortex_r5/gnu/inc/gx_port.h | 2 +- ports/cortex_r5/iar/inc/gx_port.h | 2 +- ports/generic/inc/gx_port.h | 2 +- ports/linux/gnu/inc/gx_port.h | 2 +- ports/win32/inc/gx_port.h | 2 +- ports/win32/vs_2019_standalone/inc/gx_port.h | 2 +- ...emo_guix_car_infotainment_specifications.c | 11 + ...demo_guix_home_automation_specifications.c | 11 + .../demo_guix_industrial_specifications.c | 11 + .../guix_medical_specifications.c | 11 + .../guix_widget_types_specifications.c | 11 + scripts/guix_studio_release.psm1 | 30 ++- scripts/prepare_release.sh | 6 +- scripts/update_studio_release_version.ps1 | 6 +- .../all_widgets/all_widgets_specifications.c | 11 + .../all_widgets_32argb_specifications.c | 11 + .../all_widgets_565bgr_specifications.c | 11 + .../all_widgets_5_4_0_specifications.c | 11 + .../all_widgets_5_4_1_specifications.c | 11 + .../all_widgets_5_4_2_specifications.c | 11 + .../all_widgets_5_5_1_specifications.c | 11 + ...fined_5_4_0_compatibility_specifications.c | 11 + .../all_widgets_execute_specifications.c | 11 + .../all_widgets_synergy_specifications.c | 11 + ...idgets_synergy_16bpp_flip_specifications.c | 11 + ...ets_synergy_dave_disabled_specifications.c | 11 + ...ll_widgets_synergy_565rgb_specifications.c | 11 + ...all_widgets_synergy_5_4_2_specifications.c | 11 + .../folder_output_test_specifications.c | 11 + ...uix_medical_mouse_support_specifications.c | 11 + ...artial_frame_buffer_16bpp_specifications.c | 11 + ...ndalone_binres_load_16bpp_specifications.c | 11 + .../system_screen_stack_specifications.c | 11 + .../template/template_specifications.c | 11 + .../test_demo/demo_compile/CMakeLists.txt | 6 +- .../test_demo/test_animation_pool_size.py | 239 ++++++++++++++++++ .../all_widgets_execute_specifications.c | 11 + .../golden_files/template_specifications.c | 11 + .../trigger_target_rename_specifications.c | 11 + .../demo_guix_menu_specifications.c | 11 + .../demo_guix_transitions_specifications.c | 11 + 87 files changed, 690 insertions(+), 67 deletions(-) create mode 100644 test/guix_studio_test/test_demo/test_animation_pool_size.py diff --git a/common/inc/gx_api.h b/common/inc/gx_api.h index e78d1e911..b47dc46f3 100644 --- a/common/inc/gx_api.h +++ b/common/inc/gx_api.h @@ -61,7 +61,7 @@ extern "C" { #define GUIX_MINOR_VERSION 5 #define GUIX_PATCH_VERSION 1 #define GUIX_BUILD_VERSION 202602 -#define GUIX_HOTFIX_VERSION ' ' +#define GUIX_HOTFIX_VERSION 'a' /* The following symbols are defined for backward compatibility reasons.*/ #define __PRODUCT_GUIX__ diff --git a/guix_studio/build/vs_2022/msix_package_project/Package.appxmanifest b/guix_studio/build/vs_2022/msix_package_project/Package.appxmanifest index 7d782ee47..f5405142c 100644 --- a/guix_studio/build/vs_2022/msix_package_project/Package.appxmanifest +++ b/guix_studio/build/vs_2022/msix_package_project/Package.appxmanifest @@ -22,7 +22,7 @@ + Version="6.5.1.03" /> Eclipse ThreadX GUIX Studio diff --git a/guix_studio/installer/guix_installer_release.iss b/guix_studio/installer/guix_installer_release.iss index 49d50a06b..5bf79a43d 100644 --- a/guix_studio/installer/guix_installer_release.iss +++ b/guix_studio/installer/guix_installer_release.iss @@ -11,7 +11,7 @@ ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! #ifndef StudioFullVersion -#define StudioFullVersion "6.5.1.202602" +#define StudioFullVersion "6.5.1.202602a" #endif #ifndef StudioShortVersion #define StudioShortVersion "6.5.1" @@ -20,7 +20,7 @@ #define StudioMajorMinorVersion "6.5" #endif #ifndef StudioVersionInfoVersion -#define StudioVersionInfoVersion "6.5.1.2" +#define StudioVersionInfoVersion "6.5.1.3" #endif [Setup] diff --git a/guix_studio/ports/gx_port.h b/guix_studio/ports/gx_port.h index c384508e3..c77e062b3 100644 --- a/guix_studio/ports/gx_port.h +++ b/guix_studio/ports/gx_port.h @@ -193,7 +193,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Win32/Visual Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Win32/Visual Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/guix_studio/screen_generator.cpp b/guix_studio/screen_generator.cpp index f7a944f13..61be10f45 100644 --- a/guix_studio/screen_generator.cpp +++ b/guix_studio/screen_generator.cpp @@ -9,6 +9,7 @@ * SPDX-License-Identifier: MIT **************************************************************************/ // Some portions generated by Codex (OpenAI GPT-5.5). +// Some portions generated by Claude Code (Opus 5). #include "studiox_includes.h" #ifdef _DEBUG @@ -1395,6 +1396,17 @@ CString out(""); /* Set output file to the default file: Empty means default output file. */ SetOutFile(out); + /* Write the prototypes of the static screen flow helpers. Declaring them up + front keeps the generated file compliant with projects that require a + visible prototype for every function definition. */ + out = "static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action);\n" + "static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action);\n" + "#if (GX_ANIMATION_POOL_SIZE > 0)\n" + "static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action);\n" + "static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action);\n" + "#endif\n\n"; + FileWrite(out); + out = "static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action)\n" "{\n" " GX_WIDGET *parent = GX_NULL;\n" @@ -1460,7 +1472,12 @@ CString out(""); "}\n\n"; FileWrite(out); - out = "static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action)\n" + /* gx_studio_action_parent_find() and gx_studio_animation_execute() are only + reachable from the GX_ACTION_TYPE_ANIMATION handler, and they reference the + animation API which is compiled out when the animation pool is empty. Guard + both so that a screen flow project builds with GX_ANIMATION_POOL_SIZE = 0. */ + out = "#if (GX_ANIMATION_POOL_SIZE > 0)\n" + "static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action)\n" "{\n" "GX_WIDGET *parent = GX_NULL;\n" "GX_STUDIO_WIDGET *widget_define;\n\n" @@ -1530,7 +1547,8 @@ CString out(""); " gx_animation_start(animation, &animation_info);\n" " }\n" " }\n" - "}\n\n"; + "}\n" + "#endif\n\n"; FileWrite(out); out = "UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record)\n" @@ -1610,9 +1628,11 @@ CString out(""); " gx_widget_hide(target);\n" " }\n" " break;\n\n" + "#if (GX_ANIMATION_POOL_SIZE > 0)\n" " case GX_ACTION_TYPE_ANIMATION:\n" " gx_studio_animation_execute(widget, action);\n" - " break;\n\n" + " break;\n" + "#endif\n\n" " case GX_ACTION_TYPE_WINDOW_EXECUTE:\n" " parent = widget->gx_widget_parent;\n" " target = gx_studio_action_target_get(widget, action);\n" @@ -1697,9 +1717,11 @@ CString out(""); " gx_widget_hide(target);\n" " }\n" " break;\n\n" + "#if (GX_ANIMATION_POOL_SIZE > 0)\n" " case GX_ACTION_TYPE_ANIMATION:\n" " gx_studio_animation_execute(widget, action);\n" - " break;\n\n" + " break;\n" + "#endif\n\n" " case GX_ACTION_TYPE_WINDOW_EXECUTE:\n" " if((action->flags & GX_ACTION_FLAG_POP_TARGET) ||\n" " (action->flags & GX_ACTION_FLAG_POP_PARENT))\n" diff --git a/guix_studio/studiox.rc b/guix_studio/studiox.rc index e1947836b..e65446258 100644 --- a/guix_studio/studiox.rc +++ b/guix_studio/studiox.rc @@ -1767,8 +1767,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 6,5,1,2 - PRODUCTVERSION 6,5,1,2 + FILEVERSION 6,5,1,3 + PRODUCTVERSION 6,5,1,3 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -1785,12 +1785,12 @@ BEGIN BEGIN VALUE "CompanyName", "Eclipse Foundation" VALUE "FileDescription", "GUIX Studio Application" - VALUE "FileVersion", "6.5.1.202602" + VALUE "FileVersion", "6.5.1.202602a" VALUE "InternalName", "studiox.exe" VALUE "LegalCopyright", "(c) Eclipse ThreadX contributors" VALUE "OriginalFilename", "studiox.exe" VALUE "ProductName", "Eclipse ThreadX GUIX Studio" - VALUE "ProductVersion", "6.5.1.202602" + VALUE "ProductVersion", "6.5.1.202602a" END END BLOCK "VarFileInfo" diff --git a/ports/arc_em/metaware/inc/gx_port.h b/ports/arc_em/metaware/inc/gx_port.h index f215b1f4b..01aa24127 100644 --- a/ports/arc_em/metaware/inc/gx_port.h +++ b/ports/arc_em/metaware/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX ARCv2_EM/MetaWare Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX ARCv2_EM/MetaWare Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/arc_hs/metaware/inc/gx_port.h b/ports/arc_hs/metaware/inc/gx_port.h index 6fce23adb..b65b97043 100644 --- a/ports/arc_hs/metaware/inc/gx_port.h +++ b/ports/arc_hs/metaware/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX ARC_HS/MetaWare Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX ARC_HS/MetaWare Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/arm9/ac5/inc/gx_port.h b/ports/arm9/ac5/inc/gx_port.h index 03d32f6d0..2379034b1 100644 --- a/ports/arm9/ac5/inc/gx_port.h +++ b/ports/arm9/ac5/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX ARM9/AC5 Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX ARM9/AC5 Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/arm9/gnu/inc/gx_port.h b/ports/arm9/gnu/inc/gx_port.h index 09437bde8..14faebe45 100644 --- a/ports/arm9/gnu/inc/gx_port.h +++ b/ports/arm9/gnu/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX ARM9/GNU Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX ARM9/GNU Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/arm9/iar/inc/gx_port.h b/ports/arm9/iar/inc/gx_port.h index ceb8ac33e..a2266679b 100644 --- a/ports/arm9/iar/inc/gx_port.h +++ b/ports/arm9/iar/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX ARM9/IAR Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX ARM9/IAR Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/c667x/ccs/inc/gx_port.h b/ports/c667x/ccs/inc/gx_port.h index c58ab63b8..15ed57ef4 100644 --- a/ports/c667x/ccs/inc/gx_port.h +++ b/ports/c667x/ccs/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX C6xxx/TI Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX C6xxx/TI Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/ccrx/inc/gx_port.h b/ports/ccrx/inc/gx_port.h index 9f833ae1d..8c0ae1eee 100644 --- a/ports/ccrx/inc/gx_port.h +++ b/ports/ccrx/inc/gx_port.h @@ -140,7 +140,7 @@ typedef unsigned char GX_UCHAR; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_a15/gnu/inc/gx_port.h b/ports/cortex_a15/gnu/inc/gx_port.h index 354a64459..9d7776cb7 100644 --- a/ports/cortex_a15/gnu/inc/gx_port.h +++ b/ports/cortex_a15/gnu/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A15/GNU Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A15/GNU Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_a5/ac5/inc/gx_port.h b/ports/cortex_a5/ac5/inc/gx_port.h index 14f3657f1..4f9f726d6 100644 --- a/ports/cortex_a5/ac5/inc/gx_port.h +++ b/ports/cortex_a5/ac5/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A5/AC5 Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A5/AC5 Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_a5/gnu/inc/gx_port.h b/ports/cortex_a5/gnu/inc/gx_port.h index f6f052a28..c8bc7e737 100644 --- a/ports/cortex_a5/gnu/inc/gx_port.h +++ b/ports/cortex_a5/gnu/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A5/GNU Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A5/GNU Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_a5/iar/inc/gx_port.h b/ports/cortex_a5/iar/inc/gx_port.h index a2884e9ca..eeeeb1064 100644 --- a/ports/cortex_a5/iar/inc/gx_port.h +++ b/ports/cortex_a5/iar/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A5/IAR Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A5/IAR Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_a5x/ac6/inc/gx_port.h b/ports/cortex_a5x/ac6/inc/gx_port.h index 10b146001..f7be078d8 100644 --- a/ports/cortex_a5x/ac6/inc/gx_port.h +++ b/ports/cortex_a5x/ac6/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A5x/AC6 Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A5x/AC6 Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_a7/ac5/inc/gx_port.h b/ports/cortex_a7/ac5/inc/gx_port.h index a47d02e12..12f77f60e 100644 --- a/ports/cortex_a7/ac5/inc/gx_port.h +++ b/ports/cortex_a7/ac5/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A7/AC5 Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A7/AC5 Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_a7/gnu/inc/gx_port.h b/ports/cortex_a7/gnu/inc/gx_port.h index a086ef590..b9c451d62 100644 --- a/ports/cortex_a7/gnu/inc/gx_port.h +++ b/ports/cortex_a7/gnu/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A7/GNU Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A7/GNU Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_a7/iar/inc/gx_port.h b/ports/cortex_a7/iar/inc/gx_port.h index 514edb6b6..dabdbc50b 100644 --- a/ports/cortex_a7/iar/inc/gx_port.h +++ b/ports/cortex_a7/iar/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A7/IAR Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A7/IAR Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_a8/ac5/inc/gx_port.h b/ports/cortex_a8/ac5/inc/gx_port.h index af8048882..5d0ee0a2e 100644 --- a/ports/cortex_a8/ac5/inc/gx_port.h +++ b/ports/cortex_a8/ac5/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A8/AC5 Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A8/AC5 Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_a8/gnu/inc/gx_port.h b/ports/cortex_a8/gnu/inc/gx_port.h index 5f75c4ce1..011ccc268 100644 --- a/ports/cortex_a8/gnu/inc/gx_port.h +++ b/ports/cortex_a8/gnu/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A8/GNU Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A8/GNU Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_a8/iar/inc/gx_port.h b/ports/cortex_a8/iar/inc/gx_port.h index 6423e0b5a..2490244eb 100644 --- a/ports/cortex_a8/iar/inc/gx_port.h +++ b/ports/cortex_a8/iar/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A8/IAR Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A8/IAR Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_a9/ac5/inc/gx_port.h b/ports/cortex_a9/ac5/inc/gx_port.h index c6a472806..798bba73f 100644 --- a/ports/cortex_a9/ac5/inc/gx_port.h +++ b/ports/cortex_a9/ac5/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A9/AC5 Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A9/AC5 Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_a9/gnu/inc/gx_port.h b/ports/cortex_a9/gnu/inc/gx_port.h index 2c995e1df..c97ab73a7 100644 --- a/ports/cortex_a9/gnu/inc/gx_port.h +++ b/ports/cortex_a9/gnu/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A9/GNU Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A9/GNU Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_a9/iar/inc/gx_port.h b/ports/cortex_a9/iar/inc/gx_port.h index 5f00bef53..9a38832f6 100644 --- a/ports/cortex_a9/iar/inc/gx_port.h +++ b/ports/cortex_a9/iar/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A9/IAR Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-A9/IAR Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_m0/ac5/inc/gx_port.h b/ports/cortex_m0/ac5/inc/gx_port.h index e75d59876..ebb977928 100644 --- a/ports/cortex_m0/ac5/inc/gx_port.h +++ b/ports/cortex_m0/ac5/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M0/AC5 Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M0/AC5 Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_m0/gnu/inc/gx_port.h b/ports/cortex_m0/gnu/inc/gx_port.h index c65bf03b2..56689e65b 100644 --- a/ports/cortex_m0/gnu/inc/gx_port.h +++ b/ports/cortex_m0/gnu/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M0/GNU Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M0/GNU Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_m0/iar/inc/gx_port.h b/ports/cortex_m0/iar/inc/gx_port.h index 2a537f936..2f441d8f5 100644 --- a/ports/cortex_m0/iar/inc/gx_port.h +++ b/ports/cortex_m0/iar/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M0/IAR Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M0/IAR Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_m3/ac5/inc/gx_port.h b/ports/cortex_m3/ac5/inc/gx_port.h index bb2dd4a63..089b9bba3 100644 --- a/ports/cortex_m3/ac5/inc/gx_port.h +++ b/ports/cortex_m3/ac5/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M3/AC5 Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M3/AC5 Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_m3/gnu/inc/gx_port.h b/ports/cortex_m3/gnu/inc/gx_port.h index f08ec1ec2..8183bd8c7 100644 --- a/ports/cortex_m3/gnu/inc/gx_port.h +++ b/ports/cortex_m3/gnu/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M3/GNU Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M3/GNU Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_m3/iar/inc/gx_port.h b/ports/cortex_m3/iar/inc/gx_port.h index 9e478d411..f46a80955 100644 --- a/ports/cortex_m3/iar/inc/gx_port.h +++ b/ports/cortex_m3/iar/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M3/IAR Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M3/IAR Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_m3/keil/inc/gx_port.h b/ports/cortex_m3/keil/inc/gx_port.h index f2b8f7b16..27d2e85b8 100644 --- a/ports/cortex_m3/keil/inc/gx_port.h +++ b/ports/cortex_m3/keil/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M3/KEIL Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M3/KEIL Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_m4/ac5/inc/gx_port.h b/ports/cortex_m4/ac5/inc/gx_port.h index 35644488b..74b66fca5 100644 --- a/ports/cortex_m4/ac5/inc/gx_port.h +++ b/ports/cortex_m4/ac5/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M4/AC5 Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M4/AC5 Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_m4/gnu/inc/gx_port.h b/ports/cortex_m4/gnu/inc/gx_port.h index dae91ac3d..ba1cfb2eb 100644 --- a/ports/cortex_m4/gnu/inc/gx_port.h +++ b/ports/cortex_m4/gnu/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M4/GNU Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M4/GNU Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_m4/iar/inc/gx_port.h b/ports/cortex_m4/iar/inc/gx_port.h index 79353116e..2564b5897 100644 --- a/ports/cortex_m4/iar/inc/gx_port.h +++ b/ports/cortex_m4/iar/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M4/IAR Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M4/IAR Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_m4/keil/inc/gx_port.h b/ports/cortex_m4/keil/inc/gx_port.h index fd633b547..485250b73 100644 --- a/ports/cortex_m4/keil/inc/gx_port.h +++ b/ports/cortex_m4/keil/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M4/KEIL Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M4/KEIL Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_m7/ac5/inc/gx_port.h b/ports/cortex_m7/ac5/inc/gx_port.h index e59174306..34d1dd7e4 100644 --- a/ports/cortex_m7/ac5/inc/gx_port.h +++ b/ports/cortex_m7/ac5/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M7/AC5 Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M7/AC5 Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_m7/gnu/inc/gx_port.h b/ports/cortex_m7/gnu/inc/gx_port.h index cf5a57c34..da31dcd95 100644 --- a/ports/cortex_m7/gnu/inc/gx_port.h +++ b/ports/cortex_m7/gnu/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M7/GNU Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M7/GNU Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_m7/iar/inc/gx_port.h b/ports/cortex_m7/iar/inc/gx_port.h index 9d68cf35c..1ab1da137 100644 --- a/ports/cortex_m7/iar/inc/gx_port.h +++ b/ports/cortex_m7/iar/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M7/IAR Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-M7/IAR Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_r4/ac5/inc/gx_port.h b/ports/cortex_r4/ac5/inc/gx_port.h index 1499b62e1..a25231550 100644 --- a/ports/cortex_r4/ac5/inc/gx_port.h +++ b/ports/cortex_r4/ac5/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-R4/AC5 Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-R4/AC5 Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_r4/ac6/inc/gx_port.h b/ports/cortex_r4/ac6/inc/gx_port.h index 668dc3825..1faaba1d2 100644 --- a/ports/cortex_r4/ac6/inc/gx_port.h +++ b/ports/cortex_r4/ac6/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-R4/AC6 Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-R4/AC6 Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_r4/gnu/inc/gx_port.h b/ports/cortex_r4/gnu/inc/gx_port.h index 7691829a0..0af060f64 100644 --- a/ports/cortex_r4/gnu/inc/gx_port.h +++ b/ports/cortex_r4/gnu/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-R4/GNU Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-R4/GNU Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_r4/iar/inc/gx_port.h b/ports/cortex_r4/iar/inc/gx_port.h index 6aae85a48..1b3af8f08 100644 --- a/ports/cortex_r4/iar/inc/gx_port.h +++ b/ports/cortex_r4/iar/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-R4/IAR Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-R4/IAR Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_r5/ac5/inc/gx_port.h b/ports/cortex_r5/ac5/inc/gx_port.h index 6d7572281..a15636b1c 100644 --- a/ports/cortex_r5/ac5/inc/gx_port.h +++ b/ports/cortex_r5/ac5/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-R5/AC5 Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-R5/AC5 Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_r5/gnu/inc/gx_port.h b/ports/cortex_r5/gnu/inc/gx_port.h index 641cc3da9..7e7db2303 100644 --- a/ports/cortex_r5/gnu/inc/gx_port.h +++ b/ports/cortex_r5/gnu/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-R5/GNU Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-R5/GNU Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/cortex_r5/iar/inc/gx_port.h b/ports/cortex_r5/iar/inc/gx_port.h index 47d668f45..08de499e0 100644 --- a/ports/cortex_r5/iar/inc/gx_port.h +++ b/ports/cortex_r5/iar/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-R5/IAR Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Cortex-R5/IAR Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/generic/inc/gx_port.h b/ports/generic/inc/gx_port.h index c61d880d6..4e039d0a1 100644 --- a/ports/generic/inc/gx_port.h +++ b/ports/generic/inc/gx_port.h @@ -132,7 +132,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/linux/gnu/inc/gx_port.h b/ports/linux/gnu/inc/gx_port.h index a87270bd9..d3ac3b968 100644 --- a/ports/linux/gnu/inc/gx_port.h +++ b/ports/linux/gnu/inc/gx_port.h @@ -127,7 +127,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Linux/GNU Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Linux/GNU Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/win32/inc/gx_port.h b/ports/win32/inc/gx_port.h index 7e110770b..ab31cb420 100644 --- a/ports/win32/inc/gx_port.h +++ b/ports/win32/inc/gx_port.h @@ -147,7 +147,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Win32/Visual Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Win32/Visual Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/ports/win32/vs_2019_standalone/inc/gx_port.h b/ports/win32/vs_2019_standalone/inc/gx_port.h index 3217e7615..1b21b49b5 100644 --- a/ports/win32/vs_2019_standalone/inc/gx_port.h +++ b/ports/win32/vs_2019_standalone/inc/gx_port.h @@ -90,7 +90,7 @@ typedef SHORT GX_VALUE; #ifdef GX_SYSTEM_INIT CHAR _gx_version_id[] = - "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Win32/Standalone/Visual Version 6.5.1.202602 *"; + "(c) 2024 Microsoft Corp. (c) 2026 Eclipse ThreadX contributors. * GUIX Win32/Standalone/Visual Version 6.5.1.202602a *"; #else extern CHAR _gx_version_id[]; #endif diff --git a/samples/demo_guix_car_infotainment/demo_guix_car_infotainment_specifications.c b/samples/demo_guix_car_infotainment/demo_guix_car_infotainment_specifications.c index e563dd49a..540f72c85 100644 --- a/samples/demo_guix_car_infotainment/demo_guix_car_infotainment_specifications.c +++ b/samples/demo_guix_car_infotainment/demo_guix_car_infotainment_specifications.c @@ -62,6 +62,13 @@ GX_STUDIO_DISPLAY_INFO demo_guix_car_infotainment_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -127,6 +134,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -192,6 +200,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -293,9 +302,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/samples/demo_guix_home_automation/demo_guix_home_automation_specifications.c b/samples/demo_guix_home_automation/demo_guix_home_automation_specifications.c index c5762eae5..58d4930c6 100644 --- a/samples/demo_guix_home_automation/demo_guix_home_automation_specifications.c +++ b/samples/demo_guix_home_automation/demo_guix_home_automation_specifications.c @@ -76,6 +76,13 @@ GX_STUDIO_DISPLAY_INFO demo_guix_home_automation_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -141,6 +148,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -206,6 +214,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -307,9 +316,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/samples/demo_guix_industrial/demo_guix_industrial_specifications.c b/samples/demo_guix_industrial/demo_guix_industrial_specifications.c index 6c81a0c38..2dc4e2c06 100644 --- a/samples/demo_guix_industrial/demo_guix_industrial_specifications.c +++ b/samples/demo_guix_industrial/demo_guix_industrial_specifications.c @@ -60,6 +60,13 @@ GX_STUDIO_DISPLAY_INFO demo_guix_industrial_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -125,6 +132,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -190,6 +198,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -291,9 +300,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/samples/demo_guix_medical/guix_medical_specifications.c b/samples/demo_guix_medical/guix_medical_specifications.c index 2276cf085..63f6118ab 100644 --- a/samples/demo_guix_medical/guix_medical_specifications.c +++ b/samples/demo_guix_medical/guix_medical_specifications.c @@ -59,6 +59,13 @@ GX_STUDIO_DISPLAY_INFO guix_medical_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -124,6 +131,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -189,6 +197,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -290,9 +299,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/samples/demo_guix_widget_types/guix_widget_types_specifications.c b/samples/demo_guix_widget_types/guix_widget_types_specifications.c index e78e10f98..91632ee47 100644 --- a/samples/demo_guix_widget_types/guix_widget_types_specifications.c +++ b/samples/demo_guix_widget_types/guix_widget_types_specifications.c @@ -63,6 +63,13 @@ GX_STUDIO_DISPLAY_INFO guix_widget_types_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -128,6 +135,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -193,6 +201,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -294,9 +303,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/scripts/guix_studio_release.psm1 b/scripts/guix_studio_release.psm1 index 14a419d0a..a892e7870 100644 --- a/scripts/guix_studio_release.psm1 +++ b/scripts/guix_studio_release.psm1 @@ -5,6 +5,7 @@ # https://opensource.org/licenses/MIT. # # SPDX-License-Identifier: MIT +# Some portions generated by Claude Code (Opus 5). function Get-StudioReleaseVersion { [CmdletBinding()] @@ -13,8 +14,8 @@ function Get-StudioReleaseVersion { [string]$Version ) - if ($Version -notmatch '^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$') { - throw "Version must use the form major.minor.patch.build, for example 6.5.1.202602." + if ($Version -notmatch '^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)([a-z]?)$') { + throw "Version must use the form major.minor.patch.build[hotfix_letter], for example 6.5.1.202602 or 6.5.1.202602a." } $major = [int]$matches[1] @@ -22,12 +23,24 @@ function Get-StudioReleaseVersion { $patch = [int]$matches[3] $buildText = $matches[4] $build = [int]$buildText + $hotfix = $matches[5] + + # The Win32 and MSIX version formats are strictly numeric, so a hotfix + # letter cannot be carried over as is. Offset the revision by the position + # of the letter in the alphabet instead, so that 'a' produces a revision one + # higher than the base release and Windows recognizes the hotfix installer + # as the newer build. + $hotfixOffset = 0 + if ($hotfix) { + $hotfixOffset = [int][char]$hotfix - [int][char]'a' + 1 + } + $revisionText = $buildText if ($revisionText.Length -gt 2) { $revisionText = $revisionText.Substring($revisionText.Length - 2) } - $revisionText = $revisionText.PadLeft(2, '0') - $revision = [int]$revisionText + $revision = [int]$revisionText + $hotfixOffset + $revisionText = ([string]$revision).PadLeft(2, '0') foreach ($part in @($major, $minor, $patch, $revision)) { if ($part -lt 0 -or $part -gt 65535) { @@ -35,6 +48,13 @@ function Get-StudioReleaseVersion { } } + if ($hotfix) { + $hotfixDefine = "'$hotfix'" + } + else { + $hotfixDefine = "' '" + } + [PSCustomObject]@{ FullVersion = $Version ShortVersion = "$major.$minor.$patch" @@ -44,6 +64,8 @@ function Get-StudioReleaseVersion { Patch = $patch Build = $build BuildText = $buildText + Hotfix = $hotfix + HotfixDefine = $hotfixDefine Revision = $revision RevisionText = $revisionText Win32Version = "$major.$minor.$patch.$revision" diff --git a/scripts/prepare_release.sh b/scripts/prepare_release.sh index c90d3bff4..e832e92fd 100755 --- a/scripts/prepare_release.sh +++ b/scripts/prepare_release.sh @@ -10,11 +10,13 @@ # 1. Creates branch release--preparation from dev # 2. Updates version constants in common/inc/gx_api.h # (commit: "Updated version number constants") -# 3. Updates port version strings in all gx_port.h files +# 3. Updates port version strings in all gx_port.h files, both the GUIX +# ports and the GUIX Studio Win32 port # (commit: "Updated port version strings") # # Copyright (C) 2026 Eclipse ThreadX contributors # SPDX-License-Identifier: MIT +# Some portions generated by Claude Code (Opus 5). set -eu @@ -23,7 +25,7 @@ REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" API_HEADER="${REPO_ROOT}/common/inc/gx_api.h" PORT_HEADER_NAME="gx_port.h" -PORT_DIRS="ports" +PORT_DIRS="ports guix_studio/ports" # -------------------------------------------------------------------------- # Argument validation diff --git a/scripts/update_studio_release_version.ps1 b/scripts/update_studio_release_version.ps1 index cb218687a..46807434c 100644 --- a/scripts/update_studio_release_version.ps1 +++ b/scripts/update_studio_release_version.ps1 @@ -5,6 +5,7 @@ # https://opensource.org/licenses/MIT. # # SPDX-License-Identifier: MIT +# Some portions generated by Claude Code (Opus 5). [CmdletBinding()] param( @@ -70,7 +71,7 @@ $content = Replace-Required $content '(?m)^#define GUIX_MAJOR_VERSION\s+\d+' "#d $content = Replace-Required $content '(?m)^#define GUIX_MINOR_VERSION\s+\d+' "#define GUIX_MINOR_VERSION $($release.Minor)" 'GUIX_MINOR_VERSION' $content = Replace-Required $content '(?m)^#define GUIX_PATCH_VERSION\s+\d+' "#define GUIX_PATCH_VERSION $($release.Patch)" 'GUIX_PATCH_VERSION' $content = Replace-Required $content '(?m)^#define GUIX_BUILD_VERSION\s+\d+' "#define GUIX_BUILD_VERSION $($release.Build)" 'GUIX_BUILD_VERSION' -$content = Replace-Required $content "(?m)^#define GUIX_HOTFIX_VERSION\s+'.*'" "#define GUIX_HOTFIX_VERSION ' '" 'GUIX_HOTFIX_VERSION' +$content = Replace-Required $content "(?m)^#define GUIX_HOTFIX_VERSION\s+'.*'" "#define GUIX_HOTFIX_VERSION $($release.HotfixDefine)" 'GUIX_HOTFIX_VERSION' Set-AsciiFile -Path $gxApi -Content $content $content = Get-Content -LiteralPath $studioProject -Raw @@ -96,5 +97,8 @@ $content = Replace-Required $content '#define StudioVersionInfoVersion "[^"]+"' Set-AsciiFile -Path $innoScript -Content $content Write-Host "Updated GUIX Studio release version to $($release.FullVersion)." +if ($release.Hotfix) { + Write-Host "Hotfix letter: $($release.Hotfix)" +} Write-Host "Win32 version: $($release.Win32Version)" Write-Host "MSIX version: $($release.MsixVersion)" diff --git a/test/example_internal/all_widgets/all_widgets_specifications.c b/test/example_internal/all_widgets/all_widgets_specifications.c index aa3bac2dc..077227294 100644 --- a/test/example_internal/all_widgets/all_widgets_specifications.c +++ b/test/example_internal/all_widgets/all_widgets_specifications.c @@ -69,6 +69,13 @@ GX_STUDIO_DISPLAY_INFO all_widgets_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -134,6 +141,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -199,6 +207,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -300,9 +309,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/test/example_internal/all_widgets_32argb/all_widgets_32argb_specifications.c b/test/example_internal/all_widgets_32argb/all_widgets_32argb_specifications.c index 4717e1997..94c6a5603 100644 --- a/test/example_internal/all_widgets_32argb/all_widgets_32argb_specifications.c +++ b/test/example_internal/all_widgets_32argb/all_widgets_32argb_specifications.c @@ -67,6 +67,13 @@ GX_STUDIO_DISPLAY_INFO all_widgets_32argb_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -132,6 +139,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -197,6 +205,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -298,9 +307,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/test/example_internal/all_widgets_565bgr/all_widgets_565bgr_specifications.c b/test/example_internal/all_widgets_565bgr/all_widgets_565bgr_specifications.c index 3c497d5ab..fe3b8b37f 100644 --- a/test/example_internal/all_widgets_565bgr/all_widgets_565bgr_specifications.c +++ b/test/example_internal/all_widgets_565bgr/all_widgets_565bgr_specifications.c @@ -68,6 +68,13 @@ GX_STUDIO_DISPLAY_INFO all_widgets_565bgr_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -133,6 +140,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -198,6 +206,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -299,9 +308,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/test/example_internal/all_widgets_5_4_0/all_widgets_5_4_0_specifications.c b/test/example_internal/all_widgets_5_4_0/all_widgets_5_4_0_specifications.c index c0ed43ac1..9c3864174 100644 --- a/test/example_internal/all_widgets_5_4_0/all_widgets_5_4_0_specifications.c +++ b/test/example_internal/all_widgets_5_4_0/all_widgets_5_4_0_specifications.c @@ -65,6 +65,13 @@ GX_STUDIO_DISPLAY_INFO all_widgets_5_4_0_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -130,6 +137,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -178,6 +186,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -260,9 +269,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: parent = widget->gx_widget_parent; diff --git a/test/example_internal/all_widgets_5_4_1/all_widgets_5_4_1_specifications.c b/test/example_internal/all_widgets_5_4_1/all_widgets_5_4_1_specifications.c index a4c7b17fc..6dc07a7e5 100644 --- a/test/example_internal/all_widgets_5_4_1/all_widgets_5_4_1_specifications.c +++ b/test/example_internal/all_widgets_5_4_1/all_widgets_5_4_1_specifications.c @@ -65,6 +65,13 @@ GX_STUDIO_DISPLAY_INFO all_widgets_5_4_1_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -130,6 +137,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -178,6 +186,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -260,9 +269,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: parent = widget->gx_widget_parent; diff --git a/test/example_internal/all_widgets_5_4_2/all_widgets_5_4_2_specifications.c b/test/example_internal/all_widgets_5_4_2/all_widgets_5_4_2_specifications.c index 0c2dd9c27..39b9b7b2f 100644 --- a/test/example_internal/all_widgets_5_4_2/all_widgets_5_4_2_specifications.c +++ b/test/example_internal/all_widgets_5_4_2/all_widgets_5_4_2_specifications.c @@ -65,6 +65,13 @@ GX_STUDIO_DISPLAY_INFO all_widgets_5_4_2_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -130,6 +137,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -178,6 +186,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -260,9 +269,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: parent = widget->gx_widget_parent; diff --git a/test/example_internal/all_widgets_5_5_1/all_widgets_5_5_1_specifications.c b/test/example_internal/all_widgets_5_5_1/all_widgets_5_5_1_specifications.c index bc6d3695f..efd0f73e9 100644 --- a/test/example_internal/all_widgets_5_5_1/all_widgets_5_5_1_specifications.c +++ b/test/example_internal/all_widgets_5_5_1/all_widgets_5_5_1_specifications.c @@ -66,6 +66,13 @@ GX_STUDIO_DISPLAY_INFO all_widgets_5_5_1_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -131,6 +138,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -196,6 +204,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -297,9 +306,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/test/example_internal/all_widgets_defined_5_4_0_compatibility/all_widgets_defined_5_4_0_compatibility_specifications.c b/test/example_internal/all_widgets_defined_5_4_0_compatibility/all_widgets_defined_5_4_0_compatibility_specifications.c index 1f1ee7b61..54fa4b78a 100644 --- a/test/example_internal/all_widgets_defined_5_4_0_compatibility/all_widgets_defined_5_4_0_compatibility_specifications.c +++ b/test/example_internal/all_widgets_defined_5_4_0_compatibility/all_widgets_defined_5_4_0_compatibility_specifications.c @@ -67,6 +67,13 @@ GX_STUDIO_DISPLAY_INFO all_widgets_defined_5_4_0_compatibility_display_table[1] } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -132,6 +139,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -197,6 +205,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -298,9 +307,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/test/example_internal/all_widgets_execute/all_widgets_execute_specifications.c b/test/example_internal/all_widgets_execute/all_widgets_execute_specifications.c index 753bf3624..91b23b867 100644 --- a/test/example_internal/all_widgets_execute/all_widgets_execute_specifications.c +++ b/test/example_internal/all_widgets_execute/all_widgets_execute_specifications.c @@ -65,6 +65,13 @@ GX_STUDIO_DISPLAY_INFO all_widgets_execute_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -130,6 +137,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -195,6 +203,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -296,9 +305,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/test/example_internal/all_widgets_synergy/all_widgets_synergy_specifications.c b/test/example_internal/all_widgets_synergy/all_widgets_synergy_specifications.c index 19806d362..8aa6b018e 100644 --- a/test/example_internal/all_widgets_synergy/all_widgets_synergy_specifications.c +++ b/test/example_internal/all_widgets_synergy/all_widgets_synergy_specifications.c @@ -66,6 +66,13 @@ GX_STUDIO_DISPLAY_INFO all_widgets_synergy_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -131,6 +138,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -196,6 +204,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -297,9 +306,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/test/example_internal/all_widgets_synergy_16bpp_flip/all_widgets_synergy_16bpp_flip_specifications.c b/test/example_internal/all_widgets_synergy_16bpp_flip/all_widgets_synergy_16bpp_flip_specifications.c index 15506b7b8..6a415a6aa 100644 --- a/test/example_internal/all_widgets_synergy_16bpp_flip/all_widgets_synergy_16bpp_flip_specifications.c +++ b/test/example_internal/all_widgets_synergy_16bpp_flip/all_widgets_synergy_16bpp_flip_specifications.c @@ -66,6 +66,13 @@ GX_STUDIO_DISPLAY_INFO all_widgets_synergy_16bpp_flip_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -131,6 +138,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -196,6 +204,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -297,9 +306,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/test/example_internal/all_widgets_synergy_24BPP_Dave_Disabled/all_widgets_synergy_dave_disabled_specifications.c b/test/example_internal/all_widgets_synergy_24BPP_Dave_Disabled/all_widgets_synergy_dave_disabled_specifications.c index 902fbc4a9..afe2a191d 100644 --- a/test/example_internal/all_widgets_synergy_24BPP_Dave_Disabled/all_widgets_synergy_dave_disabled_specifications.c +++ b/test/example_internal/all_widgets_synergy_24BPP_Dave_Disabled/all_widgets_synergy_dave_disabled_specifications.c @@ -65,6 +65,13 @@ GX_STUDIO_DISPLAY_INFO all_widgets_synergy_dave_disabled_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -130,6 +137,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -195,6 +203,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -296,9 +305,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/test/example_internal/all_widgets_synergy_565rgb/all_widgets_synergy_565rgb_specifications.c b/test/example_internal/all_widgets_synergy_565rgb/all_widgets_synergy_565rgb_specifications.c index 0cfac6bb7..efff969e4 100644 --- a/test/example_internal/all_widgets_synergy_565rgb/all_widgets_synergy_565rgb_specifications.c +++ b/test/example_internal/all_widgets_synergy_565rgb/all_widgets_synergy_565rgb_specifications.c @@ -66,6 +66,13 @@ GX_STUDIO_DISPLAY_INFO all_widgets_synergy_565rgb_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -131,6 +138,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -196,6 +204,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -297,9 +306,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/test/example_internal/all_widgets_synergy_5_4_2/all_widgets_synergy_5_4_2_specifications.c b/test/example_internal/all_widgets_synergy_5_4_2/all_widgets_synergy_5_4_2_specifications.c index 80f9a2a24..918f3ddde 100644 --- a/test/example_internal/all_widgets_synergy_5_4_2/all_widgets_synergy_5_4_2_specifications.c +++ b/test/example_internal/all_widgets_synergy_5_4_2/all_widgets_synergy_5_4_2_specifications.c @@ -64,6 +64,13 @@ GX_STUDIO_DISPLAY_INFO all_widgets_synergy_5_4_2_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -129,6 +136,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -177,6 +185,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -259,9 +268,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: parent = widget->gx_widget_parent; diff --git a/test/example_internal/folder_output_test/folder_output_test_specifications.c b/test/example_internal/folder_output_test/folder_output_test_specifications.c index 2cbfbf97f..e5150119a 100644 --- a/test/example_internal/folder_output_test/folder_output_test_specifications.c +++ b/test/example_internal/folder_output_test/folder_output_test_specifications.c @@ -128,6 +128,13 @@ static VOID gx_studio_screen_toggle(GX_WIDGET *target1, GX_WIDGET *target2) } } +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -193,6 +200,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -258,6 +266,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -344,9 +353,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/test/example_internal/guix_medical_mouse_support/guix_medical_mouse_support_specifications.c b/test/example_internal/guix_medical_mouse_support/guix_medical_mouse_support_specifications.c index c50b054e0..56f570a97 100644 --- a/test/example_internal/guix_medical_mouse_support/guix_medical_mouse_support_specifications.c +++ b/test/example_internal/guix_medical_mouse_support/guix_medical_mouse_support_specifications.c @@ -59,6 +59,13 @@ GX_STUDIO_DISPLAY_INFO guix_medical_mouse_support_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -124,6 +131,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -189,6 +197,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -290,9 +299,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/test/example_internal/partial_frame_buffer_16bpp/partial_frame_buffer_16bpp_specifications.c b/test/example_internal/partial_frame_buffer_16bpp/partial_frame_buffer_16bpp_specifications.c index d4ea65dac..631411370 100644 --- a/test/example_internal/partial_frame_buffer_16bpp/partial_frame_buffer_16bpp_specifications.c +++ b/test/example_internal/partial_frame_buffer_16bpp/partial_frame_buffer_16bpp_specifications.c @@ -71,6 +71,13 @@ GX_STUDIO_DISPLAY_INFO partial_frame_buffer_16bpp_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -136,6 +143,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -201,6 +209,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -302,9 +311,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/test/example_internal/standalone_binres_load_16bpp/standalone_binres_load_16bpp_specifications.c b/test/example_internal/standalone_binres_load_16bpp/standalone_binres_load_16bpp_specifications.c index a2d817f73..e0d953e3a 100644 --- a/test/example_internal/standalone_binres_load_16bpp/standalone_binres_load_16bpp_specifications.c +++ b/test/example_internal/standalone_binres_load_16bpp/standalone_binres_load_16bpp_specifications.c @@ -60,6 +60,13 @@ GX_STUDIO_DISPLAY_INFO standalone_binres_load_16bpp_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -125,6 +132,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -190,6 +198,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -291,9 +300,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/test/example_internal/system_screen_stack/system_screen_stack_specifications.c b/test/example_internal/system_screen_stack/system_screen_stack_specifications.c index 4c1425718..a42160f0f 100644 --- a/test/example_internal/system_screen_stack/system_screen_stack_specifications.c +++ b/test/example_internal/system_screen_stack/system_screen_stack_specifications.c @@ -61,6 +61,13 @@ GX_STUDIO_DISPLAY_INFO system_screen_stack_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -126,6 +133,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -191,6 +199,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -292,9 +301,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/test/example_internal/template/template_specifications.c b/test/example_internal/template/template_specifications.c index b69f7a229..6e689eb44 100644 --- a/test/example_internal/template/template_specifications.c +++ b/test/example_internal/template/template_specifications.c @@ -59,6 +59,13 @@ GX_STUDIO_DISPLAY_INFO template_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -124,6 +131,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -189,6 +197,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -290,9 +299,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/test/guix_studio_test/test_demo/demo_compile/CMakeLists.txt b/test/guix_studio_test/test_demo/demo_compile/CMakeLists.txt index 814e788cc..8bb7bcd33 100644 --- a/test/guix_studio_test/test_demo/demo_compile/CMakeLists.txt +++ b/test/guix_studio_test/test_demo/demo_compile/CMakeLists.txt @@ -18,4 +18,8 @@ FOREACH(TEST_FILE ${TEST_SLN_FILE_LIST}) FILE(RELATIVE_PATH TEST_NAME "${CMAKE_CURRENT_SOURCE_DIR}/../../../../" ${TEST_FILE}) ADD_TEST(${TEST_NAME} python ${CMAKE_CURRENT_SOURCE_DIR}/../test_main.py -p ${TEST_FILE} --compile_project --debug) SET_TESTS_PROPERTIES(${TEST_NAME} PROPERTIES TIMEOUT 600) -ENDFOREACH() \ No newline at end of file +ENDFOREACH() + +#regression test for issue #172: Screen Flow output must build with an empty animation pool +ADD_TEST(animation_pool_size_zero python ${CMAKE_CURRENT_SOURCE_DIR}/../test_animation_pool_size.py --debug) +SET_TESTS_PROPERTIES(animation_pool_size_zero PROPERTIES TIMEOUT 1200) \ No newline at end of file diff --git a/test/guix_studio_test/test_demo/test_animation_pool_size.py b/test/guix_studio_test/test_demo/test_animation_pool_size.py new file mode 100644 index 000000000..6691569e7 --- /dev/null +++ b/test/guix_studio_test/test_demo/test_animation_pool_size.py @@ -0,0 +1,239 @@ +# Copyright (c) 2026 Eclipse ThreadX contributors +# +# This program and the accompanying materials are made available under the +# terms of the MIT License which is available at +# https://opensource.org/licenses/MIT. +# +# SPDX-License-Identifier: MIT +# Some portions generated by Claude Code (Opus 5). + +"""Regression test for https://github.com/eclipse-threadx/guix/issues/172. + +GUIX Studio emits five static helper functions in the generated specification +file as soon as a project uses Screen Flow. Two of them, +gx_studio_action_parent_find() and gx_studio_animation_execute(), are reachable +only from the GX_ACTION_TYPE_ANIMATION handler and call the GUIX animation API, +which is compiled out when GX_ANIMATION_POOL_SIZE is 0. The generator must +therefore guard them with "#if (GX_ANIMATION_POOL_SIZE > 0)", otherwise a Screen +Flow project cannot be built with an empty animation pool. + +The test runs in two stages: + +1. Source check: every checked-in generated specification file that uses Screen + Flow must guard the animation helpers. This stage needs no compiler. +2. Compile check: the same files are compiled with GX_ANIMATION_POOL_SIZE set to + 0. The MSVC warning about an implicit function declaration (C4013) is + promoted to an error so that the missing gx_system_animation_get() macro is + reported, which is what a linker or GCC 14 would reject. +""" + +import argparse +import logging +import os +import shutil +import subprocess +import sys +import tempfile + +import search_gxps + +ANIMATION_HELPER = 'gx_studio_animation_execute' +ANIMATION_GUARD = '#if (GX_ANIMATION_POOL_SIZE > 0)' + +# Every one of these must sit inside an ANIMATION_GUARD block. The first two are +# the definitions of the helpers that reference the animation API, the third is +# the switch case that calls them. A prototype or a call ends with a semicolon, +# so the check below ignores those lines and only looks at the definitions and +# at the case label. +GUARDED_LINES = ['static GX_WIDGET *gx_studio_action_parent_find(', + 'static VOID gx_studio_animation_execute(', + 'case GX_ACTION_TYPE_ANIMATION:'] + +# These projects were generated for GUIX 5.4.0 and 5.4.1, whose widget API is +# not source compatible with the current library, so they cannot be compiled +# standalone. The demo compile test skips them for the same reason. Their +# generated files are still covered by the source check below. +UNCOMPILABLE_PROJECTS = ['all_widgets_5_4_0', 'all_widgets_5_4_1'] + +# Scratch directories that some Studio projects generate into. They hold copies +# of the generated files, not sources, so they are not part of this test. +SCRATCH_DIRECTORIES = ['output_files', 'project_output_folder', + 'xml_output_folder'] + +GX_USER_CONTENT = """/* Generated by test_animation_pool_size.py. Do not edit. */ + +#ifndef GX_USER_H +#define GX_USER_H + +/* Build without the animation pool to make sure the code generated for Screen + Flow does not reference the animation API. */ +#define GX_ANIMATION_POOL_SIZE 0 + +#endif +""" + +# count[total, passed, failed] +count_source = [0, 0, 0] +count_compile = [0, 0, 0] + + +def find_screen_flow_files(root_dir): + """Return the generated specification files that use Screen Flow.""" + + files = [] + for pathname in search_gxps.files_find(['*_specifications.c'], root_dir): + if os.path.basename(os.path.dirname(pathname)) in SCRATCH_DIRECTORIES: + continue + + with open(pathname, 'r') as source: + if ANIMATION_HELPER in source.read(): + files.append(pathname) + return sorted(files) + + +def check_source(pathname): + """Verify that the animation helpers are guarded in one generated file.""" + + with open(pathname, 'r') as source: + lines = source.readlines() + + guard_depth = 0 + guarded = dict.fromkeys(GUARDED_LINES, False) + + for line in lines: + stripped = line.strip() + if stripped == ANIMATION_GUARD: + guard_depth += 1 + elif stripped.startswith('#if'): + if guard_depth: + guard_depth += 1 + elif stripped.startswith('#endif'): + if guard_depth: + guard_depth -= 1 + elif guard_depth and not stripped.endswith(';'): + for expected in guarded: + if stripped.startswith(expected): + guarded[expected] = True + + missing = [expected for expected in GUARDED_LINES if not guarded[expected]] + if missing: + logging.error('**Error** %s: "%s" not guarded by "%s"', + pathname, '", "'.join(missing), ANIMATION_GUARD) + return False + return True + + +def compile_file(pathname, root_dir, gx_user_dir, output_dir): + """Compile one generated file with an empty animation pool.""" + + command = ['cl', '/nologo', '/c', '/W3', + # An undeclared gx_system_animation_get() is only a warning for + # MSVC. Promote it so that this test fails the way a GCC 14 or a + # link step would. + '/we4013', + '/DGX_INCLUDE_USER_DEFINE_FILE', + '/DWIN32', '/D_DEBUG', '/D_WINDOWS', + '/D_CRT_SECURE_NO_WARNINGS', + '/Fo' + os.path.join(output_dir, '')] + + for directory in [gx_user_dir, + os.path.dirname(pathname), + os.path.join(root_dir, 'common', 'inc'), + os.path.join(root_dir, 'ports', 'win32', 'inc'), + os.path.join(root_dir, 'ports', 'win32', 'lib', 'vs_2019')]: + command += ['/I', directory] + + command.append(pathname) + + result = subprocess.run(command, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + output = result.stdout.decode(errors='replace') + logging.debug(output) + + if result.returncode: + logging.error('**Error** Compilation failed for %s', pathname) + logging.error(output) + return False + return True + + +def write_test_result(): + logging.info('********************************************') + logging.info(' Source checked files : %d', count_source[0]) + logging.info(' Passed : %d', count_source[1]) + logging.info(' Failed : %d', count_source[2]) + logging.info(' Compiled files : %d', count_compile[0]) + logging.info(' Passed : %d', count_compile[1]) + logging.info(' Failed : %d', count_compile[2]) + + +def __main__(): + # Change the current working directory to the path of this file. + current_path = os.path.split(os.path.realpath(__file__))[0] + os.chdir(current_path) + root_dir = os.path.realpath(os.path.join(current_path, '..', '..', '..')) + + parser = argparse.ArgumentParser( + description='Test Screen Flow output with GX_ANIMATION_POOL_SIZE = 0.') + parser.add_argument('--debug', action='store_true', dest='debug', + help='Print the debug logs to console.') + args = parser.parse_args() + + logging.basicConfig(filename='animation_pool_size_test_log.txt', + filemode='w', level=logging.DEBUG, format='%(message)s') + console = logging.StreamHandler() + console.setLevel(logging.DEBUG if args.debug else logging.INFO) + console.setFormatter(logging.Formatter('%(message)s')) + logging.getLogger('').addHandler(console) + + files = [] + for directory in ['samples', os.path.join('test', 'example_internal'), + 'tutorials']: + files += find_screen_flow_files(os.path.join(root_dir, directory)) + + if not files: + logging.error('**Error** No Screen Flow specification file found.') + return 1 + + logging.info('Found %d Screen Flow specification files.', len(files)) + + for pathname in files: + count_source[0] += 1 + if check_source(pathname): + count_source[1] += 1 + else: + count_source[2] += 1 + + if shutil.which('cl') is None: + logging.warning('** Skipped ** cl.exe not found on PATH, the compile ' + 'stage of this test did not run. Run the test from a ' + 'Visual Studio developer command prompt.') + else: + work_dir = tempfile.mkdtemp(prefix='gx_animation_pool_size_') + try: + with open(os.path.join(work_dir, 'gx_user.h'), 'w') as gx_user: + gx_user.write(GX_USER_CONTENT) + + for pathname in files: + project = os.path.basename(os.path.dirname(pathname)) + if project in UNCOMPILABLE_PROJECTS: + logging.info('Skipping %s, it targets a legacy GUIX API.', + pathname) + continue + + count_compile[0] += 1 + if compile_file(pathname, root_dir, work_dir, work_dir): + count_compile[1] += 1 + else: + count_compile[2] += 1 + finally: + shutil.rmtree(work_dir, ignore_errors=True) + + write_test_result() + + if count_source[2] or count_compile[2]: + return 1 + return 0 + + +sys.exit(__main__()) diff --git a/test/guix_studio_test/test_view/golden_files/all_widgets_execute_specifications.c b/test/guix_studio_test/test_view/golden_files/all_widgets_execute_specifications.c index ee626729c..50865501c 100644 --- a/test/guix_studio_test/test_view/golden_files/all_widgets_execute_specifications.c +++ b/test/guix_studio_test/test_view/golden_files/all_widgets_execute_specifications.c @@ -63,6 +63,13 @@ GX_STUDIO_DISPLAY_INFO all_widgets_execute_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -128,6 +135,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -176,6 +184,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -258,9 +267,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: parent = widget->gx_widget_parent; diff --git a/test/guix_studio_test/test_view/golden_files/template_specifications.c b/test/guix_studio_test/test_view/golden_files/template_specifications.c index 2c8966e7c..7f3f78d38 100644 --- a/test/guix_studio_test/test_view/golden_files/template_specifications.c +++ b/test/guix_studio_test/test_view/golden_files/template_specifications.c @@ -61,6 +61,13 @@ GX_STUDIO_DISPLAY_INFO template_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -126,6 +133,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -191,6 +199,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -292,9 +301,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/test/guix_studio_test/test_view/golden_files/trigger_target_rename_specifications.c b/test/guix_studio_test/test_view/golden_files/trigger_target_rename_specifications.c index 03c95c589..fe5a44354 100644 --- a/test/guix_studio_test/test_view/golden_files/trigger_target_rename_specifications.c +++ b/test/guix_studio_test/test_view/golden_files/trigger_target_rename_specifications.c @@ -57,6 +57,13 @@ GX_STUDIO_DISPLAY_INFO trigger_target_rename_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -122,6 +129,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -170,6 +178,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -252,9 +261,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: parent = widget->gx_widget_parent; diff --git a/tutorials/demo_guix_menu/demo_guix_menu_specifications.c b/tutorials/demo_guix_menu/demo_guix_menu_specifications.c index e618dea7c..d620c7b60 100644 --- a/tutorials/demo_guix_menu/demo_guix_menu_specifications.c +++ b/tutorials/demo_guix_menu/demo_guix_menu_specifications.c @@ -60,6 +60,13 @@ GX_STUDIO_DISPLAY_INFO demo_guix_menu_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -125,6 +132,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -190,6 +198,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -291,9 +300,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || diff --git a/tutorials/demo_guix_transitions/demo_guix_transitions_specifications.c b/tutorials/demo_guix_transitions/demo_guix_transitions_specifications.c index b31603713..878e6f92d 100644 --- a/tutorials/demo_guix_transitions/demo_guix_transitions_specifications.c +++ b/tutorials/demo_guix_transitions/demo_guix_transitions_specifications.c @@ -62,6 +62,13 @@ GX_STUDIO_DISPLAY_INFO demo_guix_transitions_display_table[1] = } }; +static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#if (GX_ANIMATION_POOL_SIZE > 0) +static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action); +#endif + static GX_WIDGET *gx_studio_action_target_get(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -127,6 +134,7 @@ static GX_WIDGET *gx_studio_action_target_find(GX_WIDGET *current, GX_CONST GX_S return target; } +#if (GX_ANIMATION_POOL_SIZE > 0) static GX_WIDGET *gx_studio_action_parent_find(GX_WIDGET *current, GX_CONST GX_STUDIO_ACTION *action) { GX_WIDGET *parent = GX_NULL; @@ -192,6 +200,7 @@ static VOID gx_studio_animation_execute(GX_WIDGET *current, GX_CONST GX_STUDIO_A } } } +#endif UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CONST GX_STUDIO_EVENT_PROCESS *record) { @@ -293,9 +302,11 @@ UINT gx_studio_auto_event_handler(GX_WIDGET *widget, GX_EVENT *event_ptr, GX_CON } break; +#if (GX_ANIMATION_POOL_SIZE > 0) case GX_ACTION_TYPE_ANIMATION: gx_studio_animation_execute(widget, action); break; +#endif case GX_ACTION_TYPE_WINDOW_EXECUTE: if((action->flags & GX_ACTION_FLAG_POP_TARGET) || From d049c7fa4f37181d7a1e6113a941257b13d9ebb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Thu, 27 Aug 2026 07:03:30 -0400 Subject: [PATCH 3/8] Revived the Windows workflows, which had reached no runner since 2025 (#174) * Revived the Windows workflows, which had reached no runner since 2025 The four GUIX Studio workflows requested `runs-on: windows-2019`, an image GitHub retired on 2025-06-30. Nothing can match a retired label, so every run queued for the full 24 hours and was then cancelled without ever starting a job: run 28477318708 created 2026-06-30T21:33:40Z cancelled 2026-07-01T21:33:41Z Every run of these workflows since 2025-09-29 has that same created-plus-24h-cancelled shape. The Studio demo, demo compile, view and MSIX package tests have gated nothing for about a year, and a manual workflow_dispatch on 2026-08-25 queued the same way. Three more defects were in the path behind that one, so fixing the image alone would not have produced a green run. - actions/upload-artifact was pinned at v3.1.3 in all four workflows. GitHub began auto-failing every request that used v3 on 2025-01-30, and both upload steps run under `if: success() || failure()`, so every run would have ended red even with the tests passing. - The scripts hard-coded a Visual Studio edition path. build_guix.cmd, test_studio_demo.cmd, test_studio_demo_compile.cmd and test_studio_view.cmd all call VS 2022 *Enterprise*, which no developer machine has, and build_guix_studio.cmd calls VS 2022 *Community*, which no GitHub runner has. So the demo test's build step would have failed on the first line. All five now locate the installation with vswhere, matching what build_guix_studio_msix_package.cmd already did, and check the result instead of assuming the call succeeded. Verified on a Community install, where the Enterprise path does not exist. - studio_msix_package.yml uploaded guix_studio/build/vs_2019/msix_package_project/AppPackages. That directory has not existed since the solution moved to vs_2022, which is where build_guix_studio_msix_package.cmd builds, so the artifact was always empty. Every action reference is now a 40-character commit SHA with the version in a trailing comment, following the pattern eclipse-threadx/threadx adopted in August 2026. A tag can be repointed at any commit; a SHA cannot, which is what makes "which code ran in our CI" answerable from the repository. Versions moved with the pinning: actions/checkout v4 -> v7.0.1 actions/upload-artifact v3.1.3 -> v7.0.1 EnricoMi/publish-unit-test-result-action v2 -> v2.24.0 Compatibility was checked against each new action.yml rather than assumed, for every input these workflows actually pass: checkout keeps `submodules`; upload-artifact keeps `name` and `path`, and the one upload per run means the v4 rule against uploading a name twice does not bite; the publish action keeps `check_name` and `files`, and the `composite` variant still exists at v2.24.0, which is the one a Windows runner needs. All three tags were confirmed to resolve to the SHAs pinned here, and all three are the current latest. The runner image is pinned rather than tracking windows-latest, on the same reasoning threadx applies to ubuntu-24.04: which image the build ran on should be a reviewable commit, not something that changes underneath it. Floating would have hidden this failure differently rather than preventing it. Also removed the dead `C:\Program Files\Python36` PATH lines. No supported runner image has shipped that Python for years, python is already on PATH there, and the lines embedded literal quote characters into PATH. The trigger branches are deliberately left alone in this commit. These workflows fire on master only, so they still gate no pull request to dev -- the same defect threadx fixed in its own suites. That wants a dispatch run to go green first, on evidence rather than hope, and is a separate change. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) * Added the Dependabot configuration the pinned actions need Follow-up to the pinning in the preceding commit. A SHA pin with nothing moving it is worse than a floating tag: it holds CI on whatever was current the day it was written. This repository is the case study for that. Nothing had ever reported that an action moved, so actions/upload-artifact sat at v3.1.3 in all four Windows workflows -- four majors behind, and a version GitHub began auto-failing every request for on 2025-01-30 -- while actions/checkout sat on an unpinned @v4, three majors behind. This adds .github/dependabot.yml: weekly, github-actions only, and closes the reference to that path which the pinning comment in each workflow now makes. Dependabot understands the SHA form and rewrites the trailing version comment together with the pin, so the comment cannot drift away from the SHA it describes. It follows the configuration eclipse-threadx/threadx added in August 2026, with three differences that are specific to this repository and documented in the file: - Only three distinct actions are in use, so the default limit of five would be enough. Ten is set anyway, to match the sibling repositories and to leave room for a wave of majors after a long gap. - There is no .github/CODEOWNERS here, so no reviewer routing exists for Dependabot to honour. Worth adding, but not by this file. - The "dependencies" label does not exist in this repository yet. Dependabot creates it on the first pull request. Two choices worth stating rather than leaving to be rediscovered. target-branch is dev. Dependabot reads this file from the default branch, which is master -- but master is deliberately kept behind dev, and pull requests belong on dev. So this arms on merge without firing: nothing happens until a release merge carries the file to master. Setting target-branch also opts out of Dependabot security updates, which only ever run against the default branch. For this ecosystem the cost is small, since an action advisory arrives as an ordinary bump on the weekly run, but it is a real trade. Patch and minor are grouped into a single pull request, because a queue reviewed one item at a time is a queue that gets ignored -- which is the failure mode this file exists to prevent. Majors stay ungrouped, one pull request each, because every breaking change met in an action here has been a major: upload-artifact v4 stopped allowing an artifact name to be uploaded twice in a run, and v6 requires a runner of 2.327.1 or newer. Dependabot reports drift, not silence. The Windows workflows rotted because they never reached a runner, not because nobody was told, and the runner image fix in the preceding commit is the cure for that half. The cross-repository reusable workflow in regression_test.yml is correctly left alone: it references a branch, so it carries no version to move. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) * Renamed the Studio IMAGE_INFO struct, which the Windows SDK now defines With the Windows workflows reaching a runner again, the Studio build failed immediately on both of them: guix_studio\system_pngs.h(15,8): error C2011: 'IMAGE_INFO': 'struct' type redefinition Windows Kits\10\Include\10.0.26100.0\um\Filter.h(340,16): error C2011: 'IMAGE_INFO': 'struct' type redefinition plus eight C2027 "use of undefined type" errors following from it. guix_studio declared its own two-field `IMAGE_INFO` in the global namespace. A newer Windows SDK added a struct of the same name to um/Filter.h, which arrives through the Windows headers the MFC sources already include. SDK 10.0.22621.0 does not define it; 10.0.26100.0 does. This was latent rather than new. studiox.vcxproj sets `10.0`, the MSBuild wildcard for "newest installed SDK", so which SDK compiles the Studio depends entirely on the machine. A developer box with 22621 as its newest builds; the runner image, which carries 26100, does not. The collision was simply waiting for whichever came first. Renamed the Studio type to STUDIO_IMAGE_INFO -- 13 references across five files. It is private to the Studio, so nothing outside guix_studio sees the name. Also dropped the `-winsdk=10.0.22621.0` argument that build_guix_studio.cmd passed to VsDevCmd. It never had the effect it looks like it has: the wildcard in the project file governs the SDK the compile actually uses, so the argument only set the shell environment and left MSBuild to pick the newest SDK anyway. Keeping it would suggest the build is pinned to an SDK when it is not. With the collision fixed there is nothing to pin against. Verified by rebuilding the Studio against SDK 10.0.22621.0 locally; the runner will exercise 10.0.26100.0. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) * Pointed the demo test back at the guix project that exists The demo compile test could not build the GUIX library at all: Exception: guix.sln not found. path=../../../ports/win32/build/vs_2022/guix.vcxproj 522aafcc ("Updated scripts for VS Community 2022", February 2025) moved three paths in test_main.py from vs_2019 to vs_2022. Two of them were right: guix_studio/build/vs_2019 really had been renamed to vs_2022. The third was collateral damage from the same search and replace -- ports/win32/build/vs_2019 was never renamed, and still holds the only guix.vcxproj and guix.sln in the repository. So --build_guix has raised this exception for eighteen months, before compiling a single library configuration. Nothing said so, because the workflow that calls it never reached a runner. Restored the vs_2019 path. Verified by building the library locally: guix.vcxproj is Win32-only and still on PlatformToolset v142, and it produces Debug/gx.lib. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) * Pointed the view test at the Studio build directory that exists The Studio view test could not start the Studio at all: MSBUILD : error MSB1009: Project file does not exist. Switch: ../../../guix_studio/build/vs_2019/studiox.sln Exception: Unable to locate Studio executable. 522aafcc ("Updated scripts for VS Community 2022", February 2025) renamed guix_studio/build/vs_2019 to vs_2022 and updated test_demo/test_main.py for it, but never touched the test_view directory. Three references there still named the old directory: - test_view/test_main.py project_sln_path - test_view/test_utils.py studio_exe_path - test_view/test_string_import_export.py studio_release So this suite has been unable to locate the Studio for eighteen months. Like the guix.vcxproj path in the preceding commit, nothing reported it, because the workflow that runs it never reached a runner. The remaining build/vs_2019 references in the tree belong to ports/win32/build/vs_2019, which is a real directory and is left alone. This commit makes the suite able to find and launch the Studio. Whether it then passes on a hosted runner is a separate question -- it drives the Studio through win32 window handles, and no run has got far enough to say. Its trigger branches are deliberately not changed here for that reason. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) * Ran the Studio demo suites on dev, where the pull requests actually are The demo and demo compile workflows trigger on master only, for both push and pull_request. dev is the integration branch, so these suites have gated no pull request that anybody opened -- the same defect eclipse-threadx/threadx fixed in its own regression suites in August 2026. Switched on only after both suites were verified green on a runner, on this branch, rather than on the assumption that they would be: GUIX Studio Demo Test 227 of 227 generation tests 147 s GUIX Studio Demo Compile Test 212 of 212 compile tests 146 s The other three workflows are deliberately left on their current triggers, and each for its own reason: - regression_test.yml does reach a runner, and is red. Its last real run, 2026-06-30, was 5 failures out of 732: accordion menu, ml_text_view_32bpp, animation_complete, animation_complete_push_stack and one more. Adding dev here would make every pull request red on a suite that has been broken since June. It needs fixing first, and that is not this change. - studio_view_test.yml can now find the Studio again, but no run has got far enough to say whether GUI automation through win32 window handles survives a hosted runner. Enabling gating on an unknown is what this commit is written to avoid. - studio_msix_package.yml is workflow_dispatch only by design. It packages a release rather than testing a change, so there is nothing to gate. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) --------- Co-authored-by: Claude Opus 5 (1M context) --- .github/dependabot.yml | 100 ++++++++++++++++++ .github/workflows/studio_demo_test.yml | 30 ++++-- .../workflows/studio_demo_test_compile.yml | 30 ++++-- .github/workflows/studio_msix_package.yml | 18 +++- .github/workflows/studio_view_test.yml | 18 +++- guix_studio/StudioXProject.cpp | 11 +- guix_studio/resource_gen.cpp | 3 +- guix_studio/resource_view.h | 5 +- guix_studio/system_pngs.cpp | 9 +- guix_studio/system_pngs.h | 3 +- scripts/build_guix.cmd | 23 +++- scripts/build_guix_studio.cmd | 23 +++- scripts/test_studio_demo.cmd | 23 +++- scripts/test_studio_demo_compile.cmd | 23 +++- scripts/test_studio_view.cmd | 23 +++- test/guix_studio_test/test_demo/test_main.py | 2 +- test/guix_studio_test/test_view/test_main.py | 2 +- .../test_view/test_string_import_export.py | 2 +- test/guix_studio_test/test_view/test_utils.py | 2 +- 19 files changed, 282 insertions(+), 68 deletions(-) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..c34e84e89 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,100 @@ +version: 2 + +# Keeps the pinned action SHAs moving. +# +# Every action reference under .github/workflows is a 40-character commit SHA +# with the version in a trailing comment. A SHA pin *without* this file is worse +# than a floating tag: it freezes CI on whatever was current the day it was +# written. This repository is the case study. Nothing had ever reported that an +# action moved, so actions/upload-artifact sat on v3.1.3 in all four Windows +# workflows -- four majors behind, and a version GitHub began auto-failing on +# 2025-01-30. actions/checkout sat on an unpinned @v4, three majors behind. +# +# Dependabot understands the SHA form and rewrites the trailing version comment +# together with the pin, so the comment cannot drift away from the SHA it +# describes. That is what keeps "which exact code ran in our CI" answerable from +# the repository, which the SBOM and certification work needs on its own. +# +# This follows the pattern set by eclipse-threadx/threadx, which added the same +# configuration in August 2026 after the same drift was measured there. +# +# What this does not fix: it reports drift, not silence. A workflow that never +# triggers rots unnoticed no matter what is pinned in it, and this repository had +# that failure in its more severe form -- the four Windows workflows requested +# runs-on: windows-2019 for more than a year after GitHub retired that image, so +# every run queued for 24 hours and was cancelled without reaching a runner. No +# amount of pinning would have said so. The runner image fix is a separate +# change; this file is the drift half only. +# +# There is no entry for any other ecosystem, and that is a decision rather than +# an oversight: the project forbids external dependencies and there are no +# submodules. The one pinned toolchain input -- the Windows SDK version passed +# to VsDevCmd in scripts/build_guix_studio.cmd -- lives in a batch file that no +# Dependabot ecosystem can parse. That pin moves by hand. +updates: + - package-ecosystem: "github-actions" + # "/" is the only accepted value for this ecosystem; it covers + # .github/workflows and .github/actions. The cross-repository reusable + # workflow in regression_test.yml + # (eclipse-threadx/threadx/.github/workflows/regression_template.yml@master) + # is correctly left alone: it references a branch, not a version, so there + # is nothing for Dependabot to move. Tracking that branch is deliberate -- + # it is first-party, in the same organisation, and it means this repository + # picks up harness fixes without a bump here. + directory: "/" + + schedule: + interval: "weekly" + day: "monday" + time: "06:00" + timezone: "Etc/UTC" + + # Dependabot reads this file from the repository's DEFAULT branch, which is + # master. But master is deliberately kept behind dev, and pull requests + # belong on dev. target-branch sends the pull requests to dev and makes + # Dependabot read the workflows it is updating from dev as well. + # + # The consequence to plan for: landing this file on dev arms it, it does not + # fire it. Nothing happens until a release merge carries it to master. + # + # Setting target-branch also opts out of Dependabot *security* updates, + # which only ever run against the default branch. For this ecosystem the + # cost is small -- an action advisory arrives as an ordinary version bump on + # the weekly run -- but it is a real trade and not a detail to rediscover + # later. + target-branch: "dev" + + groups: + # Patch and minor arrive together in one pull request: they are the + # routine traffic, and reviewing them one at a time is how an update queue + # starts being ignored, which is the failure mode this file exists to + # prevent. Majors stay ungrouped, one pull request each, because every + # breaking change met in an action here has been a major: upload-artifact + # v4 stopped allowing an artifact name to be uploaded twice in a run, and + # v6 requires a runner of 2.327.1 or newer. + actions-minor-and-patch: + patterns: + - "*" + update-types: + - "minor" + - "patch" + + # Only three distinct actions are in use today -- actions/checkout, + # actions/upload-artifact and EnricoMi/publish-unit-test-result-action -- so + # the default limit of five would be enough for now. Ten is set to match the + # sibling repositories and to leave room for a wave of majors after a long + # gap, which is exactly the situation this file is being added into. + open-pull-requests-limit: 10 + + # This repository has no "dependencies" label yet; Dependabot creates it on + # the first pull request. + labels: + - "dependencies" + + # Reviewers are not listed. Unlike eclipse-threadx/threadx this repository + # has no .github/CODEOWNERS, so there is no path routing for Dependabot to + # honour. Adding one is worth doing, but it is not this file's job. + # + # Commit subjects are left at Dependabot's own "Bump x from a to b" wording. + # The project asks for a past-tense subject and still gets one: these pull + # requests are squash-merged, and the subject is set at that point. diff --git a/.github/workflows/studio_demo_test.yml b/.github/workflows/studio_demo_test.yml index 1acc41033..ac48a7d75 100644 --- a/.github/workflows/studio_demo_test.yml +++ b/.github/workflows/studio_demo_test.yml @@ -6,19 +6,22 @@ # https://opensource.org/licenses/MIT. # # SPDX-License-Identifier: MIT +# Some portions generated by Claude Code (Opus 5). # This is a basic workflow that is manually triggered name: GUIX Studio Demo Test -# Controls when the action will run. Triggers the workflow on push or pull request -# events but only for the master branch +# Controls when the action will run. dev is included deliberately: it is the +# integration branch, so a master-only trigger gated no pull request that +# anybody opened. Verified green on a runner before being switched on -- +# 227 of 227 generation tests and 212 of 212 compile tests. on: - workflow_dispatch: + workflow_dispatch: push: - branches: [ master ] + branches: [ master, dev ] pull_request: - branches: [ master ] + branches: [ master, dev ] # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: @@ -31,12 +34,21 @@ jobs: pull-requests: write # The type of runner that the job will run on - runs-on: windows-2019 + # Pinned deliberately rather than windows-latest: the image this job + # needs has to be a reviewable commit, not something that changes + # underneath the build. windows-2019 sat here until 2026-08-26, more + # than a year after GitHub retired that image, so every run queued for + # 24 hours and was then cancelled without ever reaching a runner. + runs-on: windows-2022 # Steps represent a sequence of tasks that will be executed as part of the job steps: + # Actions are pinned to a commit SHA, with the version in the trailing + # comment. A tag can be moved; a SHA cannot, so this is what makes "which + # code ran in CI" answerable from the repository. Dependabot moves these + # pins and rewrites the comment with them -- see .github/dependabot.yml. - name: Check out the repository - uses: actions/checkout@v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: submodules: true @@ -47,7 +59,7 @@ jobs: run: scripts\test_studio_demo.cmd - name: Publish Test Results - uses: EnricoMi/publish-unit-test-result-action/composite@v2 + uses: EnricoMi/publish-unit-test-result-action/composite@d0a4676d0e0b938bc201470d88276b7c74c712b3 # v2.24.0 if: always() with: check_name: Test Results GUIX Studio Demo @@ -56,7 +68,7 @@ jobs: - name: Upload Test Results if: success() || failure() - uses: actions/upload-artifact@v3.1.3 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: test_reports path: | diff --git a/.github/workflows/studio_demo_test_compile.yml b/.github/workflows/studio_demo_test_compile.yml index 897eb3fcd..a5c9142c9 100644 --- a/.github/workflows/studio_demo_test_compile.yml +++ b/.github/workflows/studio_demo_test_compile.yml @@ -6,19 +6,22 @@ # https://opensource.org/licenses/MIT. # # SPDX-License-Identifier: MIT +# Some portions generated by Claude Code (Opus 5). # This is a basic workflow that is manually triggered name: GUIX Studio Demo Compile Test -# Controls when the action will run. Triggers the workflow on push or pull request -# events but only for the master branch +# Controls when the action will run. dev is included deliberately: it is the +# integration branch, so a master-only trigger gated no pull request that +# anybody opened. Verified green on a runner before being switched on -- +# 227 of 227 generation tests and 212 of 212 compile tests. on: - workflow_dispatch: + workflow_dispatch: push: - branches: [ master ] + branches: [ master, dev ] pull_request: - branches: [ master ] + branches: [ master, dev ] # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: @@ -31,12 +34,21 @@ jobs: pull-requests: write # The type of runner that the job will run on - runs-on: windows-2019 + # Pinned deliberately rather than windows-latest: the image this job + # needs has to be a reviewable commit, not something that changes + # underneath the build. windows-2019 sat here until 2026-08-26, more + # than a year after GitHub retired that image, so every run queued for + # 24 hours and was then cancelled without ever reaching a runner. + runs-on: windows-2022 # Steps represent a sequence of tasks that will be executed as part of the job steps: + # Actions are pinned to a commit SHA, with the version in the trailing + # comment. A tag can be moved; a SHA cannot, so this is what makes "which + # code ran in CI" answerable from the repository. Dependabot moves these + # pins and rewrites the comment with them -- see .github/dependabot.yml. - name: Check out the repository - uses: actions/checkout@v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: submodules: true @@ -47,7 +59,7 @@ jobs: run: scripts\test_studio_demo_compile.cmd - name: Publish Test Results - uses: EnricoMi/publish-unit-test-result-action/composite@v2 + uses: EnricoMi/publish-unit-test-result-action/composite@d0a4676d0e0b938bc201470d88276b7c74c712b3 # v2.24.0 if: always() with: check_name: Test Results GUIX Studio Demo Compile @@ -56,7 +68,7 @@ jobs: - name: Upload Test Results if: success() || failure() - uses: actions/upload-artifact@v3.1.3 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: test_reports path: | diff --git a/.github/workflows/studio_msix_package.yml b/.github/workflows/studio_msix_package.yml index 2ff833560..cce0d49da 100644 --- a/.github/workflows/studio_msix_package.yml +++ b/.github/workflows/studio_msix_package.yml @@ -6,6 +6,7 @@ # https://opensource.org/licenses/MIT. # # SPDX-License-Identifier: MIT +# Some portions generated by Claude Code (Opus 5). # This is a basic workflow that is manually triggered @@ -26,12 +27,21 @@ jobs: pull-requests: write # The type of runner that the job will run on - runs-on: windows-2019 + # Pinned deliberately rather than windows-latest: the image this job + # needs has to be a reviewable commit, not something that changes + # underneath the build. windows-2019 sat here until 2026-08-26, more + # than a year after GitHub retired that image, so every run queued for + # 24 hours and was then cancelled without ever reaching a runner. + runs-on: windows-2022 # Steps represent a sequence of tasks that will be executed as part of the job steps: + # Actions are pinned to a commit SHA, with the version in the trailing + # comment. A tag can be moved; a SHA cannot, so this is what makes "which + # code ran in CI" answerable from the repository. Dependabot moves these + # pins and rewrites the comment with them -- see .github/dependabot.yml. - name: Check out the repository - uses: actions/checkout@v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: submodules: true @@ -39,9 +49,9 @@ jobs: run: scripts/build_guix_studio_msix_package.cmd - name: Upload GUIX Studio package upload file - uses: actions/upload-artifact@v3.1.3 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: GUIXStudioPackages - path: guix_studio/build/vs_2019/msix_package_project/AppPackages + path: guix_studio/build/vs_2022/msix_package_project/AppPackages \ No newline at end of file diff --git a/.github/workflows/studio_view_test.yml b/.github/workflows/studio_view_test.yml index dac9be92d..cc4b2cb2d 100644 --- a/.github/workflows/studio_view_test.yml +++ b/.github/workflows/studio_view_test.yml @@ -6,6 +6,7 @@ # https://opensource.org/licenses/MIT. # # SPDX-License-Identifier: MIT +# Some portions generated by Claude Code (Opus 5). # This is a basic workflow that is manually triggered @@ -31,12 +32,21 @@ jobs: pull-requests: write # The type of runner that the job will run on - runs-on: windows-2019 + # Pinned deliberately rather than windows-latest: the image this job + # needs has to be a reviewable commit, not something that changes + # underneath the build. windows-2019 sat here until 2026-08-26, more + # than a year after GitHub retired that image, so every run queued for + # 24 hours and was then cancelled without ever reaching a runner. + runs-on: windows-2022 # Steps represent a sequence of tasks that will be executed as part of the job steps: + # Actions are pinned to a commit SHA, with the version in the trailing + # comment. A tag can be moved; a SHA cannot, so this is what makes "which + # code ran in CI" answerable from the repository. Dependabot moves these + # pins and rewrites the comment with them -- see .github/dependabot.yml. - name: Check out the repository - uses: actions/checkout@v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: submodules: true @@ -47,7 +57,7 @@ jobs: run: scripts\test_studio_view.cmd - name: Publish Test Results - uses: EnricoMi/publish-unit-test-result-action/composite@v2 + uses: EnricoMi/publish-unit-test-result-action/composite@d0a4676d0e0b938bc201470d88276b7c74c712b3 # v2.24.0 if: always() with: check_name: Test Results GUIX Studio View @@ -56,7 +66,7 @@ jobs: - name: Upload Test Results if: success() || failure() - uses: actions/upload-artifact@v3.1.3 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: test_reports path: | diff --git a/guix_studio/StudioXProject.cpp b/guix_studio/StudioXProject.cpp index 527878a9d..517a99537 100644 --- a/guix_studio/StudioXProject.cpp +++ b/guix_studio/StudioXProject.cpp @@ -9,6 +9,7 @@ * SPDX-License-Identifier: MIT **************************************************************************/ // Some portions generated by Codex (OpenAI GPT-5.5). +// Some portions generated by Claude Code (Opus 5). #include "system_pngs.h" @@ -254,10 +255,10 @@ FONT_RECORD DEFAULT_FONT_TABLE[] = { {NULL, -1, NULL} }; -extern IMAGE_INFO _system_png_radio_on; -extern IMAGE_INFO _system_png_radio_off; -extern IMAGE_INFO _system_png_checkbox_on; -extern IMAGE_INFO _system_png_checkbox_off; +extern STUDIO_IMAGE_INFO _system_png_radio_on; +extern STUDIO_IMAGE_INFO _system_png_radio_off; +extern STUDIO_IMAGE_INFO _system_png_checkbox_on; +extern STUDIO_IMAGE_INFO _system_png_checkbox_off; // FIXME: do we want to use hardcoded path? PIXELMAP_RECORD DEFAULT_PIXELMAP_TABLE[] = { @@ -1521,7 +1522,7 @@ BOOL studiox_project::InitializeOnePixelmap(res_info *info, palette_info *theme_ image_reader *pReader = NULL; CString abspath; - IMAGE_INFO *default_image_info = NULL; + STUDIO_IMAGE_INFO *default_image_info = NULL; int frame_count = 1; int frame_id = -1; diff --git a/guix_studio/resource_gen.cpp b/guix_studio/resource_gen.cpp index 5be93459d..cc24e35ab 100644 --- a/guix_studio/resource_gen.cpp +++ b/guix_studio/resource_gen.cpp @@ -9,6 +9,7 @@ * SPDX-License-Identifier: MIT **************************************************************************/ // Some portions generated by Codex (OpenAI GPT-5.5). +// Some portions generated by Claude Code (Opus 5). @@ -4156,7 +4157,7 @@ GX_PIXELMAP* resource_gen::RotatePixelmap(res_info* info, int theme_id, GX_PIXEL image_reader *pReader = NULL; CString abspath; - IMAGE_INFO* default_image_info = NULL; + STUDIO_IMAGE_INFO* default_image_info = NULL; int frame_count = 1; if (info->is_default && info->pathinfo.pathname.IsEmpty()) diff --git a/guix_studio/resource_view.h b/guix_studio/resource_view.h index f0296d399..8c6dcc452 100644 --- a/guix_studio/resource_view.h +++ b/guix_studio/resource_view.h @@ -8,6 +8,7 @@ * * SPDX-License-Identifier: MIT **************************************************************************/ +// Some portions generated by Claude Code (Opus 5). @@ -16,7 +17,7 @@ #include class resource_view_provider; -struct IMAGE_INFO; +struct STUDIO_IMAGE_INFO; struct COLOR_RECORD { char *name; @@ -34,7 +35,7 @@ struct PIXELMAP_RECORD { char *name; int pixelmap_id; BOOL include_alpha; - IMAGE_INFO *image_info; + STUDIO_IMAGE_INFO *image_info; }; struct font_table { diff --git a/guix_studio/system_pngs.cpp b/guix_studio/system_pngs.cpp index f78df6074..b4fd771cb 100644 --- a/guix_studio/system_pngs.cpp +++ b/guix_studio/system_pngs.cpp @@ -8,6 +8,7 @@ * * SPDX-License-Identifier: MIT **************************************************************************/ +// Some portions generated by Claude Code (Opus 5). #include "system_pngs.h" @@ -112,22 +113,22 @@ static unsigned char SYSTEM_PNG_CHECKBOX_OFF_pixelmap_data[519] = 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; -IMAGE_INFO _system_png_radio_on = { +STUDIO_IMAGE_INFO _system_png_radio_on = { SYSTEM_PNG_RADIO_ON_pixelmap_data, sizeof(SYSTEM_PNG_RADIO_ON_pixelmap_data) }; -IMAGE_INFO _system_png_radio_off = { +STUDIO_IMAGE_INFO _system_png_radio_off = { SYSTEM_PNG_RADIO_OFF_pixelmap_data, sizeof(SYSTEM_PNG_RADIO_ON_pixelmap_data) }; -IMAGE_INFO _system_png_checkbox_on = { +STUDIO_IMAGE_INFO _system_png_checkbox_on = { SYSTEM_PNG_CHECKBOX_ON_pixelmap_data, sizeof(SYSTEM_PNG_CHECKBOX_ON_pixelmap_data) }; -IMAGE_INFO _system_png_checkbox_off = { +STUDIO_IMAGE_INFO _system_png_checkbox_off = { SYSTEM_PNG_CHECKBOX_OFF_pixelmap_data, sizeof(SYSTEM_PNG_CHECKBOX_OFF_pixelmap_data) }; \ No newline at end of file diff --git a/guix_studio/system_pngs.h b/guix_studio/system_pngs.h index 910499c09..1b3cff036 100644 --- a/guix_studio/system_pngs.h +++ b/guix_studio/system_pngs.h @@ -8,11 +8,12 @@ * * SPDX-License-Identifier: MIT **************************************************************************/ +// Some portions generated by Claude Code (Opus 5). #ifndef _SYSTEM_PNGS_ #define _SYSTEM_PNGS_ -struct IMAGE_INFO { +struct STUDIO_IMAGE_INFO { unsigned char* data; int data_len; }; diff --git a/scripts/build_guix.cmd b/scripts/build_guix.cmd index 205723baa..647d4ca44 100644 --- a/scripts/build_guix.cmd +++ b/scripts/build_guix.cmd @@ -7,13 +7,26 @@ @rem @rem SPDX-License-Identifier: MIT @rem Some portions generated by Codex (OpenAI GPT-5.5). +@rem Some portions generated by Claude Code (Opus 5). -rem Initialize the developer environment just like a developer box. Note that 'call' keyword that ensures that the script does not exist after -rem calling the other batch file. -call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 +rem Initialize the developer environment just like a developer box. The Visual +rem Studio edition differs between a developer machine and a GitHub runner, so +rem locate the installation with vswhere rather than assuming an edition path. +rem Note the 'call' keyword, which ensures that this script does not exit when +rem the other batch file returns. +set "VSINSTALL=" +set "VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" +if exist "%VSWHERE%" ( + for /f "usebackq tokens=*" %%i in (`"%VSWHERE%" -latest -products * -requires Microsoft.Component.MSBuild -property installationPath`) do set "VSINSTALL=%%i" +) -rem Set Python path -SET PATH=%PATH%;"C:\Program Files\Python36";"C:\Program Files\Python36\scripts" +if not defined VSINSTALL ( + echo Visual Studio 2022 with MSBuild was not found. + exit /B 1 +) + +call "%VSINSTALL%\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 +if ERRORLEVEL 1 exit /B %ERRORLEVEL% rem Save working directory so that we can restore it back after building everything. This will make developers happy and then rem switch to the folder this script resides in. Don't assume absolute paths because on the build host and on the dev host the locations may be different. diff --git a/scripts/build_guix_studio.cmd b/scripts/build_guix_studio.cmd index 6bebc2c7d..600a05ed3 100644 --- a/scripts/build_guix_studio.cmd +++ b/scripts/build_guix_studio.cmd @@ -6,15 +6,28 @@ @rem https://opensource.org/licenses/MIT. @rem @rem SPDX-License-Identifier: MIT +@rem Some portions generated by Claude Code (Opus 5). @echo off -rem Initialize the developer environment just like a developer box. Note that 'call' keyword that ensures that the script does not exist after -rem calling the other batch file. -call "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 -winsdk=10.0.22621.0 +rem Initialize the developer environment just like a developer box. The Visual +rem Studio edition differs between a developer machine and a GitHub runner, so +rem locate the installation with vswhere rather than assuming an edition path. +rem Note the 'call' keyword, which ensures that this script does not exit when +rem the other batch file returns. +set "VSINSTALL=" +set "VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" +if exist "%VSWHERE%" ( + for /f "usebackq tokens=*" %%i in (`"%VSWHERE%" -latest -products * -requires Microsoft.Component.MSBuild -property installationPath`) do set "VSINSTALL=%%i" +) -rem Set Python path. Not needed if installed with WinGet. -rem SET PATH=%PATH%;"C:\Program Files\Python36";"C:\Program Files\Python36\scripts" +if not defined VSINSTALL ( + echo Visual Studio 2022 with MSBuild was not found. + exit /B 1 +) + +call "%VSINSTALL%\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 +if ERRORLEVEL 1 exit /B %ERRORLEVEL% rem Save working directory so that we can restore it back after building everything. This will make developers happy and then rem switch to the folder this script resides in. Don't assume absolute paths because on the build host and on the dev host the locations may be different. diff --git a/scripts/test_studio_demo.cmd b/scripts/test_studio_demo.cmd index 3143f485c..4a6bbca64 100644 --- a/scripts/test_studio_demo.cmd +++ b/scripts/test_studio_demo.cmd @@ -7,13 +7,26 @@ @rem @rem SPDX-License-Identifier: MIT @rem Some portions generated by Codex (OpenAI GPT-5.5). +@rem Some portions generated by Claude Code (Opus 5). -rem Initialize the developer environment just like a developer box. Note that 'call' keyword that ensures that the script does not exist after -rem calling the other batch file. -call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 +rem Initialize the developer environment just like a developer box. The Visual +rem Studio edition differs between a developer machine and a GitHub runner, so +rem locate the installation with vswhere rather than assuming an edition path. +rem Note the 'call' keyword, which ensures that this script does not exit when +rem the other batch file returns. +set "VSINSTALL=" +set "VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" +if exist "%VSWHERE%" ( + for /f "usebackq tokens=*" %%i in (`"%VSWHERE%" -latest -products * -requires Microsoft.Component.MSBuild -property installationPath`) do set "VSINSTALL=%%i" +) -rem Set Python path -SET PATH=%PATH%;"C:\Program Files\Python36";"C:\Program Files\Python36\scripts" +if not defined VSINSTALL ( + echo Visual Studio 2022 with MSBuild was not found. + exit /B 1 +) + +call "%VSINSTALL%\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 +if ERRORLEVEL 1 exit /B %ERRORLEVEL% rem Save working directory so that we can restore it back after building everything. This will make developers happy and then rem switch to the folder this script resides in. Don't assume absolute paths because on the build host and on the dev host the locations may be different. diff --git a/scripts/test_studio_demo_compile.cmd b/scripts/test_studio_demo_compile.cmd index 5a08cf24f..217cff9a1 100644 --- a/scripts/test_studio_demo_compile.cmd +++ b/scripts/test_studio_demo_compile.cmd @@ -7,13 +7,26 @@ @rem @rem SPDX-License-Identifier: MIT @rem Some portions generated by Codex (OpenAI GPT-5.5). +@rem Some portions generated by Claude Code (Opus 5). -rem Initialize the developer environment just like a developer box. Note that 'call' keyword that ensures that the script does not exist after -rem calling the other batch file. -call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 +rem Initialize the developer environment just like a developer box. The Visual +rem Studio edition differs between a developer machine and a GitHub runner, so +rem locate the installation with vswhere rather than assuming an edition path. +rem Note the 'call' keyword, which ensures that this script does not exit when +rem the other batch file returns. +set "VSINSTALL=" +set "VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" +if exist "%VSWHERE%" ( + for /f "usebackq tokens=*" %%i in (`"%VSWHERE%" -latest -products * -requires Microsoft.Component.MSBuild -property installationPath`) do set "VSINSTALL=%%i" +) -rem Set Python path -SET PATH=%PATH%;"C:\Program Files\Python36";"C:\Program Files\Python36\scripts" +if not defined VSINSTALL ( + echo Visual Studio 2022 with MSBuild was not found. + exit /B 1 +) + +call "%VSINSTALL%\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 +if ERRORLEVEL 1 exit /B %ERRORLEVEL% rem Save working directory so that we can restore it back after building everything. This will make developers happy and then rem switch to the folder this script resides in. Don't assume absolute paths because on the build host and on the dev host the locations may be different. diff --git a/scripts/test_studio_view.cmd b/scripts/test_studio_view.cmd index fa7724a41..2bcda14b6 100644 --- a/scripts/test_studio_view.cmd +++ b/scripts/test_studio_view.cmd @@ -7,13 +7,26 @@ @rem @rem SPDX-License-Identifier: MIT @rem Some portions generated by Codex (OpenAI GPT-5.5). +@rem Some portions generated by Claude Code (Opus 5). -rem Initialize the developer environment just like a developer box. Note that 'call' keyword that ensures that the script does not exist after -rem calling the other batch file. -call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 +rem Initialize the developer environment just like a developer box. The Visual +rem Studio edition differs between a developer machine and a GitHub runner, so +rem locate the installation with vswhere rather than assuming an edition path. +rem Note the 'call' keyword, which ensures that this script does not exit when +rem the other batch file returns. +set "VSINSTALL=" +set "VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" +if exist "%VSWHERE%" ( + for /f "usebackq tokens=*" %%i in (`"%VSWHERE%" -latest -products * -requires Microsoft.Component.MSBuild -property installationPath`) do set "VSINSTALL=%%i" +) -rem Set Python path -SET PATH=%PATH%;"C:\Program Files\Python36";"C:\Program Files\Python36\scripts" +if not defined VSINSTALL ( + echo Visual Studio 2022 with MSBuild was not found. + exit /B 1 +) + +call "%VSINSTALL%\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 +if ERRORLEVEL 1 exit /B %ERRORLEVEL% rem Save working directory so that we can restore it back after building everything. This will make developers happy and then rem switch to the folder this script resides in. Don't assume absolute paths because on the build host and on the dev host the locations may be different. diff --git a/test/guix_studio_test/test_demo/test_main.py b/test/guix_studio_test/test_demo/test_main.py index 76f5af255..7b2f8ebf7 100644 --- a/test/guix_studio_test/test_demo/test_main.py +++ b/test/guix_studio_test/test_demo/test_main.py @@ -641,7 +641,7 @@ def __main__(): os.chdir(current_path) studio_sln_path = "../../../guix_studio/build/vs_2022/studiox.sln" studio_exe_path = "../../../guix_studio/build/vs_2022/Release/guix_studio.exe" - guix_project_path = "../../../ports/win32/build/vs_2022/guix.vcxproj" + guix_project_path = "../../../ports/win32/build/vs_2019/guix.vcxproj" gxp_projects = [] diff --git a/test/guix_studio_test/test_view/test_main.py b/test/guix_studio_test/test_view/test_main.py index 1146e3558..6cf431b4d 100644 --- a/test/guix_studio_test/test_view/test_main.py +++ b/test/guix_studio_test/test_view/test_main.py @@ -82,7 +82,7 @@ def __main__(): logging.basicConfig(stream=test_utils.test_log_stream, level=logging.DEBUG, format=Format) msbuild_exe_path = "C:/Windows/Microsoft.NET/Framework64/v4.0.30319/MSBuild.exe" - project_sln_path = "../../../guix_studio/build/vs_2019/studiox.sln" + project_sln_path = "../../../guix_studio/build/vs_2022/studiox.sln" parser = argparse.ArgumentParser(description = "Test Studio UI") parser.add_argument('-b', action='store_true', dest='build_studio', help='Build Studio') diff --git a/test/guix_studio_test/test_view/test_string_import_export.py b/test/guix_studio_test/test_view/test_string_import_export.py index 231b8d039..db513bbcf 100644 --- a/test/guix_studio_test/test_view/test_string_import_export.py +++ b/test/guix_studio_test/test_view/test_string_import_export.py @@ -98,7 +98,7 @@ def csv_string_import_export(): print("import string from command line") test_utils.toolbar_save() test_utils.close_project(1) - studio_release = test_utils.DEFAULT_OUTPUT_FILE_PATH + "../../../../guix_studio/build/vs_2019/Release/guix_studio.exe" + studio_release = test_utils.DEFAULT_OUTPUT_FILE_PATH + "../../../../guix_studio/build/vs_2022/Release/guix_studio.exe" project_pathname = test_utils.DEFAULT_OUTPUT_FILE_PATH + "/test_string_import_export.gxp" studio_release = os.path.abspath(studio_release) project_pathname = os.path.abspath(project_pathname) diff --git a/test/guix_studio_test/test_view/test_utils.py b/test/guix_studio_test/test_view/test_utils.py index dc7b5d18f..17e43fb05 100644 --- a/test/guix_studio_test/test_view/test_utils.py +++ b/test/guix_studio_test/test_view/test_utils.py @@ -28,7 +28,7 @@ user32 = ctypes.windll.user32 -studio_exe_path = "../../../guix_studio/build/vs_2019/Release/guix_studio.exe" +studio_exe_path = "../../../guix_studio/build/vs_2022/Release/guix_studio.exe" top_windows = [] WM_CLOSE = 0x0010 reset_map_format = False From 70463f8fac203f1597a7c0657c851997bb0554c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Thu, 27 Aug 2026 09:11:38 -0400 Subject: [PATCH 4/8] Fixed animation start regression that prevented animations from running (#175) Commit 8a35f690 (#158) made _gx_animation_start() assign the return value of _gx_canvas_drawing_initiate() to its local "status" variable. That variable is both the value returned to the caller and the flag that gates linking the animation into the active list, so the drawing status leaked into the completion status. _gx_widget_show() releases the view list of the animation root window on the line just above that call, so _gx_canvas_drawing_initiate() reports GX_NO_VIEWS every time an animation canvas is used. The animation was therefore never linked into _gx_system_animation_list, the frame timer was never started and _gx_animation_complete() never ran: no animation frames were produced and GX_ANIMATION_PUSH_STACK never pushed its target onto the screen stack. The drawing status is now held in a separate draw_status variable. The #148 guard that keeps _gx_canvas_drawing_complete() from being called after GX_DRAW_NESTING_EXCEEDED is preserved, while the completion status returned to the caller is left untouched. _gx_animation_drag_tracking_start() contains the identical block but returns GX_SUCCESS unconditionally, so it was not affected. Its variable is renamed to draw_status as well, with no change in behaviour, so the two functions cannot drift apart again. Verified on Linux with the default_build_coverage regression suite. Before the fix, matching CI run 28477318897 exactly: 447 guix_all_widgets_16bpp_canvas_animation SEGFAULT 457 guix_animation_complete golden_file_frame_id = 1, test_frame_id = 3 458 guix_animation_complete_push_stack Failed, no output After the fix all three pass and 730 of 732 tests pass. The two remaining failures, guix_ml_text_view_32bpp and guix_all_widgets_accordion_menu, are unrelated to animation and are diagnosed separately. No new regression test is added: guix_animation_complete, guix_animation_complete_push_stack and guix_all_widgets_16bpp_canvas_animation already cover this path and are the tests that caught the regression. No golden file is regenerated, since the change restores the recorded behaviour rather than altering it. guix_canvas_draw_nesting_overflow_no_output, the test added by #158, still passes. No documentation change is required: no public API or behaviour contract changes. Assisted-by: Claude Code (Opus 5) Co-authored-by: Claude Opus 5 (1M context) --- common/src/gx_animation_drag_tracking_start.c | 15 ++++++++++++--- common/src/gx_animation_start.c | 18 ++++++++++++++++-- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/common/src/gx_animation_drag_tracking_start.c b/common/src/gx_animation_drag_tracking_start.c index bc12163d4..105c60d15 100644 --- a/common/src/gx_animation_drag_tracking_start.c +++ b/common/src/gx_animation_drag_tracking_start.c @@ -9,6 +9,7 @@ * SPDX-License-Identifier: MIT **************************************************************************/ // Some portions generated by Copilot (Claude Sonnet 4.6). +// Some portions generated by Claude Code (Opus 5). /**************************************************************************/ @@ -77,7 +78,7 @@ INT current_pos; GX_WINDOW_ROOT *root; GX_VALUE left; GX_VALUE top; -UINT status; +UINT draw_status; VOID (*active_display_area_set)(INT layer, GX_RECTANGLE *size); info = &animation -> gx_animation_info; @@ -285,8 +286,16 @@ VOID (*active_display_area_set)(INT layer, GX_RECTANGLE *size); /* and show the animation root window to make everything visible */ _gx_widget_show((GX_WIDGET *)root); - status = _gx_canvas_drawing_initiate(animation -> gx_animation_canvas, (GX_WIDGET *)root, &root -> gx_widget_size); - if (status == GX_SUCCESS || status == GX_NO_VIEWS) + /* The drawing status is deliberately kept out of the completion + status of this function: _gx_widget_show() above releases the + view list of the animation root window, so + _gx_canvas_drawing_initiate() reports GX_NO_VIEWS here. */ + draw_status = _gx_canvas_drawing_initiate(animation -> gx_animation_canvas, (GX_WIDGET *)root, &root -> gx_widget_size); + + /* Draw and complete only when a draw context was actually pushed. + GX_DRAW_NESTING_EXCEEDED means no context was pushed, so calling + _gx_canvas_drawing_complete() would corrupt the outer context. */ + if ((draw_status == GX_SUCCESS) || (draw_status == GX_NO_VIEWS)) { _gx_widget_children_draw((GX_WIDGET *)root); _gx_canvas_drawing_complete(animation -> gx_animation_canvas, GX_FALSE); diff --git a/common/src/gx_animation_start.c b/common/src/gx_animation_start.c index 61c2882b7..7392ca6a7 100644 --- a/common/src/gx_animation_start.c +++ b/common/src/gx_animation_start.c @@ -9,6 +9,7 @@ * SPDX-License-Identifier: MIT **************************************************************************/ // Some portions generated by Copilot (Claude Sonnet 4.6). +// Some portions generated by Claude Code (Opus 5). /**************************************************************************/ @@ -79,6 +80,7 @@ UINT _gx_animation_start(GX_ANIMATION *animation, GX_ANIMATION_INFO *info) { UINT status = GX_SUCCESS; +UINT draw_status; GX_WINDOW_ROOT *root; #ifdef GX_THREADX_BINDING @@ -122,8 +124,20 @@ GX_VALUE top; /* and show the animation root window to make everything visible */ _gx_widget_show((GX_WIDGET *)root); - status = _gx_canvas_drawing_initiate(animation -> gx_animation_canvas, (GX_WIDGET *) root, &root -> gx_widget_size); - if (status == GX_SUCCESS || status == GX_NO_VIEWS) + /* Keep the drawing status separate from the completion status returned + by this function. _gx_widget_show() above releases the view list of + the animation root window, so _gx_canvas_drawing_initiate() reports + GX_NO_VIEWS here. That is expected for an animation canvas and must + neither be returned to the caller nor prevent the animation from + being linked into the active list below. */ + draw_status = _gx_canvas_drawing_initiate(animation -> gx_animation_canvas, (GX_WIDGET *) root, &root -> gx_widget_size); + + /* Draw and complete only when a draw context was actually pushed. + GX_DRAW_NESTING_EXCEEDED means no context was pushed, so calling + _gx_canvas_drawing_complete() would corrupt the outer context. The + children of a root window with no views are still drawn, matching + the behaviour of _gx_system_canvas_refresh(). */ + if ((draw_status == GX_SUCCESS) || (draw_status == GX_NO_VIEWS)) { _gx_widget_children_draw((GX_WIDGET *)root); _gx_canvas_drawing_complete(animation -> gx_animation_canvas, GX_FALSE); From 3030cc64d31cb855a004839965faa911e92a4753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Thu, 27 Aug 2026 10:59:37 -0400 Subject: [PATCH 5/8] Fixed text being dropped when the draw context stack overflows (#176) The fix for issue #148 (#158) made every caller of _gx_canvas_drawing_initiate() skip its draw when the call returns GX_DRAW_NESTING_EXCEEDED. Four of those callers push a nested context on the widget they are already drawing, for one reason only: to narrow the clipping rectangle to the widget's client area. For them, skipping the draw turns a correct rendering into no rendering at all, which is what made guix_all_widgets_accordion_menu report "Frame 12 is different". The accordion menu screen of the all_widgets demo nests widgets nine levels deep - multi_level_accordion, menu_list, mla_menu_1_accordion, menu_list, text_view_3 - and _gx_system_canvas_refresh() consumes two contexts before the widget tree is walked, so the eight slots of GX_MAX_CONTEXT_NESTING are exhausted before _gx_multi_line_text_view_text_draw() can push its own. Raising the limit in a scratch build makes frame 12 match the existing golden file exactly, which shows that the golden records the correct rendering and that the text is now being lost rather than merely clipped differently. When the stack is full there is nothing to push, but the caller's context is still the right context to draw through: it was created for the same widget and differs only in its clipping rectangle. These four callers now narrow the caller's clipping rectangle, draw, and restore it, instead of dropping the draw. _gx_canvas_drawing_complete() is still not called on overflow, so the stack corruption that #158 fixed stays fixed. Applied to _gx_multi_line_text_view_text_draw, _gx_multi_line_text_input_draw, _gx_rich_text_view_text_draw and _gx_single_line_text_input_draw. _gx_widget_block_move and _gx_radial_progress_bar_background_draw are left alone: neither pushes a clip-only context on the widget being drawn. guix_canvas_draw_nesting_overflow_render_no_output closes the coverage gap that #158 left. guix_canvas_draw_nesting_overflow_no_output covers detection and state preservation; the new test covers what a caller must render: that the text is still drawn at maximum nesting depth, that the borrowed context is handed back with its nesting count, context pointer and clipping rectangle unchanged, and that the pixels match those produced when a nested context is available. Assisted-by: Claude Code (Opus 5) Co-authored-by: Claude Opus 5 (1M context) --- common/src/gx_multi_line_text_input_draw.c | 42 +++- .../src/gx_multi_line_text_view_text_draw.c | 40 +++- common/src/gx_rich_text_view_text_draw.c | 40 +++- common/src/gx_single_line_text_input_draw.c | 41 +++- .../guix_test/cmake/regression/CMakeLists.txt | 1 + ...s_draw_nesting_overflow_render_no_output.c | 202 ++++++++++++++++++ 6 files changed, 354 insertions(+), 12 deletions(-) create mode 100644 test/guix_test/regression_test/tests/validation_guix_canvas_draw_nesting_overflow_render_no_output.c diff --git a/common/src/gx_multi_line_text_input_draw.c b/common/src/gx_multi_line_text_input_draw.c index 7554906d1..8a6b6f96e 100644 --- a/common/src/gx_multi_line_text_input_draw.c +++ b/common/src/gx_multi_line_text_input_draw.c @@ -9,6 +9,7 @@ * SPDX-License-Identifier: MIT **************************************************************************/ // Some portions generated by Copilot (Claude Sonnet 4.6). +// Some portions generated by Claude Code (Opus 5). /**************************************************************************/ @@ -102,6 +103,8 @@ GX_VALUE client_width; GX_SCROLLBAR *scroll; GX_VALUE space_width; UINT status; +GX_DRAW_CONTEXT *context; +GX_RECTANGLE saved_dirty; if (input -> gx_widget_style & GX_STYLE_ENABLED) { @@ -205,10 +208,26 @@ UINT status; /* Offset client area by the size of whitespace. */ _gx_utility_rectangle_resize(&client, (GX_VALUE)(-input -> gx_multi_line_text_view_whitespace)); - _gx_utility_rectangle_overlap_detect(&_gx_system_current_draw_context -> gx_draw_context_dirty, &client, &draw_area); + /* Remember the current context and its clipping rectangle, in case the + draw context stack turns out to be full. */ + context = _gx_system_current_draw_context; + saved_dirty = context -> gx_draw_context_dirty; + + _gx_utility_rectangle_overlap_detect(&saved_dirty, &client, &draw_area); status = _gx_canvas_drawing_initiate(canvas, (GX_WIDGET *)input, &draw_area); - if (status == GX_SUCCESS) + if (status == GX_DRAW_NESTING_EXCEEDED) + { + /* The context stack is full, so no context was pushed. The context + that would have been pushed is created for this same widget, so + it differs from the current one only in its clipping rectangle. + Narrow the current context's clipping rectangle instead and draw + through it, rather than dropping the text. The rectangle is + restored once the text is drawn. */ + context -> gx_draw_context_dirty = draw_area; + } + + if ((status == GX_SUCCESS) || (status == GX_DRAW_NESTING_EXCEEDED)) { /* Pickup text height. */ line_height = (GX_VALUE)(font -> gx_font_line_height + input -> gx_multi_line_text_view_line_space); @@ -364,12 +383,29 @@ UINT status; } } - _gx_canvas_drawing_complete(canvas, GX_FALSE); + if (status == GX_SUCCESS) + { + _gx_canvas_drawing_complete(canvas, GX_FALSE); + } + else + { + /* Nothing was pushed, so _gx_canvas_drawing_complete() must + not be called: it would pop the caller's context. Restore + the clipping rectangle borrowed above instead. */ + context -> gx_draw_context_dirty = saved_dirty; + } } else if (status == GX_NO_VIEWS) { _gx_canvas_drawing_complete(canvas, GX_FALSE); } + else + { + /* Any other status, such as GX_INVALID_MEMORY_SIZE when drawing + into a partial frame buffer, is also returned before a context + is pushed, so there is nothing to draw and nothing to + complete. */ + } } } diff --git a/common/src/gx_multi_line_text_view_text_draw.c b/common/src/gx_multi_line_text_view_text_draw.c index d63709c7f..186ffc125 100644 --- a/common/src/gx_multi_line_text_view_text_draw.c +++ b/common/src/gx_multi_line_text_view_text_draw.c @@ -9,6 +9,7 @@ * SPDX-License-Identifier: MIT **************************************************************************/ // Some portions generated by Copilot (Claude Sonnet 4.6). +// Some portions generated by Claude Code (Opus 5). /**************************************************************************/ @@ -115,6 +116,8 @@ GX_VALUE client_width; GX_FONT *font; GX_SCROLLBAR *scroll; UINT status; +GX_DRAW_CONTEXT *context; +GX_RECTANGLE saved_dirty; #if defined(GX_DYNAMIC_BIDI_TEXT_SUPPORT) GX_BIDI_RESOLVED_TEXT_INFO *next = GX_NULL; @@ -187,10 +190,25 @@ UINT bidi_text_line_index = 0; text_view -> gx_multi_line_text_view_text_scroll_shift = (space_width >> 1); } - _gx_utility_rectangle_overlap_detect(&_gx_system_current_draw_context -> gx_draw_context_dirty, &client, &draw_area); + /* Remember the current context and its clipping rectangle, in case the draw + context stack turns out to be full. */ + context = _gx_system_current_draw_context; + saved_dirty = context -> gx_draw_context_dirty; + + _gx_utility_rectangle_overlap_detect(&saved_dirty, &client, &draw_area); status = _gx_canvas_drawing_initiate(canvas, (GX_WIDGET *)text_view, &draw_area); - if (status == GX_SUCCESS) + if (status == GX_DRAW_NESTING_EXCEEDED) + { + /* The context stack is full, so no context was pushed. The context that + would have been pushed is created for this same widget, so it differs + from the current one only in its clipping rectangle. Narrow the current + context's clipping rectangle instead and draw through it, rather than + dropping the text. The rectangle is restored once the text is drawn. */ + context -> gx_draw_context_dirty = draw_area; + } + + if ((status == GX_SUCCESS) || (status == GX_DRAW_NESTING_EXCEEDED)) { /* Compute the start displaying position of pixels in x direction and y direction. */ y_pos = client.gx_rectangle_top; @@ -310,11 +328,27 @@ UINT bidi_text_line_index = 0; y_pos += line_height; } - _gx_canvas_drawing_complete(canvas, GX_FALSE); + if (status == GX_SUCCESS) + { + _gx_canvas_drawing_complete(canvas, GX_FALSE); + } + else + { + /* Nothing was pushed, so _gx_canvas_drawing_complete() must not be + called: it would pop the caller's context. Restore the clipping + rectangle borrowed above instead. */ + context -> gx_draw_context_dirty = saved_dirty; + } } else if (status == GX_NO_VIEWS) { _gx_canvas_drawing_complete(canvas, GX_FALSE); } + else + { + /* Any other status, such as GX_INVALID_MEMORY_SIZE when drawing into a + partial frame buffer, is also returned before a context is pushed, so + there is nothing to draw and nothing to complete. */ + } } diff --git a/common/src/gx_rich_text_view_text_draw.c b/common/src/gx_rich_text_view_text_draw.c index 9ecc2e180..6da05aa84 100644 --- a/common/src/gx_rich_text_view_text_draw.c +++ b/common/src/gx_rich_text_view_text_draw.c @@ -9,6 +9,7 @@ * SPDX-License-Identifier: MIT **************************************************************************/ // Some portions generated by Copilot (Claude Sonnet 4.6). +// Some portions generated by Claude Code (Opus 5). /**************************************************************************/ @@ -307,6 +308,8 @@ GX_VALUE ypos; GX_CANVAS *canvas; GX_RECTANGLE draw_area; UINT status; +GX_DRAW_CONTEXT *context; +GX_RECTANGLE saved_dirty; if (!text_view -> gx_multi_line_text_view_text.gx_string_length) { @@ -377,10 +380,25 @@ UINT status; /* pick up current canvas */ canvas = _gx_system_current_draw_context -> gx_draw_context_canvas; - _gx_utility_rectangle_overlap_detect(&_gx_system_current_draw_context -> gx_draw_context_dirty, &client, &draw_area); + /* Remember the current context and its clipping rectangle, in case the draw + context stack turns out to be full. */ + context = _gx_system_current_draw_context; + saved_dirty = context -> gx_draw_context_dirty; + + _gx_utility_rectangle_overlap_detect(&saved_dirty, &client, &draw_area); status = _gx_canvas_drawing_initiate(canvas, (GX_WIDGET *)text_view, &draw_area); - if (status == GX_SUCCESS) + if (status == GX_DRAW_NESTING_EXCEEDED) + { + /* The context stack is full, so no context was pushed. The context that + would have been pushed is created for this same widget, so it differs + from the current one only in its clipping rectangle. Narrow the current + context's clipping rectangle instead and draw through it, rather than + dropping the text. The rectangle is restored once the text is drawn. */ + context -> gx_draw_context_dirty = draw_area; + } + + if ((status == GX_SUCCESS) || (status == GX_DRAW_NESTING_EXCEEDED)) { /* Calculate the total rows of text view string. */ while (text.gx_string_length > 0) @@ -430,12 +448,28 @@ UINT status; text.gx_string_ptr += line_info.gx_rich_text_line_info_text.gx_string_length; text.gx_string_length -= line_info.gx_rich_text_line_info_text.gx_string_length; } - _gx_canvas_drawing_complete(canvas, GX_FALSE); + if (status == GX_SUCCESS) + { + _gx_canvas_drawing_complete(canvas, GX_FALSE); + } + else + { + /* Nothing was pushed, so _gx_canvas_drawing_complete() must not be + called: it would pop the caller's context. Restore the clipping + rectangle borrowed above instead. */ + context -> gx_draw_context_dirty = saved_dirty; + } } else if (status == GX_NO_VIEWS) { _gx_canvas_drawing_complete(canvas, GX_FALSE); } + else + { + /* Any other status, such as GX_INVALID_MEMORY_SIZE when drawing into a + partial frame buffer, is also returned before a context is pushed, so + there is nothing to draw and nothing to complete. */ + } _gx_rich_text_view_context_reset(); } diff --git a/common/src/gx_single_line_text_input_draw.c b/common/src/gx_single_line_text_input_draw.c index 356cd63a0..11a7c2ca9 100644 --- a/common/src/gx_single_line_text_input_draw.c +++ b/common/src/gx_single_line_text_input_draw.c @@ -9,6 +9,7 @@ * SPDX-License-Identifier: MIT **************************************************************************/ // Some portions generated by Copilot (Claude Sonnet 4.6). +// Some portions generated by Claude Code (Opus 5). /**************************************************************************/ @@ -107,6 +108,8 @@ GX_VALUE text_width; GX_BRUSH *brush; GX_CHAR *input_buffer = text_input -> gx_single_line_text_input_buffer; GX_STRING string; +GX_DRAW_CONTEXT *context; +GX_RECTANGLE saved_dirty; /* Draw text input background. */ if (text_input -> gx_widget_style & GX_STYLE_ENABLED) @@ -150,10 +153,26 @@ GX_STRING string; /* pick up current canvas */ canvas = _gx_system_current_draw_context -> gx_draw_context_canvas; - _gx_utility_rectangle_overlap_detect(&_gx_system_current_draw_context -> gx_draw_context_dirty, &client, &overlap); + + /* Remember the current context and its clipping rectangle, in case the draw + context stack turns out to be full. */ + context = _gx_system_current_draw_context; + saved_dirty = context -> gx_draw_context_dirty; + + _gx_utility_rectangle_overlap_detect(&saved_dirty, &client, &overlap); status = _gx_canvas_drawing_initiate(canvas, widget, &overlap); - if (status == GX_SUCCESS) + if (status == GX_DRAW_NESTING_EXCEEDED) + { + /* The context stack is full, so no context was pushed. The context that + would have been pushed is created for this same widget, so it differs + from the current one only in its clipping rectangle. Narrow the current + context's clipping rectangle instead and draw through it, rather than + dropping the text. The rectangle is restored once the text is drawn. */ + context -> gx_draw_context_dirty = overlap; + } + + if ((status == GX_SUCCESS) || (status == GX_DRAW_NESTING_EXCEEDED)) { /* Draw the cursor. */ if ((start_mark == end_mark) && @@ -237,12 +256,28 @@ GX_STRING string; } } - _gx_canvas_drawing_complete(canvas, GX_FALSE); + if (status == GX_SUCCESS) + { + _gx_canvas_drawing_complete(canvas, GX_FALSE); + } + else + { + /* Nothing was pushed, so _gx_canvas_drawing_complete() must not be + called: it would pop the caller's context. Restore the clipping + rectangle borrowed above instead. */ + context -> gx_draw_context_dirty = saved_dirty; + } } else if (status == GX_NO_VIEWS) { _gx_canvas_drawing_complete(canvas, GX_FALSE); } + else + { + /* Any other status, such as GX_INVALID_MEMORY_SIZE when drawing into a + partial frame buffer, is also returned before a context is pushed, so + there is nothing to draw and nothing to complete. */ + } _gx_widget_children_draw(widget); } diff --git a/test/guix_test/cmake/regression/CMakeLists.txt b/test/guix_test/cmake/regression/CMakeLists.txt index ecac43750..518c56ce9 100644 --- a/test/guix_test/cmake/regression/CMakeLists.txt +++ b/test/guix_test/cmake/regression/CMakeLists.txt @@ -286,6 +286,7 @@ set(all_widgets_REG_TESTS guix_button_deselect_no_output guix_canvas_drawing_complete guix_canvas_draw_nesting_overflow_no_output + guix_canvas_draw_nesting_overflow_render_no_output guix_canvas_hardware_layer guix_canvas_pixelmap_blend guix_canvas_pixelmap_get_no_output diff --git a/test/guix_test/regression_test/tests/validation_guix_canvas_draw_nesting_overflow_render_no_output.c b/test/guix_test/regression_test/tests/validation_guix_canvas_draw_nesting_overflow_render_no_output.c new file mode 100644 index 000000000..5032204ad --- /dev/null +++ b/test/guix_test/regression_test/tests/validation_guix_canvas_draw_nesting_overflow_render_no_output.c @@ -0,0 +1,202 @@ +/*************************************************************************** + * Copyright (c) 2026 Eclipse ThreadX contributors + * + * This program and the accompanying materials are made available under the + * terms of the MIT License which is available at + * https://opensource.org/licenses/MIT. + * + * AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5). + * The AI-generated portions may be considered public domain (CC0-1.0) + * and not subject to the project's licence. The human contributor has + * reviewed and verified that the code is correct. + * + * SPDX-License-Identifier: MIT and CC0-1.0 + **************************************************************************/ + +/* Regression test for what a caller must RENDER when + * _gx_canvas_drawing_initiate() returns GX_DRAW_NESTING_EXCEEDED. + * + * guix_canvas_draw_nesting_overflow_no_output covers the other half of the + * contract: that the overflow is detected and that the draw context stack is + * left untouched. It says nothing about the pixels, and issue #148's fix + * originally answered "draw nothing", which silently dropped text that GUIX had + * always drawn. + * + * A widget such as a multi line text view pushes a nested context on itself for + * one reason only: to narrow the clipping rectangle to its client area. When + * the stack is full there is nothing to push, but the caller's context is still + * the correct context to draw through - it belongs to the same widget - so the + * widget narrows that context's clipping rectangle, draws, and restores it. + * + * Tests: + * 1. The text is still drawn when the draw context stack is full. + * 2. The borrowed context is restored: nesting count, context pointer and + * clipping rectangle are all exactly as they were. + * 3. The pixels produced at maximum nesting depth are identical to the pixels + * produced when a nested context is available. + */ + +#include +#include +#include "tx_api.h" +#include "gx_api.h" +#include "gx_system.h" +#include "gx_widget.h" +#include "gx_multi_line_text_view.h" +#include "gx_validation_utility.h" + +TEST_PARAM test_parameter = { + "guix_canvas_draw_nesting_overflow_render_no_output", + 0, 0, 0, 0 +}; + +int main(int argc, char **argv) +{ + tx_kernel_enter(); + return 0; +} + +static VOID control_thread_entry(ULONG input); + +VOID tx_application_define(void *first_unused_memory) +{ + gx_validation_control_thread_create(control_thread_entry); + gx_validation_application_define(first_unused_memory); + gx_validation_watchdog_create(100); +} + +#ifdef WIN32 +#undef WIN32 +#endif + +#include "gx_validation_wrapper.h" +#include "demo_guix_all_widgets.c" + +/* Sum every byte of the canvas frame buffer. Working in bytes keeps the + comparison independent of the colour depth, so the test behaves the same in + every build configuration. */ +static ULONG canvas_checksum(GX_CANVAS *canvas) +{ +ULONG sum = 0; +ULONG index; +GX_UBYTE *memory = (GX_UBYTE *)canvas -> gx_canvas_memory; + + for (index = 0; index < canvas -> gx_canvas_memory_size; index++) + { + sum += memory[index]; + } + + return sum; +} + +static VOID control_thread_entry(ULONG input) +{ +int failed_tests = 0; +GX_CANVAS *canvas; +GX_MULTI_LINE_TEXT_VIEW *text_view; +GX_RECTANGLE size; +GX_RECTANGLE saved_dirty; +GX_DRAW_CONTEXT *saved_context; +GX_UBYTE saved_nesting; +UINT status; +UINT index; +ULONG blank_sum; +ULONG overflow_sum; +ULONG nested_sum; + + canvas = root -> gx_window_root_canvas; + text_view = &text_screen.text_screen_text_view_1; + + /* Bring up the screen that owns the multi line text view, so that the widget + has a clip rectangle and a view list of its own. */ + ToggleScreen((GX_WINDOW *)&text_screen, (GX_WINDOW *)&button_screen); + tx_thread_sleep(10); + + /* Give the widget a non-zero whitespace. The rectangle it passes to + _gx_canvas_drawing_initiate() is its client area shrunk by the whitespace, + so the narrowed clipping rectangle becomes strictly smaller than the + widget's own clip rectangle. That is what makes the narrowing matter. */ + gx_multi_line_text_view_whitespace_set(text_view, 6); + tx_thread_sleep(10); + + size = text_view -> gx_widget_size; + + /* Pre-condition: the draw context stack must be clean. */ + EXPECT_EQ(0, (int)canvas -> gx_canvas_draw_nesting); + EXPECT_EQ(GX_NULL, _gx_system_current_draw_context); + + /* Fill the draw context stack, drawing on the text view itself so that every + context carries the widget's view list. The last one is the context the + widget has to borrow. */ + for (index = 0; index < GX_MAX_CONTEXT_NESTING; index++) + { + status = gx_canvas_drawing_initiate(canvas, (GX_WIDGET *)text_view, &size); + EXPECT_EQ(GX_SUCCESS, status); + } + + saved_nesting = canvas -> gx_canvas_draw_nesting; + saved_context = _gx_system_current_draw_context; + saved_dirty = saved_context -> gx_draw_context_dirty; + + memset(canvas -> gx_canvas_memory, 0, canvas -> gx_canvas_memory_size); + blank_sum = canvas_checksum(canvas); + + /* Test 1: the text is drawn even though the stack is full. */ + _gx_multi_line_text_view_text_draw(text_view, + text_view -> gx_multi_line_text_view_normal_text_color); + + overflow_sum = canvas_checksum(canvas); + + if (overflow_sum == blank_sum) + { + PRINT_ERROR("no pixels were written at maximum draw context nesting depth"); + failed_tests++; + } + + /* Test 2: the borrowed context is handed back untouched. */ + EXPECT_EQ(saved_nesting, canvas -> gx_canvas_draw_nesting); + EXPECT_EQ(saved_context, _gx_system_current_draw_context); + EXPECT_EQ(saved_dirty.gx_rectangle_left, saved_context -> gx_draw_context_dirty.gx_rectangle_left); + EXPECT_EQ(saved_dirty.gx_rectangle_top, saved_context -> gx_draw_context_dirty.gx_rectangle_top); + EXPECT_EQ(saved_dirty.gx_rectangle_right, saved_context -> gx_draw_context_dirty.gx_rectangle_right); + EXPECT_EQ(saved_dirty.gx_rectangle_bottom, saved_context -> gx_draw_context_dirty.gx_rectangle_bottom); + + /* Unwind the stack. */ + for (index = 0; index < GX_MAX_CONTEXT_NESTING; index++) + { + gx_canvas_drawing_complete(canvas, GX_FALSE); + } + + EXPECT_EQ(0, (int)canvas -> gx_canvas_draw_nesting); + EXPECT_EQ(GX_NULL, _gx_system_current_draw_context); + + /* Test 3: draw the same text again with room left on the stack, so that the + nested context is really pushed, and compare the two renderings. */ + status = gx_canvas_drawing_initiate(canvas, (GX_WIDGET *)text_view, &size); + EXPECT_EQ(GX_SUCCESS, status); + + memset(canvas -> gx_canvas_memory, 0, canvas -> gx_canvas_memory_size); + + _gx_multi_line_text_view_text_draw(text_view, + text_view -> gx_multi_line_text_view_normal_text_color); + + nested_sum = canvas_checksum(canvas); + + gx_canvas_drawing_complete(canvas, GX_FALSE); + + EXPECT_EQ(0, (int)canvas -> gx_canvas_draw_nesting); + EXPECT_EQ(GX_NULL, _gx_system_current_draw_context); + + EXPECT_EQ(nested_sum, overflow_sum); + + if (failed_tests == 0) + { + gx_validation_print_test_result(TEST_SUCCESS); + exit(0); + } + else + { + gx_validation_print_test_result(TEST_FAIL); + exit(1); + } +} From 1bae371195ecec89536f03dc9a4c7111ca7b9216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Thu, 27 Aug 2026 11:47:57 -0400 Subject: [PATCH 6/8] Fixed word wrapping emitting a blank row for trailing whitespace (#177) b8bb23b8 (#159) fixed issue #130 by letting the overflow branch of _gx_multi_line_text_view_display_info_get() run when an ASCII space is the character that overflows the available width. That branch consumes the space and any consecutive spaces without adding them to the row width, which is correct, and then breaks. When the whitespace ran to the end of the source line, the line terminator was left behind: the next call started on it, hit the GX_KEY_LINE_FEED case immediately and returned a row of one byte and zero width, which draws as a blank line that is not in the text. The overflow branch now takes the line terminator with the whitespace when nothing else separates them, handling a bare line feed and a carriage return / line feed pair, and guarding the second byte on the remaining length -- unlike the pre-existing GX_KEY_CARRIAGE_RETURN case earlier in the same loop, which reads ch.gx_string_ptr[1] unchecked. gx_text_display_width is untouched, so the issue #130 fix stands. Two such rows appear in the guix_ml_text_view_32bpp fixture, at string offsets 2992 and 23988 of readme_guix_generic.txt: "...Improved internal logic." with twelve trailing spaces, and "...cursor_pos_calculate.c" with one. Both were confirmed with a conditional breakpoint on display_number == 1 and display_width == 0 preceded by a space, which fires exactly twice on the pre-fix code and never after. The two extra rows are why 268 of that test's 300 frames and 144 of guix_bidi_text_draw_32bpp's 429 frames have differed from their golden data since June. Nothing inside GUIX reads gx_text_display_width -- every caller uses only gx_text_display_number, to advance its index -- so the row count alone governs where every row starts, and two extra rows change the scrollbar's value-to-pixel mapping. Every scroll step then lands at a slightly different pixel offset and the whole text block is drawn a few pixels up or down. Of the 300 frames, 297 were a pure vertical shift of otherwise identical text; only 3 were laid out differently, and those 3 are the two places above. No golden data is regenerated. gx_multi_line_text_view_text_total_rows for the long text view goes back from 2226 to 2224, and both tests pass against their existing golden files. guix_ml_text_view_word_wrap_no_output did not protect #159's fix: it passed on the pre-#159 code as well. Its available_width was one pixel too generous -- a_width + space_width, so the over-wide row the old code produced measured exactly available_width and still satisfied "width <= available_width". It is now a_width + space_width - 1, which makes appending the space genuinely overflow, and three cases are added: a line feed terminator, a carriage return / line feed terminator, and the total row count that _gx_multi_line_text_view_string_total_rows_compute() derives from them. That last one is the quantity the golden frames actually depend on, and the only one of the three a unit test can pin without golden data. The test was verified to discriminate in both directions by rebuilding against each. Against the pre-#159 source it fails four width assertions, which is issue #130. Against #159 as shipped it fails the line feed row (2 bytes, not 3), the carriage return / line feed row (2, not 4) and the row count (3, not 2). It passes only with both fixes in place. Verified on Linux across all eighteen build configurations, 1847 tests, no failures. default_build_coverage 733/733, dynamic_bidi_text_build 3/3 including guix_bidi_text_draw_32bpp, no_utf8_build_coverage 135/135. One coverage boundary worth naming: the unit test builds against the all_widgets demo, which is not in NO_UTF8_DEMOS, so it runs in default_build_coverage and disable_error_check_build but not in the GX_UTF8_SUPPORT-off configurations. The changed code is common to both paths -- only the surrounding character advance differs -- and no_utf8_build_coverage covers it through its 135 golden tests. No documentation change is required. _gx_multi_line_text_view_display_info_get is internal, and the GUIX documentation does not describe multi-line text view wrapping behaviour for trailing whitespace. Assisted-by: Claude Code (Opus 5) Co-authored-by: Claude Opus 5 (1M context) --- ...gx_multi_line_text_view_display_info_get.c | 31 +++++++- ...on_guix_ml_text_view_word_wrap_no_output.c | 78 +++++++++++++++++-- 2 files changed, 101 insertions(+), 8 deletions(-) diff --git a/common/src/gx_multi_line_text_view_display_info_get.c b/common/src/gx_multi_line_text_view_display_info_get.c index 127c8cb8a..a5ee22194 100644 --- a/common/src/gx_multi_line_text_view_display_info_get.c +++ b/common/src/gx_multi_line_text_view_display_info_get.c @@ -1,7 +1,6 @@ /*************************************************************************** * Copyright (c) 2024 Microsoft Corporation * Copyright (c) 2026 Eclipse ThreadX contributors - * // Some portions generated by Copilot (Sonnet 4.6). * * This program and the accompanying materials are made available under the * terms of the MIT License which is available at @@ -10,6 +9,9 @@ * SPDX-License-Identifier: MIT **************************************************************************/ +// Some portions generated by Copilot (Sonnet 4.6). +// Some portions generated by Claude Code (Opus 5). + /**************************************************************************/ /**************************************************************************/ @@ -197,6 +199,33 @@ GX_FONT *font; string.gx_string_ptr++; string.gx_string_length--; } + + /* If that whitespace ran to the end of the source line, take the + line terminator with it. Left behind, the terminator becomes a + row of its own, which draws as a blank line that is not present + in the text. */ + if (string.gx_string_length > 0) + { + if (string.gx_string_ptr[0] == GX_KEY_CARRIAGE_RETURN) + { + text_info -> gx_text_display_number++; + + if ((string.gx_string_length > 1) && (string.gx_string_ptr[1] == GX_KEY_LINE_FEED)) + { + text_info -> gx_text_display_number++; + } + } + else if (string.gx_string_ptr[0] == GX_KEY_LINE_FEED) + { + text_info -> gx_text_display_number++; + } + else + { + /* More text follows the whitespace, so the next row starts + at the next word. */ + } + } + break; } if (display_number == 0) diff --git a/test/guix_test/regression_test/tests/validation_guix_ml_text_view_word_wrap_no_output.c b/test/guix_test/regression_test/tests/validation_guix_ml_text_view_word_wrap_no_output.c index 7f42aadb6..a75aef7db 100644 --- a/test/guix_test/regression_test/tests/validation_guix_ml_text_view_word_wrap_no_output.c +++ b/test/guix_test/regression_test/tests/validation_guix_ml_text_view_word_wrap_no_output.c @@ -13,22 +13,39 @@ * SPDX-License-Identifier: MIT and CC0-1.0 **************************************************************************/ -/* Regression test for issue #130: word-wrapping broken for UTF-8 strings. +// Some portions generated by Claude Code (Opus 5). + +/* Regression test for issue #130 (word wrapping broken for UTF-8 strings) and + * for the blank row that its first fix introduced. * * _gx_multi_line_text_view_display_info_get() had a guard * `(ch.gx_string_ptr[0] != ' ')` in the overflow condition that prevented * the overflow branch from executing when an ASCII space caused overflow. - * The space was instead appended to gx_text_display_width, making it - * exceed available_width. + * The space was instead appended to gx_text_display_width, making it exceed + * available_width. Removing that guard fixed the width but left the line + * terminator behind whenever the consumed whitespace ran to the end of the + * source line: the terminator then formed a row of its own, which draws as a + * blank line that is not in the text. + * + * available_width is derived from the measured glyph widths so that the space + * is the character that overflows, and is one pixel short of what the row plus + * that space would need. Appending the space therefore takes the row past + * available_width, which is what makes the width assertions discriminate. * * Tests: * 1. Space at overflow boundary: gx_text_display_width <= available_width. * 2. Space at overflow boundary: gx_text_display_number includes the * trailing space (next line does not start with a space). * 3. Multiple consecutive spaces at overflow boundary: all trailing spaces - * are consumed in gx_text_display_number. + * are consumed in gx_text_display_number, and the width stays within + * available_width. * 4. Normal word overflow (non-space char): backtrack to last word * boundary still works correctly (no regression). + * 5. Whitespace running to a line feed: the line feed is consumed with it, + * so no zero-width row is produced. + * 6. Same, with a carriage return / line feed pair: both bytes are consumed. + * 7. The row count a text view derives from the above: text shaped "A \nC" + * wraps to two rows, not three. */ #include @@ -81,6 +98,8 @@ GX_STRING ch; GX_CONST GX_CHAR text1[] = "A B"; GX_CONST GX_CHAR text2[] = "A B"; GX_CONST GX_CHAR text3[] = "AB CD"; +GX_CONST GX_CHAR text4[] = "A \nC"; +GX_CONST GX_CHAR text5[] = "A \r\nC"; memset(&text_view, 0, sizeof(GX_MULTI_LINE_TEXT_VIEW)); gx_utility_rectangle_define(&size, 0, 0, 200, 200); @@ -108,10 +127,12 @@ GX_CONST GX_CHAR text3[] = "AB CD"; EXPECT_EQ(1, a_width > 0); EXPECT_EQ(1, space_width > 0); - /* available_width = a_width + space_width forces the space in "A B" to + /* available_width = a_width + space_width - 1 forces the space in "A B" to be the character that causes overflow (running_width + space_width - == available_width >= available_width). */ - avail = (GX_VALUE)(a_width + space_width); + >= available_width), and leaves the row one pixel short of being able to + hold that space. Appending it, as the code before the issue #130 fix did, + therefore takes gx_text_display_width past available_width. */ + avail = (GX_VALUE)(a_width + space_width - 1); /* --- Test 1 & 2: single space at overflow boundary ("A B") --- */ text_view.gx_multi_line_text_view_text.gx_string_ptr = text1; @@ -135,6 +156,9 @@ GX_CONST GX_CHAR text3[] = "AB CD"; /* Both spaces must be consumed so the next line starts at 'B'. */ EXPECT_EQ(3, (int)info.gx_text_display_number); + /* Neither space contributes to the width of the row. */ + EXPECT_EQ(1, info.gx_text_display_width <= (USHORT)avail); + /* --- Test 4: non-space char causes overflow ("AB CD") --- */ /* available_width = a_width + b_width + space_width + 1 ensures the space fits (no overflow at space) but 'C' overflows, triggering @@ -153,6 +177,46 @@ GX_CONST GX_CHAR text3[] = "AB CD"; /* display_width must also be within available_width. */ EXPECT_EQ(1, info.gx_text_display_width <= (USHORT)avail); + /* --- Test 5: whitespace runs to a line feed ("A \nC") --- */ + avail = (GX_VALUE)(a_width + space_width - 1); + + text_view.gx_multi_line_text_view_text.gx_string_ptr = text4; + text_view.gx_multi_line_text_view_text.gx_string_length = sizeof(text4) - 1; + + _gx_multi_line_text_view_display_info_get(&text_view, 0, sizeof(text4) - 1, &info, avail); + + /* 'A', the space and the line feed: 3 bytes, so the next row starts at 'C'. + Leaving the line feed behind gives 2, and it becomes a row of its own. */ + EXPECT_EQ(3, (int)info.gx_text_display_number); + EXPECT_EQ(1, info.gx_text_display_width <= (USHORT)avail); + + /* --- Test 6: whitespace runs to a carriage return / line feed pair --- */ + text_view.gx_multi_line_text_view_text.gx_string_ptr = text5; + text_view.gx_multi_line_text_view_text.gx_string_length = sizeof(text5) - 1; + + _gx_multi_line_text_view_display_info_get(&text_view, 0, sizeof(text5) - 1, &info, avail); + + /* 'A', the space, and both terminator bytes: 4. */ + EXPECT_EQ(4, (int)info.gx_text_display_number); + EXPECT_EQ(1, info.gx_text_display_width <= (USHORT)avail); + + /* --- Test 7: the row count a text view derives from the above. + This is the quantity the golden frame tests depend on. Text shaped + "A \nC" is two rows; a leftover line feed makes it three. */ + text_view.gx_multi_line_text_view_text.gx_string_ptr = text4; + text_view.gx_multi_line_text_view_text.gx_string_length = sizeof(text4) - 1; + + /* _gx_multi_line_text_view_string_total_rows_compute() wraps at + (client width - 2 * whitespace) - 2, so size the client area to put the + wrap point exactly where the space overflows. */ + text_view.gx_window_client.gx_rectangle_left = 0; + text_view.gx_window_client.gx_rectangle_right = + (GX_VALUE)(avail + 1 + (text_view.gx_multi_line_text_view_whitespace * 2)); + + EXPECT_EQ(GX_SUCCESS, _gx_multi_line_text_view_string_total_rows_compute(&text_view)); + + EXPECT_EQ(2, (int)text_view.gx_multi_line_text_view_text_total_rows); + if (failed_tests == 0) { gx_validation_print_test_result(TEST_SUCCESS); From d6a0667977e82e546c227be96695f8e1d0f2e6b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Thu, 27 Aug 2026 12:35:57 -0400 Subject: [PATCH 7/8] Fixed reading past the end of a string ending in a carriage return (#179) _gx_multi_line_text_view_display_info_get() decided whether a line terminator was "\r" or "\r\n" by examining ch.gx_string_ptr[1], the byte after the current character, without checking that a byte remained. When the carriage return is the last byte of the range, that access is outside the caller's buffer. A GX_STRING carries its own length and need not be NUL terminated -- that is why the _ext string API exists, and it is what the deprecation warning added in #167 says about the older char * API. _gx_multi_line_text_view_text_set_ext() stores the caller's GX_STRING verbatim unless GX_STYLE_TEXT_COPY is set, and callers of this function pass end_index = gx_string_length, so in the default configuration the read lands one byte past what the application supplied. The consequence is not only the read. If that byte happens to be 0x0A, the function reports a two-byte terminator for a one-byte remainder, so every caller advances its index by one more than the string holds. In _gx_multi_line_text_view_string_total_rows_compute() the loop then exits with index == gx_string_length + 1 and evaluates string.gx_string_ptr[index - 1], one byte past the end as well, and can add a row that is not in the text. The same over-advance reaches the line index cache in gx_multi_line_text_view_line_cache_update.c and the cursor arithmetic in gx_multi_line_text_input_cursor_pos_update.c. Both reads now go through string rather than ch. string has already been advanced past the current character and its length is exactly the number of bytes still readable there, so guarding on it bounds the access to what the caller supplied. The same idiom in _gx_multi_line_text_input_new_line_character_get() is corrected as well. That one is not currently reachable as a read past the end: its only caller, _gx_multi_line_text_input_text_set_ext(), writes a NUL immediately after the copied text. It is fixed anyway because it depends on an invariant established in a different function and documented nowhere, and because the byte it reads decides whether the widget inserts a one- or two-byte terminator on every subsequent Enter. The rest of the codebase was audited for the same shape. Five other sites handle a carriage return followed by a possible line feed; all five are already correct. gx_rich_text_view_line_info_get.c, gx_multi_line_text_input_char_insert.c and gx_utility_bidi_paragraph_reorder.c guard on the remaining length, the preprocessed-line-break branch at the top of the changed function guards on it too, and gx_multi_line_text_button_line_pointers_set.c walks a NUL-terminated char * buffer where the byte after a carriage return is at worst the terminator. guix_ml_text_line_terminator_bounds_no_output covers this. It places a line feed immediately after the string under test but outside the length the widget is given, so the over-read is observable without a sanitizer: the unfixed code counts the out-of-bounds byte and reports a 4-byte row for a 3-byte string, which the test catches as "Expected: 3, Got: 4". Two controls pin the cases that must not change -- a "\r\n" pair genuinely inside the string still counts as two bytes, and a carriage return followed by ordinary text still counts as one. The test also asserts the terminator a multi-line text input adopts from its text, for a lone carriage return and for a "\r\n" pair. Those two cases pass both before and after the change, for the reason given above; they are there to pin the behaviour, not to reproduce a fault. Verified on Linux across all eighteen build configurations, no failures. No documentation change is required: no public API or behaviour contract changes, and the corrected behaviour is what the documented terminator handling already describes. Assisted-by: Claude Code (Opus 5) Co-authored-by: Claude Opus 5 (1M context) --- .../src/gx_multi_line_text_input_text_set.c | 8 +- ...gx_multi_line_text_view_display_info_get.c | 7 +- .../guix_test/cmake/regression/CMakeLists.txt | 1 + ...ml_text_line_terminator_bounds_no_output.c | 165 ++++++++++++++++++ 4 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 test/guix_test/regression_test/tests/validation_guix_ml_text_line_terminator_bounds_no_output.c diff --git a/common/src/gx_multi_line_text_input_text_set.c b/common/src/gx_multi_line_text_input_text_set.c index 3d2db862d..acb4ed823 100644 --- a/common/src/gx_multi_line_text_input_text_set.c +++ b/common/src/gx_multi_line_text_input_text_set.c @@ -9,6 +9,8 @@ * SPDX-License-Identifier: MIT **************************************************************************/ +// Some portions generated by Claude Code (Opus 5). + /**************************************************************************/ /**************************************************************************/ @@ -92,7 +94,11 @@ UINT glyph_len; if (ch[0] == GX_KEY_CARRIAGE_RETURN) { - if (ch[1] == GX_KEY_LINE_FEED) + /* string now points at the byte after ch. Read it through string, so + that its length bounds the access: ch[1] would rely on the caller + having NUL terminated a GX_STRING, which carries its own length + and need not be terminated at all. */ + if ((string.gx_string_length > 0) && (string.gx_string_ptr[0] == GX_KEY_LINE_FEED)) { memcpy(text_input -> gx_multi_line_text_input_new_line_character, "\r\n", 3); /* Use case of memcpy is verified. */ text_input -> gx_multi_line_text_input_new_line_character_size = 2; diff --git a/common/src/gx_multi_line_text_view_display_info_get.c b/common/src/gx_multi_line_text_view_display_info_get.c index a5ee22194..4379efb58 100644 --- a/common/src/gx_multi_line_text_view_display_info_get.c +++ b/common/src/gx_multi_line_text_view_display_info_get.c @@ -168,7 +168,12 @@ GX_FONT *font; if (ch.gx_string_ptr[0] == GX_KEY_CARRIAGE_RETURN) { - if (ch.gx_string_ptr[1] == GX_KEY_LINE_FEED) + /* string now points at the byte after ch, and its length is the + number of bytes still readable there. A GX_STRING carries its + own length and need not be NUL terminated, so the byte after a + trailing carriage return may lie outside the caller's buffer: + it must not be examined. */ + if ((string.gx_string_length > 0) && (string.gx_string_ptr[0] == GX_KEY_LINE_FEED)) { text_info -> gx_text_display_number = (USHORT)(text_info -> gx_text_display_number + 2); } diff --git a/test/guix_test/cmake/regression/CMakeLists.txt b/test/guix_test/cmake/regression/CMakeLists.txt index 518c56ce9..30d8b8b50 100644 --- a/test/guix_test/cmake/regression/CMakeLists.txt +++ b/test/guix_test/cmake/regression/CMakeLists.txt @@ -353,6 +353,7 @@ set(all_widgets_REG_TESTS guix_ml_input_char_insert_no_output guix_ml_input_text_set_no_output guix_ml_input_no_output + guix_ml_text_line_terminator_bounds_no_output guix_ml_text_view_word_wrap_no_output guix_ml_view_text_set_no_output guix_ml_view_no_output diff --git a/test/guix_test/regression_test/tests/validation_guix_ml_text_line_terminator_bounds_no_output.c b/test/guix_test/regression_test/tests/validation_guix_ml_text_line_terminator_bounds_no_output.c new file mode 100644 index 000000000..9f021ad85 --- /dev/null +++ b/test/guix_test/regression_test/tests/validation_guix_ml_text_line_terminator_bounds_no_output.c @@ -0,0 +1,165 @@ +/*************************************************************************** + * Copyright (c) 2026 Eclipse ThreadX contributors + * + * This program and the accompanying materials are made available under the + * terms of the MIT License which is available at + * https://opensource.org/licenses/MIT. + * + * AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5). + * The AI-generated portions may be considered public domain (CC0-1.0) + * and not subject to the project's licence. The human contributor has + * reviewed and verified that the code is correct. + * + * SPDX-License-Identifier: MIT and CC0-1.0 + **************************************************************************/ + +/* Regression test for reading one byte past the end of a GX_STRING when it + * ends with a carriage return. + * + * A GX_STRING carries its own length and need not be NUL terminated, and + * _gx_multi_line_text_view_text_set_ext() stores the caller's string verbatim + * unless GX_STYLE_TEXT_COPY is set. When the last byte of such a string is a + * carriage return, _gx_multi_line_text_view_display_info_get() examined the + * byte after it to decide whether the terminator was "\r" or "\r\n". That byte + * lies outside the caller's buffer. + * + * Beyond the read itself, if the byte happened to be a line feed the function + * reported a two-byte terminator for a one-byte remainder, so callers advanced + * their index past gx_string_length -- and + * _gx_multi_line_text_view_string_total_rows_compute() then read + * string.gx_string_ptr[index - 1] one byte past the end as well, and could add + * a row that is not in the text. + * + * The fixtures below place a line feed immediately after the string under test + * but outside the length the widget is given, so the over-read is observable + * without a sanitizer: the old code counts the out-of-bounds byte, the fixed + * code does not. + * + * Tests: + * 1. Range ending on a carriage return, line feed just past the end: the + * terminator counts as one byte, not two. + * 2. Control -- the same buffer with the line feed inside the range: two. + * 3. Control -- carriage return followed by ordinary text: one. + * 4. _gx_multi_line_text_input_new_line_character_get() gives a one-byte + * terminator for text ending in a lone carriage return, and two bytes for + * a "\r\n" pair. + */ + +#include +#include "tx_api.h" +#include "gx_api.h" +#include "gx_system.h" +#include "gx_widget.h" +#include "gx_multi_line_text_view.h" +#include "gx_validation_utility.h" + +TEST_PARAM test_parameter = { + "guix_ml_text_line_terminator_bounds_no_output", + 0, 0, 0, 0 +}; + +int main(int argc, char **argv) +{ + tx_kernel_enter(); + return 0; +} + +static VOID control_thread_entry(ULONG input); + +VOID tx_application_define(void *first_unused_memory) +{ + gx_validation_control_thread_create(control_thread_entry); + gx_validation_application_define(first_unused_memory); + gx_validation_watchdog_create(100); +} + +#ifdef WIN32 +#undef WIN32 +#endif + +#include "gx_validation_wrapper.h" +#include "demo_guix_all_widgets.c" + +static VOID control_thread_entry(ULONG input) +{ +int failed_tests = 0; +GX_MULTI_LINE_TEXT_VIEW text_view; +GX_MULTI_LINE_TEXT_INPUT *ml_input = &text_screen.text_screen_text_input_2; +GX_RECTANGLE size; +GX_MULTI_LINE_TEXT_INFO info; +GX_STRING string; + +/* The string under test is the first three bytes, "AB\r". The line feed is + deliberately present in the buffer but outside that length. */ +GX_CONST GX_CHAR cr_then_lf[] = "AB\r\n"; +GX_CONST GX_CHAR cr_then_text[] = "AB\rX"; +GX_CONST GX_CHAR trailing_cr[] = "A\r"; +GX_CONST GX_CHAR trailing_crlf[] = "A\r\n"; + + memset(&text_view, 0, sizeof(GX_MULTI_LINE_TEXT_VIEW)); + gx_utility_rectangle_define(&size, 0, 0, 200, 200); + gx_multi_line_text_view_create(&text_view, "test_terminator", GX_NULL, 0, 0, 0, &size); + text_view.gx_multi_line_text_view_font_id = GX_FONT_ID_TEXT_INPUT; + + /* Attach the widget to root so the display and font table can be found + through the parent chain. */ + text_view.gx_widget_parent = (GX_WIDGET *)root; + text_view.gx_widget_status |= GX_STATUS_VISIBLE; + + /* --- Test 1: carriage return is the last byte of the string --- */ + text_view.gx_multi_line_text_view_text.gx_string_ptr = cr_then_lf; + text_view.gx_multi_line_text_view_text.gx_string_length = 3; + + _gx_multi_line_text_view_display_info_get(&text_view, 0, 3, &info, 200); + + /* 'A', 'B' and the carriage return: 3. Counting the line feed that follows + the string would give 4 and advance the caller past its own buffer. */ + EXPECT_EQ(3, (int)info.gx_text_display_number); + + /* --- Test 2: control, the line feed is inside the string --- */ + text_view.gx_multi_line_text_view_text.gx_string_length = 4; + + _gx_multi_line_text_view_display_info_get(&text_view, 0, 4, &info, 200); + + EXPECT_EQ(4, (int)info.gx_text_display_number); + + /* --- Test 3: control, ordinary text follows the carriage return --- */ + text_view.gx_multi_line_text_view_text.gx_string_ptr = cr_then_text; + text_view.gx_multi_line_text_view_text.gx_string_length = 4; + + _gx_multi_line_text_view_display_info_get(&text_view, 0, 4, &info, 200); + + EXPECT_EQ(3, (int)info.gx_text_display_number); + + /* --- Test 4: the terminator a text input adopts from its text --- + _gx_multi_line_text_input_text_set_ext() writes a NUL after the copied + text, so the byte after a trailing carriage return is in bounds here. + These cases pin that behaviour rather than reproduce a read past the + end: the same idiom is fixed in that file so it does not depend on an + invariant established elsewhere. */ + string.gx_string_ptr = trailing_cr; + string.gx_string_length = sizeof(trailing_cr) - 1; + EXPECT_EQ(GX_SUCCESS, gx_multi_line_text_input_text_set_ext(ml_input, &string)); + + EXPECT_EQ(1, (int)ml_input -> gx_multi_line_text_input_new_line_character_size); + EXPECT_EQ(GX_KEY_CARRIAGE_RETURN, (int)ml_input -> gx_multi_line_text_input_new_line_character[0]); + + string.gx_string_ptr = trailing_crlf; + string.gx_string_length = sizeof(trailing_crlf) - 1; + EXPECT_EQ(GX_SUCCESS, gx_multi_line_text_input_text_set_ext(ml_input, &string)); + + EXPECT_EQ(2, (int)ml_input -> gx_multi_line_text_input_new_line_character_size); + EXPECT_EQ(GX_KEY_CARRIAGE_RETURN, (int)ml_input -> gx_multi_line_text_input_new_line_character[0]); + EXPECT_EQ(GX_KEY_LINE_FEED, (int)ml_input -> gx_multi_line_text_input_new_line_character[1]); + + if (failed_tests == 0) + { + gx_validation_print_test_result(TEST_SUCCESS); + exit(0); + } + else + { + gx_validation_print_test_result(TEST_FAIL); + exit(1); + } +} From e2d28f57ebc3457b661414b8431c5819bc9c7785 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Thu, 27 Aug 2026 16:42:04 -0400 Subject: [PATCH 8/8] Fixed the Studio view test comparing goldens at the wrong offset (#184) compare_file() locates the line where comparison should start, so that the banner GUIX Studio writes into every generated file -- which carries a revision string and a generation timestamp -- is skipped rather than compared. It looked that line up correctly in the first file and then looked it up in the first file again for the second: for line in list_2: if compare_start_string in line: start_row_2 = list_1.index(line) So the golden was sliced at the *generated* file's offset. While both files happened to reach "#include" on the same line the mistake was invisible, which is why it survived since the tests were added in #84. The offsets diverged when 6ba13dbd added a ten-line MIT licence header to all 111 golden .c and .h files. GUIX Studio does not emit that header, so every golden now reaches its first #include ten lines later than the file it is compared against. The golden was therefore sliced ten lines early and compared banner text against source. That made every one of the 107 .c and .h comparisons in the suite fail -- all 29 reported test failures -- while the .csv, .xliff and .xml comparisons passed. Those use skip_line instead of compare_start_string and never reach this code, which is exactly the split the failure log shows. The reported mismatch is the same in all 29: a generated "#include" line against a golden banner comment. Confirmed arithmetically -- in every case the golden line reported sits exactly ten lines before that golden's own first #include: generic_16bpp_resources.c reported idx 13, #include at 23, delta 10 generic_16bpp_resources.h reported idx 16, #include at 26, delta 10 generic_16bpp_specifications.c reported idx 14, #include at 24, delta 10 generic_16bpp_specifications.h reported idx 16, #include at 26, delta 10 compare_output_file() is the only caller that passes compare_start_string, so the change cannot affect the xliff, xml or plain-file comparisons. Verified by running the suite locally against a Studio built from this tree. Seven suites that fail in CI now pass with no mismatches at all, each gaining exactly the tests it had been failing: CI (broken) local (fixed) Font 9 / 1 10 / 0 Multi-Themes 18 / 1 19 / 0 Project Import 10 / 2 12 / 0 Trigger Edit 6 / 1 7 / 0 Trigger Target Rename 1 / 1 2 / 0 Bidi Text 3 / 1 4 / 0 Widget Name 3 / 1 4 / 0 Project Import compares a generated specifications file, so this also shows that the screen flow prototype block added by #173 does not disturb these goldens: that block is only emitted for projects that use Screen Flow, and these do not. No golden file is regenerated. The goldens still carry "GUIX Studio Revision 6.1.12.0" and a 2022 timestamp in their banners, and still name Azure RTOS rather than Eclipse ThreadX, but the banner is what the comparison is supposed to skip -- so none of that needs to be touched to make the suite correct. This workflow had never actually executed before 2026-08-27. Every earlier run was cancelled after queueing 24 hours for the retired windows-2019 image, or sat awaiting approval on a fork pull request, including the run for the v6.5.1 release itself. #174 gave it a runner again; this is the first result it has ever produced, and the defect it found is in the test harness rather than in GUIX or in Studio. Note that studio_view_test.yml triggers only on pull requests targeting master, so this change is not exercised by its own pull request into dev. It is validated by the release pull request that carries dev to master. Assisted-by: Claude Code (Opus 5) Co-authored-by: Claude Opus 5 (1M context) --- test/guix_studio_test/test_view/test_utils.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/guix_studio_test/test_view/test_utils.py b/test/guix_studio_test/test_view/test_utils.py index 17e43fb05..ae1849e1c 100644 --- a/test/guix_studio_test/test_view/test_utils.py +++ b/test/guix_studio_test/test_view/test_utils.py @@ -7,6 +7,7 @@ # https://opensource.org/licenses/MIT. # # SPDX-License-Identifier: MIT +# Some portions generated by Claude Code (Opus 5). import os import sys @@ -217,7 +218,11 @@ def compare_file(pathname_1, pathname_2, encoding = "", compare_start_string = " start_row_2 = 0 if compare_start_string != "": - # find the line where comparing starts + # Find the line where comparing starts, independently in each file. The + # two files may reach that line at different offsets -- a generated file + # carries the Studio banner, while the golden checked in beside it also + # carries a licence header -- so each start row must be looked up in its + # own list. for line in list_1: if compare_start_string in line: start_row_1 = list_1.index(line) @@ -225,7 +230,7 @@ def compare_file(pathname_1, pathname_2, encoding = "", compare_start_string = " for line in list_2: if compare_start_string in line: - start_row_2 = list_1.index(line) + start_row_2 = list_2.index(line) break; # compare from the start line