summaryrefslogtreecommitdiff
path: root/src/protocols/TearingControl.cpp
blob: f3c17bfb24b25f98a899592ce2a454944631bc75 (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
#include "TearingControl.hpp"
#include "tearing-control-v1-protocol.h"
#include "../managers/ProtocolManager.hpp"
#include "../desktop/Window.hpp"
#include "../Compositor.hpp"

static void destroyManager(wl_client* client, wl_resource* resource) {
    RESOURCE_OR_BAIL(PRESOURCE);
    reinterpret_cast<CTearingControlProtocol*>(PRESOURCE->data())->onManagerResourceDestroy(resource);
}

static void getTearingControl(wl_client* client, wl_resource* resource, uint32_t id, wl_resource* surface) {
    RESOURCE_OR_BAIL(PRESOURCE);
    reinterpret_cast<CTearingControlProtocol*>(PRESOURCE->data())->onGetController(client, resource, id, wlr_surface_from_resource(surface));
}

//

CTearingControlProtocol::CTearingControlProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
    g_pHookSystem->hookDynamic("destroyWindow", [this](void* self, SCallbackInfo& info, std::any param) { this->onWindowDestroy(std::any_cast<CWindow*>(param)); });
}

static const struct wp_tearing_control_manager_v1_interface MANAGER_IMPL = {
    .destroy             = ::destroyManager,
    .get_tearing_control = ::getTearingControl,
};

void CTearingControlProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
    const auto RESOURCE = m_vManagers.emplace_back(std::make_unique<CWaylandResource>(client, &wp_tearing_control_manager_v1_interface, ver, id)).get();

    if (!RESOURCE->good()) {
        Debug::log(LOG, "Couldn't bind TearingControlMgr");
        return;
    }

    RESOURCE->setImplementation(&MANAGER_IMPL, nullptr);
    RESOURCE->setData(this);
}

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

void CTearingControlProtocol::onGetController(wl_client* client, wl_resource* resource, uint32_t id, wlr_surface* surf) {
    const auto CONTROLLER = m_vTearingControllers
                                .emplace_back(std::make_unique<CTearingControl>(
                                    std::make_shared<CWaylandResource>(client, &wp_tearing_control_v1_interface, wl_resource_get_version(resource), id), surf))
                                .get();

    if (!CONTROLLER->good()) {
        m_vTearingControllers.pop_back();
        return;
    }
}

void CTearingControlProtocol::onControllerDestroy(CTearingControl* control) {
    std::erase_if(m_vTearingControllers, [control](const auto& other) { return other.get() == control; });
}

void CTearingControlProtocol::onWindowDestroy(CWindow* pWindow) {
    for (auto& c : m_vTearingControllers) {
        if (c->pWindow == pWindow)
            c->pWindow = nullptr;
    }
}

//

static void destroyController(wl_client* client, wl_resource* resource) {
    RESOURCE_OR_BAIL(PRESOURCE);
    PROTO::tearing->onControllerDestroy(reinterpret_cast<CTearingControl*>(PRESOURCE->data()));
}

static void setPresentationHint(wl_client* client, wl_resource* resource, uint32_t hint) {
    RESOURCE_OR_BAIL(PRESOURCE);
    reinterpret_cast<CTearingControl*>(PRESOURCE->data())->onHint(hint);
}

static const struct wp_tearing_control_v1_interface CONTROLLER_IMPL = {
    .set_presentation_hint = ::setPresentationHint,
    .destroy               = ::destroyController,
};

CTearingControl::CTearingControl(SP<CWaylandResource> resource_, wlr_surface* surf_) : resource(resource_) {
    resource->setImplementation(&CONTROLLER_IMPL, nullptr);
    resource->setData(this);
    resource->setOnDestroyHandler([](CWaylandResource* res) { PROTO::tearing->onControllerDestroy(reinterpret_cast<CTearingControl*>(res->data())); });

    for (auto& w : g_pCompositor->m_vWindows) {
        if (w->m_pWLSurface.wlr() == surf_) {
            pWindow = w.get();
            break;
        }
    }
}

void CTearingControl::onHint(uint32_t hint_) {
    hint = hint_ == WP_TEARING_CONTROL_V1_PRESENTATION_HINT_VSYNC ? TEARING_VSYNC : TEARING_ASYNC;
    updateWindow();
}

void CTearingControl::updateWindow() {
    if (!pWindow)
        return;

    pWindow->m_bTearingHint = hint == TEARING_ASYNC;
}

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