Commit 5f42c217 authored by Valeriy Malov's avatar Valeriy Malov
Browse files

Initial per-screen rotation handling

Summary:
Pass screen index to TabletHandler::onScreenRotated, and check if the
tablet is actually mapped to the screen that has been rotated.
If no screen is specified, then auto-detect rotation using QScreen.

Remove all xrandr mentions since it's not used anywhere anymore.
Clean up X11Info class.

Test Plan:
See if there aren't any regressions
Multi-screen rotation handling seems to be still broken
because QScreen doesn't seem to fire rotation events
for non-primary screens (probably https://bugreports.qt.io/browse/QTBUG-65598)

Reviewers: xuetianweng, fvogt

Subscribers: ngraham

Differential Revision: https://phabricator.kde.org/D9719
parent a5698d64
......@@ -14,8 +14,8 @@ include(ECMInstallIcons)
find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets DBus X11Extras Qml)
find_package(KF5 REQUIRED COMPONENTS CoreAddons I18n GlobalAccel Config XmlGui WidgetsAddons WindowSystem Notifications DBusAddons Plasma DocTools)
find_package(XCB REQUIRED COMPONENTS RANDR OPTIONAL_COMPONENTS XINPUT)
find_package(X11 REQUIRED COMPONENTS XLIB RANDR)
find_package(XCB OPTIONAL_COMPONENTS XINPUT)
find_package(X11 REQUIRED COMPONENTS XLIB)
find_package(XorgWacom REQUIRED)
# xcb-xinput is an experimental API and is not built by default in the xcb
......@@ -28,11 +28,11 @@ find_package(XorgWacom REQUIRED)
# Users can enable xcb-xinput by building xcb with the configuration flag --enable-xinput.
if(XCB_XINPUT_FOUND)
message(STATUS "Using XCB_XINPUT. Please note this is an unstable API.")
set(USING_X_LIBRARIES XCB::XINPUT XCB::RANDR ${X11_Xrandr_LIB} ${X11_Xinput_LIB})
set(USING_X_LIBRARIES XCB::XINPUT ${X11_Xinput_LIB})
add_definitions(-DHAVE_XCB_XINPUT)
else()
message(STATUS "Falling back to X11_XINPUT.")
set(USING_X_LIBRARIES XCB::RANDR ${X11_LIBRARIES} ${X11_Xinput_LIB} ${X11_Xrandr_LIB})
set(USING_X_LIBRARIES ${X11_LIBRARIES} ${X11_Xinput_LIB})
endif()
add_definitions( -DQT_STRICT_ITERATORS )
......
......@@ -44,7 +44,6 @@ Build dependencies on Debian/Ubuntu:
* libkf5notifications-dev
* plasma-framework-dev
* kdoctools-dev
* libxrandr-dev
* libxi-dev
Building from source
......
......@@ -179,6 +179,7 @@ void TestTabletHandler::testListProfiles()
void TestTabletHandler::testOnScreenRotated()
{
m_tabletHandler->onMapToScreen1();
// reset screen rotation
m_tabletHandler->setProperty(QLatin1String("4321"), DeviceType::Stylus, Property::Rotate, ScreenRotation::NONE.key());
m_tabletHandler->setProperty(QLatin1String("4321"), DeviceType::Eraser, Property::Rotate, ScreenRotation::NONE.key());
......@@ -193,7 +194,7 @@ void TestTabletHandler::testOnScreenRotated()
QCOMPARE(m_tabletHandler->getProperty(QLatin1String("4321"), DeviceType::Touch, Property::Rotate), ScreenRotation::NONE.key());
// rotate screen
m_tabletHandler->onScreenRotated(Qt::InvertedLandscapeOrientation);
m_tabletHandler->onScreenRotated(0, Qt::InvertedLandscapeOrientation);
// validate result
QCOMPARE(m_tabletHandler->getProperty(QLatin1String("4321"), DeviceType::Eraser, Property::Rotate), ScreenRotation::HALF.key());
......
......@@ -36,40 +36,26 @@ const QRect X11Info::getDisplayGeometry()
return unitedScreen;
}
int X11Info::getNumberOfScreens()
{
if (QGuiApplication::primaryScreen()->virtualSiblings().size() > 1) {
return QGuiApplication::screens().size();
}
return 1;
}
const QList< QRect > X11Info::getScreenGeometries()
{
QList< QRect > screenGeometries;
const auto screens = QGuiApplication::screens();
auto primaryScreen = QGuiApplication::primaryScreen();
if(primaryScreen->virtualSiblings().size() > 1) {
auto screens = QGuiApplication::screens();
Q_FOREACH (QScreen *screen, screens) {
QRect geometry = screen->geometry();
screenGeometries.append(QRect(geometry.topLeft(), geometry.size() * screen->devicePixelRatio()));
}
} else {
QRect geometry = primaryScreen->geometry();
screenGeometries.append(QRect(geometry.topLeft(), geometry.size() * primaryScreen->devicePixelRatio()));
Q_FOREACH (QScreen *screen, screens) {
QRect geometry = screen->geometry();
screenGeometries.append(QRect(geometry.topLeft(), geometry.size() * screen->devicePixelRatio()));
}
return screenGeometries;
}
const ScreenRotation X11Info::getScreenRotation()
const ScreenRotation X11Info::getScreenRotation(int screenIndex)
{
switch (QGuiApplication::primaryScreen()->orientation()) {
const auto screen = screenIndex >= 0 && screenIndex < QGuiApplication::screens().size()
? QGuiApplication::screens().at(screenIndex)
: QGuiApplication::primaryScreen();
switch (screen->orientation()) {
case Qt::PrimaryOrientation:
case Qt::LandscapeOrientation:
return ScreenRotation::NONE;
......
......@@ -42,12 +42,6 @@ public:
*/
static const QRect getDisplayGeometry();
/**
* @return The number of screens the current display has.
*/
static int getNumberOfScreens();
/**
* Returns a list of all X11 screen geometries.
*
......@@ -62,8 +56,7 @@ public:
*
* @return The current rotation as seen by the monitor.
*/
static const ScreenRotation getScreenRotation();
static const ScreenRotation getScreenRotation(int screenIndex = -1);
private:
......
......@@ -219,9 +219,17 @@ void TabletDaemon::monitorScreenGeometry(QScreen *screen)
{
Q_D( TabletDaemon );
auto tabletHandler = &(d->tabletHandler);
const auto &tabletHandler = &(d->tabletHandler);
connect(screen, &QScreen::orientationChanged,
[=](const Qt::ScreenOrientation &newScreenRotation){
// FIXME: This is somewhat of a hack, ideally we probably should rely on
// output names (screen->name()) instead of screen indices,
// since indices can change when screens configuration is changed
int outputIndex = QGuiApplication::screens().indexOf(screen);
tabletHandler->onScreenRotated(outputIndex, newScreenRotation);
});
connect(screen, &QScreen::orientationChanged, tabletHandler, &TabletHandler::onScreenRotated);
screen->setOrientationUpdateMask(Qt::LandscapeOrientation |
Qt::PortraitOrientation |
Qt::InvertedLandscapeOrientation |
......
......@@ -37,6 +37,7 @@
#include "tabletprofile.h"
#include "x11info.h"
#include <QGuiApplication>
#include <QList>
#include <QRect>
#include <QRegExp>
......@@ -178,11 +179,11 @@ void TabletHandler::onTabletRemoved( const TabletInformation& info )
void TabletHandler::onScreenRotated( const Qt::ScreenOrientation &newScreenRotation )
void TabletHandler::onScreenRotated(int screenIndex, const Qt::ScreenOrientation &newScreenRotation)
{
Q_D( TabletHandler );
dbgWacom << "Screen rotation changed: " << newScreenRotation;
dbgWacom << "Screen " << screenIndex << "rotation has changed to" << newScreenRotation;
//for each connected tablet, do the rotation
foreach(const QString &tabletId, d->tabletInformationList.keys()) {
......@@ -208,7 +209,7 @@ void TabletHandler::onScreenRotated( const Qt::ScreenOrientation &newScreenRotat
}
// rotation has to be applied before screen mapping
autoRotateTablet(tabletId, screenRotation, tabletProfile);
autoRotateTablet(tabletId, tabletProfile, screenIndex, screenRotation);
// when the rotation changes, the screen mapping has to be applied again
mapTabletToCurrentScreenSpace(tabletId, tabletProfile);
......@@ -367,7 +368,7 @@ void TabletHandler::onMapToScreen2()
{
Q_D( TabletHandler );
if (X11Info::getNumberOfScreens() >= 2) {
if (QGuiApplication::screens().count() > 1) {
foreach(const QString &tabletId, d->tabletInformationList.keys()) {
mapPenToScreenSpace(tabletId, ScreenSpace::monitor(1).toString());
}
......@@ -482,7 +483,7 @@ void TabletHandler::setProfile( const QString &tabletId, const QString &profile
// Handle auto-rotation.
// This has to be done before screen mapping!
autoRotateTablet(tabletId, X11Info::getScreenRotation(), tabletProfile);
autoRotateTablet(tabletId, tabletProfile);
// Map tablet to screen.
// This is necessary to ensure the correct area map is used. Somone might have changed
......@@ -541,22 +542,37 @@ void TabletHandler::setProfileRotationList(const QString &tabletId, const QStrin
}
void TabletHandler::autoRotateTablet(const QString &tabletId,
const ScreenRotation &screenRotation,
const TabletProfile &tabletProfile)
const TabletProfile &tabletProfile,
int screenIndex,
ScreenRotation screenRotation)
{
// determine auto-rotation configuration
DeviceProfile stylusProfile = tabletProfile.getDevice(DeviceType::Stylus);
QString rotateProperty = stylusProfile.getProperty( Property::Rotate);
QString rotateProperty = stylusProfile.getProperty(Property::Rotate);
const ScreenRotation* lookupRotation = ScreenRotation::find(rotateProperty);
ScreenRotation tabletRotation = (lookupRotation != NULL) ?
ScreenRotation tabletRotation = (lookupRotation != nullptr) ?
*lookupRotation : ScreenRotation::NONE;
bool doAutoInvert = (tabletRotation == ScreenRotation::AUTO_INVERTED);
bool doAutoRotation = (doAutoInvert || tabletRotation == ScreenRotation::AUTO);
if (!doAutoRotation) {
return; // auto-rotation is disabled
dbgWacom << "Auto-rotation is disabled in profile settings";
return;
}
ScreenSpace stylusSpace = ScreenSpace(stylusProfile.getProperty(Property::ScreenSpace));
if (!stylusSpace.isMonitor()) {
dbgWacom << "We're not mapped to a specific display, can't determine auto-rotation";
return;
}
if (screenIndex == -1) {
screenRotation = X11Info::getScreenRotation(stylusSpace.getScreenNumber());
} else if (screenIndex != stylusSpace.getScreenNumber()) {
dbgWacom << "Tablet is mapped to a different screen";
return;
}
// determine new rotation and set it
......@@ -603,7 +619,7 @@ void TabletHandler::mapDeviceToOutput(const QString &tabletId,
}
ScreenSpace screen(screenSpace);
int screenCount = X11Info::getNumberOfScreens();
int screenCount = QGuiApplication::screens().count();
if (screen.isMonitor()) {
......
......@@ -133,9 +133,10 @@ public Q_SLOTS:
* This slot has to be connected to the X event notifier and executed
* when the screen is rotated.
*
* @param screenIndex Index of the screen that has been rotated.
* @param screenRotation The screen rotation.
*/
void onScreenRotated(const Qt::ScreenOrientation &newScreenRotation);
void onScreenRotated(int screenIndex, const Qt::ScreenOrientation &newScreenRotation);
/**
* @brief Handles screens being connected and disconnected
......@@ -244,11 +245,13 @@ private:
* is disabled, the tablet's rotation settings will be left untouched.
*
* @param tabletId The id of the Tablet that will be used
* @param screenRotation The current screen rotation.
* @param tabletProfile The tablet profile to read the rotation settings from.
* @param screenIndex Index of the screen that has been rotated. -1 means scan all devices.
* @param screenRotation Rotation of the screen specified by screenIndex.
*/
void autoRotateTablet(const QString &tabletId, const ScreenRotation& screenRotation,
const TabletProfile& tabletProfile );
void autoRotateTablet(const QString &tabletId, const TabletProfile& tabletProfile,
int screenIndex = -1,
ScreenRotation screenRotations = ScreenRotation::NONE);
/**
* Checks if the current tablet supports the given device type.
......
......@@ -151,17 +151,5 @@ int X11EventNotifier::registerForNewDeviceEvent(xcb_connection_t* conn)
mask_buf[0] = XCB_INPUT_XI_EVENT_MASK_HIERARCHY;
xcb_input_xi_select_events(conn, QX11Info::appRootWindow(), 1, evmask);
// This is already done by xcb plugin with more flags, doing this ourselves
// will break Qt's xrandr functionality because connection is shared with Qt.
// TODO: uncomment this again when we use our private connection.
#if 0
//register RandR events
int rrmask = XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE;
xcb_randr_select_input(conn, QX11Info::appRootWindow(), 0);
xcb_randr_select_input(conn, QX11Info::appRootWindow(), rrmask);
#endif
return 0;
}
......@@ -72,13 +72,6 @@ private:
*/
void handleX11InputEvent(xcb_ge_generic_event_t* event);
/**
* Handles X11 screen events which signal rotation of the screen.
* This method should not be called directly, but only by our X11 event
* handler method.
*/
void handleX11ScreenEvent(xcb_generic_event_t* event);
/**
* Register the eventhandler with the X11 system
*/
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment