Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

48 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

SpaceWidget

macOS Space๋ณ„ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ํ”Œ๋กœํŒ… ์œ„์ ฏ. ์—ฌ๋Ÿฌ ํ”„๋กœ์ ํŠธ๋ฅผ Space๋ณ„๋กœ ๋‚˜๋ˆ  ์“ฐ๋Š” ํ๋ฆ„์—์„œ, ๊ธฐ๋ณธ Dock์ด ํ˜„์žฌ Space์˜ ์ž‘์—… ๋งฅ๋ฝ์„ ์ถฉ๋ถ„ํžˆ ๋ณด์—ฌ์ฃผ์ง€ ๋ชปํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•ด ์‹œ์ž‘ํ•œ ํ”„๋กœ์ ํŠธ์ž…๋‹ˆ๋‹ค.

ํ˜„์žฌ Space์˜ ๋ฒˆํ˜ธ์™€ ์ปจํ…์ŠคํŠธ ๋ผ๋ฒจ, ํ•ด๋‹น Space์—์„œ ์ž‘์—… ์ค‘์ธ ์•ฑ ๋ชฉ๋ก์„ ํ•˜๋‹จ ํŒจ๋„์— ํ‘œ์‹œํ•˜๊ณ , ์ƒํƒœ๋ฅผ state.json์œผ๋กœ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.

Why

mac์„ ์“ฐ๋ฉด์„œ ์š”์ฆ˜ API ๊ธฐ๋ฐ˜ ํ”„๋กœ์ ํŠธ๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ๋ณ‘๋ ฌ๋กœ ๋‹ค๋ฃจ๋ฉด, ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ Space๋ฅผ ํ”„๋กœ์ ํŠธ ๋‹จ์œ„ ์ž‘์—… ์ปจํ…์ŠคํŠธ๋กœ ์“ฐ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋ฌธ์ œ๋Š” ๊ธฐ๋ณธ Dock์ด ํ˜„์žฌ Space ๊ธฐ์ค€์˜ ๋งฅ๋ฝ์„ ๋ช…ํ™•ํžˆ ๋ณด์—ฌ์ฃผ์ง€ ๋ชปํ•œ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.

SpaceWidget์€ ์ด ์ง€์ ์„ ๋ณด์™„ํ•ฉ๋‹ˆ๋‹ค.

  • ์ง€๊ธˆ ๋‚ด๊ฐ€ ์–ด๋А Space์—์„œ ์ž‘์—… ์ค‘์ธ์ง€ ๋ฐ”๋กœ ๋ณด์ด๊ฒŒ ํ•˜๊ณ 
  • ๊ทธ Space์˜ ์ปจํ…์ŠคํŠธ ๋ผ๋ฒจ์„ ์ง์ ‘ ๋ถ™์ผ ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๊ณ 
  • ํ˜„์žฌ ์ž‘์—… ์ค‘์ธ ์•ฑ๋งŒ ๋น ๋ฅด๊ฒŒ ํ›‘๊ณ  ๋‹ค์‹œ ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค

Preview

Menu Bar Icon

SpaceWidget menu bar icon

Live Screenshots

Space 1 screenshot

Space 2 screenshot

Features

Space-Aware Context Bar

  • ํ˜„์žฌ ํ™œ์„ฑ Space ๋ฒˆํ˜ธ์™€ ์ปจํ…์ŠคํŠธ ๋ผ๋ฒจ์„ ์ขŒํ•˜๋‹จ ํ”Œ๋กœํŒ… ๋ฐ”์— ํ‘œ์‹œ
  • Space ์ „ํ™˜ ์‹œ ์ž๋™ ๊ฐ์ง€ ๋ฐ ๊ฐฑ์‹ 
  • ๋ผ๋ฒจ ์˜์—ญ ํด๋ฆญ์œผ๋กœ ์ธ๋ผ์ธ ๋ผ๋ฒจ ํŽธ์ง‘
  • non-desktop space (fullscreen, overlay, tiled) ์ž๋™ ํ•„ํ„ฐ๋ง

Multi-Monitor Support

  • ์—ฐ๊ฒฐ๋œ ๋””์Šคํ”Œ๋ ˆ์ด๋งˆ๋‹ค ๋…๋ฆฝ ํŒจ๋„ ์ž๋™ ์ƒ์„ฑ
  • ๋ฏธ๋Ÿฌ๋ง: ์ฃผ ๋””์Šคํ”Œ๋ ˆ์ด์™€ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘
  • ํ™•์žฅ ๋””์Šคํ”Œ๋ ˆ์ด: ๋ณ„๋„ Space๋กœ ์ธ์‹, per-display ordinal๋กœ Space ๋ฒˆํ˜ธ ํ‘œ์‹œ, ๋…๋ฆฝ ๋ผ๋ฒจ ๊ด€๋ฆฌ
  • ๋””์Šคํ”Œ๋ ˆ์ด ์—ฐ๊ฒฐ/๋ถ„๋ฆฌ ์‹œ ํŒจ๋„ ์ž๋™ ์ถ”๊ฐ€/์ œ๊ฑฐ

Label Persistence

  • ๋ผ๋ฒจ์€ ์•ˆ์ •์ ์ธ spaceID์— ๊ณ ์ • (Space ์ˆœ์„œ ๋ณ€๊ฒฝ/ํ’€์Šคํฌ๋ฆฐ ์ „ํ™˜ ์‹œ์—๋„ ๋ผ๋ฒจ ์œ ์ง€)
  • Space ์ˆœ์„œ ๋ณ€๊ฒฝ ์‹œ ordinal ์ž๋™ ์žฌ๋ฐ”์ธ๋”ฉ
  • v1 ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜: __main__ sentinel entry๋กœ ordinal ๊ธฐ๋ฐ˜ ๊ตฌ ๋ผ๋ฒจ ๋ณด์กด
  • Dead-display fallback (Tier 0): ์ฃผ ๋””์Šคํ”Œ๋ ˆ์ด๊ฐ€ ๋ถ„๋ฆฌ๋˜์–ด ๋‹จ์ผ-๋””์Šคํ”Œ๋ ˆ์ด ๋ชจ๋“œ๊ฐ€ ๋˜๋ฉด, ๋‚จ์€ ๋””์Šคํ”Œ๋ ˆ์ด์— ์—ฐ๊ฒฐ์ด ๋Š๊ธด ๋””์Šคํ”Œ๋ ˆ์ด์˜ ๋ผ๋ฒจ์„ ordinal ๊ธฐ๋ฐ˜์œผ๋กœ shadow ํ‘œ์‹œ
  • Tier 0 write-back: shadow ์ƒํƒœ์—์„œ ํŽธ์ง‘ ์‹œ ์›๋ณธ(๋ถ„๋ฆฌ๋œ) ๋””์Šคํ”Œ๋ ˆ์ด์˜ entry๋ฅผ ๊ฐฑ์‹ ํ•ด ์žฌ์—ฐ๊ฒฐ ์‹œ ํŽธ์ง‘ ๋‚ด์šฉ ๋ณต์›
  • ์„ ํƒ ์•ˆ์ •์„ฑ: tiebreaker๋กœ dead-display ์„ ํƒ์„ ๊ฒฐ์ •์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•ด ์ค‘๋ณต ๋ฎ์–ด์“ฐ๊ธฐ ๋ฐฉ์ง€

Running App Snapshot

  • ํ˜„์žฌ Space์—์„œ ์‹คํ–‰ ์ค‘์ธ ์•ฑ์„ ์ˆ˜์ง‘ํ•ด ์•„์ด์ฝ˜ ๋ชฉ๋ก์œผ๋กœ ๋ Œ๋”๋ง
  • ์•ฑ๋ณ„ ์œˆ๋„์šฐ ์ˆ˜ ์ง‘๊ณ„
  • ํฌ์ปค์Šค๋œ ์•ฑ ํ•˜์ด๋ผ์ดํŠธ ํ‘œ์‹œ
  • ์ˆจ๊น€/์ตœ์†Œํ™”๋œ ์•ฑ ๊ฐ์ง€ ๋ฐ ํ‘œ์‹œ
  • ์•„์ด์ฝ˜ ํด๋ฆญ์œผ๋กœ ์•ฑ ํ™œ์„ฑํ™” (์ตœ์†Œํ™”/์ˆจ๊น€ ์ƒํƒœ ํ•ด์ œ ํฌํ•จ)
  • ์ตœ๋Œ€ 20๊ฐœ ์•ฑ ํ‘œ์‹œ

Icon Pagination

  • ํŽ˜์ด์ง€๋‹น ์•„์ด์ฝ˜ ์ˆ˜ ์„ค์ • ๊ฐ€๋Šฅ (5~10๊ฐœ, ๊ธฐ๋ณธ 5)
  • ์ขŒ์šฐ ์Šค์™€์ดํ”„๋กœ ํŽ˜์ด์ง€ ์ „ํ™˜
  • ๊ฒฝ๊ณ„์—์„œ ๋Ÿฌ๋ฒ„๋ฐด๋“œ ํšจ๊ณผ
  • ํ•˜๋‹จ ํŽ˜์ด์ง€ ์ธ๋””์ผ€์ดํ„ฐ ๋„ํŠธ
  • ํฌ์ปค์Šค๋œ ์•ฑ์ด ์žˆ๋Š” ํŽ˜์ด์ง€๋กœ ์ž๋™ ์ด๋™

Balloon Context Menu

  • ์•ฑ ์•„์ด์ฝ˜ ์šฐํด๋ฆญ ์‹œ ๋งํ’์„  ํ˜•ํƒœ์˜ ์ปจํ…์ŠคํŠธ ๋ฉ”๋‰ด ํ‘œ์‹œ
  • New Window: ์ƒˆ ์ฐฝ ์—ด๊ธฐ (AX API ๋ฉ”๋‰ด ํƒ์ƒ‰ โ†’ CGEvent Cmd+N ํด๋ฐฑ)
  • Close from Space: ํ˜„์žฌ Space์˜ ํ•ด๋‹น ์•ฑ ์œˆ๋„์šฐ๋งŒ ๋‹ซ๊ธฐ (sticky ์œˆ๋„์šฐ ์ œ์™ธ)
  • Quit: ์•ฑ ์ข…๋ฃŒ
  • ํ™”๋ฉด ๋ฐ– ๋ฐฉ์ง€ ํด๋žจํ•‘

Window Snapping

๋‹จ์ถ•ํ‚ค๋กœ ์ฐฝ์„ ํ™”๋ฉด์˜ ํŠน์ • ์˜์—ญ์— ๋ฐฐ์น˜:

