2 điểm bởi GN⁺ 2024-04-02 | 1 bình luận | Chia sẻ qua WhatsApp
  • Libmui là thư viện UI tái tạo phần lớn API “Toolbox” của Macintosh Classic; không phải bản triển khai hoàn chỉnh nhưng cung cấp các tính năng cần cho trình giả lập MII Apple //e và các ứng dụng đơn giản
  • Ban đầu nó được tạo ra như thư viện UI cho MII, với mục tiêu là UI được bố trí thủ công thay vì phụ thuộc nặng hoặc các menu kiểu game “Arrow Keys + Return + Escape”
  • Cách render là vẽ vào bộ đệm ARGB rồi chép sang texture OpenGL hoặc X11/XCB shared pixmap, đồng thời theo dõi invalid region để chỉ vẽ lại những vùng cần thiết
  • API hoạt động theo kiểu bất đồng bộ và dựa trên callback, khác với Macintosh Toolbox gốc; khi thay đổi trạng thái thì UI sẽ tự vẽ lại khi cần, còn sự kiện được chuyển qua callback thay vì polling
  • Có các tính năng Window, Menu, Control, List, Alert, Standard File, nhưng không cung cấp zooming, resizing, Save dialog, dark mode, theme, Wayland, GTK/QT/SDL hay binding cho Rust/Go/Python

Libmui tạo ra gì

  • Libmui là một thư viện tái tạo khá nhiều của API “Toolbox” Macintosh Classic
  • Nó không phải một bản triển khai đầy đủ, nhưng bao gồm những phần cần thiết cho một vài ứng dụng đơn giản và trình giả lập MII Apple //e
  • Điểm khởi đầu là cần một thư viện UI cho MII, đồng thời muốn một UI không có quá nhiều phụ thuộc và không thiên về kiểu thao tác menu giống game
  • Tác giả từng thử Nuklear immediate mode UI trước, nhưng không thích giao diện của nó, thấy việc tùy biến bị hạn chế nhiều, và cho rằng engine layout đặt phần tử khác với vị trí mong muốn
  • Một phần bối cảnh nữa là trải nghiệm với immediate mode UI vốn nội bộ vẫn giữ trạng thái dựa trên hash, và va chạm hash có thể gây ra vấn đề debug thực tế
  • Mục tiêu là hướng tới UI được tinh chỉnh thủ công hơn là UI để engine layout tự quyết định

Mô hình render và vận hành

  • Libmui vẽ UI lên một “màn hình” là bộ đệm ARGB
    • Trong MII, bộ đệm này được overlay thành texture OpenGL
    • Demo playground trong thư mục example chép nó vào cửa sổ X11 bằng XCB shared pixmap, và vẫn hoạt động cả với remote X11
  • Giống các OS cũ, nó theo dõi invalid region để chỉ vẽ lại những phần cần thiết
    • Không phải vẽ lại toàn bộ mỗi lần nên overdraw rất thấp
    • Nếu cần vẽ lên framebuffer 16-bit chẳng hạn, thì phải chuyển đổi trực tiếp từ đầu ra ARGB
    • Vì chỉ cần chuyển đổi dirty region nên chi phí không quá lớn
  • Cũng có thể vector hóa quá trình render thành vertex buffer các kiểu, nhưng tác giả cho rằng cách hiện tại đã đủ nhanh và không cần quay lại kiểu hoạt động vẽ lại toàn bộ như immediate mode UI

Điểm khác với Macintosh Toolbox gốc

  • Về ngoại hình, nó bắt đầu từ MacOS 8/9 nhưng bỏ các thành phần grayscale; tác giả cho rằng dáng vẻ phẳng của System 7 già đi đẹp hơn nên chọn theo hướng đó
  • Popup menu gần với OS8 hơn, còn scrollbar lại gần GS/OS hơn
  • Khác biệt lớn trong API là hoạt động hoàn toàn bất đồng bộ
    • Không thể tùy ý vẽ vào window hay GrafPort bằng spinloop như bản gốc
    • Khi thay đổi trạng thái UI, giao diện sẽ tự vẽ lại khi cần
  • Xử lý sự kiện là dựa trên callback
    • Không polling để xem chuyện gì đã xảy ra trong UI
    • Khi có click vào menu item hoặc nhập phím tắt, action callback sẽ được gọi
  • Cấu trúc khái niệm cũng đơn giản hơn bản gốc
    • Mọi thứ đều là mui_window hoặc mui_control
    • windows, menubars, menus là mui_window
    • tiêu đề menu, menu item, mọi phần tử trong window và separator line là mui_control

