GNOMEフレームワーク

出典: フリー教科書『ウィキブックス(Wikibooks)』
移動: 案内検索

メインページ > 工学 > 情報技術 > プログラミング > GNOMEフレームワーク


GNOMEとは[編集]

w:GNOME (GNU Network Object Model Environment) はw:GPLで提供されるGUIデスクトップ環境で、多くのPC-Unix上で動作します。これはUnix上でより現代的な操作方法を提供するために用いられます。

Ubuntu 9.04 Jaunty Jackalope.png

実際には特に外見にこだわりが無く、またコンピュータを扱うスキルが相応にあるのなら、特にUnix系の環境ではGUIのデスクトップ環境が無くとも、コンピュータについてほとんど全ての管理や操作を行うことができます。

例としてプログラムの起動を行うことを考えてみます。Windowsw:Macでは、プログラムを起動する際に対応するアイコンを用いて操作を行うことが普通です。 一方、デスクトップ環境が動いていないUnixではプログラムを起動するためのアイコンは提供されません。幸いなことにアイコンが存在しなくとも対応する"シェル"からプログラムの名称を指定すれば、対応するプログラムを起動することができます。これは、デスクトップ環境を起動した上で対応するアイコンを用いた操作を行うことと同じ操作に対応します。"シェル"の説明や実際の操作についてはUNIX/Linux入門を参照してください。

上の例から分かるように、コンピュータに慣れたものにとってはGUIデスクトップ環境はいくつかの場合を除いて無くてもよいものです。これはGUIで行うことができる操作は大抵GUI無しでも行うことができるからです。一方、GUIを用いた操作はより直観的であり、初心のうちはGUIを用いた操作の方が安心感があるでしょう。

GNOMEは、初心者にも簡単にコンピュータを操作できる手法を提供します。このためには、熟練した利用者が"シェル"を用いて行い得ることを、直観的なGUIとともに利用者に提供する方法を作成する必要があります。控え目にいってもこれは高度なプログラムです。例えば、GNOMEが提供するソースコードはライブラリからアプリケーションまで多岐に渡っておりそれらは更にw:GTK+w:GStreamerなどの他のライブラリに依存しています。

GPLはプログラムの利用者に対してソースコードを公開するよう義務づけています。そのため、GNOMEの利用者はGNOMEのシステムがどのように動いているかを知ることができます。これらの動作には様々な工夫がなされており、その中にはプログラミングが得意なものにとっても非常に興味のある内容が含まれています。

ここでは、GNOMEがどのように動作しているかを様々な角度から見て行きます。具体的にはGNOMEが起動するプロセスを確認し、それらがどのような動作とGUIを提供しているかをソースコードを通して見ていきます。特に、"gnome-panel"と"nautilus"及び"metacity"の動作を確認します。

gnome-panelは上の図上方と下方にある、パネルを提供するアプリケーションです。このアプリケーションはいわゆるw:ランチャー(launcher)であり、登録されたアプリケーションを起動するために用いることができます。このアプリケーションは主にWebブラウザやオフィススイート等のよく用いられるアプリケーションを起動するために用いられます。また、GNOMEやコンピュータの設定を行うためのプログラムもここに含まれる場合があります。

対応する"シェル"の機能は実行可能なアプリケーションを指定されたときに、そのアプリケーションを起動する機能です。熟練した利用者はよく使うアプリケーションの名称を把握しており、それを用いてアプリケーションを起動することができます。このため、ある程度アプリケーションの名称を把握していればランチャーは不要になります。 もちろん、あって損になるものではないでしょう。

次に、nautilusは上の図では全てのウィンドウの後方にある"壁紙"を提供するアプリケーションです。実際にはそれだけではなく、基本的なファイル操作のための機能も提供します。例えば、ファイルのコピーや移動、消去などの操作をGUIで提供します。また、いわゆる"ゴミ箱"の機能も提供します。

ファイル操作はw:OSの機能として基本的であり、対応する操作は"シェル"の基本機能でもあります。例えば、ファイルのコピーはUnixでいうcpコマンドを用いてなされますが、このコマンドは読みだし先のファイルと書き出し先のファイルを開いてファイルディスクリプタを与え、そのファイルから読み出した内容をコピー先のファイルへ書き出すことで行われています(w:coreutils-x.x/src/cp.cを参照)。nautilusはこのような操作に加えてマウスの動作やドラッグアンドドロップなどの操作も把握している必要があります。

一方、壁紙を提供する機能は単に画像を配置する機能であり、画像を提供する機能がライブラリにより提供されているなら比較的単純なプログラムとなります。

最後に、metacityはw:ウィンドウマネージャであり、上の図ではそれぞれのウィンドウの上に貼り付いており、最大化や最小化のためのボタンを提供している部分を与えるプログラムです。これはw:windowsw:Macでは変更できない部分ですが、Unix上でGUIを提供するX Window Systemでは変更可能です。例えば、上の図中の環境でもmetacityを終了し、別のウィンドウマネージャを起動することで上に貼り付いている部分を付け変えることができます。

ウィンドウマネージャはGNOMEの機能というよりXの機能であり、古くから利用されているアプリケーションです。しかし、最近に至ってもw:compizw:en:berylなどの先進的なウィンドウマネージャが提供されています。これらはXを拡張してウィンドウの透明化や3Dの表現などの機能を付け加えています。


ここからの議論ではある程度のC言語の知識を前提とします。また、Unixの動作や高等学校情報の内容も助けになります。これらの事柄を考えると、ここで扱う内容は大学2年以降で扱うべき内容といえそうです。

gnome-panel[編集]

gnome-panelの起動[編集]

まず、gnome-panelを起動する方法について述べます。w:LinuxなどのPC-Unix上でGNOMEデスクトップが動いているときには、gnome-panelは常に起動しています。この状態でシステムのプロセスを表示すると、"gnome-panel"という名称のプロセスが動いているはずです。プロセスを表示するには例えば

$ps ax

のコマンドを用いることができます。

gnome-panelが常に動いていることから、このプロセスをGNOMEデスクトップから離れて、個別に起動することはできないように見えます。しかし、実際にはgnome-panelはデスクトップを構成していると同時に1つのgtk+を用いたGUIアプリケーションでもあります。そのため、gtk+が利用できる環境なら、gnome-panelはGNOME全体を動かすこと無く個別に起動することができます。

Linux上でgtk+を用いるアプリケーションを動かすには、X Window Systemを動かす必要があります。通常GNOMEデスクトップはX上で動くので、GNOMEが動いているときにはXも動いています。ここでは実験のために一時的にGNOMEデスクトップとXを止めることにします。

Linuxを用いているときにこれを行うには、多くの場合システムの"ランレベル"を変える必要があります。"ランレベル"はシステムにおいてどのようなサービスを使用するかを定める値であり、通常3以下がGUIを使用しない環境であり、5がGUIを用いたデスクトップ環境を使う環境です。ここではシステムのランレベルを3にし、GUIを用いない設定を使います。Linuxとしてはw:Fedora Core 5を使用しました。

