Hyprland/src/events/Windows.cpp

283 lines
11 KiB
C++
Raw Normal View History

2022-03-21 15:17:04 +01:00
#include "Events.hpp"
#include "../Compositor.hpp"
#include "../helpers/WLClasses.hpp"
#include "../managers/InputManager.hpp"
#include "../render/Renderer.hpp"
// ------------------------------------------------------------ //
// __ _______ _ _ _____ ______ _______ //
// \ \ / /_ _| \ | | __ \ / __ \ \ / / ____| //
// \ \ /\ / / | | | \| | | | | | | \ \ /\ / / (___ //
// \ \/ \/ / | | | . ` | | | | | | |\ \/ \/ / \___ \ //
// \ /\ / _| |_| |\ | |__| | |__| | \ /\ / ____) | //
// \/ \/ |_____|_| \_|_____/ \____/ \/ \/ |_____/ //
// //
// ------------------------------------------------------------ //
void Events::listener_mapWindow(wl_listener* listener, void* data) {
CWindow* PWINDOW = wl_container_of(listener, PWINDOW, listen_mapWindow);
const auto PMONITOR = g_pCompositor->getMonitorFromCursor();
PWINDOW->m_iMonitorID = PMONITOR->ID;
PWINDOW->m_bMappedX11 = true;
PWINDOW->m_iWorkspaceID = PMONITOR->activeWorkspace;
2022-03-22 20:53:11 +01:00
PWINDOW->m_bIsMapped = true;
2022-03-21 15:17:04 +01:00
2022-03-22 21:28:57 +01:00
// checks if the window wants borders and sets the appriopriate flag
g_pXWaylandManager->checkBorders(PWINDOW);
2022-03-21 17:00:17 +01:00
const auto PWINDOWSURFACE = g_pXWaylandManager->getWindowSurface(PWINDOW);
if (!PWINDOWSURFACE) {
g_pCompositor->m_lWindows.remove(*PWINDOW);
return;
}
wl_signal_add(&PWINDOWSURFACE->events.new_subsurface, &PWINDOW->listen_newSubsurfaceWindow);
2022-03-21 16:16:47 +01:00
2022-03-24 18:22:01 +01:00
if (g_pXWaylandManager->shouldBeFloated(PWINDOW))
2022-03-21 17:24:41 +01:00
PWINDOW->m_bIsFloating = true;
2022-03-24 18:22:01 +01:00
// window rules
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW);
for (auto& r : WINDOWRULES) {
if (r.szRule.find("monitor") == 0) {
try {
const long int MONITOR = std::stoi(r.szRule.substr(r.szRule.find(" ")));
if (MONITOR >= (long int)g_pCompositor->m_lMonitors.size() || MONITOR < (long int)0)
PWINDOW->m_iMonitorID = 0;
else
PWINDOW->m_iMonitorID = MONITOR;
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeWorkspace;
2022-03-24 19:05:25 +01:00
Debug::log(LOG, "Rule monitor, applying to window %x -> mon: %i, workspace: %i", PWINDOW, PWINDOW->m_iMonitorID, PWINDOW->m_iWorkspaceID);
2022-03-24 18:22:01 +01:00
} catch (...) {
Debug::log(LOG, "Rule monitor failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str());
}
} else if (r.szRule.find("float") == 0) {
PWINDOW->m_bIsFloating = true;
} else if (r.szRule.find("tile") == 0) {
PWINDOW->m_bIsFloating = false;
}
}
if (PWINDOW->m_bIsFloating) {
g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(PWINDOW);
// size and move rules
for (auto& r : WINDOWRULES) {
if (r.szRule.find("size") == 0) {
try {
const auto VALUE = r.szRule.substr(r.szRule.find(" ") + 1);
const auto SIZEX = stoi(VALUE.substr(0, VALUE.find(" ")));
const auto SIZEY = stoi(VALUE.substr(VALUE.find(" ") + 1));
Debug::log(LOG, "Rule size, applying to window %x", PWINDOW);
PWINDOW->m_vEffectiveSize = Vector2D(SIZEX, SIZEY);
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vEffectiveSize);
} catch (...) {
Debug::log(LOG, "Rule size failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str());
}
} else if (r.szRule.find("move") == 0) {
try {
const auto VALUE = r.szRule.substr(r.szRule.find(" ") + 1);
const auto POSX = stoi(VALUE.substr(0, VALUE.find(" ")));
const auto POSY = stoi(VALUE.substr(VALUE.find(" ") + 1));
Debug::log(LOG, "Rule move, applying to window %x", PWINDOW);
PWINDOW->m_vEffectivePosition = Vector2D(POSX, POSY) + PMONITOR->vecPosition;
} catch (...) {
Debug::log(LOG, "Rule move failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str());
}
}
}
2022-03-21 17:24:41 +01:00
}
2022-03-21 15:17:04 +01:00
else
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW);
2022-03-24 18:22:01 +01:00
PWINDOW->m_szTitle = g_pXWaylandManager->getTitle(PWINDOW);
2022-03-22 18:29:13 +01:00
if (!PWINDOW->m_bIsModal)
g_pCompositor->focusWindow(PWINDOW);
2022-03-21 15:17:04 +01:00
2022-03-24 19:05:25 +01:00
Debug::log(LOG, "Map request dispatched, monitor %s, xywh: %f %f %f %f", PMONITOR->szName.c_str(), PWINDOW->m_vEffectivePosition.x, PWINDOW->m_vEffectivePosition.y, PWINDOW->m_vEffectiveSize.x, PWINDOW->m_vEffectiveSize.y);
2022-03-21 15:17:04 +01:00
}
void Events::listener_unmapWindow(wl_listener* listener, void* data) {
CWindow* PWINDOW = wl_container_of(listener, PWINDOW, listen_unmapWindow);
if (g_pXWaylandManager->getWindowSurface(PWINDOW) == g_pCompositor->m_pLastFocus)
g_pCompositor->m_pLastFocus = nullptr;
2022-03-22 20:04:39 +01:00
PWINDOW->m_bMappedX11 = false;
2022-03-21 19:18:33 +01:00
// remove the fullscreen window status from workspace if we closed it
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID);
if (PWORKSPACE->hasFullscreenWindow && PWINDOW->m_bIsFullscreen)
PWORKSPACE->hasFullscreenWindow = false;
2022-03-21 15:17:04 +01:00
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW);
2022-03-22 22:22:59 +01:00
// do this after onWindowRemoved because otherwise it'll think the window is invalid
PWINDOW->m_bIsMapped = false;
2022-03-21 19:28:43 +01:00
// refocus on a new window
2022-03-22 20:13:58 +01:00
// TODO: investigate.
// If a parent window has focus, any popups (XWayland) will be broken (they will disappear instantly)
2022-03-22 20:43:06 +01:00
// This might be way more sinister in nature and have a problem more deeply
// rooted in the code.
2022-03-22 20:13:58 +01:00
// g_pInputManager->refocus();
2022-03-21 19:28:43 +01:00
2022-03-21 15:17:04 +01:00
Debug::log(LOG, "Window %x unmapped", PWINDOW);
}
void Events::listener_commitWindow(wl_listener* listener, void* data) {
CWindow* PWINDOW = wl_container_of(listener, PWINDOW, listen_commitWindow);
2022-03-21 21:58:44 +01:00
// Debug::log(LOG, "Window %x committed", PWINDOW); // SPAM!
2022-03-21 15:17:04 +01:00
}
void Events::listener_destroyWindow(wl_listener* listener, void* data) {
CWindow* PWINDOW = wl_container_of(listener, PWINDOW, listen_destroyWindow);
if (g_pXWaylandManager->getWindowSurface(PWINDOW) == g_pCompositor->m_pLastFocus)
g_pCompositor->m_pLastFocus = nullptr;
2022-03-23 22:21:03 +01:00
// TODO:
// We sometimes get invalid pointers here (stack ones)
// this obviously means we tainted wlroots.
// Investigate
2022-03-21 15:17:04 +01:00
2022-03-23 22:21:03 +01:00
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW);
2022-03-21 15:17:04 +01:00
Debug::log(LOG, "Window %x destroyed", PWINDOW);
2022-03-23 22:21:03 +01:00
wl_list_remove(&PWINDOW->listen_mapWindow.link);
wl_list_remove(&PWINDOW->listen_unmapWindow.link);
wl_list_remove(&PWINDOW->listen_destroyWindow.link);
wl_list_remove(&PWINDOW->listen_setTitleWindow.link);
wl_list_remove(&PWINDOW->listen_fullscreenWindow.link);
if (PWINDOW->m_bIsX11) {
wl_list_remove(&PWINDOW->listen_activateX11.link);
wl_list_remove(&PWINDOW->listen_configureX11.link);
} else {
wl_list_remove(&PWINDOW->listen_commitWindow.link);
2022-03-23 22:21:03 +01:00
}
g_pCompositor->removeWindowFromVectorSafe(PWINDOW);
2022-03-21 15:17:04 +01:00
}
void Events::listener_setTitleWindow(wl_listener* listener, void* data) {
CWindow* PWINDOW = wl_container_of(listener, PWINDOW, listen_setTitleWindow);
2022-03-22 17:31:19 +01:00
if (!g_pCompositor->windowValidMapped(PWINDOW))
return;
2022-03-21 15:17:04 +01:00
PWINDOW->m_szTitle = g_pXWaylandManager->getTitle(PWINDOW);
Debug::log(LOG, "Window %x set title to %s", PWINDOW, PWINDOW->m_szTitle.c_str());
}
void Events::listener_fullscreenWindow(wl_listener* listener, void* data) {
CWindow* PWINDOW = wl_container_of(listener, PWINDOW, listen_fullscreenWindow);
2022-03-21 19:18:33 +01:00
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW);
2022-03-21 15:17:04 +01:00
Debug::log(LOG, "Window %x fullscreen to %i", PWINDOW, PWINDOW->m_bIsFullscreen);
}
void Events::listener_activate(wl_listener* listener, void* data) {
// TODO
}
void Events::listener_activateX11(wl_listener* listener, void* data) {
CWindow* PWINDOW = wl_container_of(listener, PWINDOW, listen_activateX11);
if (PWINDOW->m_iX11Type == 1 /* Managed */) {
wlr_xwayland_surface_activate(PWINDOW->m_uSurface.xwayland, 1);
}
}
void Events::listener_configureX11(wl_listener* listener, void* data) {
CWindow* PWINDOW = wl_container_of(listener, PWINDOW, listen_configureX11);
const auto E = (wlr_xwayland_surface_configure_event*)data;
// TODO: ignore if tiled?
wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height);
2022-03-21 16:13:43 +01:00
}
void Events::listener_surfaceXWayland(wl_listener* listener, void* data) {
const auto XWSURFACE = (wlr_xwayland_surface*)data;
g_pCompositor->m_lWindows.push_back(CWindow());
const auto PNEWWINDOW = &g_pCompositor->m_lWindows.back();
PNEWWINDOW->m_uSurface.xwayland = XWSURFACE;
PNEWWINDOW->m_iX11Type = XWSURFACE->override_redirect ? 2 : 1;
PNEWWINDOW->m_bIsX11 = true;
wl_signal_add(&XWSURFACE->events.map, &PNEWWINDOW->listen_mapWindow);
wl_signal_add(&XWSURFACE->events.unmap, &PNEWWINDOW->listen_unmapWindow);
wl_signal_add(&XWSURFACE->events.request_activate, &PNEWWINDOW->listen_activateX11);
wl_signal_add(&XWSURFACE->events.request_configure, &PNEWWINDOW->listen_configureX11);
wl_signal_add(&XWSURFACE->events.set_title, &PNEWWINDOW->listen_setTitleWindow);
wl_signal_add(&XWSURFACE->events.destroy, &PNEWWINDOW->listen_destroyWindow);
wl_signal_add(&XWSURFACE->events.request_fullscreen, &PNEWWINDOW->listen_fullscreenWindow);
Debug::log(LOG, "New XWayland Surface created.");
}
void Events::listener_newXDGSurface(wl_listener* listener, void* data) {
// A window got opened
const auto XDGSURFACE = (wlr_xdg_surface*)data;
if (XDGSURFACE->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
return; // TODO: handle?
g_pCompositor->m_lWindows.push_back(CWindow());
const auto PNEWWINDOW = &g_pCompositor->m_lWindows.back();
PNEWWINDOW->m_uSurface.xdg = XDGSURFACE;
wl_signal_add(&XDGSURFACE->surface->events.commit, &PNEWWINDOW->listen_commitWindow);
wl_signal_add(&XDGSURFACE->events.map, &PNEWWINDOW->listen_mapWindow);
wl_signal_add(&XDGSURFACE->events.unmap, &PNEWWINDOW->listen_unmapWindow);
wl_signal_add(&XDGSURFACE->events.destroy, &PNEWWINDOW->listen_destroyWindow);
wl_signal_add(&XDGSURFACE->toplevel->events.set_title, &PNEWWINDOW->listen_setTitleWindow);
wl_signal_add(&XDGSURFACE->toplevel->events.request_fullscreen, &PNEWWINDOW->listen_fullscreenWindow);
Debug::log(LOG, "New XDG Surface created.");
}
//
// Subsurfaces
//
void createSubsurface(CWindow* pWindow, wlr_subsurface* pSubsurface) {
if (!pWindow || !pSubsurface)
return;
g_pCompositor->m_lSubsurfaces.push_back(SSubsurface());
const auto PNEWSUBSURFACE = &g_pCompositor->m_lSubsurfaces.back();
wl_signal_add(&pSubsurface->events.destroy, &PNEWSUBSURFACE->listen_destroySubsurface);
wl_signal_add(&pSubsurface->events.map, &PNEWSUBSURFACE->listen_mapSubsurface);
wl_signal_add(&pSubsurface->events.unmap, &PNEWSUBSURFACE->listen_unmapSubsurface);
wl_signal_add(&pSubsurface->surface->events.commit, &PNEWSUBSURFACE->listen_commitSubsurface);
}
void Events::listener_newSubsurfaceWindow(wl_listener* listener, void* data) {
CWindow* PWINDOW = wl_container_of(listener, PWINDOW, listen_newSubsurfaceWindow);
const auto PSUBSURFACE = (wlr_subsurface*)data;
createSubsurface(PWINDOW, PSUBSURFACE);
2022-03-22 17:31:19 +01:00
}