Support hotplug events for outputs in DrmBackend
The DrmBackend installs a UdevMonitor to listen for output hotplug events. Whenever a hotplug event occurrs the resources are queried again and a signal is emitted for each removed and added output.
This commit is contained in:
parent
d9a29f3a49
commit
7aee69a6b2
2 changed files with 80 additions and 2 deletions
|
@ -59,6 +59,7 @@ namespace KWin
|
|||
DrmBackend::DrmBackend(QObject *parent)
|
||||
: AbstractBackend(parent)
|
||||
, m_udev(new Udev)
|
||||
, m_udevMonitor(m_udev->monitor())
|
||||
{
|
||||
m_cursor[0] = nullptr;
|
||||
m_cursor[1] = nullptr;
|
||||
|
@ -197,6 +198,34 @@ void DrmBackend::openDrm()
|
|||
);
|
||||
m_drmId = device->sysNum();
|
||||
queryResources();
|
||||
|
||||
// setup udevMonitor
|
||||
if (m_udevMonitor) {
|
||||
m_udevMonitor->filterSubsystemDevType("drm");
|
||||
const int fd = m_udevMonitor->fd();
|
||||
if (fd != -1) {
|
||||
QSocketNotifier *notifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
|
||||
connect(notifier, &QSocketNotifier::activated, this,
|
||||
[this] {
|
||||
auto device = m_udevMonitor->getDevice();
|
||||
if (!device) {
|
||||
return;
|
||||
}
|
||||
if (device->sysNum() != m_drmId) {
|
||||
return;
|
||||
}
|
||||
if (device->hasProperty("HOTPLUG", "1")) {
|
||||
qCDebug(KWIN_CORE()) << "Received hot plug event for monitored drm device";
|
||||
queryResources();
|
||||
m_cursorIndex = (m_cursorIndex + 1) % 2;
|
||||
updateCursor();
|
||||
}
|
||||
}
|
||||
);
|
||||
m_udevMonitor->enable();
|
||||
}
|
||||
}
|
||||
|
||||
emit screensQueried();
|
||||
|
||||
initCursor();
|
||||
|
@ -222,6 +251,8 @@ void DrmBackend::queryResources()
|
|||
qCWarning(KWIN_CORE) << "drmModeGetResources failed";
|
||||
return;
|
||||
}
|
||||
|
||||
QVector<DrmOutput*> connectedOutputs;
|
||||
for (int i = 0; i < resources->count_connectors; ++i) {
|
||||
const auto id = resources->connectors[i];
|
||||
ScopedDrmPointer<_drmModeConnector, &drmModeFreeConnector> connector(drmModeGetConnector(m_fd, id));
|
||||
|
@ -231,6 +262,13 @@ void DrmBackend::queryResources()
|
|||
if (connector->connection != DRM_MODE_CONNECTED) {
|
||||
continue;
|
||||
}
|
||||
if (connector->count_modes == 0) {
|
||||
continue;
|
||||
}
|
||||
if (DrmOutput *o = findOutput(connector->connector_id)) {
|
||||
connectedOutputs << o;
|
||||
continue;
|
||||
}
|
||||
bool crtcFound = false;
|
||||
const quint32 crtcId = findCrtc(resources.data(), connector.data(), &crtcFound);
|
||||
if (!crtcFound) {
|
||||
|
@ -242,14 +280,47 @@ void DrmBackend::queryResources()
|
|||
}
|
||||
DrmOutput *drmOutput = new DrmOutput(this);
|
||||
drmOutput->m_crtcId = crtcId;
|
||||
drmOutput->m_mode = crtc->mode;
|
||||
if (crtc->mode_valid) {
|
||||
drmOutput->m_mode = crtc->mode;
|
||||
} else {
|
||||
drmOutput->m_mode = connector->modes[0];
|
||||
}
|
||||
drmOutput->m_connector = connector->connector_id;
|
||||
drmOutput->init();
|
||||
m_outputs << drmOutput;
|
||||
connectedOutputs << drmOutput;
|
||||
}
|
||||
// check for outputs which got removed
|
||||
auto it = m_outputs.begin();
|
||||
while (it != m_outputs.end()) {
|
||||
if (connectedOutputs.contains(*it)) {
|
||||
it++;
|
||||
continue;
|
||||
}
|
||||
DrmOutput *removed = *it;
|
||||
it = m_outputs.erase(it);
|
||||
emit outputRemoved(removed);
|
||||
delete removed;
|
||||
}
|
||||
for (auto it = connectedOutputs.constBegin(); it != connectedOutputs.constEnd(); ++it) {
|
||||
if (!m_outputs.contains(*it)) {
|
||||
emit outputAdded(*it);
|
||||
}
|
||||
}
|
||||
m_outputs = connectedOutputs;
|
||||
// TODO: install global space
|
||||
}
|
||||
|
||||
DrmOutput *DrmBackend::findOutput(quint32 connector)
|
||||
{
|
||||
auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), [connector] (DrmOutput *o) {
|
||||
return o->m_connector == connector;
|
||||
});
|
||||
if (it != m_outputs.constEnd()) {
|
||||
return *it;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
quint32 DrmBackend::findCrtc(drmModeRes *res, drmModeConnector *connector, bool *ok)
|
||||
{
|
||||
if (ok) {
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace KWin
|
|||
{
|
||||
|
||||
class Udev;
|
||||
class UdevMonitor;
|
||||
|
||||
class DrmBuffer;
|
||||
class DrmOutput;
|
||||
|
@ -64,6 +65,8 @@ public:
|
|||
|
||||
Q_SIGNALS:
|
||||
void screensQueried();
|
||||
void outputRemoved(KWin::DrmOutput *output);
|
||||
void outputAdded(KWin::DrmOutput *output);
|
||||
|
||||
private:
|
||||
static void pageFlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data);
|
||||
|
@ -79,7 +82,9 @@ private:
|
|||
void initCursor();
|
||||
quint32 findCrtc(drmModeRes *res, drmModeConnector *connector, bool *ok = nullptr);
|
||||
bool crtcIsUsed(quint32 crtc);
|
||||
DrmOutput *findOutput(quint32 connector);
|
||||
QScopedPointer<Udev> m_udev;
|
||||
QScopedPointer<UdevMonitor> m_udevMonitor;
|
||||
int m_fd = -1;
|
||||
int m_drmId = 0;
|
||||
QVector<DrmOutput*> m_outputs;
|
||||
|
@ -168,5 +173,7 @@ private:
|
|||
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(KWin::DrmOutput*)
|
||||
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in a new issue