// Copyright (C) 2024-2026 UnionTech Software Technology Co., Ltd.
// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

#include "ddeshellmanagerinterfacev1.h"

#include "qwayland-server-treeland-dde-shell-v1.h"

#include "helper.h"

#include <woutput.h>

#include <qwcompositor.h>
#include <qwdisplay.h>
#include <qwoutput.h>
#include <qwseat.h>

#include <wayland-server.h>

#define TREELAND_DDE_SHELL_MANAGER_V1_VERSION 1

static QList<DDEShellSurfaceInterface *> s_shellSurfaces;
static QList<DDEActiveInterface *> s_ddeActives;
static QList<WindowOverlapCheckerInterface *> s_OverlapCheckers;
static QList<MultiTaskViewInterface *> s_multiTaskViews;
static QList<WindowPickerInterface *> s_windowPickers;
static QList<LockScreenInterface *> s_lockScreens;
static QMap<WindowOverlapCheckerInterface *, QRect> s_conflictList;

class DDEShellManagerInterfaceV1Private : public QtWaylandServer::treeland_dde_shell_manager_v1
{
public:
    explicit DDEShellManagerInterfaceV1Private(DDEShellManagerInterfaceV1 *_q);
    wl_global *global() const;

    DDEShellManagerInterfaceV1 *q;

protected:
    void get_window_overlap_checker(Resource *resource, uint32_t id) override;
    void get_shell_surface(Resource *resource, uint32_t id, struct ::wl_resource *surface) override;
    void get_treeland_dde_active(Resource *resource, uint32_t id, struct ::wl_resource *seat) override;
    void get_treeland_multitaskview(Resource *resource, uint32_t id) override;
    void get_treeland_window_picker(Resource *resource, uint32_t id) override;
    void get_treeland_lockscreen(Resource *resource, uint32_t id) override;
    void set_xwindow_position_relative(Resource *resource, uint32_t callback, uint32_t wid,
                                       struct ::wl_resource *anchor, wl_fixed_t dx, wl_fixed_t dy) override;
};

void DDEShellManagerInterfaceV1Private::get_treeland_lockscreen(Resource *resource,
                                                                uint32_t id)
{
    wl_resource *lockscreen_resource = wl_resource_create(resource->client(),
                                                          &treeland_lockscreen_v1_interface,
                                                          resource->version(),
                                                          id);
    if (!lockscreen_resource) {
        wl_client_post_no_memory(resource->client());
        return;
    }

    auto lockScreen = new LockScreenInterface(lockscreen_resource);
    s_lockScreens.append(lockScreen);

    QObject::connect(lockScreen, &QObject::destroyed, [lockScreen]() {
        s_lockScreens.removeOne(lockScreen);
    });
    Q_EMIT q->lockScreenCreated(lockScreen);
}

void DDEShellManagerInterfaceV1Private::set_xwindow_position_relative(Resource *resource,
                                                                      uint32_t callback,
                                                                      uint32_t wid,
                                                                      struct ::wl_resource *anchor,
                                                                      wl_fixed_t dx,
                                                                      wl_fixed_t dy)
{
    WSurface *wsurface = WSurface::fromHandle(qw_surface::from_resource(anchor));
    uint32_t ok = (wsurface && Helper::instance()->setXWindowPositionRelative(wid, wsurface, dx, dy)) ? 0 : 1;
    wl_resource *cb = wl_resource_create(resource->client(), &wl_callback_interface, 1, callback);
    wl_callback_send_done(cb, ok);
    wl_resource_destroy(cb);
}

DDEShellManagerInterfaceV1Private::DDEShellManagerInterfaceV1Private(DDEShellManagerInterfaceV1 *_q)
    : QtWaylandServer::treeland_dde_shell_manager_v1()
    , q(_q)
{
}

wl_global *DDEShellManagerInterfaceV1Private::global() const
{
    return m_global;
}

void DDEShellManagerInterfaceV1Private::get_window_overlap_checker(Resource *resource,
                                                                   uint32_t id)
{
    wl_resource *checker_resource = wl_resource_create(resource->client(),
                                                       &treeland_window_overlap_checker_interface,
                                                       resource->version(),
                                                       id);
    if (!checker_resource) {
        wl_client_post_no_memory(resource->client());
        return;
    }

    auto overlapChecker = new WindowOverlapCheckerInterface(checker_resource);
    s_OverlapCheckers.append(overlapChecker);

    QObject::connect(overlapChecker, &QObject::destroyed, [overlapChecker]() {
        s_OverlapCheckers.removeOne(overlapChecker);
    });

    Q_EMIT q->windowOverlapCheckerCreated(overlapChecker);
}

void DDEShellManagerInterfaceV1Private::get_shell_surface(Resource *resource,
                                                          uint32_t id,
                                                          wl_resource *surface)
{
    if (!surface) {
        wl_resource_post_error(resource->handle, 0, "surface resource is NULL!");
        return;
    }

    if (DDEShellSurfaceInterface::get(surface)) {
        wl_resource_post_error(resource->handle, 0, "treeland_dde_shell_surface_v1 already exists");
        return;
    }

    wl_resource *shell_resource = wl_resource_create(resource->client(),
                                                     &treeland_dde_shell_surface_v1_interface,
                                                     resource->version(),
                                                     id);
    if (!shell_resource) {
        wl_client_post_no_memory(resource->client());
        return;
    }

    auto shellSurface = new DDEShellSurfaceInterface(surface, shell_resource);
    s_shellSurfaces.append(shellSurface);

    QObject::connect(shellSurface, &QObject::destroyed, [shellSurface]() {
        s_shellSurfaces.removeOne(shellSurface);
    });

    Q_EMIT q->surfaceCreated(shellSurface);
}

void DDEShellManagerInterfaceV1Private::get_treeland_dde_active(Resource *resource,
                                                                uint32_t id,
                                                                struct ::wl_resource *seat)
{
    if (!seat) {
        wl_resource_post_error(resource->handle, 0, "seat resource is NULL!");
        return;
    }

    wl_resource *active_resource = wl_resource_create(resource->client(),
                                                      &treeland_dde_active_v1_interface,
                                                      resource->version(),
                                                      id);

    if (!active_resource) {
        wl_client_post_no_memory(resource->client());
        return;
    }

    auto active = new DDEActiveInterface(seat, active_resource);
    s_ddeActives.append(active);

    QObject::connect(active, &QObject::destroyed, [active]() {
        s_ddeActives.removeOne(active);
    });

    Q_EMIT q->activeCreated(active);
}

void DDEShellManagerInterfaceV1Private::get_treeland_multitaskview(Resource *resource,
                                                                   uint32_t id)
{
    wl_resource *multiTaskViewResource = wl_resource_create(resource->client(),
                                                            &treeland_multitaskview_v1_interface,
                                                            resource->version(),
                                                            id);

    if (!multiTaskViewResource) {
        wl_client_post_no_memory(resource->client());
        return;
    }

    auto multiTaskView = new MultiTaskViewInterface(multiTaskViewResource);
    s_multiTaskViews.append(multiTaskView);

    QObject::connect(multiTaskView, &QObject::destroyed, [multiTaskView]() {
        s_multiTaskViews.removeOne(multiTaskView);
    });
    QObject::connect(multiTaskView,
                     &MultiTaskViewInterface::toggle,
                     q,
                     &DDEShellManagerInterfaceV1::toggleMultitaskview);

    Q_EMIT q->multiTaskViewsCreated(multiTaskView);
}

