diff --git a/README.md b/README.md index ca9867c..be0fcca 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Hypr is a Linux tiling window manager for Xorg. It's written in XCB with modern - [ ] Fix windows minimizing themselves to tray not being able to come back without pkill - [x] Moving windows between workspaces without floating - [x] EWMH ~ Basic, idk if i'll add more. -- [ ] Docks / Fullscreen Apps etc. auto-detection +- [x] Docks / Fullscreen Apps etc. auto-detection - [ ] Fix animation flicker (if possible) - [ ] Config expansion (rules, default workspaces, etc.) diff --git a/src/events/events.cpp b/src/events/events.cpp index 084ec75..cbe535e 100644 --- a/src/events/events.cpp +++ b/src/events/events.cpp @@ -114,6 +114,37 @@ CWindow* Events::remapFloatingWindow(int windowID, int forcemonitor) { window.setDefaultSize(Vector2D(g_pWindowManager->Screen->width_in_pixels / 2.f, g_pWindowManager->Screen->height_in_pixels / 2.f)); } + // + // Dock Checks + // + const auto wm_type_cookie = xcb_get_property(g_pWindowManager->DisplayConnection, false, windowID, HYPRATOMS["_NET_WM_WINDOW_TYPE"], XCB_GET_PROPERTY_TYPE_ANY, 0, (4294967295U)); + const auto wm_type_cookiereply = xcb_get_property_reply(g_pWindowManager->DisplayConnection, wm_type_cookie, NULL); + xcb_atom_t TYPEATOM = NULL; + if (wm_type_cookiereply == NULL || xcb_get_property_value_length(wm_type_cookiereply) < 1) { + Debug::log(LOG, "No preferred type found."); + } else { + const auto ATOMS = (xcb_atom_t*)xcb_get_property_value(wm_type_cookiereply); + if (!ATOMS) { + Debug::log(ERR, "Atoms not found in preferred type!"); + } else { + if (xcbContainsAtom(wm_type_cookiereply, HYPRATOMS["_NET_WM_WINDOW_TYPE_DOCK"])) { + // set to floating and set the immovable and nointerventions flag + window.setImmovable(true); + window.setNoInterventions(true); + + window.setDefaultPosition(Vector2D(GEOMETRY->x, GEOMETRY->y)); + window.setDefaultSize(Vector2D(GEOMETRY->width, GEOMETRY->height)); + + Debug::log(LOG, "New dock created, setting default XYWH to: " + std::to_string(GEOMETRY->x) + ", " + std::to_string(GEOMETRY->y) + + ", " + std::to_string(GEOMETRY->width) + ", " + std::to_string(GEOMETRY->height)); + } + } + } + free(wm_type_cookiereply); + // + // + // + // Also sets the old one g_pWindowManager->calculateNewWindowParams(&window); @@ -254,13 +285,21 @@ void Events::eventMapWindow(xcb_generic_event_t* event) { // We check if the window is not on our tile-blacklist and if it is, we have a special treatment procedure for it. // this func also sets some stuff + + CWindow* pNewWindow = nullptr; if (g_pWindowManager->shouldBeFloatedOnInit(E->window)) { Debug::log(LOG, "Window SHOULD be floating on start."); - remapFloatingWindow(E->window); + pNewWindow = remapFloatingWindow(E->window); } else { Debug::log(LOG, "Window should NOT be floating on start."); - remapWindow(E->window); + pNewWindow = remapWindow(E->window); } + + if (!pNewWindow) + return; + + // Do post-creation checks. + g_pWindowManager->doPostCreationChecks(pNewWindow); } void Events::eventButtonPress(xcb_generic_event_t* event) { diff --git a/src/utilities/XCBProps.cpp b/src/utilities/XCBProps.cpp index 6ee717e..26115f5 100644 --- a/src/utilities/XCBProps.cpp +++ b/src/utilities/XCBProps.cpp @@ -17,10 +17,12 @@ std::pair getClassName(int64_t window) { char* CLASSINSTANCE = strndup(NEWCLASS, PROPLEN); char* CLASSNAME; + bool freeClassName = true; if (CLASSNAMEINDEX < PROPLEN) { CLASSNAME = strndup(NEWCLASS + CLASSNAMEINDEX, PROPLEN - CLASSNAMEINDEX); } else { CLASSNAME = ""; + freeClassName = false; } std::string CLASSINST(CLASSINSTANCE); @@ -28,7 +30,8 @@ std::pair getClassName(int64_t window) { free(class_cookiereply); free(CLASSINSTANCE); - free(CLASSNAME); + if (freeClassName) + free(CLASSNAME); return std::make_pair<>(CLASSINST, CLASSNAM); } diff --git a/src/window.cpp b/src/window.cpp index f17687e..2c61a1b 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1,7 +1,7 @@ #include "window.hpp" #include "windowManager.hpp" -CWindow::CWindow() { this->setDirty(true); this->setFullscreen(false); this->setIsFloating(false); this->setParentNodeID(0); this->setChildNodeAID(0); this->setChildNodeBID(0); this->setName(""); } +CWindow::CWindow() { this->setImmovable(false); this->setDirty(true); this->setFullscreen(false); this->setIsFloating(false); this->setParentNodeID(0); this->setChildNodeAID(0); this->setChildNodeBID(0); this->setName(""); } CWindow::~CWindow() { } void CWindow::generateNodeID() { diff --git a/src/window.hpp b/src/window.hpp index c981951..b6dd254 100644 --- a/src/window.hpp +++ b/src/window.hpp @@ -61,6 +61,10 @@ public: // Monitors EXPOSED_MEMBER(Monitor, int, i); + + // Docks etc + EXPOSED_MEMBER(Immovable, bool, b); + EXPOSED_MEMBER(NoInterventions, bool, b); private: diff --git a/src/windowManager.cpp b/src/windowManager.cpp index 4008e5d..e0e2a57 100644 --- a/src/windowManager.cpp +++ b/src/windowManager.cpp @@ -304,8 +304,8 @@ void CWindowManager::refreshDirtyWindows() { if (window.getDirty()) { window.setDirty(false); - // Check if the window isn't a node - if (window.getChildNodeAID() != 0) + // Check if the window isn't a node or has the noInterventions prop + if (window.getChildNodeAID() != 0 || window.getNoInterventions()) continue; setEffectiveSizePosUsingConfig(&window); @@ -632,14 +632,16 @@ void CWindowManager::calculateNewFloatingWindow(CWindow* pWindow) { if (!pWindow) return; - pWindow->setPosition(pWindow->getDefaultPosition()); - pWindow->setSize(pWindow->getDefaultSize()); + if (!pWindow->getNoInterventions()) { + pWindow->setPosition(pWindow->getDefaultPosition()); + pWindow->setSize(pWindow->getDefaultSize()); - pWindow->setEffectivePosition(pWindow->getPosition() + Vector2D(10,10)); - pWindow->setEffectiveSize(pWindow->getDefaultSize()); + pWindow->setEffectivePosition(pWindow->getPosition() + Vector2D(10, 10)); + pWindow->setEffectiveSize(pWindow->getDefaultSize()); - pWindow->setRealPosition(pWindow->getPosition()); - pWindow->setRealSize(pWindow->getSize()); + pWindow->setRealPosition(pWindow->getPosition()); + pWindow->setRealSize(pWindow->getSize()); + } Values[0] = XCB_STACK_MODE_ABOVE; xcb_configure_window(DisplayConnection, pWindow->getDrawable(), XCB_CONFIG_WINDOW_STACK_MODE, Values); @@ -1160,6 +1162,9 @@ bool CWindowManager::shouldBeFloatedOnInit(int64_t window) { if (xcbContainsAtom(wm_type_cookiereply, HYPRATOMS["_NET_WM_WINDOW_TYPE_NOTIFICATION"])) { free(wm_type_cookiereply); return true; + } else if (xcbContainsAtom(wm_type_cookiereply, HYPRATOMS["_NET_WM_WINDOW_TYPE_DOCK"])) { + free(wm_type_cookiereply); + return true; } } } @@ -1182,4 +1187,36 @@ void CWindowManager::updateActiveWindowName() { Debug::log(LOG, "Update, window got name: " + WINNAME); PLASTWINDOW->setName(WINNAME); } +} + +void CWindowManager::doPostCreationChecks(CWindow* pWindow) { + // + Debug::log(LOG, "Post creation checks init"); + + const auto window = pWindow->getDrawable(); + + PROP(wm_type_cookie, HYPRATOMS["_NET_WM_WINDOW_TYPE"], UINT32_MAX); + xcb_atom_t TYPEATOM = NULL; + + if (wm_type_cookiereply == NULL || xcb_get_property_value_length(wm_type_cookiereply) < 1) { + Debug::log(LOG, "No preferred type found."); + } else { + const auto ATOMS = (xcb_atom_t*)xcb_get_property_value(wm_type_cookiereply); + if (!ATOMS) { + Debug::log(ERR, "Atoms not found in preferred type!"); + } else { + if (xcbContainsAtom(wm_type_cookiereply, HYPRATOMS["_NET_WM_STATE_FULLSCREEN"])) { + // set it fullscreen + pWindow->setFullscreen(true); + + setFocusedWindow(window); + + KeybindManager::toggleActiveWindowFullscreen(""); + } + } + } + free(wm_type_cookiereply); + + Debug::log(LOG, "Post creation checks ended"); + // } \ No newline at end of file diff --git a/src/windowManager.hpp b/src/windowManager.hpp index d341aab..d7c08b8 100644 --- a/src/windowManager.hpp +++ b/src/windowManager.hpp @@ -91,6 +91,7 @@ public: CWindow* findWindowAtCursor(); bool shouldBeFloatedOnInit(int64_t); + void doPostCreationChecks(CWindow*); void setupRandrMonitors(); void createAndOpenAllPipes();