2P by GN⁺ | ★ favorite | 댓글 1개
  • Libmui는 Macintosh Classic “Toolbox” API의 상당 부분을 복제한 UI 라이브러리로, 완전 구현은 아니지만 MII Apple //e emulator와 간단한 애플리케이션에 필요한 기능을 제공함
  • MII용 UI 라이브러리로 시작했으며, 의존성이 많거나 “Arrow Keys + Return + Escape”식 게임형 메뉴가 아닌 수작업으로 배치한 UI를 목표로 함
  • 렌더링은 ARGB 버퍼에 그린 뒤 OpenGL 텍스처나 X11/XCB shared pixmap으로 복사하는 방식이며, invalid region을 추적해 필요한 영역만 다시 그림
  • API는 원래 Macintosh Toolbox와 달리 비동기·콜백 기반으로 동작하며, 상태를 바꾸면 UI가 필요할 때 다시 그리고 이벤트는 폴링 대신 콜백으로 전달됨
  • Window, Menu, Control, List, Alert, Standard File 기능을 갖췄지만 zooming, resizing, Save dialog, dark mode, theme, Wayland, GTK/QT/SDL, Rust/Go/Python 바인딩은 제공하지 않음

Libmui가 만드는 것

  • Libmui는 Macintosh Classic “Toolbox” API를 많이 복제한 라이브러리임
  • 완전한 구현은 아니지만 몇 가지 간단한 애플리케이션과 MII Apple //e emulator에 필요한 부분을 포함함
  • MII용 UI 라이브러리가 필요했고, 의존성이 많지 않으면서 게임식 메뉴 조작에 치우치지 않은 UI를 원한 것이 출발점임
  • Nuklear immediate mode UI를 먼저 써봤지만, 외형이 마음에 들지 않고 커스텀 작업에 제한이 크며 레이아웃 엔진이 원하는 위치와 다르게 배치한다고 판단함
  • immediate mode UI가 내부적으로 해시 기반 상태를 유지하며, 해시 충돌이 실제 디버깅 문제를 만들 수 있다는 경험도 배경이 됨
  • 목표는 레이아웃 엔진이 알아서 정하는 UI보다 직접 다듬은 UI에 가까움

렌더링과 동작 모델

  • Libmui는 ARGB 버퍼로 된 “screen”에 UI를 그림
    • MII에서는 이 버퍼를 OpenGL 텍스처로 오버레이함
    • example 폴더의 playground 데모는 X11 창에 XCB shared pixmap으로 복사하며, remote X11에서도 동작함
  • 오래된 OS처럼 invalid region을 추적해 필요한 부분만 다시 그림
    • 전체를 매번 다시 그리지 않아 overdraw가 매우 적음
    • 16비트 framebuffer 등에 그리려면 ARGB 출력에서 직접 변환해야 함
    • dirty region만 변환하면 되므로 부담이 크지 않음
  • 렌더링을 vertex buffer 등으로 벡터화할 수도 있지만, 현재 방식이 충분히 빠르고 immediate mode UI처럼 전체를 다시 그리는 동작으로 돌아갈 필요가 없다고 봄

원래 Macintosh Toolbox와 다른 점

  • 외형은 MacOS 8/9에서 시작했지만 grayscale 요소를 제거한 느낌이며, System 7의 flat한 모습이 더 잘 늙었다고 판단해 그쪽을 선택함
  • popup menu는 OS8에 더 가깝고, scrollbar는 GS/OS 쪽에 더 가까움
  • API의 큰 차이는 완전 비동기 동작임
    • 원래처럼 아무 때나 window나 GrafPort에 spinloop로 그릴 수 없음
    • UI 상태를 바꾸면 필요할 때 UI가 스스로 다시 그림
  • 이벤트 처리는 콜백 기반
    • UI에 무슨 일이 있었는지 폴링하지 않음
    • 메뉴 아이템 클릭이나 키보드 단축키 입력이 발생하면 action 콜백이 호출됨
  • 개념 구조는 원본보다 단순함
    • 모든 것은 mui_window 또는 mui_control
    • windows, menubars, menus는 mui_window
    • menu titles, menu items, window 안의 모든 요소, separator lines는 mui_control

제공하는 매니저와 컨트롤

  • Window Manager

    • 창 생성과 창 안 그리기를 지원함
    • 최대 15개 layer, clipping, BringToFront 동작, 창 드래그를 지원함
    • 좌표계는 원래와 비슷하게 screen coordinates와 window content coordinates 2개로 제한함
    • invalid rectangle 목록을 관리해 전체 창을 매번 다시 그리지 않음
    • zooming과 resizing은 TODO임
    • transparent windows는 의도적으로 지원하지 않음
      • top-down 방식으로 창을 그려 clipping을 최적화하기 때문임
      • 투명도를 처리하려면 bottom-up으로 그려야 하고, 더 많은 내용을 다시 그리게 됨
      • 전체 UI screen을 원하는 곳에 alpha blend하는 것은 가능함
  • Menu Manager

    • menubar, menus, checkmarks, keyboard shortcuts를 지원함
    • System 7/8 또는 GS/OS처럼 보이도록 만들어짐
    • hierarchical menus가 있지만 원본과 완전히 같지는 않으며 개선이 필요함
    • 아주 큰 popup의 표시와 스크롤은 TODO임
    • sticky menus 지원은 반쯤 구현됐지만 아직 맞지 않아 비활성화됨
  • Control Manager

    • buttons, checkboxes, radio buttons, vertical scrollbars, wrapping textboxes 등을 지원함
    • Edit Field는 작업 중이며 Slider는 빠져 있음
    • text edit control 프로토타입은 한 줄 입력에는 괜찮지만 여러 줄 텍스트 박스에는 아직 맞지 않음
  • List Manager

    • 현재는 파일명을 표시하는 용도에 가깝게 하드코딩돼 있음
    • arrow keys, page up/down, scroll wheel을 처리함
    • 원래 MacOS처럼 typeahead로 원하는 항목을 찾을 수 있음
    • 항목 텍스트가 너무 길 때 font compression이나 ellipsis abbreviation을 쓰는 기능은 TODO임
  • Alerts와 Standard File

    • Alert는 일반적인 Cancel + OK 대화상자를 제공함
    • 더 많은 alert 종류는 TODO임
    • Standard File은 클래식한 Open file dialog를 제공함
      • 이 기능은 라이브러리의 초기 주요 목표 중 하나였음
      • Save dialog는 TODO임
      • 최근 사용한 디렉터리를 보여주는 추가 popup이 있음
      • arrow keys, page up/down, typeahead 파일 검색을 지원함
  • Resource Manager

    • Resource Manager는 없음
    • ResEdit 같은 도구가 필요하다고 보고, 현재 범위에서는 제외함
    • 리소스용 MessagePack 형식 아이디어는 있지만 이후 작업으로 남아 있음

의존성과 빌드

  • 외부 의존성은 libpixman뿐임
    • libpixman은 픽셀 처리용 라이브러리이며 clipping에 유용한 region 기능을 제공함
    • QuickDraw의 region만큼 좋지는 않지만 충분하다고 봄
  • 소스에 포함된 구성 요소도 있음
    • libcg: cairo와 비슷한 작은 antialiased renderer이며 2개 파일로 구성됨
    • stb_truetype.h: TrueType font 로딩에 사용됨
    • stb_ttc.h: stb_truetype.h 확장으로 font/glyph dictionary, hash table, font texture 등을 구성함
    • 2D geometry 코드는 25년 넘게 된 코드이며 libc3에도 포함됐음
  • 빌드는 루트 디렉터리에서 make를 실행하는 단순한 Makefile 방식임
  • tests, demos, samples 빌드에는 xcb, xcb-shm, xcb-randr, xkbcommon-x11이 필요함
  • Nvidia binary driver를 쓰는 경우 mui_shell이 동작하려면 /etc/X11/xorg.confDeviceOption "AllowSHMPixmaps" "1"을 추가해야 함

사용 방식과 개발 워크플로

  • 시작점으로는 mui_shell.cmui_widgets_demo.c를 수정해보는 방식이 권장됨
  • ui_mui_shellmui_widgets_demo.soplugin으로 로드하고, 변경을 감지하면 자동으로 다시 로드함
  • mui_widgets_demo.c를 수정하면 재로드 후 다시 실행되므로 새 dialog를 빠르게 만들 수 있음
  • make watchlibmui 디렉터리에서 실행하면 변경 시 라이브러리와 mui_shell을 자동으로 다시 빌드함
  • 에디터의 auto save와 함께 쓰면 수정하면서 계속 빌드·실행되는 워크플로를 만들 수 있음

