summaryrefslogtreecommitdiff
path: root/src/protocols/IdleNotify.cpp
blob: b80bf5c66189c4b401cc58b3b6e99c1d7f4edb8b (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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include "IdleNotify.hpp"
#include "../managers/eventLoop/EventLoopManager.hpp"

static int onTimer(SP<CEventLoopTimer> self, void* data) {

    const auto NOTIF = sc<CExtIdleNotification*>(data);

    NOTIF->onTimerFired();

    return 0;
}

CExtIdleNotification::CExtIdleNotification(SP<CExtIdleNotificationV1> resource_, uint32_t timeoutMs_, bool obeyInhibitors_) :
    m_resource(resource_), m_timeoutMs(timeoutMs_), m_obeyInhibitors(obeyInhibitors_) {
    if UNLIKELY (!resource_->resource())
        return;

    m_resource->setDestroy([this](CExtIdleNotificationV1* r) { PROTO::idle->destroyNotification(this); });
    m_resource->setOnDestroy([this](CExtIdleNotificationV1* r) { PROTO::idle->destroyNotification(this); });

    m_timer = makeShared<CEventLoopTimer>(std::nullopt, onTimer, this);
    g_pEventLoopManager->addTimer(m_timer);

    update();

    LOGM(Log::DEBUG, "Registered idle-notification for {}ms", timeoutMs_);
}

CExtIdleNotification::~CExtIdleNotification() {
    g_pEventLoopManager->removeTimer(m_timer);
    m_timer.reset();
}

bool CExtIdleNotification::good() {
    return m_resource->resource();
}

void CExtIdleNotification::update(uint32_t elapsedMs) {
    m_timer->updateTimeout(std::nullopt);

    if (elapsedMs == 0 && PROTO::idle->isInhibited && m_obeyInhibitors) {
        reset();
        return;
    }

    if (m_timeoutMs > elapsedMs) {
        reset();
        m_timer->updateTimeout(std::chrono::milliseconds(m_timeoutMs - elapsedMs));
    } else
        onTimerFired();
}

void CExtIdleNotification::update() {
    update(0);
}

void CExtIdleNotification::onTimerFired() {
    if (m_idled)
        return;

    m_resource->sendIdled();
    m_idled = true;
}

void CExtIdleNotification::reset() {
    if (!m_idled)
        return;

    m_resource->sendResumed();
    m_idled = false;
}

bool CExtIdleNotification::inhibitorsAreObeyed() const {
    return m_obeyInhibitors;
}

CIdleNotifyProtocol::CIdleNotifyProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
    ;
}

void CIdleNotifyProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
    const auto RESOURCE = m_managers.emplace_back(makeUnique<CExtIdleNotifierV1>(client, ver, id)).get();
    RESOURCE->setOnDestroy([this](CExtIdleNotifierV1* p) { this->onManagerResourceDestroy(p->resource()); });

    RESOURCE->setDestroy([this](CExtIdleNotifierV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); });
    RESOURCE->setGetIdleNotification(
        [this](CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat) { this->onGetNotification(pMgr, id, timeout, seat, true); });
    RESOURCE->setGetInputIdleNotification(
        [this](CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat) { this->onGetNotification(pMgr, id, timeout, seat, false); });
}

void CIdleNotifyProtocol::onManagerResourceDestroy(wl_resource* res) {
    std::erase_if(m_managers, [&](const auto& other) { return other->resource() == res; });
}

void CIdleNotifyProtocol::destroyNotification(CExtIdleNotification* notif) {
    std::erase_if(m_notifications, [&](const auto& other) { return other.get() == notif; });
}

void CIdleNotifyProtocol::onGetNotification(CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat, bool obeyInhibitors) {
    const auto CLIENT = pMgr->client();
    const auto RESOURCE =
        m_notifications.emplace_back(makeShared<CExtIdleNotification>(makeShared<CExtIdleNotificationV1>(CLIENT, pMgr->version(), id), timeout, obeyInhibitors)).get();

    if UNLIKELY (!RESOURCE->good()) {
        pMgr->noMemory();
        m_notifications.pop_back();
        return;
    }
}

void CIdleNotifyProtocol::onActivity() {
    for (auto const& n : m_notifications) {
        n->update();
    }
}

void CIdleNotifyProtocol::setInhibit(bool inhibited) {
    isInhibited = inhibited;
    for (auto const& n : m_notifications) {
        if (n->inhibitorsAreObeyed())
            n->update();
    }
}

void CIdleNotifyProtocol::setTimers(uint32_t elapsedMs) {
    for (auto const& n : m_notifications) {
        n->update(elapsedMs);
    }
}