Fix Windows windowing and refine migration UI - #202
Conversation
📝 WalkthroughWalkthroughThe pull request revises Windows Snap Layout integration, moves Rhythmbox migration into preferences, adds formatting enforcement, updates Windows build variables, and normalizes text-file line endings. ChangesWindows Snap Layout support
Rhythmbox migration action
Repository format and build tooling
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant GTKWindow
participant enable_snap_layout
participant Win32Subclass
participant DWM
GTKWindow->>enable_snap_layout: provide window and header widgets
enable_snap_layout->>GTKWindow: derive scaled maximize-button geometry
enable_snap_layout->>Win32Subclass: install subclass and SnapState
Win32Subclass->>DWM: delegate non-client messages
DWM-->>Win32Subclass: return native message handling result
Win32Subclass->>GTKWindow: toggle maximize or restore on button release
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Not up to standards ⛔🔴 Issues
|
| Category | Results |
|---|---|
| Security | 21 high |
🟢 Metrics 94 complexity · 0 duplication
Metric Results Complexity 94 Duplication 0
AI Reviewer: first review requested successfully. AI can make mistakes. Always validate suggestions.
TIP This summary will be updated as you push new changes.
|
Claude finished @jm2's task in 5m 10s —— View job Claude's PR Review
Scope note7 of the 14 changed files ( Findings1. Asymmetric retry on Snap Layout install failure ( Things that look solid
Not verifiedThis sandbox is Linux-only, and Codacy's "18 high" security findings weren't independently reproducible in this environment; given the file is a documented raw Win32 FFI/ |
There was a problem hiding this comment.
Pull Request Overview
The PR introduces significant improvements to the Windows windowing experience and refines the migration UI. However, the current implementation is not up to standards due to high complexity and a lack of coverage in critical areas. Specifically, src/ui/win32_snap.rs has been identified as a high-risk file where complexity has spiked, masking potential edge cases in window management and memory handling.
A major blocking concern is the manual memory management within the Win32 subclassing logic, which may lead to leaks if the subclass is removed before the window is destroyed. Additionally, the acceptance criterion regarding MSYS2 target-prefixed environment variable generation remains unverified by existing tests. These issues, along with the high volume of unresolved quality findings, should be addressed before merging.
About this PR
- The centralization of Win32 FFI, state management, and complex coordinate math in
src/ui/win32_snap.rswithout sufficient modularization or unit testing creates a high maintenance burden. Significant effort should be directed at refactoring this file and increasing test coverage for the hit-testing and resizing logic.
1 comment outside of the diff
scripts/build-windows.ps1
line 375🟡 MEDIUM RISK
Empty catch blocks prevent error visibility. Instead of an empty block, useWrite-Debugor check the process status before attempting to kill it.try { $taskkillProcess.Kill() } catch { Write-Debug "Process termination failed: $($_.Exception.Message)" }
Test suggestions
- Verify hit-test coordinates are correctly handled as signed values for monitors with negative virtual-screen origins.
- Verify that logical GTK surface coordinates and transforms are correctly mapped to physical pixels for hit-testing.
- Verify correct calculation of physical CSD insets from surface and widget dimensions at various DPI scales.
- Verify that maximized window bounds are clipped to the work area without restricting the manual tracking size.
- Verify that interactive resizing is constrained by the taskbar only when the specific edge entering the taskbar strip is being dragged.
- Verify correct identification of active sizing edges based on cursor proximity during corner and edge drags.
- Verify that localization key verification tests correctly scan the new Preferences file location for migration strings.
- Verify the build script generates the correct target-prefixed environment variables for different MSYS2 environments (Clang vs GCC).
Prompt proposal for missing tests
Consider implementing these tests if applicable:
1. Verify the build script generates the correct target-prefixed environment variables for different MSYS2 environments (Clang vs GCC).
TIP Improve review quality by adding custom instructions
TIP How was this review? Give us feedback
| if ref_data != 0 { | ||
| // SAFETY: this exactly balances Arc::into_raw at successful | ||
| // installation, and WM_NCDESTROY is delivered once per HWND. | ||
| drop(unsafe { Arc::from_raw(ref_data as *const SnapState) }); |
There was a problem hiding this comment.
🔴 HIGH RISK
Suggestion: Manual memory management via raw pointers in FFI callbacks is high-risk. While this implementation correctly balances the Arc reference count, ensure that RemoveWindowSubclass (line 790) does not prevent WM_NCDESTROY from reaching this handler, or the memory will leak.
| drop(unsafe { Arc::from_raw(ref_data as *const SnapState) }); | |
| let result = unsafe { DefSubclassProc(hwnd, msg, wparam, lparam) }; | |
| if ref_data != 0 { | |
| // SAFETY: this exactly balances Arc::into_raw at successful | |
| // installation, and WM_NCDESTROY is delivered once per HWND. | |
| // Reconstruct the Arc to let it drop and decrement the ref count. | |
| drop(unsafe { Arc::from_raw(ref_data as *const SnapState) }); | |
| } | |
| result |
| apply_monitor_work_area(info, monitor_info.monitor, monitor_info.work_area); | ||
| } | ||
|
|
||
| unsafe fn constrain_interactive_window_pos_to_work_area( |
There was a problem hiding this comment.
🟡 MEDIUM RISK
The function logic should be split. Separating the pure coordinate math (proposed rectangle calculations) from the side-effect-heavy Win32 API calls will make the logic easier to test and maintain. This is particularly important given the high complexity (89 delta) and lack of coverage in this file.
Try running the following prompt in your IDE agent:
Refactor the
constrain_interactive_window_pos_to_work_areafunction insrc/ui/win32_snap.rsto reduce cyclomatic complexity. Extract the logic that calculates the proposedRectand the sizing edge detection into separate, pure helper functions that can be unit tested without FFI.
| let (w, _) = win.default_size(); | ||
| super::win32_snap::update_maximize_rect((w - 92, 0, 46, 36)); | ||
| }); | ||
| super::win32_snap::enable_snap_layout(hwnd_ptr, &window, &hb.header); |
There was a problem hiding this comment.
Return value of enable_snap_layout is discarded on the immediate-install path.
In the else branch below (deferred install via connect_is_active_notify), a false return is stored in installed_for_handler, so the handler keeps retrying on every subsequent notify::is-active until SetWindowSubclass succeeds (src/ui/win32_snap.rs:648-674).
Here, on the "HWND ready at present" path, the same bool is dropped. If SetWindowSubclass fails on this first attempt (e.g. comctl32 not yet ready), win32_snap::enable_snap_layout only logs tracing::warn!("Failed to install Windows 11 Snap Layout subclass") — there's no retry hookup at all in this branch, so Snap Layout support is silently lost for the rest of the session.
Consider unifying: always register the notify::is-active retry handler (guarded by the same installed cell) regardless of which path performs the first attempt, so a failed immediate install still gets a second chance.
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
scripts/build-windows.ps1 (1)
1-7: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winAdd a UTF-8 BOM or remove non-ASCII characters.
scripts/build-windows.ps1contains U+2014 and U+2500 but has no UTF-8 BOM. Save it as UTF-8 with BOM, or make it ASCII-only.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/build-windows.ps1` around lines 1 - 7, Update the build-windows.ps1 file encoding to UTF-8 with a BOM while preserving the existing non-ASCII characters, or replace those characters with ASCII equivalents so the script is ASCII-only.Source: Linters/SAST tools
🧹 Nitpick comments (4)
src/ui/win32_snap.rs (3)
499-628: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider extracting the monitor-info lookup.
Both functions build a
MonitorInfo, callGetMonitorInfoW, and return early on failure. A sharedunsafe fn monitor_bounds(monitor: *mut c_void) -> Option<(Rect, Rect)>would remove the duplication and reduce the reported 75-line length ofconstrain_interactive_window_pos_to_work_area.♻️ Sketch of the shared helper
unsafe fn monitor_bounds(monitor: *mut c_void) -> Option<(Rect, Rect)> { if monitor.is_null() { return None; } let mut info = MonitorInfo { size: std::mem::size_of::<MonitorInfo>() as u32, monitor: Rect::default(), work_area: Rect::default(), flags: 0, }; // SAFETY: monitor is non-null and info has the documented size. (unsafe { GetMonitorInfoW(monitor, &raw mut info) } != 0) .then_some((info.monitor, info.work_area)) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/ui/win32_snap.rs` around lines 499 - 628, Extract the duplicated monitor metadata initialization and GetMonitorInfoW failure handling into an unsafe monitor_bounds helper returning Option<(Rect, Rect)>. Update constrain_maximized_window_to_work_area and constrain_interactive_window_pos_to_work_area to use this helper while preserving their existing early-return behavior and monitor/work-area values.Source: Linters/SAST tools
1005-1027: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a test for the ambiguous edge tie-break.
active_sizing_edgesfalls back to cursor proximity when both bounds shift. The tests cover only the unambiguous corner drag. Add a case whereproposed.leftandproposed.rightboth differ fromcurrent, and assert that the cursor position selects the expected edge.💚 Proposed test
#[test] fn ambiguous_bounds_resolve_by_cursor_proximity() { let current = Rect { left: 100, top: 200, right: 1_100, bottom: 1_000, }; // Both outer bounds shifted, as DPI bookkeeping can do. let proposed = Rect { left: 99, top: 200, right: 1_400, bottom: 1_000, }; assert_eq!( active_sizing_edges(current, proposed, Point { x: 1_399, y: 600 }), SizingEdges { horizontal: Some(HorizontalEdge::Right), vertical: None, } ); assert_eq!( active_sizing_edges(current, proposed, Point { x: 101, y: 600 }), SizingEdges { horizontal: Some(HorizontalEdge::Left), vertical: None, } ); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/ui/win32_snap.rs` around lines 1005 - 1027, Add an ambiguous horizontal-bounds test near active_edges_preserve_the_fixed_sides_of_a_corner_drag, using a proposed Rect where both left and right differ from current. Assert that active_sizing_edges selects the right edge for a cursor near the right bound and the left edge for a cursor near the left bound, with no vertical edge selected.
454-497: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider extracting the per-axis edge detection.
The horizontal and vertical blocks apply the same algorithm to different fields. A shared helper that takes the two current bounds, the two proposed bounds, and the cursor coordinate would remove the duplication and lower the reported cyclomatic complexity of 13.
♻️ Sketch of the shared helper
/// Returns `Some(false)` for the low edge and `Some(true)` for the high edge. fn active_edge( current_low: i32, current_high: i32, proposed_low: i32, proposed_high: i32, cursor: i32, ) -> Option<bool> { if current_high - current_low == proposed_high - proposed_low { return None; } if proposed_low != current_low && proposed_high == current_high { return Some(false); } if proposed_low == current_low && proposed_high != current_high { return Some(true); } let low_distance = (i64::from(cursor) - i64::from(proposed_low)).abs(); let high_distance = (i64::from(cursor) - i64::from(proposed_high)).abs(); Some(low_distance > high_distance) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/ui/win32_snap.rs` around lines 454 - 497, Extract the duplicated per-axis logic from active_sizing_edges into a shared active_edge helper accepting current/proposed low and high bounds plus the cursor coordinate, returning the selected low/high edge or None when the size is unchanged. Use this helper for both horizontal and vertical detection, mapping its result to HorizontalEdge and VerticalEdge while preserving the existing boundary and proximity behavior.Source: Linters/SAST tools
hooks/pre-commit (1)
21-21: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCheck the standalone fuzz workspace in the formatting hook.
fuzz/Cargo.tomldeclares a separate[workspace]. Verify whether the rootcargo fmt --checkat Line 21 checksfuzz/fuzz_targets/fuzz_dmap.rs. If it does not, add a second check forfuzz/Cargo.toml, or state that this hook covers only the application workspace.Suggested check
-if ! cargo fmt --check 2>/dev/null; then +if ! cargo fmt --check 2>/dev/null || + ! cargo fmt --manifest-path fuzz/Cargo.toml -- --check 2>/dev/null; then🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@hooks/pre-commit` at line 21, Update the pre-commit formatting hook around the existing cargo fmt check to explicitly verify the standalone fuzz workspace declared by fuzz/Cargo.toml, including fuzz/fuzz_targets/fuzz_dmap.rs. Add a separate cargo fmt --check invocation for that manifest while preserving the existing application workspace check and failure behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/fuzz.yml:
- Line 29: Update the actions/checkout step in the fuzz workflow to set
persist-credentials to false, ensuring no checkout token is stored for later
repository-controlled commands; leave the existing checkout behavior unchanged.
In `@hooks/pre-commit`:
- Line 1: Change the executable mode of the hooks/pre-commit file from 100644 to
100755 so Git records it as executable and Unix-like clients can run it.
In `@scripts/build-windows.ps1`:
- Around line 1398-1409: Update the `$ToolEnvTarget` normalization to replace
both hyphens and periods with underscores before constructing the `DLLTOOL_`,
`CC_`, `CXX_`, and `AR_` environment variable names.
- Around line 1394-1409: In the target tool environment setup around
$ToolEnvTarget, set RC_$ToolEnvTarget to the MSYS2 llvm-rc.exe path in both the
clang and non-clang branches. Keep the existing DLLTOOL, CC, CXX, and AR
assignments unchanged, using the same target-specific environment-variable
mechanism.
---
Outside diff comments:
In `@scripts/build-windows.ps1`:
- Around line 1-7: Update the build-windows.ps1 file encoding to UTF-8 with a
BOM while preserving the existing non-ASCII characters, or replace those
characters with ASCII equivalents so the script is ASCII-only.
---
Nitpick comments:
In `@hooks/pre-commit`:
- Line 21: Update the pre-commit formatting hook around the existing cargo fmt
check to explicitly verify the standalone fuzz workspace declared by
fuzz/Cargo.toml, including fuzz/fuzz_targets/fuzz_dmap.rs. Add a separate cargo
fmt --check invocation for that manifest while preserving the existing
application workspace check and failure behavior.
In `@src/ui/win32_snap.rs`:
- Around line 499-628: Extract the duplicated monitor metadata initialization
and GetMonitorInfoW failure handling into an unsafe monitor_bounds helper
returning Option<(Rect, Rect)>. Update constrain_maximized_window_to_work_area
and constrain_interactive_window_pos_to_work_area to use this helper while
preserving their existing early-return behavior and monitor/work-area values.
- Around line 1005-1027: Add an ambiguous horizontal-bounds test near
active_edges_preserve_the_fixed_sides_of_a_corner_drag, using a proposed Rect
where both left and right differ from current. Assert that active_sizing_edges
selects the right edge for a cursor near the right bound and the left edge for a
cursor near the left bound, with no vertical edge selected.
- Around line 454-497: Extract the duplicated per-axis logic from
active_sizing_edges into a shared active_edge helper accepting current/proposed
low and high bounds plus the cursor coordinate, returning the selected low/high
edge or None when the size is unchanged. Use this helper for both horizontal and
vertical detection, mapping its result to HorizontalEdge and VerticalEdge while
preserving the existing boundary and proximity behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: c9b03e01-6c9c-4dea-b36a-cb10c2d66f4c
📒 Files selected for processing (14)
.gitattributes.github/workflows/fuzz.ymlfuzz/Cargo.tomlfuzz/fuzz_targets/fuzz_dmap.rshooks/pre-commitscripts/build-windows.ps1src/audio/output.rssrc/radio/api.rssrc/ui/header_bar.rssrc/ui/persistence.rssrc/ui/preferences.rssrc/ui/rhythmbox_migration.rssrc/ui/win32_snap.rssrc/ui/window.rs
💤 Files with no reviewable changes (1)
- src/ui/header_bar.rs
| fi | ||
| echo "[pre-commit] Formatting OK." | ||
| #!/bin/sh |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/sh
mode="$(git ls-files --stage -- hooks/pre-commit | awk '{print $1}')"
test "$mode" = 100755Repository: jm2/tributary
Length of output: 151
🏁 Script executed:
#!/bin/sh
printf '%s\n' 'Tracked index entry:'
git ls-files --stage -- hooks/pre-commit
printf '%s\n' 'Working-tree mode:'
stat -c '%a %n' hooks/pre-commit 2>/dev/null || true
printf '%s\n' 'Tracked files matching hook path:'
git ls-files --stage | grep -E '(^|/)hooks/pre-commit$' || trueRepository: jm2/tributary
Length of output: 292
Set hooks/pre-commit to mode 100755.
Git records the hook as 100644, so Unix-like clients will not run it.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@hooks/pre-commit` at line 1, Change the executable mode of the
hooks/pre-commit file from 100644 to 100755 so Git records it as executable and
Unix-like clients can run it.
| # Force target build scripts to use MSYS2 tools without overriding the native | ||
| # compiler used by host build dependencies. Generic CC/CXX/AR variables also | ||
| # apply to MSVC-hosted build scripts (for example `vswhom-sys`) and make them | ||
| # invoke the MinGW compiler without the Visual Studio include environment. | ||
| $ToolEnvTarget = $RustTarget.Replace("-", "_") | ||
| if ($MsysEnv -match "clang") { | ||
| $env:DLLTOOL = Join-Path $MsysPath "bin\llvm-dlltool.exe" | ||
| $env:CC = Join-Path $MsysPath "bin\clang.exe" | ||
| $env:CXX = Join-Path $MsysPath "bin\clang++.exe" | ||
| $env:AR = Join-Path $MsysPath "bin\llvm-ar.exe" | ||
| [Environment]::SetEnvironmentVariable("DLLTOOL_$ToolEnvTarget", (Join-Path $MsysPath "bin\llvm-dlltool.exe"), "Process") | ||
| [Environment]::SetEnvironmentVariable("CC_$ToolEnvTarget", (Join-Path $MsysPath "bin\clang.exe"), "Process") | ||
| [Environment]::SetEnvironmentVariable("CXX_$ToolEnvTarget", (Join-Path $MsysPath "bin\clang++.exe"), "Process") | ||
| [Environment]::SetEnvironmentVariable("AR_$ToolEnvTarget", (Join-Path $MsysPath "bin\llvm-ar.exe"), "Process") | ||
| } | ||
| else { | ||
| $env:DLLTOOL = Join-Path $MsysPath "bin\dlltool.exe" | ||
| $env:CC = Join-Path $MsysPath "bin\gcc.exe" | ||
| $env:CXX = Join-Path $MsysPath "bin\g++.exe" | ||
| $env:AR = Join-Path $MsysPath "bin\ar.exe" | ||
| [Environment]::SetEnvironmentVariable("DLLTOOL_$ToolEnvTarget", (Join-Path $MsysPath "bin\dlltool.exe"), "Process") | ||
| [Environment]::SetEnvironmentVariable("CC_$ToolEnvTarget", (Join-Path $MsysPath "bin\gcc.exe"), "Process") | ||
| [Environment]::SetEnvironmentVariable("CXX_$ToolEnvTarget", (Join-Path $MsysPath "bin\g++.exe"), "Process") | ||
| [Environment]::SetEnvironmentVariable("AR_$ToolEnvTarget", (Join-Path $MsysPath "bin\ar.exe"), "Process") |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
rg -n -C 4 'DLLTOOL|CC|CXX|AR|cc::Build|vswhom|dlltool' .Repository: jm2/tributary
Length of output: 50370
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- Windows build script references ---'
rg -n -C 5 'DLLTOOL|CC_|CXX_|AR_|SetEnvironmentVariable|RustTarget|MsysEnv|vswhom' scripts/build-windows.ps1
printf '%s\n' '--- Rust manifests and build-related dependencies ---'
rg -n -C 3 '(^|\s)(cc|vswhom|bindgen|cmake|build-dependencies|target\.)' --glob 'Cargo.toml' --glob 'Cargo.lock' .
printf '%s\n' '--- Build scripts and native-tool consumers ---'
git ls-files | rg '(^|/)(build\.rs|.*build.*\.(rs|toml|ps1|sh)|.*sys.*\.rs)$' | head -200
rg -n -C 3 'env::var|var_os|DLLTOOL|CC|CXX|AR|cc::Build|cc::Tool|dlltool|clang|gcc' --glob '*.rs' --glob 'build.rs' --glob '*.toml' --glob '*.ps1' --glob '*.sh' . | head -500Repository: jm2/tributary
Length of output: 6958
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- Focused files ---'
fd -i 'build-windows.ps1|Cargo.toml|Cargo.lock|build.rs' . | sort
printf '%s\n' '--- Relevant script sections ---'
sed -n '1360,1435p' scripts/build-windows.ps1
printf '%s\n' '--- Dependency declarations ---'
rg -n -C 5 'cc|vswhom|bindgen|cmake|build-dependencies' --glob 'Cargo.toml' --glob 'Cargo.lock' .
printf '%s\n' '--- Repository-owned native build consumers ---'
rg -l 'DLLTOOL|CC_|CXX_|AR_|cc::Build|cc::Tool|dlltool|vswhom' --glob '*.rs' --glob 'build.rs' --glob '*.toml' --glob '*.ps1' --glob '*.sh' . | sortRepository: jm2/tributary
Length of output: 50370
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
for p in Path('.').rglob('Cargo.toml'):
text = p.read_text(errors='replace')
if any(x in text for x in ('cc', 'vswhom', 'bindgen', 'cmake')):
print(f'--- {p} ---')
for i, line in enumerate(text.splitlines(), 1):
if any(x in line for x in ('cc', 'vswhom', 'bindgen', 'cmake', 'build-dependencies')):
print(f'{i}: {line}')
PY
printf '%s\n' '--- Environment assignments in the PowerShell script ---'
rg -n -C 8 'SetEnvironmentVariable|RemoveItem Env:|Env:' scripts/build-windows.ps1Repository: jm2/tributary
Length of output: 1896
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- Root manifest and build script ---'
sed -n '1,175p' Cargo.toml
cat -n build.rs
printf '%s\n' '--- Relevant lockfile package records ---'
python3 - <<'PY'
from pathlib import Path
text = Path('Cargo.lock').read_text()
for name in ('name = "cc"', 'name = "embed-resource"', 'name = "vswhom"', 'name = "winresource"'):
pos = 0
while True:
pos = text.find(name, pos)
if pos < 0:
break
start = text.rfind('[[package]]', 0, pos)
end = text.find('[[package]]', pos + len(name))
print(text[start:end if end >= 0 else None].rstrip())
pos += len(name)
PY
printf '%s\n' '--- All repository references to native variables ---'
rg -n 'DLLTOOL|CC_|CXX_|AR_|cc::|embed_resource|winresource|vswhom' --glob '!fuzz/Cargo.lock' --glob '!Cargo.lock' --glob '*.rs' --glob '*.toml' --glob '*.ps1' .Repository: jm2/tributary
Length of output: 13801
🌐 Web query:
cc-rs target-qualified CC CXX AR environment variables DLLTOOL embed-resource vswhom source
💡 Result:
The cc-rs crate uses various environment variables to configure the C/C++ build process, allowing for target-specific overrides and flexible integration with external tools. Environment Variables and Target Qualification The cc-rs crate supports target-qualified environment variables to allow granular control when building for specific architectures or platforms [1][2][3]. For any configuration variable (e.g., CC, CXX, AR, CFLAGS), you can provide versions prefixed or suffixed by the target triple [1][2]. The search order for these variables is as follows [1][2][3]: 1. : e.g., CC_x86_64-unknown-linux-gnu [1][2] 2. <TARGET_WITH_UNDERSCORES>: e.g., CC_x86_64_unknown_linux_gnu (where periods and dashes are replaced by underscores) [1][2] 3. <BUILD_KIND>: e.g., HOST_CC or TARGET_CFLAGS [1][2] 4. : The plain variable (e.g., CC, AR) [1][2] Core Configuration Variables - CC / CXX: Specifies the C or C++ compiler [2][4]. These can also be used to specify compiler wrappers like sccache by setting CC="sccache cc" [2][4]. - AR: Specifies the archiver executable used for static libraries [1][2]. - DLLTOOL: Used in specific cross-compilation contexts (often associated with mingw-w64 toolchains) to generate import libraries for DLLs. - CRATE_CC_NO_DEFAULTS: If set, disables the generation of default compiler flags, which can be useful to avoid conflicts in complex cross-compilation setups [2][4]. Related Tools and Integration - embed-resource: This crate is commonly used for Windows resource compilation [5]. It interacts with cc-rs to find MSVC tools and include directories [5][6]. Specifically, it uses environment variables like RC$TARGET or RC to override the default resource compiler [5]. When using LLVM-RC, it often relies on the cc-rs crate to provide the correct preprocessor configuration and environment (such as INCLUDE paths) [5][6]. - vswhom: This is an internal or related utility often used by these crates (via cc::windows_registry) to locate the MSVC toolchain on Windows, including the compiler (cl.exe), linker, and other build tools [5][6]. For programmatic configuration, the Build struct provides methods like env to set variables for child processes and try_flags_from_environment to dynamically inject flags from user-defined environment variables [1][7].
Citations:
- 1: https://github.com/rust-lang/cc-rs/blob/main/src/lib.rs
- 2: https://docs.rs/cc/latest/cc/
- 3: https://docs.rs/cc/latest/cc/index.html
- 4: https://docs.rs/cc
- 5: https://docs.rs/embed-resource/latest/embed_resource/
- 6: Unable to find windows.h nabijaczleweli/rust-embed-resource#11
- 7: https://docs.rs/cc/latest/cc/struct.Build.html
🌐 Web query:
docs.rs embed-resource DLLTOOL CC target environment variables vswhom-sys
💡 Result:
The embed-resource crate is a tool for compiling and linking Windows resource files (.rc) into Rust executables via build.rs scripts [1][2]. The vswhom-sys crate provides low-level FFI bindings to a C-based discovery script (originally by Jon Blow) designed to locate Visual Studio and Windows SDK installations, which helps other tools find necessary compilers, linkers, and libraries when building C/C++ code on Windows [3][4][5]. Regarding the specific technical environment variables and interactions you mentioned: Environment Variable Overrides for embed-resource: When building for Windows, embed-resource defaults to using x86_64-w64-mingw32-windres for *-pc-windows-gnu targets and llvm-rc for *-pc-windows-msvc targets [1][6]. These defaults can be overridden by setting the RC_$TARGET, RC_${TARGET//-/_}, or RC environment variables [1][6]. Role of C Compilers and Discovery: - When using llvm-rc to compile resource files, an external C compiler is employed to preprocess the resource [1][6]. This process is pre-configured using settings from the cc crate [1][6]. - While embed-resource can attempt to find Windows SDK tools like RC.EXE or MIDL.EXE [1][7][8], it often leverages cc or vswhom (and by extension vswhom-sys) for more robust discovery of the Visual Studio environment, including compiler and linker locations [3][8][5]. - vswhom-sys specifically aids in finding paths for Visual Studio libraries (e.g., libvcruntime.lib) and executables (e.g., link.exe), as well as Windows SDK libraries (e.g., kernel32.lib) [3][5]. Note on vswhom-sys: The vswhom-sys crate is a pure FFI wrapper. Users should be aware that the underlying native code has been documented to cause memory corruption in some cases [4][9]. Most users typically interact with the higher-level vswhom crate rather than the -sys binding directly [8].
Citations:
- 1: https://docs.rs/embed-resource/latest/embed_resource/
- 2: https://crates.io/crates/embed-resource
- 3: https://docs.rs/vswhom-sys/latest/vswhom_sys/
- 4: https://crates.io/crates/vswhom-sys
- 5: https://docs.rs/vswhom-sys
- 6: https://docs.rs/embed-resource/latest/aarch64-unknown-linux-gnu/embed_resource/
- 7: https://docs.rs/embed-resource/latest/embed_resource/fn.compile.html
- 8: https://docs.rs/embed-resource/1.4.1/embed_resource/fn.find_windows_sdk_tool.html
- 9: https://docs.rs/crate/vswhom-sys/latest
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
# Inspect only the lockfile records that can introduce native build consumers.
python3 - <<'PY'
from pathlib import Path
for filename in ('Cargo.lock', 'fuzz/Cargo.lock'):
text = Path(filename).read_text()
print(f'--- {filename} ---')
records = text.split('[[package]]')
for record in records:
if any(f'name = "{n}"' in record for n in ('cc', 'embed-resource', 'vswhom', 'winresource')):
print('[[package]]' + record.rstrip())
PY
printf '%s\n' '--- Build script behavior ---'
cat -n build.rsRepository: jm2/tributary
Length of output: 4144
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
python3 - <<'PY'
import json, urllib.request
urls = {
'embed-resource Cargo.toml':
'https://raw.githubusercontent.com/nabijaczleweli/rust-embed-resource/v3.0.11/Cargo.toml',
'embed-resource src/lib.rs':
'https://raw.githubusercontent.com/nabijaczleweli/rust-embed-resource/v3.0.11/src/lib.rs',
'cc 1.2.64 src/lib.rs':
'https://raw.githubusercontent.com/rust-lang/cc-rs/cc-1.2.64/src/lib.rs',
}
for label, url in urls.items():
print(f'--- {label} ---')
try:
text = urllib.request.urlopen(url, timeout=10).read().decode()
except Exception as e:
print(f'FETCH ERROR: {e}')
continue
lines = text.splitlines()
needles = ('DLLTOOL', 'RC_', 'CC_', 'CXX_', 'AR_', 'windows_registry',
'env::var', 'var_os', 'Build::new', 'Tool::with_features')
for i, line in enumerate(lines, 1):
if any(n in line for n in needles):
lo, hi = max(1, i-3), min(len(lines), i+5)
print(f'[{lo}-{hi}]')
for j in range(lo, hi+1):
print(f'{j}: {lines[j-1]}')
PYRepository: jm2/tributary
Length of output: 692
🌐 Web query:
site:github.com/nabijaczleweli/rust-embed-resource "DLLTOOL" "compile_for"
💡 Result:
The term "compile_for" refers to a function provided by the rust-embed-resource Rust crate, rather than a standard option or command for the binutils tool "dlltool" [1][2]. In the context of the rust-embed-resource crate, which is used to compile and include Windows resources (like icons or version information) in Rust projects, the compile_for function is used to associate a specific resource file with one or more designated binaries or targets [1][2]. Syntax and Usage: The function typically takes the path to the resource file, a list of binaries for which the resource should be compiled, and any additional configuration parameters [1][2]. Example: embed_resource::compile_for("assets/poke-a-mango.rc", &["poke-a-mango", "poke-a-mango-installer"], &["VERSION="0.5.0""]).manifest_required.unwrap; This allows developers to manage different resource files for different parts of a project, such as assigning a specific icon to an installer binary versus the main application binary [1][2]. If you were searching for a "compile for" option related to dlltool, no such parameter exists in the standard GNU binutils dlltool implementation.
Citations:
- 1: https://github.com/nabijaczleweli/rust-embed-resource/blob/master/README.md
- 2: https://github.com/nabijaczleweli/rust-embed-resource
🌐 Web query:
site:github.com/nabijaczleweli/rust-embed-resource "CC_" "RC_" src
💡 Result:
In technical contexts, particularly within Rust build scripts and software development for Windows, CC_, RC_, and src are typically related to build configuration and environment variables: 1. CC_: Often refers to the C compiler (e.g., set via the CC environment variable). In many build systems, including those using the 'cc' crate in Rust, this variable defines the path to the C compiler executable [1]. 2. RC_: Frequently refers to the Resource Compiler (e.g., rc.exe or windres). In Windows development, the resource compiler is used to compile.rc files into.res files, which are then linked into the final executable. Build tools often look for an environment variable named RC or RC_ to locate the correct resource compiler for a specific target architecture [2][3][1]. 3. src: This is a standard convention for a directory name, typically standing for "source," which contains the source code files for a project. In Rust, it is standard for crates to have a src/ directory containing lib.rs or main.rs [4][2]. These terms often appear together in the context of build automation where a build script needs to locate compilers (CC for C code, RC for Windows resources) to process files found in the project's source directory (src) [4][2][3].
Citations:
- 1: Does it support cross-compiling for Windows ARM64 from Windows x86_64? nabijaczleweli/rust-embed-resource#90
- 2: https://github.com/nabijaczleweli/rust-embed-resource/blob/master/src/non_windows.rs
- 3: nabijaczleweli/rust-embed-resource@v3.0.6...v3.0.7
- 4: https://github.com/nabijaczleweli/rust-embed-resource/blob/master/src/lib.rs
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
python3 - <<'PY'
import io, tarfile, urllib.request
for crate, version in [('embed-resource', '3.0.11'), ('cc', '1.2.64')]:
url = f'https://crates.io/api/v1/crates/{crate}/{version}/download'
print(f'--- {crate} {version} ---')
try:
data = urllib.request.urlopen(url, timeout=20).read()
archive = tarfile.open(fileobj=io.BytesIO(data), mode='r:gz')
except Exception as e:
print(f'FETCH ERROR: {e}')
continue
for member in archive.getmembers():
if not member.isfile() or not member.name.endswith(('.rs', '.toml')):
continue
text = archive.extractfile(member).read().decode(errors='replace')
lines = text.splitlines()
if any(token in text for token in ('DLLTOOL', 'RC_', 'CC_', 'CXX_', 'AR_',
'windows_registry', 'Build::new')):
print(f'### {member.name}')
for i, line in enumerate(lines, 1):
if any(token in line for token in ('DLLTOOL', 'RC_', 'CC_', 'CXX_', 'AR_',
'windows_registry', 'Build::new')):
for j in range(max(1, i-3), min(len(lines), i+5)+1):
print(f'{j}: {lines[j-1]}')
print()
PYRepository: jm2/tributary
Length of output: 495
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
python3 - <<'PY'
import io, tarfile, subprocess
for crate, version in [('embed-resource', '3.0.11'), ('cc', '1.2.64')]:
url = f'https://crates.io/api/v1/crates/{crate}/{version}/download'
print(f'--- {crate} {version} ---')
data = subprocess.check_output(['curl', '-fsSLk', url])
archive = tarfile.open(fileobj=io.BytesIO(data), mode='r:gz')
for member in archive.getmembers():
if not member.isfile() or not member.name.endswith(('.rs', '.toml')):
continue
text = archive.extractfile(member).read().decode(errors='replace')
lines = text.splitlines()
tokens = ('DLLTOOL', 'RC_', 'CC_', 'CXX_', 'AR_', 'windows_registry',
'Build::new', 'env::var')
if any(token in text for token in tokens):
print(f'### {member.name}')
shown = set()
for i, line in enumerate(lines, 1):
if any(token in line for token in tokens):
lo, hi = max(1, i-3), min(len(lines), i+5)
if (lo, hi) in shown:
continue
shown.add((lo, hi))
for j in range(lo, hi+1):
print(f'{j}: {lines[j-1]}')
print()
PYRepository: jm2/tributary
Length of output: 768
🌐 Web query:
embed-resource 3.0.11 source RC_TARGET cc Build target gnullvm DLLTOOL
💡 Result:
The query relates to the behavior of the rust-embed-resource crate (version 3.0.11), which is a library used in Rust build scripts to handle the compilation and inclusion of Windows resources [1][2]. When building for Windows targets, especially the *-windows-gnullvm target family (e.g., aarch64-pc-windows-gnullvm), the library uses specific environmental configurations and toolchains to invoke resource compilers [3][4]. Key technical points regarding your query: 1. Resource Compilation: For *-windows-gnullvm targets, which rely on LLVM-based tools rather than the traditional GNU binutils (like windres and dlltool), the crate is designed to use compatible tools [4][5]. Specifically, llvm-rc is preferred and used for these targets [3][6]. 2. Environment Variable Overrides: The library allows users to override the default tool selection by setting environment variables such as RC_$TARGET, RC_${TARGET//-/_}, or RC [3]. 3. Interaction with cc: When using LLVM-RC, an external C compiler is employed to preprocess the resource file, using configurations derived from the cc crate [3]. Recent developments in the ecosystem have addressed issues where invalid target triples (containing the -gnullvm suffix) were passed to Clang by the cc crate; fixes involve stripping the llvm suffix to produce a valid target string (e.g., converting aarch64-pc-windows-gnullvm to aarch64-pc-windows-gnu for the compiler invocation) [7][8]. 4. dlltool: The gnullvm target architecture intentionally moves away from reliance on GNU dlltool [4]. Efforts within the Rust ecosystem have sought to further reduce reliance on dlltool for creating DLL import libraries to improve compatibility and reduce complexity [5]. In summary, the specific combination of build targets and tools you mentioned is part of the orchestration required to manage Windows resource embedding using modern LLVM-based toolchains on Rust platforms [3][4]. Version 3.0.11 of embed-resource includes refinements to these tool selection processes, such as improved support for llvm-rc on gnullvm targets [9][6].
Citations:
- 1: https://crates.io/crates/embed-resource
- 2: https://docs.rs/crate/embed-resource/3.0.11/source/
- 3: https://docs.rs/embed-resource/latest/embed_resource/
- 4: https://doc.rust-lang.org/rustc/platform-support/windows-gnullvm.html
- 5: Do not use dlltool to create DLL Import Libraries for Windows rust-lang/rust#147274
- 6: Use llvm-rc on aarch64-gnullvm nabijaczleweli/rust-embed-resource#88
- 7: Compilation failure on LLVM 19 with
*-gnullvmrust-lang/cc-rs#1167 - 8: Fails to build for aarch64-pc-windows-gnullvm target due to invalid target triple getting passed to clang xiph/rav1e#3393
- 9: Bump embed-resource from 3.0.9 to 3.0.11 OpenSpeleo/speleodb_compass_sidecar#103
🌐 Web query:
cc-rs 1.2.64 source target qualified environment variable DLLTOOL
💡 Result:
The cc-rs crate does not have a dedicated environment variable named DLLTOOL. Environment variables supported by cc-rs are used to configure compilers and their flags [1][2]. While cc-rs supports target-qualified environment variables for tools like CC, CXX, and AR (e.g., CC_x86_64-unknown-linux-gnu) [1][2], the specific tool dlltool is not typically managed through cc-rs environment variables. Instead, the -Cdlltool option is a rustc codegen option used to specify the path to the dlltool executable, particularly for Windows cross-compilation targets using the raw-dylib feature [3][4][5]. This option is passed to the Rust compiler (e.g., via RUSTFLAGS) rather than the cc-rs crate's configuration mechanism [5]. Projects encountering issues with dlltool may sometimes use RUSTFLAGS to explicitly set the path to the correct dlltool binary to work around host/target environment discrepancies [5].
Citations:
- 1: https://docs.rs/cc/latest/cc/
- 2: https://docs.rs/cc/latest/cc/index.html
- 3: Fix cross-compiling with dlltool for raw-dylib rust-lang/rust#108355
- 4: Stabilize raw-dylib, link_ordinal, import_name_type and -Cdlltool rust-lang/rust#109677
- 5: [1.94+] Build Error when absolut path includes Whitespaces rust-lang/rust#155591
Set RC_$ToolEnvTarget for embed-resource.
embed-resource selects the Windows resource compiler through RC_<target> or RC. DLLTOOL_<target> does not configure this path. Set RC_$ToolEnvTarget to the MSYS2 llvm-rc.exe for both default *-windows-gnullvm targets.
🧰 Tools
🪛 PSScriptAnalyzer (1.25.0)
[warning] Missing BOM encoding for non-ASCII encoded file 'build-windows.ps1'
(PSUseBOMForUnicodeEncodedFile)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/build-windows.ps1` around lines 1394 - 1409, In the target tool
environment setup around $ToolEnvTarget, set RC_$ToolEnvTarget to the MSYS2
llvm-rc.exe path in both the clang and non-clang branches. Keep the existing
DLLTOOL, CC, CXX, and AR assignments unchanged, using the same target-specific
environment-variable mechanism.
|
Claude finished @jm2's task in 2m 49s —— View job Claude's PR Review (round 2 — commit
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/packaging_metadata.rs`:
- Around line 363-365: Update the MSVC host dependency assertion in the
packaging metadata test to reject generic compiler environment assignments made
through both the `$env:` syntax and `[Environment]::SetEnvironmentVariable`,
while preserving target-specific handling so only unqualified overrides are
rejected.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 6b5500ca-dd25-4b14-a698-939a3f0dcaad
📒 Files selected for processing (6)
.github/workflows/fuzz.ymlhooks/pre-commitscripts/build-windows.ps1src/ui/win32_snap.rssrc/ui/window.rstests/packaging_metadata.rs
🚧 Files skipped from review as they are similar to previous changes (3)
- hooks/pre-commit
- .github/workflows/fuzz.yml
- src/ui/win32_snap.rs
576a36c to
50b9144
Compare
|
Claude finished @jm2's task in 2m 4s —— View job Claude's PR Review (round 3 — commit
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/ui/win32_snap.rs (1)
1057-1079: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider a test for the unchanged-axis case.
active_axis_edgereturnsNonewhen the axis size does not change. The suite covers corner drags, ambiguous shifts, and ties, but not this branch. A single-axis drag test would lock the behavior that a translated axis is never clamped.♻️ Proposed additional test
#[test] fn active_edges_ignore_an_axis_that_only_translates() { let current = Rect { left: 100, top: 200, right: 1_100, bottom: 1_000 }; let proposed = Rect { left: 140, top: 200, right: 1_140, bottom: 1_300 }; assert_eq!( active_sizing_edges(current, proposed, Point { x: 1_140, y: 1_300 }), SizingEdges { horizontal: None, vertical: Some(VerticalEdge::Bottom) } ); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/ui/win32_snap.rs` around lines 1057 - 1079, Add a unit test alongside active_edges_preserve_the_fixed_sides_of_a_corner_drag covering a proposed rectangle whose horizontal axis only translates while the vertical axis changes. Assert that active_edges_ignore_an_axis_that_only_translates yields horizontal: None and vertical: Some(VerticalEdge::Bottom), confirming translated axes are not clamped.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/ui/win32_snap.rs`:
- Around line 1057-1079: Add a unit test alongside
active_edges_preserve_the_fixed_sides_of_a_corner_drag covering a proposed
rectangle whose horizontal axis only translates while the vertical axis changes.
Assert that active_edges_ignore_an_axis_that_only_translates yields horizontal:
None and vertical: Some(VerticalEdge::Bottom), confirming translated axes are
not clamped.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: c1b5ea84-5871-4f87-ae70-296c062b24da
📒 Files selected for processing (6)
.github/workflows/fuzz.ymlhooks/pre-commitscripts/build-windows.ps1src/ui/win32_snap.rssrc/ui/window.rstests/packaging_metadata.rs
🚧 Files skipped from review as they are similar to previous changes (4)
- tests/packaging_metadata.rs
- hooks/pre-commit
- .github/workflows/fuzz.yml
- src/ui/window.rs
Summary
HTMAXBUTTONhandling for Windows 11 Snap Layouts while preserving maximize/restore clicksRoot cause and impact
GTK 4.22 performs CSD resize drags with pointer capture and repeated
SetWindowPoscalls. The earlier workaround cappedMINMAXINFO.max_track_sizeto one monitor's work area, preventing a restored window from reaching the full width of a high-DPI portrait monitor. Removing that cap restored width but allowed the manually dragged outer surface, including GTK's transparent CSD shadow, into the taskbar strip.The new subclass preserves GTK's tracking limits, adjusts only maximized bounds in
WM_GETMINMAXINFO, and constrains only the active edge during GTK's capturedWM_WINDOWPOSCHANGINGresize loop. It does not forceWS_THICKFRAMEor other frame styles.Validation
.\scripts\build-windows.ps1 -Fmt.\scripts\build-windows.ps1 -Check.\scripts\build-windows.ps1 -Test— 20 library, 1,707 application, and 26 packaging tests passed.\scripts\build-windows.ps1 -Clippy— strict debug/all-target and release passesgit diff --checkSummary by CodeRabbit
New Features
Changes
Bug Fixes