Skip to content

fix(window): resolve window-geometry audit findings (H/M/L series) - #97

Merged
pignuante merged 11 commits into
mainfrom
fix/window-geometry-phase1
Jul 21, 2026
Merged

fix(window): resolve window-geometry audit findings (H/M/L series)#97
pignuante merged 11 commits into
mainfrom
fix/window-geometry-phase1

Conversation

@pignuante

Copy link
Copy Markdown
Contributor

What

์ฐฝ ๋ฐฐ์น˜ยทํฌ๊ธฐ ์กฐ์ ˆยทํ™”๋ฉด ๊ฐ„ ์ด๋™ยทAX ์ ์šฉยทUndo ๊ฒฝ๋กœ ๊ฐ์‚ฌ์—์„œ ๋‚˜์˜จ findings๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค.
์ˆœ์ˆ˜ ๊ธฐํ•˜๋Š” ๊ฒฌ๊ณ ํ–ˆ๊ณ , ์œ„ํ—˜์€ ์„ธ ๊ฒฝ๊ณ„ โ€” AX ์ ์šฉ ๊ฒฐ๊ณผ ๋ถ„๋ฅ˜ / snap ํŒ์ • / ๋‹ค์ค‘ ๋””์Šคํ”Œ๋ ˆ์ด ์„ ํƒ โ€” ์— ๋ชฐ๋ ค ์žˆ์—ˆ๋‹ค.

ํ•ต์‹ฌ ์ ‘๊ทผ: ์œ„ํ—˜ํ•œ ๊ฒฐ์ • ๋กœ์ง์„ ์ž…๋ ฅ๋งŒ ๋ฐ›๋Š” ์ˆœ์ˆ˜ ํ•จ์ˆ˜(FrameApplyยทFrameCalculator)๋กœ ๋‚ด๋ ค ๊ธฐ์กด swiftc ํ•˜๋„ค์Šค์—์„œ ์ „์ˆ˜ ํ…Œ์ŠคํŠธํ•˜๊ณ , AppKit/AX ๊ณ„์ธต์€ ์–‡์€ ์–ด๋Œ‘ํ„ฐ๋กœ ์œ ์ง€ํ–ˆ๋‹ค(์ƒˆ XCTest ํƒ€๊นƒยทAX fake ์—†์ด ๊ฐ์‚ฌ์˜ "๊ฐ€์žฅ ์œ„ํ—˜ํ•œ ๊ณ„์ธต ๋ฏธํ…Œ์ŠคํŠธ" ์ง€์ ์„ ์‹ค์งˆ ํ•ด์†Œ).

Findings โ†’ ์ปค๋ฐ‹

