#include "ProtocolManager.hpp" #include "../config/ConfigValue.hpp" #include "../protocols/TearingControl.hpp" #include "../protocols/FractionalScale.hpp" #include "../protocols/XDGOutput.hpp" #include "../protocols/CursorShape.hpp" #include "../protocols/IdleInhibit.hpp" #include "../protocols/RelativePointer.hpp" #include "../protocols/XDGDecoration.hpp" #include "../protocols/AlphaModifier.hpp" #include "../protocols/GammaControl.hpp" #include "../protocols/ForeignToplevel.hpp" #include "../protocols/PointerGestures.hpp" #include "../protocols/ForeignToplevelWlr.hpp" #include "../protocols/ShortcutsInhibit.hpp" #include "../protocols/TextInputV3.hpp" #include "../protocols/PointerConstraints.hpp" #include "../protocols/OutputPower.hpp" #include "../protocols/XDGActivation.hpp" #include "../protocols/IdleNotify.hpp" #include "../protocols/LockNotify.hpp" #include "../protocols/SessionLock.hpp" #include "../protocols/InputMethodV2.hpp" #include "../protocols/VirtualKeyboard.hpp" #include "../protocols/VirtualPointer.hpp" #include "../protocols/OutputManagement.hpp" #include "../protocols/ServerDecorationKDE.hpp" #include "../protocols/FocusGrab.hpp" #include "../protocols/Tablet.hpp" #include "../protocols/LayerShell.hpp" #include "../protocols/PresentationTime.hpp" #include "../protocols/XDGShell.hpp" #include "../protocols/DataDeviceWlr.hpp" #include "../protocols/PrimarySelection.hpp" #include "../protocols/XWaylandShell.hpp" #include "../protocols/Viewporter.hpp" #include "../protocols/MesaDRM.hpp" #include "../protocols/LinuxDMABUF.hpp" #include "../protocols/DRMLease.hpp" #include "../protocols/DRMSyncobj.hpp" #include "../protocols/Screencopy.hpp" #include "../protocols/ToplevelExport.hpp" #include "../protocols/ToplevelMapping.hpp" #include "../protocols/TextInputV1.hpp" #include "../protocols/GlobalShortcuts.hpp" #include "../protocols/XDGDialog.hpp" #include "../protocols/SinglePixel.hpp" #include "../protocols/SecurityContext.hpp" #include "../protocols/CTMControl.hpp" #include "../protocols/HyprlandSurface.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" #include "../protocols/core/Compositor.hpp" #include "../protocols/core/Subcompositor.hpp" #include "../protocols/core/Output.hpp" #include "../protocols/core/Shm.hpp" #include "../protocols/ColorManagement.hpp" #include "../protocols/XXColorManagement.hpp" #include "../protocols/FrogColorManagement.hpp" #include "../protocols/ContentType.hpp" #include "../protocols/XDGTag.hpp" #include "../protocols/XDGBell.hpp" #include "../helpers/Monitor.hpp" #include "../render/Renderer.hpp" #include "../Compositor.hpp" #include "content-type-v1.hpp" #include #include #include // ******************************************************************************************** // * IMPORTANT: make sure to .reset() any protocol UP's you create! (put reset in destructor) * // * otherwise Hyprland might crash when exiting. * // ******************************************************************************************** void CProtocolManager::onMonitorModeChange(PHLMONITOR pMonitor) { const bool ISMIRROR = pMonitor->isMirror(); // onModeChanged we check if the current mirror status matches the global. // mirrored outputs should have their global removed, as they are not physical parts of the // layout. if (ISMIRROR && PROTO::outputs.contains(pMonitor->szName)) PROTO::outputs.at(pMonitor->szName)->remove(); else if (!ISMIRROR && (!PROTO::outputs.contains(pMonitor->szName) || PROTO::outputs.at(pMonitor->szName)->isDefunct())) { if (PROTO::outputs.contains(pMonitor->szName)) PROTO::outputs.erase(pMonitor->szName); PROTO::outputs.emplace(pMonitor->szName, makeShared(&wl_output_interface, 4, std::format("WLOutput ({})", pMonitor->szName), pMonitor->self.lock())); } if (PROTO::colorManagement && g_pCompositor->shouldChangePreferredImageDescription()) { Debug::log(ERR, "FIXME: color management protocol is enabled, need a preferred image description id"); PROTO::colorManagement->onImagePreferredChanged(0); } } CProtocolManager::CProtocolManager() { static const auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); static const auto PENABLECM = CConfigValue("render:cm_enabled"); static const auto PENABLEXXCM = CConfigValue("experimental:xx_color_management_v4"); static const auto PDEBUGCM = CConfigValue("debug:full_cm_proto"); // Outputs are a bit dumb, we have to agree. static auto P = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) { auto M = std::any_cast(param); // ignore mirrored outputs. I don't think this will ever be hit as mirrors are applied after // this event is emitted iirc. // also ignore the fallback if (M->isMirror() || M == g_pCompositor->m_unsafeOutput) return; if (PROTO::outputs.contains(M->szName)) PROTO::outputs.erase(M->szName); auto ref = makeShared(&wl_output_interface, 4, std::format("WLOutput ({})", M->szName), M->self.lock()); PROTO::outputs.emplace(M->szName, ref); ref->self = ref; m_mModeChangeListeners[M->szName] = M->events.modeChanged.registerListener([M, this](std::any d) { onMonitorModeChange(M); }); }); static auto P2 = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { auto M = std::any_cast(param); if (!PROTO::outputs.contains(M->szName)) return; PROTO::outputs.at(M->szName)->remove(); m_mModeChangeListeners.erase(M->szName); }); // Core PROTO::seat = makeUnique(&wl_seat_interface, 9, "WLSeat"); PROTO::data = makeUnique(&wl_data_device_manager_interface, 3, "WLDataDevice"); PROTO::compositor = makeUnique(&wl_compositor_interface, 6, "WLCompositor"); PROTO::subcompositor = makeUnique(&wl_subcompositor_interface, 1, "WLSubcompositor"); PROTO::shm = makeUnique(&wl_shm_interface, 1, "WLSHM"); // Extensions PROTO::viewport = makeUnique(&wp_viewporter_interface, 1, "Viewporter"); PROTO::tearing = makeUnique(&wp_tearing_control_manager_v1_interface, 1, "TearingControl"); PROTO::fractional = makeUnique(&wp_fractional_scale_manager_v1_interface, 1, "FractionalScale"); PROTO::xdgOutput = makeUnique(&zxdg_output_manager_v1_interface, 3, "XDGOutput"); PROTO::cursorShape = makeUnique(&wp_cursor_shape_manager_v1_interface, 1, "CursorShape"); PROTO::idleInhibit = makeUnique(&zwp_idle_inhibit_manager_v1_interface, 1, "IdleInhibit"); PROTO::relativePointer = makeUnique(&zwp_relative_pointer_manager_v1_interface, 1, "RelativePointer"); PROTO::xdgDecoration = makeUnique(&zxdg_decoration_manager_v1_interface, 1, "XDGDecoration"); PROTO::alphaModifier = makeUnique(&wp_alpha_modifier_v1_interface, 1, "AlphaModifier"); PROTO::gamma = makeUnique(&zwlr_gamma_control_manager_v1_interface, 1, "GammaControl"); PROTO::foreignToplevel = makeUnique(&ext_foreign_toplevel_list_v1_interface, 1, "ForeignToplevel"); PROTO::pointerGestures = makeUnique(&zwp_pointer_gestures_v1_interface, 3, "PointerGestures"); PROTO::foreignToplevelWlr = makeUnique(&zwlr_foreign_toplevel_manager_v1_interface, 3, "ForeignToplevelWlr"); PROTO::shortcutsInhibit = makeUnique(&zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1, "ShortcutsInhibit"); PROTO::textInputV1 = makeUnique(&zwp_text_input_manager_v1_interface, 1, "TextInputV1"); PROTO::textInputV3 = makeUnique(&zwp_text_input_manager_v3_interface, 1, "TextInputV3"); PROTO::constraints = makeUnique(&zwp_pointer_constraints_v1_interface, 1, "PointerConstraints"); PROTO::outputPower = makeUnique(&zwlr_output_power_manager_v1_interface, 1, "OutputPower"); PROTO::activation = makeUnique(&xdg_activation_v1_interface, 1, "XDGActivation"); PROTO::idle = makeUnique(&ext_idle_notifier_v1_interface, 2, "IdleNotify"); PROTO::lockNotify = makeUnique(&hyprland_lock_notifier_v1_interface, 1, "IdleNotify"); PROTO::sessionLock = makeUnique(&ext_session_lock_manager_v1_interface, 1, "SessionLock"); PROTO::ime = makeUnique(&zwp_input_method_manager_v2_interface, 1, "IMEv2"); PROTO::virtualKeyboard = makeUnique(&zwp_virtual_keyboard_manager_v1_interface, 1, "VirtualKeyboard"); PROTO::virtualPointer = makeUnique(&zwlr_virtual_pointer_manager_v1_interface, 2, "VirtualPointer"); PROTO::outputManagement = makeUnique(&zwlr_output_manager_v1_interface, 4, "OutputManagement"); PROTO::serverDecorationKDE = makeUnique(&org_kde_kwin_server_decoration_manager_interface, 1, "ServerDecorationKDE"); PROTO::focusGrab = makeUnique(&hyprland_focus_grab_manager_v1_interface, 1, "FocusGrab"); PROTO::tablet = makeUnique(&zwp_tablet_manager_v2_interface, 1, "TabletV2"); PROTO::layerShell = makeUnique(&zwlr_layer_shell_v1_interface, 5, "LayerShell"); PROTO::presentation = makeUnique(&wp_presentation_interface, 1, "Presentation"); PROTO::xdgShell = makeUnique(&xdg_wm_base_interface, 6, "XDGShell"); PROTO::dataWlr = makeUnique(&zwlr_data_control_manager_v1_interface, 2, "DataDeviceWlr"); PROTO::primarySelection = makeUnique(&zwp_primary_selection_device_manager_v1_interface, 1, "PrimarySelection"); PROTO::xwaylandShell = makeUnique(&xwayland_shell_v1_interface, 1, "XWaylandShell"); PROTO::screencopy = makeUnique(&zwlr_screencopy_manager_v1_interface, 3, "Screencopy"); PROTO::toplevelExport = makeUnique(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport"); PROTO::toplevelMapping = makeUnique(&hyprland_toplevel_mapping_manager_v1_interface, 1, "ToplevelMapping"); PROTO::globalShortcuts = makeUnique(&hyprland_global_shortcuts_manager_v1_interface, 1, "GlobalShortcuts"); PROTO::xdgDialog = makeUnique(&xdg_wm_dialog_v1_interface, 1, "XDGDialog"); PROTO::singlePixel = makeUnique(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel"); PROTO::securityContext = makeUnique(&wp_security_context_manager_v1_interface, 1, "SecurityContext"); PROTO::ctm = makeUnique(&hyprland_ctm_control_manager_v1_interface, 2, "CTMControl"); PROTO::hyprlandSurface = makeUnique(&hyprland_surface_manager_v1_interface, 2, "HyprlandSurface"); PROTO::contentType = makeUnique(&wp_content_type_manager_v1_interface, 1, "ContentType"); PROTO::xdgTag = makeUnique(&xdg_toplevel_tag_manager_v1_interface, 1, "XDGTag"); PROTO::xdgBell = makeUnique(&xdg_system_bell_v1_interface, 1, "XDGBell"); if (*PENABLECM) PROTO::colorManagement = makeUnique(&wp_color_manager_v1_interface, 1, "ColorManagement", *PDEBUGCM); if (*PENABLEXXCM && *PENABLECM) { PROTO::xxColorManagement = makeUnique(&xx_color_manager_v4_interface, 1, "XXColorManagement"); PROTO::frogColorManagement = makeUnique(&frog_color_management_factory_v1_interface, 1, "FrogColorManagement"); } // ! please read the top of this file before adding another protocol for (auto const& b : g_pCompositor->m_aqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) continue; PROTO::lease = makeUnique(&wp_drm_lease_device_v1_interface, 1, "DRMLease"); if (*PENABLEEXPLICIT) PROTO::sync = makeUnique(&wp_linux_drm_syncobj_manager_v1_interface, 1, "DRMSyncobj"); break; } if (g_pHyprOpenGL->getDRMFormats().size() > 0) { PROTO::mesaDRM = makeUnique(&wl_drm_interface, 2, "MesaDRM"); PROTO::linuxDma = makeUnique(&zwp_linux_dmabuf_v1_interface, 5, "LinuxDMABUF"); } else Debug::log(WARN, "ProtocolManager: Not binding linux-dmabuf and MesaDRM: DMABUF not available"); } CProtocolManager::~CProtocolManager() { // this is dumb but i don't want to replace all 600 PROTO with the right thing // Output PROTO::outputs.clear(); // Core PROTO::seat.reset(); PROTO::data.reset(); PROTO::compositor.reset(); PROTO::subcompositor.reset(); PROTO::shm.reset(); // Extensions PROTO::viewport.reset(); PROTO::tearing.reset(); PROTO::fractional.reset(); PROTO::xdgOutput.reset(); PROTO::cursorShape.reset(); PROTO::idleInhibit.reset(); PROTO::relativePointer.reset(); PROTO::xdgDecoration.reset(); PROTO::alphaModifier.reset(); PROTO::gamma.reset(); PROTO::foreignToplevel.reset(); PROTO::pointerGestures.reset(); PROTO::foreignToplevelWlr.reset(); PROTO::shortcutsInhibit.reset(); PROTO::textInputV1.reset(); PROTO::textInputV3.reset(); PROTO::constraints.reset(); PROTO::outputPower.reset(); PROTO::activation.reset(); PROTO::idle.reset(); PROTO::lockNotify.reset(); PROTO::sessionLock.reset(); PROTO::ime.reset(); PROTO::virtualKeyboard.reset(); PROTO::virtualPointer.reset(); PROTO::outputManagement.reset(); PROTO::serverDecorationKDE.reset(); PROTO::focusGrab.reset(); PROTO::tablet.reset(); PROTO::layerShell.reset(); PROTO::presentation.reset(); PROTO::xdgShell.reset(); PROTO::dataWlr.reset(); PROTO::primarySelection.reset(); PROTO::xwaylandShell.reset(); PROTO::screencopy.reset(); PROTO::toplevelExport.reset(); PROTO::toplevelMapping.reset(); PROTO::globalShortcuts.reset(); PROTO::xdgDialog.reset(); PROTO::singlePixel.reset(); PROTO::securityContext.reset(); PROTO::ctm.reset(); PROTO::hyprlandSurface.reset(); PROTO::contentType.reset(); PROTO::colorManagement.reset(); PROTO::xxColorManagement.reset(); PROTO::frogColorManagement.reset(); PROTO::xdgTag.reset(); PROTO::xdgBell.reset(); PROTO::lease.reset(); PROTO::sync.reset(); PROTO::mesaDRM.reset(); PROTO::linuxDma.reset(); } bool CProtocolManager::isGlobalPrivileged(const wl_global* global) { if (!global) return false; for (auto& [k, v] : PROTO::outputs) { if (global == v->getGlobal()) return false; } // this is a static whitelist of allowed protocols, // outputs are dynamic so we checked them above // clang-format off static const std::vector ALLOWED_WHITELIST = { PROTO::seat->getGlobal(), PROTO::data->getGlobal(), PROTO::compositor->getGlobal(), PROTO::subcompositor->getGlobal(), PROTO::shm->getGlobal(), PROTO::viewport->getGlobal(), PROTO::tearing->getGlobal(), PROTO::fractional->getGlobal(), PROTO::cursorShape->getGlobal(), PROTO::idleInhibit->getGlobal(), PROTO::relativePointer->getGlobal(), PROTO::xdgDecoration->getGlobal(), PROTO::alphaModifier->getGlobal(), PROTO::pointerGestures->getGlobal(), PROTO::shortcutsInhibit->getGlobal(), PROTO::textInputV1->getGlobal(), PROTO::textInputV3->getGlobal(), PROTO::constraints->getGlobal(), PROTO::activation->getGlobal(), PROTO::idle->getGlobal(), PROTO::ime->getGlobal(), PROTO::virtualKeyboard->getGlobal(), PROTO::virtualPointer->getGlobal(), PROTO::serverDecorationKDE->getGlobal(), PROTO::tablet->getGlobal(), PROTO::presentation->getGlobal(), PROTO::xdgShell->getGlobal(), PROTO::xdgDialog->getGlobal(), PROTO::singlePixel->getGlobal(), PROTO::primarySelection->getGlobal(), PROTO::hyprlandSurface->getGlobal(), PROTO::xdgTag->getGlobal(), PROTO::xdgBell->getGlobal(), PROTO::sync ? PROTO::sync->getGlobal() : nullptr, PROTO::mesaDRM ? PROTO::mesaDRM->getGlobal() : nullptr, PROTO::linuxDma ? PROTO::linuxDma->getGlobal() : nullptr, }; // clang-format on return std::ranges::find(ALLOWED_WHITELIST, global) == ALLOWED_WHITELIST.end(); }