gtk3によるマウスカーソルの変更(落とし穴と解決策)

gtk3を導入してアプリケーションを書いています。
アプリケーション上で表示するマウスカーソルのアイコンを変更しようとして、落とし穴にはまったので、原因と解決策を紹介します。
(原因、というほど大げさなものではありませんが)

(画像にアイコンが無いのは単にgnome-screenshotの仕様)


現象としては、gdk_window_set_cursor()関数を呼んでも、マウスカーソルのアイコンが変更されず、機能しません。

出現するエラーメッセージは以下。
コマンドライン実行すると確認できます。
(PhotonVector.exe:19302): Gdk-CRITICAL **: gdk_window_set_cursor: assertion 'GDK_IS_WINDOW (window)' failed

で、原因ですが、
『gtk_widget_show() または gtk_widget_show_all()を呼ぶ前に、
マウスカーソル変更のgdk_window_set_cursor()を呼ぼうとすると、
引数に必要なGdkWindowを正常に取得できていないため、変更に失敗する』
ということのようです。

Sample Source

以下がサンプルソースです。
マウスカーソルのアイコン変更が機能することを確認できます。
落とし穴である不具合は、下のマウスカーソル指定をコメントアウトして、上のコメントアウトを解除すると再現を確認できるはずです。

任意の画像ファイル(透過png矢印画像)によるアイコン

環境はUbuntu15.10-amd64です。
なお、ライブラリ導入はこちら。
sudo apt-get install libgtk-3-dev -y
Makefileにしてしまったので、ビルドコマンドは記載できませんが、
pkg-config --libs --cflags gtk+-3.0
を絡めることになるかと。良いかんじに作ってください。

サンプルソースの動作が確認できれば、あとは任意のGdkCursorを生成することで、マウスカーソルを思い通りの画像に変更することができるはずです。

===
#include <gdk/gdk.h>
#include <gtk/gtk.h>

int main (int argc, char **argv){
    gtk_init(&argc, &argv);

    GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_widget_set_size_request (window, 300,200);

    g_signal_connect(window, "delete-event", G_CALLBACK(gtk_main_quit), NULL);

/*
    // ** error occurs (not work) use *set_cursor() before gtk_widget_show*()
    GdkWindow* win = gtk_widget_get_window(window);
    GdkCursor* cursor = gdk_cursor_new(GDK_PENCIL);
    gdk_window_set_cursor(win, cursor);
*/
    gtk_widget_show_all(window);

    GdkWindow* win = gtk_widget_get_window(window);
    GdkCursor* cursor = gdk_cursor_new(GDK_PENCIL);
    gdk_window_set_cursor(win, cursor);

    gtk_main();
return 0;
}

===

実際のアプリケーションでは以下のような感じで使っています。
====

 
GdkWindow *window = gtk_widget_get_parent_window(self->widget);
 
if(!window){
 
 
et_debug("GdkWindow not grub");
 
}else{
 
 
GdkCursor* cursor = gdk_cursor_new_from_pixbuf(
 
 
 
 
gdk_display_get_default(),
 
 
 
 
self->tools[tool_id]->icon_unfocus,
 
 
 
 
0,
 
 
 
 
0);
 
 
/*
 
 
GdkCursor* cursor = gdk_cursor_new_from_name(
 
 
 
 
gdk_display_get_default(),
 
 
 
 
"help");
 
 
*/
 
 
if(!cursor){
 
 
 
et_error("%d", tool_id);
 
 
}else{
 
 
 
gdk_window_set_cursor(window, cursor);
 
 
}
 
}

====

Linuxコマンドライン上でSVGベクタ画像をJPG等へラスタライズ変換する

 Linuxコマンドライン上でSVGベクタ画像をJPG等へラスタライズ変換することができるが、上手く変換されない場合がある。   以前作った魔法陣イラスト素材をイラスト素材ストックサイトへ登録しようと思い立ち、改めて素材用にラスタライズ変換をかけようとした。   ラスタライズ変換...