๊ฐ์‚ฌ ๋‚ด์šฉ ์ปค๋ฐ‹
H-1 ์„ฑ๊ณต/์‹คํŒจ๋Š” AX ์“ฐ๊ธฐ ๊ฒฐ๊ณผ๋กœ, Undo ๊ธฐ๋ก์€ ์‹ค์ œ ๋‹ฌ์„ฑ frame์œผ๋กœ ๋ถ„๋ฆฌ โ€” ๋ถ€๋ถ„ ์ ์šฉ ์‹œ ๋ณต์› ์ง€์  ๋ณด์กด, ๋ฌด์‹œ๋œ ์“ฐ๊ธฐ๋กœ ์ง์ „ undo๋ฅผ ๋ฎ์ง€ ์•Š์Œ 821db45
H-2 ๋А์Šจํ•œ isSnapped(์ˆ˜๋™ ๋ฐฐ์น˜ยทํ™”๋ฉด ๋ฐ– ์ฐฝ ์˜คํŒ)๋ฅผ SnapStateStore + ์—„๊ฒฉ ๊ธฐํ•˜๋กœ ๋Œ€์ฒด โ€” ์ฒซ ์ž…๋ ฅ์€ ์Šค๋ƒ…, ์ œ์•ฝ ์•ฑ์€ ์ƒํƒœ๋กœ ์ธ์‹ํ•ด ๋‘ ๋ฒˆ์งธ์— ๋˜์ง€๊ธฐ a545b0b
H-3 ์‘๋‹ต ์—†๋Š” ์•ฑ์˜ ํ˜ธ์ถœ๋ณ„ 2์ดˆ timeout ๋ˆ„์  ํ”„๋ฆฌ์ฆˆ๋ฅผ ํ˜ธ์ถœ ๊ฒฝ๊ณ„ ์˜ˆ์‚ฐ์œผ๋กœ ์กฐ๊ธฐ ์ค‘๋‹จ(โ‘ ์ฆ๋ถ„; โ‘ก๋ฐฑ๊ทธ๋ผ์šด๋“œ ์›Œ์ปค๋Š” ๋ณ„๋„ ๊ณผ์ œ) deb094f
M-1 ์ธ์ ‘ ๋””์Šคํ”Œ๋ ˆ์ด ์—†์„ ๋•Œ ์žฌ์Šค๋ƒ… ๋Œ€์‹  stays put(README ๊ณ„์•ฝ ์ผ์น˜) a545b0b
M-2 Move์˜ ํ™”๋ฉด ๋ฐ– ์ฐฝ ํšŒ์ˆ˜ ๋™์ž‘ ๋ฌธ์„œํ™”(์ฝ”๋“œ ๋ฌด๋ณ€๊ฒฝ, ๊ฒฐ์ •๋Œ€๋กœ) 74b7a53
M-3 ์‹ค์ œ ๋ฐ”๋€Œ๋Š” ์ถ•์˜ ๊ถŒํ•œ๋งŒ ์š”๊ตฌยท๊ทธ ์ถ•๋งŒ ์“ฐ๊ธฐ โ€” ๊ณ ์ • ํฌ๊ธฐ ์ฐฝ Move ํ—ˆ์šฉ, ๋ถˆํ•„์š” AX IPC ๊ฐ์†Œ 8f10486
M-4 ์ƒ๋Œ€ ์ถ•์†Œ์˜ ๊ณ ์ • ๋ชจ์„œ๋ฆฌ ์˜๋„๋ฅผ FrameAnchor๋กœ ์ „๋‹ฌ โ€” ์…€ ๋‹จ์œ„ ๋ฐ˜์˜ฌ๋ฆผ ๋“œ๋ฆฌํ”„ํŠธ ์ œ๊ฑฐ 6abb0a2
M-5 ๋‹ค์Œ ๋””์Šคํ”Œ๋ ˆ์ด ์ด๋™ ์‹œ ์ ˆ๋Œ€ ํ”ฝ์…€ ํฌ๊ธฐยท์ข…ํšก๋น„ ์œ ์ง€(๋Œ€์ƒ ์ดˆ๊ณผ ์ถ•๋งŒ ์บก) + ๋งค๋‰ด์–ผ ์ •์ • 52317b6
M-6 ์ธ์ ‘ ํ™”๋ฉด ์„ ํƒ์„ ์ฃผ์ถ• edge-gap ์ตœ์†Œ ๊ณ„์ธต ์šฐ์„ ์œผ๋กœ โ€” ๋จผ๋ฐ ์ •๋ ฌ๋œ ํ™”๋ฉด์œผ๋กœ leap ๋ฐฉ์ง€ cb67081
L-1 50:50 ๊ฒน์นจ tie๋ฅผ ์—ด๊ฑฐ ์ˆœ์„œ ๋น„์˜์กด(์ฐฝ ์ค‘์‹ฌ โ†’ displayID)์œผ๋กœ ๊ฒฐ์ •ํ™” 37b0ee9
L-2 WindowUndoStore ์žฌ๊ธฐ๋ก ์‹œ ์Šน๊ฒฉ โ†’ ์ง„์งœ LRU(FIFO ์•„๋‹˜) ec5d6bc
L-3 ํ•ด์„ ์‹œ non-finiteยท0ยท์Œ์ˆ˜ frame ์ฐจ๋‹จ(isUsableFrame + .invalidFrame) b4e01b4

M-7(๊ฐ€์žฅ ์œ„ํ—˜ํ•œ ๊ณ„์ธต ๋ฏธํ…Œ์ŠคํŠธ)์€ ์œ„ ์ˆœ์ˆ˜-ํ•จ์ˆ˜ seam์œผ๋กœ ์ „ findings์— ์ „์ˆ˜ ํ…Œ์ŠคํŠธ๋ฅผ ๋™๋ฐ˜ํ•ด ํ•ด์†Œ.

๊ฒ€์ฆ

  • make build โœ… / make lint 0 ์œ„๋ฐ˜ โœ… / make test 186 checks(160โ†’186) โœ… / make coverage ๋ผ์ธ 100% โœ… / make secrets no leaks โœ…
  • ๋ผ์ด๋ธŒ ๊ฒ€์ฆ: Phase 2ยท3(AX ์“ฐ๊ธฐ ๊ฒฝ๋กœยท์Šค๋ƒ… ์ƒํƒœ ๋Œ€๋ณ€๊ฒฝ)๋ฅผ make run์œผ๋กœ ์‹ค์ œ ์ฐฝ ์กฐ์ž‘(Move/์ƒ๋Œ€์ถ•์†Œ/undo/snapThrow) ํ™•์ธ โ€” ์ •์ƒ ๋™์ž‘.

ํ›„์†(๋ณ„๋„)

  • H-3 โ‘ก โ€” AX I/O๋ฅผ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ง๋ ฌ ์›Œ์ปค๋กœ ์ด์ „ + command generation(์™„์ „ non-blocking). ์Šค๋ ˆ๋“œ ๊ณ„์•ฝ ๋ฆฌ์Šคํฌ๊ฐ€ ์ปค "์‹ค์ œ ์‘๋‹ต ์—†๋Š” ์•ฑ" ๋ผ์ด๋ธŒ ํ…Œ์ŠคํŠธ๊ฐ€ ํ•„์š” โ†’ ๋ณ„๋„ ๊ณผ์ œ๋กœ ๋ถ„๋ฆฌ.