๋™์ž‘ ๊ธฐ๋ณธ ๋‹จ์ถ•ํ‚ค
์™ผ์ชฝ ์ ˆ๋ฐ˜ Cmd+Ctrl+โ†
์˜ค๋ฅธ์ชฝ ์ ˆ๋ฐ˜ Cmd+Ctrl+โ†’
์ตœ๋Œ€ํ™” Cmd+Ctrl+Enter
์ตœ์†Œํ™” Cmd+Ctrl+Esc
์ฒซ ๋ฒˆ์งธ 1/3 Cmd+Ctrl+D
๊ฐ€์šด๋ฐ 1/3 Cmd+Ctrl+F
๋งˆ์ง€๋ง‰ 1/3 Cmd+Ctrl+G
์ฒซ ๋ฒˆ์งธ 2/3 Cmd+Ctrl+E
๊ฐ€์šด๋ฐ 2/3 Cmd+Ctrl+V
๋งˆ์ง€๋ง‰ 2/3 Cmd+Ctrl+T

๋ชจ๋“  ๋‹จ์ถ•ํ‚ค๋Š” Preferences์—์„œ ์ปค์Šคํ„ฐ๋งˆ์ด์ฆˆ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

Layout Templates

  • ์œˆ๋„์šฐ ๋ ˆ์ด์•„์›ƒ ํ…œํ”Œ๋ฆฟ ์ƒ์„ฑ/ํŽธ์ง‘/์‚ญ์ œ/๋ณต์ œ
  • ํ…œํ”Œ๋ฆฟ์— ์œˆ๋„์šฐ ๋ฐฐ์น˜ ์กด(zone) ์ •์˜ (WindowAction ๊ธฐ๋ฐ˜)
  • ์กด๋ณ„ ์•ฑ bundle ID ํ• ๋‹น
  • ํ…œํ”Œ๋ฆฟ๋ณ„ ํ‚ค๋ณด๋“œ ๋‹จ์ถ•ํ‚ค ์ง€์ •
  • Space๋ณ„ Auto-Apply: Space ์ „ํ™˜ ์‹œ ์ž๋™์œผ๋กœ ํ…œํ”Œ๋ฆฟ ์ ์šฉ
  • Launch Closed Apps: ํ…œํ”Œ๋ฆฟ ์ ์šฉ ์‹œ ์‹คํ–‰๋˜์ง€ ์•Š์€ ์•ฑ ์ž๋™ ์‹คํ–‰

Hidden Apps

  • Preferences โ†’ Hidden Apps ํƒญ์—์„œ ์œ„์ ฏ ๋ฐ”์— ํ‘œ์‹œํ•˜์ง€ ์•Š์„ ์•ฑ ๊ด€๋ฆฌ
  • SpaceWidget์€ ๊ธฐ๋ณธ ์ œ์™ธ ํ•ญ๋ชฉ (์‚ญ์ œ ๋ถˆ๊ฐ€)
  • Add App ๋ฒ„ํŠผ์œผ๋กœ ์„ค์น˜๋œ ์•ฑ(.app) ์„ ํƒํ•˜์—ฌ ์ œ์™ธ ๋ชฉ๋ก์— ์ถ”๊ฐ€
  • ์Šคํฌ๋ฆฐ ์บก์ฒ˜ ๋„๊ตฌ(Flameshot ๋“ฑ) ์‚ฌ์šฉ ์‹œ ์œ„์ ฏ ํŒจ๋„์ด ์บก์ฒ˜์— ํฌํ•จ๋˜์ง€ ์•Š์Œ

Desktop Switcher

  • Space ๋ฒˆํ˜ธ ํด๋ฆญ ์‹œ ํ•ด๋‹น ๋””์Šคํ”Œ๋ ˆ์ด์˜ ์ „์ฒด ๋ฐ์Šคํฌํƒ‘ ๋ชฉ๋ก ํŒ์—… ํ‘œ์‹œ
  • ๋ชฉ๋ก์—์„œ ๋ฐ์Šคํฌํƒ‘ ์„ ํƒ ์‹œ CGEvent dock-swipe ํ•ฉ์„ฑ์œผ๋กœ ์ฆ‰์‹œ ์ „ํ™˜
  • Ctrl+N ํ‚ค๋ณด๋“œ ๋‹จ์ถ•ํ‚ค ํด๋ฐฑ (์‹œ์Šคํ…œ ์„ค์ •์—์„œ ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ)
  • ๋ฉ€ํ‹ฐ ๋””์Šคํ”Œ๋ ˆ์ด: active display ๊ฒ€์ฆ ๊ฐ€๋“œ๋กœ ์ž˜๋ชป๋œ ๋””์Šคํ”Œ๋ ˆ์ด ์ „ํ™˜ ๋ฐฉ์ง€
  • ์ „ํ™˜ ํ›„ ์‹ค์ œ Space ๋ณ€๊ฒฝ ๊ฒ€์ฆ (์‹คํŒจ ์‹œ ์ž๋™ ํด๋ฐฑ)

Dock Overlap Detection

  • Dock๊ณผ ์œ„์ ฏ ๋ฐ”๊ฐ€ ๊ฒน์น  ๋•Œ ํŽ˜์ด์ง€๋‹น ์•„์ด์ฝ˜ ์ˆ˜๋ฅผ ์ž๋™์œผ๋กœ ์ถ•์†Œ
  • ์„ค์ •: enabled (ํ™œ์„ฑํ™”), min_icons (์ตœ์†Œ ์•„์ด์ฝ˜ ์ˆ˜ 210), reduce_step (์ถ•์†Œ ๋‹จ์œ„ 12)
  • Dock ์œ„์น˜/ํฌ๊ธฐ ๋ณ€๊ฒฝ ์‹œ ์‹ค์‹œ๊ฐ„ ์žฌ๊ณ„์‚ฐ
  • ์ถ•์†Œํ•ด๋„ ๊ฒน์นจ์ด ํ•ด์†Œ๋˜์ง€ ์•Š์œผ๋ฉด ์›๋ž˜ ์„ค์ • ์œ ์ง€

