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);
 
 
}
 
}

====

TIGORA(ティゴラ)のトレッキング シューズ

 TIGORA(ティゴラ)の トレッキング シューズを買いました。 メインの靴がアシックスウォーキングで街歩き用なのですが、これまではこれで高尾山などの軽い山も登っていました。 今回、靴底があまりに摩耗したこともあってアシックスウォーキングを買い替えたのですが、ついでに消耗が激...