initial commit, very simple and buggy prolly :)

This commit is contained in:
vaxerski 2021-11-18 18:04:09 +01:00
parent efb783c97c
commit 53a64d9574
18 changed files with 555 additions and 0 deletions

3
.gitignore vendored
View File

@ -9,3 +9,6 @@ install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps
build/
.vscode/

24
CMakeLists.txt Normal file
View File

@ -0,0 +1,24 @@
cmake_minimum_required(VERSION 3.4)
project(Hypr
VERSION 0.1
DESCRIPTION "A Modern OOP C++ Window Manager"
)
add_compile_options(-std=c++17)
file(GLOB_RECURSE SRCFILES "src/*.cpp")
add_executable(Hypr ${SRCFILES})
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
target_link_libraries(Hypr
xcb
xcb-ewmh
xcb-icccm
xcb-keysyms
xcb-randr
xcb-xinerama
)

View File

@ -1,2 +1,4 @@
# Hypr
Hypr is a tiling window manager written in modern OOP C++
I will make this readme better in the future cant be arsed to do it rn

10
src/KeybindManager.cpp Normal file
View File

@ -0,0 +1,10 @@
#include "KeybindManager.hpp"
Keybind* KeybindManager::findKeybindByKey(int mod, xcb_keysym_t keysym) {
for(auto& key : KeybindManager::keybinds) {
if (keysym == key.getKeysym() && mod == key.getMod()) {
return &key;
}
}
return nullptr;
}

11
src/KeybindManager.hpp Normal file
View File

@ -0,0 +1,11 @@
#include "utilities/Keybind.hpp"
#include <vector>
namespace KeybindManager {
std::vector<Keybind> keybinds;
// -- Methods -- //
Keybind* findKeybindByKey(int mod, xcb_keysym_t keysym);
};

24
src/defines.hpp Normal file
View File

@ -0,0 +1,24 @@
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcb_keysyms.h>
#include <string>
#include "./helpers/Vector.hpp"
#include "./utilities/Debug.hpp"
#define EXPOSED_MEMBER(var, type, prefix) \
private: \
type m_##prefix##var; \
public: \
type get##var() { return this->m_##prefix##var; } \
void set##var(type value) { this->m_##prefix##var = value; }
#define EVENT(name) \
void event##name(xcb_generic_event_t* event);
#define STICKS(a, b) abs(a - b) < 2

56
src/events/events.cpp Normal file
View File

@ -0,0 +1,56 @@
#include "events.hpp"
void Events::eventEnter(xcb_generic_event_t* event) {
const auto E = reinterpret_cast<xcb_enter_notify_event_t*>(event);
// Just focus it and update.
WindowManager::setFocusedWindow(E->event);
// vvv insallah no segfaults
WindowManager::getWindowFromDrawable(E->event)->setDirty(true);
}
void Events::eventDestroy(xcb_generic_event_t* event) {
const xcb_destroy_notify_event_t* E = reinterpret_cast<xcb_destroy_notify_event_t*>(event);
xcb_kill_client(WindowManager::DisplayConnection, E->window);
// fix last window
const auto CLOSEDWINDOW = WindowManager::getWindowFromDrawable(E->window);
if (CLOSEDWINDOW) {
WindowManager::fixWindowOnClose(CLOSEDWINDOW);
// delete off of the arr
WindowManager::removeWindowFromVectorSafe(E->window);
}
}
void Events::eventMapWindow(xcb_generic_event_t* event) {
const xcb_map_request_event_t* E = reinterpret_cast<xcb_map_request_event_t*>(event);
// Map the window
xcb_map_window(WindowManager::DisplayConnection, E->window);
// Do the setup of the window's params and stuf
CWindow window;
window.setDrawable(E->window);
window.setIsFloating(false);
window.setDirty(true);
// Also sets the old one
WindowManager::calculateNewWindowParams(&window);
// Focus
WindowManager::setFocusedWindow(E->window);
// Add to arr
WindowManager::addWindowToVectorSafe(window);
Debug::log(LOG, "Created a new window! X: " + std::to_string(window.getPosition().x) + ", Y: " + std::to_string(window.getPosition().y) + ", W: "
+ std::to_string(window.getSize().x) + ", H:" + std::to_string(window.getSize().y) + " ID: " + std::to_string(E->window));
// Set map values
WindowManager::Values[0] = XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_FOCUS_CHANGE;
xcb_change_window_attributes_checked(WindowManager::DisplayConnection, E->window, XCB_CW_EVENT_MASK, WindowManager::Values);
WindowManager::setFocusedWindow(E->window);
}

8
src/events/events.hpp Normal file
View File

@ -0,0 +1,8 @@
#include "../defines.hpp"
#include "../windowManager.hpp"
namespace Events {
EVENT(Enter);
EVENT(Destroy);
EVENT(MapWindow);
};

19
src/helpers/Vector.cpp Normal file
View File

@ -0,0 +1,19 @@
#include "Vector.hpp"
Vector2D::Vector2D(double xx, double yy) {
x = xx;
y = yy;
}
Vector2D::Vector2D() { x = 0; y = 0; }
Vector2D::~Vector2D() {}
double Vector2D::normalize() {
// get max abs
const auto max = abs(x) > abs(y) ? abs(x) : abs(y);
x /= max;
y /= max;
return max;
}

29
src/helpers/Vector.hpp Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include <math.h>
class Vector2D {
public:
Vector2D(double, double);
Vector2D();
~Vector2D();
double x = 0;
double y = 0;
// returns the scale
double normalize();
Vector2D operator+(Vector2D a) {
return Vector2D(this->x + a.x, this->y + a.y);
}
Vector2D operator-(Vector2D a) {
return Vector2D(this->x - a.x, this->y - a.y);
}
Vector2D operator*(float a) {
return Vector2D(this->x * a, this->y * a);
}
Vector2D operator/(float a) {
return Vector2D(this->x / a, this->y / a);
}
};

32
src/main.cpp Normal file
View File

@ -0,0 +1,32 @@
/*
Hypr Window Manager for X.
Started by Vaxry on 2021 / 11 / 17
*/
#include "windowManager.hpp"
int main(int argc, char** argv) {
Debug::log(LOG, "Hypr debug log. Built on " + std::string(__DATE__) + " at " + std::string(__TIME__));
WindowManager::DisplayConnection = xcb_connect(NULL, NULL);
if (const auto RET = xcb_connection_has_error(WindowManager::DisplayConnection); RET != 0) {
Debug::log(CRIT, "Connection Failed! Return: " + std::to_string(RET));
return RET;
}
WindowManager::Screen = xcb_setup_roots_iterator(xcb_get_setup(WindowManager::DisplayConnection)).data;
WindowManager::setupManager();
Debug::log(LOG, "Hypr Started!");
while (WindowManager::handleEvent()) {
;
}
Debug::log(LOG, "Hypr reached the end! Exiting...");
return 0;
}

26
src/utilities/Debug.cpp Normal file
View File

@ -0,0 +1,26 @@
#include "Debug.hpp"
void Debug::log(LogLevel level, std::string msg) {
switch (level)
{
case LOG:
msg = "[LOG] " + msg;
break;
case WARN:
msg = "[WARN] " + msg;
break;
case ERR:
msg = "[ERR] " + msg;
break;
case CRIT:
msg = "[CRITICAL] " + msg;
break;
default:
break;
}
printf((msg + "\n").c_str());
}

14
src/utilities/Debug.hpp Normal file
View File

@ -0,0 +1,14 @@
#pragma once
#include <string>
enum LogLevel {
NONE = -1,
LOG = 0,
WARN,
ERR,
CRIT
};
namespace Debug {
void log(LogLevel, std::string msg);
};

View File

@ -0,0 +1,9 @@
#include "../defines.hpp"
class Keybind {
EXPOSED_MEMBER(Mod, int, i);
EXPOSED_MEMBER(Keysym, xcb_keysym_t,);
EXPOSED_MEMBER(Command, std::string, sz);
EXPOSED_MEMBER(Dispatcher, void*, p);
};

4
src/window.cpp Normal file
View File

@ -0,0 +1,4 @@
#include "window.hpp"
CWindow::CWindow() { this->setDirty(true); }
CWindow::~CWindow() { }

29
src/window.hpp Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include "defines.hpp"
class CWindow {
public:
CWindow();
~CWindow();
void move(Vector2D dest);
void moveByDelta(Vector2D delta);
void resize(Vector2D size);
void resize(float percx, float percy);
std::string getName();
// Tells the window manager to reload the window's params
EXPOSED_MEMBER(Dirty, bool, b);
EXPOSED_MEMBER(Size, Vector2D, vec);
EXPOSED_MEMBER(Position, Vector2D, vec);
EXPOSED_MEMBER(IsFloating, bool, b);
EXPOSED_MEMBER(Drawable, xcb_drawable_t, i);
private:
};

226
src/windowManager.cpp Normal file
View File

@ -0,0 +1,226 @@
#include "windowManager.hpp"
#include "./events/events.hpp"
void WindowManager::setupManager() {
WindowManager::Values[0] = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE;
xcb_change_window_attributes_checked(WindowManager::DisplayConnection, WindowManager::Screen->root,
XCB_CW_EVENT_MASK, WindowManager::Values);
xcb_ungrab_key(WindowManager::DisplayConnection, XCB_GRAB_ANY, WindowManager::Screen->root, XCB_MOD_MASK_ANY);
/*int key_table_size = sizeof(keys) / sizeof(*keys);
for (int i = 0; i < key_table_size; ++i) {
xcb_keycode_t *keycode = xcb_get_keycodes(keys[i].keysym);
if (keycode != NULL) {
xcb_grab_key(WindowManager::DisplayConnection, 1, WindowManager::Screen->root, keys[i].mod, *keycode,
XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
}
}
xcb_flush(WindowManager::DisplayConnection);
xcb_grab_button(WindowManager::DisplayConnection, 0, WindowManager::Screen->root, XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_ASYNC, WindowManager::Screen->root, XCB_NONE, 1, MOD1);
xcb_grab_button(WindowManager::DisplayConnection, 0, WindowManager::Screen->root, XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_ASYNC, WindowManager::Screen->root, XCB_NONE, 3, MOD1);*/
xcb_flush(WindowManager::DisplayConnection);
}
bool WindowManager::handleEvent() {
if (xcb_connection_has_error(WindowManager::DisplayConnection))
return false;
xcb_generic_event_t* ev = xcb_wait_for_event(WindowManager::DisplayConnection);
if (ev != NULL) {
switch (ev->response_type & ~0x80) {
case XCB_ENTER_NOTIFY:
Events::eventEnter(ev);
Debug::log(LOG, "Event dispatched ENTER");
break;
case XCB_DESTROY_NOTIFY:
Events::eventDestroy(ev);
Debug::log(LOG, "Event dispatched DESTROY");
break;
case XCB_MAP_REQUEST:
Events::eventMapWindow(ev);
Debug::log(LOG, "Event dispatched MAP");
break;
default:
Debug::log(WARN, "Unknown event: " + std::to_string(ev->response_type & ~0x80));
break;
}
free(ev);
}
// refresh and apply the parameters of all dirty windows.
WindowManager::refreshDirtyWindows();
xcb_flush(WindowManager::DisplayConnection);
return true;
}
void WindowManager::refreshDirtyWindows() {
for(auto& window : windows) {
if (window.getDirty()) {
Values[0] = (int)window.getSize().x;
Values[1] = (int)window.getSize().y;
xcb_configure_window(WindowManager::DisplayConnection, window.getDrawable(), XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, Values);
Values[0] = (int)window.getPosition().x;
Values[1] = (int)window.getPosition().y;
xcb_configure_window(WindowManager::DisplayConnection, window.getDrawable(), XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, Values);
window.setDirty(false);
Debug::log(LOG, "Refreshed dirty window.");
}
}
}
void WindowManager::setFocusedWindow(xcb_drawable_t window) {
if (window && window != WindowManager::Screen->root) {
xcb_set_input_focus(WindowManager::DisplayConnection, XCB_INPUT_FOCUS_POINTER_ROOT, window, XCB_CURRENT_TIME);
WindowManager::LastWindow = window;
}
}
CWindow* WindowManager::getWindowFromDrawable(xcb_drawable_t window) {
for(auto& w : WindowManager::windows) {
if (w.getDrawable() == window) {
return &w;
}
Debug::log(LOG, "Not " + std::to_string(w.getDrawable()));
}
return nullptr;
}
void WindowManager::addWindowToVectorSafe(CWindow window) {
for (auto& w : WindowManager::windows) {
if (w.getDrawable() == window.getDrawable())
return; // Do not add if already present.
}
WindowManager::windows.push_back(window);
}
void WindowManager::removeWindowFromVectorSafe(xcb_drawable_t window) {
if (!window)
return;
std::vector<CWindow> temp = WindowManager::windows;
WindowManager::windows.clear();
for(auto p : temp) {
if (p.getDrawable() != window) {
WindowManager::windows.push_back(p);
continue;
}
Debug::log(LOG, "Is, removing: " + std::to_string(p.getDrawable()));
}
}
void calculateNewTileSetOldTile(CWindow* pWindow) {
const auto PLASTWINDOW = WindowManager::getWindowFromDrawable(WindowManager::LastWindow);
if (PLASTWINDOW) {
const auto PLASTSIZE = PLASTWINDOW->getSize();
const auto PLASTPOS = PLASTWINDOW->getPosition();
if (PLASTSIZE.x > PLASTSIZE.y) {
PLASTWINDOW->setSize(Vector2D(PLASTSIZE.x / 2.f, PLASTSIZE.y));
pWindow->setSize(Vector2D(PLASTSIZE.x / 2.f, PLASTSIZE.y));
pWindow->setPosition(Vector2D(PLASTPOS.x + PLASTSIZE.x / 2.f, PLASTPOS.y));
} else {
PLASTWINDOW->setSize(Vector2D(PLASTSIZE.x, PLASTSIZE.y / 2.f));
pWindow->setSize(Vector2D(PLASTSIZE.x, PLASTSIZE.y / 2.f));
pWindow->setPosition(Vector2D(PLASTPOS.x, PLASTPOS.y + PLASTSIZE.y / 2.f));
}
PLASTWINDOW->setDirty(true);
} else {
// Open a fullscreen window
pWindow->setSize(Vector2D(WindowManager::Screen->width_in_pixels, WindowManager::Screen->height_in_pixels));
pWindow->setPosition(Vector2D(0, 0));
}
}
void WindowManager::calculateNewWindowParams(CWindow* pWindow) {
// And set old one's if needed.
if (!pWindow)
return;
if (!pWindow->getIsFloating()) {
calculateNewTileSetOldTile(pWindow);
}
pWindow->setDirty(true);
}
bool isNeighbor(CWindow* a, CWindow* b) {
const auto POSA = a->getPosition();
const auto POSB = b->getPosition();
const auto SIZEA = a->getSize();
const auto SIZEB = a->getSize();
if (POSA.x != 0) {
if (STICKS(POSA.x, (POSB.x + SIZEB.x))) {
return true;
}
}
if (POSA.y != 0) {
if (STICKS(POSA.y, (POSB.y + SIZEB.y))) {
return true;
}
}
if (POSB.x != 0) {
if (STICKS(POSB.x, (POSA.x + SIZEA.x))) {
return true;
}
}
if (POSB.y != 0) {
if (STICKS(POSB.y, (POSA.y + SIZEA.y))) {
return true;
}
}
return false;
}
void eatWindow(CWindow* a, CWindow* toEat) {
// Pos is min of both.
a->setPosition(Vector2D(std::min(a->getPosition().x, toEat->getPosition().x), std::min(a->getPosition().y, toEat->getPosition().y)));
// Size is pos + size max - pos
const auto OPPCORNERA = a->getPosition() + a->getSize();
const auto OPPCORNERB = toEat->getPosition() + toEat->getSize();
a->setSize(Vector2D(std::max(OPPCORNERA.x, OPPCORNERB.x), std::max(OPPCORNERA.y, OPPCORNERB.y)) - a->getPosition());
}
void WindowManager::fixWindowOnClose(CWindow* pClosedWindow) {
if (!pClosedWindow)
return;
// get the first neighboring window
CWindow* neighbor = nullptr;
for(auto& w : WindowManager::windows) {
if (w.getDrawable() == pClosedWindow->getDrawable())
continue;
if (isNeighbor(&w, pClosedWindow)) {
neighbor = &w;
break;
}
}
if (!neighbor)
return; // No neighbor. Don't update, easy.
// update neighbor to "eat" closed.
eatWindow(neighbor, pClosedWindow);
neighbor->setDirty(true);
}

29
src/windowManager.hpp Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include "defines.hpp"
#include "window.hpp"
#include <vector>
namespace WindowManager {
inline xcb_connection_t* DisplayConnection;
inline xcb_screen_t* Screen;
inline xcb_drawable_t Drawable;
inline uint32_t Values[3];
inline std::vector<CWindow> windows; // windows never left. It has always been hiding amongst us.
inline xcb_drawable_t LastWindow = -1;
CWindow* getWindowFromDrawable(xcb_drawable_t);
void addWindowToVectorSafe(CWindow);
void removeWindowFromVectorSafe(xcb_drawable_t);
void setupManager();
bool handleEvent();
void refreshDirtyWindows();
void setFocusedWindow(xcb_drawable_t);
void calculateNewWindowParams(CWindow*);
void fixWindowOnClose(CWindow*);
};