Auto-Hide

  • ๋ฐ” ์ž๋™ ์ˆจ๊น€ ๋ชจ๋“œ ํ† ๊ธ€
  • ๋งˆ์šฐ์Šค๋ฅผ ๋ฐ” ์˜์—ญ์— ์˜ฌ๋ฆฌ๋ฉด ํ‘œ์‹œ, ๋– ๋‚˜๋ฉด 0.3์ดˆ ํ›„ ์ˆจ๊น€
  • Hot Zone ๊ฐ์ง€ ์˜์—ญ์œผ๋กœ ๋งˆ์šฐ์Šค ์ง„์ž…/์ดํƒˆ ์ถ”์ 

Dock Control

macOS Dock ๋™์ž‘ ์ œ์–ด (CoreDock private framework ์‚ฌ์šฉ):

๋ชจ๋“œ ์„ค๋ช…
Auto Hide ๊ธฐ๋ณธ macOS ์ž๋™ ์ˆจ๊น€ ๋™์ž‘
Always Hide ์˜๊ตฌ ์ˆจ๊น€ (๋Œ€๊ธฐ ์‹œ๊ฐ„ ๊ทน๋Œ€ํ™”)
Always Show ํ•ญ์ƒ ํ‘œ์‹œ

์•ฑ ์ข…๋ฃŒ ์‹œ ์›๋ž˜ Dock ์„ค์ • ๋ณต์›.

Menu Bar

๋ฉ”๋‰ด๋ฐ” ์•„์ด์ฝ˜์œผ๋กœ ๋น ๋ฅธ ์„ค์ • ์ ‘๊ทผ:

  • Auto Hide ํ† ๊ธ€
  • Icons per Page ์„ค์ • (5~10)
  • Dock ๋ชจ๋“œ ์„ ํƒ
  • Layout ํ…œํ”Œ๋ฆฟ ๋ชฉ๋ก ๋ฐ ์ ์šฉ
  • Auto-Apply ํ† ๊ธ€
  • Preferences ์—ด๊ธฐ
  • Quit SpaceWidget

Preferences UI

  • Shortcuts ํƒญ: ์œˆ๋„์šฐ ์Šค๋ƒ… ๋‹จ์ถ•ํ‚ค ํ™œ์„ฑํ™”/๋น„ํ™œ์„ฑํ™”, ์ƒˆ ๋‹จ์ถ•ํ‚ค ๋…นํ™”, ๊ธฐ๋ณธ๊ฐ’ ๋ณต์›
  • Layouts ํƒญ: ๋ ˆ์ด์•„์›ƒ ํ…œํ”Œ๋ฆฟ ์ƒ์„ฑ/ํŽธ์ง‘/์‚ญ์ œ, ์•ฑ ํ• ๋‹น, Space๋ณ„ Auto-Apply ์„ค์ •
  • Hidden Apps ํƒญ: ์œ„์ ฏ ๋ฐ”์—์„œ ์ œ์™ธํ•  ์•ฑ ๊ด€๋ฆฌ (๊ธฐ๋ณธ ํ•ญ๋ชฉ + ์‚ฌ์šฉ์ž ์ถ”๊ฐ€)

State Export

  • ~/.config/space-dock/state.json์— ํ˜„์žฌ ์ƒํƒœ ๊ธฐ๋ก
  • ๋‚ด์šฉ: current_space, space_id, space_label, apps ๋ฐฐ์—ด
  • 1์ดˆ ๋””๋ฐ”์šด์Šค๋กœ ๊ณผ๋„ํ•œ ์“ฐ๊ธฐ ๋ฐฉ์ง€
  • CLI ์Šคํฌ๋ฆฝํŠธ ๋ฐ ์™ธ๋ถ€ ์ž๋™ํ™” ์—ฐ๋™์šฉ

Architecture

space-widget/
โ”œโ”€โ”€ Sources/SpaceWidget/
โ”‚   โ”œโ”€โ”€ App/
โ”‚   โ”‚   โ”œโ”€โ”€ SpaceWidgetApp.swift              โ† ์•ฑ ์ง„์ž…์ , ์˜์กด์„ฑ ์กฐ๋ฆฝ
โ”‚   โ”‚   โ”œโ”€โ”€ MenuBarController.swift           โ† ๋ฉ”๋‰ด๋ฐ” ์•„์ด์ฝ˜ + ์„ค์ • ๋ฉ”๋‰ด
โ”‚   โ”‚   โ”œโ”€โ”€ PreferencesWindowController.swift โ† ์„ค์ • ์ฐฝ ๋ผ์ดํ”„์‚ฌ์ดํด
โ”‚   โ”‚   โ””โ”€โ”€ DockController.swift              โ† macOS Dock ๋™์ž‘ ์ œ์–ด (CoreDock)
โ”‚   โ”œโ”€โ”€ Config/
โ”‚   โ”‚   โ”œโ”€โ”€ ConfigManager.swift           โ† ์„ค์ • ๋กœ๋“œ/์ €์žฅ (labels, ignored apps, shortcuts ๋“ฑ)
โ”‚   โ”‚   โ”œโ”€โ”€ Logger.swift                  โ† ํŒŒ์ผ + stderr ๋กœ๊ทธ
โ”‚   โ”‚   โ”œโ”€โ”€ Migrator.swift                โ† sketchybar โ†’ space-dock ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜
โ”‚   โ”‚   โ”œโ”€โ”€ StateWriter.swift             โ† state.json ๊ธฐ๋ก
โ”‚   โ”‚   โ”œโ”€โ”€ OverlapDetection.swift        โ† Dock-์œ„์ ฏ ๊ฒน์นจ ๊ฐ์ง€/์•„์ด์ฝ˜ ์ˆ˜ ์ถ•์†Œ ๊ณ„์‚ฐ
โ”‚   โ”‚   โ””โ”€โ”€ ShortcutBinding.swift         โ† ๋‹จ์ถ•ํ‚ค ๋ฐ”์ธ๋”ฉ ๋ชจ๋ธ
โ”‚   โ”œโ”€โ”€ Engine/
โ”‚   โ”‚   โ”œโ”€โ”€ SpaceMonitor.swift            โ† ์ „์ฒด ๋””์Šคํ”Œ๋ ˆ์ด Space ๊ฐ์ง€
โ”‚   โ”‚   โ”œโ”€โ”€ WindowListProvider.swift      โ† ์•ฑ ๋ชฉ๋ก ์ˆ˜์ง‘ (ํ™”๋ฉด๋ณ„ ํ•„ํ„ฐ๋ง)
โ”‚   โ”‚   โ”œโ”€โ”€ SpaceEngine.swift             โ† ๋ฉ€ํ‹ฐ ๋””์Šคํ”Œ๋ ˆ์ด snapshot ํŒŒ์ดํ”„๋ผ์ธ
โ”‚   โ”‚   โ”œโ”€โ”€ CGSPrivate.swift              โ† CGS private API bridge
โ”‚   โ”‚   โ”œโ”€โ”€ AppActions.swift              โ† ์•ฑ ์•ก์…˜ (new window, close, activate)
โ”‚   โ”‚   โ”œโ”€โ”€ SpaceSwitcher.swift           โ† CGEvent dock-swipe ๊ธฐ๋ฐ˜ Space ์ „ํ™˜
โ”‚   โ”‚   โ”œโ”€โ”€ CoreDockBridge.swift          โ† CoreDock private API bridge
โ”‚   โ”‚   โ”œโ”€โ”€ DockGeometry.swift            โ† Dock ์œ„์น˜/ํฌ๊ธฐ ๊ณ„์‚ฐ
โ”‚   โ”‚   โ””โ”€โ”€ WindowMoveObserver.swift      โ† ์œˆ๋„์šฐ ์ด๋™/๋ฆฌ์‚ฌ์ด์ฆˆ ๊ฐ์ง€
โ”‚   โ”œโ”€โ”€ Panel/
โ”‚   โ”‚   โ”œโ”€โ”€ SpacePanel.swift              โ† ํˆฌ๋ช… NSPanel (์Šคํฌ๋ฆฐ ์บก์ฒ˜ ์ œ์™ธ)
โ”‚   โ”‚   โ”œโ”€โ”€ SpacePanelController.swift    โ† ๋ฉ€ํ‹ฐ ํŒจ๋„ ์ƒ์„ฑ/์—…๋ฐ์ดํŠธ/์ œ๊ฑฐ
โ”‚   โ”‚   โ”œโ”€โ”€ BalloonMenuPanel.swift        โ† ์šฐํด๋ฆญ ๋งํ’์„  ๋ฉ”๋‰ด
โ”‚   โ”‚   โ”œโ”€โ”€ DesktopListMenuContent.swift  โ† ๋ฐ์Šคํฌํƒ‘ ๋ฆฌ์ŠคํŠธ ํŒ์—… UI
โ”‚   โ”‚   โ””โ”€โ”€ AutoHideManager.swift         โ† ๋ฐ” ์ž๋™ ์ˆจ๊น€ ์ƒํƒœ ๊ด€๋ฆฌ
โ”‚   โ”œโ”€โ”€ Views/
โ”‚   โ”‚   โ”œโ”€โ”€ SpaceBarView.swift            โ† SwiftUI ๋ฐ” UI
โ”‚   โ”‚   โ”œโ”€โ”€ PreferencesView.swift         โ† ์„ค์ • UI (Shortcuts, Layouts, Hidden Apps ํƒญ)
โ”‚   โ”‚   โ”œโ”€โ”€ ShortcutRecorderView.swift    โ† ๋‹จ์ถ•ํ‚ค ๋…นํ™” ๋ทฐ
โ”‚   โ”‚   โ”œโ”€โ”€ LayoutTemplatesView.swift     โ† ๋ ˆ์ด์•„์›ƒ ํ…œํ”Œ๋ฆฟ ํŽธ์ง‘ ๋ทฐ
โ”‚   โ”‚   โ””โ”€โ”€ WindowActionIcon.swift        โ† ์œˆ๋„์šฐ ๋ฐฐ์น˜ ์‹œ๊ฐํ™” ์•„์ด์ฝ˜
โ”‚   โ”œโ”€โ”€ Models/
โ”‚   โ”‚   โ”œโ”€โ”€ ActiveSpace.swift
โ”‚   โ”‚   โ”œโ”€โ”€ DockItem.swift
โ”‚   โ”‚   โ””โ”€โ”€ DockSnapshot.swift
โ”‚   โ”œโ”€โ”€ WindowManagement/
โ”‚   โ”‚   โ”œโ”€โ”€ WindowShortcutController.swift โ† ์œˆ๋„์šฐ ์Šค๋ƒ… ๋‹จ์ถ•ํ‚ค ๊ด€๋ฆฌ
โ”‚   โ”‚   โ”œโ”€โ”€ WindowSnapManager.swift        โ† AX API ๊ธฐ๋ฐ˜ ์œˆ๋„์šฐ ์กฐ์ž‘
โ”‚   โ”‚   โ”œโ”€โ”€ WindowElement.swift            โ† AX ์œˆ๋„์šฐ ๋ž˜ํผ
โ”‚   โ”‚   โ”œโ”€โ”€ WindowCalculation.swift        โ† ์ขŒํ‘œ ๊ณ„์‚ฐ (AX โ†” Cocoa)
โ”‚   โ”‚   โ”œโ”€โ”€ WindowAction.swift             โ† ์œˆ๋„์šฐ ๋ฐฐ์น˜ ์•ก์…˜ ์ •์˜
โ”‚   โ”‚   โ”œโ”€โ”€ ScreenGeometry.swift           โ† ํ™”๋ฉด ์ง€์˜ค๋ฉ”ํŠธ๋ฆฌ ์œ ํ‹ธ
โ”‚   โ”‚   โ”œโ”€โ”€ LayoutApplier.swift            โ† ๋ ˆ์ด์•„์›ƒ ํ…œํ”Œ๋ฆฟ ์ ์šฉ
โ”‚   โ”‚   โ”œโ”€โ”€ LayoutTemplate.swift           โ† ๋ ˆ์ด์•„์›ƒ ํ…œํ”Œ๋ฆฟ ๋ชจ๋ธ
โ”‚   โ”‚   โ”œโ”€โ”€ LayoutTemplateStore.swift      โ† ํ…œํ”Œ๋ฆฟ ์ €์žฅ์†Œ
โ”‚   โ”‚   โ”œโ”€โ”€ SpaceLayoutBridge.swift        โ† Space ์ „ํ™˜ โ†’ ๋ ˆ์ด์•„์›ƒ ์ž๋™ ์ ์šฉ
โ”‚   โ”‚   โ””โ”€โ”€ HotKeyManager.swift            โ† ์ „์—ญ ๋‹จ์ถ•ํ‚ค ๋“ฑ๋ก (Carbon)
โ”‚   โ””โ”€โ”€ Resources/
โ”‚       โ””โ”€โ”€ icon.png                       โ† ๋ฉ”๋‰ด๋ฐ” ์•„์ด์ฝ˜
โ”œโ”€โ”€ RunSpaceWidget.app              โ† ํ„ฐ๋ฏธ๋„ ์—†์ด ์‹คํ–‰๋˜๋Š” Finder ๋Ÿฐ์ฒ˜
โ”œโ”€โ”€ RunSpaceWidget.command          โ† ํ„ฐ๋ฏธ๋„ ๊ธฐ๋ฐ˜ ๋Ÿฐ์ฒ˜
โ”œโ”€โ”€ Makefile
โ””โ”€โ”€ README.md

