summaryrefslogtreecommitdiff
path: root/gjs/mainloop.cpp
blob: efe9d05aa0afe48b27c4590ddbb13f7f674604d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
// SPDX-FileCopyrightText: 2021 Evan Welsh <contact@evanwelsh.com>

#include <gio/gio.h>
#include <glib.h>

#include "gjs/context-private.h"
#include "gjs/mainloop.h"

namespace Gjs {

MainLoop::MainLoop() { m_refcount = 0; }

void MainLoop::ref() { m_refcount++; }

bool MainLoop::unref() {
    if (m_refcount == 0)
        return false;

    m_refcount--;
    return true;
}

void MainLoop::spin(GjsContext* context) {
    auto priv = GjsContextPrivate::from_object(context);

    // Check if System.exit() has been called.
    if (priv->should_exit(nullptr))
        return;

    GjsAutoPointer<GMainContext, GMainContext, g_main_context_unref>
        main_context(g_main_context_ref_thread_default());

    do {
        if (priv->should_exit(nullptr))
            break;

        // Allow the loop to block if the event loop is referenced.
        bool can_block = m_refcount > 0;
        // Only run the loop if there are pending jobs.
        if (g_main_context_pending(main_context))
            g_main_context_iteration(main_context, can_block);

        // Check if System.exit() has been called.
        if (priv->should_exit(nullptr))
            break;
    } while (
        // If there are pending sources or the job queue is not empty
        (m_refcount > 0 || !priv->empty()) &&
        // and System.exit() has not been called
        // continue spinning the event loop.
        !priv->should_exit(nullptr));
}
};  // namespace Gjs