Yet another gdk3 clickthrough issue post

Naturally, the suggested combine input shape with empty rect did not work and gtk_widget_input_combine_region() did not help How to create a transparent window in GDK 3 that passes mouse events? . Same with gdk_window_set_pass_through() though gtk_overlay_set_overlay_pass_through is uhh not completely certain how adding an overlay would help with pass through (though as a newbie I cant be completely sure) https://stackoverflow.com/questions/79204687/how-to-create-a-transparent-window-in-gdk-3-that-passes-mouse-events-using-c

notably gdk_window_set_pass_through is not called twice gtk_widget_update_input_shape (GtkWidget *widget) doesnt seem like it should be able to do that anyways? (per gtk/gtkwidget.c · 3.24.43 · GNOME / gtk · GitLab) still not passing through tho

forgot to mention but tested on xfce (so it should exist on x11)

Hi,

the following code works for me (tested on X11 / Compiz, but should work generally). Note:

  • In my experience, directly calling `gdk_window_set_pass_through()` is not necessary.
  • With `gtk_widget_update_input_shape()` you should set the region that want input. So to get a “hole” (as in the case of my example), you have to subtract it from the whole window area.
#include <gtk/gtk.h>
#include <gdk/gdk.h>

static cairo_surface_t *surface = NULL;

static void _on_button_press(G_GNUC_UNUSED GtkWidget* pWidget, G_GNUC_UNUSED GdkEventButton* event, G_GNUC_UNUSED gpointer data) {
	fprintf(stderr,"button event\n");
}

static void _on_enter(G_GNUC_UNUSED GtkWidget* pWidget, G_GNUC_UNUSED GdkEvent* event, G_GNUC_UNUSED gpointer data) {
	fprintf(stderr,"enter event\n");
}

static void _on_leave(G_GNUC_UNUSED GtkWidget* pWidget, G_GNUC_UNUSED GdkEvent* event, G_GNUC_UNUSED gpointer data) {
	fprintf(stderr,"leave event\n");
}

static void _draw_realize(GtkWidget* pWidget, G_GNUC_UNUSED gpointer unused) {
	if(surface) cairo_surface_destroy(surface);
	surface = gdk_window_create_similar_surface(gtk_widget_get_window(pWidget),
		CAIRO_CONTENT_COLOR_ALPHA, gtk_widget_get_allocated_width(pWidget), gtk_widget_get_allocated_height(pWidget));
	
	cairo_t* cr = cairo_create(surface);
	cairo_set_source_rgb(cr, 1, 1, 1);
	cairo_paint(cr);
	cairo_move_to(cr, 100, 100);
	cairo_line_to(cr, 300, 100);
	cairo_line_to(cr, 300, 300);
	cairo_line_to(cr, 100, 300);
	cairo_close_path(cr);
	cairo_set_source_rgba(cr, 1, 1, 1, 0);
	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
	cairo_fill(cr);
	cairo_destroy(cr);
}

static void _on_realize(GtkWidget* pWidget, G_GNUC_UNUSED gpointer unused) {
	GdkWindow* win = gtk_widget_get_window(pWidget);
	GdkEventMask events = gdk_window_get_events(win);
	gdk_window_set_events(win, events | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
	_draw_realize(pWidget, NULL);
}

static gboolean _draw(G_GNUC_UNUSED GtkWidget* pWidget, cairo_t* cr, G_GNUC_UNUSED gpointer unused) {
	if(surface) {
		cairo_set_source_surface(cr, surface, 0, 0);
		cairo_paint(cr);
	}
	return TRUE;
}


int main(int argc, char **argv) {
	const int w = 500;
	const int h = 400;
	
	gtk_init(&argc, &argv);
	
	GtkWindow* win = (GtkWindow*)gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title(win, "GDK input shape test");
	gtk_window_set_default_size(win, w, h);
	gtk_widget_set_size_request(GTK_WIDGET(win), w, h);
	
	g_signal_connect(win, "delete-event", gtk_main_quit, NULL);
	g_signal_connect(win, "realize", G_CALLBACK(_on_realize), NULL);
    g_signal_connect(win, "button-press-event", G_CALLBACK(_on_button_press), NULL);
	g_signal_connect(win, "button-release-event", G_CALLBACK(_on_button_press), NULL);
	g_signal_connect(win, "enter-notify-event", G_CALLBACK(_on_enter), NULL);
	g_signal_connect(win, "leave-notify-event", G_CALLBACK(_on_leave), NULL);
	g_signal_connect(win, "draw", G_CALLBACK(_draw), NULL);
	
	GdkScreen* screen = gtk_window_get_screen(win);
	GdkVisual* visual = gdk_screen_get_rgba_visual(screen);
	if(visual) gtk_widget_set_visual(GTK_WIDGET(win), visual);
	gtk_widget_set_app_paintable(GTK_WIDGET(win), TRUE);
	
	cairo_rectangle_int_t rect1 = { .x = 0, .y = 0, .width = w, .height = h };
	cairo_rectangle_int_t rect2 = { .x = 100, .y = 100, .width = 200, .height = 200 };
	cairo_region_t* r = cairo_region_create_rectangle(&rect1);
	cairo_region_subtract_rectangle(r, &rect2);
	gtk_widget_input_shape_combine_region(GTK_WIDGET(win), r);
	cairo_region_destroy(r);

	gtk_widget_show_all(GTK_WIDGET(win));
	gtk_main();
	
	return 0;
}

huh, maybe a xfwm4 gdk/gtk thing then

oclock works somehow though so would this go in like…a bug report?