Data Flow

ConfigManager
    โ”œโ”€ ignored apps, space labels
    โ”œโ”€ shortcuts, templates
    โ””โ”€ settings (icons per page)

SpaceMonitor (per-display)
    โ””โ”€ displaySpaces: [DisplayID: ActiveSpace]

WindowListProvider
    โ””โ”€ fetchItems (screen-filtered + space-aware)

SpaceEngine
    โ”œโ”€ publishes snapshots: [DisplayID: DockSnapshot]
    โ”œโ”€ reacts to space changes (all displays)
    โ””โ”€ reacts to app activate / launch / terminate / hide

Subscribers
    โ”œโ”€ StateWriter              โ†’ state.json (main display only)
    โ”œโ”€ SpacePanelController     โ†’ N SpacePanels (1 per display)
    โ””โ”€ SpaceLayoutBridge        โ†’ auto-apply templates on space change

Runtime Responsibilities

Component ์—ญํ• 
ConfigManager ์„ค์ • ๋””๋ ‰ํ„ฐ๋ฆฌ ๊ด€๋ฆฌ, ๊ธฐ๋ณธ ํŒŒ์ผ ์ƒ์„ฑ, ๋ชจ๋“  ์„ค์ • ๋กœ๋“œ/์ €์žฅ
SpaceMonitor ์ „์ฒด ๋””์Šคํ”Œ๋ ˆ์ด์˜ ํ™œ์„ฑ Space ๊ฐ์ง€, per-display ordinal ๊ณ„์‚ฐ
WindowListProvider ํ™”๋ฉด์ƒ ์•ฑ ๋ชฉ๋ก ์ˆ˜์ง‘, ํ™”๋ฉด๋ณ„ ํ•„ํ„ฐ๋ง, bundle ๋‹จ์œ„ dedupe
SpaceEngine ๋””์Šคํ”Œ๋ ˆ์ด๋ณ„ DockSnapshot ์†Œ์œ , refresh scheduling, stale drop
StateWriter state.json debounce ๊ธฐ๋ก (์ฃผ ๋””์Šคํ”Œ๋ ˆ์ด)
SpacePanelController ๋””์Šคํ”Œ๋ ˆ์ด๋ณ„ ํŒจ๋„ ์ƒ์„ฑ/์ œ๊ฑฐ/๋ฆฌ์‚ฌ์ด์ฆˆ, snapshot ๊ธฐ๋ฐ˜ UI ๊ฐฑ์‹ 
SpaceSwitcher CGEvent dock-swipe ํ•ฉ์„ฑ์œผ๋กœ Space ์ „ํ™˜, Ctrl+N ํด๋ฐฑ
SpaceBarView Space ๋ผ๋ฒจ/์•ฑ ์•„์ด์ฝ˜ ๋ Œ๋”๋ง, ์Šค์™€์ดํ”„, ์•ฑ ํ™œ์„ฑํ™”
MenuBarController ๋ฉ”๋‰ด๋ฐ” ์•„์ด์ฝ˜ + ์ „์ฒด ์„ค์ • ๋ฉ”๋‰ด
WindowShortcutController ์œˆ๋„์šฐ ์Šค๋ƒ… ์ „์—ญ ๋‹จ์ถ•ํ‚ค ๊ด€๋ฆฌ
LayoutApplier ๋ ˆ์ด์•„์›ƒ ํ…œํ”Œ๋ฆฟ ์ ์šฉ (์•ฑ ๋Ÿฐ์น˜ + ์œˆ๋„์šฐ ๋ฐฐ์น˜)
SpaceLayoutBridge Space ์ „ํ™˜ ์‹œ ๋ ˆ์ด์•„์›ƒ ์ž๋™ ์ ์šฉ
AutoHideManager ๋ฐ” ์ž๋™ ์ˆจ๊น€ ์ƒํƒœ ๊ด€๋ฆฌ
DockController macOS Dock ๋™์ž‘ ์ œ์–ด (CoreDock)
OverlapDetection Dock-์œ„์ ฏ ๊ฒน์นจ ๊ฐ์ง€ ๋ฐ ์•„์ด์ฝ˜ ์ˆ˜ ์ถ•์†Œ ๊ณ„์‚ฐ
WindowMoveObserver ์œˆ๋„์šฐ ์ด๋™/๋ฆฌ์‚ฌ์ด์ฆˆ ๊ฐ์ง€

