Selection rectangle example in gtk4

Hi all.

Is there any example about drawing an interactive ‘selection rectangle’ in Gtk4?
I have a working one with Gtk3 but the drawing model has changed in Gtk4 (no more invalidating rectangles).

It would be good to have some example like this for a DrawingArea, so far all the examples I’ve seen draw something in the callback ‘draw_function’ but not in response to interaction of the user i.e. with the mouse.

Thanks!

I haven’t seen any examples that I could think of, but the GTK4 list widgets currently do this by creating a temporary widget with the css name “rubberband” and then resizing it based on drag events. See here: gtklistbase.c#L1504

Hi jfrancis,
Thanks for your response.

I was having a look at nautilus (https://github.com/GNOME/nautilus/blob/master/src/nautilus-selection-canvas-item.c), but it calls the eel (library?) for that purpose.

I still think that an example of this kind would be fabulous.

Nautilus still uses GTK3, and “libeel” is an internal library implementing a canvas.

Hi Emmanuele !

That’s what I wanted to say (I thought that libeel still uses Gtk3).

I remembered that gtk4-demos included a GtkDrawingArea demo with two split panes, one drawing content programatically (3 circles with a checkered pattern) and the other one allowing the user to draw freely with the mouse.

My use case mixes these two in one Drawing Area.
In it I draw some elements programatically (circles, rectangles, etc…) in its redrawing function with a timer but at the same time I would like that the user could select some of them via a rubberband rectangle.

In Gtk3 I got this working more or less via invalidating rectangles but in Gtk4 I get a lot of flickering as we have no more ‘invalid rectangles’, that’s why I was asking for an example about how to do it properly.

Thanks for all your work in Gtk.

I guess you want some “marching ants” look? But do you really need that? I do need such selections for my SDL GTK4 tool too, but I think it currently is not implemented. But in the Nim drawingarea.nim example it is implemented for GTK3, and it should work for GTK4 very similar. We use a semitransparent filled cairo rectangle, so you can select with the middle mouse button a region to zoom into this rectangle. I think its looks better than marching ants. And is very simple.

Hi Stefan!

Not marching ants, my Gtk3 solution uses the semitransparent filled cairo rectangle you mention.

In Gtk3 I invalidated this rectangle (the cairo one drawn by the user) but in Gtk4 I have to repaint all the DrawingArea contents and I get a lot of flickering.
Clearly I’m not doing it ok :frowning:
I’ll give a try to the example you mention.

Yes, then I think you may be doing it wrong. Cairo drawing can be slow if we repaint all for each frame, but there should be no flickering. Unfortunately my SDT GTK4 app redraws currently all when something changed, so that is not a helpful example for you. In a similar GTK3 app written in Ruby ten years ago I tried hard to clip drawing to only the changed areas, but that was very difficult and speed increase was not really big. Now with Nim drawing is really not that slow. Finally I may add smart clipping, but maybe I will switch to Blend2D before doing that. Blend2D should be a few times faster than Cairo.

For speeding up rendering in GTK4 you probably want to avoid Cairo if you can. To avoid flickering and unnecessary redraws you will want to cache the render nodes that you use. GtkWidgets will do this automatically for the whole widget but if using a custom widget you will have to manage this yourself if you want to avoid redrawing the whole widget.

The process can be simplified by turning things into widgets as in the code from the list view I showed, for a rectangular region you can easily just make an empty widget that has a border and background using CSS. Rectangular shapes can also be drawn manually by using gtk_snapshot_append_border and gtk_snapshot_append_color. That should be faster than using Cairo. But if you want more complex shapes then you will have to use Cairo or write your own GL shaders, or plug in some other GL-based renderer.

acorbi when you are using plain C or C++ you may really try to use Blend2d. That one is in active development. Unfortunately to use it from other languages, one has to create bindings first.

Hi Stefan!
Rust here, there are bindings in crates.io (2 years old…).

Meanwhile I’ll stick to cairo and try to follow your progress with Blend2d from Nim.
If I make any progress on this I’ll post on this thread.

1 Like

Blend2d is the best I have seen for a CPU based renderer. For GPU rendering I think the current focus is Skia. It has some Rust bindings too. Or Pathfinder for a pure Rust renderer, but I’m not sure if it’s still active. But if you have no strict performance requirements you can probably get away with using Cairo.

Thanks jfrancis!

Due to the simplicity of my drawings :slightly_smiling_face: my bottleneck is in the unknowing of gtk4 drawing/redrawing model and not in cairo itself.

I’ve just started to use gtk4 and I’ve to learn its ways of doing things. That’s why I try to search examples for things that are different that they were in gtk3.

But you told us that you are using the GtkDrawingArea, so the GTK drawing model should not matter that much for you. You have to know cairo and cairo clipping. Generally your drawing area is fully visible, so GTK should initiate a full redraw, but you can use cairo clipping to draw only parts. The Blend2d author recommends tiling instead of clipping. Tiling where the tiles are of multiple word size, and we redraw all the tiles which have changed. My feeling was, that cairo clipping with arbitrary rectangles is indeed not very fast. An important component is using backup surfaces, e.g. in my SDT app I store the background grid in a backup surface, which is only blitted into the drawingarea. So I have not to redraw the background grid when we move an object. Next step would be to make the background surface a bit larger than the drawing area, so for scrolling we can just blit the background with offset avoiding redraws. Unfortunately cairo is nearly dead, so we can not discuss this with cairo developers. There is a very new pure Nim lib available, see https://github.com/treeform/pixie, but I am not sure if that one can already compete with blend2d.

Just for reference: if you have your backup surface, you will probably want to store as a GdkMemoryTexture and then cache it as a render node using gsk_texture_node_new. That should ensure it only gets uploaded to the GPU once. But this will only work if using snapshots and the simple clipping available there. It should be fine for rendering a background but more complex content will probably still need cairo clipping or similar.

1 Like

Hi Stefan!

I used Gdk.Window.invalidate_rect , I’ll try to use cairo clipping in gtk4.

In my gtk4 I use a surface for the background, in this surface (the background) constantly appear circles, rectangles, etc… that I want the user to be able to select with the rubberband rectangle.

As far as I can tell, in your case the background is static and in my case is changing every some time-lapse (I use GLib.timeout_add) for this.

Thanks for the cairo clip tip, I’ll also give it a try.

Hi jfrancis!

Thanks for the GdkMemoryTexture tip, I’ll also have a look at it.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.