Gnome Overlays
Gnome how to detect mouse events in an overlay window?
I recently wrote this posting about cross platform overlay windows:
My current Gnome implementation works, but with the following cavet: All mouse event are transparent to the window. That is, if the user presses a mouse button while over my overlay, the mouse press goes through my window and whatever is beneath it receives the mouse press. I am using a gtk_window_new(GTK_WINDOW_POPUP) as my overlay window class.
I'd like to revise my implementation such that mouse events are optionally captured by my window, but only when the pixel under the mouse is not transparent.
How can I do this with Gnome? On windows I can use the WM_HITTEST message, examine the pixel at the cursor position, and return HTTRANSPARENT to pass mouse events to the window below if the pixel is transparent. As an aside, I can also return HTCAPTION to allow the window to be dragged.
Whatever the solution is, I do not want my overlay to be activated or receive keyboard focus when a mouse button is pressed while inside my overlay window. I just want the option for mouse events to be gobbled by my overlay window (or perhaps processed by a mouse events callback for overlay) and not to always travel through it to whatever window is beneath the overlay.
procedure SplashScreenChanged(widget: PGtkWidget; old_screen: PGdkScreen; userdata: GPointer); cdecl; var Screen: PGdkScreen; Colormap: PGdkColormap; begin Screen := gtk_widget_get_screen(widget); Colormap := gdk_screen_get_rgba_colormap(Screen); gtk_widget_set_colormap(widget, Colormap); end; procedure Clip(Splash: TSplashCairo; Widget: PGtkWidget); var Window: PGdkWindow; Bitmap: PGdkBitmap; Bits: Integer; begin if Splash.FClipped then Exit; Splash.FClipped := True; Window := gtk_widget_get_window(Widget); Bits := 0; Bitmap := gdk_bitmap_create_from_data(Widget.window, Pointer(@Bits), 1, 1); gdk_window_input_shape_combine_mask(Window, Bitmap, 0, 0); g_object_unref(Bitmap); end; function SplashExpose(widget: PGtkWidget; event: PGdkEventExpose; userdata: GPointer): GBoolean; cdecl; var Splash: TSplashCairo absolute userdata; BitmapSurface: TBitmapSurfaceCairo; Surface: PCairoSurface; Pattern: PCairoPattern; Dest: PCairo; begin Clip(Splash, widget); BitmapSurface := Splash.FBitmap.Surface as TBitmapSurfaceCairo; if BitmapSurface.HandleAvailable then begin Surface := cairo_get_target(BitmapSurface.FCairo); Pattern := cairo_pattern_create_for_surface(Surface); Dest := gdk_cairo_create(widget.window); cairo_set_operator(Dest, CAIRO_OPERATOR_SOURCE); cairo_set_source(Dest, Pattern); cairo_paint(Dest); cairo_destroy(Dest); cairo_pattern_destroy(Pattern); end; end; constructor TSplashCairo.Create; begin inherited Create; FBitmap := TBitmapCairo.Create; FOpacity := $FF; FWidget := gtk_window_new(GTK_WINDOW_POPUP); gtk_widget_set_app_paintable(FWidget, True); g_signal_connect(G_OBJECT(FWidget), 'expose-event', G_CALLBACK(@SplashExpose), Pointer(Self)); g_signal_connect(G_OBJECT(FWidget), 'screen-changed', G_CALLBACK(@SplashScreenChanged), nil); SplashScreenChanged(FWidget, nil, nil); end; destructor TSplashCairo.Destroy; begin gtk_widget_destroy(FWidget); inherited Destroy; end; function TSplashCairo.GetBitmap: IBitmap; begin Result := FBitmap; end; function TSplashCairo.GetOpacity: Byte; begin Result := FOpacity; end; procedure TSplashCairo.SetOpacity(Value: Byte); begin if Value <> FOpacity then gtk_window_set_opacity(GTK_WINDOW(FWidget), Value / $FF); FOpacity := Value; end; function TSplashCairo.GetVisible: Boolean; begin Result := FVisible; end; procedure TSplashCairo.SetVisible(Value: Boolean); begin Value := Value and (not FBitmap.Empty); if Value <> FVisible then begin FVisible := Value; if FVisible then begin gtk_window_resize(GTK_WINDOW(FWidget), FBitmap.Width, FBitmap.Height); gtk_widget_show_all(FWidget); end else gtk_widget_hide_all(FWidget); end; end; function TSplashCairo.GetHandle: THandle; begin Result := THandle(FWidget); end; procedure TSplashCairo.Move(X, Y: Integer); begin gtk_window_move(GTK_WINDOW(FWidget), X, Y); end; procedure TSplashCairo.Update; begin if FBitmap.Empty then SetVisible(False) else if FVisible then begin gtk_window_resize(GTK_WINDOW(FWidget), FBitmap.Width, FBitmap.Height); gtk_widget_queue_draw(FWidget); end; end; function NewSplashCairo: ISplash; begin Result := TSplashCairo.Create; end;