summaryrefslogtreecommitdiff
path: root/src/helpers/Monitor.cpp
blob: 9e7f76c426be3909dc2ac06b44b557452872883d (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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#include "Monitor.hpp"

#include "../Compositor.hpp"

void CMonitor::onConnect(bool noRule) {
    // get monitor rule that matches
    SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name);

    hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this);
    hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this);

    // if it's disabled, disable and ignore
    if (monitorRule.disabled) {
        wlr_output_enable(output, 0);
        wlr_output_commit(output);

        hyprListener_monitorFrame.removeCallback();
        return;
    }

    if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) == g_pCompositor->m_vMonitors.end()){
        g_pCompositor->m_vMonitors.push_back(*m_pThisWrap);
    }
    
    m_bEnabled = true;

    ID = g_pCompositor->getNextAvailableMonitorID();
    szName = output->name;

    wlr_output_set_scale(output, monitorRule.scale);
    wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, monitorRule.scale);
    wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL);  // TODO: support other transforms

    wlr_output_enable_adaptive_sync(output, 1);

    // create it in the arr
    vecPosition = monitorRule.offset;
    vecSize = monitorRule.resolution;
    refreshRate = monitorRule.refreshRate;

    wlr_output_enable(output, 1);

    // TODO: this doesn't seem to set the X and Y correctly,
    // wlr_output_layout_output_coords returns invalid values, I think...
    wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, output, monitorRule.offset.x, monitorRule.offset.y);

    // set mode, also applies
    if (!noRule)
        g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);

    Debug::log(LOG, "Added new monitor with name %s at %i,%i with size %ix%i, pointer %x", output->name, (int)monitorRule.offset.x, (int)monitorRule.offset.y, (int)monitorRule.resolution.x, (int)monitorRule.resolution.y, output);

    damage = wlr_output_damage_create(output);

    // add a WLR workspace group
    if (!pWLRWorkspaceGroupHandle) {
        pWLRWorkspaceGroupHandle = wlr_ext_workspace_group_handle_v1_create(g_pCompositor->m_sWLREXTWorkspaceMgr);
    }
    
    wlr_ext_workspace_group_handle_v1_output_enter(pWLRWorkspaceGroupHandle, output);

    // Workspace
    std::string newDefaultWorkspaceName = "";
    auto WORKSPACEID = monitorRule.defaultWorkspace == "" ? g_pCompositor->m_vWorkspaces.size() + 1 : getWorkspaceIDFromString(monitorRule.defaultWorkspace, newDefaultWorkspaceName);

    if (WORKSPACEID == INT_MAX || WORKSPACEID == (long unsigned int)SPECIAL_WORKSPACE_ID) {
        WORKSPACEID = g_pCompositor->m_vWorkspaces.size() + 1;
        newDefaultWorkspaceName = std::to_string(WORKSPACEID);

        Debug::log(LOG, "Invalid workspace= directive name in monitor parsing, workspace name \"%s\" is invalid.", monitorRule.defaultWorkspace.c_str());
    }

    auto PNEWWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);

    Debug::log(LOG, "New monitor: WORKSPACEID %d, exists: %d", WORKSPACEID, (int)(PNEWWORKSPACE != nullptr));

    if (PNEWWORKSPACE) {
        // workspace exists, move it to the newly connected monitor
        g_pCompositor->moveWorkspaceToMonitor(PNEWWORKSPACE, this);
        activeWorkspace = PNEWWORKSPACE->m_iID;
        g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
        PNEWWORKSPACE->startAnim(true, true, true);
    } else {

        if (newDefaultWorkspaceName == "")
            newDefaultWorkspaceName = std::to_string(WORKSPACEID);

        PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(ID, newDefaultWorkspaceName)).get();

        // We are required to set the name here immediately
        wlr_ext_workspace_handle_v1_set_name(PNEWWORKSPACE->m_pWlrHandle, newDefaultWorkspaceName.c_str());

        PNEWWORKSPACE->m_iID = WORKSPACEID;
    }

    activeWorkspace = PNEWWORKSPACE->m_iID;
    scale = monitorRule.scale;

    forceFullFrames = 3;  // force 3 full frames to make sure there is no blinking due to double-buffering.

    g_pCompositor->deactivateAllWLRWorkspaces(PNEWWORKSPACE->m_pWlrHandle);
    PNEWWORKSPACE->setActive(true);
    //

    if (!g_pCompositor->m_pLastMonitor)  // set the last monitor if it isnt set yet
        g_pCompositor->m_pLastMonitor = this;

    g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName});
}

void CMonitor::onDisconnect() {
    // Cleanup everything. Move windows back, snap cursor, shit.
    CMonitor* BACKUPMON = nullptr;
    for (auto& m : g_pCompositor->m_vMonitors) {
        if (m.get() != this) {
            BACKUPMON = m.get();
            break;
        }
    }

    if (!BACKUPMON) {
        Debug::log(CRIT, "No monitors! Unplugged last! Exiting.");
        g_pCompositor->cleanup();
        return;
    }

    m_bEnabled = false;

    hyprListener_monitorFrame.removeCallback();

    const auto BACKUPWORKSPACE = BACKUPMON->activeWorkspace > 0 ? std::to_string(BACKUPMON->activeWorkspace) : "name:" + g_pCompositor->getWorkspaceByID(BACKUPMON->activeWorkspace)->m_szName;

    // snap cursor
    wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, BACKUPMON->vecPosition.x + BACKUPMON->vecTransformedSize.x / 2.f, BACKUPMON->vecPosition.y + BACKUPMON->vecTransformedSize.y / 2.f);

    // move workspaces
    std::deque<CWorkspace*> wspToMove;
    for (auto& w : g_pCompositor->m_vWorkspaces) {
        if (w->m_iMonitorID == ID) {
            wspToMove.push_back(w.get());
        }
    }

    for (auto& w : wspToMove) {
        g_pCompositor->moveWorkspaceToMonitor(w, BACKUPMON);
        w->startAnim(true, true, true);
    }

    activeWorkspace = -1;

    wlr_output_damage_destroy(damage);

    wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);

    wlr_output_enable(output, false);

    wlr_output_commit(output);

    g_pCompositor->m_vWorkspaces.erase(std::remove_if(g_pCompositor->m_vWorkspaces.begin(), g_pCompositor->m_vWorkspaces.end(), [&](std::unique_ptr<CWorkspace>& el) { return el->m_iMonitorID == ID; }));

    Debug::log(LOG, "Removed monitor %s!", szName.c_str());

    g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName});

    g_pCompositor->m_vMonitors.erase(std::remove_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](std::shared_ptr<CMonitor>& el) { return el.get() == this; }));
}