Quick Start

# ๋””๋ฒ„๊ทธ ๋นŒ๋“œ
swift build

# ๋ฐ”๋กœ ์‹คํ–‰
./.build/debug/SpaceWidget

# ํ„ฐ๋ฏธ๋„ ๋Ÿฐ์ฒ˜ ์‚ฌ์šฉ
./RunSpaceWidget.command

# Finder์—์„œ ๋”๋ธ”ํด๋ฆญ ์‹คํ–‰
open RunSpaceWidget.app

RunSpaceWidget.app์€ ํ„ฐ๋ฏธ๋„ ์ฐฝ ์—†์ด ์‹คํ–‰๋˜๋Š” Finder์šฉ ๋Ÿฐ์ฒ˜์ž…๋‹ˆ๋‹ค.

Install

# ๋ฆด๋ฆฌ์ฆˆ ๋นŒ๋“œ
make build

# /usr/local/bin/SpaceWidget ์„ค์น˜
make install

# ์„ค์น˜ ํ›„ ์‹คํ–‰
/usr/local/bin/SpaceWidget

# ์„ค์น˜ ํ›„ Finder ๋Ÿฐ์ฒ˜ ์‚ฌ์šฉ
open RunSpaceWidget.app

Configuration

๊ธฐ๋ณธ ์„ค์ • ๋””๋ ‰ํ„ฐ๋ฆฌ: ~/.config/space-dock/

Config Files

ํŒŒ์ผ ์„ค๋ช…
space_labels.json Space ๋ผ๋ฒจ ({"1": "Work", "2": "Browse", "displayID:1": "Extended"})
ignored_apps.json ๋ฐ”์—์„œ ์ œ์™ธํ•  ์•ฑ ๋ชฉ๋ก
app_actions.json ์•ฑ๋ณ„ ์ปค์Šคํ…€ ์•ก์…˜ (new window, quit ํ•ธ๋“ค๋Ÿฌ)
settings.json ์ผ๋ฐ˜ ์„ค์ • (icons_per_page)
shortcuts.json ์œˆ๋„์šฐ ์Šค๋ƒ… ๋‹จ์ถ•ํ‚ค ๋ฐ”์ธ๋”ฉ
templates.json ๋ ˆ์ด์•„์›ƒ ํ…œํ”Œ๋ฆฟ ์ •์˜
space_assignments.json Space โ†’ ํ…œํ”Œ๋ฆฟ ๋งคํ•‘, auto-apply ์„ค์ •

State Files

ํŒŒ์ผ ์„ค๋ช…
state.json ํ˜„์žฌ Space ์ƒํƒœ (์™ธ๋ถ€ ์Šคํฌ๋ฆฝํŠธ ์—ฐ๋™์šฉ)
spacewidget.log ์•ฑ ๋กœ๊ทธ (๋งค ์‹คํ–‰ ์‹œ ์ดˆ๊ธฐํ™”)

CLI Options

SpaceWidget --version           # ๋ฒ„์ „ ์ถœ๋ ฅ (0.1.0)
SpaceWidget --help              # ๋„์›€๋ง
SpaceWidget --migrate           # sketchybar ์„ค์ • ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜
SpaceWidget --migrate --force   # ๊ธฐ์กด ํŒŒ์ผ ๋ฎ์–ด์“ฐ๊ธฐ
SpaceWidget --config-dir PATH   # ์„ค์ • ๋””๋ ‰ํ„ฐ๋ฆฌ ์ง€์ •