#/sbin/telinit 3

このコマンドによって"シェル"だけが与えられた環境へと移行します。以降では"シェル"だけを用いてコンピュータを操作する環境になるので、実際に試すときには注意してください。

上のコマンドは、Xも停止させてしまいますが、これではgnome-panelの起動もできないので、再びXを動かす必要があります。XもまたLinux上で動く1つのアプリケーションであるため、自由に停止と起動ができます。システムによってはXを起動するためのコマンドとしてstartxコマンドが推奨されているかもしれません。しかし、このコマンドは多くのXアプリケーションを起動するためここでは使用しません。その代わりに、ここではXを動かすためにxinitコマンドを利用します。xinitはXサーバと少数のXクライアントを起動するプログラムです。これについてはXプログラミングも参照してください。筆者の環境ではxinitコマンドはXサーバに加えて1つのxtermを起動しました。ここで、xtermはX上で動く端末です。

ここまででgnome-panelを起動する準備が整いました。gnome-panelが存在する場所はシステムによってまちまちですが、環境変数PATHの設定が正しければ

$gnome-panel

で見慣れたgnome-panelが表示されます。ただし、GNOMEデスクトップが動いていない場合、"ウィンドウマネージャ"が貼り付いてしまいます。ウィンドウマネージャとしてはtwmを使用していますが、これはXに付属のアプリケーションです。twmは古いアプリケーションなので見た目がやや現代的でない点が難点です。

Gnome panel generic.png

gnome-panelを停止するには

$killall gnome-panel

などを用いてください。killallは指定された名前のプロセスを停止するコマンドです。もしくは、killコマンドを用いることでもプロセスの停止を行うことができます。kill, killallの使い分けについては、UNIX/Linux入門を参照してください。

gnome-panelの動作[編集]

ここからはgnome-panelの個々の機能に付いてソースコードを見ながら説明します。このためにはある程度のGUIプログラミングの知識が必要です。gnome-panelのソースコードはGNOMEのサイト[1]からGPLライセンスで提供されています。筆者が使った版はgnome-panel-2.14.3です。ここで、これ以降./の記述が出て来た場合には、gnome-panel-2.14.3/の意味を表しています。また、同じサイトからはGNOMEデスクトップの使い方に関する文書も提供されています。

また、gnome-panelのGUIに用いられているライブラリであるgtk+はCで書かれたライブラリであると同時にw:オブジェクト指向を用いたライブラリです。以降ではオブジェクト指向の用語としてクラス、インスタンス、メソッド、メンバなどの語句を使いますが、異なった言語では同じ意味の内容に異なった名前をあてていることがあるので注意してください。例えば、オブジェクト指向における"オブジェクト"は大抵インスタンスのことを指します。

各種"オブジェクト"の配置について[編集]

gnome-panelは基本的にはランチャーであり、各アプリケーションの起動を行います。ここで、ランチャーを使うためには、そのランチャーに、どのようなアプリケーションをどのコマンドで起動するかなどの情報を与える必要があります。GNOMEではこの目的でw:en:gconfと呼ばれるライブラリを使います。gconfはGNOMEアプリケーションの様々な設定を記録するためのライブラリです。 ここではまず設定の内容がgnome-panelに伝達されたとして、それを用いてどのように実際に表示される内容が構築されるかについて見て行きます。

gnome-panelには"オブジェクト"と呼ばれるGUI要素があります。"オブジェクト"は、メニューや時計など、gnome-panel内で操作を与えられているGUI要素の総称で、そのGUIは何らかのgtk+ウィジェットで与えられます。ここでは個々のオブジェクトの性質は後回しにして、これらを配置する部分に注目します。

gnome-panelには、実際にオブジェクトを設置できる部分が提供されています。これは、パネル内でメニューや時計などが設定されていない全ての部分を指します。もっとも実際にはメニューや時計なども1つの"オブジェクト"であるため、これらを取り去ることでパネル中のあらゆる位置にオブジェクトを配置することができます。

GUI要素を自由に配置できるgtk+ウィジェットとしてGtkFixedウィジェットがあげられます。このウィジェットはGtkContainerクラスを継承しており、いくつかの別のウィジェットをパックする事ができます。また、ウィジェット内でパックしたウィジェットの場所を指定することができます。GtkFixedを使ったサンプルとして次に例をあげます。

#include <gtk/gtk.h>
int main (int argc, char **argv){
  gtk_init(&argc, &argv);
  GtkWidget *window, *fixed, *button, *label;
  /* ウィンドウ、GtkFixedなど各種ウィジェットを作成 */
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  fixed = gtk_fixed_new();
  button = gtk_button_new_with_label("aaa");
  label = gtk_label_new("bbb");
  /* GtkFixedをウィンドウにパック */
  gtk_container_add(GTK_CONTAINER(window), fixed);
  /* GtkFixed内の(100,100)にボタンを置き、(200,200)にラベルを配置 */
  gtk_fixed_put(GTK_FIXED(fixed), button, 100,100);
  gtk_fixed_put(GTK_FIXED(fixed), label, 200,200);
  /*  表示 */
  gtk_widget_show_all(window);
  gtk_main();
  return 0;
}
Gnome fixed.png

上の例ではGtkFixedウィジェットを作成しボタン、ラベルのウィジェットをGtkFixedウィジェット内に配置しています。このようにウィジェット内のどこにでも他のウィジェットを収納できるウィジェットがGtkFixedウィジェットです。

実際にはgnome-panelの中でもGtkFixedウィジェットが使用されており、"オブジェクト"の配置を自由な位置に行うために役立っています。ただし、GUIを提供する以外に他の項目を設定するために、GtkFixedクラスを継承する形でウィジェットが提供されています。

実際に提供されているウィジェットはPanelWidgetウィジェットと呼ばれ、ソースコード中では./gnome-panel/panel-widget.hで定義されています。このクラスに対応する構造体は最初にGtkFixedを持っていますが、これとCの機能を使うとw:en:glibでいう"継承"を行うことができます。詳しくはOSS開発ツール GUIツールキットを参照してください。

ここまでで、gnome-panel内で"オブジェクト"の配置はGtkFixedクラスの機能によってなされていることが分かりました。他に興味ある点としては、個々の"オブジェクト"がどのように定義されているかや、オブジェクトを導入するための操作などがあります。例えば、"オブジェクト"が配置できる部分を右クリックすると、メニューが開き、追加するオブジェクトを選ぶことができます。この操作はGtkMenuなどで提供される機能ですが、実際にソースコード中でどのようにGtkMenuが用いられているかも調べることができます。

"メニューバー"オブジェクトについて[編集]

