在OSD Lyrics中,我使用以下代码,来实现鼠标穿透功能:
gdk_drawable_get_size (osd->osd_window, &w, &h); GdkPixmap *input_mask = gdk_pixmap_new (NULL, w, h, 1); GdkGC *gc = gdk_gc_new (input_mask); GdkColor color; color.pixel = 0; /* black */ gdk_gc_set_foreground (gc, &color); gdk_draw_rectangle (input_mask, gc, TRUE, 0, 0, w, h); gdk_window_input_shape_combine_mask (osd->osd_window, input_mask, 0, 0); g_object_unref (input_mask); g_object_unref (gc);
简单来说,就是生成一个w*h的黑白pixmap,用绘制矩形的方法将它的所有像素置零,然后将它作为OSD窗口的input shape mask,使得在其上的所有鼠标事件都不会被OSD窗口捕捉。
这段代码在之前一直工作很正常,但是最近有人报告说穿透功能失效了。然而这项功能在我的Ubuntu 9.10上很正常,于是我怀疑是与Gnome 2.30自带的GTK 2.20有兼容性问题。
最近把系统升级到了10.04,GTK升级到了 2.20,果然问题出现了。无论color的pixel设为0还是1,都没法产生效果。进一步实验发现,如果去掉gdk_draw_rectangle一句,也就是生成pixmap后不绘制任何东西,那么input mask是可以生效的。一旦在上面绘制矩形,不论怎么绘制,绘制的部分都会没有穿透效果,也就是说,被绘制的部分成了有遮挡的标记。
但是不能直接把绘制矩形的部分去掉,因为在低版本的GTK中,gdk_pixmap_new返回的pixmap并不是所有像素都置零的,也就是mask是一个随机的效果,这也是为什么我在实现的时候要画个矩形。一个比较丑陋的解决方法就是判断GTK的版本,如果版本小于2.20,就绘制矩形,否则不绘制。这个方法很恶心,而且天知道新的GTK出来后会不会出问题,至少在文档中没有对gdk_pixmap_new返回的pixmap作任何保证。
后来想到notify-osd在lucid下鼠标穿透的功能依然正常,查看了它的代码,发现对input_shape部分进行了大幅地修改,参考之后代码修改为如下形式:
GdkRegion *region = gdk_region_new (); gdk_window_input_shape_combine_region (osd->osd_window, region, 0, 0); gdk_region_destroy (region);
就是创建一个空区域,然后将它作为input shape,因为是空区域,所以整个OSD窗口都是镂空的。
虽然问题解决了,但是还是不明白,为什么之前的方法在GTK 2.20上不能用了(应该说是在GDK 2.20上不能用了),2.20在input shape mask和pixmap上有什么改动,上面的代码要作什么改动才能正常工作呢?如果有朋友知道,请告诉我:)
May 18, 2010 12:14:24 AM
Thanks very much!!
这个问题我纠结了好久,终于解决了,我尝试过pixmap但是不起作用,我竟然没想到用GdkRegion,哈哈
顺便说下,OSDLyrics 是一个非常不错的项目
May 18, 2010 03:14:33 AM
@Edward: 哈哈,我也从来没考虑过GdkRegion,还是多亏了Notify-OSD,这就是开源的力量呀