Defaults

  • Space ๋ผ๋ฒจ ๊ธฐ๋ณธ๊ฐ’: "1" โ†’ "Work", "2" โ†’ "Browse"
  • ํŽ˜์ด์ง€๋‹น ์•„์ด์ฝ˜ ์ˆ˜: 5 (๋ฒ”์œ„: 5~10)
  • ์ตœ๋Œ€ ๋ Œ๋”๋ง ์•ฑ ์ˆ˜: 20
  • Fallback ๋ผ๋ฒจ: "Untitled"

Private APIs

SpaceWidget์€ macOS์˜ ๊ณต๊ฐœ๋˜์ง€ ์•Š์€ API๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค:

CGS (Core Graphics Server):

  • CGSMainConnectionID() โ€” CGS ์—ฐ๊ฒฐ ํš๋“
  • CGSCopyManagedDisplaySpaces() โ€” ๋””์Šคํ”Œ๋ ˆ์ด๋ณ„ Space ์—ด๊ฑฐ
  • CGSManagedDisplayGetCurrentSpace() โ€” ๋””์Šคํ”Œ๋ ˆ์ด๋ณ„ ํ˜„์žฌ Space ์กฐํšŒ
  • CGSSpaceGetType() โ€” Space ํƒ€์ž… ํŒ๋ณ„ (desktop/fullscreen/system/tiled)
  • CGSCopySpacesForWindows() โ€” ์œˆ๋„์šฐ๊ฐ€ ์†ํ•œ Space ์กฐํšŒ
  • CGSCopyActiveMenuBarDisplayIdentifier() โ€” ํ™œ์„ฑ ๋ฉ”๋‰ด๋ฐ” ๋””์Šคํ”Œ๋ ˆ์ด ์‹๋ณ„

CGEvent Gesture Synthesis:

  • dock-swipe ํ•ฉ์„ฑ ์ด๋ฒคํŠธ๋กœ Space ์ „ํ™˜ (CGEventField 55, 110, 119, 123, 124, 129, 130, 132, 135, 139)

CoreDock:

  • CoreDockGetAutoHideEnabled / CoreDockSetAutoHideEnabled โ€” Dock ์ž๋™ ์ˆจ๊น€ ์ œ์–ด

Accessibility (AX):

  • ์œˆ๋„์šฐ ์—ด๊ฑฐ, ์œ„์น˜/ํฌ๊ธฐ ์กฐ์ž‘, ๋ฉ”๋‰ด ํƒ์ƒ‰, ์ƒํƒœ ์กฐํšŒ

Requirements

  • macOS 14.0 (Sonoma) ์ด์ƒ
  • Swift 5.9+
  • Accessibility ๊ถŒํ•œ ํ•„์š” (์œˆ๋„์šฐ ์กฐ์ž‘, ๋ฉ”๋‰ด ํƒ์ƒ‰, ๋‹จ์ถ•ํ‚ค ๊ฐ์ง€)
  • ์™ธ๋ถ€ ์˜์กด์„ฑ ์—†์Œ (Foundation, AppKit, Combine, ApplicationServices๋งŒ ์‚ฌ์šฉ)

Development

swift build               # ๋””๋ฒ„๊ทธ ๋นŒ๋“œ
make build                # ๋ฆด๋ฆฌ์ฆˆ ๋นŒ๋“œ
make install              # ์„ค์น˜
make uninstall            # ์ œ๊ฑฐ
make migrate              # ์„ค์ • ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜
make clean                # ํด๋ฆฐ

Acknowledgements

๋‹ค์Œ ์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ์˜ ๊ตฌํ˜„์„ ์ฐธ๊ณ ํ–ˆ์Šต๋‹ˆ๋‹ค:

ํ”„๋กœ์ ํŠธ ์ฐธ๊ณ  ๋‚ด์šฉ
WhichSpace CGEvent dock-swipe ํ•ฉ์„ฑ์„ ํ†ตํ•œ Space ์ „ํ™˜ ๊ธฐ๋ฒ•. ๋น„๊ณต๊ฐœ CGEventField ์ธ๋ฑ์Šค์™€ gesture phase ์‹œํ€€์Šค ์ฐธ์กฐ
yabai CGS private API ์‚ฌ์šฉ ํŒจํ„ด (CGSCopyManagedDisplaySpaces, CGSSpaceGetType ๋“ฑ)
Rectangle AX API ๊ธฐ๋ฐ˜ ์œˆ๋„์šฐ ์Šค๋ƒ… ๋ฐ ํ™”๋ฉด ์˜์—ญ ๊ณ„์‚ฐ ๋กœ์ง ์ฐธ์กฐ

Notes

  • macOS ์ „์šฉ ํ”„๋กœ์ ํŠธ์ž…๋‹ˆ๋‹ค.
  • SwiftPM ๊ธฐ๋ฐ˜์œผ๋กœ ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค.
  • CGS private API๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ macOS ๋‚ด๋ถ€ ๋™์ž‘ ๋ณ€ํ™”์— ์˜ํ–ฅ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์•ฑ์€ .accessory ํ™œ์„ฑํ™” ์ •์ฑ…์œผ๋กœ ์‹คํ–‰๋˜์–ด Dock ์•„์ด์ฝ˜ ๋ฐ Cmd+Tab์— ํ‘œ์‹œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages