/* * Copyright (C) 2013-2015 Canonical, Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3, as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, * SATISFACTORY QUALITY, 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 program. If not, see . */ // local #include "screen.h" #include "logging.h" // Mir #include "mir/geometry/size.h" // Qt #include #include #include #include #include // Qt sensors #include #include namespace mg = mir::geometry; Q_LOGGING_CATEGORY(QTMIR_SENSOR_MESSAGES, "qtmir.sensor") namespace { bool isLittleEndian() { unsigned int i = 1; char *c = (char*)&i; return *c == 1; } enum QImage::Format qImageFormatFromMirPixelFormat(MirPixelFormat mirPixelFormat) { switch (mirPixelFormat) { case mir_pixel_format_abgr_8888: if (isLittleEndian()) { // 0xRR,0xGG,0xBB,0xAA return QImage::Format_RGBA8888; } else { // 0xAA,0xBB,0xGG,0xRR qFatal("[mirserver QPA] " "Qt doesn't support mir_pixel_format_abgr_8888 in a big endian architecture"); } break; case mir_pixel_format_xbgr_8888: if (isLittleEndian()) { // 0xRR,0xGG,0xBB,0xXX return QImage::Format_RGBX8888; } else { // 0xXX,0xBB,0xGG,0xRR qFatal("[mirserver QPA] " "Qt doesn't support mir_pixel_format_xbgr_8888 in a big endian architecture"); } break; break; case mir_pixel_format_argb_8888: // 0xAARRGGBB return QImage::Format_ARGB32; break; case mir_pixel_format_xrgb_8888: // 0xffRRGGBB return QImage::Format_RGB32; break; case mir_pixel_format_bgr_888: qFatal("[mirserver QPA] Qt doesn't support mir_pixel_format_bgr_888"); break; default: qFatal("[mirserver QPA] Unknown mir pixel format"); break; } } } // namespace { class OrientationReadingEvent : public QEvent { public: OrientationReadingEvent(QEvent::Type type, QOrientationReading::Orientation orientation) : QEvent(type) , m_orientation(orientation) { } static const QEvent::Type m_type; QOrientationReading::Orientation m_orientation; }; const QEvent::Type OrientationReadingEvent::m_type = static_cast(QEvent::registerEventType()); bool Screen::skipDBusRegistration = false; Screen::Screen(mir::graphics::DisplayConfigurationOutput const &screen) : QObject(nullptr) , m_orientationSensor(new QOrientationSensor(this)) , m_unityScreen(nullptr) { readMirDisplayConfiguration(screen); // Set the default orientation based on the initial screen dimmensions. m_nativeOrientation = (m_geometry.width() >= m_geometry.height()) ? Qt::LandscapeOrientation : Qt::PortraitOrientation; qCDebug(QTMIR_SENSOR_MESSAGES) << "Screen - nativeOrientation is:" << m_nativeOrientation; // If it's a landscape device (i.e. some tablets), start in landscape, otherwise portrait m_currentOrientation = (m_nativeOrientation == Qt::LandscapeOrientation) ? Qt::LandscapeOrientation : Qt::PortraitOrientation; qCDebug(QTMIR_SENSOR_MESSAGES) << "Screen - initial currentOrientation is:" << m_currentOrientation; QObject::connect(m_orientationSensor, &QOrientationSensor::readingChanged, this, &Screen::onOrientationReadingChanged); m_orientationSensor->start(); if (!skipDBusRegistration) { // FIXME This is a unity8 specific dbus call and shouldn't be in qtmir m_unityScreen = new QDBusInterface("com.canonical.Unity.Screen", "/com/canonical/Unity/Screen", "com.canonical.Unity.Screen", QDBusConnection::systemBus(), this); m_unityScreen->connection().connect("com.canonical.Unity.Screen", "/com/canonical/Unity/Screen", "com.canonical.Unity.Screen", "DisplayPowerStateChange", this, SLOT(onDisplayPowerStateChanged(int, int))); } } bool Screen::orientationSensorEnabled() { return m_orientationSensor->isActive(); } void Screen::onDisplayPowerStateChanged(int status, int reason) { Q_UNUSED(reason); toggleSensors(status); } void Screen::readMirDisplayConfiguration(mir::graphics::DisplayConfigurationOutput const &screen) { // Physical screen size m_physicalSize.setWidth(screen.physical_size_mm.width.as_float()); m_physicalSize.setHeight(screen.physical_size_mm.height.as_float()); // Pixel Format m_format = qImageFormatFromMirPixelFormat(screen.current_format); // Pixel depth m_depth = 8 * MIR_BYTES_PER_PIXEL(screen.current_format); // Mode = Resolution & refresh rate mir::graphics::DisplayConfigurationMode mode = screen.modes.at(screen.current_mode_index); m_geometry.setWidth(mode.size.width.as_int()); m_geometry.setHeight(mode.size.height.as_int()); m_refreshRate = mode.vrefresh_hz; } void Screen::toggleSensors(const bool enable) const { qCDebug(QTMIR_SENSOR_MESSAGES) << "Screen::toggleSensors - enable=" << enable; if (enable) { m_orientationSensor->start(); } else { m_orientationSensor->stop(); } } void Screen::customEvent(QEvent* event) { OrientationReadingEvent* oReadingEvent = static_cast(event); switch (oReadingEvent->m_orientation) { case QOrientationReading::LeftUp: { m_currentOrientation = (m_nativeOrientation == Qt::LandscapeOrientation) ? Qt::InvertedPortraitOrientation : Qt::LandscapeOrientation; break; } case QOrientationReading::TopUp: { m_currentOrientation = (m_nativeOrientation == Qt::LandscapeOrientation) ? Qt::LandscapeOrientation : Qt::PortraitOrientation; break; } case QOrientationReading::RightUp: { m_currentOrientation = (m_nativeOrientation == Qt::LandscapeOrientation) ? Qt::PortraitOrientation : Qt::InvertedLandscapeOrientation; break; } case QOrientationReading::TopDown: { m_currentOrientation = (m_nativeOrientation == Qt::LandscapeOrientation) ? Qt::InvertedLandscapeOrientation : Qt::InvertedPortraitOrientation; break; } default: { qWarning("Unknown orientation."); event->accept(); return; } } // Raise the event signal so that client apps know the orientation changed QWindowSystemInterface::handleScreenOrientationChange(screen(), m_currentOrientation); event->accept(); qCDebug(QTMIR_SENSOR_MESSAGES) << "Screen::customEvent - new orientation" << m_currentOrientation << "handled"; } void Screen::onOrientationReadingChanged() { qCDebug(QTMIR_SENSOR_MESSAGES) << "Screen::onOrientationReadingChanged"; // Make sure to switch to the main Qt thread context QCoreApplication::postEvent(this, new OrientationReadingEvent( OrientationReadingEvent::m_type, m_orientationSensor->reading()->orientation())); }