pignuante added 11 commits July 21, 2026 11:31
๊ต์ง‘ํ•ฉ ๋ฉด์  ๋™๋ฅ (์ •ํ™•ํžˆ ๋‘ ํ™”๋ฉด์— ๋ฐ˜์”ฉ ๊ฑธ์นœ ์ฐฝ)์—์„œ NSScreen.screens ์—ด๊ฑฐ
์ˆœ์„œ์— ์˜์กดํ•˜๋˜ ๊ฒƒ์„, ์ฐฝ ์ค‘์‹ฌ ํฌํ•จ โ†’ ์ž‘์€ displayID ์ˆœ์˜ ๊ฒฐ์ •์  ๊ทœ์น™์œผ๋กœ ๋ฐ”๊พผ๋‹ค.
๊ฐ์‚ฌ L-1.
๊ธฐ์กด ์ฐฝ์„ ๋‹ค์‹œ ๊ธฐ๋กํ•  ๋•Œ order ๋์œผ๋กœ ์Šน๊ฒฉํ•˜์ง€ ์•Š์•„ ์‚ฝ์ž… ์ˆœ์„œ(FIFO)๋กœ ํ‡ด์ถœ๋˜๋˜
๋ฌธ์ œ๋ฅผ ๊ณ ์ณ, ์ž์ฃผ ์“ฐ๋Š” ์˜ค๋ž˜๋œ ์ฐฝ์ด 64๊ฐœ ์šฉ๋Ÿ‰์—์„œ ๋จผ์ € ๋ฐ€๋ ค๋‚˜์ง€ ์•Š๊ฒŒ ํ•œ๋‹ค. ๊ฐ์‚ฌ L-2.
์ธ์ ‘ ํ™”๋ฉด ์„ ํƒ์„ perpendicular(์ •๋ ฌ) ์šฐ์„ ์—์„œ ์ฃผ์ถ• edge-gap ์ตœ์†Œ ๊ณ„์ธต ์šฐ์„ ์œผ๋กœ
๋ฐ”๊พผ๋‹ค. 3๋Œ€ ์ด์ƒ ๋ชจ๋‹ˆํ„ฐ์—์„œ '๋ฉ€์ง€๋งŒ ์ฐฝ Y์— ์ •๋ ฌ๋œ' ํ™”๋ฉด์œผ๋กœ leapํ•˜๋˜ ๊ฒƒ์„ ๋ง‰๊ณ ,
๊ทธ ๊ณ„์ธต ์•ˆ์—์„œ๋งŒ ์ •๋ ฌ์ด ๊ฐ€๊นŒ์šด ํ™”๋ฉด์„ ๊ณ ๋ฅธ๋‹ค. primaryGapโ†’primaryEdgeGap. ๊ฐ์‚ฌ M-6.
displayMoveRect๊ฐ€ ํ™”๋ฉด ๋น„์œจ๋กœ ๊ฐ ์ถ•์„ ๋…๋ฆฝ ์Šค์ผ€์ผํ•˜๋˜ ๊ฒƒ์„, ์ฐฝ์˜ ํ”ฝ์…€ ํฌ๊ธฐ๋ฅผ
๋ณด์กด(๋Œ€์ƒ ํ™”๋ฉด๋ณด๋‹ค ํฐ ์ถ•๋งŒ ์บก)ํ•˜๋„๋ก ๋ฐ”๊ฟ” ์ข…ํšก๋น„ยทํฌ๊ธฐ๋ฅผ ์œ ์ง€ํ•œ๋‹ค. README์˜
'preserves shape and size'์™€ ์ผ์น˜. ๋งค๋‰ด์–ผ์˜ 'proportional size' ๋ฌธ๊ตฌ๋„ ์ •์ •. ๊ฐ์‚ฌ M-5.
ํ•ด์„ ๋‹จ๊ณ„์—์„œ ์ฝ์€ frame์ด ์œ ํ•œยท์–‘์ˆ˜์ธ์ง€ ๊ฒ€์‚ฌํ•˜๋Š” ์ˆœ์ˆ˜ isUsableFrame ๊ฐ€๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด,
NaNยท๋ฌดํ•œยท0ยท์Œ์ˆ˜ frame(๋น„์ •์ƒ ์•ฑยทํ™”๋ฉด ์ „ํ™˜ ์ˆœ๊ฐ„)์ด ํ™”๋ฉด fallbackยท์ž˜๋ชป๋œ target
๊ณ„์‚ฐ์„ ์˜ค์—ผ์‹œํ‚ค๋Š” ๊ฒƒ์„ ๋ง‰๋Š”๋‹ค. ์ƒˆ .invalidFrame ์˜ค๋ฅ˜๋กœ ์‚ฌ์šฉ์ž์—๊ฒŒ ์‚ฌ์œ  ๋…ธ์ถœ. ๊ฐ์‚ฌ L-3.
Writer๊ฐ€ ์„ฑ๊ณตยท์‹คํŒจ ์–‘์ชฝ์—์„œ ์‹ค์ œ frame(achieved)์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก FrameApplyResult๋ฅผ
๋„์ž…ํ•˜๊ณ , Executor๋Š” achieved๊ฐ€ pre์—์„œ ์‹ค์ œ๋กœ ๋ณ€ํ–ˆ์„ ๋•Œ๋งŒ undo๋ฅผ ๊ธฐ๋กํ•œ๋‹ค:
 - ๋ถ€๋ถ„ ์ ์šฉ(ํ•œ ์ถ•๋งŒ ๋ฐ˜์˜)์œผ๋กœ ์ฐฝ์ด ์ด๋™ํ–ˆ์œผ๋ฉด ์‹คํŒจ์—ฌ๋„ ๋ณต์› ์ง€์ ์„ ๋‚จ๊ธด๋‹ค.
 - ๋ฌด์‹œ๋œ ์“ฐ๊ธฐ(์ฐฝ์ด ๊ทธ๋Œ€๋กœ)๋ฉด ๊ธฐ๋กํ•˜์ง€ ์•Š์•„ ์ง์ „ ์„ฑ๊ณต ๋ช…๋ น์˜ undo๋ฅผ ๋ฎ์ง€ ์•Š๋Š”๋‹ค.
 - undo ๋ณต์›์€ ์‹ค์ œ๋กœ ์ง์ „ frame์— ๋„๋‹ฌํ–ˆ์„ ๋•Œ๋งŒ entry๋ฅผ ์†Œ๋น„ํ•œ๋‹ค.
ํŒ์ • ๋กœ์ง์€ ์ˆœ์ˆ˜ FrameApply(changed/reached)๋กœ ๋ถ„๋ฆฌํ•ด ์ „์ˆ˜ ํ…Œ์ŠคํŠธ. ๊ฐ์‚ฌ H-1.
Move์ฒ˜๋Ÿผ ์œ„์น˜๋งŒ ๋ฐ”๊พธ๋Š” ๋ช…๋ น์ด size settable์„ ์š”๊ตฌํ•˜๊ณ  size๋ฅผ ๋‹ค์‹œ ์“ฐ๋˜ ๊ฒƒ์„ ๊ณ ์นœ๋‹ค.
target์ด current์—์„œ ์‹ค์ œ๋กœ ์˜ฎ๊ธฐ๋Š”/๋ฆฌ์‚ฌ์ด์ฆˆํ•˜๋Š” ์ถ•์„ ํŒ์ •ํ•ด(FrameApply.movesOrigin/
resizesSize) ๊ทธ ์ถ•์˜ ๊ถŒํ•œ๋งŒ ์š”๊ตฌํ•˜๊ณ  ๊ทธ ์ถ•๋งŒ ์“ด๋‹ค:
 - ์ด๋™ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ๊ณ ์ • ํฌ๊ธฐ์ธ ์ฐฝ์˜ Move๊ฐ€ ์„ฑ๊ณตํ•œ๋‹ค(size-only๋Š” .notResizable๋กœ ๋ถ„๋ฆฌ).
 - ๋ถˆํ•„์š”ํ•œ size AX IPC์™€ ๋ถ€๋ถ„ ์‹คํŒจ ๊ฐ€๋Šฅ์„ฑ์ด ์ค€๋‹ค. ์–ด๋А ์ถ•๋„ ์•ˆ ๋ฐ”๋€Œ๋ฉด ์“ฐ๊ธฐ ์—†์ด no-op. ๊ฐ์‚ฌ M-3.
์ƒ๋Œ€ ์ถ•์†Œ์˜ ๊ณ ์ • ๋ชจ์„œ๋ฆฌ๋ฅผ ๋ช…๋ น์ด FrameAnchor๋กœ ์‹ค์–ด Writer์— ์ „๋‹ฌํ•œ๋‹ค. ๊ธฐ์กด
anchorOrigin์€ ์ž‘์—…์˜์—ญ ๋ชจ์„œ๋ฆฌ ์ ‘์ด‰๋งŒ ์ถ”๋ก ํ•ด, ํ™”๋ฉด ๊ฐ€์žฅ์ž๋ฆฌ์— ๋‹ฟ์ง€ ์•Š์€ ์ƒ๋Œ€ ์ถ•์†Œ๋Š”
๊ณ ์ •์ ์„ ๋ณต๊ตฌํ•  ์ˆ˜ ์—†์—ˆ๋‹ค โ€” ์•ฑ์ด ์š”์ฒญ๋ณด๋‹ค ์ž‘๊ฒŒ ๋ฐ˜์˜ฌ๋ฆผ(ํฌ๊ธฐ์ฆ๋ถ„ ์•ฑ์˜ ์…€ ๋‹จ์œ„)ํ•˜๋ฉด
right/bottom ๋ชจ์„œ๋ฆฌ๊ฐ€ ๋ฐ˜๋ณต ์ถ•์†Œ๋งˆ๋‹ค ๋ฐ€๋ ธ๋‹ค. ์ด์ œ ์‹ค์ œ ํฌ๊ธฐ๋ฅผ ์ฝ์–ด target.maxX/maxY๋ฅผ
์œ ์ง€ํ•˜๋„๋ก origin์„ ๋‹ค์‹œ ๊ณ„์‚ฐํ•œ๋‹ค(์ž‘๊ฒŒ๋“  ํฌ๊ฒŒ๋“  ์–‘๋ฐฉํ–ฅ). ๊ฐ์‚ฌ M-4.
๋А์Šจํ•œ isSnapped(ํ•œ์ชฝ flush + ์ˆ˜์ง ์ ˆ๋ฐ˜ ์ปค๋ฒ„)๊ฐ€ ์ˆ˜๋™์œผ๋กœ ์ข๊ฒŒ/๋ฉ€๋ฆฌ/ํ™”๋ฉด ๋ฐ–์— ๋‘” ์ฐฝ์„
'์ด๋ฏธ ์Šค๋ƒ…๋จ'์œผ๋กœ ์˜คํŒํ•ด ์ฒซ ์ž…๋ ฅ๋ถ€ํ„ฐ ์˜† ๋ชจ๋‹ˆํ„ฐ๋กœ ๋˜์ง€๋˜ ๋ฌธ์ œ๋ฅผ ๊ณ ์นœ๋‹ค(๊ฐ์‚ฌ H-2).

- SnapStateStore: Azimuth๊ฐ€ ์ฐฝ์„ ์–ด๋А edge๋กœ ์Šค๋ƒ…ํ–ˆ๊ณ  ๊ทธ๋•Œ frame์ด ๋ฌด์—‡์ด์—ˆ๋Š”์ง€ ๊ธฐ๋ก
  (capacity 64ยทLRU, UndoStore์™€ ๋™์ผ ํ‚ค ์„ค๊ณ„, ๋””์Šคํ”Œ๋ ˆ์ด ์žฌ๊ตฌ์„ฑ ์‹œ clearAll).
- ๋˜์ง€๊ธฐ ํŠธ๋ฆฌ๊ฑฐ = ์—„๊ฒฉ ๊ธฐํ•˜(์ •ํ™•ํžˆ ๊ทธ ์ ˆ๋ฐ˜) OR known-snap(๊ธฐ๋ก๋œ edge + ์™ธ๋ถ€ ๋ฏธ์ด๋™).
  ์ œ์•ฝ ์•ฑ์€ ์ƒํƒœ๋กœ ์ธ์‹ํ•˜๊ณ , ์ˆ˜๋™ ๋ฐฐ์น˜ ์ฐฝ์€ ์ฒซ ์ž…๋ ฅ์— ์Šค๋ƒ…๋˜๊ณ  ๋˜์ ธ์ง€์ง€ ์•Š๋Š”๋‹ค.
- M-1: ์ธ์ ‘ ๋””์Šคํ”Œ๋ ˆ์ด๊ฐ€ ์—†์œผ๋ฉด ์žฌ์Šค๋ƒ…์œผ๋กœ ๋ฏธ์„ธํ•˜๊ฒŒ ๋ฐ€์ง€ ์•Š๊ณ  ํ˜„ ์œ„์น˜๋ฅผ ๊ทธ๋Œ€๋กœ ์œ ์ง€
  (README 'No adjacent display โ†’ stays put' ์ผ์น˜).

isSnapped์™€ ๋ณด์กฐ helper(outerFlush/spansPerpendicular/tolerance/overlap)๋ฅผ ์ˆœ์ˆ˜
isAlreadySnapped๋กœ ๋Œ€์ฒด. Executor์— snapStore๋ฅผ ๋ฐฐ์„ (AppDelegateยทStatusBarController).
- Move: ์ด๋ฏธ ํ™”๋ฉด ๋ฐ–์œผ๋กœ ๋ฒ—์–ด๋‚œ ์ฐฝ์€ ์ž‘์—…์˜์—ญ ์•ˆ์œผ๋กœ ํšŒ์ˆ˜๋˜๋ฏ€๋กœ ๋ฐฉํ–ฅ ์ด๋™์ด ์ฐฝ์„ ๋ฐ˜๋Œ€๋กœ
  ๋‹น๊ฒจ ํ™”๋ฉด์— ๋˜๋Œ๋ฆด ์ˆ˜ ์žˆ์Œ์„ READMEยท๋งค๋‰ด์–ผ์— ๋ช…์‹œ(๊ฐ์‚ฌ M-2 โ€” ์ฝ”๋“œ ๋ฌด๋ณ€๊ฒฝ, ๋™์ž‘ ๋ฌธ์„œํ™”).
- snapThrow: ์ธ์ ‘ ๋””์Šคํ”Œ๋ ˆ์ด ์—†์„ ๋•Œ 'stays in its current half' โ†’ 'stays put'์œผ๋กœ ์ •์ •ํ•ด
  ์‹ค์ œ ๋™์ž‘(ํ˜„ ์œ„์น˜ ๊ทธ๋Œ€๋กœ ์œ ์ง€, ์žฌ์Šค๋ƒ… ์•ˆ ํ•จ)ยทREADME์™€ ์ผ์น˜(M-1).
๋งค๋‰ด์–ผ์€ data-en/data-ko/๊ฐ€์‹œ ํ…์ŠคํŠธ 3์ค‘ ๋™๊ธฐ ์œ ์ง€.
AX IPC๋Š” ๋™๊ธฐ๋ผ ์‘๋‹ต ์—†๋Š” ์•ฑ์ด ํ˜ธ์ถœ๋งˆ๋‹ค ์ตœ๋Œ€ 2์ดˆ(messagingTimeout) MainActor๋ฅผ ๋ง‰๊ณ ,
์ง๋ ฌ๋กœ ์Œ“์ด๋ฉด ๋ช…๋ น ํ•˜๋‚˜๊ฐ€ ์ˆ˜์‹ญ ์ดˆ UI๋ฅผ ๋ฉˆ์ถœ ์ˆ˜ ์žˆ๋‹ค(๊ฐ์‚ฌ H-3). ๊ฐœ๋ณ„ ํ˜ธ์ถœ์€ ๋ชป ๋Š์œผ๋ฏ€๋กœ
ํ˜ธ์ถœ ๊ฒฝ๊ณ„์—์„œ ์†Œ๋Ÿ‰ ์˜ˆ์‚ฐ์œผ๋กœ ์กฐ๊ธฐ ์ค‘๋‹จํ•œ๋‹ค(๋ถ€๋ถ„ ์™„ํ™”):
 - Executor: ํ•ด์„(๋‹ค์ˆ˜ AX ์ฝ๊ธฐ)์ด 3์ดˆ๋ฅผ ๋„˜์œผ๋ฉด ์“ฐ๊ธฐ ๋‹จ๊ณ„๋ฅผ ๊ฑด๋„ˆ๋›ฐ๊ณ  .transient(์กฐ์šฉํžˆ ์Šคํ‚ต).
 - Writer: ์ดˆ๊ธฐ ์“ฐ๊ธฐยท๊ฒ€์ฆ์ด 1์ดˆ๋ฅผ ๋„˜์œผ๋ฉด verify ์žฌ์‹œ๋„(์ถ”๊ฐ€ position/size ์“ฐ๊ธฐ)๋ฅผ ์ƒ๋žต.
์ •์ƒ ์•ฑ์€ ๋ช…๋ น๋‹น <100ms๋ผ ์˜ˆ์‚ฐ์— ๊ฑธ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค. ์“ฐ๊ธฐ ํ˜ธ์ถœ ์ตœ์†Œํ™”๋Š” M-3์—์„œ ์ด๋ฏธ ๋ฐ˜์˜.
์™„์ „ ๋น„๋ธ”๋กœํ‚น(AX I/O ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ง๋ ฌ ์›Œ์ปค + command generation)์€ ๋ณ„๋„ ๊ณผ์ œ๋กœ ๋ถ„๋ฆฌ.
@pignuante
pignuante merged commit b7692e5 into main Jul 21, 2026
3 checks passed
@pignuante
pignuante deleted the fix/window-geometry-phase1 branch July 21, 2026 07:48
pignuante added a commit that referenced this pull request Jul 21, 2026
โ€ฆ99)

* fix(undo): use the write threshold when deciding a frame changed

FrameApply.changed๋Š” 'Undo๋ฅผ ๊ธฐ๋กํ• ์ง€'๋ฅผ ๋ฌป๋Š”๋ฐ reached์šฉ ๊ด€๋Œ€ํ•œ ํ—ˆ์šฉ์˜ค์ฐจ(origin 2ptยท
size 8pt)๋ฅผ ์“ฐ๊ณ  ์žˆ์—ˆ๋‹ค. ์“ฐ๊ธฐ ์—ฌ๋ถ€๋Š” changeEpsilon(0.5pt)์œผ๋กœ ์ •ํ•˜๋ฏ€๋กœ 0.5~8pt ๊ตฌ๊ฐ„์—์„œ
๋‘ ํŒ์ •์ด ์–ด๊ธ‹๋‚˜, ์ฐฝ์€ ์‹ค์ œ๋กœ ๋ฐ”๋€Œ์—ˆ๋Š”๋ฐ undo๊ฐ€ ๊ธฐ๋ก๋˜์ง€ ์•Š์•˜๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ง์ „ ๋ช…๋ น์˜ undo
ํ•ญ๋ชฉ์ด ์‚ด์•„๋‚จ์•„ Undo ์‹œ ์ฐฝ์ด ํ•œ์ฐธ ์ „ frame์œผ๋กœ ํŠ„๋‹ค.

changed๊ฐ€ ์“ฐ๊ธฐ์™€ ๋™์ผํ•œ changeEpsilon์„ ์“ฐ๋„๋ก ํ•ด '์“ธ ๋งŒํผ ๋‹ฌ๋ผ์กŒ์œผ๋ฉด ๋ณ€ํ•œ ๊ฒƒ' ๋ถˆ๋ณ€์‹์„
๋ณต์›ํ•œ๋‹ค. reached๋Š” '์•ฑ์ด ๋ชฉํ‘œ์— ๋„๋‹ฌํ–ˆ๋‚˜'๋ผ๋Š” ๋‹ค๋ฅธ ์งˆ๋ฌธ์ด๋ฏ€๋กœ ๊ด€๋Œ€ํ•œ ๊ฐ’์„ ์œ ์ง€ํ•œ๋‹ค.

์˜ํ–ฅ ๋ฒ”์œ„(์ˆ˜์ • ์ „ ์Šค์œ•): 7๊ฐœ ๋ช…๋ น 384์กฐํ•ฉ โ€” ์ƒ๋Œ€ ์ถ•์†Œ 100pt ํ•˜ํ•œ ๊ตฌ๊ฐ„, ์ ˆ๋Œ€ ๋ฐฐ์น˜,
์ด๋™ ํด๋žจํ”„ ๊ตฌ๊ฐ„. ์ˆ˜์ • ํ›„ ๋™์ผ ์Šค์œ•์—์„œ ๋ถˆ์ผ์น˜ 0.
b7692e5(#97)์—์„œ ๋“ค์–ด์˜จ ํšŒ๊ท€.

* fix(window): clamp anchored origin and reject non-finite app sizes

anchoredOrigin์˜ .right/.bottom ๊ฒฝ๋กœ์— ์ž‘์—…์˜์—ญ ํด๋žจํ”„๊ฐ€ ์—†์—ˆ๋‹ค. M-4 ์ด์ „์—๋Š” ์ƒ๋Œ€ ์ถ•์†Œ๋„
workAreaEdges(ํด๋žจํ”„ ์žˆ์Œ) ๊ฒฝ๋กœ๋ฅผ ํƒ”์œผ๋ฏ€๋กœ, ๋ช…์‹œ์  anchor๋ฅผ ๋„์ž…ํ•˜๋ฉฐ ๋ณดํ˜ธ๋ฅผ ์žƒ์€ ํšŒ๊ท€๋‹ค.
์ตœ์†Œํญ์ด ํฐ ์ œ์•ฝ ์•ฑ์„ ํ™”๋ฉด ์™ผ์ชฝ ๊ทผ์ฒ˜์—์„œ ์šฐ์ธก ์•ต์ปค๋กœ ์ถ•์†Œํ•˜๋ฉด ๊ณ ์ • ๋ชจ์„œ๋ฆฌ๋ฅผ ์ง€ํ‚ค๋ ค๋‹ค ์ฐฝ์ด
์ž‘์—…์˜์—ญ ๋ฐ–์œผ๋กœ ๋ฐ€๋ ธ๋‹ค(์˜ˆ: target.maxX=350, ์•ฑ ์‹ค์ œํญ 800 โ†’ x=-450).

๋˜ actualSize์˜ ์œ ํ•œ์„ฑ์„ ๊ฒ€์‚ฌํ•˜์ง€ ์•Š์•„, ์•ฑ์ด NaN/๋ฌดํ•œ ํฌ๊ธฐ๋ฅผ ๋ณด๊ณ ํ•˜๋ฉด NaN origin์ด ๊ทธ๋Œ€๋กœ
AX ์“ฐ๊ธฐ๋กœ ํ˜๋Ÿฌ๊ฐ”๋‹ค. ๋น„์ •์ƒ ํฌ๊ธฐ๋ฉด ์•ต์ปค ๋ณด์ •์„ ํฌ๊ธฐํ•˜๊ณ  ๋ชฉํ‘œ origin์„ ์“ด๋‹ค.

๋‘˜ ๋‹ค b7692e5(#97)์—์„œ ๋“ค์–ด์˜จ ํšŒ๊ท€. ํšŒ๊ท€ ํ…Œ์ŠคํŠธ 3๊ฑด ์ถ”๊ฐ€(ํด๋žจํ”„ ์ขŒ/ํ•˜, NaN ํด๋ฐฑ).

* fix(window): reject invalid AX frames and make screen picks order-independent

๋ฆฌ๋ทฐ์—์„œ ์ถ”๊ฐ€๋กœ ๋“œ๋Ÿฌ๋‚œ 3๊ฑด. ์•ž์„  ๋‘ ํšŒ๊ท€์™€ ๊ฐ™์€ ๊ณ„์—ด(ํ—ˆ์šฉ์˜ค์ฐจยท๋น„๊ต์ž ์„ค๊ณ„)์ด๋‹ค.

1) Writer์˜ readFrame์ด ๋น„์ •์ƒ frame์„ ๊ฑฐ๋ฅด์ง€ ์•Š์•„, NaN achieved๊ฐ€ Executor๋กœ ํ˜๋Ÿฌ๊ฐ€
   FrameApply.changed์—์„œ 'true'(NaN ๋น„๊ต๋Š” ์ „๋ถ€ false โ†’ ๋‹ค๋ฆ„์œผ๋กœ ํŒ์ •)๊ฐ€ ๋˜๊ณ  **ํ—ˆ์œ„ undo
   ํ•ญ๋ชฉ**์ด ๋ฉ€์ฉกํ•œ ์ง์ „ ํ•ญ๋ชฉ์„ ๋ฎ์—ˆ๋‹ค. readFrame์—์„œ isUsableFrame์œผ๋กœ ์ฐจ๋‹จํ•œ๋‹ค.

2) NSScreen.bestMatch์˜ ์ˆœ์ฐจ ๋น„๊ต์ž๊ฐ€ ๋น„์ถ”์ด์ ์ด์—ˆ๋‹ค. ๋™๋ฅ ๋กœ ์ด๊ธด ํ™”๋ฉด์˜ ๋” ์ž‘์€ ๋ฉด์ ์ด
   ๊ธฐ์ค€(bestArea)์„ ๋‚ฎ์ถฐ ์ดํ›„ ํ›„๋ณด์˜ ๋ฌธํ„ฑ์ด ๋‚ด๋ ค๊ฐ€๊ณ , ์—ด๊ฑฐ ์ˆœ์„œ์— ๋”ฐ๋ผ ์ตœ๋Œ€ ๋ฉด์ ์ด ์•„๋‹Œ
   ํ™”๋ฉด์ด ๋ฝ‘ํž ์ˆ˜ ์žˆ์—ˆ๋‹ค(L-1์ด ์—†์• ๋ ค๋˜ ์ˆœ์„œ ์˜์กด์„ฑ). ์ตœ๋Œ€ ๋ฉด์ ์„ ๋จผ์ € ํ™•์ •ํ•œ ๋’ค ๊ทธ ๋™๋ฅ 
   ์ง‘ํ•ฉ์—์„œ๋งŒ ์ฐฝ ์ค‘์‹ฌ ํฌํ•จ โ†’ ์ž‘์€ displayID๋กœ ๊ณ ๋ฅด๋Š” 2-ํŒจ์Šค๋กœ ๋ฐ”๊พผ๋‹ค.