ここからは、個々のオブジェクトについて詳しく調べていきます。gnome-panelの多くの設定で使用されているオブジェクトに、"メニューバー"があります。

Gnome panel menu bar generic.png

このオブジェクトはアプリケーションメニューと場所メニュー、アクションメニューの3つのメニューから構成されています。それぞれのメニューをクリックすると種々のメニューが提供されます。アプリケーションメニューではシステムに存在するアプリケーションの起動が扱われ、アクションメニューでは"画面のロック"や"ログアウト"などのGNOMEデスクトップ全体に関わる事柄が扱われます。

メニューバーは大抵の設定でただ1つだけパネル内におかれているので、この部分は動かせないと思われがちです。しかし、実際にはこの部分は取り去ることが可能であり、またパネル内に複数置くことも可能です。

Gnome panel no menu.png
Gnome panel multiple menus.png

メニューバーのクラスはソースコード内では./gnome-panel/panel-menu-bar.hで定義されています。この中のPanelMenuBar構造体を確認すると分かる通り、このクラスはGtkMenuBarを継承しています。そのため、このクラスは基本的にGtkMenuBarと同じ動作をします。GtkMenuBarを使ったサンプルとして次のようなメニューの例があげられます。

int main (int argc, char **argv){
  gtk_init(&argc, &argv);
  GtkWidget *window, *menubar, *menuitem, *menu;
  /* ウィンドウを作成 */
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  /* メニューバーを登録 */
  menubar = gtk_menu_bar_new();
  gtk_container_add(GTK_CONTAINER(window), menubar);
  /* メニューバーの項目を登録 */
  menuitem = gtk_menu_item_new_with_label("mmm");
  gtk_menu_shell_prepend(GTK_MENU_SHELL(menubar), menuitem);
  /* 項目から派生するメニューを登録 */
  menu = gtk_menu_new();
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
  /* 派生した先に登録する項目を作成 */
  menuitem = gtk_menu_item_new_with_label("lll");
  gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), menuitem);
  /* メニューの項目に対応するコールバック menu_cb を登録 */
  g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(menu_cb), NULL );
  gtk_widget_show_all(window);
  gtk_main();
  return 0;
}
GtkMenuを使った例。この画像はできたGUIアプリケーションを見ながら、手で描いたものである。

GtkMenuBarはGtkMenuItemを書き込むことでメニューを作成することができるウィジェットです。 上の例はmmmという名のメニューを作成し、それをクリックしたときlllと書かれたメニューを表示し、更にその中のlllと書かれた部分をクリックすることで関数menu_cbを実行するというプログラムです。メニューの項目は増やせるので、コールバック関数をいろいろなアプリケーションの起動を行う関数とすることで、ランチャーの役目を果たすアプリケーションとすることができます。

ポップアップメニュー[編集]

gnome-panelではパネルの各所を右クリックすることでポップアップメニューを得ることができます。この操作はGUIを使った操作としてはよく見られるもので、どのように実現されるかが気になる所です。実は、この操作はGTK+のクラスであるGtkMenuの操作として典型的なものです。ここではGtkMenuのポップアップの例を見るとともに、実際にこの操作がどのようにgnome-panel中で用いられているかを見て行きます。

GtkMenuのポップアップの例として、次のサンプルをあげます。

int main (int argc, char **argv){
  gtk_init(&argc, &argv);
  GtkWidget *menuitem, *menu;
  /* メニューの例を参照 */ 
  menu = gtk_menu_new();
  menuitem = gtk_menu_item_new_with_label("lll");
  gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), menuitem); 
  g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(menu_cb), NULL ); 
  gtk_widget_show_all(menu);
  /* ウィンドウから離れてメニューを表示*/
  gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0,
     gtk_get_current_event_time() );
  /*メインループ*/
  gtk_main();
  return 0;
}
Gnome panel gtk menu popup no window.svg

上の例では"lll"と書き込まれたメニューを作成した後、そのメニューをgtk_menu_popupによって表示します。メニューが表示される場所はgtk_menu_popupの引数によって変更できるのですが、上の例ではgtk_menu_popupが実行された時点でのマウスカーソルの場所になります。実行例を見るとわかるのですがこの例は何も無い部分に突然メニューが表示されるため、やや非直観的です。普通の例ではGtkWindow等のマウスイベントを設定し,マウスのボタンが押されたときにメニューが表示されるようにします。ただし、GtkWindowは通常ではマウスのボタンに対応するイベントを持たないため,その点を補う必要があります。 このためには、gtk_widget_add_eventsかGtkEventBoxを使う方法がありますが、ここではgtk_widget_add_eventsを用いる方法を述べます。GtkEventBoxについてはGTK+のリファレンス等を参照してください。以降の説明ではある程度Xプログラミングの経験があると理解が容易になります。

gtk_widget_add_eventsはウィジェットがGTK+の背後で動いているウィンドウシステムから、新しいイベントを得るように設定する関数です。背後のウィンドウシステムの代表例はw:X Window SystemですがUnix系のシステムでないなら他のものになることもあります。GTKではウィンドウシステムの値を直接使わなくてもすむよう、w:GDKというライブラリを用いています。GDKはGTK+とともに配布されるライブラリです。

gtk_widget_add_eventsでは引数として(GtkWidget *, GdkEventMask)を取ります。ここで、EventMask(イベントマスク)は対応するイベントをXなどから受け取るかを定めるビット列です。例えば,Xを用いてイベントを処理する場合にはXSelectInputなどを用いますが,この関数の引数としてイベントマスクが用いられます。詳しくはXプログラミングを参照してください。ここで扱うGdkEventMaskも同種の値です。

実際にマウスボタンのイベントを見るには,GdkEventMaskとしてGDK_BUTTON_PRESS_MASKを用います。結局GtkWindowを作った後,

gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK);

を実行すると,ウィンドウ内でマウスボタンの操作を見ることができるようになります。この関数の後には,GTKのイベントである"button_press_event"を用いてマウスのボタンを扱うことができます。

ここまでのことを用いて,メニューを作成してからメインループに至るまでの部分は次のようになります。

GtkWindow *window;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK);
g_signal_connect(window, "button_press_event", G_CALLBACK(window_button_cb), menu);
gtk_widget_show(window);

ただし、menuは上で作成したGtkMenuと同一です。ここで、window_button_cbは次のように与えます。

void window_button_cb(GtkWidget *window, GdkEventButton *button, GtkWidget *menu){
  gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0,
      gtk_get_current_event_time() );
}
Gnome panel gtk menu popup with window.svg


アプリケーションの起動[編集]

