forked from quickshell/quickshell
wayland/toplevel_management: add foreign toplevel management
This commit is contained in:
parent
5d1def3e49
commit
b5b9c1f6c3
13 changed files with 1026 additions and 2 deletions
228
src/wayland/toplevel_management/handle.cpp
Normal file
228
src/wayland/toplevel_management/handle.cpp
Normal file
|
@ -0,0 +1,228 @@
|
|||
#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
|
Loading…
Add table
Add a link
Reference in a new issue