measurrred devlog #01

RanolP·2022년 3월 29일
0
post-thumbnail

Windows 11의 작업 표시줄은 아주 깔끔해졌습니다. 다시 말해, 비어있습니다. 앱 아이콘은 가운데 정렬되어 있고, 오른쪽은 시계와 트레이 아이콘 등의 것이 있습니다. 왼쪽 공간은 쓰이지 않습니다. 적어도 제가 개발 시작할 때는 그랬습니다. 마이크로소프트도 활용하려고 노력하더군요. 어쨌든, Windows 11의 작업 표시줄은 아주 콤팩트해져 여백을 남깁니다. 저는 그 버려진 공간을 활용하고 싶었습니다.

옛 Deskband API

Windows 11보다도 한참 옛날, 작업 표시줄에는 Deskband라는, 자체적인 컴포넌트를 작업 표시줄에 끼워넣을 수 있는 API가 존재했습니다. 하지만 비권장되었던 그 API는 Windows 11에서 결국 지워지고 맙니다. 네, 제가 그 영향으로 BatteryBarNetSpeedMonitor의 대안 프로그램을 찾아다니게 되었습니다. 물론, BatteryBar를 Floating Mode로 쓰고, NetSpeedMonitorTrafficSpeedMonitor를 쓰면 됩니다. 하지만, 저것들은 충분히 확정성이 높지도 않기도 하고... 이런 기이한 개발 경험을 지금 아니면 언제 쌓겠어요? 갑시다!

오버레이 만들기 (2022년 1월 9일)

TrafficSpeedMonitor의 소스 코드(Anti 996이라는 라이선스를 쓰는데요. MIT와 비슷합니다)를 찬찬히 분석해본 결과 작업 표시줄의 창 핸들을 가져와서 그걸 부모 창으로 하는 자체 창을 만들어서 그리는 방식이더군요. 그래서 저도 그 방식을 따르기로 했습니다.

Do Rust!