void DDEShellManagerInterfaceV1Private::get_treeland_window_picker(Resource *resource,
                                                                   uint32_t id)
{
    wl_resource *windowPickerResource = wl_resource_create(resource->client(),
                                                           &treeland_window_picker_v1_interface,
                                                           resource->version(),
                                                           id);

    if (!windowPickerResource) {
        wl_client_post_no_memory(resource->client());
        return;
    }

    auto windowPicker = new WindowPickerInterface(windowPickerResource);
    s_windowPickers.append(windowPicker);

    QObject::connect(windowPicker, &QObject::destroyed, [windowPicker]() {
        s_windowPickers.removeOne(windowPicker);
    });
    QObject::connect(windowPicker, &WindowPickerInterface::pick, [windowPicker, this]() {
        Q_EMIT q->requestPickWindow(windowPicker);
    });

    Q_EMIT q->PickerCreated(windowPicker);
}

DDEShellManagerInterfaceV1::DDEShellManagerInterfaceV1(QObject *parent)
    : QObject(parent)
    , d(new DDEShellManagerInterfaceV1Private(this))
{
}

DDEShellManagerInterfaceV1::~DDEShellManagerInterfaceV1() = default;

void DDEShellManagerInterfaceV1::checkRegionalConflict([[maybe_unused]] const QRegion &region) { }

void DDEShellManagerInterfaceV1::create(WServer *server)
{
    d->init(server->handle()->handle(), TREELAND_DDE_SHELL_MANAGER_V1_VERSION);
}

void DDEShellManagerInterfaceV1::destroy([[maybe_unused]] WServer *server)
{
    d->globalRemove();
}

wl_global *DDEShellManagerInterfaceV1::global() const
{
    return d->global();
}

QByteArrayView DDEShellManagerInterfaceV1::interfaceName() const
{
    return d->interfaceName();
}

class DDEShellSurfaceInterfacePrivate : public QtWaylandServer::treeland_dde_shell_surface_v1
{
public:
    DDEShellSurfaceInterfacePrivate(DDEShellSurfaceInterface *_q,
                                    wl_resource *surface,
                                    wl_resource *resource);

    DDEShellSurfaceInterface *q;
    wl_resource *surfaceResource{ nullptr };
    std::optional<QPoint> surfacePos;
    std::optional<DDEShellSurfaceInterface::Role> role;
    // if m_yOffset has_value, preventing surface from being displayed beyond
    // the edge of the output.
    std::optional<uint32_t> yOffset;
    std::optional<bool> skipSwitcher;
    std::optional<bool> skipDockPreView;
    std::optional<bool> skipMutiTaskView;
    bool acceptKeyboardFocus = true;

protected:
    void destroy_resource([[maybe_unused]] Resource *resource) override;
    void destroy([[maybe_unused]] Resource *resource) override;
    void set_surface_position([[maybe_unused]] Resource *resource,
                                                            int32_t x,
                                                            int32_t y) override;
    void set_role(Resource *resource, uint32_t value) override;
    void set_auto_placement([[maybe_unused]] Resource *resource,
                                                          uint32_t y_offset) override;
    void set_skip_switcher([[maybe_unused]] Resource *resource,
                                                         uint32_t skip) override;
    void set_skip_dock_preview([[maybe_unused]] Resource *resource,
                                                             uint32_t skip) override;
    void set_skip_muti_task_view([[maybe_unused]] Resource *resource,
                                                               uint32_t skip) override;
    void set_accept_keyboard_focus([[maybe_unused]] Resource *resource,
                                                                 uint32_t accept) override;
};

DDEShellSurfaceInterfacePrivate::DDEShellSurfaceInterfacePrivate(DDEShellSurfaceInterface *_q,
                                                                 wl_resource *surface,
                                                                 wl_resource *resource)
    : QtWaylandServer::treeland_dde_shell_surface_v1(resource)
    , q(_q)
    , surfaceResource(surface)
{
}

void DDEShellSurfaceInterfacePrivate::destroy_resource([[maybe_unused]] Resource *resource)
{
    delete q;
}

void DDEShellSurfaceInterfacePrivate::destroy([[maybe_unused]] Resource *resource)
{
    wl_resource_destroy(resource->handle);
}

void DDEShellSurfaceInterfacePrivate::set_surface_position([[maybe_unused]] Resource *resource,
    int32_t x,
    int32_t y)
{
    QPoint pos(x, y);

    if (surfacePos == pos) {
        return;
    }

    surfacePos = pos;
    Q_EMIT q->positionChanged(pos);
}

void DDEShellSurfaceInterfacePrivate::set_role(Resource *resource,
                                               uint32_t value)
{
    DDEShellSurfaceInterface::Role newRole;
    switch (value) {
    case QtWaylandServer::treeland_dde_shell_surface_v1::role::role_overlay:
        newRole = DDEShellSurfaceInterface::OVERLAY;
        break;
    default:
        wl_resource_post_error(resource->handle,
                               0,
                               "Invalid treeland_dde_shell_surface_v1::role: %u",
                               value);
        return;
    }

    if (role.has_value() && role.value() == newRole) {
        return;
    }

    role = newRole;
    Q_EMIT q->roleChanged(newRole);
}

void DDEShellSurfaceInterfacePrivate::set_auto_placement([[maybe_unused]] Resource *resource,
                                                         uint32_t y_offset)
{
    if (y_offset == yOffset) {
        return;
    }

    yOffset = y_offset;
    Q_EMIT q->yOffsetChanged(y_offset);
}

void DDEShellSurfaceInterfacePrivate::set_skip_switcher([[maybe_unused]] Resource *resource,
                                                        uint32_t skip)
{
    if (skip == skipSwitcher) {
        return;
    }

    skipSwitcher = skip;
    Q_EMIT q->skipSwitcherChanged(skip);
}

void DDEShellSurfaceInterfacePrivate::set_skip_dock_preview([[maybe_unused]] Resource *resource,
                                                            uint32_t skip)
{
    if (skip == skipDockPreView) {
        return;
    }

    skipDockPreView = skip;
    Q_EMIT q->skipDockPreViewChanged(skip);
}

void DDEShellSurfaceInterfacePrivate::set_skip_muti_task_view([[maybe_unused]] Resource *resource,
                                                              uint32_t skip)
{
    if (skip == skipMutiTaskView) {
        return;
    }

    skipMutiTaskView = skip;
    Q_EMIT q->skipMutiTaskViewChanged(skip);
}

void DDEShellSurfaceInterfacePrivate::set_accept_keyboard_focus([[maybe_unused]] Resource *resource,
                                                                uint32_t accept)
{
    if (accept == acceptKeyboardFocus) {
        return;
    }

    acceptKeyboardFocus = accept;
    Q_EMIT q->acceptKeyboardFocusChanged(accept);
}

DDEShellSurfaceInterface::DDEShellSurfaceInterface(wl_resource *surface, wl_resource *resource)
    : d(new DDEShellSurfaceInterfacePrivate(this, surface, resource))
{
}

DDEShellSurfaceInterface::~DDEShellSurfaceInterface() = default;

WSurface *DDEShellSurfaceInterface::wSurface() const
{
    return WSurface::fromHandle(qw_surface::from(wlr_surface_from_resource(d->surfaceResource)));
}

bool DDEShellSurfaceInterface::ddeShellSurfaceIsMappedToWsurface(const WSurface *surface)
{
    return wSurface() == surface;
}

std::optional<QPoint> DDEShellSurfaceInterface::surfacePos() const
{
    return d->surfacePos;
}

std::optional<DDEShellSurfaceInterface::Role> DDEShellSurfaceInterface::role() const
{
    return d->role;
}

std::optional<uint32_t> DDEShellSurfaceInterface::yOffset() const
{
    return d->yOffset;
}

std::optional<bool> DDEShellSurfaceInterface::skipSwitcher() const
{
    return d->skipSwitcher;
}

std::optional<bool> DDEShellSurfaceInterface::skipDockPreView() const
{
    return d->skipDockPreView;
}

std::optional<bool> DDEShellSurfaceInterface::skipMutiTaskView() const
{
    return d->skipMutiTaskView;
}

bool DDEShellSurfaceInterface::acceptKeyboardFocus() const
{
    return d->acceptKeyboardFocus;
}

DDEShellSurfaceInterface *DDEShellSurfaceInterface::get(wl_resource *native)
{
    WSurface *surface = WSurface::fromHandle(wlr_surface_from_resource(native));
    if (surface) {
        return DDEShellSurfaceInterface::get(surface);
    }

    return nullptr;
}

DDEShellSurfaceInterface *DDEShellSurfaceInterface::get(WSurface *surface)
{
    for (DDEShellSurfaceInterface *shellSurface : std::as_const(s_shellSurfaces)) {
        if (shellSurface->wSurface() == surface) {
            return shellSurface;
        }
    }

    return nullptr;
}

class DDEActiveInterfacePrivate : public QtWaylandServer::treeland_dde_active_v1
{
public:
    DDEActiveInterfacePrivate(DDEActiveInterface *_q, wl_resource *_seat, wl_resource *resource);

    DDEActiveInterface *q;
    wl_resource *seatResouce{ nullptr };

protected:
    void destroy_resource([[maybe_unused]] Resource *resource) override;
    void destroy([[maybe_unused]] Resource *resource) override;
};

DDEActiveInterfacePrivate::DDEActiveInterfacePrivate(DDEActiveInterface *_q,
                                                     wl_resource *_seat,
                                                     wl_resource *resource)
    : QtWaylandServer::treeland_dde_active_v1(resource)
    , q(_q)
    , seatResouce(_seat)
{
}

void DDEActiveInterfacePrivate::destroy_resource([[maybe_unused]] Resource *resource)
{
    delete q;
}

void DDEActiveInterfacePrivate::destroy([[maybe_unused]] Resource *resource)
{
    wl_resource_destroy(resource->handle);
}

DDEActiveInterface::DDEActiveInterface(wl_resource *seat, wl_resource *resource)
    : d(new DDEActiveInterfacePrivate(this, seat, resource))
{
}

DDEActiveInterface::~DDEActiveInterface() = default;

WSeat *DDEActiveInterface::seat() const
{
    auto wlrSeat =
        static_cast<struct wlr_seat_client *>(wl_resource_get_user_data(d->seatResouce))->seat;
    return WSeat::fromHandle(qw_seat::from(wlrSeat));
}

void DDEActiveInterface::sendActiveIn(uint32_t reason)
{
    d->send_active_in(reason);
}

void DDEActiveInterface::sendActiveOut(uint32_t reason)
{
    d->send_active_out(reason);
}

void DDEActiveInterface::sendStartDrag()
{
    d->send_start_drag();
}

void DDEActiveInterface::sendDrop()
{
    d->send_drop();
}

void DDEActiveInterface::sendActiveIn(uint32_t reason, const WSeat *seat)
{
    for (auto interface : s_ddeActives) {
        if (interface->seat() == seat) {
            interface->sendActiveIn(reason);
        }
    }
}

void DDEActiveInterface::sendActiveOut(uint32_t reason, const WSeat *seat)
{
    for (auto interface : s_ddeActives) {
        if (interface->seat() == seat) {
            interface->sendActiveOut(reason);
        }
    }
}

void DDEActiveInterface::sendStartDrag(const WSeat *seat)
{
    for (auto interface : s_ddeActives) {
        if (interface->seat() == seat) {
            interface->sendStartDrag();
        }
    }
}

void DDEActiveInterface::sendDrop(const WSeat *seat)
{
    for (auto interface : s_ddeActives) {
        if (interface->seat() == seat) {
            interface->sendDrop();
        }
    }
}

class WindowOverlapCheckerInterfacePrivate : public QtWaylandServer::treeland_window_overlap_checker
{
public:
    WindowOverlapCheckerInterfacePrivate(WindowOverlapCheckerInterface *_q, wl_resource *resource);

    WindowOverlapCheckerInterface *q;

    struct wlr_output *output = nullptr;
    QSize size;
    bool alreadySend{ false };
    bool overlapped{ false };

protected:
    void destroy_resource([[maybe_unused]] Resource *resource) override;
    void update(Resource *resource,
                int32_t width,
                int32_t height,
                uint32_t anchor,
                struct ::wl_resource *output) override;
    void destroy(Resource *resource) override;
};

WindowOverlapCheckerInterface::WindowOverlapCheckerInterface(wl_resource *resource)
    : d(new WindowOverlapCheckerInterfacePrivate(this, resource))
{
}

WindowOverlapCheckerInterface::~WindowOverlapCheckerInterface() = default;

void WindowOverlapCheckerInterface::sendOverlapped(bool overlapped)
{
    if (d->alreadySend && overlapped == d->overlapped) {
        d->alreadySend = true;
        return;
    }

    d->overlapped = overlapped;
    d->alreadySend = false;

    if (d->overlapped) {
        d->send_enter();
    } else {
        d->send_leave();
    }
}

void WindowOverlapCheckerInterface::checkRegionalConflict(const QRegion &region)
{
    for (auto &&[interface, checkRect] : s_conflictList.asKeyValueRange()) {
        if (region.intersects(checkRect)) {
            interface->sendOverlapped(true);
            continue;
        } else {
            interface->sendOverlapped(false);
        }
    }
}

WindowOverlapCheckerInterfacePrivate::WindowOverlapCheckerInterfacePrivate(
    WindowOverlapCheckerInterface *_q,
    wl_resource *resource)
    : QtWaylandServer::treeland_window_overlap_checker(resource)
    , q(_q)
{
}

void WindowOverlapCheckerInterfacePrivate::destroy_resource([[maybe_unused]] Resource *resource)
{
    s_conflictList.remove(q);
    delete q;
}

void WindowOverlapCheckerInterfacePrivate::update(Resource *resource,
                                                  int32_t width,
                                                  int32_t height,
                                                  uint32_t anchor,
                                                  wl_resource *o)
{
    output = wlr_output_from_resource(o);
    size = QSize(width, height);

    auto *wOutput = WOutput::fromHandle(qw_output::from(output));
    QSizeF wSize = wOutput->size() / wOutput->scale();
    QRegion region(0, 0, wOutput->size().width(), wOutput->size().height());
    QRect checkRect;
    switch (anchor) {
    case WindowOverlapCheckerInterface::Anchor::TOP:
        checkRect = QRect(0, 0, wSize.width(), size.height());
        break;
    case WindowOverlapCheckerInterface::Anchor::RIGHT:
        checkRect = QRect(wSize.width() - size.width(), 0, size.width(), wSize.height());
        break;
    case WindowOverlapCheckerInterface::Anchor::BOTTOM:
        checkRect = QRect(0, wSize.height() - size.height(), wSize.width(), size.height());
        break;
    case WindowOverlapCheckerInterface::Anchor::LEFT:
        checkRect = QRect(0, 0, wSize.width(), size.height());
        break;
    default:
        wl_resource_post_error(resource->handle,
                               0,
                               "Invalid treeland_window_overlap_checker::anchor: %u",
                               anchor);
        return;
    }

    s_conflictList.insert(q, checkRect);
    Q_EMIT q->refresh();
}

void WindowOverlapCheckerInterfacePrivate::destroy(Resource *resource)
{
    wl_resource_destroy(resource->handle);
}

class MultiTaskViewInterfacePrivate : public QtWaylandServer::treeland_multitaskview_v1
{
public:
    MultiTaskViewInterfacePrivate(MultiTaskViewInterface *_q, wl_resource *resource);

    MultiTaskViewInterface *q;

protected:
    void destroy_resource([[maybe_unused]] Resource *resource) override;
    void destroy([[maybe_unused]] Resource *resource) override;
    void toggle([[maybe_unused]] Resource *resource) override;
};

MultiTaskViewInterfacePrivate::MultiTaskViewInterfacePrivate(MultiTaskViewInterface *_q,
                                                             wl_resource *resource)
    : QtWaylandServer::treeland_multitaskview_v1(resource)
    , q(_q)
{
}

void MultiTaskViewInterfacePrivate::destroy_resource([[maybe_unused]] Resource *resource)
{
    delete q;
}

void MultiTaskViewInterfacePrivate::destroy([[maybe_unused]] Resource *resource)
{
    wl_resource_destroy(resource->handle);
}

void MultiTaskViewInterfacePrivate::toggle([[maybe_unused]] Resource *resource)
{
    Q_EMIT q->toggle();
}

MultiTaskViewInterface::~MultiTaskViewInterface() { }

MultiTaskViewInterface::MultiTaskViewInterface(wl_resource *resource)
    : d(new MultiTaskViewInterfacePrivate(this, resource))
{
}

class WindowPickerInterfacePrivate : public QtWaylandServer::treeland_window_picker_v1
{
public:
    WindowPickerInterfacePrivate(WindowPickerInterface *_q, wl_resource *resource);

    WindowPickerInterface *q;

protected:
    void destroy_resource([[maybe_unused]] Resource *resource) override;
    void destroy([[maybe_unused]] Resource *resource) override;
    void pick([[maybe_unused]] Resource *resource, const QString &hint) override;
};

WindowPickerInterfacePrivate::WindowPickerInterfacePrivate(WindowPickerInterface *_q,
                                                           wl_resource *resource)
    : QtWaylandServer::treeland_window_picker_v1(resource)
    , q(_q)
{
}

void WindowPickerInterfacePrivate::destroy_resource([[maybe_unused]] Resource *resource)
{
    Q_EMIT q->beforeDestroy();
    delete q;
}

void WindowPickerInterfacePrivate::destroy([[maybe_unused]] Resource *resource)
{
    wl_resource_destroy(resource->handle);
}

void WindowPickerInterfacePrivate::pick([[maybe_unused]] Resource *resource,
    const QString &hint)
{
    Q_EMIT q->pick(hint);
}

WindowPickerInterface::~WindowPickerInterface() { }

void WindowPickerInterface::sendWindowPid(qint32 pid)
{
    d->send_window(pid);
}

WindowPickerInterface::WindowPickerInterface(wl_resource *resource)
    : d(new WindowPickerInterfacePrivate(this, resource))
{
}

class LockScreenInterfacePrivate : public QtWaylandServer::treeland_lockscreen_v1
{
public:
    LockScreenInterfacePrivate(LockScreenInterface *_q, wl_resource *resource);

    LockScreenInterface *q;

protected:
    void destroy_resource([[maybe_unused]] Resource *resource) override;
    void destroy([[maybe_unused]] Resource *resource) override;
    void lock([[maybe_unused]] Resource *resource) override;
    void shutdown([[maybe_unused]] Resource *resource) override;
    void switch_user([[maybe_unused]] Resource *resource) override;
};

void LockScreenInterfacePrivate::lock([[maybe_unused]] Resource *resource)
{
    Q_EMIT q->lock();
}

void LockScreenInterfacePrivate::shutdown([[maybe_unused]] Resource *resource)
{
    Q_EMIT q->shutdown();
}

void LockScreenInterfacePrivate::switch_user([[maybe_unused]] Resource *resource)
{
    Q_EMIT q->switchUser();
}

LockScreenInterfacePrivate::LockScreenInterfacePrivate(LockScreenInterface *_q,
                                                       wl_resource *resource)
    : QtWaylandServer::treeland_lockscreen_v1(resource)
    , q(_q)
{
}

void LockScreenInterfacePrivate::destroy_resource([[maybe_unused]] Resource *resource)
{
    delete q;
}

void LockScreenInterfacePrivate::destroy([[maybe_unused]] Resource *resource)
{
    wl_resource_destroy(resource->handle);
}

LockScreenInterface::~LockScreenInterface() { }

LockScreenInterface::LockScreenInterface(wl_resource *resource)
    : d(new LockScreenInterfacePrivate(this, resource))
{
}
