diff --git a/README.md b/README.md
index 631f436..0786f2f 100644
--- a/README.md
+++ b/README.md
@@ -8,8 +8,11 @@ Hypr is a Linux tiling window manager for Xorg. It's written in XCB with modern
# Features
+- True parabolic animations
+- A built-in status bar
- Keybinds
- Tiling windows
+- Floating windows
- Workspaces
- Config reloaded instantly upon saving
- Moving / Fullscreening windows
@@ -18,12 +21,14 @@ Hypr is a Linux tiling window manager for Xorg. It's written in XCB with modern
- [x] Multi-monitor support
- [x] Status bar ~ Needs expanding
- [x] Floating windows support
-- [x] Config system ~ Basic done
+- [x] Config system
- [x] Workspaces
- [x] Moving windows / user input (e.g. fullscreening) ~ More to be done probably
-- [ ] True lerp animations
+- [x] True lerp animations ~ BETA
- [x] Rewriting the window system to be a tree
+Roadmap complete! Wait for a redone readme and a new one! 🎉
+
# Contributions
diff --git a/src/bar/Bar.cpp b/src/bar/Bar.cpp
index 9f011e4..acb1993 100644
--- a/src/bar/Bar.cpp
+++ b/src/bar/Bar.cpp
@@ -132,6 +132,9 @@ int getTextWidth(std::string text, xcb_font_t font) {
void CStatusBar::draw() {
+ // update animations.
+ AnimationUtil::move();
+
const auto WORKSPACE = g_pWindowManager->getWorkspaceByID(g_pWindowManager->activeWorkspaces[m_iMonitorID]);
if (!WORKSPACE || WORKSPACE->getHasFullscreenWindow()) // TODO: fix this
diff --git a/src/bar/Bar.hpp b/src/bar/Bar.hpp
index 85d3a33..569839f 100644
--- a/src/bar/Bar.hpp
+++ b/src/bar/Bar.hpp
@@ -3,6 +3,7 @@
#include
#include "../defines.hpp"
+#include "../utilities/AnimationUtil.hpp"
struct SDrawingContext {
xcb_gcontext_t GContext;
diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index 05e0461..949b939 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -24,6 +24,11 @@ void ConfigManager::init() {
configValues["col.active_border"].intValue = 0x77FF3333;
configValues["col.inactive_border"].intValue = 0x77222222;
+
+ // animations
+ configValues["anim.speed"].floatValue = 1;
+ configValues["anim.enabled"].intValue = 1;
+
loadConfigLoadVars();
applyKeybindsToX();
}
@@ -166,18 +171,6 @@ void ConfigManager::loadConfigLoadVars() {
loadBar = true;
}
-void emptyEvent() {
- xcb_expose_event_t exposeEvent;
- exposeEvent.window = g_pWindowManager->statusBar.getWindowID();
- exposeEvent.response_type = 0;
- exposeEvent.x = 0;
- exposeEvent.y = 0;
- exposeEvent.width = g_pWindowManager->Screen->width_in_pixels;
- exposeEvent.height = g_pWindowManager->Screen->height_in_pixels;
- xcb_send_event(g_pWindowManager->DisplayConnection, false, g_pWindowManager->Screen->root, XCB_EVENT_MASK_EXPOSURE, (char*)&exposeEvent);
- xcb_flush(g_pWindowManager->DisplayConnection);
-}
-
void ConfigManager::applyKeybindsToX() {
xcb_ungrab_key(g_pWindowManager->DisplayConnection, XCB_GRAB_ANY, g_pWindowManager->Screen->root, XCB_MOD_MASK_ANY);
diff --git a/src/defines.hpp b/src/defines.hpp
index a014ba5..b9ffd5d 100644
--- a/src/defines.hpp
+++ b/src/defines.hpp
@@ -40,3 +40,6 @@
return; \
} \
free(error##name);
+
+
+#define VECTORDELTANONZERO(veca, vecb) ((int)abs(veca.x - vecb.x) > 0 || (int)abs(veca.y - vecb.y) > 0)
diff --git a/src/events/events.cpp b/src/events/events.cpp
index b1e6499..883474f 100644
--- a/src/events/events.cpp
+++ b/src/events/events.cpp
@@ -114,8 +114,9 @@ CWindow* Events::remapWindow(int windowID, bool wasfloating) {
// Also sets the old one
g_pWindowManager->calculateNewWindowParams(&window);
- // Focus
- g_pWindowManager->setFocusedWindow(windowID);
+ // Set real size. No animations in the beginning. Maybe later. TODO?
+ window.setRealPosition(window.getEffectivePosition());
+ window.setRealSize(window.getEffectiveSize());
// Add to arr
g_pWindowManager->addWindowToVectorSafe(window);
@@ -211,8 +212,6 @@ void Events::eventMotionNotify(xcb_generic_event_t* event) {
return;
}
- float Values[2];
-
if (abs(POINTERDELTA.x) < 1 && abs(POINTERDELTA.y) < 1)
return; // micromovements
@@ -221,6 +220,7 @@ void Events::eventMotionNotify(xcb_generic_event_t* event) {
PACTINGWINDOW->setPosition(PACTINGWINDOW->getPosition() + POINTERDELTA);
PACTINGWINDOW->setEffectivePosition(PACTINGWINDOW->getPosition());
PACTINGWINDOW->setDefaultPosition(PACTINGWINDOW->getPosition());
+ PACTINGWINDOW->setRealPosition(PACTINGWINDOW->getPosition());
// update workspace if needed
if (g_pWindowManager->getMonitorFromCursor()) {
@@ -240,6 +240,7 @@ void Events::eventMotionNotify(xcb_generic_event_t* event) {
// apply to other
PACTINGWINDOW->setDefaultSize(PACTINGWINDOW->getSize());
PACTINGWINDOW->setEffectiveSize(PACTINGWINDOW->getSize());
+ PACTINGWINDOW->setRealSize(PACTINGWINDOW->getSize());
PACTINGWINDOW->setDirty(true);
}
@@ -250,6 +251,8 @@ void Events::eventMotionNotify(xcb_generic_event_t* event) {
void Events::eventExpose(xcb_generic_event_t* event) {
const auto E = reinterpret_cast(event);
- // Draw the bar
+ // Draw the bar, disable thread warn
+ g_pWindowManager->mainThreadBusy = false;
g_pWindowManager->statusBar.draw();
+ g_pWindowManager->mainThreadBusy = true;
}
\ No newline at end of file
diff --git a/src/utilities/AnimationUtil.cpp b/src/utilities/AnimationUtil.cpp
new file mode 100644
index 0000000..f23dd72
--- /dev/null
+++ b/src/utilities/AnimationUtil.cpp
@@ -0,0 +1,73 @@
+#include "AnimationUtil.hpp"
+#include "../windowManager.hpp"
+
+void AnimationUtil::move() {
+
+ static std::chrono::time_point lastFrame = std::chrono::high_resolution_clock::now();
+ const double DELTA = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - lastFrame).count();
+
+ // wait for the main thread to be idle
+ while (g_pWindowManager->mainThreadBusy) {
+ ;
+ }
+
+ // set state to let the main thread know to wait.
+ g_pWindowManager->animationUtilBusy = true;
+
+ const double ANIMATIONSPEED = ((double)1 / (double)ConfigManager::getFloat("anim.speed")) * DELTA;
+
+
+ bool updateRequired = false;
+ // Now we are (or should be, lul) thread-safe.
+ for (auto& window : g_pWindowManager->windows) {
+ // check if window needs an animation.
+
+ if (ConfigManager::getInt("anim.enabled") == 0) {
+ // Disabled animations. instant warps.
+ window.setRealPosition(window.getEffectivePosition());
+ window.setRealSize(window.getEffectiveSize());
+
+ if (VECTORDELTANONZERO(window.getRealPosition(), window.getEffectivePosition())
+ || VECTORDELTANONZERO(window.getRealSize(), window.getEffectiveSize())) {
+ window.setDirty(true);
+ updateRequired = true;
+ }
+
+ continue;
+ }
+
+ if (VECTORDELTANONZERO(window.getRealPosition(), window.getEffectivePosition())) {
+ Debug::log(LOG, "Updating position animations for " + std::to_string(window.getDrawable()) + " delta: " + std::to_string(ANIMATIONSPEED));
+
+ // we need to update it.
+ window.setDirty(true);
+ updateRequired = true;
+
+ const auto EFFPOS = window.getEffectivePosition();
+ const auto REALPOS = window.getRealPosition();
+
+ window.setRealPosition(Vector2D(parabolic(REALPOS.x, EFFPOS.x, ANIMATIONSPEED), parabolic(REALPOS.y, EFFPOS.y, ANIMATIONSPEED)));
+ }
+
+ if (VECTORDELTANONZERO(window.getRealSize(), window.getEffectiveSize())) {
+ Debug::log(LOG, "Updating size animations for " + std::to_string(window.getDrawable()) + " delta: " + std::to_string(ANIMATIONSPEED));
+
+ // we need to update it.
+ window.setDirty(true);
+ updateRequired = true;
+
+ const auto REALSIZ = window.getRealSize();
+ const auto EFFSIZ = window.getEffectiveSize();
+
+ window.setRealSize(Vector2D(parabolic(REALSIZ.x, EFFSIZ.x, ANIMATIONSPEED), parabolic(REALSIZ.y, EFFSIZ.y, ANIMATIONSPEED)));
+ }
+ }
+
+ if (updateRequired)
+ emptyEvent(); // send a fake request to update dirty windows
+
+ // restore anim state
+ g_pWindowManager->animationUtilBusy = false;
+
+ lastFrame = std::chrono::high_resolution_clock::now();
+}
\ No newline at end of file
diff --git a/src/utilities/AnimationUtil.hpp b/src/utilities/AnimationUtil.hpp
new file mode 100644
index 0000000..45d5082
--- /dev/null
+++ b/src/utilities/AnimationUtil.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+#include
+#include
+
+#include "Util.hpp"
+
+namespace AnimationUtil {
+
+ void move();
+};
\ No newline at end of file
diff --git a/src/utilities/Util.cpp b/src/utilities/Util.cpp
index e251c74..f999b77 100644
--- a/src/utilities/Util.cpp
+++ b/src/utilities/Util.cpp
@@ -1,4 +1,5 @@
#include "Util.hpp"
+#include "../windowManager.hpp"
// Execute a shell command and get the output
std::string exec(const char* cmd) {
@@ -22,4 +23,20 @@ void clearLogs() {
logs.open(DEBUGPATH, std::ios::out | std::ios::trunc);
logs << " ";
logs.close();
+}
+
+double parabolic(double from, double to, double incline) {
+ return from + ((to - from) / incline);
+}
+
+void emptyEvent() {
+ xcb_expose_event_t exposeEvent;
+ exposeEvent.window = g_pWindowManager->statusBar.getWindowID();
+ exposeEvent.response_type = 0;
+ exposeEvent.x = 0;
+ exposeEvent.y = 0;
+ exposeEvent.width = g_pWindowManager->Screen->width_in_pixels;
+ exposeEvent.height = g_pWindowManager->Screen->height_in_pixels;
+ xcb_send_event(g_pWindowManager->DisplayConnection, false, g_pWindowManager->Screen->root, XCB_EVENT_MASK_EXPOSURE, (char*)&exposeEvent);
+ xcb_flush(g_pWindowManager->DisplayConnection);
}
\ No newline at end of file
diff --git a/src/utilities/Util.hpp b/src/utilities/Util.hpp
index 7df0d7a..f8373f0 100644
--- a/src/utilities/Util.hpp
+++ b/src/utilities/Util.hpp
@@ -5,3 +5,6 @@
std::string exec(const char* cmd);
void clearLogs();
+void emptyEvent();
+
+double parabolic(double from, double to, double incline);
\ No newline at end of file
diff --git a/src/window.hpp b/src/window.hpp
index d808b6d..fc14844 100644
--- a/src/window.hpp
+++ b/src/window.hpp
@@ -44,6 +44,8 @@ public:
EXPOSED_MEMBER(EffectiveSize, Vector2D, vec);
EXPOSED_MEMBER(EffectivePosition, Vector2D, vec);
EXPOSED_MEMBER(Position, Vector2D, vec);
+ EXPOSED_MEMBER(RealSize, Vector2D, vec);
+ EXPOSED_MEMBER(RealPosition, Vector2D, vec);
EXPOSED_MEMBER(IsFloating, bool, b);
EXPOSED_MEMBER(Drawable, int64_t, i); // int64_t because it's my internal ID system too.
diff --git a/src/windowManager.cpp b/src/windowManager.cpp
index 8a10ea7..1059bca 100644
--- a/src/windowManager.cpp
+++ b/src/windowManager.cpp
@@ -188,7 +188,7 @@ void CWindowManager::setupManager() {
updateBarInfo();
// start its' update thread
- //Events::setThread();
+ Events::setThread();
Debug::log(LOG, "Bar done.");
@@ -204,6 +204,13 @@ bool CWindowManager::handleEvent() {
xcb_flush(DisplayConnection);
const auto ev = xcb_wait_for_event(DisplayConnection);
if (ev != NULL) {
+ while (animationUtilBusy) {
+ ; // wait for it to finish
+ }
+
+ // Set thread state, halt animations until done.
+ mainThreadBusy = true;
+
switch (ev->response_type & ~0x80) {
case XCB_ENTER_NOTIFY:
Events::eventEnter(ev);
@@ -258,6 +265,9 @@ bool CWindowManager::handleEvent() {
xcb_flush(DisplayConnection);
+ // Restore thread state
+ mainThreadBusy = false;
+
return true;
}
@@ -343,14 +353,14 @@ void CWindowManager::refreshDirtyWindows() {
continue;
}
- Values[0] = (int)window.getEffectiveSize().x;
- Values[1] = (int)window.getEffectiveSize().y;
+ Values[0] = (int)window.getRealSize().x;
+ Values[1] = (int)window.getRealSize().y;
xcb_configure_window(DisplayConnection, window.getDrawable(), XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, Values);
// Update the position because the border makes the window jump
// I have added the bordersize vec2d before in the setEffectiveSizePosUsingConfig function.
- Values[0] = (int)window.getEffectivePosition().x - ConfigManager::getInt("border_size");
- Values[1] = (int)window.getEffectivePosition().y - ConfigManager::getInt("border_size");
+ Values[0] = (int)window.getRealPosition().x - ConfigManager::getInt("border_size");
+ Values[1] = (int)window.getRealPosition().y - ConfigManager::getInt("border_size");
xcb_configure_window(DisplayConnection, window.getDrawable(), XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, Values);
// Focused special border.
@@ -441,8 +451,6 @@ void CWindowManager::setEffectiveSizePosUsingConfig(CWindow* pWindow) {
pWindow->setEffectivePosition(pWindow->getPosition() + Vector2D(ConfigManager::getInt("border_size"), ConfigManager::getInt("border_size")));
pWindow->setEffectiveSize(pWindow->getSize() - (Vector2D(ConfigManager::getInt("border_size"), ConfigManager::getInt("border_size")) * 2));
- //TODO: make windows with no bar taller, this aint working chief
-
// do gaps, set top left
pWindow->setEffectivePosition(pWindow->getEffectivePosition() + Vector2D(DISPLAYLEFT ? ConfigManager::getInt("gaps_out") : ConfigManager::getInt("gaps_in"), DISPLAYTOP ? ConfigManager::getInt("gaps_out") + (MONITOR->ID == statusBar.getMonitorID() ? ConfigManager::getInt("bar_height") : 0) : ConfigManager::getInt("gaps_in")));
// fix to old size bottom right
@@ -547,6 +555,8 @@ void CWindowManager::calculateNewWindowParams(CWindow* pWindow) {
calculateNewFloatingWindow(pWindow);
}
+ setEffectiveSizePosUsingConfig(pWindow);
+
pWindow->setDirty(true);
}
diff --git a/src/windowManager.hpp b/src/windowManager.hpp
index 794e3b2..fdf947e 100644
--- a/src/windowManager.hpp
+++ b/src/windowManager.hpp
@@ -13,6 +13,7 @@
#include "config/ConfigManager.hpp"
#include "utilities/Monitor.hpp"
#include "utilities/Util.hpp"
+#include "utilities/AnimationUtil.hpp"
class CWindowManager {
public:
@@ -40,6 +41,9 @@ public:
CStatusBar statusBar;
std::thread* barThread;
+ std::atomic mainThreadBusy = false;
+ std::atomic animationUtilBusy = false;
+
CWindow* getWindowFromDrawable(int64_t);
void addWindowToVectorSafe(CWindow);
void removeWindowFromVectorSafe(int64_t);