Rust와 Slint로 Kindle Paperwhite에서 GUI 개발 성공!
Kindle Paperwhite를 탈옥(Jailbreak)하여 Rust 개발 환경을 구축하고, Slint GUI 라이브러리를 활용하여 GUI 애플리케이션을 개발함
ARMv7 아키텍처를 타겟으로 cargo-zigbuild를 사용하여 크로스 컴파일 환경을 구성하고, SSH를 통해 셸(Shell) 접근 권한을 확보함
e-ink 화면 출력을 위해 LineBufferProvider를 구현하고, /dev/fb0 파일에 래스터화된 이미지를 출력하는 방식을 사용함
터치 입력 처리를 위해 /dev/input/event1에서 이벤트를 읽어 Slint에 전달하는 방식을 구현하여, Kindle의 터치 인터랙션(Touch Interaction)을 가능하게 함
크로스 컴파일 환경 구축
저자는 Kindle Paperwhite에서 Rust 코드를 실행하기 위해 ARMv7 아키텍처(Architecture)를 타겟으로 하는 크로스 컴파일 환경을 구축했다. cargo-zigbuild를 사용하여 Zig 컴파일러를 통해 musl libc를 포함한 완전한 크로스 컴파일 툴체인을 구성했다. 특히, Zig는 musl libc 소스 및 헤더를 내장하고 있어, 별도의 설정 없이 간편하게 크로스 컴파일을 수행할 수 있다는 점이 강조된다. 이는 저전력 환경에서 Rust 개발의 어려움을 해결하는 핵심 전략으로 작용한다.
e-ink 화면 출력 구현
Kindle의 e-ink 화면에 GUI를 출력하기 위해, 저자는 Slint의 LineBufferProvider를 구현하여 래스터화된 이미지를 획득했다. 획득한 이미지를 흑백으로 변환하여 /dev/fb0 파일에 기록하는 방식으로 화면 출력을 구현했다. 이는 리눅스 철학인 '모든 것이 파일이다(Everything is a file)'를 활용한 접근 방식이다. 또한, ioctl() 함수를 사용하여 화면을 갱신하는 방식을 통해 e-ink 디스플레이의 특성을 고려한 구현을 보여준다.
터치 입력 처리
Kindle의 터치 입력을 처리하기 위해, 저자는 /dev/input/event1 파일을 통해 터치 이벤트를 읽어 Slint에 전달하는 방식을 사용했다. Kindle은 리눅스 커널의 멀티 터치 프로토콜 타입 B를 사용하며, 저자는 이벤트를 분석하여 X, Y 좌표 및 트래킹 ID를 추출했다. 특히, 트래킹 ID가 -1인 경우 포인터 릴리즈(PointerReleased)로, 그 외에는 포인터 프레스(PointerPressed) 또는 포인터 무브(PointerMoved) 이벤트로 변환하여 Slint에 전달했다. 이 과정을 통해 Kindle의 터치 인터랙션을 구현했다.
Slint 라이브러리 활용
저자는 Rust 기반의 GUI 라이브러리인 Slint를 사용하여 Kindle Paperwhite용 GUI 애플리케이션을 개발했다. Slint는 다양한 렌더러와 백엔드를 지원하며, 특히 저전력 환경에 적합한 소프트웨어 렌더러를 제공한다. 저자는 Slint의 Kindle-backend를 개발하여 e-ink 화면 출력 및 터치 입력 처리를 구현했다. 이 과정에서 발생한 다양한 버그를 해결하고, Kindle-backend를 crates.io에 공개하여 다른 개발자들도 활용할 수 있도록 했다.