Các manager và control được cung cấp

  • Window Manager

    • Hỗ trợ tạo cửa sổ và vẽ trong cửa sổ
    • Hỗ trợ tối đa 15 layer, clipping, BringToFront và kéo cửa sổ
    • Hệ tọa độ, tương tự bản gốc, được giới hạn ở 2 loại là screen coordinates và window content coordinates
    • Quản lý danh sách invalid rectangle để không phải vẽ lại toàn bộ cửa sổ mỗi lần
    • zooming và resizing hiện vẫn là TODO
    • Chủ ý không hỗ trợ transparent windows
      • Vì nó vẽ cửa sổ theo hướng từ trên xuống để tối ưu clipping
      • Nếu xử lý độ trong suốt thì phải vẽ từ dưới lên và sẽ phải vẽ lại nhiều nội dung hơn
      • Tuy vậy vẫn có thể alpha blend toàn bộ màn hình UI vào bất kỳ nơi nào mong muốn
  • Menu Manager

    • Hỗ trợ menubar, menus, checkmark, keyboard shortcut
    • Được làm để trông giống System 7/8 hoặc GS/OS
    • Có hierarchical menus nhưng chưa hoàn toàn giống bản gốc và cần cải thiện thêm
    • Việc hiển thị và cuộn các popup rất lớn vẫn là TODO
    • Hỗ trợ sticky menus đã làm được một nửa nhưng chưa đúng nên hiện bị tắt
  • Control Manager

    • Hỗ trợ buttons, checkboxes, radio buttons, vertical scrollbars, textbox có xuống dòng
    • Edit Field đang được làm, còn Slider thì chưa có
    • Bản prototype của text edit control ổn cho nhập một dòng, nhưng chưa phù hợp với hộp văn bản nhiều dòng
  • List Manager

    • Hiện tại gần như được hardcode cho mục đích hiển thị tên tệp
    • Xử lý arrow keys, page up/down và scroll wheel
    • Giống MacOS gốc, có thể tìm mục mong muốn bằng typeahead
    • Tính năng dùng font compression hoặc ellipsis abbreviation khi văn bản mục quá dài vẫn là TODO
  • Alerts và Standard File

    • Alert cung cấp hộp thoại Cancel + OK thông thường
    • Nhiều loại alert hơn vẫn là TODO
    • Standard File cung cấp hộp thoại Open file kiểu cổ điển
      • Đây là một trong những mục tiêu lớn ban đầu của thư viện
      • Save dialog vẫn là TODO
      • Có thêm popup hiển thị các thư mục dùng gần đây
      • Hỗ trợ arrow keys, page up/down và tìm tệp bằng typeahead
  • Resource Manager

    • Không có Resource Manager
    • Tác giả cho rằng cần một công cụ kiểu ResEdit nên phần này nằm ngoài phạm vi hiện tại
    • Có ý tưởng dùng định dạng MessagePack cho resource, nhưng để lại cho công việc sau

Phụ thuộc và build

  • Phụ thuộc bên ngoài duy nhất là libpixman
    • libpixman là thư viện xử lý pixel, đồng thời cung cấp tính năng region hữu ích cho clipping
    • Nó không tốt bằng region của QuickDraw, nhưng được xem là đủ dùng
  • Cũng có các thành phần đi kèm trong mã nguồn
    • libcg: trình render antialiased nhỏ tương tự cairo, chỉ gồm 2 file
    • stb_truetype.h: dùng để nạp font TrueType
    • stb_ttc.h: phần mở rộng của stb_truetype.h để xây dựng font/glyph dictionary, hash table, font texture...
    • Mã 2D geometry đã hơn 25 năm tuổi và cũng có trong libc3
  • Việc build dùng Makefile đơn giản, chỉ cần chạy make ở thư mục gốc
  • Để build tests, demos, samples thì cần xcb, xcb-shm, xcb-randr, xkbcommon-x11
  • Nếu dùng Nvidia binary driver, để mui_shell hoạt động cần thêm Option "AllowSHMPixmaps" "1" vào phần Device của /etc/X11/xorg.conf

Cách dùng và quy trình phát triển

  • Điểm bắt đầu được khuyến nghị là thử sửa mui_shell.cmui_widgets_demo.c
  • ui_mui_shell nạp mui_widgets_demo.so dưới dạng plugin và tự động nạp lại khi phát hiện thay đổi
  • Khi sửa mui_widgets_demo.c, nó sẽ chạy lại sau khi reload nên có thể tạo dialog mới rất nhanh
  • Chạy make watch trong thư mục libmui sẽ tự động build lại thư viện và mui_shell khi có thay đổi
  • Kết hợp với auto save của editor thì có thể tạo quy trình vừa sửa vừa build/chạy liên tục

Những gì chủ ý không cung cấp

  • Không có dark mode
  • Không có hỗ trợ theme
  • Không có transparent windows và cube effect
  • sticky menus hiện không được bật
  • Không dùng cmake, meson, ninja, autotools
  • Không có binding cho các ngôn ngữ như Rust, Go, Python
  • Không dùng các framework như GTK, QT
  • Không dùng SDL
  • Không hỗ trợ Wayland

1 bình luận

 
GN⁺ 2024-04-02
Các ý kiến trên Hacker News
  • Liên quan đến việc này, có một phông TrueType thuộc phạm vi công cộng mô phỏng khá tốt phông hệ thống Chicago gốc: https://fontlibrary.org/en/font/chicagoflf

    • Tôi từng cân nhắc dùng Chicago làm phông mặc định, nhưng nó mang hình ảnh quá cố định
      Charcoal, được dùng từ System 8.x trở đi, ít được biết đến hơn nhiều, và cá nhân tôi thấy đó là một cải tiến khá lớn
      Dù vậy, thực ra việc đổi thư viện sang Chicago khá dễ. Ngoài bản mô phỏng đã nhắc đến, phiên bản TTF “plain” của Chicago gốc cũng đang lưu truyền đâu đó
    • Liên quan đến chuyện có một bản mô phỏng tuyệt vời của “phông hệ thống Chicago gốc”, cũng có thể lấy TrueType Chicago thật do Bigelow & Holmes thiết kế thông qua bản tải xuống System 7.6.1
      Sau đó chỉ cần dùng công cụ dòng lệnh FontForge để chuyển TTF sang 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 hiện đại cũng đi kèm một phông tiếng Thái tên là Silom, trong đó dùng Chicago cho các glyph Latin
  • Thật sự rất tuyệt. Michel làm nó cho trình giả lập Apple II của anh ấy, còn tôi thì đang dùng nó như một trò đùa nho nhỏ để thay thế frontend của trình giả lập Archimedes
    Vẫn còn ở giai đoạn đầu, nhưng nếu tôi có thể hiểu được API thì chắc hẳn đó là một API ổn :)

    • Ngay cả việc dùng nó cho trình giả lập Apple II cũng có cảm giác hơi như đùa. Vì người dùng Apple II thời đó muốn Apple tiếp tục duy trì dòng Apple II, nhưng khi Apple tập trung vào Mac và về cơ bản bị xem là đã bỏ rơi Apple II, họ không ưa Mac
      Dù vậy, tôi vẫn có cảm tình với giao diện Mac cổ điển
  • Tôi thích rasterizer đồ họa 2D theo kiểu hai header mà dự án này dùng: https://github.com/xboot/libcg
    Việc có thể tạo ra phần mềm mạnh mẽ chỉ với số phụ thuộc tối thiểu như vậy luôn khiến tôi ngạc nhiên
    Liệu việc tạo một thư viện UI gọn gàng, mạnh mẽ có thể thay thế Electron có khó đến thế không?

    • Không. Nhưng nếu vậy thì biết dùng bộ nhớ và hiệu năng dư thừa vào đâu?
  • Ấn tượng thật. Giấy phép MIT và viết bằng C! Nếu thêm một shim cho API AppKit thì có khi còn có thể cạnh tranh với GNUstep

    • Hoặc chỉ cần khoác theme GNUstep lên là được. Nó hỗ trợ các theme kiểu này
  • Trông đẹp đấy. Ước gì tôi có thể đổi toàn bộ UI macOS của mình thành như vậy

    • Bật chế độ tương phản cao trong cài đặt trợ năng là sẽ gần giống như thế
  • Dự án hay. Tôi từng rất thích UI Mac cổ điển ngày xưa
    Các ví dụ trông đều tuyệt, và nhìn code demo widget thì có vẻ cũng dễ dùng

  • Thật sự rất tuyệt. Tôi tò mò không biết sẽ tốn bao nhiêu công sức để đọc các tệp tài nguyên (.rsrc) trong resource fork rồi dựng UI từ đó
    Nếu làm được thì có thể dùng ResEdit :-)