アプリケーションの起動を行うためには、 コールバック関数として定義された関数(上の例ではmenu_cbと与えられている)の中で、新たな"プロセス"を作る必要があります。"プロセス"はOSが複数のアプリケーションを同時に動かすときの単位で、それを作る方法はOSによって異なっています。Unix系のOSではプロセスを作る関数は大抵w:forkと呼ばれます。forkはプロセスを作成し、新たに作成されたプロセスのIDを返します。また、作成されたプロセスで実際にあるアプリケーションを起動する関数として、Unix系のOSではexec系の関数が与えられます。execは与えられる引数によっていくつかの似た関数が提供されます。

forkとexecを使った例

実際にそれぞれのメニューバーの項目に対応するコールバックを設定する操作は、./gnome-panel/panel-menu-item.c内の関数panel_menu_items_append_from_desktop内で行われています。この関数は第1引数にメニューの項目、第2引数に起動するアプリケーションの名称を取り、これを新たに作成したメニューの項目に与えています。

既にメニューの項目をクリックしたときの動作を与える方法として、

g_signal_connect(menuitem, "activate", menu_cb, NULL);

を使う方法を紹介しました。ここで、menuitemはここで内容を与えるメニュー項目であり、menu_cbは実際にこのメニューの項目がクリックされたときに実行させたい関数です。指定したアプリケーションを起動して、新たなプロセスを実行するためには、この関数はforkやexecを用いる関数である必要があります。

  • 注意

g_signal_connectはw:en:glibで定義された関数で、"シグナル"が定義されたGObjectクラス及びそれを継承したクラスに対して、コールバック関数を与える関数です。ここで、"シグナル"はおおよそコールバック関数と同じ意味で、Unixでいう"シグナル"(他のプロセスに影響を与える機構)とは無関係です。

panel_menu_item_append_from_desktop内でもこの関数が用いられており、コールバック関数として同じファイル内で定義された、関数panel_menu_item_activate_desktop_fileを取ります。この関数はクリックされたメニュー項目の情報に加えて、そのメニュー項目がクリックされたときに実行されるべきアプリケーションの名称を引数として受け取ります。ここで、この関数はアプリケーションの名称を引数として与えながら、関数panel_ditem_launchを呼びます。launchの名から分かる通り、この関数は実際にアプリケーションの起動を行います。launchは"起動する"、"発射する"などの意味を持つ英単語です。

ここまでも既に長い道のりでした。しかし、ここから実際にforkが呼ばれるまでに、更にいくつかのライブラリを見る必要があります。ある意味でlaunchと名の付いた関数を見付けた時点で、この関数がプログラムの実行を行う可能性は高いため、そこで探索を終える方法もあるでしょう。ここでは、一応最後まで関数の流れを追ってみます。

panel_ditem_launchは、./gnome-panel/panel-util.c内で定義されています。この関数はいくつかの準備を行った後、関数gnome_desktop_item_launch_on_screenを呼びます。実はこの関数はgnome-panel内の関数ではないため、ソースを読もうと試みる人は、この関数が定義されたソースを求めて方々を探す必要があります。実際にはw:googleなどを試してみるのがよいでしょう。

実際にこれを探すと、関数gnome_desktop_item_launch_on_screenは、gnome-desktopというライブラリ内の関数だとわかります。このライブラリもGNOMEのサイトから提供されているので、必要ならダウンロードしてください。実際には、この関数は、gnome-desktop-x.x.x/libgnome-desktop/gnome-desktop-item.cで定義されています。

この関数ではいくつかの引数のチェックを行った後、同じファイル内の関数ditem_executeを呼びます。この関数は関数の名前の最初に、gnome_desktop_...がついていません。このような関数は大抵staticをつけて宣言されており、そのファイル内だけで用いられる関数です。これは、staticをつけた関数は外部からは参照できないことを利用しています。他のファイルの関数名と重複することがないため、単純な名前でもよい訳です。

ditem_executeは様々なチェックなどを行った後、関数g_spawn_asyncを呼びます。この関数はg_から始まっていますが、GNOMEのアプリケーションでこの名称が出て来た場合、この関数は大抵w:en:glibの関数です。例えば、コールバックを与える関数であるg_signal_connectがglibの関数であることは既に述べました。

多くの関数をたどって来ましたが、g_spawn_asyncは事実上最後の関数です。この関数はglib-x.x.x/glib/gspawn.c内で定義されていますが、この関数はいくつかの関数を経て、関数fork_exec_with_pipesという関数を呼びます。この関数は名前の通りforkとexecを呼ぶ関数です。

ここまでで一応gnome-panelのメニュー項目がクリックされてから、実際に新たなプロセスが作成されるまでの道のりを見て来ました。もちろんただプロセスを作ることが目的なら、gnome-panel内で直接forkを呼ぶことも可能です。敢えてライブラリを使うのは、例えばw:Windowsを使うときにはこの方法が使えないことがあげられます。これは、Windows上でプロセスを作るときにはforkではなく別のw:Windows APIを使う必要があるからです。実際glibのgspawn.cがあるディレクトリ内には、gspawn-win32.cというWindows向けの関数も定義されており、glibライブラリをクロスプラットフォームライブラリにするよう試みているようです。

gconfを用いた設定[編集]

ここまでで一応ランチャーとしての役目を果たすための機能を見て来ました。メニューを表示し、そのメニュー項目と対応するアプリケーションを起動することは、ランチャーの機能としては基本的です。ただし、ランチャーが扱えるアプリケーションは、プログラムのふるまいを外部から制御する機構がないのなら、ランチャーを作った人間がプログラム内に書き込んだアプリケーションに限られます。これでは新たなアプリケーションが加わった時にランチャーの振舞いを拡張することができないことになり、不便です。

ソフトウェアの動作を制御するためには、"設定ファイル"を使った方法がよく用いられます。例えば、XサーバやWebサーバ の動作を変更するために、これらの設定ファイルを書き直すことは特にホビーとしてのPC-Unixではよく行われます。

ただし、アプリケーションの動作を制御するために設定ファイルを使った方法を用いる場合には、その設定がアプリケーション内に取り込まれるタイミングが重要になります。例えば、設定ファイルを読む操作がアプリケーションの起動時にしか行われない場合、設定ファイルを変更した後アプリケーションの動作を変更するには、設定ファイルを書き直すたびに対応するアプリケーションを起動し直す必要があり、少し不便です。

より進んだ方法では、設定ファイルを書き直した後、そのことをアプリケーションに伝達する機構を用意しています。ここで、設定ファイルを書き直すプロセスは、一般には設定ファイルを利用するプロセスとは異なっています。このため、設定が変更されたことをその設定を使用しているアプリケーションに伝達するには、"プロセス間通信"の機構を用いる必要があります。

プロセス間通信は異なったプロセスの間で情報を伝達する機構です。この機構もプロセスの操作と同様OSによって提供される機構であり、異なったOSでは異なった動作をします。Unixにおける代表的なプロセス間通信には、w:ソケットを使った方法があげられます。ソケットは異なったプロセスからの情報を受け取るための一般的な機構ですが、これは異なったコンピュータ上にあるプロセスに対しても用いることができます。例えばLinuxでは、w:TCPの通信を行うためのソケットを提供していますが、この通信手法はw:インターネットのあらゆるサービスを提供するための手法として用いられています。

