Hello again.

So I am creating an app that would let users to select time in seconds, and display a gtk.Spinner for the given time period. The button that triggers the spinner (in the code, trigger) is also supposed to show a countdown in the button label.

Problem is, the timeout is way too inaccurate. What's causing this inaccuracy and how can I fix it?

    import gio.Application : GioApp = Application;
    import gtk.Application : Application;
    import gtkc.giotypes : GApplicationFlags;

    auto app = new Application("org.gitlab.radagast.spinner", GApplicationFlags.FLAGS_NONE);
    app.addOnActivate(delegate void(GioApp _) {
        import gtk.ApplicationWindow : ApplicationWindow;

        auto aw = new ApplicationWindow(app);
        scope (success)
            aw.showAll();

        aw.setDefaultSize(320, 200);
        aw.setBorderWidth(40);
        aw.setTitle("Spinner Demo");

        import gtk.Box : Box;
        import gtkc.gtktypes : GtkOrientation;

        auto vbox = new Box(GtkOrientation.VERTICAL, 10);
        scope (success)
            aw.add(vbox);

        import gtk.Spinner : Spinner;

        auto spinner = new Spinner();
        vbox.packStart(spinner, true, true, 0);

        auto hbox = new Box(GtkOrientation.HORIZONTAL, 10);
        scope (success)
            vbox.packStart(hbox, false, true, 0);

        import gtk.SpinButton : SpinButton;
        import gtkc.gtktypes : SpinButtonUpdatePolicy;

        auto spinButton = new SpinButton(0, 50, 1);
        spinButton.setNumeric(true);
        spinButton.setUpdatePolicy(SpinButtonUpdatePolicy.IF_VALID);
        hbox.packStart(spinButton, true, true, 0);

        import gtk.Button : Button;

        auto trigger = new Button("Start");
        trigger.addOnClicked(delegate void(Button _) {
            // retrieve the time
            auto time = spinButton.getValueAsInt();
            // set the button and the spinbutton insensitive
            spinButton.setSensitive(false);
            trigger.setSensitive(false);
            // start the spinner
            spinner.start();
            // stop the spinner after the given time

            import glib.Timeout : Timeout;
            import gtkc.gtktypes : GPriority;

            //Timeout(bool delegate() dlg, uint seconds, bool fireNow = false)
            auto timeout = new Timeout(delegate bool() {
                static int s;
                s++;
                if (s >= time) {
                    s = 0;
                    // stop the spinner
                    spinner.stop();
                    // hide the spinner
                    //spinner.setVisible(false);
                    // make the button and the spinbutton sensitive again
                    spinButton.setSensitive(true);
                    trigger.setLabel("Start");
                    trigger.setSensitive(true);
                    return false;
                }
                else {
                    import std.format : format;

                    trigger.setLabel(format("Start (%s)", time - s));
                    return true;
                }
            }, time, GPriority.HIGH);
        });
        hbox.packStart(trigger, true, true, 0);
    });
    return app.run(args);
}