mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-22 19:45:58 +01:00
xwayland: move to hyprland impl (#6086)
This commit is contained in:
parent
a71207434c
commit
addd3e7f1a
36 changed files with 2956 additions and 707 deletions
|
@ -315,6 +315,7 @@ protocolNew("stable/tablet" "tablet-v2" false)
|
|||
protocolNew("stable/presentation-time" "presentation-time" false)
|
||||
protocolNew("stable/xdg-shell" "xdg-shell" false)
|
||||
protocolNew("unstable/primary-selection" "primary-selection-unstable-v1" false)
|
||||
protocolNew("staging/xwayland-shell" "xwayland-shell-v1" false)
|
||||
|
||||
protocolWayland()
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@ new_protocols = [
|
|||
[wl_protocol_dir, 'stable/presentation-time/presentation-time.xml'],
|
||||
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
|
||||
[wl_protocol_dir, 'unstable/primary-selection/primary-selection-unstable-v1.xml'],
|
||||
[wl_protocol_dir, 'staging/xwayland-shell/xwayland-shell-v1.xml'],
|
||||
]
|
||||
|
||||
wl_protos_src = []
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "protocols/LayerShell.hpp"
|
||||
#include "protocols/XDGShell.hpp"
|
||||
#include "desktop/LayerSurface.hpp"
|
||||
#include "xwayland/XWayland.hpp"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
@ -332,12 +333,9 @@ void CCompositor::cleanup() {
|
|||
m->state.commit();
|
||||
}
|
||||
|
||||
m_vMonitors.clear();
|
||||
g_pXWayland.reset();
|
||||
|
||||
if (g_pXWaylandManager->m_sWLRXWayland) {
|
||||
wlr_xwayland_destroy(g_pXWaylandManager->m_sWLRXWayland);
|
||||
g_pXWaylandManager->m_sWLRXWayland = nullptr;
|
||||
}
|
||||
m_vMonitors.clear();
|
||||
|
||||
wl_display_destroy_clients(g_pCompositor->m_sWLDisplay);
|
||||
removeAllSignals();
|
||||
|
@ -462,6 +460,9 @@ void CCompositor::initManagers(eManagersInitStage stage) {
|
|||
|
||||
Debug::log(LOG, "Creating the CursorManager!");
|
||||
g_pCursorManager = std::make_unique<CCursorManager>();
|
||||
|
||||
Debug::log(LOG, "Starting XWayland");
|
||||
g_pXWayland = std::make_unique<CXWayland>();
|
||||
} break;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
|
@ -669,7 +670,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
|
|||
if (properties & ALLOW_FLOATING) {
|
||||
for (auto& w : m_vWindows | std::views::reverse) {
|
||||
const auto BB = w->getWindowBoxUnified(properties);
|
||||
CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
|
||||
CBox box = BB.copy().expand(w->m_iX11Type == 2 ? BORDER_GRAB_AREA : 0);
|
||||
if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sAdditionalConfigData.noFocus && w != pIgnoreWindow) {
|
||||
if (box.containsPoint(g_pPointerManager->position()))
|
||||
return w;
|
||||
|
@ -698,7 +699,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
|
|||
BB.x + BB.width <= PWINDOWMONITOR->vecPosition.x + PWINDOWMONITOR->vecSize.x && BB.y + BB.height <= PWINDOWMONITOR->vecPosition.y + PWINDOWMONITOR->vecSize.y)
|
||||
continue;
|
||||
|
||||
CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
|
||||
CBox box = BB.copy().expand(w->m_iX11Type == 2 ? BORDER_GRAB_AREA : 0);
|
||||
if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_pWorkspace) && !w->isHidden() && !w->m_bPinned && !w->m_sAdditionalConfigData.noFocus &&
|
||||
w != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) {
|
||||
// OR windows should add focus to parent
|
||||
|
@ -707,7 +708,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
|
|||
|
||||
if (box.containsPoint(g_pPointerManager->position())) {
|
||||
|
||||
if (w->m_bIsX11 && w->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(w->m_uSurface.xwayland)) {
|
||||
if (w->m_bIsX11 && w->m_iX11Type == 2 && !w->m_pXWaylandSurface->wantsFocus()) {
|
||||
// Override Redirect
|
||||
return g_pCompositor->m_pLastWindow.lock(); // we kinda trick everything here.
|
||||
// TODO: this is wrong, we should focus the parent, but idk how to get it considering it's nullptr in most cases.
|
||||
|
@ -892,7 +893,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (pWindow && pWindow->m_bIsX11 && pWindow->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(pWindow->m_uSurface.xwayland))
|
||||
if (pWindow && pWindow->m_bIsX11 && pWindow->m_iX11Type == 2 && !pWindow->m_pXWaylandSurface->wantsFocus())
|
||||
return;
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->bringWindowToTop(pWindow);
|
||||
|
@ -1273,10 +1274,9 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) {
|
|||
if (top)
|
||||
pWindow->m_bCreatedOverFullscreen = true;
|
||||
|
||||
if (!pWindow->m_bIsX11) {
|
||||
if (!pWindow->m_bIsX11)
|
||||
moveToZ(pWindow, top);
|
||||
return;
|
||||
} else {
|
||||
else {
|
||||
// move X11 window stack
|
||||
|
||||
std::deque<PHLWINDOW> toMove;
|
||||
|
@ -1288,7 +1288,7 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) {
|
|||
toMove.emplace_front(pw);
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsX11 && w->X11TransientFor() == pw) {
|
||||
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsX11 && w->X11TransientFor() == pw && w != pw && std::find(toMove.begin(), toMove.end(), w) == toMove.end()) {
|
||||
x11Stack(w, top, x11Stack);
|
||||
}
|
||||
}
|
||||
|
@ -2226,7 +2226,7 @@ PHLWINDOW CCompositor::getX11Parent(PHLWINDOW pWindow) {
|
|||
if (!w->m_bIsX11)
|
||||
continue;
|
||||
|
||||
if (w->m_uSurface.xwayland == pWindow->m_uSurface.xwayland->parent)
|
||||
if (w->m_pXWaylandSurface == pWindow->m_pXWaylandSurface->parent)
|
||||
return w;
|
||||
}
|
||||
|
||||
|
|
|
@ -189,21 +189,3 @@ class CCompositor {
|
|||
};
|
||||
|
||||
inline std::unique_ptr<CCompositor> g_pCompositor;
|
||||
|
||||
// For XWayland
|
||||
inline std::map<std::string, xcb_atom_t> HYPRATOMS = {HYPRATOM("_NET_WM_WINDOW_TYPE"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_NORMAL"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_DOCK"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_DIALOG"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_UTILITY"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_TOOLBAR"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_SPLASH"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_MENU"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_POPUP_MENU"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_TOOLTIP"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_NOTIFICATION"),
|
||||
HYPRATOM("_KDE_NET_WM_WINDOW_TYPE_OVERRIDE"),
|
||||
HYPRATOM("_NET_SUPPORTING_WM_CHECK"),
|
||||
HYPRATOM("_NET_WM_NAME"),
|
||||
HYPRATOM("UTF8_STRING")};
|
||||
|
|
|
@ -7,11 +7,14 @@
|
|||
#include <any>
|
||||
#include "../managers/TokenManager.hpp"
|
||||
#include "../protocols/XDGShell.hpp"
|
||||
#include "../xwayland/XWayland.hpp"
|
||||
|
||||
PHLWINDOW CWindow::create() {
|
||||
PHLWINDOW pWindow = SP<CWindow>(new CWindow);
|
||||
PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) {
|
||||
PHLWINDOW pWindow = SP<CWindow>(new CWindow(surface));
|
||||
|
||||
pWindow->m_pSelf = pWindow;
|
||||
pWindow->m_pSelf = pWindow;
|
||||
pWindow->m_bIsX11 = true;
|
||||
pWindow->m_iX11Type = surface->overrideRedirect ? 2 : 1;
|
||||
|
||||
pWindow->m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
pWindow->m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
|
||||
|
@ -61,8 +64,19 @@ CWindow::CWindow(SP<CXDGSurfaceResource> resource) : m_pXDGSurface(resource) {
|
|||
listeners.updateMetadata = m_pXDGSurface->toplevel->events.metadataChanged.registerListener([this](std::any d) { onUpdateMeta(); });
|
||||
}
|
||||
|
||||
CWindow::CWindow() {
|
||||
;
|
||||
CWindow::CWindow(SP<CXWaylandSurface> surface) : m_pXWaylandSurface(surface) {
|
||||
listeners.map = m_pXWaylandSurface->events.map.registerListener([this](std::any d) { Events::listener_mapWindow(this, nullptr); });
|
||||
listeners.unmap = m_pXWaylandSurface->events.unmap.registerListener([this](std::any d) { Events::listener_unmapWindow(this, nullptr); });
|
||||
listeners.destroy = m_pXWaylandSurface->events.destroy.registerListener([this](std::any d) { Events::listener_destroyWindow(this, nullptr); });
|
||||
listeners.commit = m_pXWaylandSurface->events.commit.registerListener([this](std::any d) { Events::listener_commitWindow(this, nullptr); });
|
||||
listeners.configure = m_pXWaylandSurface->events.configure.registerListener([this](std::any d) { onX11Configure(std::any_cast<CBox>(d)); });
|
||||
listeners.updateState = m_pXWaylandSurface->events.stateChanged.registerListener([this](std::any d) { onUpdateState(); });
|
||||
listeners.updateMetadata = m_pXWaylandSurface->events.metadataChanged.registerListener([this](std::any d) { onUpdateMeta(); });
|
||||
listeners.resourceChange = m_pXWaylandSurface->events.resourceChange.registerListener([this](std::any d) { onResourceChangeX11(); });
|
||||
listeners.activate = m_pXWaylandSurface->events.activate.registerListener([this](std::any d) { Events::listener_activateX11(this, nullptr); });
|
||||
|
||||
if (m_pXWaylandSurface->overrideRedirect)
|
||||
listeners.setGeometry = m_pXWaylandSurface->events.setGeometry.registerListener([this](std::any d) { Events::listener_unmanagedSetGeometry(this, nullptr); });
|
||||
}
|
||||
|
||||
CWindow::~CWindow() {
|
||||
|
@ -300,10 +314,10 @@ pid_t CWindow::getPID() {
|
|||
|
||||
wl_client_get_credentials(m_pXDGSurface->owner->client(), &PID, nullptr, nullptr);
|
||||
} else {
|
||||
if (!m_uSurface.xwayland)
|
||||
if (!m_pXWaylandSurface)
|
||||
return -1;
|
||||
|
||||
PID = m_uSurface.xwayland->pid;
|
||||
PID = m_pXWaylandSurface->pid;
|
||||
}
|
||||
|
||||
return PID;
|
||||
|
@ -426,22 +440,23 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
}
|
||||
|
||||
PHLWINDOW CWindow::X11TransientFor() {
|
||||
if (!m_bIsX11)
|
||||
if (!m_pXWaylandSurface || !m_pXWaylandSurface->parent)
|
||||
return nullptr;
|
||||
|
||||
if (!m_uSurface.xwayland->parent)
|
||||
return nullptr;
|
||||
|
||||
auto PPARENT = g_pCompositor->getWindowFromSurface(m_uSurface.xwayland->parent->surface);
|
||||
|
||||
while (validMapped(PPARENT) && PPARENT->m_uSurface.xwayland->parent) {
|
||||
PPARENT = g_pCompositor->getWindowFromSurface(PPARENT->m_uSurface.xwayland->parent->surface);
|
||||
auto s = m_pXWaylandSurface->parent;
|
||||
while (s) {
|
||||
if (!s->parent)
|
||||
break;
|
||||
s = s->parent;
|
||||
}
|
||||
|
||||
if (!validMapped(PPARENT))
|
||||
return nullptr;
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_pXWaylandSurface != s)
|
||||
continue;
|
||||
return w;
|
||||
}
|
||||
|
||||
return PPARENT;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CWindow::removeDecorationByType(eDecorationType type) {
|
||||
|
@ -494,8 +509,6 @@ void CWindow::onUnmap() {
|
|||
|
||||
std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other.expired() || other.lock().get() == this; });
|
||||
|
||||
hyprListener_unmapWindow.removeCallback();
|
||||
|
||||
if (*PCLOSEONLASTSPECIAL && g_pCompositor->getWindowsOnWorkspace(workspaceID()) == 0 && onSpecialWorkspace()) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
if (PMONITOR && PMONITOR->activeSpecialWorkspace && PMONITOR->activeSpecialWorkspace == m_pWorkspace)
|
||||
|
@ -548,9 +561,6 @@ void CWindow::onMap() {
|
|||
|
||||
g_pCompositor->m_vWindowFocusHistory.push_back(m_pSelf);
|
||||
|
||||
if (m_bIsX11)
|
||||
hyprListener_unmapWindow.initCallback(&m_uSurface.xwayland->surface->events.unmap, &Events::listener_unmapWindow, this, "CWindow");
|
||||
|
||||
m_vReportedSize = m_vPendingReportedSize;
|
||||
m_bAnimatingIn = true;
|
||||
|
||||
|
@ -1119,9 +1129,9 @@ bool CWindow::opaque() {
|
|||
return false;
|
||||
|
||||
if (m_bIsX11)
|
||||
return !m_uSurface.xwayland->has_alpha;
|
||||
return false;
|
||||
|
||||
if (m_pXDGSurface->surface->opaque)
|
||||
if (m_pXDGSurface && m_pXDGSurface->surface->opaque)
|
||||
return true;
|
||||
|
||||
const auto EXTENTS = pixman_region32_extents(&m_pXDGSurface->surface->opaque_region);
|
||||
|
@ -1337,23 +1347,23 @@ void CWindow::activate(bool force) {
|
|||
}
|
||||
|
||||
void CWindow::onUpdateState() {
|
||||
if (!m_pXDGSurface)
|
||||
return;
|
||||
std::optional<bool> requestsFS = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsFullscreen : m_pXWaylandSurface->state.requestsFullscreen;
|
||||
std::optional<bool> requestsMX = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsMaximize : m_pXWaylandSurface->state.requestsMaximize;
|
||||
|
||||
if (m_pXDGSurface->toplevel->state.requestsFullscreen && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) {
|
||||
bool fs = m_pXDGSurface->toplevel->state.requestsFullscreen.value();
|
||||
if (requestsFS.has_value() && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) {
|
||||
bool fs = requestsFS.value();
|
||||
|
||||
if (fs != m_bIsFullscreen && m_pXDGSurface->mapped)
|
||||
if (fs != m_bIsFullscreen && m_bIsMapped)
|
||||
g_pCompositor->setWindowFullscreen(m_pSelf.lock(), fs, FULLSCREEN_FULL);
|
||||
|
||||
if (!m_pXDGSurface->mapped)
|
||||
if (!m_bIsMapped)
|
||||
m_bWantsInitialFullscreen = fs;
|
||||
}
|
||||
|
||||
if (m_pXDGSurface->toplevel->state.requestsMaximize && !(m_eSuppressedEvents & SUPPRESS_MAXIMIZE)) {
|
||||
bool fs = m_pXDGSurface->toplevel->state.requestsMaximize.value();
|
||||
if (requestsMX.has_value() && !(m_eSuppressedEvents & SUPPRESS_MAXIMIZE)) {
|
||||
bool fs = requestsMX.value();
|
||||
|
||||
if (fs != m_bIsFullscreen && m_pXDGSurface->mapped)
|
||||
if (fs != m_bIsFullscreen && m_bIsMapped)
|
||||
g_pCompositor->setWindowFullscreen(m_pSelf.lock(), fs, FULLSCREEN_MAXIMIZED);
|
||||
}
|
||||
}
|
||||
|
@ -1402,8 +1412,8 @@ std::string CWindow::fetchTitle() {
|
|||
if (m_pXDGSurface && m_pXDGSurface->toplevel)
|
||||
return m_pXDGSurface->toplevel->state.title;
|
||||
} else {
|
||||
if (m_uSurface.xwayland && m_uSurface.xwayland->title)
|
||||
return m_uSurface.xwayland->title;
|
||||
if (m_pXWaylandSurface)
|
||||
return m_pXWaylandSurface->state.title;
|
||||
}
|
||||
|
||||
return "";
|
||||
|
@ -1414,8 +1424,8 @@ std::string CWindow::fetchClass() {
|
|||
if (m_pXDGSurface && m_pXDGSurface->toplevel)
|
||||
return m_pXDGSurface->toplevel->state.appid;
|
||||
} else {
|
||||
if (m_uSurface.xwayland && m_uSurface.xwayland->_class)
|
||||
return m_uSurface.xwayland->_class;
|
||||
if (m_pXWaylandSurface)
|
||||
return m_pXWaylandSurface->state.appid;
|
||||
}
|
||||
|
||||
return "";
|
||||
|
@ -1430,3 +1440,79 @@ void CWindow::onAck(uint32_t serial) {
|
|||
m_pPendingSizeAck = *SERIAL;
|
||||
std::erase_if(m_vPendingSizeAcks, [&](const auto& el) { return el.first <= SERIAL->first; });
|
||||
}
|
||||
|
||||
void CWindow::onResourceChangeX11() {
|
||||
if (m_pXWaylandSurface->surface && !m_pWLSurface.wlr())
|
||||
m_pWLSurface.assign(m_pXWaylandSurface->surface, m_pSelf.lock());
|
||||
else if (!m_pXWaylandSurface->surface && m_pWLSurface.wlr())
|
||||
m_pWLSurface.unassign();
|
||||
|
||||
// update metadata as well,
|
||||
// could be first assoc and we need to catch the class
|
||||
onUpdateMeta();
|
||||
|
||||
Debug::log(LOG, "xwayland window {:x} -> association to {:x}", (uintptr_t)m_pXWaylandSurface.get(), (uintptr_t)m_pWLSurface.wlr());
|
||||
}
|
||||
|
||||
void CWindow::onX11Configure(CBox box) {
|
||||
|
||||
if (!m_pXWaylandSurface->surface || !m_pXWaylandSurface->mapped || !m_bIsMapped) {
|
||||
m_pXWaylandSurface->configure(box);
|
||||
m_vPendingReportedSize = box.size();
|
||||
m_vReportedSize = box.size();
|
||||
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR)
|
||||
m_fX11SurfaceScaledBy = PMONITOR->scale;
|
||||
return;
|
||||
}
|
||||
|
||||
g_pHyprRenderer->damageWindow(m_pSelf.lock());
|
||||
|
||||
if (!m_bIsFloating || m_bIsFullscreen || g_pInputManager->currentlyDraggedWindow == m_pSelf) {
|
||||
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal(), true);
|
||||
g_pInputManager->refocus();
|
||||
g_pHyprRenderer->damageWindow(m_pSelf.lock());
|
||||
return;
|
||||
}
|
||||
|
||||
if (box.size() > Vector2D{1, 1})
|
||||
setHidden(false);
|
||||
else
|
||||
setHidden(true);
|
||||
|
||||
const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords(box.pos());
|
||||
|
||||
m_vRealPosition.setValueAndWarp(LOGICALPOS);
|
||||
m_vRealSize.setValueAndWarp(box.size());
|
||||
|
||||
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
|
||||
if (*PXWLFORCESCALEZERO) {
|
||||
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) {
|
||||
m_vRealSize.setValueAndWarp(m_vRealSize.goal() / PMONITOR->scale);
|
||||
m_fX11SurfaceScaledBy = PMONITOR->scale;
|
||||
}
|
||||
}
|
||||
|
||||
m_vPosition = m_vRealPosition.value();
|
||||
m_vSize = m_vRealSize.value();
|
||||
|
||||
m_pXWaylandSurface->configure(box);
|
||||
|
||||
m_vPendingReportedSize = box.size();
|
||||
m_vReportedSize = box.size();
|
||||
|
||||
updateWindowDecos();
|
||||
|
||||
if (!g_pCompositor->isWorkspaceVisible(m_pWorkspace))
|
||||
return; // further things are only for visible windows
|
||||
|
||||
m_pWorkspace = g_pCompositor->getMonitorFromVector(m_vRealPosition.value() + m_vRealSize.value() / 2.f)->activeWorkspace;
|
||||
|
||||
g_pCompositor->changeWindowZOrder(m_pSelf.lock(), true);
|
||||
|
||||
m_bCreatedOverFullscreen = true;
|
||||
|
||||
if (!m_sAdditionalConfigData.windowDanceCompat)
|
||||
g_pInputManager->refocus();
|
||||
|
||||
g_pHyprRenderer->damageWindow(m_pSelf.lock());
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "../helpers/signal/Signal.hpp"
|
||||
|
||||
class CXDGSurfaceResource;
|
||||
class CXWaylandSurface;
|
||||
|
||||
enum eIdleInhibitMode {
|
||||
IDLEINHIBIT_NONE = 0,
|
||||
|
@ -199,48 +200,23 @@ struct SInitialWorkspaceToken {
|
|||
class CWindow {
|
||||
public:
|
||||
static PHLWINDOW create(SP<CXDGSurfaceResource>);
|
||||
// xwl
|
||||
static PHLWINDOW create();
|
||||
static PHLWINDOW create(SP<CXWaylandSurface>);
|
||||
|
||||
private:
|
||||
CWindow(SP<CXDGSurfaceResource> resource);
|
||||
CWindow();
|
||||
CWindow(SP<CXWaylandSurface> surface);
|
||||
|
||||
public:
|
||||
~CWindow();
|
||||
|
||||
DYNLISTENER(commitWindow);
|
||||
DYNLISTENER(mapWindow);
|
||||
DYNLISTENER(unmapWindow);
|
||||
DYNLISTENER(destroyWindow);
|
||||
DYNLISTENER(setTitleWindow);
|
||||
DYNLISTENER(setGeometryX11U);
|
||||
DYNLISTENER(fullscreenWindow);
|
||||
DYNLISTENER(requestMove);
|
||||
DYNLISTENER(requestMinimize);
|
||||
DYNLISTENER(requestMaximize);
|
||||
DYNLISTENER(requestResize);
|
||||
DYNLISTENER(activateX11);
|
||||
DYNLISTENER(configureX11);
|
||||
DYNLISTENER(toplevelClose);
|
||||
DYNLISTENER(toplevelActivate);
|
||||
DYNLISTENER(toplevelFullscreen);
|
||||
DYNLISTENER(setOverrideRedirect);
|
||||
DYNLISTENER(associateX11);
|
||||
DYNLISTENER(dissociateX11);
|
||||
DYNLISTENER(ackConfigure);
|
||||
// DYNLISTENER(newSubsurfaceWindow);
|
||||
|
||||
CWLSurface m_pWLSurface;
|
||||
|
||||
struct {
|
||||
CSignal destroy;
|
||||
} events;
|
||||
|
||||
union {
|
||||
wlr_xwayland_surface* xwayland;
|
||||
} m_uSurface;
|
||||
WP<CXDGSurfaceResource> m_pXDGSurface;
|
||||
WP<CXWaylandSurface> m_pXWaylandSurface;
|
||||
|
||||
// this is the position and size of the "bounding box"
|
||||
Vector2D m_vPosition = Vector2D(0, 0);
|
||||
|
@ -391,7 +367,7 @@ class CWindow {
|
|||
|
||||
// For the list lookup
|
||||
bool operator==(const CWindow& rhs) {
|
||||
return m_pXDGSurface == rhs.m_pXDGSurface && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
|
||||
return m_pXDGSurface == rhs.m_pXDGSurface && m_pXWaylandSurface == rhs.m_pXWaylandSurface && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
|
||||
m_bFadingOut == rhs.m_bFadingOut;
|
||||
}
|
||||
|
||||
|
@ -459,6 +435,8 @@ class CWindow {
|
|||
void onWorkspaceAnimUpdate();
|
||||
void onUpdateState();
|
||||
void onUpdateMeta();
|
||||
void onX11Configure(CBox box);
|
||||
void onResourceChangeX11();
|
||||
std::string fetchTitle();
|
||||
std::string fetchClass();
|
||||
|
||||
|
@ -478,8 +456,12 @@ class CWindow {
|
|||
CHyprSignalListener unmap;
|
||||
CHyprSignalListener commit;
|
||||
CHyprSignalListener destroy;
|
||||
CHyprSignalListener activate;
|
||||
CHyprSignalListener configure;
|
||||
CHyprSignalListener setGeometry;
|
||||
CHyprSignalListener updateState;
|
||||
CHyprSignalListener updateMetadata;
|
||||
CHyprSignalListener resourceChange;
|
||||
} listeners;
|
||||
|
||||
private:
|
||||
|
|
|
@ -33,8 +33,6 @@ namespace Events {
|
|||
DYNLISTENFUNC(requestMinimize);
|
||||
DYNLISTENFUNC(requestMaximize);
|
||||
DYNLISTENFUNC(setOverrideRedirect);
|
||||
DYNLISTENFUNC(associateX11);
|
||||
DYNLISTENFUNC(dissociateX11);
|
||||
DYNLISTENFUNC(ackConfigure);
|
||||
|
||||
LISTENER(newInput);
|
||||
|
@ -56,7 +54,6 @@ namespace Events {
|
|||
DYNLISTENFUNC(monitorBind);
|
||||
|
||||
// XWayland
|
||||
LISTENER(readyXWayland);
|
||||
LISTENER(surfaceXWayland);
|
||||
|
||||
// Renderer destroy
|
||||
|
|
|
@ -25,50 +25,6 @@ void Events::listener_leaseRequest(wl_listener* listener, void* data) {
|
|||
}
|
||||
}
|
||||
|
||||
void Events::listener_readyXWayland(wl_listener* listener, void* data) {
|
||||
#ifndef NO_XWAYLAND
|
||||
const auto XCBCONNECTION = xcb_connect(g_pXWaylandManager->m_sWLRXWayland->display_name, NULL);
|
||||
const auto ERR = xcb_connection_has_error(XCBCONNECTION);
|
||||
if (ERR) {
|
||||
Debug::log(LogLevel::ERR, "XWayland -> xcb_connection_has_error failed with {}", ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& ATOM : HYPRATOMS) {
|
||||
xcb_intern_atom_cookie_t cookie = xcb_intern_atom(XCBCONNECTION, 0, ATOM.first.length(), ATOM.first.c_str());
|
||||
xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(XCBCONNECTION, cookie, NULL);
|
||||
|
||||
if (!reply) {
|
||||
Debug::log(LogLevel::ERR, "XWayland -> Atom failed: {}", ATOM.first);
|
||||
continue;
|
||||
}
|
||||
|
||||
ATOM.second = reply->atom;
|
||||
|
||||
free(reply);
|
||||
}
|
||||
|
||||
//wlr_xwayland_set_seat(g_pXWaylandManager->m_sWLRXWayland, g_pCompositor->m_sSeat.seat);
|
||||
|
||||
g_pCursorManager->setXWaylandCursor(g_pXWaylandManager->m_sWLRXWayland);
|
||||
|
||||
const auto ROOT = xcb_setup_roots_iterator(xcb_get_setup(XCBCONNECTION)).data->root;
|
||||
auto cookie = xcb_get_property(XCBCONNECTION, 0, ROOT, HYPRATOMS["_NET_SUPPORTING_WM_CHECK"], XCB_ATOM_ANY, 0, 2048);
|
||||
auto reply = xcb_get_property_reply(XCBCONNECTION, cookie, nullptr);
|
||||
|
||||
const auto XWMWINDOW = *(xcb_window_t*)xcb_get_property_value(reply);
|
||||
const char* name = "Hyprland";
|
||||
|
||||
xcb_change_property(wlr_xwayland_get_xwm_connection(g_pXWaylandManager->m_sWLRXWayland), XCB_PROP_MODE_REPLACE, XWMWINDOW, HYPRATOMS["_NET_WM_NAME"], HYPRATOMS["UTF8_STRING"],
|
||||
8, // format
|
||||
strlen(name), name);
|
||||
|
||||
free(reply);
|
||||
|
||||
xcb_disconnect(XCBCONNECTION);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Events::listener_RendererDestroy(wl_listener* listener, void* data) {
|
||||
Debug::log(LOG, "!!Renderer destroyed!!");
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "../config/ConfigValue.hpp"
|
||||
#include "../protocols/LayerShell.hpp"
|
||||
#include "../protocols/XDGShell.hpp"
|
||||
#include "../xwayland/XSurface.hpp"
|
||||
|
||||
// ------------------------------------------------------------ //
|
||||
// __ _______ _ _ _____ ______ _______ //
|
||||
|
@ -20,19 +21,6 @@
|
|||
// //
|
||||
// ------------------------------------------------------------ //
|
||||
|
||||
void addViewCoords(void* pWindow, int* x, int* y) {
|
||||
const auto PWINDOW = (CWindow*)pWindow;
|
||||
*x += PWINDOW->m_vRealPosition.goal().x;
|
||||
*y += PWINDOW->m_vRealPosition.goal().y;
|
||||
|
||||
if (!PWINDOW->m_bIsX11 && PWINDOW->m_bIsMapped) {
|
||||
Vector2D pos = PWINDOW->m_pXDGSurface->current.geometry.pos();
|
||||
|
||||
*x -= pos.x;
|
||||
*y -= pos.y;
|
||||
}
|
||||
}
|
||||
|
||||
void setAnimToMove(void* data) {
|
||||
auto* const PANIMCFG = g_pConfigManager->getAnimationPropertyConfig("windowsMove");
|
||||
|
||||
|
@ -68,7 +56,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
|||
PWINDOW->m_bReadyToDelete = false;
|
||||
PWINDOW->m_bFadingOut = false;
|
||||
PWINDOW->m_szTitle = PWINDOW->fetchTitle();
|
||||
PWINDOW->m_iX11Type = PWINDOW->m_bIsX11 ? (PWINDOW->m_uSurface.xwayland->override_redirect ? 2 : 1) : 1;
|
||||
PWINDOW->m_bFirstMap = true;
|
||||
PWINDOW->m_szInitialTitle = PWINDOW->m_szTitle;
|
||||
PWINDOW->m_szInitialClass = PWINDOW->fetchClass();
|
||||
|
@ -129,8 +116,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
|||
PWINDOW->m_bRequestsFloat = true;
|
||||
}
|
||||
|
||||
PWINDOW->m_bX11ShouldntFocus =
|
||||
PWINDOW->m_bX11ShouldntFocus || (PWINDOW->m_bIsX11 && PWINDOW->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland));
|
||||
PWINDOW->m_bX11ShouldntFocus = PWINDOW->m_bX11ShouldntFocus || (PWINDOW->m_bIsX11 && PWINDOW->m_iX11Type == 2 && !PWINDOW->m_pXWaylandSurface->wantsFocus());
|
||||
|
||||
if (PWORKSPACE->m_bDefaultFloating)
|
||||
PWINDOW->m_bIsFloating = true;
|
||||
|
@ -144,7 +130,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
|||
|
||||
// window rules
|
||||
PWINDOW->m_vMatchedRules = g_pConfigManager->getMatchingRules(PWINDOW, false);
|
||||
bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xwayland->fullscreen);
|
||||
bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->fullscreen);
|
||||
bool requestsFakeFullscreen = false;
|
||||
bool requestsMaximize = false;
|
||||
bool overridingNoFullscreen = false;
|
||||
|
@ -492,9 +478,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
|||
}
|
||||
|
||||
if (!PWINDOW->m_sAdditionalConfigData.noFocus && !PWINDOW->m_bNoInitialFocus &&
|
||||
(PWINDOW->m_iX11Type != 2 ||
|
||||
(PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xwayland->window_type_len > 0 && wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))) &&
|
||||
!workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) && !g_pInputManager->isConstrained()) {
|
||||
(PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->wantsFocus())) && !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) &&
|
||||
!g_pInputManager->isConstrained()) {
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA);
|
||||
PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sAdditionalConfigData.forceNoDim ? 0.f : *PDIMSTRENGTH);
|
||||
|
@ -503,22 +488,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
|||
PWINDOW->m_fDimPercent.setValueAndWarp(0);
|
||||
}
|
||||
|
||||
if (PWINDOW->m_bIsX11) {
|
||||
PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW.get(),
|
||||
"XWayland Window Late");
|
||||
PWINDOW->hyprListener_activateX11.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_activate, &Events::listener_activateX11, PWINDOW.get(),
|
||||
"XWayland Window Late");
|
||||
PWINDOW->hyprListener_setTitleWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.set_title, &Events::listener_setTitleWindow, PWINDOW.get(), "XWayland Window Late");
|
||||
PWINDOW->hyprListener_requestMinimize.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_minimize, &Events::listener_requestMinimize, PWINDOW.get(),
|
||||
"Xwayland Window Late");
|
||||
PWINDOW->hyprListener_requestMaximize.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_maximize, &Events::listener_requestMaximize, PWINDOW.get(),
|
||||
"Xwayland Window Late");
|
||||
|
||||
if (PWINDOW->m_iX11Type == 2)
|
||||
PWINDOW->hyprListener_setGeometryX11U.initCallback(&PWINDOW->m_uSurface.xwayland->events.set_geometry, &Events::listener_unmanagedSetGeometry, PWINDOW.get(),
|
||||
"XWayland Window Late");
|
||||
}
|
||||
|
||||
if ((requestsFullscreen && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN) || overridingNoFullscreen)) ||
|
||||
(requestsMaximize && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) || overridingNoMaximize)) || requestsFakeFullscreen) {
|
||||
// fix fullscreen on requested (basically do a switcheroo)
|
||||
|
@ -687,16 +656,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
|||
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->onWindowUnmap(PWINDOW);
|
||||
|
||||
if (!PWINDOW->m_bIsX11) {
|
||||
Debug::log(LOG, "Unregistered late callbacks XWL");
|
||||
PWINDOW->hyprListener_fullscreenWindow.removeCallback();
|
||||
PWINDOW->hyprListener_activateX11.removeCallback();
|
||||
PWINDOW->hyprListener_setTitleWindow.removeCallback();
|
||||
PWINDOW->hyprListener_setGeometryX11U.removeCallback();
|
||||
PWINDOW->hyprListener_requestMaximize.removeCallback();
|
||||
PWINDOW->hyprListener_requestMinimize.removeCallback();
|
||||
}
|
||||
|
||||
if (PWINDOW->m_bIsFullscreen)
|
||||
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL);
|
||||
|
||||
|
@ -859,9 +818,6 @@ void Events::listener_destroyWindow(void* owner, void* data) {
|
|||
|
||||
Debug::log(LOG, "{:c} destroyed, queueing.", PWINDOW);
|
||||
|
||||
if (PWINDOW->m_bIsX11)
|
||||
Debug::log(LOG, "XWayland class raw: {}", PWINDOW->m_uSurface.xwayland->_class ? PWINDOW->m_uSurface.xwayland->_class : "null");
|
||||
|
||||
if (PWINDOW == g_pCompositor->m_pLastWindow.lock()) {
|
||||
g_pCompositor->m_pLastWindow.reset();
|
||||
g_pCompositor->m_pLastFocus = nullptr;
|
||||
|
@ -869,15 +825,6 @@ void Events::listener_destroyWindow(void* owner, void* data) {
|
|||
|
||||
PWINDOW->m_pWLSurface.unassign();
|
||||
|
||||
PWINDOW->hyprListener_commitWindow.removeCallback();
|
||||
PWINDOW->hyprListener_mapWindow.removeCallback();
|
||||
PWINDOW->hyprListener_unmapWindow.removeCallback();
|
||||
PWINDOW->hyprListener_destroyWindow.removeCallback();
|
||||
PWINDOW->hyprListener_configureX11.removeCallback();
|
||||
PWINDOW->hyprListener_setOverrideRedirect.removeCallback();
|
||||
PWINDOW->hyprListener_associateX11.removeCallback();
|
||||
PWINDOW->hyprListener_dissociateX11.removeCallback();
|
||||
|
||||
PWINDOW->listeners = {};
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW);
|
||||
|
@ -901,39 +848,6 @@ void Events::listener_setTitleWindow(void* owner, void* data) {
|
|||
PWINDOW->onUpdateMeta();
|
||||
}
|
||||
|
||||
void Events::listener_fullscreenWindow(void* owner, void* data) {
|
||||
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
|
||||
|
||||
// x11 only
|
||||
|
||||
if (!PWINDOW->m_bIsMapped) {
|
||||
PWINDOW->m_bWantsInitialFullscreen = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (PWINDOW->isHidden() || (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN))
|
||||
return;
|
||||
|
||||
bool requestedFullState = false;
|
||||
|
||||
if (!PWINDOW->m_uSurface.xwayland->surface->mapped)
|
||||
return;
|
||||
|
||||
if (!PWINDOW->m_bFakeFullscreenState)
|
||||
g_pCompositor->setWindowFullscreen(PWINDOW, PWINDOW->m_uSurface.xwayland->fullscreen, FULLSCREEN_FULL);
|
||||
|
||||
requestedFullState = PWINDOW->m_uSurface.xwayland->fullscreen;
|
||||
|
||||
if (!requestedFullState && PWINDOW->m_bFakeFullscreenState) {
|
||||
g_pXWaylandManager->setWindowFullscreen(PWINDOW, false); // fixes for apps expecting a de-fullscreen (e.g. ff)
|
||||
g_pXWaylandManager->setWindowFullscreen(PWINDOW, true);
|
||||
}
|
||||
|
||||
PWINDOW->updateToplevel();
|
||||
|
||||
Debug::log(LOG, "{} fullscreen to {}", PWINDOW, PWINDOW->m_bIsFullscreen);
|
||||
}
|
||||
|
||||
void Events::listener_activateX11(void* owner, void* data) {
|
||||
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
|
||||
|
||||
|
@ -946,7 +860,7 @@ void Events::listener_activateX11(void* owner, void* data) {
|
|||
if (g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->getPID() != PWINDOW->getPID())
|
||||
return;
|
||||
|
||||
if (!wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))
|
||||
if (!PWINDOW->m_pXWaylandSurface->wantsFocus())
|
||||
return;
|
||||
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
|
@ -959,82 +873,16 @@ void Events::listener_activateX11(void* owner, void* data) {
|
|||
PWINDOW->activate();
|
||||
}
|
||||
|
||||
void Events::listener_configureX11(void* owner, void* data) {
|
||||
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
|
||||
|
||||
const auto E = (wlr_xwayland_surface_configure_event*)data;
|
||||
|
||||
if (!PWINDOW->m_uSurface.xwayland->surface || !PWINDOW->m_uSurface.xwayland->surface->mapped || !PWINDOW->m_bIsMapped) {
|
||||
wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height);
|
||||
PWINDOW->m_vPendingReportedSize = {E->width, E->height};
|
||||
PWINDOW->m_vReportedSize = {E->width, E->height};
|
||||
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR)
|
||||
PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale;
|
||||
return;
|
||||
}
|
||||
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
|
||||
if (!PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen || g_pInputManager->currentlyDraggedWindow.lock() == PWINDOW) {
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true);
|
||||
g_pInputManager->refocus();
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
return;
|
||||
}
|
||||
|
||||
if (E->width > 1 && E->height > 1)
|
||||
PWINDOW->setHidden(false);
|
||||
else
|
||||
PWINDOW->setHidden(true);
|
||||
|
||||
const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords({E->x, E->y});
|
||||
|
||||
PWINDOW->m_vRealPosition.setValueAndWarp(LOGICALPOS);
|
||||
PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(E->width, E->height));
|
||||
|
||||
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
|
||||
if (*PXWLFORCESCALEZERO) {
|
||||
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) {
|
||||
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goal() / PMONITOR->scale);
|
||||
PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale;
|
||||
}
|
||||
}
|
||||
|
||||
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.value();
|
||||
PWINDOW->m_vSize = PWINDOW->m_vRealSize.value();
|
||||
|
||||
wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height);
|
||||
|
||||
PWINDOW->m_vPendingReportedSize = {E->width, E->height};
|
||||
PWINDOW->m_vReportedSize = {E->width, E->height};
|
||||
|
||||
PWINDOW->updateWindowDecos();
|
||||
|
||||
if (!g_pCompositor->isWorkspaceVisible(PWINDOW->m_pWorkspace))
|
||||
return; // further things are only for visible windows
|
||||
|
||||
PWINDOW->m_pWorkspace = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.value() + PWINDOW->m_vRealSize.value() / 2.f)->activeWorkspace;
|
||||
|
||||
g_pCompositor->changeWindowZOrder(PWINDOW, true);
|
||||
|
||||
PWINDOW->m_bCreatedOverFullscreen = true;
|
||||
|
||||
if (!PWINDOW->m_sAdditionalConfigData.windowDanceCompat)
|
||||
g_pInputManager->refocus();
|
||||
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
}
|
||||
|
||||
void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
||||
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
|
||||
|
||||
if (!PWINDOW->m_bIsMapped)
|
||||
if (!PWINDOW->m_bIsMapped || !PWINDOW->m_pXWaylandSurface || !PWINDOW->m_pXWaylandSurface->overrideRedirect)
|
||||
return;
|
||||
|
||||
const auto POS = PWINDOW->m_vRealPosition.goal();
|
||||
const auto SIZ = PWINDOW->m_vRealSize.goal();
|
||||
|
||||
if (PWINDOW->m_uSurface.xwayland->width > 1 && PWINDOW->m_uSurface.xwayland->height > 1)
|
||||
if (PWINDOW->m_pXWaylandSurface->geometry.size() > Vector2D{1, 1})
|
||||
PWINDOW->setHidden(false);
|
||||
else
|
||||
PWINDOW->setHidden(true);
|
||||
|
@ -1047,18 +895,17 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
|||
|
||||
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
|
||||
|
||||
const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y});
|
||||
const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords(PWINDOW->m_pXWaylandSurface->geometry.pos());
|
||||
|
||||
if (abs(std::floor(POS.x) - LOGICALPOS.x) > 2 || abs(std::floor(POS.y) - LOGICALPOS.y) > 2 || abs(std::floor(SIZ.x) - PWINDOW->m_uSurface.xwayland->width) > 2 ||
|
||||
abs(std::floor(SIZ.y) - PWINDOW->m_uSurface.xwayland->height) > 2) {
|
||||
Debug::log(LOG, "Unmanaged window {} requests geometry update to {:j} {} {}", PWINDOW, LOGICALPOS, (int)PWINDOW->m_uSurface.xwayland->width,
|
||||
(int)PWINDOW->m_uSurface.xwayland->height);
|
||||
if (abs(std::floor(POS.x) - LOGICALPOS.x) > 2 || abs(std::floor(POS.y) - LOGICALPOS.y) > 2 || abs(std::floor(SIZ.x) - PWINDOW->m_pXWaylandSurface->geometry.width) > 2 ||
|
||||
abs(std::floor(SIZ.y) - PWINDOW->m_pXWaylandSurface->geometry.height) > 2) {
|
||||
Debug::log(LOG, "Unmanaged window {} requests geometry update to {:j} {:j}", PWINDOW, LOGICALPOS, PWINDOW->m_pXWaylandSurface->geometry.size());
|
||||
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
PWINDOW->m_vRealPosition.setValueAndWarp(Vector2D(LOGICALPOS.x, LOGICALPOS.y));
|
||||
|
||||
if (abs(std::floor(SIZ.x) - PWINDOW->m_uSurface.xwayland->width) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_uSurface.xwayland->height) > 2)
|
||||
PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(PWINDOW->m_uSurface.xwayland->width, PWINDOW->m_uSurface.xwayland->height));
|
||||
if (abs(std::floor(SIZ.x) - PWINDOW->m_pXWaylandSurface->geometry.w) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_pXWaylandSurface->geometry.h) > 2)
|
||||
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_pXWaylandSurface->geometry.size());
|
||||
|
||||
if (*PXWLFORCESCALEZERO) {
|
||||
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) {
|
||||
|
@ -1079,92 +926,3 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
|||
PWINDOW->m_vPendingReportedSize = PWINDOW->m_vRealSize.goal();
|
||||
}
|
||||
}
|
||||
|
||||
void Events::listener_setOverrideRedirect(void* owner, void* data) {
|
||||
// const auto PWINDOW = (CWindow*)owner;
|
||||
|
||||
//if (!PWINDOW->m_bIsMapped && PWINDOW->m_uSurface.xwayland->mapped) {
|
||||
// Events::listener_mapWindow(PWINDOW, nullptr);
|
||||
//}
|
||||
}
|
||||
|
||||
void Events::listener_associateX11(void* owner, void* data) {
|
||||
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
|
||||
|
||||
PWINDOW->hyprListener_mapWindow.initCallback(&PWINDOW->m_uSurface.xwayland->surface->events.map, &Events::listener_mapWindow, PWINDOW.get(), "XWayland Window");
|
||||
PWINDOW->hyprListener_commitWindow.initCallback(&PWINDOW->m_uSurface.xwayland->surface->events.commit, &Events::listener_commitWindow, PWINDOW.get(), "XWayland Window");
|
||||
|
||||
PWINDOW->m_pWLSurface.assign(PWINDOW->m_uSurface.xwayland->surface, PWINDOW);
|
||||
}
|
||||
|
||||
void Events::listener_dissociateX11(void* owner, void* data) {
|
||||
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
|
||||
|
||||
PWINDOW->m_pWLSurface.unassign();
|
||||
|
||||
PWINDOW->hyprListener_mapWindow.removeCallback();
|
||||
PWINDOW->hyprListener_commitWindow.removeCallback();
|
||||
}
|
||||
|
||||
void Events::listener_surfaceXWayland(wl_listener* listener, void* data) {
|
||||
const auto XWSURFACE = (wlr_xwayland_surface*)data;
|
||||
|
||||
Debug::log(LOG, "New XWayland Surface created (class {}).", XWSURFACE->_class ? XWSURFACE->_class : "null");
|
||||
if (XWSURFACE->parent)
|
||||
Debug::log(LOG, "Window parent data: {} at {:x}", XWSURFACE->parent->_class ? XWSURFACE->parent->_class : "null", (uintptr_t)XWSURFACE->parent);
|
||||
|
||||
const auto PNEWWINDOW = g_pCompositor->m_vWindows.emplace_back(CWindow::create());
|
||||
|
||||
PNEWWINDOW->m_uSurface.xwayland = XWSURFACE;
|
||||
PNEWWINDOW->m_iX11Type = XWSURFACE->override_redirect ? 2 : 1;
|
||||
PNEWWINDOW->m_bIsX11 = true;
|
||||
|
||||
PNEWWINDOW->m_pX11Parent = g_pCompositor->getX11Parent(PNEWWINDOW);
|
||||
|
||||
PNEWWINDOW->hyprListener_associateX11.initCallback(&XWSURFACE->events.associate, &Events::listener_associateX11, PNEWWINDOW.get(), "XWayland Window");
|
||||
PNEWWINDOW->hyprListener_dissociateX11.initCallback(&XWSURFACE->events.dissociate, &Events::listener_dissociateX11, PNEWWINDOW.get(), "XWayland Window");
|
||||
PNEWWINDOW->hyprListener_destroyWindow.initCallback(&XWSURFACE->events.destroy, &Events::listener_destroyWindow, PNEWWINDOW.get(), "XWayland Window");
|
||||
PNEWWINDOW->hyprListener_setOverrideRedirect.initCallback(&XWSURFACE->events.set_override_redirect, &Events::listener_setOverrideRedirect, PNEWWINDOW.get(), "XWayland Window");
|
||||
PNEWWINDOW->hyprListener_configureX11.initCallback(&XWSURFACE->events.request_configure, &Events::listener_configureX11, PNEWWINDOW.get(), "XWayland Window");
|
||||
}
|
||||
|
||||
void Events::listener_requestMaximize(void* owner, void* data) {
|
||||
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
|
||||
|
||||
if (PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE)
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "Maximize request for {}", PWINDOW);
|
||||
if (!PWINDOW->m_bIsX11) {
|
||||
|
||||
g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen,
|
||||
FULLSCREEN_MAXIMIZED); // this will be rejected if there already is a fullscreen window
|
||||
|
||||
} else {
|
||||
if (!PWINDOW->m_bIsMapped || PWINDOW->m_iX11Type != 1)
|
||||
return;
|
||||
|
||||
g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, FULLSCREEN_MAXIMIZED);
|
||||
}
|
||||
}
|
||||
|
||||
void Events::listener_requestMinimize(void* owner, void* data) {
|
||||
PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock();
|
||||
|
||||
Debug::log(LOG, "Minimize request for {}", PWINDOW);
|
||||
|
||||
if (PWINDOW->m_bIsX11) {
|
||||
if (!PWINDOW->m_bIsMapped || PWINDOW->m_iX11Type != 1)
|
||||
return;
|
||||
|
||||
const auto E = (wlr_xwayland_minimize_event*)data;
|
||||
|
||||
g_pEventManager->postEvent({"minimize", std::format("{:x},{}", (uintptr_t)PWINDOW.get(), (int)E->minimize)});
|
||||
EMIT_HOOK_EVENT("minimize", (std::vector<std::any>{PWINDOW, E->minimize}));
|
||||
|
||||
wlr_xwayland_surface_set_minimized(PWINDOW->m_uSurface.xwayland, E->minimize && g_pCompositor->m_pLastWindow.lock() != PWINDOW); // fucking DXVK
|
||||
} else {
|
||||
g_pEventManager->postEvent({"minimize", std::format("{:x},{}", (uintptr_t)PWINDOW.get(), 1)});
|
||||
EMIT_HOOK_EVENT("minimize", (std::vector<std::any>{PWINDOW, (int64_t)(1)}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,172 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <wayland-server.h>
|
||||
|
||||
typedef unsigned int xcb_atom_t;
|
||||
struct xcb_icccm_wm_hints_t;
|
||||
typedef struct {
|
||||
/** User specified flags */
|
||||
uint32_t flags;
|
||||
/** User-specified position */
|
||||
int32_t x, y;
|
||||
/** User-specified size */
|
||||
int32_t width, height;
|
||||
/** Program-specified minimum size */
|
||||
int32_t min_width, min_height;
|
||||
/** Program-specified maximum size */
|
||||
int32_t max_width, max_height;
|
||||
/** Program-specified resize increments */
|
||||
int32_t width_inc, height_inc;
|
||||
/** Program-specified minimum aspect ratios */
|
||||
int32_t min_aspect_num, min_aspect_den;
|
||||
/** Program-specified maximum aspect ratios */
|
||||
int32_t max_aspect_num, max_aspect_den;
|
||||
/** Program-specified base size */
|
||||
int32_t base_width, base_height;
|
||||
/** Program-specified window gravity */
|
||||
uint32_t win_gravity;
|
||||
} xcb_size_hints_t;
|
||||
typedef unsigned int xcb_window_t;
|
||||
|
||||
typedef enum xcb_stack_mode_t {
|
||||
XCB_STACK_MODE_ABOVE = 0,
|
||||
XCB_STACK_MODE_BELOW = 1,
|
||||
XCB_STACK_MODE_TOP_IF = 2,
|
||||
XCB_STACK_MODE_BOTTOM_IF = 3,
|
||||
XCB_STACK_MODE_OPPOSITE = 4
|
||||
} xcb_stack_mode_t;
|
||||
|
||||
struct wlr_xwayland {
|
||||
struct wlr_xwayland_server* server;
|
||||
struct wlr_xwm* xwm;
|
||||
struct wlr_xwayland_cursor* cursor;
|
||||
|
||||
const char* display_name;
|
||||
|
||||
struct wl_display* wl_display;
|
||||
struct wlr_compositor* compositor;
|
||||
struct wlr_seat* seat;
|
||||
|
||||
void* data;
|
||||
};
|
||||
|
||||
struct wlr_xwayland_surface {
|
||||
xcb_window_t window_id;
|
||||
struct wlr_xwm* xwm;
|
||||
uint32_t surface_id;
|
||||
|
||||
struct wl_list link;
|
||||
struct wl_list stack_link;
|
||||
struct wl_list unpaired_link;
|
||||
|
||||
struct wlr_surface* surface;
|
||||
int16_t x, y;
|
||||
uint16_t width, height;
|
||||
uint16_t saved_width, saved_height;
|
||||
bool override_redirect;
|
||||
bool mapped;
|
||||
|
||||
char* title;
|
||||
char* _class;
|
||||
char* instance;
|
||||
char* role;
|
||||
char* startup_id;
|
||||
pid_t pid;
|
||||
bool has_utf8_title;
|
||||
|
||||
struct wl_list children; // wlr_xwayland_surface::parent_link
|
||||
struct wlr_xwayland_surface* parent;
|
||||
struct wl_list parent_link; // wlr_xwayland_surface::children
|
||||
|
||||
xcb_atom_t* window_type;
|
||||
size_t window_type_len;
|
||||
|
||||
xcb_atom_t* protocols;
|
||||
size_t protocols_len;
|
||||
|
||||
uint32_t decorations;
|
||||
xcb_icccm_wm_hints_t* hints;
|
||||
xcb_size_hints_t* size_hints;
|
||||
|
||||
bool pinging;
|
||||
struct wl_event_source* ping_timer;
|
||||
|
||||
// _NET_WM_STATE
|
||||
bool modal;
|
||||
bool fullscreen;
|
||||
bool maximized_vert, maximized_horz;
|
||||
bool minimized;
|
||||
|
||||
bool has_alpha;
|
||||
|
||||
struct {
|
||||
struct wl_signal destroy;
|
||||
struct wl_signal request_configure;
|
||||
struct wl_signal request_move;
|
||||
struct wl_signal request_resize;
|
||||
struct wl_signal request_minimize;
|
||||
struct wl_signal request_maximize;
|
||||
struct wl_signal request_fullscreen;
|
||||
struct wl_signal request_activate;
|
||||
|
||||
struct wl_signal map;
|
||||
struct wl_signal unmap;
|
||||
struct wl_signal associate;
|
||||
struct wl_signal dissociate;
|
||||
struct wl_signal set_title;
|
||||
struct wl_signal set_class;
|
||||
struct wl_signal set_role;
|
||||
struct wl_signal set_parent;
|
||||
struct wl_signal set_startup_id;
|
||||
struct wl_signal set_window_type;
|
||||
struct wl_signal set_hints;
|
||||
struct wl_signal set_decorations;
|
||||
struct wl_signal set_override_redirect;
|
||||
struct wl_signal set_geometry;
|
||||
struct wl_signal ping_timeout;
|
||||
} events;
|
||||
};
|
||||
|
||||
struct wlr_xwayland_surface_configure_event {
|
||||
struct wlr_xwayland_surface* surface;
|
||||
int16_t x, y;
|
||||
uint16_t width, height;
|
||||
uint16_t mask; // xcb_config_window_t
|
||||
};
|
||||
|
||||
struct wlr_xwayland_minimize_event {
|
||||
struct wlr_xwayland_surface* surface;
|
||||
bool minimize;
|
||||
};
|
||||
|
||||
inline void wlr_xwayland_destroy(wlr_xwayland*) {}
|
||||
|
||||
inline void wlr_xwayland_surface_configure(wlr_xwayland_surface*, int, int, int, int) {}
|
||||
|
||||
inline bool wlr_surface_is_xwayland_surface(void*) {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void wlr_xwayland_surface_activate(wlr_xwayland_surface*, bool) {}
|
||||
|
||||
inline void wlr_xwayland_surface_restack(wlr_xwayland_surface*, void*, xcb_stack_mode_t) {}
|
||||
|
||||
inline wlr_xwayland_surface* wlr_xwayland_surface_from_wlr_surface(void*) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline void wlr_xwayland_surface_close(wlr_xwayland_surface*) {}
|
||||
|
||||
inline void wlr_xwayland_surface_set_fullscreen(wlr_xwayland_surface*, bool) {}
|
||||
|
||||
inline void wlr_xwayland_surface_set_minimized(wlr_xwayland_surface*, bool) {}
|
||||
|
||||
inline wlr_xwayland_surface* wlr_xwayland_surface_try_from_wlr_surface(wlr_surface*) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline bool wlr_xwayland_or_surface_wants_focus(const wlr_xwayland_surface*) {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void wlr_xwayland_set_cursor(wlr_xwayland* wlr_xwayland, uint8_t* pixels, uint32_t stride, uint32_t width, uint32_t height, int32_t hotspot_x, int32_t hotspot_y) {}
|
|
@ -82,10 +82,6 @@ extern "C" {
|
|||
#if WLR_HAS_X11_BACKEND
|
||||
#include <wlr/backend/x11.h>
|
||||
#endif
|
||||
|
||||
#ifndef NO_XWAYLAND
|
||||
#include <wlr/xwayland.h>
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef delete
|
||||
|
@ -110,7 +106,6 @@ extern "C" {
|
|||
|
||||
#ifdef NO_XWAYLAND
|
||||
#define XWAYLAND false
|
||||
#include "helpers/XWaylandStubs.hpp"
|
||||
#else
|
||||
#define XWAYLAND true
|
||||
#endif
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "../config/ConfigValue.hpp"
|
||||
#include "../desktop/Window.hpp"
|
||||
#include "../protocols/XDGShell.hpp"
|
||||
#include "../xwayland/XSurface.hpp"
|
||||
|
||||
void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) {
|
||||
if (pWindow->m_bIsFloating) {
|
||||
|
@ -111,10 +112,10 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) {
|
|||
if (pWindow->m_vRealSize.goal().x <= 5 || pWindow->m_vRealSize.goal().y <= 5)
|
||||
pWindow->m_vRealSize = PMONITOR->vecSize / 2.f;
|
||||
|
||||
if (pWindow->m_bIsX11 && pWindow->m_uSurface.xwayland->override_redirect) {
|
||||
if (pWindow->m_bIsX11 && pWindow->m_iX11Type == 2) {
|
||||
|
||||
if (pWindow->m_uSurface.xwayland->x != 0 && pWindow->m_uSurface.xwayland->y != 0)
|
||||
pWindow->m_vRealPosition = g_pXWaylandManager->xwaylandToWaylandCoords({pWindow->m_uSurface.xwayland->x, pWindow->m_uSurface.xwayland->y});
|
||||
if (pWindow->m_pXWaylandSurface->geometry.x != 0 && pWindow->m_pXWaylandSurface->geometry.y != 0)
|
||||
pWindow->m_vRealPosition = g_pXWaylandManager->xwaylandToWaylandCoords(pWindow->m_pXWaylandSurface->geometry.pos());
|
||||
else
|
||||
pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize.goal().x) / 2.f,
|
||||
PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize.goal().y) / 2.f);
|
||||
|
@ -161,7 +162,7 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) {
|
|||
if (*PXWLFORCESCALEZERO && pWindow->m_bIsX11)
|
||||
pWindow->m_vRealSize = pWindow->m_vRealSize.goal() / PMONITOR->scale;
|
||||
|
||||
if (pWindow->m_bX11DoesntWantBorders || (pWindow->m_bIsX11 && pWindow->m_uSurface.xwayland->override_redirect)) {
|
||||
if (pWindow->m_bX11DoesntWantBorders || (pWindow->m_bIsX11 && pWindow->m_iX11Type == 2)) {
|
||||
pWindow->m_vRealPosition.warp();
|
||||
pWindow->m_vRealSize.warp();
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "Compositor.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
#include "PointerManager.hpp"
|
||||
#include "../xwayland/XWayland.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include <wlr/interfaces/wlr_buffer.h>
|
||||
|
@ -246,14 +247,14 @@ SCursorImageData CCursorManager::dataFor(const std::string& name) {
|
|||
return IMAGES.images[0];
|
||||
}
|
||||
|
||||
void CCursorManager::setXWaylandCursor(wlr_xwayland* xwayland) {
|
||||
void CCursorManager::setXWaylandCursor() {
|
||||
const auto CURSOR = dataFor("left_ptr");
|
||||
if (CURSOR.surface) {
|
||||
wlr_xwayland_set_cursor(xwayland, cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), CURSOR.size, CURSOR.size, CURSOR.hotspotX,
|
||||
CURSOR.hotspotY);
|
||||
g_pXWayland->setCursor(cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), {CURSOR.size, CURSOR.size},
|
||||
{CURSOR.hotspotX, CURSOR.hotspotY});
|
||||
} else if (const auto XCURSOR = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, "left_ptr", 1); XCURSOR) {
|
||||
wlr_xwayland_set_cursor(xwayland, XCURSOR->images[0]->buffer, XCURSOR->images[0]->width * 4, XCURSOR->images[0]->width, XCURSOR->images[0]->height,
|
||||
XCURSOR->images[0]->hotspot_x, XCURSOR->images[0]->hotspot_y);
|
||||
g_pXWayland->setCursor(XCURSOR->images[0]->buffer, XCURSOR->images[0]->width * 4, {XCURSOR->images[0]->width, XCURSOR->images[0]->height},
|
||||
{XCURSOR->images[0]->hotspot_x, XCURSOR->images[0]->hotspot_y});
|
||||
} else
|
||||
Debug::log(ERR, "CursorManager: no valid cursor for xwayland");
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
struct wlr_buffer;
|
||||
struct wlr_xcursor_manager;
|
||||
struct wlr_xwayland;
|
||||
class CWLSurface;
|
||||
|
||||
class CCursorManager {
|
||||
|
@ -25,7 +24,7 @@ class CCursorManager {
|
|||
void changeTheme(const std::string& name, const int size);
|
||||
void updateTheme();
|
||||
SCursorImageData dataFor(const std::string& name); // for xwayland
|
||||
void setXWaylandCursor(wlr_xwayland* xwayland);
|
||||
void setXWaylandCursor();
|
||||
|
||||
void tickAnimatedCursor();
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "../protocols/XDGShell.hpp"
|
||||
#include "../protocols/DataDeviceWlr.hpp"
|
||||
#include "../protocols/PrimarySelection.hpp"
|
||||
#include "../protocols/XWaylandShell.hpp"
|
||||
|
||||
#include "../protocols/core/Seat.hpp"
|
||||
#include "../protocols/core/DataDevice.hpp"
|
||||
|
@ -73,6 +74,7 @@ CProtocolManager::CProtocolManager() {
|
|||
PROTO::xdgShell = std::make_unique<CXDGShellProtocol>(&xdg_wm_base_interface, 6, "XDGShell");
|
||||
PROTO::dataWlr = std::make_unique<CDataDeviceWLRProtocol>(&zwlr_data_control_manager_v1_interface, 2, "DataDeviceWlr");
|
||||
PROTO::primarySelection = std::make_unique<CPrimarySelectionProtocol>(&zwp_primary_selection_device_manager_v1_interface, 1, "PrimarySelection");
|
||||
PROTO::xwaylandShell = std::make_unique<CXWaylandShellProtocol>(&xwayland_shell_v1_interface, 1, "XWaylandShell");
|
||||
|
||||
// Old protocol implementations.
|
||||
// TODO: rewrite them to use hyprwayland-scanner.
|
||||
|
|
|
@ -498,6 +498,8 @@ void CSeatManager::setCurrentSelection(SP<IDataSource> source) {
|
|||
PROTO::data->setSelection(source);
|
||||
PROTO::dataWlr->setSelection(source, false);
|
||||
}
|
||||
|
||||
events.setSelection.emit();
|
||||
}
|
||||
|
||||
void CSeatManager::setCurrentPrimarySelection(SP<IDataSource> source) {
|
||||
|
@ -521,6 +523,8 @@ void CSeatManager::setCurrentPrimarySelection(SP<IDataSource> source) {
|
|||
PROTO::primarySelection->setSelection(source);
|
||||
PROTO::dataWlr->setSelection(source, true);
|
||||
}
|
||||
|
||||
events.setPrimarySelection.emit();
|
||||
}
|
||||
|
||||
void CSeatManager::setGrab(SP<CSeatGrab> grab) {
|
||||
|
|
|
@ -106,6 +106,8 @@ class CSeatManager {
|
|||
CSignal pointerFocusChange;
|
||||
CSignal touchFocusChange;
|
||||
CSignal setCursor; // SSetCursorEvent
|
||||
CSignal setSelection;
|
||||
CSignal setPrimarySelection;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
|
|
|
@ -3,29 +3,14 @@
|
|||
#include "../events/Events.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
#include "../protocols/XDGShell.hpp"
|
||||
#include "../xwayland/XWayland.hpp"
|
||||
|
||||
#define OUTPUT_MANAGER_VERSION 3
|
||||
#define OUTPUT_DONE_DEPRECATED_SINCE_VERSION 3
|
||||
#define OUTPUT_DESCRIPTION_MUTABLE_SINCE_VERSION 3
|
||||
|
||||
CHyprXWaylandManager::CHyprXWaylandManager() {
|
||||
#ifndef NO_XWAYLAND
|
||||
m_sWLRXWayland = wlr_xwayland_create(g_pCompositor->m_sWLDisplay, g_pCompositor->m_sWLRCompositor, 1);
|
||||
|
||||
if (!m_sWLRXWayland) {
|
||||
Debug::log(ERR, "Couldn't start up the XWaylandManager because wlr_xwayland_create returned a nullptr!");
|
||||
return;
|
||||
}
|
||||
|
||||
addWLSignal(&m_sWLRXWayland->events.ready, &Events::listen_readyXWayland, m_sWLRXWayland, "XWayland Manager");
|
||||
addWLSignal(&m_sWLRXWayland->events.new_surface, &Events::listen_surfaceXWayland, m_sWLRXWayland, "XWayland Manager");
|
||||
|
||||
setenv("DISPLAY", m_sWLRXWayland->display_name, 1);
|
||||
|
||||
Debug::log(LOG, "CHyprXWaylandManager started on display {}", m_sWLRXWayland->display_name);
|
||||
#else
|
||||
unsetenv("DISPLAY"); // unset DISPLAY so that X11 apps do not try to start on a different/invalid DISPLAY
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
CHyprXWaylandManager::~CHyprXWaylandManager() {
|
||||
|
@ -42,24 +27,23 @@ void CHyprXWaylandManager::activateSurface(wlr_surface* pSurface, bool activate)
|
|||
if (!pSurface)
|
||||
return;
|
||||
|
||||
if (wlr_xwayland_surface_try_from_wlr_surface(pSurface)) {
|
||||
const auto XSURF = wlr_xwayland_surface_try_from_wlr_surface(pSurface);
|
||||
wlr_xwayland_surface_activate(XSURF, activate);
|
||||
|
||||
if (activate && !XSURF->override_redirect)
|
||||
wlr_xwayland_surface_restack(XSURF, nullptr, XCB_STACK_MODE_ABOVE);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// this cannot be nicely done until we rewrite wlr_surface
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_bIsX11 || !w->m_bIsMapped)
|
||||
if (!w->m_bIsMapped)
|
||||
continue;
|
||||
|
||||
if (w->m_pWLSurface.wlr() != pSurface)
|
||||
continue;
|
||||
|
||||
w->m_pXDGSurface->toplevel->setActive(activate);
|
||||
if (w->m_bIsX11) {
|
||||
if (activate) {
|
||||
w->m_pXWaylandSurface->setMinimized(false);
|
||||
w->m_pXWaylandSurface->restackToTop();
|
||||
}
|
||||
w->m_pXWaylandSurface->activate(activate);
|
||||
} else
|
||||
w->m_pXDGSurface->toplevel->setActive(activate);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,12 +52,12 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) {
|
|||
setWindowSize(pWindow, pWindow->m_vRealSize.value()); // update xwayland output pos
|
||||
|
||||
if (activate) {
|
||||
wlr_xwayland_surface_set_minimized(pWindow->m_uSurface.xwayland, false);
|
||||
if (!pWindow->m_uSurface.xwayland->override_redirect)
|
||||
wlr_xwayland_surface_restack(pWindow->m_uSurface.xwayland, nullptr, XCB_STACK_MODE_ABOVE);
|
||||
pWindow->m_pXWaylandSurface->setMinimized(false);
|
||||
if (pWindow->m_iX11Type != 2)
|
||||
pWindow->m_pXWaylandSurface->restackToTop();
|
||||
}
|
||||
|
||||
wlr_xwayland_surface_activate(pWindow->m_uSurface.xwayland, activate);
|
||||
pWindow->m_pXWaylandSurface->activate(activate);
|
||||
} else if (pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel)
|
||||
pWindow->m_pXDGSurface->toplevel->setActive(activate);
|
||||
|
||||
|
@ -88,7 +72,7 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) {
|
|||
|
||||
void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) {
|
||||
if (pWindow->m_bIsX11) {
|
||||
const auto SIZEHINTS = pWindow->m_uSurface.xwayland->size_hints;
|
||||
const auto SIZEHINTS = pWindow->m_pXWaylandSurface->sizeHints.get();
|
||||
|
||||
if (SIZEHINTS && pWindow->m_iX11Type != 2) {
|
||||
pbox->x = SIZEHINTS->x;
|
||||
|
@ -96,10 +80,7 @@ void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) {
|
|||
pbox->width = SIZEHINTS->width;
|
||||
pbox->height = SIZEHINTS->height;
|
||||
} else {
|
||||
pbox->x = pWindow->m_uSurface.xwayland->x;
|
||||
pbox->y = pWindow->m_uSurface.xwayland->y;
|
||||
pbox->width = pWindow->m_uSurface.xwayland->width;
|
||||
pbox->height = pWindow->m_uSurface.xwayland->height;
|
||||
*pbox = pWindow->m_pXWaylandSurface->geometry;
|
||||
}
|
||||
} else if (pWindow->m_pXDGSurface)
|
||||
*pbox = pWindow->m_pXDGSurface->current.geometry;
|
||||
|
@ -107,7 +88,7 @@ void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) {
|
|||
|
||||
void CHyprXWaylandManager::sendCloseWindow(PHLWINDOW pWindow) {
|
||||
if (pWindow->m_bIsX11)
|
||||
wlr_xwayland_surface_close(pWindow->m_uSurface.xwayland);
|
||||
pWindow->m_pXWaylandSurface->close();
|
||||
else if (pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel)
|
||||
pWindow->m_pXDGSurface->toplevel->close();
|
||||
}
|
||||
|
@ -145,7 +126,7 @@ void CHyprXWaylandManager::setWindowSize(PHLWINDOW pWindow, Vector2D size, bool
|
|||
}
|
||||
|
||||
if (pWindow->m_bIsX11)
|
||||
wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, windowPos.x, windowPos.y, size.x, size.y);
|
||||
pWindow->m_pXWaylandSurface->configure({windowPos, size});
|
||||
else if (pWindow->m_pXDGSurface->toplevel)
|
||||
pWindow->m_vPendingSizeAcks.push_back(std::make_pair<>(pWindow->m_pXDGSurface->toplevel->setSize(size), size.floor()));
|
||||
}
|
||||
|
@ -156,45 +137,36 @@ wlr_surface* CHyprXWaylandManager::surfaceAt(PHLWINDOW pWindow, const Vector2D&
|
|||
|
||||
bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) {
|
||||
if (pWindow->m_bIsX11) {
|
||||
for (size_t i = 0; i < pWindow->m_uSurface.xwayland->window_type_len; i++)
|
||||
if (pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DIALOG"] ||
|
||||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] ||
|
||||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLBAR"] ||
|
||||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_UTILITY"] ||
|
||||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"] ||
|
||||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] ||
|
||||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DOCK"] ||
|
||||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] ||
|
||||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"] ||
|
||||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_KDE_NET_WM_WINDOW_TYPE_OVERRIDE"]) {
|
||||
for (auto& a : pWindow->m_pXWaylandSurface->atoms)
|
||||
if (a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DIALOG"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLBAR"] ||
|
||||
a == HYPRATOMS["_NET_WM_WINDOW_TYPE_UTILITY"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] ||
|
||||
a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DOCK"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"] ||
|
||||
a == HYPRATOMS["_KDE_NET_WM_WINDOW_TYPE_OVERRIDE"]) {
|
||||
|
||||
if (pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] ||
|
||||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"])
|
||||
if (a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"])
|
||||
pWindow->m_bX11ShouldntFocus = true;
|
||||
|
||||
pWindow->m_bNoInitialFocus = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pWindow->m_uSurface.xwayland->role) {
|
||||
try {
|
||||
std::string winrole = std::string(pWindow->m_uSurface.xwayland->role);
|
||||
if (winrole.contains("pop-up") || winrole.contains("task_dialog")) {
|
||||
return true;
|
||||
}
|
||||
} catch (std::exception& e) { Debug::log(ERR, "Error in shouldBeFloated, winrole threw {}", e.what()); }
|
||||
}
|
||||
|
||||
if (pWindow->m_uSurface.xwayland->modal) {
|
||||
if (pWindow->m_pXWaylandSurface->modal) {
|
||||
pWindow->m_bIsModal = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pWindow->m_iX11Type == 2)
|
||||
return true; // override_redirect
|
||||
if (pWindow->m_pXWaylandSurface->transient)
|
||||
return true;
|
||||
|
||||
const auto SIZEHINTS = pWindow->m_uSurface.xwayland->size_hints;
|
||||
if (SIZEHINTS && (pWindow->m_uSurface.xwayland->parent || ((SIZEHINTS->min_width == SIZEHINTS->max_width) && (SIZEHINTS->min_height == SIZEHINTS->max_height))))
|
||||
if (pWindow->m_pXWaylandSurface->role.contains("task_dialog") || pWindow->m_pXWaylandSurface->role.contains("pop-up"))
|
||||
return true;
|
||||
|
||||
if (pWindow->m_pXWaylandSurface->overrideRedirect)
|
||||
return true;
|
||||
|
||||
const auto SIZEHINTS = pWindow->m_pXWaylandSurface->sizeHints.get();
|
||||
if (pWindow->m_pXWaylandSurface->transient || pWindow->m_pXWaylandSurface->parent ||
|
||||
(SIZEHINTS && (SIZEHINTS->min_width == SIZEHINTS->max_width) && (SIZEHINTS->min_height == SIZEHINTS->max_height)))
|
||||
return true;
|
||||
} else {
|
||||
const auto PSTATE = pending ? &pWindow->m_pXDGSurface->toplevel->pending : &pWindow->m_pXDGSurface->toplevel->current;
|
||||
|
@ -207,28 +179,14 @@ bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void CHyprXWaylandManager::moveXWaylandWindow(PHLWINDOW pWindow, const Vector2D& pos) {
|
||||
if (!validMapped(pWindow))
|
||||
return;
|
||||
|
||||
if (!pWindow->m_bIsX11)
|
||||
return;
|
||||
|
||||
wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, pos.x, pos.y, pWindow->m_vRealSize.value().x, pWindow->m_vRealSize.value().y);
|
||||
}
|
||||
|
||||
void CHyprXWaylandManager::checkBorders(PHLWINDOW pWindow) {
|
||||
if (!pWindow->m_bIsX11)
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < pWindow->m_uSurface.xwayland->window_type_len; i++) {
|
||||
if (pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] ||
|
||||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_NOTIFICATION"] ||
|
||||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] ||
|
||||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_COMBO"] ||
|
||||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"] ||
|
||||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] ||
|
||||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"]) {
|
||||
for (auto& a : pWindow->m_pXWaylandSurface->atoms) {
|
||||
if (a == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_NOTIFICATION"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] ||
|
||||
a == HYPRATOMS["_NET_WM_WINDOW_TYPE_COMBO"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] ||
|
||||
a == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"]) {
|
||||
|
||||
pWindow->m_bX11DoesntWantBorders = true;
|
||||
return;
|
||||
|
@ -242,7 +200,7 @@ void CHyprXWaylandManager::checkBorders(PHLWINDOW pWindow) {
|
|||
|
||||
void CHyprXWaylandManager::setWindowFullscreen(PHLWINDOW pWindow, bool fullscreen) {
|
||||
if (pWindow->m_bIsX11)
|
||||
wlr_xwayland_surface_set_fullscreen(pWindow->m_uSurface.xwayland, fullscreen);
|
||||
pWindow->m_pXWaylandSurface->setFullscreen(fullscreen);
|
||||
else if (pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel)
|
||||
pWindow->m_pXDGSurface->toplevel->setFullscreen(fullscreen);
|
||||
}
|
||||
|
@ -251,10 +209,10 @@ Vector2D CHyprXWaylandManager::getMaxSizeForWindow(PHLWINDOW pWindow) {
|
|||
if (!validMapped(pWindow))
|
||||
return Vector2D(99999, 99999);
|
||||
|
||||
if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel) || pWindow->m_sAdditionalConfigData.noMaxSize)
|
||||
if ((pWindow->m_bIsX11 && !pWindow->m_pXWaylandSurface->sizeHints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel) || pWindow->m_sAdditionalConfigData.noMaxSize)
|
||||
return Vector2D(99999, 99999);
|
||||
|
||||
auto MAXSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_uSurface.xwayland->size_hints->max_width, pWindow->m_uSurface.xwayland->size_hints->max_height) :
|
||||
auto MAXSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_pXWaylandSurface->sizeHints->max_width, pWindow->m_pXWaylandSurface->sizeHints->max_height) :
|
||||
pWindow->m_pXDGSurface->toplevel->current.maxSize;
|
||||
|
||||
if (MAXSIZE.x < 5)
|
||||
|
@ -269,10 +227,10 @@ Vector2D CHyprXWaylandManager::getMinSizeForWindow(PHLWINDOW pWindow) {
|
|||
if (!validMapped(pWindow))
|
||||
return Vector2D(0, 0);
|
||||
|
||||
if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel))
|
||||
if ((pWindow->m_bIsX11 && !pWindow->m_pXWaylandSurface->sizeHints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel))
|
||||
return Vector2D(0, 0);
|
||||
|
||||
auto MINSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_uSurface.xwayland->size_hints->min_width, pWindow->m_uSurface.xwayland->size_hints->min_height) :
|
||||
auto MINSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_pXWaylandSurface->sizeHints->min_width, pWindow->m_pXWaylandSurface->sizeHints->min_height) :
|
||||
pWindow->m_pXDGSurface->toplevel->current.minSize;
|
||||
|
||||
MINSIZE = MINSIZE.clamp({1, 1});
|
||||
|
|
|
@ -11,22 +11,19 @@ class CHyprXWaylandManager {
|
|||
CHyprXWaylandManager();
|
||||
~CHyprXWaylandManager();
|
||||
|
||||
wlr_xwayland* m_sWLRXWayland = nullptr;
|
||||
|
||||
wlr_surface* getWindowSurface(PHLWINDOW);
|
||||
void activateSurface(wlr_surface*, bool);
|
||||
void activateWindow(PHLWINDOW, bool);
|
||||
void getGeometryForWindow(PHLWINDOW, CBox*);
|
||||
void sendCloseWindow(PHLWINDOW);
|
||||
void setWindowSize(PHLWINDOW, Vector2D, bool force = false);
|
||||
void setWindowFullscreen(PHLWINDOW, bool);
|
||||
wlr_surface* surfaceAt(PHLWINDOW, const Vector2D&, Vector2D&);
|
||||
bool shouldBeFloated(PHLWINDOW, bool pending = false);
|
||||
void moveXWaylandWindow(PHLWINDOW, const Vector2D&);
|
||||
void checkBorders(PHLWINDOW);
|
||||
Vector2D getMaxSizeForWindow(PHLWINDOW);
|
||||
Vector2D getMinSizeForWindow(PHLWINDOW);
|
||||
Vector2D xwaylandToWaylandCoords(const Vector2D&);
|
||||
wlr_surface* getWindowSurface(PHLWINDOW);
|
||||
void activateSurface(wlr_surface*, bool);
|
||||
void activateWindow(PHLWINDOW, bool);
|
||||
void getGeometryForWindow(PHLWINDOW, CBox*);
|
||||
void sendCloseWindow(PHLWINDOW);
|
||||
void setWindowSize(PHLWINDOW, Vector2D, bool force = false);
|
||||
void setWindowFullscreen(PHLWINDOW, bool);
|
||||
wlr_surface* surfaceAt(PHLWINDOW, const Vector2D&, Vector2D&);
|
||||
bool shouldBeFloated(PHLWINDOW, bool pending = false);
|
||||
void checkBorders(PHLWINDOW);
|
||||
Vector2D getMaxSizeForWindow(PHLWINDOW);
|
||||
Vector2D getMinSizeForWindow(PHLWINDOW);
|
||||
Vector2D xwaylandToWaylandCoords(const Vector2D&);
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CHyprXWaylandManager> g_pXWaylandManager;
|
|
@ -661,7 +661,7 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) {
|
|||
|
||||
// clicking on border triggers resize
|
||||
// TODO detect click on LS properly
|
||||
if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e.state == WL_POINTER_BUTTON_STATE_PRESSED) {
|
||||
if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e.state == WL_POINTER_BUTTON_STATE_PRESSED && (!w || w->m_iX11Type != 2)) {
|
||||
if (w && !w->m_bIsFullscreen) {
|
||||
const CBox real = {w->m_vRealPosition.value().x, w->m_vRealPosition.value().y, w->m_vRealSize.value().x, w->m_vRealSize.value().y};
|
||||
const CBox grab = {real.x - BORDER_GRAB_AREA, real.y - BORDER_GRAB_AREA, real.width + 2 * BORDER_GRAB_AREA, real.height + 2 * BORDER_GRAB_AREA};
|
||||
|
@ -674,7 +674,7 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) {
|
|||
}
|
||||
|
||||
switch (e.state) {
|
||||
case WL_POINTER_BUTTON_STATE_PRESSED:
|
||||
case WL_POINTER_BUTTON_STATE_PRESSED: {
|
||||
if (*PFOLLOWMOUSE == 3) // don't refocus on full loose
|
||||
break;
|
||||
|
||||
|
@ -692,10 +692,16 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) {
|
|||
}
|
||||
|
||||
// if clicked on a floating window make it top
|
||||
if (g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsFloating)
|
||||
g_pCompositor->changeWindowZOrder(g_pCompositor->m_pLastWindow.lock(), true);
|
||||
if (!g_pSeatManager->state.pointerFocus)
|
||||
break;
|
||||
|
||||
auto HLSurf = CWLSurface::surfaceFromWlr(g_pSeatManager->state.pointerFocus);
|
||||
|
||||
if (HLSurf && HLSurf->getWindow())
|
||||
g_pCompositor->changeWindowZOrder(HLSurf->getWindow(), true);
|
||||
|
||||
break;
|
||||
}
|
||||
case WL_POINTER_BUTTON_STATE_RELEASED: break;
|
||||
}
|
||||
|
||||
|
@ -1677,6 +1683,10 @@ void CInputManager::setCursorIconOnBorder(PHLWINDOW w) {
|
|||
return;
|
||||
}
|
||||
|
||||
// ignore X11 OR windows, they shouldn't be touched
|
||||
if (w->m_bIsX11 && w->m_iX11Type == 2)
|
||||
return;
|
||||
|
||||
static auto PEXTENDBORDERGRAB = CConfigValue<Hyprlang::INT>("general:extend_border_grab_area");
|
||||
const int BORDERSIZE = w->getRealBorderSize();
|
||||
const int ROUNDING = w->rounding();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "XDGOutput.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
#include "../xwayland/XWayland.hpp"
|
||||
|
||||
#define OUTPUT_MANAGER_VERSION 3
|
||||
#define OUTPUT_DONE_DEPRECATED_SINCE_VERSION 3
|
||||
|
@ -55,7 +56,7 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32
|
|||
|
||||
CXDGOutput* pXDGOutput = m_vXDGOutputs.emplace_back(std::make_unique<CXDGOutput>(makeShared<CZxdgOutputV1>(CLIENT, mgr->version(), id), PMONITOR)).get();
|
||||
#ifndef NO_XWAYLAND
|
||||
if (g_pXWaylandManager->m_sWLRXWayland && g_pXWaylandManager->m_sWLRXWayland->server && g_pXWaylandManager->m_sWLRXWayland->server->client == CLIENT)
|
||||
if (g_pXWayland && g_pXWayland->pServer && g_pXWayland->pServer->xwaylandClient == CLIENT)
|
||||
pXDGOutput->isXWayland = true;
|
||||
#endif
|
||||
pXDGOutput->client = CLIENT;
|
||||
|
|
84
src/protocols/XWaylandShell.cpp
Normal file
84
src/protocols/XWaylandShell.cpp
Normal file
|
@ -0,0 +1,84 @@
|
|||
#include "XWaylandShell.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
#define LOGM PROTO::xwaylandShell->protoLog
|
||||
|
||||
CXWaylandSurfaceResource::CXWaylandSurfaceResource(SP<CXwaylandSurfaceV1> resource_, wlr_surface* surface_) : surface(surface_), resource(resource_) {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
resource->setDestroy([this](CXwaylandSurfaceV1* r) {
|
||||
events.destroy.emit();
|
||||
PROTO::xwaylandShell->destroyResource(this);
|
||||
});
|
||||
resource->setOnDestroy([this](CXwaylandSurfaceV1* r) {
|
||||
events.destroy.emit();
|
||||
PROTO::xwaylandShell->destroyResource(this);
|
||||
});
|
||||
|
||||
pClient = resource->client();
|
||||
|
||||
resource->setSetSerial([this](CXwaylandSurfaceV1* r, uint32_t lo, uint32_t hi) {
|
||||
serial = (((uint64_t)hi) << 32) + lo;
|
||||
PROTO::xwaylandShell->events.newSurface.emit(self.lock());
|
||||
});
|
||||
}
|
||||
|
||||
CXWaylandSurfaceResource::~CXWaylandSurfaceResource() {
|
||||
events.destroy.emit();
|
||||
}
|
||||
|
||||
bool CXWaylandSurfaceResource::good() {
|
||||
return resource->resource();
|
||||
}
|
||||
|
||||
wl_client* CXWaylandSurfaceResource::client() {
|
||||
return pClient;
|
||||
}
|
||||
|
||||
CXWaylandShellResource::CXWaylandShellResource(SP<CXwaylandShellV1> resource_) : resource(resource_) {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
resource->setDestroy([this](CXwaylandShellV1* r) { PROTO::xwaylandShell->destroyResource(this); });
|
||||
resource->setOnDestroy([this](CXwaylandShellV1* r) { PROTO::xwaylandShell->destroyResource(this); });
|
||||
|
||||
resource->setGetXwaylandSurface([this](CXwaylandShellV1* r, uint32_t id, wl_resource* surface) {
|
||||
const auto RESOURCE = PROTO::xwaylandShell->m_vSurfaces.emplace_back(
|
||||
makeShared<CXWaylandSurfaceResource>(makeShared<CXwaylandSurfaceV1>(r->client(), r->version(), id), wlr_surface_from_resource(surface)));
|
||||
|
||||
if (!RESOURCE->good()) {
|
||||
r->noMemory();
|
||||
PROTO::xwaylandShell->m_vSurfaces.pop_back();
|
||||
return;
|
||||
}
|
||||
|
||||
RESOURCE->self = RESOURCE;
|
||||
});
|
||||
}
|
||||
|
||||
bool CXWaylandShellResource::good() {
|
||||
return resource->resource();
|
||||
}
|
||||
|
||||
CXWaylandShellProtocol::CXWaylandShellProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
|
||||
;
|
||||
}
|
||||
|
||||
void CXWaylandShellProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
|
||||
const auto RESOURCE = m_vManagers.emplace_back(makeShared<CXWaylandShellResource>(makeShared<CXwaylandShellV1>(client, ver, id)));
|
||||
|
||||
if (!RESOURCE->good()) {
|
||||
wl_client_post_no_memory(client);
|
||||
m_vManagers.pop_back();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void CXWaylandShellProtocol::destroyResource(CXWaylandShellResource* resource) {
|
||||
std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; });
|
||||
}
|
||||
|
||||
void CXWaylandShellProtocol::destroyResource(CXWaylandSurfaceResource* resource) {
|
||||
std::erase_if(m_vSurfaces, [&](const auto& other) { return other.get() == resource; });
|
||||
}
|
66
src/protocols/XWaylandShell.hpp
Normal file
66
src/protocols/XWaylandShell.hpp
Normal file
|
@ -0,0 +1,66 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include "WaylandProtocol.hpp"
|
||||
#include "xwayland-shell-v1.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
|
||||
class CXWaylandSurfaceResource {
|
||||
public:
|
||||
CXWaylandSurfaceResource(SP<CXwaylandSurfaceV1> resource_, wlr_surface* surface_);
|
||||
~CXWaylandSurfaceResource();
|
||||
|
||||
bool good();
|
||||
wl_client* client();
|
||||
|
||||
struct {
|
||||
CSignal destroy;
|
||||
} events;
|
||||
|
||||
uint64_t serial = 0;
|
||||
wlr_surface* surface = nullptr;
|
||||
|
||||
WP<CXWaylandSurfaceResource> self;
|
||||
|
||||
private:
|
||||
SP<CXwaylandSurfaceV1> resource;
|
||||
wl_client* pClient = nullptr;
|
||||
};
|
||||
|
||||
class CXWaylandShellResource {
|
||||
public:
|
||||
CXWaylandShellResource(SP<CXwaylandShellV1> resource_);
|
||||
|
||||
bool good();
|
||||
|
||||
private:
|
||||
SP<CXwaylandShellV1> resource;
|
||||
};
|
||||
|
||||
class CXWaylandShellProtocol : public IWaylandProtocol {
|
||||
public:
|
||||
CXWaylandShellProtocol(const wl_interface* iface, const int& ver, const std::string& name);
|
||||
|
||||
virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);
|
||||
|
||||
struct {
|
||||
CSignal newSurface; // SP<CXWaylandSurfaceResource>. Fired when it sets a serial, otherwise it's useless
|
||||
} events;
|
||||
|
||||
private:
|
||||
void destroyResource(CXWaylandSurfaceResource* resource);
|
||||
void destroyResource(CXWaylandShellResource* resource);
|
||||
|
||||
//
|
||||
std::vector<SP<CXWaylandShellResource>> m_vManagers;
|
||||
std::vector<SP<CXWaylandSurfaceResource>> m_vSurfaces;
|
||||
|
||||
friend class CXWaylandSurfaceResource;
|
||||
friend class CXWaylandShellResource;
|
||||
};
|
||||
|
||||
namespace PROTO {
|
||||
inline UP<CXWaylandShellProtocol> xwaylandShell;
|
||||
};
|
|
@ -15,3 +15,7 @@ bool IDataSource::used() {
|
|||
void IDataSource::markUsed() {
|
||||
wasUsed = true;
|
||||
}
|
||||
|
||||
eDataSourceType IDataSource::type() {
|
||||
return DATA_SOURCE_TYPE_WAYLAND;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,11 @@
|
|||
#include <cstdint>
|
||||
#include "../../helpers/signal/Signal.hpp"
|
||||
|
||||
enum eDataSourceType {
|
||||
DATA_SOURCE_TYPE_WAYLAND = 0,
|
||||
DATA_SOURCE_TYPE_X11,
|
||||
};
|
||||
|
||||
class IDataSource {
|
||||
public:
|
||||
IDataSource() {}
|
||||
|
@ -19,6 +24,7 @@ class IDataSource {
|
|||
virtual bool used();
|
||||
virtual void markUsed();
|
||||
virtual void error(uint32_t code, const std::string& msg) = 0;
|
||||
virtual eDataSourceType type();
|
||||
|
||||
struct {
|
||||
CSignal destroy;
|
||||
|
|
|
@ -192,14 +192,10 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data)
|
|||
g_pHyprOpenGL->blend(true);
|
||||
|
||||
if (RDATA->surface && surface == RDATA->surface) {
|
||||
if (wlr_xwayland_surface_try_from_wlr_surface(surface) && !wlr_xwayland_surface_try_from_wlr_surface(surface)->has_alpha && ALPHA == 1.f) {
|
||||
if (RDATA->blur)
|
||||
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, RDATA->blockBlurOptimization, RDATA->fadeAlpha);
|
||||
else
|
||||
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, true);
|
||||
} else {
|
||||
if (RDATA->blur)
|
||||
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, RDATA->blockBlurOptimization, RDATA->fadeAlpha);
|
||||
else
|
||||
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, true);
|
||||
}
|
||||
} else {
|
||||
if (RDATA->blur && RDATA->popup)
|
||||
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, true, RDATA->fadeAlpha);
|
||||
|
|
427
src/xwayland/Server.cpp
Normal file
427
src/xwayland/Server.cpp
Normal file
|
@ -0,0 +1,427 @@
|
|||
#ifndef NO_XWAYLAND
|
||||
|
||||
#include "Server.hpp"
|
||||
#include "../defines.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../managers/CursorManager.hpp"
|
||||
#include "XWayland.hpp"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// TODO: cleanup
|
||||
static bool set_cloexec(int fd, bool cloexec) {
|
||||
int flags = fcntl(fd, F_GETFD);
|
||||
if (flags == -1) {
|
||||
wlr_log_errno(WLR_ERROR, "fcntl failed");
|
||||
return false;
|
||||
}
|
||||
if (cloexec) {
|
||||
flags = flags | FD_CLOEXEC;
|
||||
} else {
|
||||
flags = flags & ~FD_CLOEXEC;
|
||||
}
|
||||
if (fcntl(fd, F_SETFD, flags) == -1) {
|
||||
wlr_log_errno(WLR_ERROR, "fcntl failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int openSocket(struct sockaddr_un* addr, size_t path_size) {
|
||||
int fd, rc;
|
||||
socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1;
|
||||
|
||||
fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to create socket %c%s", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1);
|
||||
return -1;
|
||||
}
|
||||
if (!set_cloexec(fd, true)) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (addr->sun_path[0]) {
|
||||
unlink(addr->sun_path);
|
||||
}
|
||||
if (bind(fd, (struct sockaddr*)addr, size) < 0) {
|
||||
rc = errno;
|
||||
wlr_log_errno(WLR_ERROR, "Failed to bind socket %c%s", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1);
|
||||
goto cleanup;
|
||||
}
|
||||
if (listen(fd, 1) < 0) {
|
||||
rc = errno;
|
||||
wlr_log_errno(WLR_ERROR, "Failed to listen to socket %c%s", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
return fd;
|
||||
|
||||
cleanup:
|
||||
close(fd);
|
||||
if (addr->sun_path[0]) {
|
||||
unlink(addr->sun_path);
|
||||
}
|
||||
errno = rc;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool checkPermissionsForSocketDir(void) {
|
||||
struct stat buf;
|
||||
|
||||
if (lstat("/tmp/.X11-unix", &buf)) {
|
||||
Debug::log(ERR, "Failed statting X11 socket dir");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(buf.st_mode & S_IFDIR)) {
|
||||
Debug::log(ERR, "X11 socket dir is not a dir");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!((buf.st_uid == 0) || (buf.st_uid == getuid()))) {
|
||||
Debug::log(ERR, "X11 socket dir is not ours");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(buf.st_mode & S_ISVTX)) {
|
||||
if ((buf.st_mode & (S_IWGRP | S_IWOTH))) {
|
||||
Debug::log(ERR, "X11 socket dir is sticky by others");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool openSockets(std::array<int, 2>& sockets, int display) {
|
||||
auto ret = mkdir("/tmp/.X11-unix", 755);
|
||||
|
||||
if (ret != 0) {
|
||||
if (errno == EEXIST) {
|
||||
if (!checkPermissionsForSocketDir())
|
||||
return false;
|
||||
} else {
|
||||
Debug::log(ERR, "XWayland: couldn't create socket dir");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string path;
|
||||
sockaddr_un addr = {.sun_family = AF_UNIX};
|
||||
|
||||
#ifdef __linux__
|
||||
// cursed...
|
||||
addr.sun_path[0] = 0;
|
||||
path = std::format("/tmp/.X11-unix/X{}", display);
|
||||
strncpy(addr.sun_path + 1, path.c_str(), path.length() + 1);
|
||||
#else
|
||||
path = std::format("/tmp/.X11-unix/X{}_", display);
|
||||
strncpy(addr.sun_path, path.c_str(), path.length() + 1);
|
||||
#endif
|
||||
sockets[0] = openSocket(&addr, path.length());
|
||||
if (sockets[0] < 0)
|
||||
return false;
|
||||
|
||||
path = std::format("/tmp/.X11-unix/X{}", display);
|
||||
strncpy(addr.sun_path, path.c_str(), path.length() + 1);
|
||||
sockets[1] = openSocket(&addr, path.length());
|
||||
if (sockets[1] < 0) {
|
||||
close(sockets[0]);
|
||||
sockets[0] = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void startServer(void* data) {
|
||||
if (!g_pXWayland->pServer->start())
|
||||
Debug::log(ERR, "The XWayland server could not start! XWayland will not work...");
|
||||
}
|
||||
|
||||
static int xwaylandReady(int fd, uint32_t mask, void* data) {
|
||||
return g_pXWayland->pServer->ready(fd, mask);
|
||||
}
|
||||
|
||||
bool CXWaylandServer::tryOpenSockets() {
|
||||
for (size_t i = 0; i <= 32; ++i) {
|
||||
auto LOCK = std::format("/tmp/.X{}-lock", i);
|
||||
|
||||
if (int fd = open(LOCK.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0444); fd >= 0) {
|
||||
// we managed to open the lock
|
||||
if (!openSockets(xFDs, i)) {
|
||||
std::filesystem::remove(LOCK);
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto PIDSTR = std::format("{}", getpid());
|
||||
|
||||
if (write(fd, PIDSTR.c_str(), PIDSTR.length()) != (long)PIDSTR.length()) {
|
||||
std::filesystem::remove(LOCK);
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
display = i;
|
||||
displayName = std::format(":{}", display);
|
||||
break;
|
||||
}
|
||||
|
||||
int fd = open(LOCK.c_str(), O_RDONLY | O_CLOEXEC);
|
||||
|
||||
if (fd < 0)
|
||||
continue;
|
||||
|
||||
char pidstr[12] = {0};
|
||||
read(fd, pidstr, sizeof(pidstr) - 1);
|
||||
close(fd);
|
||||
|
||||
uint64_t pid = 0;
|
||||
try {
|
||||
pid = std::stoi(std::string{pidstr, 11});
|
||||
} catch (...) { continue; }
|
||||
|
||||
if (kill(pid, 0) != 0 && errno == ESRCH) {
|
||||
if (!std::filesystem::remove(LOCK))
|
||||
continue;
|
||||
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
if (display < 0) {
|
||||
Debug::log(ERR, "Failed to find a suitable socket for xwayland");
|
||||
return false;
|
||||
}
|
||||
|
||||
Debug::log(LOG, "XWayland found a suitable display socket at DISPLAY: {}", displayName);
|
||||
return true;
|
||||
}
|
||||
|
||||
CXWaylandServer::CXWaylandServer() {
|
||||
;
|
||||
}
|
||||
|
||||
CXWaylandServer::~CXWaylandServer() {
|
||||
die();
|
||||
if (display < 0)
|
||||
return;
|
||||
|
||||
if (xFDs[0])
|
||||
close(xFDs[0]);
|
||||
if (xFDs[1])
|
||||
close(xFDs[1]);
|
||||
|
||||
auto LOCK = std::format("/tmp/.X{}-lock", display);
|
||||
std::filesystem::remove(LOCK);
|
||||
|
||||
std::string path;
|
||||
#ifdef __linux__
|
||||
path = std::format("/tmp/.X11-unix/X{}", display);
|
||||
#else
|
||||
path = std::format("/tmp/.X11-unix/X{}_", display);
|
||||
#endif
|
||||
std::filesystem::remove(path);
|
||||
}
|
||||
|
||||
void CXWaylandServer::die() {
|
||||
if (display < 0)
|
||||
return;
|
||||
|
||||
if (xFDReadEvents[0]) {
|
||||
wl_event_source_remove(xFDReadEvents[0]);
|
||||
wl_event_source_remove(xFDReadEvents[1]);
|
||||
|
||||
xFDReadEvents = {nullptr, nullptr};
|
||||
}
|
||||
|
||||
if (pipeSource)
|
||||
wl_event_source_remove(pipeSource);
|
||||
|
||||
if (waylandFDs[0])
|
||||
close(waylandFDs[0]);
|
||||
if (waylandFDs[1])
|
||||
close(waylandFDs[1]);
|
||||
if (xwmFDs[0])
|
||||
close(xwmFDs[0]);
|
||||
if (xwmFDs[1])
|
||||
close(xwmFDs[1]);
|
||||
|
||||
if (xwaylandClient)
|
||||
wl_client_destroy(xwaylandClient);
|
||||
|
||||
xwaylandClient = nullptr;
|
||||
waylandFDs = {-1, -1};
|
||||
xwmFDs = {-1, -1};
|
||||
}
|
||||
|
||||
bool CXWaylandServer::create() {
|
||||
if (!tryOpenSockets())
|
||||
return false;
|
||||
|
||||
setenv("DISPLAY", displayName.c_str(), true);
|
||||
|
||||
// TODO: lazy mode
|
||||
|
||||
idleSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, ::startServer, nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CXWaylandServer::runXWayland(int notifyFD) {
|
||||
if (!set_cloexec(xFDs[0], false) || !set_cloexec(xFDs[1], false) || !set_cloexec(waylandFDs[1], false) || !set_cloexec(xwmFDs[1], false)) {
|
||||
Debug::log(ERR, "Failed to unset cloexec on fds");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
auto cmd = std::format("Xwayland {} -rootless -core -listenfd {} -listenfd {} -displayfd {} -wm {}", displayName, xFDs[0], xFDs[1], notifyFD, xwmFDs[1]);
|
||||
|
||||
auto waylandSocket = std::format("{}", waylandFDs[1]);
|
||||
setenv("WAYLAND_SOCKET", waylandSocket.c_str(), true);
|
||||
|
||||
Debug::log(LOG, "Starting XWayland with \"{}\", bon voyage!", cmd);
|
||||
|
||||
execl("/bin/sh", "/bin/sh", "-c", cmd.c_str(), nullptr);
|
||||
|
||||
Debug::log(ERR, "XWayland failed to open");
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
bool CXWaylandServer::start() {
|
||||
idleSource = nullptr;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, waylandFDs.data()) != 0) {
|
||||
Debug::log(ERR, "socketpair failed (1)");
|
||||
die();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!set_cloexec(waylandFDs[0], true) || !set_cloexec(waylandFDs[1], true)) {
|
||||
Debug::log(ERR, "set_cloexec failed (1)");
|
||||
die();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, xwmFDs.data()) != 0) {
|
||||
Debug::log(ERR, "socketpair failed (2)");
|
||||
die();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!set_cloexec(xwmFDs[0], true) || !set_cloexec(xwmFDs[1], true)) {
|
||||
Debug::log(ERR, "set_cloexec failed (2)");
|
||||
die();
|
||||
return false;
|
||||
}
|
||||
|
||||
xwaylandClient = wl_client_create(g_pCompositor->m_sWLDisplay, waylandFDs[0]);
|
||||
if (!xwaylandClient) {
|
||||
Debug::log(ERR, "wl_client_create failed");
|
||||
die();
|
||||
return false;
|
||||
}
|
||||
|
||||
waylandFDs[0] = -1;
|
||||
|
||||
int notify[2] = {-1, -1};
|
||||
if (pipe(notify) < 0) {
|
||||
Debug::log(ERR, "pipe failed");
|
||||
die();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!set_cloexec(notify[0], true)) {
|
||||
Debug::log(ERR, "set_cloexec failed (3)");
|
||||
close(notify[0]);
|
||||
close(notify[1]);
|
||||
die();
|
||||
return false;
|
||||
}
|
||||
|
||||
pipeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, notify[0], WL_EVENT_READABLE, ::xwaylandReady, nullptr);
|
||||
|
||||
serverPID = fork();
|
||||
if (serverPID < 0) {
|
||||
Debug::log(ERR, "fork failed");
|
||||
close(notify[0]);
|
||||
close(notify[1]);
|
||||
die();
|
||||
return false;
|
||||
} else if (serverPID == 0) {
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
Debug::log(ERR, "second fork failed");
|
||||
_exit(1);
|
||||
} else if (pid == 0) {
|
||||
runXWayland(notify[1]);
|
||||
}
|
||||
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
close(notify[1]);
|
||||
close(waylandFDs[1]);
|
||||
close(xwmFDs[1]);
|
||||
waylandFDs[1] = -1;
|
||||
xwmFDs[1] = -1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int CXWaylandServer::ready(int fd, uint32_t mask) {
|
||||
if (mask & WL_EVENT_READABLE) {
|
||||
// xwayland writes twice
|
||||
char buf[64];
|
||||
ssize_t n = read(fd, buf, sizeof(buf));
|
||||
if (n < 0 && errno != EINTR) {
|
||||
Debug::log(ERR, "Xwayland: read from displayFd failed");
|
||||
mask = 0;
|
||||
} else if (n <= 0 || buf[n - 1] != '\n')
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (waitpid(serverPID, nullptr, 0) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
Debug::log(ERR, "Xwayland: waitpid for fork failed");
|
||||
g_pXWayland->pServer.reset();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// if we don't have readable here, it failed
|
||||
if (!(mask & WL_EVENT_READABLE)) {
|
||||
Debug::log(ERR, "Xwayland: startup failed, not setting up xwm");
|
||||
g_pXWayland->pServer.reset();
|
||||
return 1;
|
||||
}
|
||||
|
||||
Debug::log(LOG, "XWayland is ready");
|
||||
|
||||
close(fd);
|
||||
wl_event_source_remove(pipeSource);
|
||||
pipeSource = nullptr;
|
||||
|
||||
// start the wm
|
||||
g_pXWayland->pWM = std::make_unique<CXWM>();
|
||||
|
||||
g_pCursorManager->setXWaylandCursor();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
48
src/xwayland/Server.hpp
Normal file
48
src/xwayland/Server.hpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
|
||||
struct wl_event_source;
|
||||
struct wl_client;
|
||||
|
||||
// TODO: add lazy mode
|
||||
class CXWaylandServer {
|
||||
public:
|
||||
CXWaylandServer();
|
||||
~CXWaylandServer();
|
||||
|
||||
// create the server.
|
||||
bool create();
|
||||
|
||||
// starts the server, meant to be called by CXWaylandServer.
|
||||
bool start();
|
||||
|
||||
// called on ready
|
||||
int ready(int fd, uint32_t mask);
|
||||
|
||||
void die();
|
||||
|
||||
struct {
|
||||
CSignal ready;
|
||||
} events;
|
||||
|
||||
wl_client* xwaylandClient = nullptr;
|
||||
|
||||
private:
|
||||
bool tryOpenSockets();
|
||||
void runXWayland(int notifyFD);
|
||||
|
||||
pid_t serverPID = 0;
|
||||
|
||||
std::string displayName;
|
||||
int display = -1;
|
||||
std::array<int, 2> xFDs = {-1, -1};
|
||||
std::array<wl_event_source*, 2> xFDReadEvents = {nullptr, nullptr};
|
||||
wl_event_source* idleSource = nullptr;
|
||||
wl_event_source* pipeSource = nullptr;
|
||||
std::array<int, 2> xwmFDs = {-1, -1};
|
||||
std::array<int, 2> waylandFDs = {-1, -1};
|
||||
|
||||
friend class CXWM;
|
||||
};
|
97
src/xwayland/XDataSource.cpp
Normal file
97
src/xwayland/XDataSource.cpp
Normal file
|
@ -0,0 +1,97 @@
|
|||
#ifndef NO_XWAYLAND
|
||||
|
||||
#include "XDataSource.hpp"
|
||||
#include "XWayland.hpp"
|
||||
#include "../defines.hpp"
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
CXDataSource::CXDataSource(SXSelection& sel_) : selection(sel_) {
|
||||
xcb_get_property_cookie_t cookie = xcb_get_property(g_pXWayland->pWM->connection,
|
||||
1, // delete
|
||||
selection.window, HYPRATOMS["_WL_SELECTION"], XCB_GET_PROPERTY_TYPE_ANY, 0, 4096);
|
||||
|
||||
xcb_get_property_reply_t* reply = xcb_get_property_reply(g_pXWayland->pWM->connection, cookie, NULL);
|
||||
if (!reply)
|
||||
return;
|
||||
|
||||
if (reply->type != XCB_ATOM_ATOM) {
|
||||
free(reply);
|
||||
return;
|
||||
}
|
||||
|
||||
auto value = (xcb_atom_t*)xcb_get_property_value(reply);
|
||||
for (uint32_t i = 0; i < reply->value_len; i++) {
|
||||
if (value[i] == HYPRATOMS["UTF8_STRING"])
|
||||
mimeTypes.push_back("text/plain;charset=utf-8");
|
||||
else if (value[i] == HYPRATOMS["TEXT"])
|
||||
mimeTypes.push_back("text/plain");
|
||||
else if (value[i] != HYPRATOMS["TARGETS"] && value[i] != HYPRATOMS["TIMESTAMP"]) {
|
||||
|
||||
auto type = g_pXWayland->pWM->mimeFromAtom(value[i]);
|
||||
|
||||
if (type == "INVALID")
|
||||
continue;
|
||||
|
||||
mimeTypes.push_back(type);
|
||||
}
|
||||
|
||||
mimeAtoms.push_back(value[i]);
|
||||
}
|
||||
|
||||
free(reply);
|
||||
}
|
||||
|
||||
std::vector<std::string> CXDataSource::mimes() {
|
||||
return mimeTypes;
|
||||
}
|
||||
|
||||
void CXDataSource::send(const std::string& mime, uint32_t fd) {
|
||||
xcb_atom_t mimeAtom = 0;
|
||||
|
||||
for (size_t i = 0; i < mimeTypes.size(); ++i) {
|
||||
if (mimeTypes.at(i) == mime) {
|
||||
mimeAtom = mimeAtoms.at(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mimeAtom) {
|
||||
Debug::log(ERR, "[XDataSource] mime atom not found");
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
Debug::log(LOG, "[XDataSource] send with mime {} to fd {}", mime, fd);
|
||||
|
||||
selection.transfer = std::make_unique<SXTransfer>(selection);
|
||||
selection.transfer->incomingWindow = xcb_generate_id(g_pXWayland->pWM->connection);
|
||||
const uint32_t MASK = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE;
|
||||
xcb_create_window(g_pXWayland->pWM->connection, XCB_COPY_FROM_PARENT, selection.transfer->incomingWindow, g_pXWayland->pWM->screen->root, 0, 0, 10, 10, 0,
|
||||
XCB_WINDOW_CLASS_INPUT_OUTPUT, g_pXWayland->pWM->screen->root_visual, XCB_CW_EVENT_MASK, &MASK);
|
||||
|
||||
xcb_convert_selection(g_pXWayland->pWM->connection, selection.transfer->incomingWindow, HYPRATOMS["CLIPBOARD"], mimeAtom, HYPRATOMS["_WL_SELECTION"], XCB_TIME_CURRENT_TIME);
|
||||
|
||||
xcb_flush(g_pXWayland->pWM->connection);
|
||||
|
||||
fcntl(fd, F_SETFL, O_WRONLY | O_NONBLOCK);
|
||||
selection.transfer->wlFD = fd;
|
||||
}
|
||||
|
||||
void CXDataSource::accepted(const std::string& mime) {
|
||||
Debug::log(LOG, "[XDataSource] accepted is a stub");
|
||||
}
|
||||
|
||||
void CXDataSource::cancelled() {
|
||||
Debug::log(LOG, "[XDataSource] cancelled is a stub");
|
||||
}
|
||||
|
||||
void CXDataSource::error(uint32_t code, const std::string& msg) {
|
||||
Debug::log(LOG, "[XDataSource] error is a stub: err {}: {}", code, msg);
|
||||
}
|
||||
|
||||
eDataSourceType CXDataSource::type() {
|
||||
return DATA_SOURCE_TYPE_X11;
|
||||
}
|
||||
|
||||
#endif
|
22
src/xwayland/XDataSource.hpp
Normal file
22
src/xwayland/XDataSource.hpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "../protocols/types/DataDevice.hpp"
|
||||
|
||||
struct SXSelection;
|
||||
|
||||
class CXDataSource : public IDataSource {
|
||||
public:
|
||||
CXDataSource(SXSelection&);
|
||||
|
||||
virtual std::vector<std::string> mimes();
|
||||
virtual void send(const std::string& mime, uint32_t fd);
|
||||
virtual void accepted(const std::string& mime);
|
||||
virtual void cancelled();
|
||||
virtual void error(uint32_t code, const std::string& msg);
|
||||
virtual eDataSourceType type();
|
||||
|
||||
private:
|
||||
SXSelection& selection;
|
||||
std::vector<std::string> mimeTypes; // these two have shared idx
|
||||
std::vector<uint32_t> mimeAtoms; //
|
||||
};
|
291
src/xwayland/XSurface.cpp
Normal file
291
src/xwayland/XSurface.cpp
Normal file
|
@ -0,0 +1,291 @@
|
|||
#include "XSurface.hpp"
|
||||
#include "XWayland.hpp"
|
||||
#include "../protocols/XWaylandShell.hpp"
|
||||
|
||||
#ifndef NO_XWAYLAND
|
||||
|
||||
#include "../Compositor.hpp"
|
||||
#include <ranges>
|
||||
|
||||
CXWaylandSurface::CXWaylandSurface(uint32_t xID_, CBox geometry_, bool OR) : xID(xID_), geometry(geometry_), overrideRedirect(OR) {
|
||||
xcb_res_query_client_ids_cookie_t client_id_cookie = {0};
|
||||
if (g_pXWayland->pWM->xres) {
|
||||
xcb_res_client_id_spec_t spec = {.client = xID, .mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID};
|
||||
client_id_cookie = xcb_res_query_client_ids(g_pXWayland->pWM->connection, 1, &spec);
|
||||
}
|
||||
|
||||
uint32_t values[1];
|
||||
values[0] = XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_PROPERTY_CHANGE;
|
||||
xcb_change_window_attributes(g_pXWayland->pWM->connection, xID, XCB_CW_EVENT_MASK, values);
|
||||
|
||||
if (g_pXWayland->pWM->xres) {
|
||||
xcb_res_query_client_ids_reply_t* reply = xcb_res_query_client_ids_reply(g_pXWayland->pWM->connection, client_id_cookie, nullptr);
|
||||
if (!reply)
|
||||
return;
|
||||
|
||||
uint32_t* ppid = nullptr;
|
||||
xcb_res_client_id_value_iterator_t iter = xcb_res_query_client_ids_ids_iterator(reply);
|
||||
while (iter.rem > 0) {
|
||||
if (iter.data->spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID && xcb_res_client_id_value_value_length(iter.data) > 0) {
|
||||
ppid = xcb_res_client_id_value_value(iter.data);
|
||||
break;
|
||||
}
|
||||
xcb_res_client_id_value_next(&iter);
|
||||
}
|
||||
if (ppid == NULL) {
|
||||
free(reply);
|
||||
return;
|
||||
}
|
||||
pid = *ppid;
|
||||
free(reply);
|
||||
}
|
||||
|
||||
events.resourceChange.registerStaticListener([this](void* data, std::any d) { ensureListeners(); }, nullptr);
|
||||
}
|
||||
|
||||
void CXWaylandSurface::ensureListeners() {
|
||||
bool connected = hyprListener_surfaceDestroy.isConnected();
|
||||
|
||||
if (connected && !surface) {
|
||||
hyprListener_surfaceDestroy.removeCallback();
|
||||
hyprListener_surfaceCommit.removeCallback();
|
||||
} else if (!connected && surface) {
|
||||
hyprListener_surfaceDestroy.initCallback(
|
||||
&surface->events.destroy,
|
||||
[this](void* owner, void* data) {
|
||||
if (mapped)
|
||||
unmap();
|
||||
|
||||
surface = nullptr;
|
||||
hyprListener_surfaceDestroy.removeCallback();
|
||||
hyprListener_surfaceCommit.removeCallback();
|
||||
events.resourceChange.emit();
|
||||
},
|
||||
nullptr, "CXWaylandSurface");
|
||||
hyprListener_surfaceCommit.initCallback(
|
||||
&surface->events.commit,
|
||||
[this](void* owner, void* data) {
|
||||
if (surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0 && !mapped) {
|
||||
map();
|
||||
return;
|
||||
}
|
||||
|
||||
if (surface->pending.buffer_width <= 0 && surface->pending.buffer_height <= 0 && mapped) {
|
||||
unmap();
|
||||
return;
|
||||
}
|
||||
|
||||
events.commit.emit();
|
||||
},
|
||||
nullptr, "CXWaylandSurface");
|
||||
}
|
||||
|
||||
if (resource) {
|
||||
listeners.destroyResource = resource->events.destroy.registerListener([this](std::any d) {
|
||||
unmap();
|
||||
surface = nullptr;
|
||||
events.resourceChange.emit();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void CXWaylandSurface::map() {
|
||||
if (mapped)
|
||||
return;
|
||||
|
||||
ASSERT(surface);
|
||||
|
||||
g_pXWayland->pWM->mappedSurfaces.emplace_back(self);
|
||||
g_pXWayland->pWM->mappedSurfacesStacking.emplace_back(self);
|
||||
|
||||
mapped = true;
|
||||
wlr_surface_map(surface);
|
||||
|
||||
Debug::log(LOG, "XWayland surface {:x} mapping", (uintptr_t)this);
|
||||
|
||||
events.map.emit();
|
||||
|
||||
g_pXWayland->pWM->updateClientList();
|
||||
}
|
||||
|
||||
void CXWaylandSurface::unmap() {
|
||||
if (!mapped)
|
||||
return;
|
||||
|
||||
ASSERT(surface);
|
||||
|
||||
std::erase(g_pXWayland->pWM->mappedSurfaces, self);
|
||||
std::erase(g_pXWayland->pWM->mappedSurfacesStacking, self);
|
||||
|
||||
mapped = false;
|
||||
wlr_surface_unmap(surface);
|
||||
|
||||
Debug::log(LOG, "XWayland surface {:x} unmapping", (uintptr_t)this);
|
||||
|
||||
events.unmap.emit();
|
||||
|
||||
g_pXWayland->pWM->updateClientList();
|
||||
}
|
||||
|
||||
void CXWaylandSurface::considerMap() {
|
||||
if (mapped)
|
||||
return;
|
||||
|
||||
if (!surface) {
|
||||
Debug::log(LOG, "XWayland surface: considerMap, nope, no surface");
|
||||
return;
|
||||
}
|
||||
|
||||
if (surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0) {
|
||||
Debug::log(LOG, "XWayland surface: considerMap, sure, we have a buffer");
|
||||
map();
|
||||
return;
|
||||
}
|
||||
|
||||
Debug::log(LOG, "XWayland surface: considerMap, nope, we don't have a buffer");
|
||||
}
|
||||
|
||||
bool CXWaylandSurface::wantsFocus() {
|
||||
if (atoms.empty())
|
||||
return true;
|
||||
|
||||
const std::array<uint32_t, 10> search = {
|
||||
HYPRATOMS["_NET_WM_WINDOW_TYPE_COMBO"], HYPRATOMS["_NET_WM_WINDOW_TYPE_DND"], HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"],
|
||||
HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"], HYPRATOMS["_NET_WM_WINDOW_TYPE_NOTIFICATION"], HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"],
|
||||
HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"], HYPRATOMS["_NET_WM_WINDOW_TYPE_DESKTOP"], HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"],
|
||||
HYPRATOMS["_NET_WM_WINDOW_TYPE_UTILITY"],
|
||||
};
|
||||
|
||||
for (auto& searched : search) {
|
||||
for (auto& a : atoms) {
|
||||
if (a == searched)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CXWaylandSurface::configure(const CBox& box) {
|
||||
Vector2D oldSize = geometry.size();
|
||||
|
||||
geometry = box;
|
||||
|
||||
uint32_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT | XCB_CONFIG_WINDOW_BORDER_WIDTH;
|
||||
uint32_t values[] = {box.x, box.y, box.width, box.height, 0};
|
||||
xcb_configure_window(g_pXWayland->pWM->connection, xID, mask, values);
|
||||
|
||||
g_pXWayland->pWM->updateClientList();
|
||||
|
||||
xcb_flush(g_pXWayland->pWM->connection);
|
||||
}
|
||||
|
||||
void CXWaylandSurface::activate(bool activate) {
|
||||
if (overrideRedirect && !activate)
|
||||
return;
|
||||
g_pXWayland->pWM->activateSurface(self.lock());
|
||||
}
|
||||
|
||||
void CXWaylandSurface::setFullscreen(bool fs) {
|
||||
fullscreen = fs;
|
||||
g_pXWayland->pWM->sendState(self.lock());
|
||||
}
|
||||
|
||||
void CXWaylandSurface::setMinimized(bool mz) {
|
||||
minimized = mz;
|
||||
g_pXWayland->pWM->sendState(self.lock());
|
||||
}
|
||||
|
||||
void CXWaylandSurface::restackToTop() {
|
||||
uint32_t values[1] = {XCB_STACK_MODE_ABOVE};
|
||||
|
||||
xcb_configure_window(g_pXWayland->pWM->connection, xID, XCB_CONFIG_WINDOW_STACK_MODE, values);
|
||||
|
||||
for (auto it = g_pXWayland->pWM->mappedSurfacesStacking.begin(); it != g_pXWayland->pWM->mappedSurfacesStacking.end(); ++it) {
|
||||
if (*it == self) {
|
||||
std::rotate(it, it + 1, g_pXWayland->pWM->mappedSurfacesStacking.end());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_pXWayland->pWM->updateClientList();
|
||||
|
||||
xcb_flush(g_pXWayland->pWM->connection);
|
||||
}
|
||||
|
||||
void CXWaylandSurface::close() {
|
||||
xcb_client_message_data_t msg = {0};
|
||||
msg.data32[0] = HYPRATOMS["WM_DELETE_WINDOW"];
|
||||
msg.data32[1] = XCB_CURRENT_TIME;
|
||||
g_pXWayland->pWM->sendWMMessage(self.lock(), &msg, XCB_EVENT_MASK_NO_EVENT);
|
||||
}
|
||||
|
||||
void CXWaylandSurface::setWithdrawn(bool withdrawn_) {
|
||||
withdrawn = withdrawn_;
|
||||
std::vector<uint32_t> props = {XCB_ICCCM_WM_STATE_NORMAL, XCB_WINDOW_NONE};
|
||||
|
||||
if (withdrawn)
|
||||
props[0] = XCB_ICCCM_WM_STATE_WITHDRAWN;
|
||||
else if (minimized)
|
||||
props[0] = XCB_ICCCM_WM_STATE_ICONIC;
|
||||
else
|
||||
props[0] = XCB_ICCCM_WM_STATE_NORMAL;
|
||||
|
||||
xcb_change_property(g_pXWayland->pWM->connection, XCB_PROP_MODE_REPLACE, xID, HYPRATOMS["WM_STATE"], HYPRATOMS["WM_STATE"], 32, props.size(), props.data());
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
CXWaylandSurface::CXWaylandSurface(uint32_t xID_, CBox geometry_, bool OR) : xID(xID_), geometry(geometry_), overrideRedirect(OR) {
|
||||
;
|
||||
}
|
||||
|
||||
void CXWaylandSurface::ensureListeners() {
|
||||
;
|
||||
}
|
||||
|
||||
void CXWaylandSurface::map() {
|
||||
;
|
||||
}
|
||||
|
||||
void CXWaylandSurface::unmap() {
|
||||
;
|
||||
}
|
||||
|
||||
bool CXWaylandSurface::wantsFocus() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void CXWaylandSurface::configure(const CBox& box) {
|
||||
;
|
||||
}
|
||||
|
||||
void CXWaylandSurface::activate(bool activate) {
|
||||
;
|
||||
}
|
||||
|
||||
void CXWaylandSurface::setFullscreen(bool fs) {
|
||||
;
|
||||
}
|
||||
|
||||
void CXWaylandSurface::setMinimized(bool mz) {
|
||||
;
|
||||
}
|
||||
|
||||
void CXWaylandSurface::restackToTop() {
|
||||
;
|
||||
}
|
||||
|
||||
void CXWaylandSurface::close() {
|
||||
;
|
||||
}
|
||||
|
||||
void CXWaylandSurface::considerMap() {
|
||||
;
|
||||
}
|
||||
|
||||
void CXWaylandSurface::setWithdrawn(bool withdrawn) {
|
||||
;
|
||||
}
|
||||
|
||||
#endif
|
120
src/xwayland/XSurface.hpp
Normal file
120
src/xwayland/XSurface.hpp
Normal file
|
@ -0,0 +1,120 @@
|
|||
#pragma once
|
||||
|
||||
#include "../helpers/WLListener.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
#include "../helpers/Box.hpp"
|
||||
#include <vector>
|
||||
|
||||
struct wlr_surface;
|
||||
class CXWaylandSurfaceResource;
|
||||
|
||||
#ifdef NO_XWAYLAND
|
||||
typedef uint32_t xcb_pixmap_t;
|
||||
typedef uint32_t xcb_window_t;
|
||||
typedef struct {
|
||||
int32_t flags;
|
||||
uint32_t input;
|
||||
int32_t initial_state;
|
||||
xcb_pixmap_t icon_pixmap;
|
||||
xcb_window_t icon_window;
|
||||
int32_t icon_x, icon_y;
|
||||
xcb_pixmap_t icon_mask;
|
||||
xcb_window_t window_group;
|
||||
} xcb_icccm_wm_hints_t;
|
||||
typedef struct {
|
||||
uint32_t flags;
|
||||
int32_t x, y;
|
||||
int32_t width, height;
|
||||
int32_t min_width, min_height;
|
||||
int32_t max_width, max_height;
|
||||
int32_t width_inc, height_inc;
|
||||
int32_t min_aspect_num, min_aspect_den;
|
||||
int32_t max_aspect_num, max_aspect_den;
|
||||
int32_t base_width, base_height;
|
||||
uint32_t win_gravity;
|
||||
} xcb_size_hints_t;
|
||||
#else
|
||||
#include <xcb/xcb_icccm.h>
|
||||
#endif
|
||||
|
||||
class CXWaylandSurface {
|
||||
public:
|
||||
wlr_surface* surface = nullptr;
|
||||
WP<CXWaylandSurfaceResource> resource;
|
||||
|
||||
struct {
|
||||
CSignal stateChanged; // maximized, fs, minimized, etc.
|
||||
CSignal metadataChanged; // title, appid
|
||||
CSignal destroy;
|
||||
|
||||
CSignal resourceChange; // associated / dissociated
|
||||
|
||||
CSignal setGeometry;
|
||||
CSignal configure; // CBox
|
||||
|
||||
CSignal map;
|
||||
CSignal unmap;
|
||||
CSignal commit;
|
||||
|
||||
CSignal activate;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
std::string title;
|
||||
std::string appid;
|
||||
|
||||
// volatile state: is reset after the stateChanged signal fires
|
||||
std::optional<bool> requestsMaximize;
|
||||
std::optional<bool> requestsFullscreen;
|
||||
std::optional<bool> requestsMinimize;
|
||||
} state;
|
||||
|
||||
uint32_t xID = 0;
|
||||
uint64_t wlID = 0;
|
||||
uint64_t wlSerial = 0;
|
||||
pid_t pid = 0;
|
||||
CBox geometry;
|
||||
bool overrideRedirect = false;
|
||||
bool withdrawn = false;
|
||||
bool fullscreen = false;
|
||||
bool maximized = false;
|
||||
bool minimized = false;
|
||||
bool mapped = false;
|
||||
bool modal = false;
|
||||
|
||||
WP<CXWaylandSurface> parent;
|
||||
WP<CXWaylandSurface> self;
|
||||
std::vector<WP<CXWaylandSurface>> children;
|
||||
|
||||
UP<xcb_icccm_wm_hints_t> hints;
|
||||
UP<xcb_size_hints_t> sizeHints;
|
||||
std::vector<uint32_t> atoms;
|
||||
std::string role = "";
|
||||
bool transient = false;
|
||||
|
||||
bool wantsFocus();
|
||||
void configure(const CBox& box);
|
||||
void activate(bool activate);
|
||||
void setFullscreen(bool fs);
|
||||
void setMinimized(bool mz);
|
||||
void restackToTop();
|
||||
void close();
|
||||
|
||||
private:
|
||||
CXWaylandSurface(uint32_t xID, CBox geometry, bool OR);
|
||||
|
||||
void ensureListeners();
|
||||
void map();
|
||||
void unmap();
|
||||
void considerMap();
|
||||
void setWithdrawn(bool withdrawn);
|
||||
|
||||
DYNLISTENER(surfaceDestroy);
|
||||
DYNLISTENER(surfaceCommit);
|
||||
|
||||
struct {
|
||||
CHyprSignalListener destroyResource;
|
||||
} listeners;
|
||||
|
||||
friend class CXWM;
|
||||
};
|
1210
src/xwayland/XWM.cpp
Normal file
1210
src/xwayland/XWM.cpp
Normal file
File diff suppressed because it is too large
Load diff
160
src/xwayland/XWM.hpp
Normal file
160
src/xwayland/XWM.hpp
Normal file
|
@ -0,0 +1,160 @@
|
|||
#pragma once
|
||||
|
||||
#include "../helpers/signal/Listener.hpp"
|
||||
#include "../helpers/WLListener.hpp"
|
||||
#include "../macros.hpp"
|
||||
|
||||
#include "XDataSource.hpp"
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xcb_errors.h>
|
||||
#include <xcb/composite.h>
|
||||
#include <xcb/xfixes.h>
|
||||
#include <xcb/res.h>
|
||||
|
||||
struct wl_event_source;
|
||||
class CXWaylandSurfaceResource;
|
||||
struct SXSelection;
|
||||
|
||||
struct SXTransfer {
|
||||
~SXTransfer();
|
||||
|
||||
SXSelection& selection;
|
||||
bool out = true;
|
||||
|
||||
bool incremental = false;
|
||||
bool flushOnDelete = false;
|
||||
bool propertySet = false;
|
||||
|
||||
int wlFD = -1;
|
||||
wl_event_source* eventSource = nullptr;
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
xcb_selection_request_event_t request;
|
||||
|
||||
int propertyStart;
|
||||
xcb_get_property_reply_t* propertyReply;
|
||||
xcb_window_t incomingWindow;
|
||||
|
||||
bool getIncomingSelectionProp(bool erase);
|
||||
};
|
||||
|
||||
struct SXSelection {
|
||||
xcb_window_t window = 0;
|
||||
xcb_window_t owner = 0;
|
||||
xcb_timestamp_t timestamp = 0;
|
||||
SP<CXDataSource> dataSource;
|
||||
|
||||
void onSelection();
|
||||
bool sendData(xcb_selection_request_event_t* e, std::string mime);
|
||||
int onRead(int fd, uint32_t mask);
|
||||
|
||||
struct {
|
||||
CHyprSignalListener setSelection;
|
||||
} listeners;
|
||||
|
||||
std::unique_ptr<SXTransfer> transfer;
|
||||
};
|
||||
|
||||
class CXWM {
|
||||
public:
|
||||
CXWM();
|
||||
|
||||
int onEvent(int fd, uint32_t mask);
|
||||
|
||||
private:
|
||||
void setCursor(unsigned char* pixData, uint32_t stride, const Vector2D& size, const Vector2D& hotspot);
|
||||
|
||||
void gatherResources();
|
||||
void getVisual();
|
||||
void getRenderFormat();
|
||||
void createWMWindow();
|
||||
void initSelection();
|
||||
|
||||
void onNewSurface(wlr_surface* surf);
|
||||
void onNewResource(SP<CXWaylandSurfaceResource> resource);
|
||||
|
||||
void setActiveWindow(xcb_window_t window);
|
||||
void sendState(SP<CXWaylandSurface> surf);
|
||||
void focusWindow(SP<CXWaylandSurface> surf);
|
||||
void activateSurface(SP<CXWaylandSurface> surf);
|
||||
bool isWMWindow(xcb_window_t w);
|
||||
|
||||
void sendWMMessage(SP<CXWaylandSurface> surf, xcb_client_message_data_t* data, uint32_t mask);
|
||||
|
||||
SP<CXWaylandSurface> windowForXID(xcb_window_t wid);
|
||||
|
||||
void readWindowData(SP<CXWaylandSurface> surf);
|
||||
void associate(SP<CXWaylandSurface> surf, wlr_surface* wlSurf);
|
||||
void dissociate(SP<CXWaylandSurface> surf);
|
||||
|
||||
void updateClientList();
|
||||
|
||||
// event handlers
|
||||
void handleCreate(xcb_create_notify_event_t* e);
|
||||
void handleDestroy(xcb_destroy_notify_event_t* e);
|
||||
void handleConfigure(xcb_configure_request_event_t* e);
|
||||
void handleConfigureNotify(xcb_configure_notify_event_t* e);
|
||||
void handleMapRequest(xcb_map_request_event_t* e);
|
||||
void handleMapNotify(xcb_map_notify_event_t* e);
|
||||
void handleUnmapNotify(xcb_unmap_notify_event_t* e);
|
||||
void handlePropertyNotify(xcb_property_notify_event_t* e);
|
||||
void handleClientMessage(xcb_client_message_event_t* e);
|
||||
void handleFocusIn(xcb_focus_in_event_t* e);
|
||||
void handleError(xcb_value_error_t* e);
|
||||
|
||||
bool handleSelectionEvent(xcb_generic_event_t* e);
|
||||
void handleSelectionNotify(xcb_selection_notify_event_t* e);
|
||||
bool handleSelectionPropertyNotify(xcb_property_notify_event_t* e);
|
||||
void handleSelectionRequest(xcb_selection_request_event_t* e);
|
||||
bool handleSelectionXFixesNotify(xcb_xfixes_selection_notify_event_t* e);
|
||||
|
||||
void selectionSendNotify(xcb_selection_request_event_t* e, bool success);
|
||||
xcb_atom_t mimeToAtom(const std::string& mime);
|
||||
std::string mimeFromAtom(xcb_atom_t atom);
|
||||
void setClipboardToWayland(SXSelection& sel);
|
||||
void getTransferData(SXSelection& sel);
|
||||
void readProp(SP<CXWaylandSurface> XSURF, uint32_t atom, xcb_get_property_reply_t* reply);
|
||||
|
||||
//
|
||||
xcb_connection_t* connection = nullptr;
|
||||
xcb_errors_context_t* errors = nullptr;
|
||||
xcb_screen_t* screen = nullptr;
|
||||
|
||||
xcb_window_t wmWindow;
|
||||
|
||||
wl_event_source* eventSource = nullptr;
|
||||
|
||||
const xcb_query_extension_reply_t* xfixes = nullptr;
|
||||
const xcb_query_extension_reply_t* xres = nullptr;
|
||||
int xfixesMajor = 0;
|
||||
|
||||
xcb_visualid_t visual_id;
|
||||
xcb_colormap_t colormap;
|
||||
uint32_t cursorXID = 0;
|
||||
|
||||
xcb_render_pictformat_t render_format_id;
|
||||
|
||||
std::vector<WP<CXWaylandSurfaceResource>> shellResources;
|
||||
std::vector<SP<CXWaylandSurface>> surfaces;
|
||||
std::vector<WP<CXWaylandSurface>> mappedSurfaces; // ordered by map time
|
||||
std::vector<WP<CXWaylandSurface>> mappedSurfacesStacking; // ordered by stacking
|
||||
|
||||
WP<CXWaylandSurface> focusedSurface;
|
||||
uint64_t lastFocusSeq = 0;
|
||||
|
||||
SXSelection clipboard;
|
||||
|
||||
DYNLISTENER(newSurface);
|
||||
|
||||
struct {
|
||||
CHyprSignalListener newXShellSurface;
|
||||
} listeners;
|
||||
|
||||
friend class CXWaylandSurface;
|
||||
friend class CXWayland;
|
||||
friend class CXDataSource;
|
||||
friend struct SXSelection;
|
||||
friend struct SXTransfer;
|
||||
};
|
28
src/xwayland/XWayland.cpp
Normal file
28
src/xwayland/XWayland.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
#include "XWayland.hpp"
|
||||
#include "../debug/Log.hpp"
|
||||
|
||||
CXWayland::CXWayland() {
|
||||
#ifndef NO_XWAYLAND
|
||||
Debug::log(LOG, "Starting up the XWayland server");
|
||||
|
||||
pServer = std::make_unique<CXWaylandServer>();
|
||||
|
||||
if (!pServer->create()) {
|
||||
Debug::log(ERR, "XWayland failed to start: it will not work.");
|
||||
return;
|
||||
}
|
||||
#else
|
||||
Debug::log(LOG, "Not starting XWayland: disabled at compile time");
|
||||
#endif
|
||||
}
|
||||
|
||||
void CXWayland::setCursor(unsigned char* pixData, uint32_t stride, const Vector2D& size, const Vector2D& hotspot) {
|
||||
#ifndef NO_XWAYLAND
|
||||
if (!pWM) {
|
||||
Debug::log(ERR, "Couldn't set XCursor: no XWM yet");
|
||||
return;
|
||||
}
|
||||
|
||||
pWM->setCursor(pixData, stride, size, hotspot);
|
||||
#endif
|
||||
}
|
129
src/xwayland/XWayland.hpp
Normal file
129
src/xwayland/XWayland.hpp
Normal file
|
@ -0,0 +1,129 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
|
||||
#include "XSurface.hpp"
|
||||
|
||||
#ifndef NO_XWAYLAND
|
||||
#include "Server.hpp"
|
||||
#include "XWM.hpp"
|
||||
#else
|
||||
class CXWaylandServer;
|
||||
class CXWM;
|
||||
#endif
|
||||
|
||||
class CXWayland {
|
||||
public:
|
||||
CXWayland();
|
||||
|
||||
#ifndef NO_XWAYLAND
|
||||
std::unique_ptr<CXWaylandServer> pServer;
|
||||
std::unique_ptr<CXWM> pWM;
|
||||
#endif
|
||||
|
||||
void setCursor(unsigned char* pixData, uint32_t stride, const Vector2D& size, const Vector2D& hotspot);
|
||||
|
||||
struct {
|
||||
CSignal newSurface;
|
||||
} events;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CXWayland> g_pXWayland;
|
||||
|
||||
#define HYPRATOM(name) \
|
||||
{ name, 0 }
|
||||
inline std::unordered_map<std::string, uint32_t> HYPRATOMS = {
|
||||
HYPRATOM("_NET_SUPPORTED"),
|
||||
HYPRATOM("_NET_SUPPORTING_WM_CHECK"),
|
||||
HYPRATOM("_NET_WM_NAME"),
|
||||
HYPRATOM("_NET_WM_VISIBLE_NAME"),
|
||||
HYPRATOM("_NET_WM_MOVERESIZE"),
|
||||
HYPRATOM("_NET_WM_STATE_STICKY"),
|
||||
HYPRATOM("_NET_WM_STATE_FULLSCREEN"),
|
||||
HYPRATOM("_NET_WM_STATE_DEMANDS_ATTENTION"),
|
||||
HYPRATOM("_NET_WM_STATE_MODAL"),
|
||||
HYPRATOM("_NET_WM_STATE_HIDDEN"),
|
||||
HYPRATOM("_NET_WM_STATE_FOCUSED"),
|
||||
HYPRATOM("_NET_WM_STATE"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_NORMAL"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_DOCK"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_DIALOG"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_UTILITY"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_TOOLBAR"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_SPLASH"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_MENU"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_POPUP_MENU"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_TOOLTIP"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_NOTIFICATION"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_COMBO"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_DND"),
|
||||
HYPRATOM("_NET_WM_WINDOW_TYPE_DESKTOP"),
|
||||
HYPRATOM("_NET_WM_STATE_MAXIMIZED_HORZ"),
|
||||
HYPRATOM("_NET_WM_STATE_MAXIMIZED_VERT"),
|
||||
HYPRATOM("_NET_WM_DESKTOP"),
|
||||
HYPRATOM("_NET_WM_STRUT_PARTIAL"),
|
||||
HYPRATOM("_NET_CLIENT_LIST"),
|
||||
HYPRATOM("_NET_CLIENT_LIST_STACKING"),
|
||||
HYPRATOM("_NET_CURRENT_DESKTOP"),
|
||||
HYPRATOM("_NET_NUMBER_OF_DESKTOPS"),
|
||||
HYPRATOM("_NET_DESKTOP_NAMES"),
|
||||
HYPRATOM("_NET_DESKTOP_VIEWPORT"),
|
||||
HYPRATOM("_NET_ACTIVE_WINDOW"),
|
||||
HYPRATOM("_NET_CLOSE_WINDOW"),
|
||||
HYPRATOM("_NET_MOVERESIZE_WINDOW"),
|
||||
HYPRATOM("_NET_WM_USER_TIME"),
|
||||
HYPRATOM("_NET_STARTUP_ID"),
|
||||
HYPRATOM("_NET_WORKAREA"),
|
||||
HYPRATOM("_NET_WM_ICON"),
|
||||
HYPRATOM("_NET_WM_CM_S0"),
|
||||
HYPRATOM("WM_PROTOCOLS"),
|
||||
HYPRATOM("WM_HINTS"),
|
||||
HYPRATOM("WM_DELETE_WINDOW"),
|
||||
HYPRATOM("UTF8_STRING"),
|
||||
HYPRATOM("WM_STATE"),
|
||||
HYPRATOM("WM_CLIENT_LEADER"),
|
||||
HYPRATOM("WM_TAKE_FOCUS"),
|
||||
HYPRATOM("WM_NORMAL_HINTS"),
|
||||
HYPRATOM("WM_SIZE_HINTS"),
|
||||
HYPRATOM("WM_WINDOW_ROLE"),
|
||||
HYPRATOM("_NET_REQUEST_FRAME_EXTENTS"),
|
||||
HYPRATOM("_NET_FRAME_EXTENTS"),
|
||||
HYPRATOM("_MOTIF_WM_HINTS"),
|
||||
HYPRATOM("WM_CHANGE_STATE"),
|
||||
HYPRATOM("_NET_SYSTEM_TRAY_OPCODE"),
|
||||
HYPRATOM("_NET_SYSTEM_TRAY_COLORS"),
|
||||
HYPRATOM("_NET_SYSTEM_TRAY_VISUAL"),
|
||||
HYPRATOM("_NET_SYSTEM_TRAY_ORIENTATION"),
|
||||
HYPRATOM("_XEMBED_INFO"),
|
||||
HYPRATOM("MANAGER"),
|
||||
HYPRATOM("XdndSelection"),
|
||||
HYPRATOM("XdndAware"),
|
||||
HYPRATOM("XdndStatus"),
|
||||
HYPRATOM("XdndPosition"),
|
||||
HYPRATOM("XdndEnter"),
|
||||
HYPRATOM("XdndLeave"),
|
||||
HYPRATOM("XdndDrop"),
|
||||
HYPRATOM("XdndFinished"),
|
||||
HYPRATOM("XdndProxy"),
|
||||
HYPRATOM("XdndTypeList"),
|
||||
HYPRATOM("XdndActionMove"),
|
||||
HYPRATOM("XdndActionCopy"),
|
||||
HYPRATOM("XdndActionAsk"),
|
||||
HYPRATOM("XdndActionPrivate"),
|
||||
HYPRATOM("CLIPBOARD"),
|
||||
HYPRATOM("PRIMARY"),
|
||||
HYPRATOM("_WL_SELECTION"),
|
||||
HYPRATOM("CLIPBOARD_MANAGER"),
|
||||
HYPRATOM("WINDOW"),
|
||||
HYPRATOM("WM_S0"),
|
||||
HYPRATOM("WL_SURFACE_ID"),
|
||||
HYPRATOM("WL_SURFACE_SERIAL"),
|
||||
HYPRATOM("TARGETS"),
|
||||
HYPRATOM("TIMESTAMP"),
|
||||
HYPRATOM("DELETE"),
|
||||
HYPRATOM("TEXT"),
|
||||
HYPRATOM("INCR"),
|
||||
};
|
Loading…
Reference in a new issue