forked from quickshell/quickshell
228 lines
7.3 KiB
C++
228 lines
7.3 KiB
C++
#include "handle.hpp"
|
|
#include <cstddef>
|
|
|
|
#include <private/qwaylanddisplay_p.h>
|
|
#include <private/qwaylandinputdevice_p.h>
|
|
#include <private/qwaylandintegration_p.h>
|
|
#include <private/qwaylandscreen_p.h>
|
|
#include <private/qwaylandwindow_p.h>
|
|
#include <qcontainerfwd.h>
|
|
#include <qlogging.h>
|
|
#include <qloggingcategory.h>
|
|
#include <qobject.h>
|
|
#include <qscreen.h>
|
|
#include <qtmetamacros.h>
|
|
#include <wayland-util.h>
|
|
|
|
#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<QScreen*> 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<QtWaylandClient::QWaylandScreen*>(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<QtWaylandClient::QWaylandWindow*>(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<QtWaylandClient::QWaylandWindow*>(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<QtWaylandClient::QWaylandWindow*>(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
|