diff options
author | vaxerski <[email protected]> | 2022-08-05 17:07:01 +0200 |
---|---|---|
committer | vaxerski <[email protected]> | 2022-08-05 17:07:01 +0200 |
commit | e0ada97a24adbe939db90c388b0d38161047f216 (patch) | |
tree | 592b55925e869ce3364e701267670ee37c0f3b43 | |
parent | 9a8a6317ff9dc7d97a0018d8d0b19cd033d2c47b (diff) | |
download | Hyprland-e0ada97a24adbe939db90c388b0d38161047f216.tar.gz Hyprland-e0ada97a24adbe939db90c388b0d38161047f216.zip |
support zwp_input_method_v2 popups
-rw-r--r-- | src/Compositor.cpp | 12 | ||||
-rw-r--r-- | src/Compositor.hpp | 1 | ||||
-rw-r--r-- | src/events/Events.hpp | 6 | ||||
-rw-r--r-- | src/helpers/WLClasses.hpp | 19 | ||||
-rw-r--r-- | src/managers/input/InputMethodRelay.cpp | 145 | ||||
-rw-r--r-- | src/managers/input/InputMethodRelay.hpp | 9 | ||||
-rw-r--r-- | src/render/Renderer.cpp | 18 | ||||
-rw-r--r-- | src/render/Renderer.hpp | 1 |
8 files changed, 211 insertions, 0 deletions
diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 96be097a..1d1dda08 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1529,3 +1529,15 @@ void CCompositor::warpCursorTo(const Vector2D& pos) { wlr_cursor_warp(m_sWLRCursor, m_sSeat.mouse->mouse, pos.x, pos.y); } +SLayerSurface* CCompositor::getLayerSurfaceFromWlr(wlr_layer_surface_v1* pLS) { + for (auto& m : m_vMonitors) { + for (auto& lsl : m->m_aLayerSurfaceLists) { + for (auto& ls : lsl) { + if (ls->layerSurface == pLS) + return ls.get(); + } + } + } + + return nullptr; +} diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 35cb76e9..0517ac1f 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -155,6 +155,7 @@ public: void addToFadingOutSafe(CWindow*); CWindow* getWindowByRegex(const std::string&); void warpCursorTo(const Vector2D&); + SLayerSurface* getLayerSurfaceFromWlr(wlr_layer_surface_v1*); std::string explicitConfigPath; diff --git a/src/events/Events.hpp b/src/events/Events.hpp index 8f969012..5cb7325c 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -138,4 +138,10 @@ namespace Events { LISTENER(newIME); LISTENER(newTextInput); LISTENER(newVirtualKeyboard); + + // IME Popups + DYNLISTENFUNC(mapInputPopup); + DYNLISTENFUNC(unmapInputPopup); + DYNLISTENFUNC(commitInputPopup); + DYNLISTENFUNC(destroyInputPopup); };
\ No newline at end of file diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index c07bf46a..31a24793 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -294,4 +294,23 @@ struct SIMEKbGrab { wlr_keyboard* pKeyboard = nullptr; DYNLISTENER(grabDestroy); +}; + +struct SIMEPopup { + wlr_input_popup_surface_v2* pSurface = nullptr; + + int x, y; + int realX, realY; + bool visible; + + DYNLISTENER(mapPopup); + DYNLISTENER(unmapPopup); + DYNLISTENER(destroyPopup); + DYNLISTENER(commitPopup); + + DYNLISTENER(focusedSurfaceUnmap); + + bool operator==(const SIMEPopup& other) { + return pSurface == other.pSurface; + } };
\ No newline at end of file diff --git a/src/managers/input/InputMethodRelay.cpp b/src/managers/input/InputMethodRelay.cpp index dc03eb89..c1800a2d 100644 --- a/src/managers/input/InputMethodRelay.cpp +++ b/src/managers/input/InputMethodRelay.cpp @@ -55,6 +55,7 @@ void CInputMethodRelay::onNewIME(wlr_input_method_v2* pIME) { hyprListener_IMEDestroy.removeCallback(); hyprListener_IMECommit.removeCallback(); hyprListener_IMEGrab.removeCallback(); + hyprListener_IMENewPopup.removeCallback(); m_pKeyboardGrab.reset(nullptr); @@ -102,6 +103,21 @@ void CInputMethodRelay::onNewIME(wlr_input_method_v2* pIME) { }, this, "IMERelay"); + hyprListener_IMENewPopup.initCallback(&m_pWLRIME->events.new_popup_surface, [&](void* owner, void* data) { + + const auto PNEWPOPUP = &m_lIMEPopups.emplace_back(); + + PNEWPOPUP->pSurface = (wlr_input_popup_surface_v2*)data; + + PNEWPOPUP->hyprListener_commitPopup.initCallback(&PNEWPOPUP->pSurface->surface->events.commit, &Events::listener_commitInputPopup, PNEWPOPUP, "IME Popup"); + PNEWPOPUP->hyprListener_mapPopup.initCallback(&PNEWPOPUP->pSurface->events.map, &Events::listener_mapInputPopup, PNEWPOPUP, "IME Popup"); + PNEWPOPUP->hyprListener_unmapPopup.initCallback(&PNEWPOPUP->pSurface->events.unmap, &Events::listener_unmapInputPopup, PNEWPOPUP, "IME Popup"); + PNEWPOPUP->hyprListener_destroyPopup.initCallback(&PNEWPOPUP->pSurface->events.destroy, &Events::listener_destroyInputPopup, PNEWPOPUP, "IME Popup"); + + Debug::log(LOG, "New input popup"); + + }, this, "IMERelay"); + const auto PTI = getFocusableTextInput(); if (PTI) { @@ -110,6 +126,131 @@ void CInputMethodRelay::onNewIME(wlr_input_method_v2* pIME) { } } +void CInputMethodRelay::updateInputPopup(SIMEPopup* pPopup) { + if (!pPopup->pSurface->mapped) + return; + + const auto PFOCUSEDTI = getFocusedTextInput(); + + if (!PFOCUSEDTI || !PFOCUSEDTI->pWlrInput->focused_surface) + return; + + bool cursorRect = PFOCUSEDTI->pWlrInput->current.features & WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE; + const auto PFOCUSEDSURFACE = PFOCUSEDTI->pWlrInput->focused_surface; + auto cursorBox = PFOCUSEDTI->pWlrInput->current.cursor_rectangle; + + Vector2D parentPos; + Vector2D parentSize; + + if (wlr_surface_is_layer_surface(PFOCUSEDSURFACE)) { + const auto PLS = g_pCompositor->getLayerSurfaceFromWlr(wlr_layer_surface_v1_from_wlr_surface(PFOCUSEDSURFACE)); + + if (PLS) { + parentPos = Vector2D(PLS->geometry.x, PLS->geometry.y) + g_pCompositor->getMonitorFromID(PLS->monitorID)->vecPosition; + parentSize = Vector2D(PLS->geometry.width, PLS->geometry.height); + } + } else { + const auto PWINDOW = g_pCompositor->getWindowFromSurface(PFOCUSEDSURFACE); + + if (PWINDOW) { + parentPos = PWINDOW->m_vRealPosition.goalv(); + parentSize = PWINDOW->m_vRealSize.goalv(); + } + } + + if (!cursorRect) { + cursorBox = {0, 0, (int)parentSize.x, (int)parentSize.y}; + } + + // todo: anti-overflow + + wlr_box finalBox = cursorBox; + + pPopup->x = finalBox.x; + pPopup->y = finalBox.y; + + pPopup->realX = finalBox.x + parentPos.x; + pPopup->realY = finalBox.y + parentPos.y; + + wlr_input_popup_surface_v2_send_text_input_rectangle(pPopup->pSurface, &finalBox); + + damagePopup(pPopup); +} + +void CInputMethodRelay::setIMEPopupFocus(SIMEPopup* pPopup, wlr_surface* pSurface) { + updateInputPopup(pPopup); +} + +void Events::listener_mapInputPopup(void* owner, void* data) { + const auto PPOPUP = (SIMEPopup*)owner; + + Debug::log(LOG, "Mapped an IME Popup"); + + g_pInputManager->m_sIMERelay.updateInputPopup(PPOPUP); +} + +void Events::listener_unmapInputPopup(void* owner, void* data) { + const auto PPOPUP = (SIMEPopup*)owner; + + Debug::log(LOG, "Unmapped an IME Popup"); + + g_pInputManager->m_sIMERelay.updateInputPopup(PPOPUP); +} + +void Events::listener_destroyInputPopup(void* owner, void* data) { + const auto PPOPUP = (SIMEPopup*)owner; + + Debug::log(LOG, "Removed an IME Popup"); + + PPOPUP->hyprListener_commitPopup.removeCallback(); + PPOPUP->hyprListener_destroyPopup.removeCallback(); + PPOPUP->hyprListener_focusedSurfaceUnmap.removeCallback(); + PPOPUP->hyprListener_mapPopup.removeCallback(); + PPOPUP->hyprListener_unmapPopup.removeCallback(); + + g_pInputManager->m_sIMERelay.removePopup(PPOPUP); +} + +void Events::listener_commitInputPopup(void* owner, void* data) { + const auto PPOPUP = (SIMEPopup*)owner; + + g_pInputManager->m_sIMERelay.updateInputPopup(PPOPUP); +} + +void CInputMethodRelay::removePopup(SIMEPopup* pPopup) { + m_lIMEPopups.remove(*pPopup); +} + +void CInputMethodRelay::damagePopup(SIMEPopup* pPopup) { + if (!pPopup->pSurface->mapped) + return; + + const auto PFOCUSEDTI = getFocusedTextInput(); + + if (!PFOCUSEDTI || !PFOCUSEDTI->pWlrInput->focused_surface) + return; + + Vector2D parentPos; + + const auto PFOCUSEDSURFACE = PFOCUSEDTI->pWlrInput->focused_surface; + + if (wlr_surface_is_layer_surface(PFOCUSEDSURFACE)) { + const auto PLS = g_pCompositor->getLayerSurfaceFromWlr(wlr_layer_surface_v1_from_wlr_surface(PFOCUSEDSURFACE)); + + if (PLS) { + parentPos = Vector2D(PLS->geometry.x, PLS->geometry.y) + g_pCompositor->getMonitorFromID(PLS->monitorID)->vecPosition; + } + } else { + const auto PWINDOW = g_pCompositor->getWindowFromSurface(PFOCUSEDSURFACE); + + if (PWINDOW) { + parentPos = PWINDOW->m_vRealPosition.goalv(); + } + } + + g_pHyprRenderer->damageSurface(pPopup->pSurface->surface, parentPos.x + pPopup->x, parentPos.y + pPopup->y); +} + SIMEKbGrab* CInputMethodRelay::getIMEKeyboardGrab(SKeyboard* pKeyboard) { if (!m_pWLRIME) @@ -249,6 +390,10 @@ void CInputMethodRelay::commitIMEState(wlr_text_input_v3* pInput) { if (pInput->active_features & WLR_TEXT_INPUT_V3_FEATURE_CONTENT_TYPE) wlr_input_method_v2_send_content_type(m_pWLRIME, pInput->current.content_type.hint, pInput->current.content_type.purpose); + for (auto& p : m_lIMEPopups) { + updateInputPopup(&p); + } + wlr_input_method_v2_send_done(m_pWLRIME); } diff --git a/src/managers/input/InputMethodRelay.hpp b/src/managers/input/InputMethodRelay.hpp index ff6fb128..1ecc5a5d 100644 --- a/src/managers/input/InputMethodRelay.hpp +++ b/src/managers/input/InputMethodRelay.hpp @@ -24,16 +24,25 @@ public: SIMEKbGrab* getIMEKeyboardGrab(SKeyboard*); + void setIMEPopupFocus(SIMEPopup*, wlr_surface*); + void updateInputPopup(SIMEPopup*); + void damagePopup(SIMEPopup*); + void removePopup(SIMEPopup*); + private: std::unique_ptr<SIMEKbGrab> m_pKeyboardGrab; std::list<STextInput> m_lTextInputs; + std::list<SIMEPopup> m_lIMEPopups; DYNLISTENER(textInputNew); DYNLISTENER(IMECommit); DYNLISTENER(IMEDestroy); DYNLISTENER(IMEGrab); + DYNLISTENER(IMENewPopup); void createNewTextInput(wlr_text_input_v3*); + + friend class CHyprRenderer; };
\ No newline at end of file diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 2f5772d5..863ea9e8 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -304,6 +304,18 @@ void CHyprRenderer::renderLayer(SLayerSurface* pLayer, CMonitor* pMonitor, times wlr_layer_surface_v1_for_each_popup_surface(pLayer->layerSurface, renderSurface, &renderdata); } +void CHyprRenderer::renderIMEPopup(SIMEPopup* pPopup, CMonitor* pMonitor, timespec* time) { + SRenderData renderdata = {pMonitor->output, time, pPopup->realX, pPopup->realY}; + + renderdata.blur = false; + renderdata.surface = pPopup->pSurface->surface; + renderdata.decorate = false; + renderdata.w = pPopup->pSurface->surface->current.width; + renderdata.h = pPopup->pSurface->surface->current.height; + + wlr_surface_for_each_surface(pPopup->pSurface->surface, renderSurface, &renderdata); +} + void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { const auto PMONITOR = g_pCompositor->getMonitorFromID(ID); @@ -403,6 +415,12 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { renderLayer(ls.get(), PMONITOR, time); } + + // Render IME popups + for (auto& imep : g_pInputManager->m_sIMERelay.m_lIMEPopups) { + renderIMEPopup(&imep, PMONITOR, time); + } + for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { renderLayer(ls.get(), PMONITOR, time); } diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 728f278d..8ed296d5 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -51,6 +51,7 @@ private: void renderWindow(CWindow*, CMonitor*, timespec*, bool, eRenderPassMode); void renderLayer(SLayerSurface*, CMonitor*, timespec*); void renderDragIcon(CMonitor*, timespec*); + void renderIMEPopup(SIMEPopup*, CMonitor*, timespec*); bool m_bHasARenderedCursor = true; |