如何在GDK 3中使用C语言创建可穿透鼠标事件的透明窗口?
如何在GDK 3中使用C语言创建可穿透鼠标事件的透明窗口?
看起来你想要的是一个完全不接收鼠标事件、内容透明的窗口,这样点击它的时候事件会直接传递给下方的应用(比如文本编辑器)。你的现有代码里有两个主要问题:一是用cairo画了黑色填充导致窗口内容不透明,二是设置的输入形状区域不符合需求——你只把左半部分设为可接收输入,但我们需要的是整个窗口都不接收输入。
关键解决思路
要实现这个需求,需要做好三件事:
- 让窗口支持RGBA透明度:必须给窗口设置带Alpha通道的视觉效果,否则透明设置不会生效。
- 绘制透明内容:替换不透明的黑色填充,保持窗口背景透明(或按需绘制半透明元素)。
- 禁用窗口的鼠标输入:告诉GDK这个窗口不接收任何鼠标事件,让事件直接穿透到下方窗口。
修改后的完整代码
#include <gtk/gtk.h> #include <cairo.h> static void on_destroy(GtkWidget *widget, gpointer data) { gtk_main_quit(); } static void on_realize(GtkWidget *widget, gpointer data) { GdkWindow *gdk_window = gtk_widget_get_window(widget); if (gdk_window) { // 核心:传入NULL区域,让整个窗口不接收任何鼠标事件 gdk_window_input_shape_combine_region(gdk_window, NULL, 0, 0); } } static gboolean on_draw(GtkWidget *widget, cairo_t *cr, gpointer data) { // 绘制完全透明的背景(alpha值0.0表示完全透明) cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_paint(cr); // 可选:如果你需要半透明的元素,比如30%不透明的红色矩形,可以取消下面的注释 // cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.3); // cairo_rectangle(cr, 50, 50, 300, 200); // cairo_fill(cr); return FALSE; } int main(int argc, char *argv[]) { GtkWidget *window; GdkVisual *visual; gtk_init(&argc, &argv); // 获取支持RGBA透明度的视觉效果 visual = gdk_screen_get_rgba_visual(gdk_screen_get_default()); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); // 给窗口设置RGBA视觉效果,这是透明生效的前提 if (visual != NULL) { gtk_widget_set_visual(window, visual); } // 设置窗口默认大小 gtk_window_set_default_size(GTK_WINDOW(window), 400, 300); // 可选:如果需要窗口始终显示在最上层,可以开启下面的设置 // gtk_window_set_keep_above(GTK_WINDOW(window), TRUE); g_signal_connect(window, "destroy", G_CALLBACK(on_destroy), NULL); g_signal_connect(window, "realize", G_CALLBACK(on_realize), NULL); g_signal_connect(window, "draw", G_CALLBACK(on_draw), NULL); gtk_widget_show_all(window); gtk_main(); return 0; }
关键修改点说明
- RGBA视觉效果:在
main函数中获取并设置支持Alpha通道的视觉效果,这是窗口能显示透明内容的必要条件。 - 透明绘制:用
draw信号替代你原来的cairo填充逻辑,通过cairo_set_source_rgba设置完全透明的背景,确保窗口本身是看不见的。 - 鼠标穿透设置:在
on_realize中把输入形状区域设为NULL,这会让GDK完全跳过这个窗口的鼠标事件处理,所有点击、移动事件都会直接传递给下方的应用。 - 移除了原代码中的黑色填充逻辑:这是导致窗口不透明的直接原因,现在替换为透明绘制。
如果之后你需要部分区域可交互、部分区域穿透,只需要把gdk_window_input_shape_combine_region的NULL换成你需要的可交互区域(比如一个圆形或矩形的cairo_region_t)即可。
备注:内容来源于stack exchange,提问作者SilverCube
相关产品推荐
相关产品推荐

