kwin/src/wayland/xdgshell_interface.cpp
2020-06-01 14:48:51 +03:00

985 lines
28 KiB
C++

/*
SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "xdgshell_interface.h"
#include "xdgshell_interface_p.h"
#include "display.h"
#include "output_interface.h"
#include "seat_interface.h"
#include <QTimer>
namespace KWaylandServer
{
XdgShellInterfacePrivate::XdgShellInterfacePrivate(XdgShellInterface *shell)
: q(shell)
{
}
static wl_client *clientFromXdgSurface(XdgSurfaceInterface *surface)
{
return XdgSurfaceInterfacePrivate::get(surface)->resource()->client();
}
void XdgShellInterfacePrivate::registerXdgSurface(XdgSurfaceInterface *surface)
{
xdgSurfaces.insert(clientFromXdgSurface(surface), surface);
}
void XdgShellInterfacePrivate::unregisterXdgSurface(XdgSurfaceInterface *surface)
{
xdgSurfaces.remove(clientFromXdgSurface(surface), surface);
}
/**
* @todo Whether the ping is delayed or has timed out is out of domain of the XdgShellInterface.
* Such matter must be handled somewhere else, e.g. XdgToplevelClient, not here!
*/
void XdgShellInterfacePrivate::registerPing(quint32 serial)
{
QTimer *timer = new QTimer(q);
timer->setInterval(1000);
QObject::connect(timer, &QTimer::timeout, q, [this, serial, attempt = 0]() mutable {
++attempt;
if (attempt == 1) {
emit q->pingDelayed(serial);
return;
}
emit q->pingTimeout(serial);
delete pings.take(serial);
});
pings.insert(serial, timer);
timer->start();
}
XdgShellInterfacePrivate *XdgShellInterfacePrivate::get(XdgShellInterface *shell)
{
return shell->d.data();
}
void XdgShellInterfacePrivate::xdg_wm_base_destroy(Resource *resource)
{
if (xdgSurfaces.contains(resource->client())) {
wl_resource_post_error(resource->handle, error_defunct_surfaces,
"xdg_wm_base was destroyed before children");
return;
}
wl_resource_destroy(resource->handle);
}
void XdgShellInterfacePrivate::xdg_wm_base_create_positioner(Resource *resource, uint32_t id)
{
wl_resource *positionerResource = wl_resource_create(resource->client(), &xdg_positioner_interface,
resource->version(), id);
new XdgPositionerPrivate(positionerResource);
}
void XdgShellInterfacePrivate::xdg_wm_base_get_xdg_surface(Resource *resource, uint32_t id,
::wl_resource *surfaceResource)
{
SurfaceInterface *surface = SurfaceInterface::get(surfaceResource);
if (surface->buffer()) {
wl_resource_post_error(resource->handle, XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER,
"xdg_surface must not have a buffer at creation");
return;
}
wl_resource *xdgSurfaceResource = wl_resource_create(resource->client(), &xdg_surface_interface,
resource->version(), id);
XdgSurfaceInterface *xdgSurface = new XdgSurfaceInterface(q, surface, xdgSurfaceResource);
registerXdgSurface(xdgSurface);
}
void XdgShellInterfacePrivate::xdg_wm_base_pong(Resource *resource, uint32_t serial)
{
Q_UNUSED(resource)
if (QTimer *timer = pings.take(serial)) {
delete timer;
emit q->pongReceived(serial);
}
}
XdgShellInterface::XdgShellInterface(Display *display, QObject *parent)
: QObject(parent)
, d(new XdgShellInterfacePrivate(this))
{
d->display = display;
d->init(*display, 1);
}
XdgShellInterface::~XdgShellInterface()
{
}
Display *XdgShellInterface::display() const
{
return d->display;
}
quint32 XdgShellInterface::ping(XdgSurfaceInterface *surface)
{
::wl_client *client = clientFromXdgSurface(surface);
XdgShellInterfacePrivate::Resource *clientResource = d->resourceMap().value(client);
if (!clientResource)
return 0;
quint32 serial = d->display->nextSerial();
d->send_ping(clientResource->handle, serial);
d->registerPing(serial);
return serial;
}
XdgSurfaceInterfacePrivate::XdgSurfaceInterfacePrivate(XdgSurfaceInterface *xdgSurface)
: q(xdgSurface)
{
}
void XdgSurfaceInterfacePrivate::commit()
{
if (current.windowGeometry != next.windowGeometry) {
current.windowGeometry = next.windowGeometry;
emit q->windowGeometryChanged(current.windowGeometry);
}
isMapped = surface->buffer();
}
void XdgSurfaceInterfacePrivate::reset()
{
isConfigured = false;
current = next = State();
emit q->resetOccurred();
}
XdgSurfaceInterfacePrivate *XdgSurfaceInterfacePrivate::get(XdgSurfaceInterface *surface)
{
return surface->d.data();
}
void XdgSurfaceInterfacePrivate::xdg_surface_destroy_resource(Resource *resource)
{
Q_UNUSED(resource)
XdgShellInterfacePrivate::get(shell)->unregisterXdgSurface(q);
delete q;
}
void XdgSurfaceInterfacePrivate::xdg_surface_destroy(Resource *resource)
{
if (toplevel || popup) {
qWarning() << "Tried to destroy xdg_surface before its role object";
}
wl_resource_destroy(resource->handle);
}
void XdgSurfaceInterfacePrivate::xdg_surface_get_toplevel(Resource *resource, uint32_t id)
{
if (SurfaceRole::get(surface)) {
wl_resource_post_error(resource->handle, error_already_constructed,
"xdg_surface has already been constructured");
return;
}
wl_resource *toplevelResource = wl_resource_create(resource->client(), &xdg_toplevel_interface,
resource->version(), id);
toplevel = new XdgToplevelInterface(q, toplevelResource);
emit shell->toplevelCreated(toplevel);
}
void XdgSurfaceInterfacePrivate::xdg_surface_get_popup(Resource *resource, uint32_t id,
::wl_resource *parentResource,
::wl_resource *positionerResource)
{
if (SurfaceRole::get(surface)) {
wl_resource_post_error(resource->handle, error_already_constructed,
"xdg_surface has already been constructured");
return;
}
XdgPositioner positioner = XdgPositioner::get(positionerResource);
if (!positioner.isComplete()) {
wl_resource_post_error(resource->handle, QtWaylandServer::xdg_wm_base::error_invalid_positioner,
"xdg_positioner is incomplete");
return;
}
// Notice that the parent surface may be null, in which case it must be specified via
// "some other protocol", before committing the initial state. However, we don't have
// support for any such protocol right now.
XdgSurfaceInterface *parentSurface = XdgSurfaceInterface::get(parentResource);
if (!parentSurface) {
wl_resource_post_error(resource->handle, -1, "parent surface is not set");
return;
}
wl_resource *popupResource = wl_resource_create(resource->client(), &xdg_popup_interface,
resource->version(), id);
popup = new XdgPopupInterface(q, parentSurface, positioner, popupResource);
emit shell->popupCreated(popup);
}
void XdgSurfaceInterfacePrivate::xdg_surface_set_window_geometry(Resource *resource,
int32_t x, int32_t y,
int32_t width, int32_t height)
{
if (!toplevel && !popup) {
wl_resource_post_error(resource->handle, error_not_constructed,
"xdg_surface must have a role");
return;
}
if (width < 1 || height < 1) {
wl_resource_post_error(resource->handle, -1, "invalid window geometry size");
return;
}
next.windowGeometry = QRect(x, y, width, height);
}
void XdgSurfaceInterfacePrivate::xdg_surface_ack_configure(Resource *resource, uint32_t serial)
{
Q_UNUSED(resource)
emit q->configureAcknowledged(serial);
}
XdgSurfaceInterface::XdgSurfaceInterface(XdgShellInterface *shell, SurfaceInterface *surface,
::wl_resource *resource)
: d(new XdgSurfaceInterfacePrivate(this))
{
d->shell = shell;
d->surface = surface;
d->init(resource);
}
XdgSurfaceInterface::~XdgSurfaceInterface()
{
}
XdgToplevelInterface *XdgSurfaceInterface::toplevel() const
{
return d->toplevel;
}
XdgPopupInterface *XdgSurfaceInterface::popup() const
{
return d->popup;
}
XdgShellInterface *XdgSurfaceInterface::shell() const
{
return d->shell;
}
SurfaceInterface *XdgSurfaceInterface::surface() const
{
return d->surface;
}
bool XdgSurfaceInterface::isConfigured() const
{
return d->isConfigured;
}
QRect XdgSurfaceInterface::windowGeometry() const
{
return d->current.windowGeometry;
}
XdgSurfaceInterface *XdgSurfaceInterface::get(::wl_resource *resource)
{
if (auto surface = QtWaylandServer::xdg_surface::Resource::fromResource(resource))
return static_cast<XdgSurfaceInterfacePrivate *>(surface->object())->q;
return nullptr;
}
XdgToplevelInterfacePrivate::XdgToplevelInterfacePrivate(XdgToplevelInterface *toplevel,
XdgSurfaceInterface *surface)
: SurfaceRole(surface->surface())
, q(toplevel)
, xdgSurface(surface)
{
}
void XdgToplevelInterfacePrivate::commit()
{
auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface);
bool isResettable = xdgSurfacePrivate->isConfigured && xdgSurfacePrivate->isMapped;
if (xdgSurfacePrivate->isConfigured) {
xdgSurfacePrivate->commit();
} else {
emit q->initializeRequested();
return;
}
if (isResettable && !xdgSurfacePrivate->isMapped) {
reset();
return;
}
if (current.minimumSize != next.minimumSize) {
current.minimumSize = next.minimumSize;
emit q->minimumSizeChanged(current.minimumSize);
}
if (current.maximumSize != next.maximumSize) {
current.maximumSize = next.maximumSize;
emit q->maximumSizeChanged(current.maximumSize);
}
}
void XdgToplevelInterfacePrivate::reset()
{
auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface);
xdgSurfacePrivate->reset();
windowTitle = QString();
windowClass = QString();
current = next = State();
emit q->resetOccurred();
}
void XdgToplevelInterfacePrivate::xdg_toplevel_destroy_resource(Resource *resource)
{
Q_UNUSED(resource)
delete q;
}
void XdgToplevelInterfacePrivate::xdg_toplevel_destroy(Resource *resource)
{
wl_resource_destroy(resource->handle);
}
void XdgToplevelInterfacePrivate::xdg_toplevel_set_parent(Resource *resource,
::wl_resource *parentResource)
{
Q_UNUSED(resource)
XdgToplevelInterface *parent = XdgToplevelInterface::get(parentResource);
if (parentXdgToplevel == parent) {
return;
}
parentXdgToplevel = parent;
emit q->parentXdgToplevelChanged();
}
void XdgToplevelInterfacePrivate::xdg_toplevel_set_title(Resource *resource, const QString &title)
{
Q_UNUSED(resource)
if (windowTitle == title) {
return;
}
windowTitle = title;
emit q->windowTitleChanged(title);
}
void XdgToplevelInterfacePrivate::xdg_toplevel_set_app_id(Resource *resource, const QString &app_id)
{
Q_UNUSED(resource)
if (windowClass == app_id) {
return;
}
windowClass = app_id;
emit q->windowClassChanged(app_id);
}
void XdgToplevelInterfacePrivate::xdg_toplevel_show_window_menu(Resource *resource, ::wl_resource *seatResource,
uint32_t serial, int32_t x, int32_t y)
{
auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface);
if (!xdgSurfacePrivate->isConfigured) {
wl_resource_post_error(resource->handle, QtWaylandServer::xdg_surface::error_not_constructed,
"surface has not been configured yet");
return;
}
SeatInterface *seat = SeatInterface::get(seatResource);
emit q->windowMenuRequested(seat, QPoint(x, y), serial);
}
void XdgToplevelInterfacePrivate::xdg_toplevel_move(Resource *resource, ::wl_resource *seatResource, uint32_t serial)
{
auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface);
if (!xdgSurfacePrivate->isConfigured) {
wl_resource_post_error(resource->handle, QtWaylandServer::xdg_surface::error_not_constructed,
"surface has not been configured yet");
return;
}
SeatInterface *seat = SeatInterface::get(seatResource);
emit q->moveRequested(seat, serial);
}
void XdgToplevelInterfacePrivate::xdg_toplevel_resize(Resource *resource, ::wl_resource *seatResource,
uint32_t serial, uint32_t xdgEdges)
{
auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface);
if (!xdgSurfacePrivate->isConfigured) {
wl_resource_post_error(resource->handle, QtWaylandServer::xdg_surface::error_not_constructed,
"surface has not been configured yet");
return;
}
SeatInterface *seat = SeatInterface::get(seatResource);
Qt::Edges edges;
if (xdgEdges & XDG_TOPLEVEL_RESIZE_EDGE_TOP) {
edges |= Qt::TopEdge;
}
if (xdgEdges & XDG_TOPLEVEL_RESIZE_EDGE_RIGHT) {
edges |= Qt::RightEdge;
}
if (xdgEdges & XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM) {
edges |= Qt::BottomEdge;
}
if (xdgEdges & XDG_TOPLEVEL_RESIZE_EDGE_LEFT) {
edges |= Qt::LeftEdge;
}
emit q->resizeRequested(seat, edges, serial);
}
void XdgToplevelInterfacePrivate::xdg_toplevel_set_max_size(Resource *resource, int32_t width, int32_t height)
{
if (width < 0 || height < 0) {
wl_resource_post_error(resource->handle, -1, "width and height must be positive or zero");
return;
}
next.maximumSize = QSize(width, height);
}
void XdgToplevelInterfacePrivate::xdg_toplevel_set_min_size(Resource *resource, int32_t width, int32_t height)
{
if (width < 0 || height < 0) {
wl_resource_post_error(resource->handle, -1, "width and height must be positive or zero");
return;
}
next.minimumSize = QSize(width, height);
}
void XdgToplevelInterfacePrivate::xdg_toplevel_set_maximized(Resource *resource)
{
Q_UNUSED(resource)
emit q->maximizeRequested();
}
void XdgToplevelInterfacePrivate::xdg_toplevel_unset_maximized(Resource *resource)
{
Q_UNUSED(resource)
emit q->unmaximizeRequested();
}
void XdgToplevelInterfacePrivate::xdg_toplevel_set_fullscreen(Resource *resource, ::wl_resource *outputResource)
{
Q_UNUSED(resource)
OutputInterface *output = OutputInterface::get(outputResource);
emit q->fullscreenRequested(output);
}
void XdgToplevelInterfacePrivate::xdg_toplevel_unset_fullscreen(Resource *resource)
{
Q_UNUSED(resource)
emit q->unfullscreenRequested();
}
void XdgToplevelInterfacePrivate::xdg_toplevel_set_minimized(Resource *resource)
{
Q_UNUSED(resource)
emit q->minimizeRequested();
}
XdgToplevelInterfacePrivate *XdgToplevelInterfacePrivate::get(XdgToplevelInterface *toplevel)
{
return toplevel->d.data();
}
XdgToplevelInterfacePrivate *XdgToplevelInterfacePrivate::get(wl_resource *resource)
{
if (auto toplevel = QtWaylandServer::xdg_toplevel::Resource::fromResource(resource))
return static_cast<XdgToplevelInterfacePrivate *>(toplevel->object());
return nullptr;
}
XdgToplevelInterface::XdgToplevelInterface(XdgSurfaceInterface *surface, ::wl_resource *resource)
: d(new XdgToplevelInterfacePrivate(this, surface))
{
d->init(resource);
}
XdgToplevelInterface::~XdgToplevelInterface()
{
}
XdgShellInterface *XdgToplevelInterface::shell() const
{
return d->xdgSurface->shell();
}
XdgSurfaceInterface *XdgToplevelInterface::xdgSurface() const
{
return d->xdgSurface;
}
SurfaceInterface *XdgToplevelInterface::surface() const
{
return d->xdgSurface->surface();
}
bool XdgToplevelInterface::isConfigured() const
{
return d->xdgSurface->isConfigured();
}
XdgToplevelInterface *XdgToplevelInterface::parentXdgToplevel() const
{
return d->parentXdgToplevel;
}
QString XdgToplevelInterface::windowTitle() const
{
return d->windowTitle;
}
QString XdgToplevelInterface::windowClass() const
{
return d->windowClass;
}
QSize XdgToplevelInterface::minimumSize() const
{
return d->current.minimumSize.isEmpty() ? QSize(0, 0) : d->current.minimumSize;
}
QSize XdgToplevelInterface::maximumSize() const
{
return d->current.maximumSize.isEmpty() ? QSize(INT_MAX, INT_MAX) : d->current.maximumSize;
}
quint32 XdgToplevelInterface::sendConfigure(const QSize &size, const States &states)
{
// Note that the states listed in the configure event must be an array of uint32_t.
uint32_t statesData[4] = { 0 };
int i = 0;
if (states & State::MaximizedHorizontal && states & State::MaximizedVertical) {
statesData[i++] = QtWaylandServer::xdg_toplevel::state_maximized;
}
if (states & State::FullScreen) {
statesData[i++] = QtWaylandServer::xdg_toplevel::state_fullscreen;
}
if (states & State::Resizing) {
statesData[i++] = QtWaylandServer::xdg_toplevel::state_resizing;
}
if (states & State::Activated) {
statesData[i++] = QtWaylandServer::xdg_toplevel::state_activated;
}
const QByteArray xdgStates = QByteArray::fromRawData(reinterpret_cast<char *>(statesData),
sizeof(uint32_t) * i);
const quint32 serial = xdgSurface()->shell()->display()->nextSerial();
d->send_configure(size.width(), size.height(), xdgStates);
auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface());
xdgSurfacePrivate->send_configure(serial);
xdgSurfacePrivate->isConfigured = true;
return serial;
}
void XdgToplevelInterface::sendClose()
{
d->send_close();
}
XdgToplevelInterface *XdgToplevelInterface::get(::wl_resource *resource)
{
if (auto toplevel = QtWaylandServer::xdg_toplevel::Resource::fromResource(resource)) {
return static_cast<XdgToplevelInterfacePrivate *>(toplevel->object())->q;
}
return nullptr;
}
XdgPopupInterfacePrivate::XdgPopupInterfacePrivate(XdgPopupInterface *popup,
XdgSurfaceInterface *surface)
: SurfaceRole(surface->surface())
, q(popup)
, xdgSurface(surface)
{
}
void XdgPopupInterfacePrivate::commit()
{
auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface);
bool isResettable = xdgSurfacePrivate->isConfigured && xdgSurfacePrivate->isMapped;
if (xdgSurfacePrivate->isConfigured) {
xdgSurfacePrivate->commit();
} else {
emit q->initializeRequested();
return;
}
if (isResettable && !xdgSurfacePrivate->isMapped) {
reset();
}
}
void XdgPopupInterfacePrivate::reset()
{
auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface);
xdgSurfacePrivate->reset();
}
void XdgPopupInterfacePrivate::xdg_popup_destroy_resource(Resource *resource)
{
Q_UNUSED(resource)
delete q;
}
void XdgPopupInterfacePrivate::xdg_popup_destroy(Resource *resource)
{
// TODO: We need to post an error with the code XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP if
// this popup is not the topmost grabbing popup. We most likely need a grab abstraction or
// something to determine whether the given popup has an explicit grab.
wl_resource_destroy(resource->handle);
}
void XdgPopupInterfacePrivate::xdg_popup_grab(Resource *resource, ::wl_resource *seatHandle, uint32_t serial)
{
if (xdgSurface->surface()->buffer()) {
wl_resource_post_error(resource->handle, error_invalid_grab,
"xdg_surface is already mapped");
return;
}
SeatInterface *seat = SeatInterface::get(seatHandle);
emit q->grabRequested(seat, serial);
}
XdgPopupInterface::XdgPopupInterface(XdgSurfaceInterface *surface,
XdgSurfaceInterface *parentSurface,
const XdgPositioner &positioner,
::wl_resource *resource)
: d(new XdgPopupInterfacePrivate(this, surface))
{
d->parentXdgSurface = parentSurface;
d->positioner = positioner;
d->init(resource);
}
XdgPopupInterface::~XdgPopupInterface()
{
}
XdgSurfaceInterface *XdgPopupInterface::parentXdgSurface() const
{
return d->parentXdgSurface;
}
XdgSurfaceInterface *XdgPopupInterface::xdgSurface() const
{
return d->xdgSurface;
}
SurfaceInterface *XdgPopupInterface::surface() const
{
return d->xdgSurface->surface();
}
bool XdgPopupInterface::isConfigured() const
{
return d->xdgSurface->isConfigured();
}
XdgPositioner XdgPopupInterface::positioner() const
{
return d->positioner;
}
quint32 XdgPopupInterface::sendConfigure(const QRect &rect)
{
const quint32 serial = xdgSurface()->shell()->display()->nextSerial();
d->send_configure(rect.x(), rect.y(), rect.width(), rect.height());
auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface());
xdgSurfacePrivate->send_configure(serial);
xdgSurfacePrivate->isConfigured = true;
return serial;
}
void XdgPopupInterface::sendPopupDone()
{
d->send_popup_done();
}
XdgPopupInterface *XdgPopupInterface::get(::wl_resource *resource)
{
if (auto popup = QtWaylandServer::xdg_popup::Resource::fromResource(resource))
return static_cast<XdgPopupInterfacePrivate *>(popup->object())->q;
return nullptr;
}
XdgPositionerPrivate::XdgPositionerPrivate(::wl_resource *resource)
: data(new XdgPositionerData)
{
init(resource);
}
XdgPositionerPrivate *XdgPositionerPrivate::get(wl_resource *resource)
{
if (auto positioner = QtWaylandServer::xdg_positioner::Resource::fromResource(resource))
return static_cast<XdgPositionerPrivate *>(positioner->object());
return nullptr;
}
void XdgPositionerPrivate::xdg_positioner_destroy_resource(Resource *resource)
{
Q_UNUSED(resource)
delete this;
}
void XdgPositionerPrivate::xdg_positioner_destroy(Resource *resource)
{
wl_resource_destroy(resource->handle);
}
void XdgPositionerPrivate::xdg_positioner_set_size(Resource *resource, int32_t width, int32_t height)
{
if (width < 1 || height < 1) {
wl_resource_post_error(resource->handle, error_invalid_input,
"width and height must be positive and non-zero");
return;
}
data->size = QSize(width, height);
}
void XdgPositionerPrivate::xdg_positioner_set_anchor_rect(Resource *resource, int32_t x, int32_t y,
int32_t width, int32_t height)
{
if (width < 1 || height < 1) {
wl_resource_post_error(resource->handle, error_invalid_input,
"width and height must be positive and non-zero");
return;
}
data->anchorRect = QRect(x, y, width, height);
}
void XdgPositionerPrivate::xdg_positioner_set_anchor(Resource *resource, uint32_t anchor)
{
if (anchor > anchor_bottom_right) {
wl_resource_post_error(resource->handle, error_invalid_input, "unknown anchor point");
return;
}
switch (anchor) {
case anchor_top:
data->anchorEdges = Qt::TopEdge;
break;
case anchor_top_right:
data->anchorEdges = Qt::TopEdge | Qt::RightEdge;
break;
case anchor_right:
data->anchorEdges = Qt::RightEdge;
break;
case anchor_bottom_right:
data->anchorEdges = Qt::BottomEdge | Qt::RightEdge;
break;
case anchor_bottom:
data->anchorEdges = Qt::BottomEdge;
break;
case anchor_bottom_left:
data->anchorEdges = Qt::BottomEdge | Qt::LeftEdge;
break;
case anchor_left:
data->anchorEdges = Qt::LeftEdge;
break;
case anchor_top_left:
data->anchorEdges = Qt::TopEdge | Qt::LeftEdge;
break;
default:
data->anchorEdges = Qt::Edges();
break;
}
}
void XdgPositionerPrivate::xdg_positioner_set_gravity(Resource *resource, uint32_t gravity)
{
if (gravity > gravity_bottom_right) {
wl_resource_post_error(resource->handle, error_invalid_input, "unknown gravity direction");
return;
}
switch (gravity) {
case gravity_top:
data->gravityEdges = Qt::TopEdge;
break;
case gravity_top_right:
data->gravityEdges = Qt::TopEdge | Qt::RightEdge;
break;
case gravity_right:
data->gravityEdges = Qt::RightEdge;
break;
case gravity_bottom_right:
data->gravityEdges = Qt::BottomEdge | Qt::RightEdge;
break;
case gravity_bottom:
data->gravityEdges = Qt::BottomEdge;
break;
case gravity_bottom_left:
data->gravityEdges = Qt::BottomEdge | Qt::LeftEdge;
break;
case gravity_left:
data->gravityEdges = Qt::LeftEdge;
break;
case gravity_top_left:
data->gravityEdges = Qt::TopEdge | Qt::LeftEdge;
break;
default:
data->gravityEdges = Qt::Edges();
break;
}
}
void XdgPositionerPrivate::xdg_positioner_set_constraint_adjustment(Resource *resource,
uint32_t constraint_adjustment)
{
Q_UNUSED(resource)
if (constraint_adjustment & constraint_adjustment_flip_x) {
data->flipConstraintAdjustments |= Qt::Horizontal;
} else {
data->flipConstraintAdjustments &= ~Qt::Horizontal;
}
if (constraint_adjustment & constraint_adjustment_flip_y) {
data->flipConstraintAdjustments |= Qt::Vertical;
} else {
data->flipConstraintAdjustments &= ~Qt::Vertical;
}
if (constraint_adjustment & constraint_adjustment_slide_x) {
data->slideConstraintAdjustments |= Qt::Horizontal;
} else {
data->slideConstraintAdjustments &= ~Qt::Horizontal;
}
if (constraint_adjustment & constraint_adjustment_slide_y) {
data->slideConstraintAdjustments |= Qt::Vertical;
} else {
data->slideConstraintAdjustments &= ~Qt::Vertical;
}
if (constraint_adjustment & constraint_adjustment_resize_x) {
data->resizeConstraintAdjustments |= Qt::Horizontal;
} else {
data->resizeConstraintAdjustments &= ~Qt::Horizontal;
}
if (constraint_adjustment & constraint_adjustment_resize_y) {
data->resizeConstraintAdjustments |= Qt::Vertical;
} else {
data->resizeConstraintAdjustments &= ~Qt::Vertical;
}
}
void XdgPositionerPrivate::xdg_positioner_set_offset(Resource *resource, int32_t x, int32_t y)
{
Q_UNUSED(resource)
data->offset = QPoint(x, y);
}
XdgPositioner::XdgPositioner()
: d(new XdgPositionerData)
{
}
XdgPositioner::XdgPositioner(const XdgPositioner &other)
: d(other.d)
{
}
XdgPositioner::~XdgPositioner()
{
}
XdgPositioner &XdgPositioner::operator=(const XdgPositioner &other)
{
d = other.d;
return *this;
}
bool XdgPositioner::isComplete() const
{
return d->size.isValid() && d->anchorRect.isValid();
}
Qt::Orientations XdgPositioner::slideConstraintAdjustments() const
{
return d->slideConstraintAdjustments;
}
Qt::Orientations XdgPositioner::flipConstraintAdjustments() const
{
return d->flipConstraintAdjustments;
}
Qt::Orientations XdgPositioner::resizeConstraintAdjustments() const
{
return d->resizeConstraintAdjustments;
}
Qt::Edges XdgPositioner::anchorEdges() const
{
return d->anchorEdges;
}
Qt::Edges XdgPositioner::gravityEdges() const
{
return d->gravityEdges;
}
QSize XdgPositioner::size() const
{
return d->size;
}
QRect XdgPositioner::anchorRect() const
{
return d->anchorRect;
}
QPoint XdgPositioner::offset() const
{
return d->offset;
}
XdgPositioner XdgPositioner::get(::wl_resource *resource)
{
XdgPositionerPrivate *xdgPositionerPrivate = XdgPositionerPrivate::get(resource);
if (xdgPositionerPrivate)
return XdgPositioner(xdgPositionerPrivate->data);
return XdgPositioner();
}
XdgPositioner::XdgPositioner(const QSharedDataPointer<XdgPositionerData> &data)
: d(data)
{
}
} // namespace KWaylandServer