- Libmuiは、Macintosh Classicの「Toolbox」APIのかなりの部分を再現したUIライブラリで、完全実装ではないものの、MII Apple //e emulatorとシンプルなアプリケーションに必要な機能を提供する
- MII向けUIライブラリとして始まり、依存関係が多かったり「矢印キー + 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のプロトタイプは1行入力には問題ないが、複数行テキストボックスにはまだ適していない
-
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.confのDeviceにOption "AllowSHMPixmaps" "1"を追加する必要がある
使い方と開発ワークフロー
- 出発点としては、
mui_shell.cとmui_widgets_demo.cを修正してみる方法が推奨される
ui_mui_shellはmui_widgets_demo.soをpluginとしてロードし、変更を検知すると自動で再ロードする
mui_widgets_demo.cを修正すると、再ロード後に再実行されるため、新しいdialogを素早く作れる
libmuiディレクトリでmake watchを実行すると、変更時にライブラリとmui_shellを自動的に再ビルドする
- エディタのauto saveと併用すると、修正しながら継続的にビルド・実行されるワークフローを作れる
明示的に提供しないもの
- dark modeなし
- themeサポートなし
- transparent windowsとcube effectなし
- sticky menusは現在有効化されていない
cmake、meson、ninja、autotoolsは使わない
- Rust、Go、Pythonのような言語バインディングなし
- GTK、QTのようなフレームワークは使わない
- SDLは使わない
- Waylandサポートなし
1件のコメント
Hacker Newsのコメント
関連して、元のChicagoシステムフォントをかなりよく再現したパブリックドメインのTrueTypeフォントがある: https://fontlibrary.org/en/font/chicagoflf
System 8.x以降で使われたCharcoalのほうがずっと知られておらず、個人的にはかなり大きな改善だと思う。
それでもライブラリでChicagoに切り替えるのは実際かなり簡単。言及した複製版以外にも、元のChicagoの“plain” TTF版がどこかに出回っている
その後、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本当にすばらしい。Michelが自分のApple IIエミュレータ用に作ったものだが、私は半分おふざけのような感じでArchimedesエミュレータのフロントエンドを置き換えるのに使っている。
まだ初期段階だが、私にAPIが理解できるなら、きっと良いAPIなのだろう :)
それでもクラシックMacインターフェースには愛着がある
このプロジェクトが使っている二重ヘッダー方式の2Dグラフィックラスタライザが気に入った: https://github.com/xboot/libcg
これほど最小限の依存関係だけで強力なソフトウェアを作れるという点にはいつも驚かされる。
Electronの代替になりうる、クリーンで強力なUIライブラリを作るのはそんなに難しいことだろうか?
すごい。MITライセンスでCで書かれているなんて! AppKit API向けのshimを追加すればGNUstepとも張り合えるかもしれない
見た目がいい。自分のmacOS UI全体をああいうふうに変えられたらいいのに
良いプロジェクトだ。昔のクラシックMac UIが本当に好きだった。
サンプルはどれもすばらしく見えるし、ウィジェットのデモコードを見ると使いやすそうでもある
本当にすばらしい。resource forkのリソースファイル(.rsrc)を読んでUIを作るのにどれくらい手間がかかるのか気になる。
もし可能ならResEditが使えるだろうし :-)