#include "handle.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "manager.hpp" #include "qwayland-wlr-foreign-toplevel-management-unstable-v1.h" #include "wayland-wlr-foreign-toplevel-management-unstable-v1-client-protocol.h" namespace qs::wayland::toplevel_management::impl { QString ToplevelHandle::appId() const { return this->mAppId; } QString ToplevelHandle::title() const { return this->mTitle; } QVector ToplevelHandle::visibleScreens() const { return this->mVisibleScreens; } ToplevelHandle* ToplevelHandle::parent() const { return this->mParent; } bool ToplevelHandle::activated() const { return this->mActivated; } bool ToplevelHandle::maximized() const { return this->mMaximized; } bool ToplevelHandle::minimized() const { return this->mMinimized; } bool ToplevelHandle::fullscreen() const { return this->mFullscreen; } void ToplevelHandle::activate() { auto* display = QtWaylandClient::QWaylandIntegration::instance()->display(); auto* inputDevice = display->lastInputDevice(); if (inputDevice == nullptr) return; this->QtWayland::zwlr_foreign_toplevel_handle_v1::activate(inputDevice->object()); } void ToplevelHandle::setMaximized(bool maximized) { if (maximized) this->set_maximized(); else this->unset_maximized(); } void ToplevelHandle::setMinimized(bool minimized) { if (minimized) this->set_minimized(); else this->unset_minimized(); } void ToplevelHandle::setFullscreen(bool fullscreen) { if (fullscreen) this->set_fullscreen(nullptr); else this->unset_fullscreen(); } void ToplevelHandle::fullscreenOn(QScreen* screen) { auto* waylandScreen = dynamic_cast(screen->handle()); this->set_fullscreen(waylandScreen != nullptr ? waylandScreen->output() : nullptr); } void ToplevelHandle::setRectangle(QWindow* window, QRect rect) { if (window == nullptr) { // will be cleared by the compositor if the surface is destroyed if (this->rectWindow != nullptr) { auto* waylandWindow = dynamic_cast(this->rectWindow->handle()); if (waylandWindow != nullptr) { this->set_rectangle(waylandWindow->surface(), 0, 0, 0, 0); } } QObject::disconnect(this->rectWindow, nullptr, this, nullptr); this->rectWindow = nullptr; return; } if (this->rectWindow != window) { if (this->rectWindow != nullptr) { QObject::disconnect(this->rectWindow, nullptr, this, nullptr); } this->rectWindow = window; QObject::connect(window, &QObject::destroyed, this, &ToplevelHandle::onRectWindowDestroyed); } if (auto* waylandWindow = dynamic_cast(window->handle())) { this->set_rectangle(waylandWindow->surface(), rect.x(), rect.y(), rect.width(), rect.height()); } else { QObject::connect(window, &QWindow::visibleChanged, this, [this, window, rect]() { if (window->isVisible()) { if (window->handle() == nullptr) { window->create(); } auto* waylandWindow = dynamic_cast(window->handle()); this->set_rectangle( waylandWindow->surface(), rect.x(), rect.y(), rect.width(), rect.height() ); } }); } } void ToplevelHandle::onRectWindowDestroyed() { this->rectWindow = nullptr; } void ToplevelHandle::zwlr_foreign_toplevel_handle_v1_done() { qCDebug(logToplevelManagement) << this << "got done"; auto wasReady = this->isReady; this->isReady = true; if (!wasReady) { emit this->ready(); } } void ToplevelHandle::zwlr_foreign_toplevel_handle_v1_closed() { qCDebug(logToplevelManagement) << this << "closed"; this->destroy(); emit this->closed(); delete this; } void ToplevelHandle::zwlr_foreign_toplevel_handle_v1_app_id(const QString& appId) { qCDebug(logToplevelManagement) << this << "got appid" << appId; this->mAppId = appId; emit this->appIdChanged(); } void ToplevelHandle::zwlr_foreign_toplevel_handle_v1_title(const QString& title) { qCDebug(logToplevelManagement) << this << "got toplevel" << title; this->mTitle = title; emit this->titleChanged(); } void ToplevelHandle::zwlr_foreign_toplevel_handle_v1_state(wl_array* stateArray) { auto activated = false; auto maximized = false; auto minimized = false; auto fullscreen = false; // wl_array_for_each is illegal in C++ so it is manually expanded. auto* state = static_cast<::zwlr_foreign_toplevel_handle_v1_state*>(stateArray->data); auto size = stateArray->size / sizeof(::zwlr_foreign_toplevel_handle_v1_state); for (size_t i = 0; i < size; i++) { auto flag = state[i]; // NOLINT switch (flag) { case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED: activated = true; break; case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MAXIMIZED: maximized = true; break; case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MINIMIZED: minimized = true; break; case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_FULLSCREEN: fullscreen = true; break; } } qCDebug(logToplevelManagement) << this << "got state update - activated:" << activated << "maximized:" << maximized << "minimized:" << minimized << "fullscreen:" << fullscreen; if (activated != this->mActivated) { this->mActivated = activated; emit this->activatedChanged(); } if (maximized != this->mMaximized) { this->mMaximized = maximized; emit this->maximizedChanged(); } if (minimized != this->mMinimized) { this->mMinimized = minimized; emit this->minimizedChanged(); } if (fullscreen != this->mFullscreen) { this->mFullscreen = fullscreen; emit this->fullscreenChanged(); } } void ToplevelHandle::zwlr_foreign_toplevel_handle_v1_output_enter(wl_output* output) { auto* display = QtWaylandClient::QWaylandIntegration::instance()->display(); auto* screen = display->screenForOutput(output)->screen(); qCDebug(logToplevelManagement) << this << "got output enter" << screen; this->mVisibleScreens.push_back(screen); emit this->visibleScreenAdded(screen); } void ToplevelHandle::zwlr_foreign_toplevel_handle_v1_output_leave(wl_output* output) { auto* display = QtWaylandClient::QWaylandIntegration::instance()->display(); auto* screen = display->screenForOutput(output)->screen(); qCDebug(logToplevelManagement) << this << "got output leave" << screen; emit this->visibleScreenRemoved(screen); this->mVisibleScreens.removeOne(screen); } void ToplevelHandle::zwlr_foreign_toplevel_handle_v1_parent( ::zwlr_foreign_toplevel_handle_v1* parent ) { auto* handle = ToplevelManager::instance()->handleFor(parent); qCDebug(logToplevelManagement) << this << "got parent" << handle; if (handle != this->mParent) { if (this->mParent != nullptr) { QObject::disconnect(this->mParent, nullptr, this, nullptr); } this->mParent = handle; if (handle != nullptr) { QObject::connect(handle, &ToplevelHandle::closed, this, &ToplevelHandle::onParentClosed); } emit this->parentChanged(); } } void ToplevelHandle::onParentClosed() { this->mParent = nullptr; emit this->parentChanged(); } } // namespace qs::wayland::toplevel_management::impl