GNOMEでは、設定を扱うためにw:en:gconfと呼ばれるライブラリを利用します。これは、設定を扱うための1つのサーバ(gconfd)を導入し、そのサーバに、サーバ上の設定を参照しているgconfクライアントを記憶させておき、設定が変更された際に、そのことをgconfクライアントに伝える機構です。簡単な例では、gconfdが保持している設定は利用者のホームディレクトリ~の~/.gconf/以下に記録されます。

  • 注意

Unixの"シェル"では、利用者のホームディレクトリを~の記号で表します。設定によるのですが、このディレクトリは大抵/home/user_name/以下におかれます。ただし、user_nameはそのコンピュータに登録されている利用者の名前です。PC-Unixでは大抵利用者はそのパソコンの所有者1人だけなので、/home以下に直接設定ファイルをおけばよいようですが、多くの利用者が異なった設定でgconfを使う場面を想定してこのような作りになっています。

実際のシステムでは~/.gconfは次のようになります。

$ls
apps/  desktop/

これはfedora core 5での~/.gconf/内のファイルを表示した例です。ここには2つのディレクトリしかありませんが,apps/以下にはw:en:Eye of GNOME, w:geditなどの各種アプリケーションの設定が記録されています。これらはそれぞれ

eog/ gedit/

などの名前を与えられています。

gconfの動作を見るために、gconfが提供するツールを使った実験をしてみます。gconfはGConf-x.x.xというライブラリとしてGNOMEのサイトから配布されているのですが、その中には、GConf-x.x.x/gconf/gconftool.cで与えられるファイルが存在します。ここで、GConfのバージョンはGConf-2.14.0を使いました。このファイルは、gconfの設定内容を変更したり参照するための簡単なツールを提供します。このツールはgconftoolと呼ばれます。

ここでは、このツールを用いてgconfを使ってみます。既に~/.gconf/の中を見てみました。ここでは、gconftoolを使ってこのディレクトリ以下に新たな設定項目を作ります。もちろんこの項目は実際にアプリケーションで使われる項目ではないのですが、gconfの動作を見る上では便利です。具体的には、~/.gconf/以下に、/aaa/bbbという項目を作ります。ここで、/aaaは項目が配置されるディレクトリ名を表し、bbbが実際に記録される設定の名前です。もちろんこの階層はいくらでも深くすることができますが、ここではこの程度でよいでしょう。

また、gconfで設定される項目には"型"が必要になります。"型"にはint, bool, float型がなどがあります。これらのうち、intとfloatはC言語の対応する型と同じで、intは整数、floatは実数を表します。boolは例えばCPlusPlusなどでは導入されているのですが、"真"、"偽"の2つの値だけを持つ型です。C言語では1 を"真"、0を"偽"などとしてint型で代用することができます。ここでは、bbbの型はboolで、値を"真"、つまりtrueとします。

具体的に、/aaa以下にbool型の項目bbbを値trueで設定するには、

$gconftool-2 -s /aaa/bbb -t bool true

とします。ここで、-sは項目を指定するための引数であり、-tは項目の型を指定する引数です。

実際にこの操作を実行すると、~/.gconf/は次のようになります。

$ls
aaa/  apps/  desktop/

新たにaaa/というディレクトリが加わっている様子がわかります。aaa/内のファイルを表示すると,

$ls
%gconf.xml

が得られます。ここではgconfの設定はw:XMLファイルに記録されています。この中身は,

<?xml version="1.0"?>
<gconf>
        <entry name="bbb" mtime="1168623910" type="bool" value="true">
        </entry>
</gconf>

で与えられます。この中では3行目の"bbb", "bool", "true"から、上で扱った内容が記録されている様子がわかります。

gnome-panelでのgconf[編集]

ここまででgconfの基本的な使い方を見て来ました。gnome-panelでもパネル内のどの位置にどのオブジェクトが配置されているかなどをを記録するために、gconfを用いています。ここではまず、gnome-panelがどのようにgconfdから設定を受け取り、設定への変更を取得しているかを見て行きます。

gnome-panelの起動[編集]

ここではgnome-panelがどのように起動するかを見て行きます。通常のアプリケーションと同様、gnome-panelは起動時に設定を参照してどこにオブジェクトを配置するかなどを決めます。この設定は設定ファイルではなく、gconfを用いて行われるのですが、ここでは実際にアプリケーションの起動時にどのようにgconfが用いられているかを見て行きます。

大抵のGNOMEアプリケーションではアプリケーションの起動はmain関数から始まります。これは普通のCプログラムと同じです。一方、w:Windows APIを用いたWindowsのcプログラムでは、アプリケーションはWinMain関数から始まります。これはGUIアプリケーション一般の性質という訳ではないので注意してください。

そのため、アプリケーションの起動の様子を見るためには、このアプリケーションのmain関数を探す必要があります。gnome-panelでは、./gnome-panel/main.cに、アプリケーションのmain関数が定義されています。main関数では各種の初期化や設定が行われているのですが、その中でgconfとの相互作用を扱う関数として、関数panel_profile_loadが呼ばれています。この関数は、./gnome-panel/panel-profile.c内で定義された関数で、"いくつのパネルがあるか、それぞれのパネルにはどのようなオブジェクトやアプレットが配置されているか"などの各種情報をgconfdから受け取り、対応するウィジェットを作成しています。

実際には関数panel_profile_loadの最後で、関数panel_applet_load_queued_appletsが呼ばれています。 この関数は、./gnome-panel/applet.c内で定義されていますが、おおよそ関数panel_applet_load_idle_handlerを呼び出す関数です。panel_applet_load_idle_handlerもapplet.c内の関数ですが、この中では追加されたオブジェクトのタイプに対して、動作を変更するための、大きなswitch文が用いられています。switch文はC言語の制御構造の1つで、複数の条件があるときに、それらの条件に対して場合分けを行う文です。詳しくはC言語内の説明を参照してください。このswitch文はgconfが与えた内容に対して作成するウィジェットを変更するための場合分けで、これ以降各ウィジェットを作成する手順はウィジェットの種類によって様々です。 具体的には追加されたオブジェクトが"メニューバー"だった場合にはpanel_menu_bar_load_from_gconfを呼んでいます。この関数は設定に従って対応する"メニューバー"オブジェクトを作成する関数です。この関数の詳細を追うこともできますが、一応gconfの設定を読んだ後に、設定に応じて各種のオブジェクトを与える過程が得られたので、アプリケーションの起動に限った話はここまでとします。

各種設定の変更[編集]