하지만... C++로 WinRT를 만지는 것과 Rust로 WinRT를 만지는 건 아주 다른 경험입니다. 다행히도 마이크로소프트는 제게 windows-rs라는 광명을 안겨주었습니다. 이 프로젝트는 단순히 C로 호출하던 WinAPI를 바인딩한 것이 아닙니다. WinRT에 있는 여러 라이브러리들을 통째로 감싼 겁니다 (C# 코드인 부분까지 깔끔하게 감싸져 있어 쓰기에 상당히 좋습니다).

The XAML Island? Sorry!

Windows에서 쓸 수 있는 UI 프레임워크는 꽤나 많습니다. GDI를 사용할 수도 있고, Windows Forms를 쓸 수도 있으며, WPF를 사용할 수도 있거니와, 웹뷰를 넣어버리기도 하고, WinUI라는 새로운 것까지 나와서 환장할 노릇입니다. 여기서, 제게 중요했던 가치는 플랫폼에서 권장하는 UI 느낌을 내는 것이었습니다. 그리고, 가능하면 최신 기술이면 좋겠다 싶어서 처음엔 WinUI 3을 찍먹해보기로 했습니다.

그런데, 아주 큰 문제가 있었습니다. In WinUI 3, is it possible to create a transparent Xaml Island overlay on top of parent hwnd?라는 이슈가 있었고, 거기에 달린 댓글은 제 예쁘고 멋질 오버레이에 투명도를 못 넣는다고 했으니까요!

어쩌겠습니까. 다시 기본으로 돌아가서, GDI를 깎아보기로 했습니다.

정보는 어디에서?

그런데, 오버레이가 있어도 정작 보여줄 정보가 단순한 정적 정보면 큰 가치가 없습니다. 본디 네트워크로 오가는 바이트의 양, 배터리 잔량 정도를 보여주고자 했고, 추가적으로 CPU나 메모리 사용량 등을 보여주고 싶었습니다. 이에 관해 검색해보니 PDH(Performance Data Helper)에 대해 찾아볼 수 있었습니다. 다양한 프로그램들이 제각각 Performance Counter를 갖고 있는데, 주기적으로 저 값을 읽어냄으로써 구간의 평균값을 알아낼 수 있는 것입니다. 현재 예시 위젯은 \Processor(_Total)\% Processor Time (총 CPU 사용 백분율)과 같은 카운터를 읽어냅니다.

한편, 메모리 사용량의 경우 Performance Counter로도 읽을 수는 있지만 GlobalMemoryStatusEx 함수를 이용하면 더 간편하게 읽어낼 수 있었습니다.

배터리 잔량의 경우 Windows.Devices.Power.Battery를 활용해 총량 및 잔량 정보를 읽어내 보여주기로 했습니다.

작동하는 프로토타입 (2022년 1월 13일)

썡 GDI를 사용해서 예쁘지 않고, 코드가 구조화되어 있지도 않지만 이건 작동합니다. 아주 중요한 가치죠. 이제 이걸 더 낫게 만들기만 하면 됩니다!

미학의 추구 (2022년 1월 16일)

갑작스럽지만 여러분께서는 SVG를 아십니까? 저는 이 SVG라는 것을 너무 좋아해서 여기에 넣었습니다. 당시 요구 사항이 텍스트를 잘 그리면서, 아이콘을 넣기에 좋고, 벡터 그래픽이면 좋겠다 (고해상도에서 안 깨지기 위함)였는데요. 정확히 이에 부합하는 유명한 포맷, SVG가 떠오르더군요. 제가 주로 웹 개발 커리어를 쌓아서 그런 걸까요? 하지만 물론, SVG는 매우, 매우 복잡하기 때문에 라이브러리를 고를 때에 신중함이 필요했습니다. 결국 일부 기능이 누락되어 있지만 빠르고 가벼운 resvg를 선택하게 되었습니다.

자체 컴포넌트 엔진

한편, 확장성 높은 오버레이를 만드는 것에 대해 고민이 있었습니다. 단순히 SVG에 템플릿 엔진을 쓴다던가 하는 선택지도 분명 있었겠지만, 그러면 재미가 없잖아요?

UI 마크업

저는 React/Flutter 등의 생태계에서 쓰는 선언적 UI를 바탕으로 생각해보기로 했습니다. 컴포넌트 트리를 만들 때 컴포넌트 자체에 넘기는 속성과 자식 노드를 받을 수 있는 마크업 언어... 아무리 생각해도 XML이 타겟 사용자들에게 친숙하고, 구현이 용이할 것 같았습니다. OGDL 같은 언어도 흥미로웠지만 너무 마이너해서 제외. B 모 씨께서 KDL도 추천해주셨지만 생태계가 아직 미숙해서 XML 결정을 지금도 유지하고 있습니다.

레이아웃 (2022년 1월 18일)

레이아웃 엔진은 한번쯤 개발해보면 재밌을 것 같았습니다만 이런 걸 자체 개발 하다간 결코 프로덕트를 출시할 수 없음을 알기에 절대 좌표 기준으로 레이아웃을 짜기로 결정했습니다.

후에 자식 컴포넌트의 너비 만큼 오른쪽으로, 혹은 높이 만큼 아래로 밀어주는 hbox, vbox까지만 만들었고, 거기에 margin과 overlap 컴포넌트를 활용해 좀 더 다양한 레이아웃을 만들기 편하게 했습니다.

텍스트 정렬은 어렵다

resvg는 dominant-baseline을 지원하지 않습니다. 필요했습니다. 없습니다. 그래서 어쩔 수 없이 polyfill(?)을 만들기로 했습니다. 렌더링을 두번 해서 baseline을 계산하는 것이죠. 그런데 이걸로도 완벽하게 정렬되지는 않아서 투명한 <rect>를 하나 그려넣었습니다. 지금은 렌더링을 두 번 하는 대신 폰트 상의 글리프 정보를 읽어서 정렬에 사용하고 있어 더 정확해졌습니다.

두번째 프로토타입

두번째 프로토타입은 코드와 강결합해서 그리던 것을 나름의 컴포넌트 엔진을 통해 그리게 한 것에 가치가 있습니다.

그리고, 파일로 분리 (2022년 1월 20일)

위 프로토타입을 구현하는 XML 컴포넌트 코드입니다. 현재는 구조가 개편되어 동작하지는 않겠지만 컴포넌트를 재컴파일 없이 수정할 수 있게 되어 가치가 있습니다.

네트워크

\Network Interface(*)\Bytes Sent/sec 카운터를 읽어서 보여줍니다. 이 때 이 값은 바이트 단위이므로 적절한 수로 나누어 보여줄 수 있게끔 스크립트 했습니다.

그래프 (2022년 1월 26일)

그래프를 그리면 예쁩니다. 최근 n개의 샘플을 기록하고 SVG Path로 그립니다.

로깅 시작 (2022년 1월 27일)

로깅하는 자만이 에러를 쉽게 해결할 수 있습니다. Tracing이 핫하다는 소식을 들은 게 좀 된 거 같네요 식어서야 쓰게 되다니

폰트 가져오기 (2022년 1월 28일)

설치된 폰트만 쓸 수 있으면 갑자기 프로그램이 죽을 수 있으니까 웹하는 감각으로 폰트를 가져올 수 있게 했습니다.

고해상도 지원 (2022년 1월 30일 ~ 2월 7일)

DPI 갱신을 인식해서 DPI Aware해지기 위해 노력했습니다. 제 환경에서는 제대로 되니까 만사 오케이입니다.

구조 개선 및 리디자인 (2022년 2월 2일)

변수 선언 이후 사용 방식으로 교체하고 새로운 디자인을 적용했습니다.

트레이 아이콘 추가 (2022년 2월 22일)

설정 창을 열거나 종료하기 위한 트레이 아이콘을 등록했습니다.

재구조화 (2022년 3월 25일 ~)

Crate 하나에 너무 많은 것들이 엮였으므로 새로 구조를 짜서 책임 경계를 더 분명히하려고 합니다.

profile
사람과 컴퓨터 사이를 이어주는 소프트웨어를 만듭니다

0개의 댓글