アプリケーション上で表示するマウスカーソルのアイコンを変更しようとして、落とし穴にはまったので、原因と解決策を紹介します。
(原因、というほど大げさなものではありませんが)
(画像にアイコンが無いのは単に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);
}
}
====