명시적으로 제공하지 않는 것

  • dark mode 없음
  • theme 지원 없음
  • transparent windows와 cube effect 없음
  • sticky menus는 현재 활성화되지 않음
  • cmake, meson, ninja, autotools를 쓰지 않음
  • Rust, Go, Python 같은 언어 바인딩 없음
  • GTK, QT 같은 프레임워크를 쓰지 않음
  • SDL을 쓰지 않음
  • Wayland 지원 없음

댓글과 토론

Hacker News 의견들
  • 관련해서, 원래 Chicago 시스템 글꼴을 꽤 잘 복제한 퍼블릭 도메인 TrueType 글꼴이 있음: https://fontlibrary.org/en/font/chicagoflf

    • 기본 글꼴로 Chicago를 쓸까 고민했지만, 너무 고정된 이미지가 강함
      System 8.x 이후 쓰인 Charcoal은 훨씬 덜 알려져 있고, 개인적으로는 꽤 큰 개선이라고 봄
      그래도 라이브러리에서 Chicago로 바꾸는 건 실제로 꽤 쉬움. 언급한 복제본 말고도 원래 Chicago의 “plain” TTF 버전이 어딘가 돌아다님
    • “원래 Chicago 시스템 글꼴”의 훌륭한 복제본이 있다는 얘기와 관련해, System 7.6.1 다운로드를 통해 Bigelow & Holmes가 설계한 진짜 TrueType Chicago도 얻을 수 있음
      이후 FontForge 명령줄 도구로 TTF를 OTF로 변환하면 됨: https://www.macintoshrepository.org/1682-mac-os-7-6-x
      fontforge -script -c 'Open($1); Generate($2);' input_font.ttf output_font.otf
    • 최신 macOS에도 Silom이라는 태국어 글꼴이 포함돼 있는데, 라틴 글리프에는 Chicago를 사용함
  • 정말 멋짐. Michel이 자기 Apple II 에뮬레이터용으로 만든 건데, 나는 약간 장난처럼 Archimedes 에뮬레이터의 프런트엔드를 대체하는 데 쓰고 있음
    아직 초기 단계지만, 내가 API를 이해할 수 있다면 괜찮은 API임이 틀림없음 :)

    • Apple II 에뮬레이터에 쓰는 것조차 약간 장난처럼 느껴짐. 당시 Apple II 사용자들은 Apple이 Apple II 라인을 계속 이어가길 원했는데, Apple이 Mac에 집중하면서 사실상 버렸다고 여겨 Mac을 못마땅해했기 때문임
      그래도 클래식 Mac 인터페이스에는 애정이 있음
  • 이 프로젝트가 쓰는 이중 헤더 방식의 2D 그래픽 래스터라이저가 마음에 들었음: https://github.com/xboot/libcg
    이렇게 최소 의존성만으로도 강력한 소프트웨어를 만들 수 있다는 점은 늘 놀라움
    Electron의 대안이 될 만한 깔끔하고 강력한 UI 라이브러리를 만드는 게 그렇게 어려운 일일까?

    • 아님. 하지만 그러면 남아도는 메모리와 성능은 어디에 쓰겠음?
  • 대단함. MIT 라이선스에 C로 작성됐다니! AppKit API용 shim을 추가하면 GNUstep과도 겨뤄볼 만할지도 모름

    • 아니면 그냥 GNUstep 테마를 입히면 됨. 이런 테마를 지원함
  • 보기 좋음. 내 macOS UI 전체를 저렇게 바꿀 수 있으면 좋겠음

    • 접근성 설정에서 고대비 모드를 켜면 거의 비슷해짐
  • 좋은 프로젝트임. 예전 클래식 Mac UI를 정말 좋아했음
    예제들이 전부 훌륭해 보이고, 위젯 데모 코드를 보면 쓰기도 쉬워 보임

  • 정말 멋짐. resource fork의 리소스 파일(.rsrc)을 읽어서 UI를 만드는 데 얼마나 노력이 들지 궁금함
    가능하다면 ResEdit를 쓸 수 있을 텐데 :-)