Emacs keybindings on Evolution3.

と言ってもメール・コンポーザ、いわゆる gtkhtml-4.0 を使った編集機能で Emacs 同様のキーバインディングを利用する方法だけれども、初めてうまく設定できた。もしかしたら自分だけかもしれないけど :o
今までのバージョンの Evoliution では gtkhtml-editor ライブラリで一応 Emacs のキーバインディングをサポートした実装がはいっており、デスクトップと統合されるようになってからは (org.gnome.desktop.interface.gtk-key-theme=”Emacs”)、別途メールコンポーザのメニュー項目にあるショートカットキーのうち、Emacs のキーバインディングで衝突するもの、例えば 「全て選択(A)」の Ctrl-A なんかを [Delete] キーを使って削除しておくだけでよいとずっと思っていた。
実際のところ、この設定だけでは全然足りなくて、それらしいキーワードを検索してたまたま見つけた情報をそのまま実施してみるとうまく使えるようになったんだけど。
一部古いところ (GConf は obsoleted) もあるので修正して紹介しておくと:

  1. デスクトップ設定の “/org/gnome/desktop/interface/can-change-accels” を ON にする:

    $ gsettings set org.gnome.desktop.interface can-change-accels true
    $ gsettings get org.gnome.desktop.interface can-change-accels
    true
    

  2. 同様に “/org/gnome/desktop/interface/gtk-key-theme” を ‘Emacs’ にする:

    $ gsettings set org.gnome.desktop.interface gtk-key-theme 'Emacs'
    $ gsettings get org.gnome.desktop.interface gtk-key-theme
    'Emacs'
    

  3. Evolutionを起動して [新規]-[メッセージ(M)] でメール・コンポーザを起動し、メニューを開いて、Emacs のキーバインディングと同じショーカットを持つメニュー項目の上にマウス・カーソルを載せてから [Delete] キーを押下するとキーバインディングが解除される。それから Evolution を一度閉じる
  4. そしてこのファイルをダウンロードして ${HOME}/.config/gtk-3.0/gtk.css として保存する
  5. それからコマンドラインから次のファイルの書き込みを禁止しておく

    $ chmod u-w ~/.gnome2/accels/evolution
    

  6. 最後に Evolution を起動し再びメール・コンポーザを開いて Emacs のキーバインディングを確認する

ということで、もうかれこれ10年くらい気になっていたのだけれど、やっとすっきりしたよ :D
See Also Emacs keybindings in GNOME Evolution 3.x: Evolution の3系で Emacs のキーバインディングを設定する方法

Removed the codeset of PANGO_RENDER_TYPE_X.

Pango のバージョン 1.31.x (公式版は 1.32.x) から X11 のフォントバックエンドのコードが完全に削除されてしまった。まぁ最低限でも freetype と xft のレンダリングを使っている今時のデスクトップ環境では不要ということでかなり前から予告はあったのだけれど:

