diff --git a/example/hyprland.conf b/example/hyprland.conf
index 72de4d5e6..46bc1a1b1 100644
--- a/example/hyprland.conf
+++ b/example/hyprland.conf
@@ -3,6 +3,8 @@
 #
 # Refer to the wiki for more information.
 
+monitor=,1280x720,0x0,0.5,1
+
 general {
     max_fps=240
     gaps_in=5
diff --git a/src/Compositor.hpp b/src/Compositor.hpp
index b2ec10a2c..149321ace 100644
--- a/src/Compositor.hpp
+++ b/src/Compositor.hpp
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <memory>
+#include <deque>
 
 #include "defines.hpp"
 #include "debug/Log.hpp"
@@ -8,6 +9,7 @@
 #include "config/ConfigManager.hpp"
 #include "ManagerThread.hpp"
 #include "input/InputManager.hpp"
+#include "helpers/Monitor.hpp"
 
 class CCompositor {
 public:
@@ -36,7 +38,9 @@ public:
 
     const char*             m_szWLDisplaySocket;
 
-    void            startCompositor();    
+    std::deque<SMonitor>    m_vMonitors;
+
+    void                    startCompositor(); 
 };
 
 
diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index eccad3411..47255651c 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -66,6 +66,52 @@ void CConfigManager::handleRawExec(const std::string& command, const std::string
     }
 }
 
+void CConfigManager::handleMonitor(const std::string& command, const std::string& args) {
+
+    // get the monitor config
+    SMonitorRule newrule;
+
+    std::string curitem = "";
+
+    std::string argZ = args;
+
+    auto nextItem = [&]() {
+        auto idx = argZ.find_first_of(',');
+
+        if (idx != std::string::npos) {
+            curitem = argZ.substr(0, idx);
+            argZ = argZ.substr(idx + 1);
+        } else {
+            argZ = "";
+            curitem = argZ;
+        }
+    };
+
+    nextItem();
+
+    newrule.name = curitem;
+
+    nextItem();
+
+    newrule.resolution.x = stoi(curitem.substr(0, curitem.find_first_of('x')));
+    newrule.resolution.y = stoi(curitem.substr(curitem.find_first_of('x') + 1));
+
+    nextItem();
+
+    newrule.offset.x = stoi(curitem.substr(0, curitem.find_first_of('x')));
+    newrule.offset.y = stoi(curitem.substr(curitem.find_first_of('x') + 1));
+
+    nextItem();
+
+    newrule.mfact = stof(curitem);
+
+    nextItem();
+
+    newrule.scale = stof(curitem);
+
+    m_dMonitorRules.push_back(newrule);
+}
+
 void CConfigManager::parseLine(std::string& line) {
     // first check if its not a comment
     const auto COMMENTSTART = line.find_first_of('#');
@@ -111,6 +157,9 @@ void CConfigManager::parseLine(std::string& line) {
             handleRawExec(COMMAND, VALUE);
             return;
         }
+    } else if (COMMAND == "monitor") {
+        handleMonitor(COMMAND, VALUE);
+        return;
     }
 
     configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE);
