開発

English

UIngは、Crystalでネイティブアプリケーションを構築するための、小さく持続可能な基盤です。 変更を加えるときは、安定性、クロスプラットフォームの動作、既存のライフタイム規則を 維持してください。

APIレベル

レベル定義場所例用途
高レベルsrc/uing/*.crbutton.on_clicked { }オブジェクト指向のアプリケーションAPI
低レベルsrc/uing/lib_ui/lib_ui.crUIng::LibUI.new_buttonlibui-ngへの直接バインディング

高レベルAPIはWindow、Label、Buttonなどの基本コントロールに加え、Tableや Areaなどの高度なコントロールも提供します。通常のアプリケーションコードでは こちらを使います。UIng::LibUIは、基盤となるC APIへの直接アクセスと、高レベル ラッパーの実装に使用します。

低レベルバインディングとネイティブライブラリ

低レベルバインディングは、当初 crystal_libで生成していました。 生成後にもLibC::Intから高レベルのBoolへの変換など、多くの手動調整が必要だったため、 現在はAIの支援も利用しながら直接保守しています。

コンポーネントを追加するときは、既存コントロールのコールバックとライフタイムの パターンに従います。ネイティブのlibui-ngは kojix2/libui-ngのGitHub Actionsでビルドされ、 UIng固有の拡張はdevブランチで保守されます。Windowsではcomctl32.manifestにより Common Controls v6を選択し、OS標準コントロールに新しい視覚スタイルを適用します。

メモリ安全性

CrystalのGC付きランタイムとネイティブC APIを安全に接続するため、UIngは次の仕組みを 使用します。

  • コントロールレジストリがネイティブ側の破棄までラッパーを保持し、親への参照が ネイティブのコントロールツリーを反映します。
  • ネイティブコードから呼び出される可能性がある間、Box化したコールバックを保持します。
  • AreaとTableの拡張ハンドラ構造体は、ネイティブ互換の基本ハンドラと一緒に コールバックデータを格納します。静的なトランポリンがそのデータを復元してCrystalの クロージャを呼び出します。
  • コールバック中だけ借用されるラッパーは、コールバック終了時に無効化されます。

利用者向けの所有権と解放規則は ランタイムとライフタイムを参照してください。

低レベルコンテキストでのクロージャ

libui-ngの多くのコールバックはdataポインタを受け取るため、UIngはこれを使って Crystalのクロージャを保持・復元します。ネイティブ構造体へ直接格納される関数ポインタの 一部には、この引数がありません。その場合はハンドラ構造体へBox化したデータを追加し、 C互換のトランポリンから拡張構造体へキャストして利用します。TableとAreaがこの パターンを使用します。

生成AIの利用

GitHub Actions、複雑なサンプル、メモリ安全性のレビュー、パッチ適用版libui-ngの開発に 生成AIを利用しています。UIngは反復的な実装と、生成コードに対する人間の行単位レビュー から始まりました。現在の人間の作業は、全体設計、ネイティブGUIの目視確認、実際の利用を 通じた改善点の発見に重点を置いています。

コントリビューション

  • リポジトリをforkしてPull Requestを送ってください。
  • 再現手順、プラットフォーム、Crystalのバージョンを添えてバグを報告してください。
  • 表示動作を変更するときは、クロスプラットフォームのサンプルも追加・更新してください。
  • UIngに関する記事や利用報告も歓迎します。