回归多进程下载模型
当GtkWindow绘制背景遇上Resize

GTK 2.20 中的input shape mask问题

Tiger Soldier posted @ 2010年4月28日 07:48 in 程序设计 with tags gtk , 5919 阅读

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上有什么改动,上面的代码要作什么改动才能正常工作呢?如果有朋友知道,请告诉我:)

 

Edward 说:
May 18, 2010 12:14:24 AM

Thanks very much!!
这个问题我纠结了好久,终于解决了,我尝试过pixmap但是不起作用,我竟然没想到用GdkRegion,哈哈
顺便说下,OSDLyrics 是一个非常不错的项目

Head_small
Tiger Soldier 说:
May 18, 2010 03:14:33 AM

@Edward: 哈哈,我也从来没考虑过GdkRegion,还是多亏了Notify-OSD,这就是开源的力量呀


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter