diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -287,6 +287,14 @@ ) set(HAVE_LIBCAP ${Libcap_FOUND}) +find_package(hwdata) +set_package_properties(hwdata PROPERTIES + TYPE RUNTIME + PURPOSE "Runtime-only dependency needed for mapping monitor hardware vendor IDs to full names" + URL "https://github.com/vcrhonek/hwdata" +) +set(HAVE_HWDATA ${hwdata_FOUND}) + include(ECMQMLModules) ecm_find_qmlmodule(QtQuick 2.3) ecm_find_qmlmodule(QtQuick.Controls 1.2) diff --git a/cmake/modules/Findhwdata.cmake b/cmake/modules/Findhwdata.cmake new file mode 100644 --- /dev/null +++ b/cmake/modules/Findhwdata.cmake @@ -0,0 +1,47 @@ +# - Try to find hwdata +# Once done this will define +# +# hwdata_DIR - The hwdata directory +# hwdata_PNPIDS_FILE - File with mapping of hw vendor IDs to names +# hwdata_FOUND - The hwdata directory exists and contains pnp.ids file + +# Copyright (c) 2020 Daniel Vrátil +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +if (UNIX AND NOT APPLE) + find_path(hwdata_DIR NAMES hwdata/pnp.ids HINTS /usr/share ENV XDG_DATA_DIRS) + find_file(hwdata_PNPIDS_FILE NAMES hwdata/pnp.ids HINTS /usr/share) + if (hwdata_DIR-NOTFOUND OR hwdata_PNPIDS_FILE-NOTFOUND) + set(hwdata_FOUND FALSE) + else() + set(hwdata_FOUND TRUE) + endif() + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(hwdata DEFAULT_MSG hwdata_FOUND hwdata_DIR hwdata_PNPIDS_FILE) + + mark_as_advanced(hwdata_FOUND hwdata_DIR hwdata_PNPIDS_FILE) +endif() diff --git a/config-kwin.h.cmake b/config-kwin.h.cmake --- a/config-kwin.h.cmake +++ b/config-kwin.h.cmake @@ -25,6 +25,7 @@ #cmakedefine01 HAVE_BREEZE_DECO #cmakedefine01 HAVE_LIBCAP #cmakedefine01 HAVE_SCHED_RESET_ON_FORK +#cmakedefine01 HAVE_HWDATA #if HAVE_BREEZE_DECO #define BREEZE_KDECORATION_PLUGIN_ID "${BREEZE_KDECORATION_PLUGIN_ID}" #endif @@ -41,3 +42,7 @@ #define XCB_ICCCM_WM_STATE_NORMAL 1 #define XCB_ICCCM_WM_STATE_ICONIC 3 #endif + +#if HAVE_HWDATA +#cmakedefine HWDATA_PNPIDS_FILE "@hwdata_PNPIDS_FILE@" +#endif diff --git a/plugins/platforms/drm/drm_output.cpp b/plugins/platforms/drm/drm_output.cpp --- a/plugins/platforms/drm/drm_output.cpp +++ b/plugins/platforms/drm/drm_output.cpp @@ -301,7 +301,9 @@ void DrmOutput::initOutputDevice(drmModeConnector *connector) { QString manufacturer; - if (!m_edid.eisaId().isEmpty()) { + if (!m_edid.vendor().isEmpty()) { + manufacturer = QString::fromLatin1(m_edid.vendor()); + } else if (!m_edid.eisaId().isEmpty()) { manufacturer = QString::fromLatin1(m_edid.eisaId()); } @@ -379,7 +381,6 @@ && mode->type == m_mode.type && qstrcmp(mode->name, m_mode.name) == 0; } - void DrmOutput::initEdid(drmModeConnector *connector) { DrmScopedPointer edid; diff --git a/plugins/platforms/drm/edid.h b/plugins/platforms/drm/edid.h --- a/plugins/platforms/drm/edid.h +++ b/plugins/platforms/drm/edid.h @@ -62,8 +62,14 @@ */ QByteArray serialNumber() const; + /** + * Returns the name of the vendor. + */ + QByteArray vendor() const; + private: QSize m_physicalSize; + QByteArray m_vendor; QByteArray m_eisaId; QByteArray m_monitorName; QByteArray m_serialNumber; diff --git a/plugins/platforms/drm/edid.cpp b/plugins/platforms/drm/edid.cpp --- a/plugins/platforms/drm/edid.cpp +++ b/plugins/platforms/drm/edid.cpp @@ -20,6 +20,9 @@ *********************************************************************/ #include "edid.h" +#include "config-kwin.h" + +#include namespace KWin { @@ -40,25 +43,9 @@ return QSize(data[0x15], data[0x16]) * 10; } -static QByteArray parseEisaId(const uint8_t *data) +static QByteArray parsePnpId(const uint8_t *data) { - for (int i = 72; i <= 108; i += 18) { - // Skip the block if it isn't used as monitor descriptor. - if (data[i]) { - continue; - } - if (data[i + 1]) { - continue; - } - - // We have found the EISA ID, it's stored as ASCII. - if (data[i + 3] == 0xfe) { - return QByteArray(reinterpret_cast(&data[i + 5]), 12).trimmed(); - } - } - - // If there isn't an ASCII EISA ID descriptor, try to decode PNP ID from - // three 5 bit words packed into 2 bytes: + // Decode PNP ID from three 5 bit words packed into 2 bytes: // // | Byte | Bit | // | | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | @@ -80,6 +67,28 @@ return QByteArray(pnpId); } + +static QByteArray parseEisaId(const uint8_t *data) +{ + for (int i = 72; i <= 108; i += 18) { + // Skip the block if it isn't used as monitor descriptor. + if (data[i]) { + continue; + } + if (data[i + 1]) { + continue; + } + + // We have found the EISA ID, it's stored as ASCII. + if (data[i + 3] == 0xfe) { + return QByteArray(reinterpret_cast(&data[i + 5]), 12).trimmed(); + } + } + + // If there isn't an ASCII EISA ID descriptor, try to decode PNP ID + return parsePnpId(data); +} + static QByteArray parseMonitorName(const uint8_t *data) { for (int i = 72; i <= 108; i += 18) { @@ -131,6 +140,25 @@ return QByteArray(); } +static QByteArray parseVendor(const uint8_t *data) +{ +#if HAVE_HWDATA + const auto pnpId = parsePnpId(data); + + // Map to vendor name + QFile pnpFile(QStringLiteral(HWDATA_PNPIDS_FILE)); + if (pnpFile.exists() && pnpFile.open(QIODevice::ReadOnly)) { + while (!pnpFile.atEnd()) { + const auto line = pnpFile.readLine(); + if (line.startsWith(pnpId)) { + return line.mid(4).trimmed(); + } + } + } +#endif + return {}; +} + Edid::Edid() { } @@ -151,6 +179,7 @@ m_eisaId = parseEisaId(bytes); m_monitorName = parseMonitorName(bytes); m_serialNumber = parseSerialNumber(bytes); + m_vendor = parseVendor(bytes); m_isValid = true; } @@ -180,4 +209,9 @@ return m_serialNumber; } +QByteArray Edid::vendor() const +{ + return m_vendor; +} + } // namespace KWin