diff --git a/CMakeLists.txt b/CMakeLists.txt index b5943e74..de745527 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -197,5 +197,6 @@ protocol("subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1. protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml" "hyprland-toplevel-export-v1" true) protocol("stable/xdg-shell/xdg-shell.xml" "xdg-shell" false) protocol("unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml" "linux-dmabuf-unstable-v1" false) +protocol("unstable/xdg-output/xdg-output-unstable-v1.xml" "xdg-output-unstable-v1" false) protocol("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-v1" false) protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false) diff --git a/protocols/meson.build b/protocols/meson.build index e9934d0d..29634542 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -22,6 +22,7 @@ protocols = [ [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], [wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'], [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'], + [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], [wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'], ['wlr-foreign-toplevel-management-unstable-v1.xml'], ['wlr-layer-shell-unstable-v1.xml'], diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 76fefca1..a9d95f39 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -194,8 +194,8 @@ void CCompositor::initServer() { m_sWLRXDGDecoMgr = wlr_xdg_decoration_manager_v1_create(m_sWLDisplay); wlr_server_decoration_manager_set_default_mode(m_sWLRServerDecoMgr, WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); - wlr_xdg_output_manager_v1_create(m_sWLDisplay, m_sWLROutputLayout); - m_sWLROutputMgr = wlr_output_manager_v1_create(m_sWLDisplay); + m_sWLRXDGOutputMgr = wlr_xdg_output_manager_v1_create(m_sWLDisplay, m_sWLROutputLayout); + m_sWLROutputMgr = wlr_output_manager_v1_create(m_sWLDisplay); m_sWLRInhibitMgr = wlr_input_inhibit_manager_create(m_sWLDisplay); m_sWLRKbShInhibitMgr = wlr_keyboard_shortcuts_inhibit_v1_create(m_sWLDisplay); diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 3cb0af62..203ae85b 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -60,6 +60,7 @@ class CCompositor { wlr_xcursor_manager* m_sWLRXCursorMgr; wlr_virtual_keyboard_manager_v1* m_sWLRVKeyboardMgr; wlr_output_manager_v1* m_sWLROutputMgr; + wlr_xdg_output_manager_v1* m_sWLRXDGOutputMgr; wlr_presentation* m_sWLRPresentation; wlr_scene* m_sWLRScene; wlr_input_inhibit_manager* m_sWLRInhibitMgr; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 6fdce7c4..86c4a4c8 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1567,6 +1567,9 @@ void CConfigManager::loadConfigLoadVars() { // update layout g_pLayoutManager->switchToLayout(configValues["general:layout"].strValue); + // update xwl scale + g_pXWaylandManager->updateXWaylandScale(); + // manual crash if (configValues["debug:manual_crash"].intValue && !m_bManualCrashInitiated) { m_bManualCrashInitiated = true; diff --git a/src/events/Events.hpp b/src/events/Events.hpp index b032b11e..35f747cd 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -103,6 +103,7 @@ namespace Events { DYNLISTENFUNC(monitorDamage); DYNLISTENFUNC(monitorNeedsFrame); DYNLISTENFUNC(monitorCommit); + DYNLISTENFUNC(monitorBind); // XWayland LISTENER(readyXWayland); diff --git a/src/events/Misc.cpp b/src/events/Misc.cpp index da680a00..a422a21c 100644 --- a/src/events/Misc.cpp +++ b/src/events/Misc.cpp @@ -74,6 +74,8 @@ void Events::listener_readyXWayland(wl_listener* listener, void* data) { } xcb_disconnect(XCBCONNECTION); + + g_pXWaylandManager->updateXWaylandScale(); #endif } diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index 23b41667..6455d4df 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -28,7 +28,7 @@ void Events::listener_change(wl_listener* listener, void* data) { const auto CONFIGHEAD = wlr_output_configuration_head_v1_create(CONFIG, m->output); - wlr_box BOX; + wlr_box BOX; wlr_output_layout_get_box(g_pCompositor->m_sWLROutputLayout, m->output, &BOX); //m->vecSize.x = BOX.width; @@ -218,4 +218,11 @@ void Events::listener_monitorCommit(void* owner, void* data) { const auto E = (wlr_output_event_commit*)data; g_pProtocolManager->m_pScreencopyProtocolManager->onOutputCommit(PMONITOR, E); + + if (E->committed & (WLR_OUTPUT_STATE_SCALE | WLR_OUTPUT_STATE_TRANSFORM | WLR_OUTPUT_STATE_MODE)) + g_pXWaylandManager->updateXWaylandScale(); +} + +void Events::listener_monitorBind(void* owner, void* data) { + g_pXWaylandManager->updateXWaylandScale(); } diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 0f8dddd4..0691cd37 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -23,12 +23,14 @@ void CMonitor::onConnect(bool noRule) { hyprListener_monitorDamage.removeCallback(); hyprListener_monitorNeedsFrame.removeCallback(); hyprListener_monitorCommit.removeCallback(); + hyprListener_monitorBind.removeCallback(); hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this); hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this); hyprListener_monitorStateRequest.initCallback(&output->events.request_state, &Events::listener_monitorStateRequest, this); hyprListener_monitorDamage.initCallback(&output->events.damage, &Events::listener_monitorDamage, this); hyprListener_monitorNeedsFrame.initCallback(&output->events.needs_frame, &Events::listener_monitorNeedsFrame, this); hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this); + hyprListener_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, this); if (m_bEnabled) { wlr_output_enable(output, 1); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 9226e100..610fa656 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -72,6 +72,7 @@ class CMonitor { DYNLISTENER(monitorDamage); DYNLISTENER(monitorNeedsFrame); DYNLISTENER(monitorCommit); + DYNLISTENER(monitorBind); // hack: a group = workspaces on a monitor. // I don't really care lol :P diff --git a/src/helpers/Vector2D.cpp b/src/helpers/Vector2D.cpp index 2d52eb9e..21701c97 100644 --- a/src/helpers/Vector2D.cpp +++ b/src/helpers/Vector2D.cpp @@ -24,15 +24,15 @@ double Vector2D::normalize() { return max; } -Vector2D Vector2D::floor() { +Vector2D Vector2D::floor() const { return Vector2D(std::floor(x), std::floor(y)); } -Vector2D Vector2D::clamp(const Vector2D& min, const Vector2D& max) { +Vector2D Vector2D::clamp(const Vector2D& min, const Vector2D& max) const { return Vector2D(std::clamp(this->x, min.x, max.x < min.x ? INFINITY : max.x), std::clamp(this->y, min.y, max.y < min.y ? INFINITY : max.y)); } -double Vector2D::distance(const Vector2D& other) { +double Vector2D::distance(const Vector2D& other) const { double dx = x - other.x; double dy = y - other.y; return std::sqrt(dx * dx + dy * dy); diff --git a/src/helpers/Vector2D.hpp b/src/helpers/Vector2D.hpp index f2943b28..1178f734 100644 --- a/src/helpers/Vector2D.hpp +++ b/src/helpers/Vector2D.hpp @@ -42,10 +42,10 @@ class Vector2D { Vector2D operator/(const Vector2D& a) const { return Vector2D(this->x / a.x, this->y / a.y); } - - double distance(const Vector2D& other); - Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D()); + double distance(const Vector2D& other) const; - Vector2D floor(); + Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D()) const; + + Vector2D floor() const; }; diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index c50d2b0d..bee41279 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -1,6 +1,11 @@ #include "XWaylandManager.hpp" #include "../Compositor.hpp" #include "../events/Events.hpp" +#include "xdg-output-unstable-v1-protocol.h" + +#define OUTPUT_MANAGER_VERSION 3 +#define OUTPUT_DONE_DEPRECATED_SINCE_VERSION 3 +#define OUTPUT_DESCRIPTION_MUTABLE_SINCE_VERSION 3 CHyprXWaylandManager::CHyprXWaylandManager() { #ifndef NO_XWAYLAND @@ -155,8 +160,10 @@ void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, Vector2D size, bool f } } + const Vector2D POS = *PXWLFORCESCALEZERO && pWindow->m_bIsX11 ? pWindow->m_vRealPosition.vec() * pWindow->m_fX11SurfaceScaledBy : pWindow->m_vRealPosition.vec(); + if (pWindow->m_bIsX11) - wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, pWindow->m_vRealPosition.vec().x, pWindow->m_vRealPosition.vec().y, size.x, size.y); + wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, POS.x, POS.y, size.x, size.y); else wlr_xdg_toplevel_set_size(pWindow->m_uSurface.xdg->toplevel, size.x, size.y); } @@ -289,3 +296,68 @@ Vector2D CHyprXWaylandManager::getMaxSizeForWindow(CWindow* pWindow) { return MAXSIZE; } + +void CHyprXWaylandManager::updateXWaylandScale() { + static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue; + + setXWaylandScale(*PXWLFORCESCALEZERO ? std::optional{1.0} : std::optional{}); +} + +void CHyprXWaylandManager::setXWaylandScale(std::optional scale) { + Debug::log(LOG, "Overriding XWayland scale with %.2f", (float)scale.value_or(0.0)); + +#ifndef NO_XWAYLAND + wl_resource* res = nullptr; + for (auto& m : g_pCompositor->m_vMonitors) { + const Vector2D LOGICALSIZE = m->vecTransformedSize / scale.value_or(m->scale); + + wl_resource* outputResource = nullptr; + bool needsDone = false; + + wl_list_for_each(res, &m->output->resources, link) { + const auto PCLIENT = wl_resource_get_client(res); + + if (PCLIENT == m_sWLRXWayland->server->client) { + const auto VERSION = wl_resource_get_version(res); + + wl_output_send_mode(res, WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED, (int32_t)LOGICALSIZE.x, (int32_t)LOGICALSIZE.y, m->output->refresh); + + if (VERSION >= WL_OUTPUT_SCALE_SINCE_VERSION) + wl_output_send_scale(res, (uint32_t)ceil(scale.value_or(m->scale))); + + wl_output_send_name(res, getFormat("HL X11 %d", m->ID).c_str()); + + outputResource = res; + needsDone = true; + + break; + } + } + + wlr_xdg_output_v1* output; + wl_list_for_each(output, &g_pCompositor->m_sWLRXDGOutputMgr->outputs, link) { + if (output->layout_output->output == m->output) { + wl_list_for_each(res, &output->resources, link) { + const auto PCLIENT = wl_resource_get_client(res); + + if (PCLIENT == m_sWLRXWayland->server->client) { + zxdg_output_v1_send_logical_size(res, LOGICALSIZE.x, LOGICALSIZE.y); + + if (wl_resource_get_version(res) < OUTPUT_DONE_DEPRECATED_SINCE_VERSION) + zxdg_output_v1_send_done(res); + + needsDone = true; + + break; + } + } + + break; + } + } + + if (needsDone && outputResource) + wl_output_send_done(outputResource); + } +#endif +} diff --git a/src/managers/XWaylandManager.hpp b/src/managers/XWaylandManager.hpp index bb4fd640..e05551e4 100644 --- a/src/managers/XWaylandManager.hpp +++ b/src/managers/XWaylandManager.hpp @@ -2,6 +2,7 @@ #include "../defines.hpp" #include "../Window.hpp" +#include class CHyprXWaylandManager { public: @@ -25,6 +26,10 @@ class CHyprXWaylandManager { void moveXWaylandWindow(CWindow*, const Vector2D&); void checkBorders(CWindow*); Vector2D getMaxSizeForWindow(CWindow*); + void updateXWaylandScale(); + + private: + void setXWaylandScale(std::optional scale); }; inline std::unique_ptr g_pXWaylandManager; \ No newline at end of file diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 5b61e70f..c9096ba0 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1880,6 +1880,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR (int)pMonitor->vecPixelSize.y, pMonitor->refreshRate, pMonitor->scale, (int)pMonitor->transform, (int)pMonitor->vecPosition.x, (int)pMonitor->vecPosition.y, (int)pMonitor->enabled10bit); + g_pXWaylandManager->updateXWaylandScale(); + return true; }