@@ -121,6 +170,8 @@ void CConfigManager::loadConfigLoadVars() {
     parseError = "";       // reset the error
     currentCategory = "";  // reset the category
 
+    m_dMonitorRules.clear();
+
     const char* const ENVHOME = getenv("HOME");
     const std::string CONFIGPATH = ENVHOME + (ISDEBUG ? (std::string) "/.config/hypr/hyprlandd.conf" : (std::string) "/.config/hypr/hyprland.conf");
 
@@ -199,3 +250,29 @@ float CConfigManager::getFloat(std::string v) {
 std::string CConfigManager::getString(std::string v) {
     return getConfigValueSafe(v).strValue;
 }
+
+SMonitorRule CConfigManager::getMonitorRuleFor(std::string name) {
+    SMonitorRule* found = nullptr;
+
+    for (auto& r : m_dMonitorRules) {
+        if (r.name == name) {
+            found = &r;
+            break;
+        }
+    }
+
+    if (found)
+        return *found;
+
+    for (auto& r : m_dMonitorRules) {
+        if (r.name == "") {
+            found = &r;
+            break;
+        }
+    }
+
+    if (found)
+        return *found;
+
+    return SMonitorRule{.name = "", .resolution = Vector2D(1280, 720), .offset = Vector2D(0, 0), .mfact = 0.5f, .scale = 1};
+}
\ No newline at end of file
diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp
index 5e58173a6..eda060447 100644
--- a/src/config/ConfigManager.hpp
+++ b/src/config/ConfigManager.hpp
@@ -5,6 +5,7 @@
 #include <unordered_map>
 #include "../defines.hpp"
 #include <vector>
+#include <deque>
 
 struct SConfigValue {
     int64_t intValue = -1;
@@ -12,6 +13,14 @@ struct SConfigValue {
     std::string strValue = "";
 };
 
+struct SMonitorRule {
+    std::string name = "";
+    Vector2D    resolution = Vector2D(1280,720);
+    Vector2D    offset = Vector2D(0,0);
+    float       mfact = 0.5;
+    float       scale = 1;
+};
+
 class CConfigManager {
 public:
     CConfigManager();
@@ -22,6 +31,8 @@ public:
     float               getFloat(std::string);
     std::string         getString(std::string);
 
+    SMonitorRule        getMonitorRuleFor(std::string);
+
 private:
     std::unordered_map<std::string, SConfigValue> configValues;
     time_t lastModifyTime = 0;  // for reloading the config if changed
@@ -32,12 +43,15 @@ private:
 
     bool isFirstLaunch = true;  // For exec-once
 
+    std::deque<SMonitorRule> m_dMonitorRules;
+
     // internal methods
     void                loadConfigLoadVars();
     SConfigValue        getConfigValueSafe(std::string);
     void                parseLine(std::string&);
     void                configSetValueSafe(const std::string&, const std::string&);
     void                handleRawExec(const std::string&, const std::string&);
+    void                handleMonitor(const std::string&, const std::string&);
 };
 
 inline std::unique_ptr<CConfigManager> g_pConfigManager;
\ No newline at end of file
diff --git a/src/events/Events.cpp b/src/events/Events.cpp
index a5b093f0f..8bdaa2321 100644
--- a/src/events/Events.cpp
+++ b/src/events/Events.cpp
@@ -1,11 +1,61 @@
 #include "Events.hpp"
 #include "../input/InputManager.hpp"
+#include "../Compositor.hpp"
 
 void Events::listener_activate(wl_listener* listener, void* data) {
     
 }
 
 void Events::listener_change(wl_listener* listener, void* data) {
+    // layout got changed, let's update monitors.
+    const auto CONFIG = wlr_output_configuration_v1_create();
+
+    const auto GEOMETRY = wlr_output_layout_get_box(g_pCompositor->m_sWLROutputLayout, NULL);
+}
+
+void Events::listener_newOutput(wl_listener* listener, void* data) {
+    // new monitor added, let's accomodate for that.
+    const auto OUTPUT = (wlr_output*)data;
+
+    SMonitor newMonitor;
+
+    wlr_output_init_render(OUTPUT, g_pCompositor->m_sWLRAllocator, g_pCompositor->m_sWLRRenderer);
+
+    // get monitor rule that matches
+    SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(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_set_mode(OUTPUT, wlr_output_preferred_mode(OUTPUT));
+    wlr_output_enable_adaptive_sync(OUTPUT, 1);
+
+    wl_signal_add(&OUTPUT->events.frame, &Events::listen_monitorFrame);
+    wl_signal_add(&OUTPUT->events.destroy, &Events::listen_monitorDestroy);
+
+    wlr_output_enable(OUTPUT, 1);
+    if (!wlr_output_commit(OUTPUT)) {
+        Debug::log(ERR, "Couldn't commit output named %s", OUTPUT->name);
+        return;
+    }
+
+    wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, OUTPUT, monitorRule.offset.x, monitorRule.offset.y);
+
+    // add new monitor to our internal arr
+    newMonitor.ID = g_pCompositor->m_vMonitors.size();
+    newMonitor.szName = OUTPUT->name;
+    newMonitor.vecPosition = monitorRule.offset;
+    newMonitor.vecSize = monitorRule.resolution;
+    
+    g_pCompositor->m_vMonitors.push_back(newMonitor);
+}
+
+void Events::listener_monitorFrame(wl_listener* listener, void* data) {
+
+}
+
+void Events::listener_monitorDestroy(wl_listener* listener, void* data) {
 
 }
 
@@ -41,10 +91,6 @@ void Events::listener_newLayerSurface(wl_listener* listener, void* data) {
     
 }
 
-void Events::listener_newOutput(wl_listener* listener, void* data) {
-
-}
-
 void Events::listener_newXDGSurface(wl_listener* listener, void* data) {
     
 }
diff --git a/src/events/Events.hpp b/src/events/Events.hpp
index 7bd24e605..ac77257ff 100644
--- a/src/events/Events.hpp
+++ b/src/events/Events.hpp
@@ -22,4 +22,7 @@ namespace Events {
 
     LISTENER(outputMgrApply);
     LISTENER(outputMgrTest);
+
+    LISTENER(monitorFrame);
+    LISTENER(monitorDestroy);
 };
\ No newline at end of file
diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp
new file mode 100644
index 000000000..6931db1e7
--- /dev/null
+++ b/src/helpers/Monitor.hpp
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "../defines.hpp"
+
+struct SMonitor {
+    Vector2D    vecPosition     = Vector2D(0,0);
+    Vector2D    vecSize         = Vector2D(0,0);
+
+    bool        primary         = false;
+
+    int         ID              = -1;
+
+    std::string szName          = "";
+
+    Vector2D    vecReservedTopLeft = Vector2D(0,0);
+    Vector2D    vecReservedBottomRight = Vector2D(0,0);
+};
\ No newline at end of file
diff --git a/src/input/InputManager.cpp b/src/input/InputManager.cpp
index 3140e22dc..4e0995933 100644
--- a/src/input/InputManager.cpp
+++ b/src/input/InputManager.cpp
@@ -14,4 +14,9 @@ void CInputManager::onMouseMoved(wlr_event_pointer_motion* e) {
 
         wlr_cursor_move(g_pCompositor->m_sWLRCursor, e->device, delta.floor().x, delta.floor().y);
     }
-}
\ No newline at end of file
+}
+
+void CInputManager::onMouseWarp(wlr_event_pointer_motion_absolute* e) {
+    wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, e->device, e->x, e->y);
+}
+
diff --git a/src/input/InputManager.hpp b/src/input/InputManager.hpp
index 38ec419a6..10492732f 100644
--- a/src/input/InputManager.hpp
+++ b/src/input/InputManager.hpp
@@ -6,7 +6,7 @@ class CInputManager {
 public:
 
     void            onMouseMoved(wlr_event_pointer_motion*);
-    void            onMouseButton(int);
+    void            onMouseWarp(wlr_event_pointer_motion_absolute*);
 
 private:
     Vector2D        m_vMouseCoords      = Vector2D(0,0);