GTKの世界観です。Linux(X11周辺)やQtも参照のこと。
X11やGNOMEで使われるGUIツールキット。ライバルはQt。
C言語でオブジェクト指向を行う独自のGLibという仕組みを使いながら、C++だけではなくC#やPythonなどにも対応することで、「ハッカー界の多くの言語」に門を開きながら、ウィジェットとイベント・シグナルをベースとした「オブジェクト指向のツールキット」を提供している。
GNOMEでの標準ツールキット。KDEで使われているQtが当時フリーでは無かったため、GNUによってGNOMEとともに開発された。開発元はPhotoshopキラーとして有名なGIMP。
Wikipedia
ソースコード
GTKは、Motifの代わりになるために開発された、GIMPの開発メンバーによるツールキット。
特徴として、オブジェクト指向の考え方に基づいて設計されていること、シグナルハンドラの考え方に基づいてイベントドリブンなGUIアプリケーションの開発ができることなどがある。
また、C言語で書かれていることから、言語バインディング(GTKをさまざまなプログラミング言語で利用するためのラッパー)を作りやすく、C/C++以外にもC#やPythonやRubyなどさまざまな言語バインディングが開発されている(対応状況に違いがあるため、全ての言語バインディングで目的の機能が使えるとは限らない)。
下位ライブラリとして、ピクセル描画ライブラリのGDK、ベクターグラフィックス描画ライブラリのCairo、オブジェクト指向を実現する低レベルライブラリのGLib/GObject、多言語文字ライブラリのPango、アクセシビリティ支援のATK、仮想ファイルシステムのGIOなどが知られる。
また「コンテナ」と呼ばれる概念があり、ひとつまたは複数のウィジェットを含めることができる。1つのウィジェットを含めることができるのはBinで、複数のウィジェットを含めることができるのはBoxとTableである。
GTKの開発元はBSDと同じカリフォルニア大学バークレー校。フォトレタッチ・デザインソフトウェアGIMPの副産物として開発された。
(一部の内容でRuby Way 第2版 (Professional Ruby Series)を参考に執筆しました。)
GTK+は「GTK」に名称を変更した。以下の記述は執筆時の「GTK+」のままだが、これから書く新しい記事は「GTK」としたい。
GTK/GLibでは、型名や関数名などなんにでもgをつけます。
たとえば、型名ならgint, gchar*, gboolean, gpointer, 関数名ならg_signal_connect()のようにです。
これは、C言語でオブジェクト指向を行うGLib/GObjectのおかげで、標準には存在しないオブジェクト指向の型や関数を使うからです。慣れるまでは醜いかもしれませんが、論理的な「オブジェクト指向のデスクトップ環境」を作る上で、C言語のままで優れたやり方をしています。
g_object_new()は、オブジェクトを作成するためのGObjectの関数です。ウィジェットは、g_object_new()あるいはウィジェットごとの関数で作成します。ウィジェットは、GtkWidget*, GtkWindow*, GtkTextView*などのポインタ変数で保持・参照します。
GObjectにおいては、g_object_new()に、型名であるGTypeを指定し、プロパティ名と値の組(必ずNULLで終わる)を指定することで、オブジェクトを作成できます。GTypeにはGTK_TYPE_WINDOW(ウィンドウ)やGTK_TYPE_LABEL(ラベル)やGTK_TYPE_BUTTON(ボタン)などがあります。
このほか、g_object_set()でプロパティ値を設定し、g_signal_connect()でイベントとコールバック関数を関連付け、gtk_container_add()でコンテナ(別のウィジェットを格納できるウィジェット)に格納します。
GObjectにおいては、g_signal_connect()でシグナルハンドラを追加します。これにより、ボタンがクリックされた時などに、コールバック関数を実行するように登録できます。
ほかにも、g_やgtk_やgdk_やgnome_ではじまる関数が多数登場します。
2023.02.19編集
g_signal_connect()の引数は、g_signal_connect(対象オブジェクト, シグナル名, 新しいシグナルハンドラとなる関数, オプションのデータ)となる。
たとえば、
GtkWindow *window; GtkButton *button; gtk_init(&argc, &argv); window = g_object_new(GTK_TYPE_WINDOW, "title", "Application 1", NULL); g_signal_connect(window, "delete-event", G_CALLBACK(delete_func), NULL); g_signal_connect(window, "destory", G_CALLBACK(end_func), NULL); button = g_object_new(GTK_TYPE_BUTTON, "label", "_Button 1", NULL); g_signal_connect(button, "clicked", G_CALLBACK(button_clicked_func), NULL); gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(button)); gtk_widget_show_all(GTK_WIDGET(window)); gtk_main(); return 0;
のようになる。実際はmain()関数に上記のコードを記述し、delete_func(), end_func(), button_clicked_func()の関数をそれぞれ作成する。
まず、gtk_init()関数で初期化を行い、ウィンドウwindowをg_object_new()関数で作る。
そして、g_signal_connect()関数を使って、windowのdelete-eventイベントに自分で作ったdelete_func()関数を、destroyイベントに自分で作ったend_func()関数をコールバック関数として(関数名にG_CALLBACK()をつける)登録している。
同様に、ボタンbuttonを作った上でbuttonのclickedイベントに自分で作ったbutton_clicked_func()関数をコールバック関数として登録している。
それらが終わった後で、gtk_container_add()関数を使ってコンテナとしてのwindowにウィジェットとしてのbuttonを追加し、gtk_widget_show_all()関数でそれらを表示している。
最後に、gtk_main()関数でアプリケーションのイベントループを開始している。
(The Official GNOME 2 developer's guideを参考に執筆しました。115~116ページに類似のコードが出てきます。)
2023.02.19編集
実際のGTKでは、g_object_new()だけではなく、gtk_window_new()やgtk_button_new_with_label()のようなさまざまなウィジェットに対応する関数が用意されている。
これらを使った方が、簡潔で簡素なコードとなる。
主なウィジェットには、GtkWindow, GtkDialog, GtkButton, GtkLabel, GtkMenu, GtkMenuItem, GtkToolbar, GtkHBox, GtkVBoxなどがある。
また画像やグラフィックスを表示するためにGtkImageや、GDKのGdkPixbufなどもよく使う。
ウィジェットの作成は、g_object_new()でオブジェクトを作成し、gtk_container_add()でウィジェットを別のコンテナ系ウィジェットに格納し、g_signal_connect()でシグナルハンドラを登録する。
2023.02.19編集
GObjectでは継承も可能。GTypeは単一継承で、基底クラスを継承して派生クラスにできる。
また、GTKではほかのプラットフォームネイティブなツールキットにあるように既に用意されているウィジェットだけではなく独自のウィジェットを作れる。
詳しいことは以下が参考になる。
カスタムウィジェットを作る方法は以下(RubyとC++とValaとC言語)。以下はさまざまな種類のカスタムウィジェットを作っていて、それぞれ違うため参考になる:
他の言語バインディングについても検索するとたくさん出てきます。
以下の書籍・ページが参考になります。
GNOMEのオブジェクトシステム。C言語などを通じて、オブジェクト指向のプログラミングが出来る。応用言語にVala(GLibをベースにC#/.NETを模したコンパイル言語)などがある。
Wikipedia
ソースコード
GIMPの開発チームによって作られたウィジェット・ツールキット。動作が遅くのっぺりしているがきちんと動くことで有名。ライバルはQt。
Cで書かれていて、さまざまな言語フロントエンドがあり、色んなオープンソースのプログラミング言語でGUIアプリケーションを表示・操作することが出来る。
Wikipedia
GDKはGTK+で使われている低レベルなグラフィックライブラリ。低レベルな描画処理・イベント処理などを担当する。
GDKはWindows APIやQuartzにも対応しているため、GIMPなどはWindows版も存在する。
Wikipedia
CairoはベクターグラフィックスのプログラミングAPI。GDKと一緒に使う。Cairoを参照のこと。
以下はGNOMEで使われているGTKのレイヤー。
ここでは、以下のようなレイヤーがあることが分かる。
レイヤー | コンポーネント |
---|---|
高水準 | GNOME(デスクトップ環境・アプリケーション) GTK(ウィジェットツールキット) |
中水準 | Pango(多言語テキスト表示) GDK(ピクセルグラフィックス描画) ATK(アクセシビリティ) GIO(IO・仮想ファイルシステム) |
低水準 | Cairo(ベクターグラフィックス描画) GLib(型・オブジェクト指向) |
ディスプレイサーバ | Xlib(X11) Wayland(ディスプレイサーバ) Linux(カーネル) |
詳しくはシステムレイヤーを参照のこと。
GTKはオンラインからGitLabのリポジトリを参照することでコードを参照できる。
パソコンの初心者がパソコンを操作して、まず最初に興味を持つのはGUIツールキットではないかと思う。世間ではカーネルやコンパイラばかりの内部仕様(インターナル)が解説されるが、本当は誰もが知りたいのはX11やGTK/Qtのコードではないかと思う。
テーマ集サイトとしてはgnome-look.orgがあります。Qtほど美しくありませんが見た目を綺麗なものに変えられます。
あまり一般的ではないが、GTK+もクロスプラットフォームに対応していて、WindowsでもGTK+アプリケーションを開発することができる。以下のようなページを参照のこと。
たとえば、GTK+で作られたGIMPやInkscapeはWindowsでも動くようになっている。
アクセシビリティツールキット。主に視覚障害や聴力障害など、さまざまな程度の障害がある人などを対象に、GNOMEを使いやすくする。
アクセシビリティはA11y(Accessibilityの短縮形)と呼ばれ、i18n(internationalizationの短縮形で、アプリケーションを国際的に使いやすくする)やl10n(localizationの短縮形で、その地域によって使いやすくする)やm17n(multilingualizationの短縮形で、たくさんの言語で使いやすくする)などと同様にGNOMEでは重要視されている。
以下のopenSUSE 評議会(Board)などでは、評議会メンバーに視聴覚障害を持った方が居ることが分かる。
ORCAと呼ばれるアクセシビリティ用のツールもある。
PangoはGNOMEで使われている多言語・多文字の表示システム。
ソースコード
GTK+アプリケーションはpkg-configを用いて独自のコマンドでコンパイルする。
pkg-configによるコンパイルは以下のようになる。
$ gcc hoge.c `pkg-config --cflags --libs gtk+-3.0`
(各々の生き方: C/C++ Hello World ウィンドウ表示(GTK+)より引用。)
主にC言語によるGTK+プログラムでは、pkg-configを用いてコンパイルを実行しなければコンパイルが通らない。
Makeも参照のこと。
英語だけど、以下のリソースが参考になるかもしれない。
あるいは、自分で検索してください。さまざまな言語が使えるし、GladeというGUIデザインツールもあります。
Gladeと呼ばれるGTK+用のGUIデザイナーがあります。Gladeを参照のこと。
GTKアプリケーションをさまざまな言語で開発できる言語バインディングについては、GTK言語バインディングを参照のこと。
基本的には、C言語の関数でウィジェットを作っていって、イベント関数を登録していく感じになるのかなと思います。
相花毅氏がとても有用なドキュメントをたくさん翻訳されてくださっているので、そちらを参考にしてください。
具体的にどんなコードになるのかは、以下のような感じ:
実際のところ、GTK+とVBは良く似ている。VBで作るのと全く同じように、ツールキットに対して関数を設定することで、GTK+プログラムは出来上がる。
以下のサイトが参考になる。
GNOME、GNOMEデスクトップ、GNOMEアプリケーションを参照のこと。
Xfceを参照のこと。
GIMPを参照のこと。
X11のAPIについては、X11やその子ページを参照のこと。
GUIの開発全般についてはGUI開発を参照のこと。
イベント駆動を参照のこと。
GTK+/GLibの問題として、クラスやAPIの設計が未熟である、というのが挙げられる。C言語で完結できて、さまざまな言語で開発できるとは言うが、クラスライブラリやAPIの設計が、DelphiやBeOSほど美しくない。
MSが.NET、OracleがJava、MacがCocoaなどで「美しいクラス設計」をしているのとは対照的に、たとえばgpointerのように型名に「g」をつける必要があるなど、「醜くて、使い辛くて、分かりにくくて、美しくない」という特徴がある。
だが、そういう人は、一度GTK#/Monoを試してみよう。LinuxでもGTK+とMonoを使うことで、C#/.NETで開発ができる。VMが邪魔だと言う人は、Valaを試してほしい。
GTK+はさまざまな言語で開発ができる。特に、PythonやRubyで開発できるのは、「Cの関数なんか使いたくないよ」という「高水準な言語オタク」にとってはとても優れた長所である。どんどんC#やRubyでGNOMEアプリを開発してほしい。GNOMEのネットワーク・オブジェクト・モデルのアーキテクチャは、そうした人々のためにある。
僕は、GTK+やBonoboなどに言えることとして、もっとウィジェットを用意して、その上でカスタムコントロールやコンポーネントをもっとたくさん用意すれば、面白いことに成るのではないかと思います。
たとえば、MS-Wordを簡単に作れるような「ワープロコンポーネント」を用意します。これによって、どんなプログラマでも簡単にコンポーネントを使うだけで、独自の自分のワープロソフトが作れるようになるでしょう。
今のところ、Gnumericのコンポーネントのようなものはあるようですが、僕はもっとGNOMEでコンポーネントを用意し、「GUIアプリケーションがたくさん生まれるような土壌」を作り出しても良いと思います。
最近のGTK界隈では、「libadwaita」と呼ばれる新しいライブラリが問題となっています。
libadwaitaは、GTK4のためのライブラリで、「新しいGNOMEの標準テーマ」でありながら、「HIGに準拠するためにテーマやウィジェットの描画をライブラリに一任させるもの」です。
今までのGNOMEでは、HIG(GNOMEの一貫したユーザーインターフェースのガイドライン)を守るために、HIGという文書を作って、あとはそれぞれのアプリケーションの開発者がそれに準拠して開発を行ってきました。
ですが、このモデルだと、手作業でHIGに準拠しなければならず、大変です。
そこで、ライブラリとして、このHIGに準拠したUI描画を行うようなライブラリを作って、それに一任しよう、という発想が今回のlibadwaita問題です。
libadwaitaを使うと、HIGへの準拠がスマートにでき、また今までGTKとGNOMEプロジェクトがやっていたことをひとつのライブラリに分離できますが、libadwaitaが標準テーマとなってしまい、そのためlibadwaitaの見た目(醜いという人も居る)を、今までのテーマエンジンのように変えることが難しくなってしまうのではないか(あるいは違うやり方になってしまうのではないか)、ということが問題です。
ただし、多くの人が指摘しているように、そもそもGNOMEでカスタムテーマを使うということは、GNOME公式の推奨ではありません。カスタムテーマは公式でも標準では推奨されておらず、もともとは外部ユーザーがハックする形で実現していたのです。
というわけで、libadwaitaを使うことで、GNOMEではテーマがlibadwaita一択になってしまい、これまで以上に「醜いインターフェースを変えられない」ようになることが予想されます。
このことにより問題が出てくるのは、カスタムテーマを採用しているカスタムディストリビューションです。自分たちが独自に採用した、ディストリビューションのデスクトップの独自テーマを変更できなくなってしまいます。そのため、System76によるPop!_OSなどでは、Rustを用いた新しいデスクトップ環境であるCOSMICなどの開発が始められています。
GTKを開発のために使う際に、知っておくべきことは「コンテナ」の概念です。
コンテナとは、ウィジェットコントロールを内包するウィジェットコントロールのことで、GTKではHBoxやVBoxのようなウィジェットの中に、さまざまなウィジェットを詰め込むことができます。
もうひとつは、「イベント」や「プロパティ」の概念です。
GTKはオブジェクト指向のGUIツールキットであり、ウィジェットにはそのウィジェットの性質を示すさまざまな「プロパティ」と、イベント駆動で関数を実行する「イベント」の概念があります。
GUIプログラミングとは、多くがそのようなイベントやプロパティとの格闘です。イベントやプロパティを操作することが、GUIプログラミングの大きな部分となります。
最後に、静的にウィジェットを作るだけではなく、動的にウィジェットを生成したり破棄したりする方法を学びましょう。
ひとつのビュー画面だけで作られるアプリケーションを作るのは楽です。ですが、タブなどを用いて複数のビュー画面をひとつのアプリケーションの中に内包する場合、タブと一緒に動的にビュー画面を作れなければなりません。
そのようなビュー画面の動的な生成と破棄の方法を知ることで、GUいアプリケーションの開発がとても簡単になるでしょう。
ほかにもGUIプログラミングにはさまざまな要素があるので、詳しくはGUI開発のページを参照のこと。
2024.06.18
GTK+
Takeshi AIHANAさんによるドキュメント和訳。
GTK+によるプログラミング。