$ git log 194b6ee552318ec6c494f34ed9f0979d0460fe4f -p
commit 194b6ee552318ec6c494f34ed9f0979d0460fe4f
Author: Behdad Esfahbod 
Date:   Thu Aug 16 21:48:50 2012 -0400
Remove PangoX
Been overdue...
diff --git a/Makefile.am b/Makefile.am
index b0b56ec..1ac018a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,13 +6,11 @@ EXTRA_DIST =                  \
autogen.sh              \
pango.pc.in             \
pangocairo.pc.in        \
-       pangox.pc.in            \
pangoxft.pc.in          \
pangoft2.pc.in          \
pangowin32.pc.in        \
pango-uninstalled.pc.in         \
pangocairo-uninstalled.pc.in    \
-       pangox-uninstalled.pc.in        \
pangoxft-uninstalled.pc.in      \
pangoft2-uninstalled.pc.in      \
pangowin32-uninstalled.pc.in    \
@@ -84,10 +82,6 @@ if HAVE_CAIRO
pkgconfig_DATA += pangocairo.pc
endif
-if HAVE_X
-pkgconfig_DATA += pangox.pc
-endif
-
if HAVE_XFT
pkgconfig_DATA += pangoxft.pc
endif
diff --git a/configure.in b/configure.in
index fc5a0f7..90ed3c4 100644
--- a/configure.in
+++ b/configure.in
@@ -225,21 +225,6 @@ AC_ARG_ENABLE(rebuilds,
AM_CONDITIONAL(CROSS_COMPILING, [test $cross_compiling = yes])
-have_x=false
-if test "x$pango_os_win32" != xyes; then
-  AC_PATH_XTRA
-
-  if test x$no_x = xyes ; then
-    AC_MSG_WARN([X development libraries not found])
-    have_x=false
-  else
-    X_LIBS="$X_LIBS -lX11"
-    have_x=true
-    AC_DEFINE(HAVE_X, 1, [Have X libraries])
-  fi
-fi
-AM_CONDITIONAL(HAVE_X, $have_x) 
(...SNIP...)

その一方で新しく導入されたのが OpenType のフリーなレンダリングの HarfBuzz。試しに今の GNOME 3.6 な環境に両ライブラリをビルド・インストールしてみたが特にレンダリングの方は問題はなかった。今の環境のフォント設定ははベクタだけでビットマップなんて使っていないので当然といえば当然だけれども。
但し弊害が無いわけではなくて、上記のコードが削除されたことで libpangox-1.0.so.0 というモジュール用ライブラリが無くなってしまうため、このライブラリと動的にリンクしているアプリは当然起動できない等の問題が発生する。
例えば、自分の環境だと GTK+ バージョン2系のアプリで ATOKX が使えなくなった。Justsystem が日本語入力システム ATOK X3 for Linux としてリリースしているバイナリはかなり古いバージョンのフレームワークでビルドされており、まさにこのモジュール用ライブラリを動的にリンクしていた:

$ ls -al /usr/lib/gtk-2.0/2.10.0/immodules/im-iiim.so
-rw-r--r-- 1 root root 103278 Nov 17 13:14 /usr/lib/gtk-2.0/2.10.0/immodules/im-iiim.so
$ ldd /usr/lib/gtk-2.0/2.10.0/immodules/im-iiim.so
linux-vdso.so.1 =>  (0x00007fff99fff000)
(...SNIP...)
libpangoxft-1.0.so.0 => /usr/lib/x86_64-linux-gnu/libpangoxft-1.0.so.0 (0x00007f44a5a87000)
libpangox-1.0.so.0 => not found
(...SNIP...)
$
$ gtk-demo
(gtk-demo:4567): Gtk-WARNING **: libpangox-1.0.so.0: cannot open shared object file: No such file or directory
(gtk-demo:4567): Gtk-WARNING **: Loading IM context type 'iiim' failed

その影響で google-chrome とか firefox3 とか OpenOffice で日本語が入力できなくなってしまった ;(
解決方法の一つはリビルドすること。Pango のXのバックエンドが廃止になると予告していたのはかなり前のバージョンからなので、最近の GTK+ バージョン2系のフレームワークであれば libpangox-1.0.so.0 は動的にリンクされない (正確には ${LIBDIR}/pkgconfig/pango*.pc を確認のこと)。
で、ATOKX ならば製品付属のソースから iiimcf 相当のモジュールをリビルドしてインストールしておけば回避できる。

$ sudo install -c -m644 .libs/im-iiim.so /usr/lib/gtk-2.0/2.10.0/immodules/im-iiim.so

ビルド方法は昔 GTK+ バージョン3系向けにブログした時の Wiki ページを参照のこと。

How to write GObject Introspection based Plugins (In Japanese).

優良な英語のドキュメントをガンガン翻訳していくシリーズ (?) の今回は、Lars Windolf 氏が自身のブログに投稿した「How to write GObject Introspection based Plugins」(2012年8月19日現在) の日本語訳です。
GObject イントロスペクションとプラグイン機能を提供するライブラリを使ってプラグインを実装していく手順を紹介しています。
氏は Liferea Feed Aggregator の開発者で、自分はメッセージ翻訳の協力で知り合いになりました。このたびは、氏が Google Plus に投稿していた記事を読んで、翻訳の許可をいただいた次第。何か誤訳や誤植があればこの投稿のコメントにどうぞ。


これは、GTK+ 3.0 のアプリケーション向けのプラグイン (ここでは Python のプラグイン) を作成する方法を簡単に紹介するものです。GTK+ 3.0 の主要な新しい機能の一つが GObject イントロスペクション (GObject Introspection) です。この技術を使えば、世にある全てのスクリプト言語からアプリケーションにランタイムでアクセスできるようになります。
この記事を投稿したきっかけは、Liferealibpeas ライブラリを使ったプラグインのサポート機能を追加しようとした時に、わずかなドキュメント (とはいえ、この時点では順をおって作業を進めていく方法を解説してくれた貴重なドキュメント) だけを頼りにちゃんと動作させるまでに三日も要してしまったことでした。ここでは、その際に得たノウハウをステップ毎に紹介しようと思います…
ステップ1. libpeas を使ってプラグインのエンジンを実装する
まず libpeas ライブラリとの統合では、たくさんのお決まりのコードを記述して初期化とプラグインのパスを登録します。ここでは、gtranslator というアプリケーションの gtr-plugins-engince.c というソースコードが実装の参考になりました。
そして最も重要なことは、peas_engine_add_search_path() 関数を使ってプラグインを格納するパスを登録することです:

peas_engine_add_search_path (PEAS_ENGINE (engine),
gtr_dirs_get_user_plugins_dir (),
gtr_dirs_get_user_plugins_dir ());
peas_engine_add_search_path (PEAS_ENGINE (engine),
gtr_dirs_get_gtr_plugins_dir (),
gtr_dirs_get_gtr_plugins_data_dir ());

アプリケーションを使うユーザが自分の権限で書き込みができる $HOME 配下のサブディレクトリと、パッケージのインストール時に作成する /usr/share/<アプリケーション名>/plugins/ といったディレクトリの二つをプラグイン・パスとして登録しておくと便利です。最後に、アプリケーションの初期化関数の中から、ここで記述したプラグインのエンジンが初期化されているか確認しておいて下さい。
ステップ2. libpeasgtk を使ってプラグインの設定ダイアログを実装する
さらに libpeas ライブラリにはユーザ・インタフェース用のライブラリが含まれており、プラグインの有効または無効を設定するユーザ・インタフェース (ノートブックのタブ) を自分のアプリケーションの設定ダイアログに追加することができるようになっています。次は Liferea の実装のスクリーンショットです:
libpeasgtk.png
ここでは “Plugins” というタブを自分の設定ダイアログに追加して、次のコードでプラグインの有効/無効を設定する画面を作成しています:

#include <libpeas-gtk/peas-gtk-plugin-manager.h>
[...]
/* ここで "plugins_box" が
* 既存のタブ型のコンテナ・ウィジェット (設定ダイアログ) と仮定します */
GtkWidget *alignment;
alignment = gtk_alignment_new (0., 0., 1., 1.);
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 12, 12, 12, 12);
widget = peas_gtk_plugin_manager_new (NULL);
gtk_container_add (GTK_CONTAINER (alignment), widget);
gtk_box_pack_start (GTK_BOX (plugins_box), alignment, TRUE, TRUE, 0);

この時点で、テストのために全てのプログラムを一度コンパイルしてみて下さい。libpeas ライブラリのプラグイン・マネージャを持つ新しい空っぽのタブが表示されますが、ウィジェットとしてはちゃんと動作するはずです。
ステップ3. Activatable なクラスを定義する
既にステップ1でプラグイン・ライブラリ (libpeas) を初期化しています。次は、自分のアプリケーションに Activatable なフック (いわゆるイベント・ハンドラ) をいくつか追加する必要があります。アプリケーションのコードの中で、これらのフックを利用して PeasExtensionSet というインタフェース型のインスタンスを一つ生成します (これは、このインタフェースを提供する全てのプラグインを表します)。
例えば前述の gtranslator にはプラグインのために GtrWindowActivable という型のインタフェースが用意されており、gtranslator のウィンドウが生成された時に、そのインタフェースで定義したフックを呼び出すようになっています。このインタフェース型の定義は次のとおりです:

struct _GtrWindowActivatableInterface
{
GTypeInterface g_iface;
/* public な仮想メソッド */
void (*activate) (GtrWindowActivatable * activatable);
void (*deactivate) (GtrWindowActivatable * activatable);
void (*update_state) (GtrWindowActivatable * activatable);
};

activate() と deactivate() というメソッドは、PeasExtensionSet 型のインスタンスから発行された “extension-added” または “extension-removed” というシグナルのハンドラからそれぞれ呼び出されるようにします。最後の update_state() メソッドは、gtranslator の場合、ユーザがプラグインを操作してその結果を反映させる時に呼び出されるようになっていました。
プラグインがたくさん必要ならばたくさんのメソッドを追加することになりますが、それぞれアプリケーションが発行するシグナルに接続することになるので、これといって特別なメソッドが必要になることはありません。そのため、Activatable なインタフェース型はシンプルな構造になっています。
では、どれくらい Activatable な実装を追加する必要があるのかというと: アプリケーションが一個のメイン・ウィンドウしか持たないという一番簡単なケースであれば、(例え、そのメイン・ウィンドウを使って全てのプラグインを初期化することになっても) そのメイン・ウィンドウと全てのプラグインに対して Activatable 型を一つ実装するだけです。
ステップ4. Activatable なクラスを実装してインスタンスを生成する
実際に Activatable なクラスを定義したり、実装したり、対応するクラスを使う必要はありません。インタフェース型の実装自身がたくさんのお決まりのコードを提供してくれるからです。GtrWindowActivatable 型を実装している gtr-window-activatable.c を確認してみて下さい。
この Activable なクラスのインスタンスは PeasExtensionSet に属すことになるので、次のような初期化が必要です (ちなみに gtranslator の場合、GtrWindowActivatable 型は GtrWindow クラスに属しています):

window->priv->extensions = peas_extension_set_new (PEAS_ENGINE (gtr_plugins_engine_get_default ()),
GTR_TYPE_WINDOW_ACTIVATABLE,
"window", window,
NULL);
g_signal_connect (window->priv->extensions,
"extension-added",
G_CALLBACK (extension_added),
window);
g_signal_connect (window->priv->extensions,
"extension-removed",
G_CALLBACK (extension_removed),
window);

PeasExtensionSet 型のインスタンスは、そのクラスのインタフェースを実装する全てのプラグインを表しており、選択したプラグインまたは全てのプラグインでメソッドを呼び出す際に使用します。PeasExtensionSet 型のインスタンスを生成した後に、”extension-added” というシグナルを使って全てのプラグインを初期化します:

peas_extension_set_foreach (window->priv->extensions,
(PeasExtensionSetForeachFunc) extension_added,
window);

登録するプラグインが一個以上あるかもしれないので、それらのプラグインを処理するための PeasExtensionSetForeachFunc 型のメソッドをそれぞれ実装しておく必要があります。この型のメソッドは上で実装したインタフェースを利用します。gtranslator の場合だと次のような実装になっていました:

static void
extension_added (PeasExtensionSet *extensions,
PeasPluginInfo   *info,
PeasExtension    *exten,
GtrWindow        *window)
{
gtr_window_activatable_activate (GTR_WINDOW_ACTIVATABLE (exten));
}

注記: libpeas のバージョン 1.1 までは、次のように、呼び出すインタフェースのメソッドの名前を引数にして、単に peas_extension_call() メソッドを呼び出すだけでよかったのですが…

peas_extension_call (extension, "activate");

それが終わったら次を実施して下さい:

  1. まず、アプリケーションの起動時に peas_extension_set_foreach() を使って、登録したプラグイン毎に “extension-added” というシグナルのハンドラを呼び出す
  2. “extension-added” または “extension-removed” というシグナルのハンドラを実装して、それぞれシグナルに接続しておく
  3. ステップ3で追加で定義したインタフェース型のメソッドに対して一個の PeasExtensionSetForeachFunc 型のメソッドを実装する
  4. インタフェース型のメソッドに対し、それぞれ peas_extension_set_foreach() を実行するメソッドを提供する

ステップ5. いくつかの API を公開する
ここまででプラグイン単体を作成する準備がほぼ整いました。但し、プラグインがこのビジネスロジックにアクセスできるようにするには、アプリケーションからいくつかの API を公開しておいた方がよいでしょう。
これは具体的には、関数やインタフェースやクラスの定義の中にマークアップを付与し、それらのソース・ファイルを引数にして g-ir-scanner を実行して、一個の GObject イントロスペクションのメタデータ (一個の .gir ファイルと一個の .typelib ファイルのペア) を生成するということです。
マークアップについて詳細はイントロスペクションの注釈ガイド (Annotation Guide) や他の類似のプロジェクトを参照してみて下さい。なおコンパイル中、不完全または文法が間違っている箇所があればそれらを g-ir-scanner が警告してくれます。
ステップ6. プラグインを作成する
プラグイン本体を作成する時は、常に二つのものを生成する必要があります:

  • プラグインに関する情報を記述した .plugin ファイル
  • プラグインを実装した実行形式またはスクリプト (を少なくとも一つ)

これらのファイルをそれぞれソース・ファイルの “plugins” ディレクトリに格納し、追加でインストールするターゲットにします。ここで、作成するプラグインを “myplugin.py” という Python スクリプトと仮定して話しを進めます。従って、このスクリプトの他に作成するのは、次の内容を記述した “myplugin.plugin” というファイルになります:

[Plugin]
Module=myplugin
Loader=python
IAge=2
Name=My Plugin
Description=My example plugin for testing only
Authors=Joe, Sue
Copyright=Copyright © 2012 Joe
Website=...
Help=...

ここで Python のプラグインの中で、次のような GObject イントロスペクションのリポジトリからパッケージをいくつかインポートしておきます:

from gi.repository import GObject
from gi.repository import Peas
from gi.repository import PeasGtk
from gi.repository import Gtk
from gi.repository import <あなたのパッケージ (アプリケーション) の接頭子>

GObject や Peas、PeasGtk、そして自分のアプリケーションからなるパッケージのインポートは必須です。その他プラグインで必要となるパッケージは任意でインポートして下さい。そして、通常であれば Gtk と相互にやりとりすることになるでしょう。
次に、ステップ3で定義したインタフェース型の全てのメソッドを使って簡単なクラスを実装しておきます:

class MyPlugin(GObject.Object, <あなたのパッケージ (アプリケーション) の接頭子>.<型>Activatable):
__gtype_name__ = 'MyPlugin'
object = GObject.property(type=GObject.Object)
def do_activate(self):
print "activate"
def do_deactivate(self):
print "deactivate"
def do_update_state(self):
print "updated state!"

必ず自分のアプリケーションからなるパッケージの接頭子を付与してから、妥当で Activatable なクラスの名前 (例えば GtkWindowActivatable) を指定して下さい。ここからメソッドの詳細を実装します。
その他:

  • お使いの言語バインディングで名前空間を分離する書式を使用することになるでしょう。例えば Python の場合はドット文字でクラスの継承を表す階層ツリーの各要素を分離しています。どのように記述するか分からない場合は inofficial online API を参照してみて下さい。
  • Activatable なクラスを初期化している最中に文法エラーが見つかった場合、libpeas ライブラリは設定ダイアログの中から問題のあったプラグインを無効にします。そのような場合は手動で有効にする必要があります。
  • 自分のプラグインを複数回、有効または無効にして初期化中の問題をデバッグできます。
  • “make install” で無限ループになるのを回避するために、ホーム・ディレクトリにプラグイン・エンジンのディレクトリを登録して、そこでプラグインをテストして下さい。

ステップ7. autotools でインストールのフックを設定する
もし、次に示すのと似たような Makefile.am を automake を使ってソース・ディレクトリの中に展開しようとしているのであれば

if HAVE_INTROSPECTION
-include $(INTROSPECTION_MAKEFILE)
INTROSPECTION_GIRS = Gtranslator-3.0.gir
Gtranslator-3.0.gir: gtranslator
INTROSPECTION_SCANNER_ARGS = -I$(top_srcdir) --warn-all --identifier-prefix=Gtr
Gtranslator_3_0_gir_NAMESPACE = Gtranslator
Gtranslator_3_0_gir_VERSION = 3.0
Gtranslator_3_0_gir_PROGRAM = $(builddir)/gtranslator
Gtranslator_3_0_gir_FILES = $(INST_H_FILES) $(libgtranslator_c_files)
Gtranslator_3_0_gir_INCLUDES = Gtk-3.0 GtkSource-3.0
girdir = $(datadir)/gtranslator/gir-1.0
gir_DATA = $(INTROSPECTION_GIRS)
typelibdir = $(libdir)/gtranslator/girepository-1.0
typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
CLEANFILES =	\
$(gir_DATA)	\
$(typelib_DATA)	\
$(BUILT_SOURCES) \
$(BUILT_SOURCES_PRIVATE)
endif

次の点を確認しておいて下さい:

  1. g-ir-scanner コマンドでスキャンしようとする全てのファイルを xxx_gir_FILES に渡す
  2. INTROSPECTION_SCANNER_ARGS–identifier-prefix=XXX (XXX はアプリケーションが持つ名前空間の接頭子) を渡す
  3. 一般的に使用する名前空間の接頭子が無い場合、INTROSPECTION_SCANNER_ARGS には –accept-unprefixed を追加する

次に、インストールするプラグインのターゲットを定義します:

plugindir = $(pkglibdir)/plugins
plugin_DATA = \
plugins/one_plugin.py \
plugins/one_plugin.plugin \
plugins/another_plugin.pl \
plugins/another_plugin.plugin

最後に、アプリケーションをビルドする際の依存関係と GIR のマクロを configure.ac に追加します:

pkg_modules="[...]
libpeas-1.0 >= 1.0.0
libpeas-gtk-1.0 >= 1.0.0"
GOBJECT_INTROSPECTION_CHECK([0.9.3])
GLIB_GSETTINGS

ステップ8. ビルドを試みる
“make” を実行して次を確認してみて下さい。

  1. 全てコンパイルできること
  2. g-ir-scanner から「ガミガミいわれないこと」(すなわち、たくさんのエラーや警告が出力されないこと)
  3. ソース・ディレクトリの中に .gir.typelib のファイルが生成されること

“make install” を実行して次を確認してみて下さい。

  1. .gir ファイルが <prefix>/share/<アプリケーション名>/gir-1.0/ 配下にインストールされること
  2. プラグインが <prefix>/lib/<アプリケーション名>/plugins/ 配下にインストールされること

アプリケーションを起動して次を確認してみて下さい。

  1. 初回にプラグイン設定ダイアログからプラグインを有効にできること
  2. 必要であれば、プラグインがまだ有効であるかどうかを確認する (初期化中に文法エラーなどで無効になる状態を確認できる)
  3. デバッグ文をプラグインにたくさん追加して、アプリケーションを起動したときに端末に出力されるログを監視する

以上です。もし間違いを見つけたりエラーに遭遇したらコメントにお願いします! このチュートリアルが多くの読者の助けになれば幸いです。

Embeddeding an icon path into .desktop file.

調べるのに時間がかかった割にはすぐにも忘れちゃいそうな些細なテクニック。
make 時にデスクトップ・ファイル (.desktop) の中に独自のアイコンパスを埋め込む (というか、置き換える) 方法。
最近の GTK+ 系アプリならばアイコンテーマに準拠したアイコンを自前で用意してインストールしておけば、ファイル名ではなく名前でアイコンを探す方法を .desktop ファイルでも利用できる。例えば、こんな感じで:

$ grep Icon /usr/share/applications/anjuta.desktop
Icon=anjuta
$ ls -1 /usr/share/icons/hicolor/*/*/anjuta.png
/usr/share/icons/hicolor/16x16/apps/anjuta.png
/usr/share/icons/hicolor/22x22/apps/anjuta.png
/usr/share/icons/hicolor/24x24/apps/anjuta.png
/usr/share/icons/hicolor/32x32/apps/anjuta.png
/usr/share/icons/hicolor/48x48/apps/anjuta.png

しかしながら、アイコン・セットを用意できない (したくない) 場合や独自のアイコン・ファイルを $(datadir) 配下の独自フォルダにインストールして、それを .desktop ファイルから参照する際は、そのアイコン・ファイルのパス名を指定しておく必要がある。例えば、こんな風に:

$ grep Icon /usr/share/applications/gip-ng.desktop
Icon=/usr/share/gip-ng/ui/gip.png

Makefile の中で sed コマンドを使った置き換えがてっとり早いけど、.desktop.in から intltool を使ってローカライズした結果も反映させたいので巧い方法がないか調べてみた:

  • make 中に自動で置き換えたい
  • @INTLTOOL_DESKTOP_RULE@ と衝突することなく連携させたい

後者は .desktop.in の段階で ja.po ファイルに従って日本語に展開されて .desktop ファイルが生成されるようになっているので、同様に .desktop.in を生成する際に Icon のエントリを sed などで文字列を置換するのが適当じゃないかと。
ということで、まずテンプレート (例: gip-ng.desktop.in.in) を作成しておく:

[Desktop Entry]
_Name=IP Address Calculator
_GenericName=IP Adress Calculator
_X-GNOME-FullName=gip IP Adress Calculator
_Comment=Calculate IP addresses and networks
Categories=GNOME;GTK;Utility;
Exec=gip-ng %U
Icon=@UIDIR@/gip.png                  <>
MimeType=application/x-gip;
StartupNotify=true
Terminal=false
Type=Application
X-GNOME-Bugzilla-Bugzilla=Mikeforce
X-GNOME-Bugzilla-Product=gip-ng
X-GNOME-Bugzilla-Component=utility
X-GNOME-Bugzilla-Version=@VERSION@    <>

このファイルの中にある置換文字を sed を使って妥当なデータで置き換えるために Makefile.am の記述を次のようにする:

NULL=
(中略)
## Icons for UI, Misc
uidir = $(pkgdatadir)/ui
(中略)
## Desktop File
gip-ng.desktop.in: gip-ng.desktop.in.in
@sed -e "s|@UIDIR@|${uidir}|g"                  \
-e "s|@VERSION[@]|${VERSION}|" $ $@
desktop_in_in_files = \ gip-ng.desktop.in.in \ $(NULL) desktop_in_files = \ gip-ng.desktop.in \ $(NULL) desktopdir = $(datadir)/applications desktop_DATA = \ gip-ng.desktop \ $(NULL)
@INTLTOOL_DESKTOP_RULE@ (中略)

みたとおりで、intltool に渡す一つ手前の段階でアイコンのパス名を埋め込むといった流れ。
ちなみに、置換せずにアイコン名だけで参照するならば上から5行目は不要。

moserial.

vala で書かれた GTK+ 3 対応のシリアル端末。ログ記録やファイル転送などの機能あり。シリアルの設定もファイルに保存しておける。でも minicom の方がいいか。
moserial-3.0.7-bbxM-20120723.png
一応、vala も i18n 対応なので、だいぶ前に日本語メッセージを commit しておいたけど、vala と gettext の実装はまだまだような気がする。
こんな風なファイルを用意して configure スクリプトで回収したこれらの情報を config.h 経由で参照するとか:

$ cat Config.vapi
[CCode (cprefix="", lower_case_cprefix="", cheader_filename="config.h")]
namespace Config
{
public const string VERSION;
public const string MOSERIAL_GLADEDIR;
public const string GETTEXT_PACKAGE;
public const string PACKAGE_DATADIR;
public const string PACKAGE_LOCALEDIR;
public const string PACKAGE_NAME;
public const string PACKAGE_VERSION;
}

これを main メソッドの中で gettext に渡すみたいな:

class moserial.Main : GLib.Object
{
(...)
public static int main (string[] args) {
(...)
Intl.bindtextdomain(Config.GETTEXT_PACKAGE, Config.PACKAGE_LOCALEDIR);
Intl.bind_textdomain_codeset(Config.GETTEXT_PACKAGE, "UTF-8");
Intl.textdomain(Config.GETTEXT_PACKAGE);
(...)
};
};

あとは Makefile.am でいろいろわたしてコンパイルする:

(...)
INCLUDES = -DMOSERIAL_GLADEDIR=\""$(gladedir)"\" \
-DPACKAGE_LOCALEDIR=\""$(datadir)/locale"\"
(...)
$(VALAC) -C -g --pkg Config --pkg dbus-glib-1 --pkg gee-1.0 --pkg gtk+-2.0 \
--vapidir $(top_srcdir)/src $^
(...)

むむ。