3) ๊ฐ™์€ ํŒจํ„ด์ด selectAdjacentIndex์—๋„ ์žˆ์—ˆ๋‹ค. perpendicular ๋น„๊ต์— ๋ฐ๋“œ๋ฐด๋“œ๋ฅผ ์“ฐ๋ฉด
   [1.2,0.8,0.4,0.0]์—์„œ ์ตœ์†Œ๊ฐ€ ์•„๋‹Œ 0.4๊ฐ€ ๋ฝ‘ํžˆ๊ณ  ์ˆœ์„œ๋ฅผ ๋’ค์ง‘์œผ๋ฉด ๊ฒฐ๊ณผ๊ฐ€ ๋‹ฌ๋ผ์กŒ๋‹ค. ๋น„๊ต์—์„œ
   ๋ฐ๋“œ๋ฐด๋“œ๋ฅผ ๋นผ ์ฐธ ์ตœ์†Ÿ๊ฐ’์„ ๊ณ ๋ฅด๊ฒŒ ํ•œ๋‹ค(์ •ํ™• ๋™๋ฅ ๋งŒ ๋จผ์ € ๋‚˜์˜จ ์ธ๋ฑ์Šค).
   ์‚ญ์ œ๋œ tiebreak๋ฅผ ์—ฌ์ „ํžˆ ์•ฝ์†ํ•˜๋˜ ํ—ค๋” ์ฃผ์„๋„ ์ •์ •.

ํšŒ๊ท€ ํ…Œ์ŠคํŠธ 2๊ฑด ์ถ”๊ฐ€(์‚ฌ๋‹ค๋ฆฌ ์ •ยท์—ญ์ˆœ). 194 checks.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant