diff --git a/src/client/output.cpp b/src/client/output.cpp index 14c7c7f..a372f0d 100644 --- a/src/client/output.cpp +++ b/src/client/output.cpp @@ -1,400 +1,400 @@ /******************************************************************** Copyright 2013 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #include "output.h" #include "wayland_pointer_p.h" // Qt #include #include #include #include // wayland #include namespace KWayland { namespace Client { namespace { typedef QList Modes; } class Q_DECL_HIDDEN Output::Private { public: Private(Output *q); ~Private(); void setup(wl_output *o); - WaylandPointer output; + WaylandPointer output; EventQueue *queue = nullptr; QSize physicalSize; QPoint globalPosition; QString manufacturer; QString model; int scale = 1; SubPixel subPixel = SubPixel::Unknown; Transform transform = Transform::Normal; Modes modes; Modes::iterator currentMode = modes.end(); static Output *get(wl_output *o); private: static void geometryCallback(void *data, wl_output *output, int32_t x, int32_t y, int32_t physicalWidth, int32_t physicalHeight, int32_t subPixel, const char *make, const char *model, int32_t transform); static void modeCallback(void *data, wl_output *output, uint32_t flags, int32_t width, int32_t height, int32_t refresh); static void doneCallback(void *data, wl_output *output); static void scaleCallback(void *data, wl_output *output, int32_t scale); void setPhysicalSize(const QSize &size); void setGlobalPosition(const QPoint &pos); void setManufacturer(const QString &manufacturer); void setModel(const QString &model); void setScale(int scale); void setSubPixel(SubPixel subPixel); void setTransform(Transform transform); void addMode(uint32_t flags, int32_t width, int32_t height, int32_t refresh); Output *q; static struct wl_output_listener s_outputListener; static QVector s_allOutputs; }; QVector Output::Private::s_allOutputs; Output::Private::Private(Output *q) : q(q) { s_allOutputs << this; } Output::Private::~Private() { s_allOutputs.removeOne(this); } Output *Output::Private::get(wl_output *o) { auto it = std::find_if(s_allOutputs.constBegin(), s_allOutputs.constEnd(), [o] (Private *p) { const wl_output *reference = p->output; return reference == o; } ); if (it != s_allOutputs.constEnd()) { return (*it)->q; } return nullptr; } void Output::Private::setup(wl_output *o) { Q_ASSERT(o); Q_ASSERT(!output); output.setup(o); wl_output_add_listener(output, &s_outputListener, this); } bool Output::Mode::operator==(const Output::Mode &m) const { return size == m.size && refreshRate == m.refreshRate && flags == m.flags && output == m.output; } Output::Output(QObject *parent) : QObject(parent) , d(new Private(this)) { } Output::~Output() { d->output.release(); } wl_output_listener Output::Private::s_outputListener = { geometryCallback, modeCallback, doneCallback, scaleCallback }; void Output::Private::geometryCallback(void *data, wl_output *output, int32_t x, int32_t y, int32_t physicalWidth, int32_t physicalHeight, int32_t subPixel, const char *make, const char *model, int32_t transform) { Q_UNUSED(transform) auto o = reinterpret_cast(data); Q_ASSERT(o->output == output); o->setGlobalPosition(QPoint(x, y)); o->setManufacturer(make); o->setModel(model); o->setPhysicalSize(QSize(physicalWidth, physicalHeight)); auto toSubPixel = [subPixel]() { switch (subPixel) { case WL_OUTPUT_SUBPIXEL_NONE: return SubPixel::None; case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB: return SubPixel::HorizontalRGB; case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR: return SubPixel::HorizontalBGR; case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB: return SubPixel::VerticalRGB; case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR: return SubPixel::VerticalBGR; case WL_OUTPUT_SUBPIXEL_UNKNOWN: default: return SubPixel::Unknown; } }; o->setSubPixel(toSubPixel()); auto toTransform = [transform]() { switch (transform) { case WL_OUTPUT_TRANSFORM_90: return Transform::Rotated90; case WL_OUTPUT_TRANSFORM_180: return Transform::Rotated180; case WL_OUTPUT_TRANSFORM_270: return Transform::Rotated270; case WL_OUTPUT_TRANSFORM_FLIPPED: return Transform::Flipped; case WL_OUTPUT_TRANSFORM_FLIPPED_90: return Transform::Flipped90; case WL_OUTPUT_TRANSFORM_FLIPPED_180: return Transform::Flipped180; case WL_OUTPUT_TRANSFORM_FLIPPED_270: return Transform::Flipped270; case WL_OUTPUT_TRANSFORM_NORMAL: default: return Transform::Normal; } }; o->setTransform(toTransform()); } void Output::Private::modeCallback(void *data, wl_output *output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { auto o = reinterpret_cast(data); Q_ASSERT(o->output == output); o->addMode(flags, width, height, refresh); } void Output::Private::addMode(uint32_t flags, int32_t width, int32_t height, int32_t refresh) { Mode mode; mode.output = QPointer(q); mode.refreshRate = refresh; mode.size = QSize(width, height); if (flags & WL_OUTPUT_MODE_CURRENT) { mode.flags |= Mode::Flag::Current; } if (flags & WL_OUTPUT_MODE_PREFERRED) { mode.flags |= Mode::Flag::Preferred; } auto currentIt = modes.insert(modes.end(), mode); bool existing = false; if (flags & WL_OUTPUT_MODE_CURRENT) { auto it = modes.begin(); while (it != currentIt) { auto &m = (*it); if (m.flags.testFlag(Mode::Flag::Current)) { m.flags &= ~Mode::Flags(Mode::Flag::Current); emit q->modeChanged(m); } if (m.refreshRate == mode.refreshRate && m.size == mode.size) { it = modes.erase(it); existing = true; } else { it++; } } currentMode = currentIt; } if (existing) { emit q->modeChanged(mode); } else { emit q->modeAdded(mode); } } void Output::Private::scaleCallback(void *data, wl_output *output, int32_t scale) { auto o = reinterpret_cast(data); Q_ASSERT(o->output == output); o->setScale(scale); } void Output::Private::doneCallback(void *data, wl_output *output) { auto o = reinterpret_cast(data); Q_ASSERT(o->output == output); emit o->q->changed(); } void Output::setup(wl_output *output) { d->setup(output); } EventQueue *Output::eventQueue() const { return d->queue; } void Output::setEventQueue(EventQueue *queue) { d->queue = queue; } void Output::Private::setGlobalPosition(const QPoint &pos) { globalPosition = pos; } void Output::Private::setManufacturer(const QString &m) { manufacturer = m; } void Output::Private::setModel(const QString &m) { model = m; } void Output::Private::setPhysicalSize(const QSize &size) { physicalSize = size; } void Output::Private::setScale(int s) { scale = s; } QRect Output::geometry() const { if (d->currentMode == d->modes.end()) { return QRect(); } return QRect(d->globalPosition, pixelSize()); } void Output::Private::setSubPixel(Output::SubPixel s) { subPixel = s; } void Output::Private::setTransform(Output::Transform t) { transform = t; } QPoint Output::globalPosition() const { return d->globalPosition; } QString Output::manufacturer() const { return d->manufacturer; } QString Output::model() const { return d->model; } wl_output *Output::output() { return d->output; } QSize Output::physicalSize() const { return d->physicalSize; } QSize Output::pixelSize() const { if (d->currentMode == d->modes.end()) { return QSize(); } return (*d->currentMode).size; } int Output::refreshRate() const { if (d->currentMode == d->modes.end()) { return 0; } return (*d->currentMode).refreshRate; } int Output::scale() const { return d->scale; } bool Output::isValid() const { return d->output.isValid(); } Output::SubPixel Output::subPixel() const { return d->subPixel; } Output::Transform Output::transform() const { return d->transform; } QList< Output::Mode > Output::modes() const { return d->modes; } Output::operator wl_output*() { return d->output; } Output::operator wl_output*() const { return d->output; } Output *Output::get(wl_output *o) { return Private::get(o); } void Output::destroy() { d->output.destroy(); } } } diff --git a/src/client/registry.cpp b/src/client/registry.cpp index 4e4695c..61d3182 100644 --- a/src/client/registry.cpp +++ b/src/client/registry.cpp @@ -1,826 +1,826 @@ /******************************************************************** Copyright 2014 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #include "registry.h" #include "compositor.h" #include "connection_thread.h" #include "datadevicemanager.h" #include "dpms.h" #include "event_queue.h" #include "fakeinput.h" #include "fullscreen_shell.h" #include "idle.h" #include "idleinhibit.h" #include "logging_p.h" #include "outputconfiguration.h" #include "outputmanagement.h" #include "outputdevice.h" #include "output.h" #include "plasmashell.h" #include "plasmawindowmanagement.h" #include "pointerconstraints.h" #include "pointergestures.h" #include "seat.h" #include "shadow.h" #include "blur.h" #include "contrast.h" #include "relativepointer.h" #include "server_decoration.h" #include "slide.h" #include "shell.h" #include "shm_pool.h" #include "subcompositor.h" #include "textinput_p.h" #include "xdgshell.h" #include "xdgshell_p.h" #include "wayland_pointer_p.h" #include "xdgforeign_v2.h" #include "appmenu.h" #include "server_decoration_palette.h" // Qt #include // wayland #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /***** * How to add another interface: * * define a new enum value in Registry::Interface * * define the bind method * * define the create method * * define the Announced signal * * define the Removed signal * * add a block to s_interfaces * * add the BIND macro for the new bind * * add the CREATE macro for the new create * * extend registry unit test to verify that it works ****/ namespace KWayland { namespace Client { namespace { struct SuppertedInterfaceData { quint32 maxVersion; QByteArray name; const wl_interface *interface; void (Registry::*announcedSignal)(quint32, quint32); void (Registry::*removedSignal)(quint32); }; static const QMap s_interfaces = { {Registry::Interface::Compositor, { 3, QByteArrayLiteral("wl_compositor"), &wl_compositor_interface, &Registry::compositorAnnounced, &Registry::compositorRemoved }}, {Registry::Interface::DataDeviceManager, { 3, QByteArrayLiteral("wl_data_device_manager"), &wl_data_device_manager_interface, &Registry::dataDeviceManagerAnnounced, &Registry::dataDeviceManagerRemoved }}, {Registry::Interface::Output, { - 2, + 3, QByteArrayLiteral("wl_output"), &wl_output_interface, &Registry::outputAnnounced, &Registry::outputRemoved }}, {Registry::Interface::Shm, { 1, QByteArrayLiteral("wl_shm"), &wl_shm_interface, &Registry::shmAnnounced, &Registry::shmRemoved }}, {Registry::Interface::Seat, { 4, QByteArrayLiteral("wl_seat"), &wl_seat_interface, &Registry::seatAnnounced, &Registry::seatRemoved }}, {Registry::Interface::Shell, { 1, QByteArrayLiteral("wl_shell"), &wl_shell_interface, &Registry::shellAnnounced, &Registry::shellRemoved }}, {Registry::Interface::SubCompositor, { 1, QByteArrayLiteral("wl_subcompositor"), &wl_subcompositor_interface, &Registry::subCompositorAnnounced, &Registry::subCompositorRemoved }}, {Registry::Interface::PlasmaShell, { 4, QByteArrayLiteral("org_kde_plasma_shell"), &org_kde_plasma_shell_interface, &Registry::plasmaShellAnnounced, &Registry::plasmaShellRemoved }}, {Registry::Interface::PlasmaWindowManagement, { 7, QByteArrayLiteral("org_kde_plasma_window_management"), &org_kde_plasma_window_management_interface, &Registry::plasmaWindowManagementAnnounced, &Registry::plasmaWindowManagementRemoved }}, {Registry::Interface::Idle, { 1, QByteArrayLiteral("org_kde_kwin_idle"), &org_kde_kwin_idle_interface, &Registry::idleAnnounced, &Registry::idleRemoved }}, {Registry::Interface::FakeInput, { 2, QByteArrayLiteral("org_kde_kwin_fake_input"), &org_kde_kwin_fake_input_interface, &Registry::fakeInputAnnounced, &Registry::fakeInputRemoved }}, {Registry::Interface::OutputManagement, { 1, QByteArrayLiteral("org_kde_kwin_outputmanagement"), &org_kde_kwin_outputmanagement_interface, &Registry::outputManagementAnnounced, &Registry::outputManagementRemoved }}, {Registry::Interface::OutputDevice, { 1, QByteArrayLiteral("org_kde_kwin_outputdevice"), &org_kde_kwin_outputdevice_interface, &Registry::outputDeviceAnnounced, &Registry::outputDeviceRemoved }}, {Registry::Interface::Shadow, { 2, QByteArrayLiteral("org_kde_kwin_shadow_manager"), &org_kde_kwin_shadow_manager_interface, &Registry::shadowAnnounced, &Registry::shadowRemoved }}, {Registry::Interface::Blur, { 1, QByteArrayLiteral("org_kde_kwin_blur_manager"), &org_kde_kwin_blur_manager_interface, &Registry::blurAnnounced, &Registry::blurRemoved }}, {Registry::Interface::Contrast, { 1, QByteArrayLiteral("org_kde_kwin_contrast_manager"), &org_kde_kwin_contrast_manager_interface, &Registry::contrastAnnounced, &Registry::contrastRemoved }}, {Registry::Interface::Slide, { 1, QByteArrayLiteral("org_kde_kwin_slide_manager"), &org_kde_kwin_slide_manager_interface, &Registry::slideAnnounced, &Registry::slideRemoved }}, {Registry::Interface::FullscreenShell, { 1, QByteArrayLiteral("_wl_fullscreen_shell"), &_wl_fullscreen_shell_interface, &Registry::fullscreenShellAnnounced, &Registry::fullscreenShellRemoved }}, {Registry::Interface::Dpms, { 1, QByteArrayLiteral("org_kde_kwin_dpms_manager"), &org_kde_kwin_dpms_manager_interface, &Registry::dpmsAnnounced, &Registry::dpmsRemoved }}, {Registry::Interface::ServerSideDecorationManager, { 1, QByteArrayLiteral("org_kde_kwin_server_decoration_manager"), &org_kde_kwin_server_decoration_manager_interface, &Registry::serverSideDecorationManagerAnnounced, &Registry::serverSideDecorationManagerRemoved }}, {Registry::Interface::TextInputManagerUnstableV0, { 1, QByteArrayLiteral("wl_text_input_manager"), &wl_text_input_manager_interface, &Registry::textInputManagerUnstableV0Announced, &Registry::textInputManagerUnstableV0Removed }}, {Registry::Interface::TextInputManagerUnstableV2, { 1, QByteArrayLiteral("zwp_text_input_manager_v2"), &zwp_text_input_manager_v2_interface, &Registry::textInputManagerUnstableV2Announced, &Registry::textInputManagerUnstableV2Removed }}, {Registry::Interface::XdgShellUnstableV5, { 1, QByteArrayLiteral("xdg_shell"), &xdg_shell_interface, &Registry::xdgShellUnstableV5Announced, &Registry::xdgShellUnstableV5Removed }}, {Registry::Interface::RelativePointerManagerUnstableV1, { 1, QByteArrayLiteral("zwp_relative_pointer_manager_v1"), &zwp_relative_pointer_manager_v1_interface, &Registry::relativePointerManagerUnstableV1Announced, &Registry::relativePointerManagerUnstableV1Removed }}, {Registry::Interface::PointerGesturesUnstableV1, { 1, QByteArrayLiteral("zwp_pointer_gestures_v1"), &zwp_pointer_gestures_v1_interface, &Registry::pointerGesturesUnstableV1Announced, &Registry::pointerGesturesUnstableV1Removed }}, {Registry::Interface::PointerConstraintsUnstableV1, { 1, QByteArrayLiteral("zwp_pointer_constraints_v1"), &zwp_pointer_constraints_v1_interface, &Registry::pointerConstraintsUnstableV1Announced, &Registry::pointerConstraintsUnstableV1Removed }}, {Registry::Interface::XdgExporterUnstableV2, { 1, QByteArrayLiteral("zxdg_exporter_v2"), &zxdg_exporter_v2_interface, &Registry::exporterUnstableV2Announced, &Registry::exporterUnstableV2Removed }}, {Registry::Interface::XdgImporterUnstableV2, { 1, QByteArrayLiteral("zxdg_importer_v2"), &zxdg_importer_v2_interface, &Registry::importerUnstableV2Announced, &Registry::importerUnstableV2Removed }}, {Registry::Interface::XdgShellUnstableV6, { 1, QByteArrayLiteral("zxdg_shell_v6"), &zxdg_shell_v6_interface, &Registry::xdgShellUnstableV6Announced, &Registry::xdgShellUnstableV6Removed }}, {Registry::Interface::IdleInhibitManagerUnstableV1, { 1, QByteArrayLiteral("zwp_idle_inhibit_manager_v1"), &zwp_idle_inhibit_manager_v1_interface, &Registry::idleInhibitManagerUnstableV1Announced, &Registry::idleInhibitManagerUnstableV1Removed }}, {Registry::Interface::AppMenu, { 1, QByteArrayLiteral("org_kde_kwin_appmenu_manager"), &org_kde_kwin_appmenu_manager_interface, &Registry::appMenuAnnounced, &Registry::appMenuRemoved }}, {Registry::Interface::ServerSideDecorationPalette, { 1, QByteArrayLiteral("org_kde_kwin_server_decoration_palette_manager"), &org_kde_kwin_server_decoration_palette_manager_interface, &Registry::serverSideDecorationPaletteManagerAnnounced, &Registry::serverSideDecorationPaletteManagerRemoved }} }; static quint32 maxVersion(const Registry::Interface &interface) { auto it = s_interfaces.find(interface); if (it != s_interfaces.end()) { return it.value().maxVersion; } return 0; } } class Q_DECL_HIDDEN Registry::Private { public: Private(Registry *q); void setup(); bool hasInterface(Interface interface) const; AnnouncedInterface interface(Interface interface) const; QVector interfaces(Interface interface) const; Interface interfaceForName(quint32 name) const; template T *bind(Interface interface, uint32_t name, uint32_t version) const; template T *create(quint32 name, quint32 version, QObject *parent, WL *(Registry::*bindMethod)(uint32_t, uint32_t) const); WaylandPointer registry; static const struct wl_callback_listener s_callbackListener; WaylandPointer callback; EventQueue *queue = nullptr; private: void handleAnnounce(uint32_t name, const char *interface, uint32_t version); void handleRemove(uint32_t name); void handleGlobalSync(); static void globalAnnounce(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version); static void globalRemove(void *data, struct wl_registry *registry, uint32_t name); static void globalSync(void *data, struct wl_callback *callback, uint32_t serial); Registry *q; struct InterfaceData { Interface interface; uint32_t name; uint32_t version; }; QList m_interfaces; static const struct wl_registry_listener s_registryListener; }; Registry::Private::Private(Registry *q) : q(q) { } void Registry::Private::setup() { wl_registry_add_listener(registry, &s_registryListener, this); wl_callback_add_listener(callback, &s_callbackListener, this); } Registry::Registry(QObject *parent) : QObject(parent) , d(new Private(this)) { } Registry::~Registry() { release(); } void Registry::release() { d->registry.release(); d->callback.release(); } void Registry::destroy() { emit registryDestroyed(); d->registry.destroy(); d->callback.destroy(); } void Registry::create(wl_display *display) { Q_ASSERT(display); Q_ASSERT(!isValid()); d->registry.setup(wl_display_get_registry(display)); d->callback.setup(wl_display_sync(display)); if (d->queue) { d->queue->addProxy(d->registry); d->queue->addProxy(d->callback); } } void Registry::create(ConnectionThread *connection) { create(connection->display()); connect(connection, &ConnectionThread::connectionDied, this, &Registry::destroy); } void Registry::setup() { Q_ASSERT(isValid()); d->setup(); } void Registry::setEventQueue(EventQueue *queue) { d->queue = queue; if (!queue) { return; } if (d->registry) { d->queue->addProxy(d->registry); } if (d->callback) { d->queue->addProxy(d->callback); } } EventQueue *Registry::eventQueue() { return d->queue; } #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct wl_registry_listener Registry::Private::s_registryListener = { globalAnnounce, globalRemove }; const struct wl_callback_listener Registry::Private::s_callbackListener = { globalSync }; #endif void Registry::Private::globalAnnounce(void *data, wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { auto r = reinterpret_cast(data); Q_ASSERT(registry == r->registry); r->handleAnnounce(name, interface, version); } void Registry::Private::globalRemove(void *data, wl_registry *registry, uint32_t name) { auto r = reinterpret_cast(data); Q_ASSERT(registry == r->registry); r->handleRemove(name); } void Registry::Private::globalSync(void* data, wl_callback* callback, uint32_t serial) { Q_UNUSED(serial) auto r = reinterpret_cast(data); Q_ASSERT(r->callback == callback); r->handleGlobalSync(); r->callback.destroy(); } void Registry::Private::handleGlobalSync() { emit q->interfacesAnnounced(); } namespace { static Registry::Interface nameToInterface(const char *interface) { for (auto it = s_interfaces.begin(); it != s_interfaces.end(); ++it) { if (qstrcmp(interface, it.value().name) == 0) { return it.key(); } } return Registry::Interface::Unknown; } } void Registry::Private::handleAnnounce(uint32_t name, const char *interface, uint32_t version) { Interface i = nameToInterface(interface); emit q->interfaceAnnounced(QByteArray(interface), name, version); if (i == Interface::Unknown) { qCDebug(KWAYLAND_CLIENT) << "Unknown interface announced: " << interface << "/" << name << "/" << version; return; } qCDebug(KWAYLAND_CLIENT) << "Wayland Interface: " << interface << "/" << name << "/" << version; m_interfaces.append({i, name, version}); auto it = s_interfaces.constFind(i); if (it != s_interfaces.end()) { emit (q->*it.value().announcedSignal)(name, version); } } void Registry::Private::handleRemove(uint32_t name) { auto it = std::find_if(m_interfaces.begin(), m_interfaces.end(), [name](const InterfaceData &data) { return data.name == name; } ); if (it != m_interfaces.end()) { InterfaceData data = *(it); m_interfaces.erase(it); auto sit = s_interfaces.find(data.interface); if (sit != s_interfaces.end()) { emit (q->*sit.value().removedSignal)(data.name); } } emit q->interfaceRemoved(name); } bool Registry::Private::hasInterface(Registry::Interface interface) const { auto it = std::find_if(m_interfaces.begin(), m_interfaces.end(), [interface](const InterfaceData &data) { return data.interface == interface; } ); return it != m_interfaces.end(); } QVector Registry::Private::interfaces(Interface interface) const { QVector retVal; for (auto it = m_interfaces.constBegin(); it != m_interfaces.constEnd(); ++it) { const auto &data = *it; if (data.interface == interface) { retVal << AnnouncedInterface{data.name, data.version}; } } return retVal; } Registry::AnnouncedInterface Registry::Private::interface(Interface interface) const { const auto all = interfaces(interface); if (!all.isEmpty()) { return all.last(); } return AnnouncedInterface{0, 0}; } Registry::Interface Registry::Private::interfaceForName(quint32 name) const { auto it = std::find_if(m_interfaces.constBegin(), m_interfaces.constEnd(), [name] (const InterfaceData &data) { return data.name == name; }); if (it == m_interfaces.constEnd()) { return Interface::Unknown; } return (*it).interface; } bool Registry::hasInterface(Registry::Interface interface) const { return d->hasInterface(interface); } QVector Registry::interfaces(Interface interface) const { return d->interfaces(interface); } Registry::AnnouncedInterface Registry::interface(Interface interface) const { return d->interface(interface); } #define BIND2(__NAME__, __INAME__, __WL__) \ __WL__ *Registry::bind##__NAME__(uint32_t name, uint32_t version) const \ { \ return d->bind<__WL__>(Interface::__INAME__, name, qMin(maxVersion(Interface::__INAME__), version)); \ } #define BIND(__NAME__, __WL__) BIND2(__NAME__, __NAME__, __WL__) BIND(Compositor, wl_compositor) BIND(Output, wl_output) BIND(Seat, wl_seat) BIND(Shell, wl_shell) BIND(Shm, wl_shm) BIND(SubCompositor, wl_subcompositor) BIND(FullscreenShell, _wl_fullscreen_shell) BIND(DataDeviceManager, wl_data_device_manager) BIND(PlasmaShell, org_kde_plasma_shell) BIND(PlasmaWindowManagement, org_kde_plasma_window_management) BIND(Idle, org_kde_kwin_idle) BIND(FakeInput, org_kde_kwin_fake_input) BIND(OutputManagement, org_kde_kwin_outputmanagement) BIND(OutputDevice, org_kde_kwin_outputdevice) BIND(ServerSideDecorationManager, org_kde_kwin_server_decoration_manager) BIND(TextInputManagerUnstableV0, wl_text_input_manager) BIND(TextInputManagerUnstableV2, zwp_text_input_manager_v2) BIND(XdgShellUnstableV5, xdg_shell) BIND(XdgShellUnstableV6, zxdg_shell_v6) BIND(RelativePointerManagerUnstableV1, zwp_relative_pointer_manager_v1) BIND(PointerGesturesUnstableV1, zwp_pointer_gestures_v1) BIND(PointerConstraintsUnstableV1, zwp_pointer_constraints_v1) BIND(XdgExporterUnstableV2, zxdg_exporter_v2) BIND(XdgImporterUnstableV2, zxdg_importer_v2) BIND(IdleInhibitManagerUnstableV1, zwp_idle_inhibit_manager_v1) BIND2(ShadowManager, Shadow, org_kde_kwin_shadow_manager) BIND2(BlurManager, Blur, org_kde_kwin_blur_manager) BIND2(ContrastManager, Contrast, org_kde_kwin_contrast_manager) BIND2(SlideManager, Slide, org_kde_kwin_slide_manager) BIND2(DpmsManager, Dpms, org_kde_kwin_dpms_manager) BIND2(AppMenuManager, AppMenu, org_kde_kwin_appmenu_manager) BIND2(ServerSideDecorationPaletteManager, ServerSideDecorationPalette, org_kde_kwin_server_decoration_palette_manager) #undef BIND #undef BIND2 template T *Registry::Private::create(quint32 name, quint32 version, QObject *parent, WL *(Registry::*bindMethod)(uint32_t, uint32_t) const) { T *t = new T(parent); t->setEventQueue(queue); t->setup((q->*bindMethod)(name, version)); QObject::connect(q, &Registry::interfaceRemoved, t, [t, name] (quint32 removed) { if (name == removed) { emit t->removed(); } } ); QObject::connect(q, &Registry::registryDestroyed, t, &T::destroy); return t; } #define CREATE2(__NAME__, __BINDNAME__) \ __NAME__ *Registry::create##__NAME__(quint32 name, quint32 version, QObject *parent) \ { \ return d->create<__NAME__>(name, version, parent, &Registry::bind##__BINDNAME__); \ } #define CREATE(__NAME__) CREATE2(__NAME__, __NAME__) CREATE(Compositor) CREATE(Seat) CREATE(Shell) CREATE(SubCompositor) CREATE(FullscreenShell) CREATE(Output) CREATE(DataDeviceManager) CREATE(PlasmaShell) CREATE(PlasmaWindowManagement) CREATE(Idle) CREATE(FakeInput) CREATE(OutputManagement) CREATE(OutputDevice) CREATE(ShadowManager) CREATE(BlurManager) CREATE(ContrastManager) CREATE(SlideManager) CREATE(DpmsManager) CREATE(ServerSideDecorationManager) CREATE2(ShmPool, Shm) CREATE(AppMenuManager) CREATE(ServerSideDecorationPaletteManager) #undef CREATE #undef CREATE2 XdgExporter *Registry::createXdgExporter(quint32 name, quint32 version, QObject *parent) { //only V1 supported for now return d->create(name, version, parent, &Registry::bindXdgExporterUnstableV2); } XdgImporter *Registry::createXdgImporter(quint32 name, quint32 version, QObject *parent) { //only V1 supported for now return d->create(name, version, parent, &Registry::bindXdgImporterUnstableV2); } TextInputManager *Registry::createTextInputManager(quint32 name, quint32 version, QObject *parent) { switch (d->interfaceForName(name)) { case Interface::TextInputManagerUnstableV0: return d->create(name, version, parent, &Registry::bindTextInputManagerUnstableV0); case Interface::TextInputManagerUnstableV2: return d->create(name, version, parent, &Registry::bindTextInputManagerUnstableV2); default: return nullptr; } } XdgShell *Registry::createXdgShell(quint32 name, quint32 version, QObject *parent) { switch (d->interfaceForName(name)) { case Interface::XdgShellUnstableV5: return d->create(name, version, parent, &Registry::bindXdgShellUnstableV5); case Interface::XdgShellUnstableV6: return d->create(name, version, parent, &Registry::bindXdgShellUnstableV6); default: return nullptr; } } RelativePointerManager *Registry::createRelativePointerManager(quint32 name, quint32 version, QObject *parent) { switch (d->interfaceForName(name)) { case Interface::RelativePointerManagerUnstableV1: return d->create(name, version, parent, &Registry::bindRelativePointerManagerUnstableV1); default: return nullptr; } } PointerGestures *Registry::createPointerGestures(quint32 name, quint32 version, QObject *parent) { switch (d->interfaceForName(name)) { case Interface::PointerGesturesUnstableV1: return d->create(name, version, parent, &Registry::bindPointerGesturesUnstableV1); default: return nullptr; } } PointerConstraints *Registry::createPointerConstraints(quint32 name, quint32 version, QObject *parent) { switch (d->interfaceForName(name)) { case Interface::PointerConstraintsUnstableV1: return d->create(name, version, parent, &Registry::bindPointerConstraintsUnstableV1); default: return nullptr; } } IdleInhibitManager *Registry::createIdleInhibitManager(quint32 name, quint32 version, QObject *parent) { switch (d->interfaceForName(name)) { case Interface::IdleInhibitManagerUnstableV1: return d->create(name, version, parent, &Registry::bindIdleInhibitManagerUnstableV1); default: return nullptr; } } namespace { static const wl_interface *wlInterface(Registry::Interface interface) { auto it = s_interfaces.find(interface); if (it != s_interfaces.end()) { return it.value().interface; } return nullptr; } } template T *Registry::Private::bind(Registry::Interface interface, uint32_t name, uint32_t version) const { auto it = std::find_if(m_interfaces.begin(), m_interfaces.end(), [=](const InterfaceData &data) { return data.interface == interface && data.name == name && data.version >= version; }); if (it == m_interfaces.end()) { qCDebug(KWAYLAND_CLIENT) << "Don't have interface " << int(interface) << "with name " << name << "and minimum version" << version; return nullptr; } auto t = reinterpret_cast(wl_registry_bind(registry, name, wlInterface(interface), version)); if (queue) { queue->addProxy(t); } return t; } bool Registry::isValid() const { return d->registry.isValid(); } wl_registry *Registry::registry() { return d->registry; } Registry::operator wl_registry*() const { return d->registry; } Registry::operator wl_registry*() { return d->registry; } } } diff --git a/src/server/output_interface.cpp b/src/server/output_interface.cpp index 75cd1a6..5342ed2 100644 --- a/src/server/output_interface.cpp +++ b/src/server/output_interface.cpp @@ -1,532 +1,546 @@ /******************************************************************** Copyright 2014 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #include "output_interface.h" #include "global_p.h" #include "display.h" #include #include namespace KWayland { namespace Server { class OutputInterface::Private : public Global::Private { public: struct ResourceData { wl_resource *resource; uint32_t version; }; Private(OutputInterface *q, Display *d); ~Private(); void sendMode(wl_resource *resource, const Mode &mode); void sendDone(const ResourceData &data); void updateGeometry(); void updateScale(); QSize physicalSize; QPoint globalPosition; QString manufacturer = QStringLiteral("org.kde.kwin"); QString model = QStringLiteral("none"); int scale = 1; SubPixel subPixel = SubPixel::Unknown; Transform transform = Transform::Normal; QList modes; QList resources; struct { DpmsMode mode = DpmsMode::On; bool supported = false; } dpms; static OutputInterface *get(wl_resource *native); private: static Private *cast(wl_resource *native); + static void releaseCallback(wl_client *client, wl_resource *resource); static void unbind(wl_resource *resource); void bind(wl_client *client, uint32_t version, uint32_t id) override; int32_t toTransform() const; int32_t toSubPixel() const; void sendGeometry(wl_resource *resource); void sendScale(const ResourceData &data); OutputInterface *q; static QVector s_privates; + static const struct wl_output_interface s_interface; static const quint32 s_version; }; QVector OutputInterface::Private::s_privates; -const quint32 OutputInterface::Private::s_version = 2; +const quint32 OutputInterface::Private::s_version = 3; OutputInterface::Private::Private(OutputInterface *q, Display *d) : Global::Private(d, &wl_output_interface, s_version) , q(q) { s_privates << this; } OutputInterface::Private::~Private() { s_privates.removeAll(this); } +#ifndef DOXYGEN_SHOULD_SKIP_THIS +const struct wl_output_interface OutputInterface::Private::s_interface = { + releaseCallback +}; +#endif + +void OutputInterface::Private::releaseCallback(wl_client *client, wl_resource *resource) +{ + Q_UNUSED(client); + unbind(resource); +} + OutputInterface *OutputInterface::Private::get(wl_resource *native) { if (Private *p = cast(native)) { return p->q; } return nullptr; } OutputInterface::Private *OutputInterface::Private::cast(wl_resource *native) { for (auto it = s_privates.constBegin(); it != s_privates.constEnd(); ++it) { const auto &resources = (*it)->resources; auto rit = std::find_if(resources.begin(), resources.end(), [native] (const ResourceData &data) { return data.resource == native; }); if (rit != resources.end()) { return (*it); } } return nullptr; } OutputInterface::OutputInterface(Display *display, QObject *parent) : Global(new Private(this, display), parent) { Q_D(); connect(this, &OutputInterface::currentModeChanged, this, [this, d] { auto currentModeIt = std::find_if(d->modes.constBegin(), d->modes.constEnd(), [](const Mode &mode) { return mode.flags.testFlag(ModeFlag::Current); }); if (currentModeIt == d->modes.constEnd()) { return; } for (auto it = d->resources.constBegin(); it != d->resources.constEnd(); ++it) { d->sendMode((*it).resource, *currentModeIt); d->sendDone(*it); } wl_display_flush_clients(*(d->display)); } ); connect(this, &OutputInterface::subPixelChanged, this, [this, d] { d->updateGeometry(); }); connect(this, &OutputInterface::transformChanged, this, [this, d] { d->updateGeometry(); }); connect(this, &OutputInterface::globalPositionChanged, this, [this, d] { d->updateGeometry(); }); connect(this, &OutputInterface::modelChanged, this, [this, d] { d->updateGeometry(); }); connect(this, &OutputInterface::manufacturerChanged, this, [this, d] { d->updateGeometry(); }); connect(this, &OutputInterface::scaleChanged, this, [this, d] { d->updateScale(); }); } OutputInterface::~OutputInterface() = default; QSize OutputInterface::pixelSize() const { Q_D(); auto it = std::find_if(d->modes.begin(), d->modes.end(), [](const Mode &mode) { return mode.flags.testFlag(ModeFlag::Current); } ); if (it == d->modes.end()) { return QSize(); } return (*it).size; } int OutputInterface::refreshRate() const { Q_D(); auto it = std::find_if(d->modes.begin(), d->modes.end(), [](const Mode &mode) { return mode.flags.testFlag(ModeFlag::Current); } ); if (it == d->modes.end()) { return 60000; } return (*it).refreshRate; } void OutputInterface::addMode(const QSize &size, OutputInterface::ModeFlags flags, int refreshRate) { Q_ASSERT(!isValid()); Q_D(); auto currentModeIt = std::find_if(d->modes.begin(), d->modes.end(), [](const Mode &mode) { return mode.flags.testFlag(ModeFlag::Current); } ); if (currentModeIt == d->modes.end() && !flags.testFlag(ModeFlag::Current)) { // no mode with current flag - enforce flags |= ModeFlag::Current; } if (currentModeIt != d->modes.end() && flags.testFlag(ModeFlag::Current)) { // another mode has the current flag - remove (*currentModeIt).flags &= ~uint(ModeFlag::Current); } if (flags.testFlag(ModeFlag::Preferred)) { // remove from existing Preferred mode auto preferredIt = std::find_if(d->modes.begin(), d->modes.end(), [](const Mode &mode) { return mode.flags.testFlag(ModeFlag::Preferred); } ); if (preferredIt != d->modes.end()) { (*preferredIt).flags &= ~uint(ModeFlag::Preferred); } } auto existingModeIt = std::find_if(d->modes.begin(), d->modes.end(), [size,refreshRate](const Mode &mode) { return mode.size == size && mode.refreshRate == refreshRate; } ); auto emitChanges = [this,flags,size,refreshRate] { emit modesChanged(); if (flags.testFlag(ModeFlag::Current)) { emit refreshRateChanged(refreshRate); emit pixelSizeChanged(size); emit currentModeChanged(); } }; if (existingModeIt != d->modes.end()) { if ((*existingModeIt).flags == flags) { // nothing to do return; } (*existingModeIt).flags = flags; emitChanges(); return; } Mode mode; mode.size = size; mode.refreshRate = refreshRate; mode.flags = flags; d->modes << mode; emitChanges(); } void OutputInterface::setCurrentMode(const QSize &size, int refreshRate) { Q_D(); auto currentModeIt = std::find_if(d->modes.begin(), d->modes.end(), [](const Mode &mode) { return mode.flags.testFlag(ModeFlag::Current); } ); if (currentModeIt != d->modes.end()) { // another mode has the current flag - remove (*currentModeIt).flags &= ~uint(ModeFlag::Current); } auto existingModeIt = std::find_if(d->modes.begin(), d->modes.end(), [size,refreshRate](const Mode &mode) { return mode.size == size && mode.refreshRate == refreshRate; } ); Q_ASSERT(existingModeIt != d->modes.end()); (*existingModeIt).flags |= ModeFlag::Current; emit modesChanged(); emit refreshRateChanged((*existingModeIt).refreshRate); emit pixelSizeChanged((*existingModeIt).size); emit currentModeChanged(); } int32_t OutputInterface::Private::toTransform() const { switch (transform) { case Transform::Normal: return WL_OUTPUT_TRANSFORM_NORMAL; case Transform::Rotated90: return WL_OUTPUT_TRANSFORM_90; case Transform::Rotated180: return WL_OUTPUT_TRANSFORM_180; case Transform::Rotated270: return WL_OUTPUT_TRANSFORM_270; case Transform::Flipped: return WL_OUTPUT_TRANSFORM_FLIPPED; case Transform::Flipped90: return WL_OUTPUT_TRANSFORM_FLIPPED_90; case Transform::Flipped180: return WL_OUTPUT_TRANSFORM_FLIPPED_180; case Transform::Flipped270: return WL_OUTPUT_TRANSFORM_FLIPPED_270; } abort(); } int32_t OutputInterface::Private::toSubPixel() const { switch (subPixel) { case SubPixel::Unknown: return WL_OUTPUT_SUBPIXEL_UNKNOWN; case SubPixel::None: return WL_OUTPUT_SUBPIXEL_NONE; case SubPixel::HorizontalRGB: return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB; case SubPixel::HorizontalBGR: return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR; case SubPixel::VerticalRGB: return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB; case SubPixel::VerticalBGR: return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR; } abort(); } void OutputInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id) { auto c = display->getConnection(client); wl_resource *resource = c->createResource(&wl_output_interface, qMin(version, s_version), id); if (!resource) { wl_client_post_no_memory(client); return; } wl_resource_set_user_data(resource, this); - wl_resource_set_destructor(resource, unbind); + wl_resource_set_implementation(resource, &s_interface, this, unbind); ResourceData r; r.resource = resource; r.version = version; resources << r; sendGeometry(resource); sendScale(r); auto currentModeIt = modes.constEnd(); for (auto it = modes.constBegin(); it != modes.constEnd(); ++it) { const Mode &mode = *it; if (mode.flags.testFlag(ModeFlag::Current)) { // needs to be sent as last mode currentModeIt = it; continue; } sendMode(resource, mode); } if (currentModeIt != modes.constEnd()) { sendMode(resource, *currentModeIt); } sendDone(r); c->flush(); } void OutputInterface::Private::unbind(wl_resource *resource) { Private *o = cast(resource); if (!o) { return; } auto it = std::find_if(o->resources.begin(), o->resources.end(), [resource](const ResourceData &r) { return r.resource == resource; }); if (it != o->resources.end()) { o->resources.erase(it); } } void OutputInterface::Private::sendMode(wl_resource *resource, const Mode &mode) { int32_t flags = 0; if (mode.flags.testFlag(ModeFlag::Current)) { flags |= WL_OUTPUT_MODE_CURRENT; } if (mode.flags.testFlag(ModeFlag::Preferred)) { flags |= WL_OUTPUT_MODE_PREFERRED; } wl_output_send_mode(resource, flags, mode.size.width(), mode.size.height(), mode.refreshRate); } void OutputInterface::Private::sendGeometry(wl_resource *resource) { wl_output_send_geometry(resource, globalPosition.x(), globalPosition.y(), physicalSize.width(), physicalSize.height(), toSubPixel(), qPrintable(manufacturer), qPrintable(model), toTransform()); } void OutputInterface::Private::sendScale(const ResourceData &data) { if (data.version < 2) { return; } wl_output_send_scale(data.resource, scale); } void OutputInterface::Private::sendDone(const ResourceData &data) { if (data.version < 2) { return; } wl_output_send_done(data.resource); } void OutputInterface::Private::updateGeometry() { for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) { sendGeometry((*it).resource); sendDone(*it); } } void OutputInterface::Private::updateScale() { for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) { sendScale(*it); sendDone(*it); } } #define SETTER(setterName, type, argumentName) \ void OutputInterface::setterName(type arg) \ { \ Q_D(); \ if (d->argumentName == arg) { \ return; \ } \ d->argumentName = arg; \ emit argumentName##Changed(d->argumentName); \ } SETTER(setPhysicalSize, const QSize&, physicalSize) SETTER(setGlobalPosition, const QPoint&, globalPosition) SETTER(setManufacturer, const QString&, manufacturer) SETTER(setModel, const QString&, model) SETTER(setScale, int, scale) SETTER(setSubPixel, SubPixel, subPixel) SETTER(setTransform, Transform, transform) #undef SETTER QSize OutputInterface::physicalSize() const { Q_D(); return d->physicalSize; } QPoint OutputInterface::globalPosition() const { Q_D(); return d->globalPosition; } QString OutputInterface::manufacturer() const { Q_D(); return d->manufacturer; } QString OutputInterface::model() const { Q_D(); return d->model; } int OutputInterface::scale() const { Q_D(); return d->scale; } OutputInterface::SubPixel OutputInterface::subPixel() const { Q_D(); return d->subPixel; } OutputInterface::Transform OutputInterface::transform() const { Q_D(); return d->transform; } QList< OutputInterface::Mode > OutputInterface::modes() const { Q_D(); return d->modes; } void OutputInterface::setDpmsMode(OutputInterface::DpmsMode mode) { Q_D(); if (d->dpms.mode == mode) { return; } d->dpms.mode = mode; emit dpmsModeChanged(); } void OutputInterface::setDpmsSupported(bool supported) { Q_D(); if (d->dpms.supported == supported) { return; } d->dpms.supported = supported; emit dpmsSupportedChanged(); } OutputInterface::DpmsMode OutputInterface::dpmsMode() const { Q_D(); return d->dpms.mode; } bool OutputInterface::isDpmsSupported() const { Q_D(); return d->dpms.supported; } QVector OutputInterface::clientResources(ClientConnection *client) const { Q_D(); QVector ret; for (auto it = d->resources.constBegin(), end = d->resources.constEnd(); it != end; ++it) { if (wl_resource_get_client((*it).resource) == client->client()) { ret << (*it).resource; } } return ret; } OutputInterface *OutputInterface::get(wl_resource* native) { return Private::get(native); } OutputInterface::Private *OutputInterface::d_func() const { return reinterpret_cast(d.data()); } } }