ここまでで、gnome-panelが起動するときに、gconfが与える設定に従って、各種ウィジェットを見分ける方法を見て来ました。実際にはgnome-panelはgnome-panelが動作している最中に設定が変更されても、それに対応してウィジェットを作成する機構を持っています。これはgconfの機能を活用した機構です。

具体的には、gnome-panelはパネルの自由な位置に利用者が指定したオブジェクトをgnome-panelを再起動すること無く導入するためのGUIを持っています。このGUIは、gnome-panelの設定の変更とそのことのgnome-panelへの伝達を同時に行っており、設定を変更するたびにgnome-panelを起動しなおす手間を省いています。 ここでは、このGUIを用いて、gnome-panelに各種オブジェクトを配置する方法を見て行きます。

まず、gnome-panelの設定を変更するためのGUIとして、gnome-panel/panel-addto.c内の関数が用いられています。このファイル内の関数はGtkDialogを用いて利用者からgnome-panel内で変更したい設定を取得しようとします。ここではこのウィジェットをAddToダイアログと呼びます。

Gnome panel addto dialog.png

ここで、GtkDialogはGtkWindowを継承したクラスで、GtkWindowに"OK", "キャンセル"などの各種ボタンを与えるクラスです。一般的なGtkDialogの例として、次のようなサンプルがあげられます。

#include <gtk/gtk.h> 
int main (int argc, char **argv){
    gtk_init(&argc, &argv); 
    GtkWidget *dialog, *label;
    /* ダイアログの作成 */
    dialog = gtk_dialog_new_with_buttons(NULL,
      NULL,
      0,
      "はい",
      1,
      "いいえ",
      2,
      NULL);
    label = gtk_label_new("あああ\n");
    gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
    gtk_widget_show_all(dialog);
    /* 応対(response)の取得*/
    int response = 0;
    response = gtk_dialog_run(GTK_DIALOG(dialog));
    switch(response){
        case 1:
            g_print("はい\n");
            break;
        case 2:
            g_print("いいえ\n"); 
            break;
        default:
            break;
        }
    return 0;
}
Gnome panel gtk dialog.png
解説


AddToダイアログの動作はgconfの機能を使っています。具体的には、gconfの設定のうち、オブジェクトの種類や配置が記録されている部分にgconf_client_add_dirを使い、その値が変更されたときのコールバック関数を登録するために、gconf_client_notify_addを使っています。具体的には、これらの関数は既に見た関数panel_profile_load内及びそこから呼び出された関数内で用いられています。

関数panel_profile_loadは、途中でgconf_client_add_dir関数を呼び出しています。ここで指定するgconfの階層は、/apps/panel/generalです。この階層以下には、パネルの数やオブジェクトの位置などが記録されるため、オブジェクトの数を確認するためにはこの部分の変化を見ておく必要があります。

ここで実際のgnome-panelでの例を示します。実際にgconfの設定を見るためにgconftoolを用います。gconftoolで対応するディレクトリ以下の設定項目を見るには,

$gconftool-2 [-R|--recursive-list] ディレクトリ名

とします。

gnome-panelの設定を見るためには、あらかじめgnome-panelをできるだけ単純に設定しておくと後が楽になります。ここでは、パネルは1つだけを残して全て取り去り、残ったパネル内のオブジェクトも全て取り去りました。この操作は対応するパネルやオブジェクトを右クリックし、対応するメニューを用いることで行えます。また、最後のパネルを消そうとすると、メニューが表示されなくなるため、全てのパネルを消し去ることはできません。パネルを右クリックした場合新たなパネルを追加するメニューが表示されるため、それを用いて新たにパネルを加え、設定を元に戻すことができます。

実際にこの設定にした後,上のコマンドでディレクトリ名として/apps/panel/generalを用いると

object_id_list = []
applet_id_list = []
toplevel_id_list = [panel_1]

などの出力が得られます。ここで、object_id_list、applet_id_listはそれぞれパネルに含まれるオブジェクト、アプレットを表します。ここでは、オブジェクトを1つも用いていないので、これらは空欄となります。一方toplevel_id_listはパネルがいくつあるかを示すリストです。ここではただ1つのパネルを用いているため項目は1つだけとなります。後にわかるのですが、panelが複数になった時にはこの部分にpanel_2, panel_3, ... などの項目が追加されます。ここで、1, 2, 3などの数字はidと呼ばれます。この用語はtoplevel_id_list等の名前にも用いられていますが、以降のソース内の関数名にも何度か用いられます。

これで、オブジェクト、アプレット、パネルの数がどのように記録されているかがわかりました。更にこれらの設定の詳細については/apps/panel以下の各ディレクトリに記録されています。例えば,/apps/panel/toplevelsにはパネルの設定が記録され、/apps/panel/appletsにはアプレットの設定が記録されます。例えば/apps/panel/toplevels/panel_1の設定を見ることもできますが、設定項目の数が多いのでこれらの詳細には触れません。比較的意味が取りやすいものでは、

size = 24
orientation = top
auto_hide = false

などがあります。これらは、それぞれパネルの幅(単位はピクセル)、パネルを画面中でどの位置に置くか、カーソルが置かれていないときパネルを隠すかどうかに対応します。これらはどれもパネルの右クリックメニューから扱うことができる"プロパティ"によって設定できる項目です。

次に、パネルの数とアプレットの数を増やして同じ操作をしてみます。ここではパネルを2枚にし、メインメニュー、時計、通知スペース、ウィンドウの一覧、デスクトップの表示などの各種オブジェクトを追加しました。ただし、パネルの位置はそれぞれ上と下とし、オブジェクトのうち最初の3つは上のパネルに加え、後の2つを下のパネルに加えました。この場合/apps/panel/generalでの出力は

object_id_list = [object_1]
applet_id_list = [applet_0,applet_1,applet_2,applet_3]
toplevel_id_list = [panel_1,panel_2]

のようになります。ここで上では5つのオブジェクトを加えたのに、設定ではオブジェクトが1つでアプレットが4つとなっています。実際にはアプレットもオブジェクトの一種なのですが、アプレットは他のオブジェクトと比べてかなり動作が異なるので、アプレットは別に扱われます。

具体的にはアプレットはソース内ではOBJECT_BONOBOなどと呼ばれます。ここで、BONOBOはアプレットを扱う技術の名前なのですが、この技術は単純にはプロセス間通信を用いた技術です。実は上の時計などのアプレットの本体は、gnome-panelのプロセスとは別のプロセスとして存在します。例えば,時計が動いているgnome-panelが存在する時には,常にclock-appletというプログラムが動いています。具体的には、対応するpsコマンドの出力には、

3855 ?        S      0:00 /usr/libexec/notification-area-applet --oaf-activate- 
3859 ?        S      0:00 /usr/libexec/clock-applet --oaf-activate-iid=OAFIID:G
3874 ?        S      0:00 /usr/libexec/wnck-applet --oaf-activate-iid=OAFIID:GN 

などの出力が含まれます。ここで注目してほしいのは、中間の/usr/libexec/以下の各項目です。これらは上から順に通知スペース(notification-area)、時計(clock), ウィンドウの一覧に対応するプロセスです。BONOBOのライブラリであるlibbonoboについてはここでは深くは扱いません。w:en:bonobo (computing)[2]などを参照してください。

ここでは更に、/apps/panel/objectsやa/apps/panel/appletsの中身も見てみます。上で導入したオブジェクトの中でメインメニューはオブジェクト(アプレットでない)なので、/apps/panel/objects内に記述があるはずです。実際にこの項目を見ると、

/apps/panel/objects/object_1:
 toplevel_id = panel_1
 object_type = menu-bar
 position = 79

などの項目が与えられます。この中で、object_1はメインメニューに対応するオブジェクトのはずですが、menu-barの名前が3行目にあるので、確かにこのオブジェクトがメインメニューに対応することがわかります。他にpositionはメニューの位置を表し、toplevel_idはこのオブジェクトがどのパネルに含まれるかを表します。panel_1は上側のパネルなのでこれで正しいわけです。他にlockedという項目がありましたがこの項目はおそらくそのオブジェクトが"ロック"されているかを表します。"ロック"はオブジェクトの移動を禁止する機能で、右クリックメニューから選ぶことができます。

更にアプレットについては次のような項目が存在します。

/apps/panel/applets/applet_0:
 toplevel_id = panel_1
 bonobo_iid = OAFIID:GNOME_NotificationAreaApplet
 object_type = bonobo-applet
 position = 606 

ここで、object_typeはbonobo-appletとなっていますが、この項目はアプレット全般に対して用いられます。また、toplevel_idとpositionについては既に扱いました。最後にbonobo_iidですが、これはBONOBOの機構内でどのプロセスからの入力を扱うかを定める1つの文字列です。ここではNotificationAreaの文字があるので、このアプレットが"通知スペース"に対応することがわかります。

ここまででgnome-panelの設定に関する実例を見てきました。これらの設定の変更を扱うために、関数panel_profile_loadの中ではgconfの設定内のパネル、オブジェクト、アプレットそれぞれの設定に対して、panel_profile_load_listという関数が呼ばれています。関数panel_profile_load_listもpanel_profile_loadと同じファイル内で定義されているのですが、この関数は関数内でgconf_client_notify_addを呼び出しています。

gconf_client_notify_addの引数は、パネルの設定に対してこの関数が呼ばれた場合とオブジェクトやアプレットに対して呼ばれた場合で変化します。例えば、オブジェクトの設定を読んだ場合には関数panel_profile_object_id_list_notifyが引数として与えられます。この関数はどのオブジェクトが消えたり追加されたりしたのかを把握し、オブジェクトに対応するウィジェットを追加したり取り除くという作業を行う関数です。実際に関数panel_profile_object_id_list_notify内ではpanel_profile_load_added_idsとpanel_profile_delete_removed_idsの2つの関数が呼ばれていますが、これらの関数は名前の通りの動作をし、付け加えられた(added)オブジェクトを読み出したり(load)、取り除かれた(removed)オブジェクトを解放したり(delete)します。

実際にウィジェットを追加するのは関数panel_profile_object_id_list_notifyの最後で呼ばれている関数panel_applet_load_queued_appletsですが、この関数は既に見た関数で、gconfから受け取ったリストを用いて、対応するウィジェットを作成する関数です。ここでは、関数panel_profile_object_id_list_notify内でリストの変更が取り入れられているので、ウィジェトの追加や削除を行うことができるわけです。

ここまででgconfの設定をアプリケーションの動作中に反映するための機構を見て来ました。これらはアプリケーションの起動時にしか変更を反映できない方法と比べて優れた方法です。同様の方法は他のGNOMEアプリケーションでも用いられており、gconfがGNOMEのライブラリとして重要であることを示しています。

アプレットの動作に必要なライブラリ[編集]

既に"アプレット"がlibbonoboを通じて実現されていることを述べました。ここで、libbonoboはプロセス間通信を行うための一般的な技術です。これは、アプレットを扱うプロセスとgnome-panelのプロセスの間の通信を行うために用いられます。

アプレットはlibbonoboに加えてlibbonobouiライブラリに含まれる技術も用いています。libbonobouiライブラリはlibbonoboを用いてあるプロセスで制御されるGTKウィジェットを他のプロセスのウィジェットに埋め込む一般的なライブラリです。

GtkPlug, GtkSocket[編集]

まず最初に、GTKを用いたウィジェットの埋め込みを扱います。GTKの枠組みでウィジェットの埋め込みを行うには、GtkPlug, GtkSocketのウィジェットを使います。GtkSocketは、ウィジェットを埋め込まれる側のプロセスが作成するウィジェットで、GtkPlugが実際に埋め込まれるウィジェットに対応します。

X上で動くGTKのプロセス中では、GtkPlug, GtkSocketは埋め込まれるウィンドウを決めるために、WindowIDを用います。WindowIDはXのウィンドウに与えられる一意の数値で、型はXID(大抵unsigned long)で与えられます。

サンプルコード

X上でのWindowIDを知るには、xwininfoコマンドを使うのが簡単です。

$xwininfo

これは指定されたウィンドウのWindow IDやジオメトリ(位置と大きさ)などの情報を与えます。

GtkPlug, GtkSocketを用いて埋め込みを行うには、GtkSocketにGtkPlugのWindowIDを伝える必要があります。このためのlibbonoboui内のクラスとして、BonoboPlug, BonoboSocketの両クラスがあります。これらはそれぞれGtkPlug, GtkSocketを継承します。

実際に埋め込みを行うために、BonoboPlug, BonoboSocketはそれぞれBonoboControl, BonoboControlFrameを使います。ここで、BonoboControlはgetWindowIDという名の"メソッド"を持っており、他のプロセスで実行されるBonoboControlFrameにBonoboPlugのWindowIDを伝えます。ただし、libbonobo, libbonobouiのバージョンとして、2.16.0を用いました。

BonoboControlFrameはGtkWidgetを継承していないため、埋め込まれる側のウィジェットの配置に手間がかかります。この手間を省くため、BonoboControlFrameを"private"なメンバとして持ったクラスBonoboWidgetが存在します。

gnome-panel中でも、/gnome-panel/panel-applet-frame.c内でBonoboWidgetが用いられています。panel-applet-frameはBonoboWidgetを収納するGtkWidgetで、GtkEventBoxを継承します。GtkEventBoxはGtkBinクラスを継承したウィジェットで1つのウィジェットを収納します。

一方gnome-panelでは、埋め込むウィジェットを提供する機構としてPanelAppletクラスが提供されています。(./libpanel-applet/panel-applet.[ch]を参照)このクラスはBonoboControlへのポインタを所持します。各アプレットはこのクラスを継承し、PanelAppletFrameと相互作用します。

各種アプレットの動作[編集]

既にgnome-panelの動作は"アプレット"によって拡張されることを見てきました。ここでアプレットはBonoboと呼ばれる技術を用いて作られており、これらはgnome-panelとは異なったプロセス内で動作しています。この時、なぜ単純にgnome-panelの新たなオブジェクトとして各機能を作成しなかったのかが疑問に思われます。

詳細は不明ですがこの方式の明らかな利点として、各アプレットを作成する言語として、C言語以外の言語を選べることがあげられます。実際gnome-applets内に含まれるアプレットでinvest-applet(gnome-applets-x.x.x/invest-applet)はw:Pythonを用いて作成されています。ここでgnome-appletsはGNOMEから配布されているファイルで、gnome-panelの各種アプレットを扱っています。この中には音量調節(gnome-applets-x.x.x/mixer)やごみ箱(gnome-applets-x.x.x/trashapplet)などのアプレットが含まれています。ただし、gnome-appletsのバージョンとしてはgnome-applets-2.16.2を用いました。

これに加えて既に登場した時計、通知スペースなどのアプレットがgnome-panel内に含まれています。(それぞれ./applets/clock, ./applets/notification_area内のファイル)ここでは、Bonoboの詳細には触れずに、各種"アプレット"の動作を見ていきます。これはBonoboを使う場合でもアプレット自体は通常のGTK+アプリケーションと同じように書くことができるからです。このことの詳細については[3]などを参照してください。

gnome-panel内のアプレット[編集]
時計アプレット[編集]

時計アプレットはその名の通りw:時計を表示するアプレットです。このアプレットはgnome-panelの./applets/clock以下に含まれています。時計アプレットの仕事はおおよそGTK+を使って時計を作成することです。簡単な時計の作り方については例えばXプログラミングを参照してください。

Gnome panel clock applet.png

(赤線は筆者が導入した)基本的に時計アプレットの本体は時刻の数値をテキストとして書き込まれたGtkLabelです。GtkLabelは既にGtkFixedの中で用いたのでここでは説明しません。対応するGtkLabelは./applets/clock/clock.c内のcreate_clock_widget関数中で作られています。時刻の書き換えはclock_timeout_callback中で呼ばれるupdate_clockで行われます。この間数はgtk_label_set_textを用いてGtkLabel内の数値を変えた後、gtk_widget_queue_resize関数を呼びます。この関数はGtkWidget及びそれを継承したウィジェットに対してその変更を画面に反映するために呼ばれます。同種の関数にgtk_widget_queue_draw(_area)がありますが、gtk_widget_queue_resizeは変更によってウィジェットのサイズが変わる場合に呼ばれます[4]。一方、gtk_widget_queue_drawはウィジェットのサイズを変えません。

追加の機能として、時計アプレットは24時間表示と12時間表示を切り替えたり、カレンダーを表示したりといくつかの機能があります。前者はGtkLabelのフォーマットを変更するだけで書き換えられますが、後者は多くの操作が必要となります。実際にはカレンダーはGtkCalendarとしてGTK+のウィジェットが与えられているため、時計アプレット内ではそれが用いられています。GtkCalendarについてはGTK+のソースを参照してください。

また、時計アプレットはロケールを変更してgnome-panelを起動すると表示が変化します。次の例はロケールをen_USに変更した例です。ただし、シェルとしてw:bashを用いています。

$LANG=en_US gnome-panel
Gnome panel clock applet en US.png

(赤線は筆者が導入した)

ロケールの変更による時刻のフォーマットの変更は、gettextライブラリによって行われます。gettextの詳細はOSS開発ツールを参照してください。実際のpoディレクトリは./po/以下で与えられます。この中では各国語でのフォーマットが文字列の形で定義されています。

wnckアプレット[編集]

wnckアプレット(wnck-applet)は、"libwnck"を用いるアプレット群で、GNOMEデスクトップのウィンドウの管理を行います。このアプレット群は複数のアプレットを含んでおり、これらはそれぞれ"デスクトップの表示"(ShowDesktop), "ウィンドウ一覧"(WindowList), "ウィンドウセレクタ"(WindowMenu), "ワークスペース切替器"(WorkspaceSwitcher)が含まれます。既にアプレットの例でwnck-appletが起動されている場面を見ました。これらはここで与えられる複数のアプレットに対応するプロセスです。

ここで、それぞれのアプレットの機能を簡単に紹介します。"デスクトップの表示"は全てのウィンドウを最小化し、デスクトップを表示します。実はデスクトップは後に述べるw:Nautilusの画面なのですがここでは触れません。ウィンドウの大きさを変更する機能はウィンドウマネージャの機能であるため、対応するウィンドウマネージャがlibwnckの要求を受けない場合には、このアプレットは機能しません。実際twmを用いて"デスクトップの表示"を動かしたところ、エラーメッセージが表示されました。

次に"ウィンドウ一覧"と"ウィンドウセレクタ"はどちらもその時点で存在するウィンドウを選択するためのアプレットです。ただし、"ウィンドウセレクタ"はこれをWnckSelectorとして与え、"ウィンドウ一覧"はWnckTasklistとして与えます。

実行例

"ウィンドウ一覧"はよく用いられるアプレットで、既に意識せずに使っているかも知れません。こちらもtwmで管理されるウィンドウは表示されません。

"ワークスペース切替器"は何枚もの画面(ワークスペース)があるように見せ、それらを切り替えながら使うことで画面を広く使うアプレットです。こちらもtwmと同時には使えません。


通知スペース(NotificationArea)アプレット[編集]
このページ「GNOMEフレームワーク」は、書きかけです。加筆・訂正など、協力いただける皆様の編集を心からお待ちしております。また、ご意見などがありましたら、お気軽にノートへどうぞ。
gnome-applets内のアプレット[編集]

gnome-appletsにもいくつかのアプレットが含まれています。ここでは比較的動作がわかりやすいアプレットを選んで紹介します。具体的には"CPU周波数"(cpufreq)アプレットと"音量調節"(mixer)アプレットを扱います。

cpufreqアプレットは使っているw:コンピュータw:クロック周波数を表示するアプレットです。クロック周波数はCPUの動作速度を表す指標で、基本的にはこの数値が大きい程速いCPUであるといえます。ただし、コンピュータを使う際の体感速度は、w:メモリの量などCPU以外の条件にもよるので、この数字だけでコンピュータの性能が決まるわけではありません。

Linux上では、使っているCPUの周波数は"ファイル"として利用者から利用できるようになっています。ただし、この値を変更してもハードウェアが変更されるわけではなく、この機能はシステムの状態を把握することを目的とした機能です。CPU周波数の情報は/proc/cpuinfo、もしくは/sys以下のディレクトリに記録されています。cpufreqアプレットはこれらの値を読み出して表示します。