.NET C# で Ubuntu で GTK で GNOME ウインドウで Hello World する

# .NET C# で Ubuntu で GTK で GNOME ウインドウで Hello World する

## 目的

Windows 11 の WSL Ubuntu 22.04 で .NET 6.0 を用いて Linux の GNOME アプリを開発して理解を深めます。  

## 実現すること

Windows 11 のデスクトップに WSL Ubuntu 22.04 の GNOME GUI カスタムアプリのウインドウを立ち上げます。  

こちらに Python で実装した姉妹記事がございます。

https://qiita.com/hiroxpepe/items/d65fb9fc7987e742723e

## 技術背景

### .NET とは？  

<details>
<summary>こちらを展開してご覧いただけます。</summary>

### [Microsoft .NET](https://dotnet.microsoft.com/ja-jp/learn)

.NET は、マイクロソフトによって開発されたオープンソースのクロスプラットフォーム開発フレームワークです。  

以下のような特徴とメリットがあります。  

#### クロスプラットフォーム対応

.NET は、Windows、macOS、Linux、Android、iOS など、複数のプラットフォームで実行されるように設計されています。これにより、同じコードを複数のプラットフォームで共有できます。  

#### 豊富なライブラリ

.NET には、豊富なライブラリが含まれています。これにより、開発者は、簡単にデータベースやネットワーク、GUIなどの機能を組み込むことができます。  

#### マルチ言語サポート

.NET は、複数のプログラミング言語 (C#、F#、Visual Basic など) をサポートしています。開発者は、自分の好きな言語でアプリケーションを開発できます。

#### 高速性

.NET は、JIT コンパイラによって実行されるため、高速に動作します。また、メモリ管理が自動的に行われるため、開発者はメモリ管理に関する問題を心配する必要がありません。  

#### セキュリティ

.NET には、セキュリティに関する多数の機能が含まれています。たとえば、コードアクセスセキュリティ (CAS) があり、アプリケーションに対する不正なアクセスを防止することができます。  

#### まとめ

これらの特徴とメリットにより、.NET は、クロスプラットフォーム開発において人気のあるフレームワークの一つとなっています。  

</details>

### GNOME とは？  

<details>
<summary>こちらを展開してご覧いただけます。</summary>

### [GNOME](https://developer.gnome.org/)

GNOME は、Linux や Unix 系オペレーティングシステム上で動作する、オープンソースのデスクトップ環境です。  

以下のような特徴とメリットがあります。  

#### クロスプラットフォーム対応

GNOME は、Linux や Unix 系オペレーティングシステム上で動作するため、多数のプラットフォームに対応しています。また、Windows や macOS 上でも動作する GNOME のフォークである Cygwin/X や XQuartz があります。  

#### カスタマイズ性

GNOME は、高度なカスタマイズが可能です。ユーザーは、アプリケーションのレイアウトやテーマ、アイコン、フォントなどを簡単に変更できます。  

#### ユーザーフレンドリー

GNOME は、シンプルで使いやすいユーザーインターフェースを提供しています。初心者でも簡単に操作できるように設計されており、視覚的にも美しいデザインが特徴です。  

#### 高い拡張性

GNOME は、多数のアプリケーションやツールを提供しており、これらを拡張することができます。また、GNOMEシェル拡張を使用することで、ユーザーは独自の機能を追加することもできます。  

#### オープンソース

GNOME は、オープンソースであり、自由に改変・配布ができるため、開発者は自分の好きなようにカスタマイズすることができます。  

#### まとめ

これらの特徴とメリットにより、GNOME は、Linux や Unix 系オペレーティングシステム上で広く使用されているデスクトップ環境の一つとなっています。また、クロスプラットフォーム対応やカスタマイズ性の高さから、Windows や macOS 上でも利用されることがあります。

</details>

### GTK とは？  

<details>
<summary>こちらを展開してご覧いただけます。</summary>

### [GTK](https://www.gtk.org/)

GTK は、GNOME デスクトップ環境で使用されるウィジェット・ツールキットです。  

以下のような特徴とメリットがあります。  

#### クロスプラットフォーム対応

GTK は、クロスプラットフォーム対応しています。Linux や Unix 系オペレーティングシステムはもちろん、Windows や macOS、さらには Android や iOS などでも利用できます。  

#### フリー・オープンソース

GTK は、フリーかつオープンソースであるため、誰でも自由に利用・改変・再配布することができます。  

#### 多言語対応

GTK は、多数のプログラミング言語で利用できます。C、C++、Python、Java などの言語をサポートしています。  

#### ウィジェットの豊富さ

GTK は、多数のウィジェットを提供しています。ボタン、テキストボックス、ラベル、プログレスバー、スピンボタンなど、様々な種類のウィジェットを利用することができます。  

#### GNOMEとの関連

GTK は、GNOME デスクトップ環境で利用されており、GNOME アプリケーションの開発に必要不可欠なツールキットとなっています。  

#### まとめ

これらの特徴とメリットにより、GTK は、クロスプラットフォームで利用できるツールキットとして、多数のアプリケーション開発者に利用されています。また、GNOME デスクトップ環境の開発にも欠かせない存在となっています。

</details>

## 開発環境

+ Windows 11 Home 22H2 を使用しています。  
+ [WSL](https://learn.microsoft.com/ja-jp/windows/wsl/about) の Ubuntu を操作していきますので macOS の方も参考にして頂けます。  

<details>

WSL (Microsoft Store アプリ版)

```sh
> wsl --version
WSL バージョン: 1.0.3.0
カーネル バージョン: 5.15.79.1
WSLg バージョン: 1.0.47
```

Ubuntu

```sh
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.1 LTS
Release:        22.04
```

</details>

※ この記事では基本的に Ubuntu のターミナルで操作を行います。

## .NET で "Hello World" を表示する

### .NET SDK をインストール

:::note alert
Ubuntu 22.04 に .NET をインストールする場合、パッケージリポジトリの追加は必要ありません。ご注意ください！
:::

インストール

```sh
$ sudo apt update
$ sudo apt install dotnet-sdk-6.0
```

バージョン確認

```sh
$ dotnet --list-sdks
6.0.113 [/usr/lib/dotnet/sdk]
$ dotnet --version
6.0.113
```

### .NET のコンソールアプリを作成、実行してみる

コンソールアプリの作成  
※ MyApp がアプリ名です。  

```sh
$ cd ~/tmp
$ dotnet new console -o MyApp -f net6.0
```

コンソールアプリをビルド・実行する

```sh
$ cd ~/tmp/MyApp
$ dotnet run
Hello World!
```

ターミナルに "Hello, World!" が表示されました。

### .NET のコンソールアプリの内容を確認

構成要素の確認

```sh
$ cd ~/tmp/MyApp
$ tree -I obj -I bin
.
├── MyApp.csproj
└── Program.cs
```

プロジェクトファイルの確認

```sh
$ cat MyApp.csproj
```

```xml:MyApp.csproj
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>
```

プログラムの確認

```sh
$ cat Program.cs
```

```csharp:Program.cs
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
```

※ 参考: .NET 5.0 まではこうでした。

```csharp:Program.cs ※ .NET 5.0
using System;
namespace MyApp {
    class Program {
        static void Main(string[] args) {
            Console.WriteLine("Hello World!");
        }
    }
}
```

### ここまでのまとめ

+ Ubuntu に dotnet SDK をインストールして .NET の開発環境を構築しました。
+ dotnet コマンドによりコンソールアプリを新規作成、ビルド、実行することが出来ました。

## .NET で GTK を使った GNOME ウインドウで "Hello World" を表示する

※ この記事では、GTK を使用して GUI アプリケーションを開発します。  
※ GTK のバージョンは3系を使用します。  

### 開発環境の構築

GTK インストール

```sh
$ sudo apt install libgtk-3-dev
```

GtkSharp インストール

※ [GtkSharp](https://github.com/GtkSharp/GtkSharp) は、GTK GUI ツールキットおよび GNOME ライブラリの .NET バインディングセットです。  

```sh
$ dotnet new --install GtkSharp.Template.CSharp
```

Glade インストール

※ [Glade](https://glade.gnome.org/) は、GTK 用 GUI ビルダです。  

```sh
$ sudo apt install glade
```

### GTK GUI アプリを作成、実行してみる

新規 GTK GUIプロジェクト作成  
※ MyGtkApp がアプリ名です。  

```sh
$ cd ~/tmp
$ dotnet new gtkapp -t net6.0 -n MyGtkApp
```

GUI アプリをビルド、実行する

```sh
$ cd ~/tmp/MyGtkApp
$ dotnet run
```

![Hello_World.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177199/e22d5aec-4470-9c7f-7dfc-b8eba1b664bf.png)
Windows 11 のデスクトップに WSL の Ubuntu 22.04 の GNOME GUI ウインドウが立ち上がります！  
※ 魔法のような話ですが本当です。 Microsoft さんありがとうございます😭  

### GTK GUIアプリの内容を確認

プロジェクトのディレクトリ、ファイル構成

```sh
$ cd ~/tmp/MyGtkApp
$ tree -I obj -I bin
.
├── MainWindow.cs
├── MainWindow.glade
├── MyGtkApp.csproj
└── Program.cs
```

プロジェクトファイルの確認

```sh
$ cat MyGtkApp.csproj
```

```xml:MyGtkApp.csproj
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <None Remove="**\*.glade" />
    <EmbeddedResource Include="**\*.glade">
      <LogicalName>%(Filename)%(Extension)</LogicalName>
    </EmbeddedResource>
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="GtkSharp" Version="3.24.24.*" />
  </ItemGroup>

</Project>
```

メインプログラムの確認
  
```sh
$ cat Program.cs
```

```csharp:Program.cs
using System;
using Gtk;

namespace MyGtkApp
{
    class Program
    {
        [STAThread]
        public static void Main(string[] args)
        {
            Application.Init();

            var app = new Application("org.MyGtkApp.MyGtkApp", GLib.ApplicationFlags.None);
            app.Register(GLib.Cancellable.Current);

            var win = new MainWindow();
            app.AddWindow(win);

            win.Show();
            Application.Run();
        }
    }
}
```

ウインドウプログラムの確認

```sh
$ cat MainWindow.cs
```

```csharp:MainWindow.cs
using System;
using Gtk;
using UI = Gtk.Builder.ObjectAttribute;

namespace MyGtkApp
{
    class MainWindow : Window
    {
        [UI] private Label _label1 = null;
        [UI] private Button _button1 = null;

        private int _counter;

        public MainWindow() : this(new Builder("MainWindow.glade")) { }

        private MainWindow(Builder builder) : base(builder.GetRawOwnedObject("MainWindow"))
        {
            builder.Autoconnect(this);

            DeleteEvent += Window_DeleteEvent;
            _button1.Clicked += Button1_Clicked;
        }

        private void Window_DeleteEvent(object sender, DeleteEventArgs a)
        {
            Application.Quit();
        }

        private void Button1_Clicked(object sender, EventArgs a)
        {
            _counter++;
            _label1.Text = "Hello World! This button has been clicked " + _counter + " time(s).";
        }
    }
}
```

UI ファイルの確認

```sh
$ cat MainWindow.glade
```

```xml:MainWindow.glade
<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <requires lib="gtk+" version="3.18"/>
  <object class="GtkWindow" id="MainWindow">
    <property name="can_focus">False</property>
    <property name="title" translatable="yes">Example Window</property>
    <property name="default_width">480</property>
    <property name="default_height">240</property>
    <child>
      <object class="GtkBox">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="margin_left">4</property>
        <property name="margin_right">4</property>
        <property name="margin_top">4</property>
        <property name="margin_bottom">4</property>
        <property name="orientation">vertical</property>
        <child>
          <object class="GtkLabel" id="_label1">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">Hello World!</property>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="_button1">
            <property name="label" translatable="yes">Click me!</property>
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="receives_default">True</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>
```

### ここまでのまとめ

+ Ubuntu に GTK、GtkSharp SDK をインストールして GTK の開発環境を構築しました。
+ dotnet コマンドにより GTK GUIアプリを新規作成、ビルド、実行することが出来ました。

## 開発環境について

### VS Code で開発してみます

開発に必要なプラグインをインストール  

+ WSL
+ Remote - SSH
+ C#

ワークスペースを開く  
※ Windows 11 の VS Code で、WSL Ubuntu 22.04 のソースコードを開きます。  

```sh
$ cd ~/tmp/MyGtkApp
$ code .
```

実行とデバッグ設定

+ [実行とデバッグ] ボタン
    + 環境の選択
        + .NET 5.0+ and .NET Core
        + VS Code からデバッグブレークが可能

![GTK_Debug.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177199/6b438fde-5430-dfe2-34a1-1ce498d84341.png)
デバッグ実行ボタンを押すと、Windows 11 の VS Code で開いている WSL の Ubuntu 22.04 側の GNOME GUI プログラムのソースコード上のブレークポイントで停止してくれます！  
※ 魔法のような話ですが本当です。 Microsoft さんありがとうございます😭  

## まとめ

+ Ubuntu 22.04 で GNOME GUI アプリを作成、ビルド、実行することが出来ました。

## 個人的見解

+ ウィジェット・ツールキット GTK は広く使用されているので、WEB ブラウザを使用しないクロスプラットフォーム UI 開発の選択肢の一つになると思いました。
+ .NET の Linux 対応により C# で開発出来るアプリの幅が広がったと思いました。

## 参考

##### GTK

https://docs.gtk.org/gtk3/

##### GtkSharp

https://www.mono-project.com/docs/gui/gtksharp/