Query_draw inside motion_event callback in X11 provoque big memory consumption with JavaScript

Hello:

I received a bug report in a program that uses motion_event to paint a rubber band selector: when the user moves the rubber band for a lot of time, the memory usage starts to rise very fast. Oddly enough, the bug only happens under X11, but not in Wayland. This is the original bug report: https://gitlab.com/rastersoft/desktop-icons-ng/issues/32

I did two proofs of concept (which I attach): one in javascript, and another one in Vala, to check if the problem was in Gtk, or in using Javascript. In Wayland, none of them triggers the bug (I moved the mouse for more than 3 minutes). Under X11, the Vala code also doesn’t trigger the bug (again, moved the mouse for 3 minutes), but the Javascript code does trigger it after about 37 seconds of moving the mouse. You can see it in this video: the memory consumption starts to grow at 0:37; when the mouse stops moving, the growth stops (there is a delay in the memory meter), and when the mouse moves again, the memory growth continues: https://youtu.be/oGRUOiBItlA).

I don’t know if this is a bug in Gtk, in Gdk-X11, in Javascript… But I would appreciate a fix or a workaround for it.

Code in Vala:

using Gtk;
using Cairo;
using Gdk;

Gtk.Window window;

double r = 0;
double g = 0;
double b = 0;
double delta = 0.01;

bool do_redraw(Gtk.Widget w, Cairo.Context cr) {
    var color = Gdk.RGBA();
    color.red = r;
    color.green = g;
    color.blue = b;
    color.alpha = 1;
    r += delta;
    if (r >= 1) {
        r = 0;
        g += delta;
        if (g >= 1) {
            g = 0;
            b += delta;
            if (b >= 1) {
                b = 0;
            }
        }
    }
    Gdk.cairo_set_source_rgba(cr, color);
    cr.paint();
    return false;
}

bool do_motion(Gdk.EventMotion event) {
    window.queue_draw();
    return false;
}

int main(string[] argv) {

    Gtk.init(ref argv);
    window = new Gtk.Window();
    window.set_app_paintable(true);
    window.draw.connect(do_redraw);
    window.add_events(Gdk.EventMask.POINTER_MOTION_MASK |
                      Gdk.EventMask.BUTTON_PRESS_MASK |
                      Gdk.EventMask.BUTTON_RELEASE_MASK |
                      Gdk.EventMask.KEY_RELEASE_MASK);
    window.motion_notify_event.connect(do_motion);
    window.show_all();
    Gtk.main();
    return 0;
}

Code in Javascript:

#!/usr/bin/env gjs

imports.gi.versions.Gtk = '3.0';
const Gtk = imports.gi.Gtk;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Gdk = imports.gi.Gdk;

let r = 0.0;
let g = 0.0;
let b = 0.0;
let delta = 0.01;
Gtk.init(null);
let window = new Gtk.Window();
let eventBox = new Gtk.EventBox({ visible: true });
//window.add(eventBox);
window.add_events(Gdk.EventMask.POINTER_MOTION_MASK |
                  Gdk.EventMask.BUTTON_PRESS_MASK |
                  Gdk.EventMask.BUTTON_RELEASE_MASK |
                  Gdk.EventMask.KEY_RELEASE_MASK);
window.set_app_paintable(true);
window.connect('draw', (widget, cr) => {
    // just do something
    Gdk.cairo_set_source_rgba(cr, new Gdk.RGBA({red: r, green: g, blue: b, alpha: 1.0}));
    cr.paint();
    r += delta;
    if (r >= 1) {
        r = 0;
        g += delta;
        if  (g >= 1) {
            g = 0;
            b += delta;
            if (b >= 1) {
                b = 0;
            }
        }
    }
    return false;
});

window.connect('motion-notify-event', (actor, event) => {
    window.queue_draw();
});

window.show_all();

Gtk.main();

Try adding cr.$dispose(); in the draw handler for your JavaScript example, e.g.

window.connect('draw', (widget, cr) => {
    // just do something
    Gdk.cairo_set_source_rgba(cr, new Gdk.RGBA({red: r, green: g, blue: b, alpha: 1.0}));
    cr.paint();
    r += delta;
    if (r >= 1) {
        r = 0;
        g += delta;
        if  (g >= 1) {
            g = 0;
            b += delta;
            if (b >= 1) {
                b = 0;
            }
        }
    }
    cr.$dispose();
    return false;
});

This should release the reference to the Cairo context.

1 Like

Seems to work. Thanks!!!

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