xcb: Handle XSettings for a virtual desktop rather than for an output

The virtual desktop may be composed of several outputs which are
represented by the QXcbScreen class. XSettings are related to
the virtual desktop, so introduce a QXcbVirtualDesktop class and
store QXcbXSettings in it.

Change-Id: Ib2261675ef8e5136592d4b856bc84646db3a3af4
Reviewed-by: Uli Schlachter <psychon@znc.in>
Reviewed-by: Jørgen Lind <jorgen.lind@theqtcompany.com>
bb10
Alexander Volkov 2015-04-03 16:40:15 +03:00
parent 6c6fe766a8
commit 4ecae86e4b
8 changed files with 93 additions and 57 deletions

View File

@ -143,7 +143,7 @@ QXcbScreen* QXcbConnection::findScreenForOutput(xcb_window_t rootWindow, xcb_ran
return 0;
}
QXcbScreen* QXcbConnection::createScreen(int screenNumber, xcb_screen_t* xcbScreen,
QXcbScreen* QXcbConnection::createScreen(QXcbVirtualDesktop* virtualDesktop,
xcb_randr_output_t outputId,
xcb_randr_get_output_info_reply_t *output)
{
@ -156,10 +156,10 @@ QXcbScreen* QXcbConnection::createScreen(int screenNumber, xcb_screen_t* xcbScre
int dotPos = displayName.lastIndexOf('.');
if (dotPos != -1)
displayName.truncate(dotPos);
name = QString::fromLocal8Bit(displayName) + QLatin1Char('.') + QString::number(screenNumber);
name = QString::fromLocal8Bit(displayName) + QLatin1Char('.') + QString::number(virtualDesktop->number());
}
return new QXcbScreen(this, xcbScreen, outputId, output, name, screenNumber);
return new QXcbScreen(this, virtualDesktop, outputId, output, name);
}
bool QXcbConnection::checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_output_t output)
@ -179,15 +179,11 @@ bool QXcbConnection::checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_out
return isPrimary;
}
xcb_screen_t* QXcbConnection::xcbScreenForRootWindow(xcb_window_t rootWindow, int *xcbScreenNumber)
QXcbVirtualDesktop* QXcbConnection::virtualDesktopForRootWindow(xcb_window_t rootWindow)
{
xcb_screen_iterator_t xcbScreenIter = xcb_setup_roots_iterator(m_setup);
for (; xcbScreenIter.rem; xcb_screen_next(&xcbScreenIter)) {
if (xcbScreenIter.data->root == rootWindow) {
if (xcbScreenNumber)
*xcbScreenNumber = xcb_setup_roots_length(m_setup) - xcbScreenIter.rem;
return xcbScreenIter.data;
}
foreach (QXcbVirtualDesktop *virtualDesktop, m_virtualDesktops) {
if (virtualDesktop->screen()->root == rootWindow)
return virtualDesktop;
}
return 0;
@ -200,8 +196,8 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event)
{
if (event->subCode == XCB_RANDR_NOTIFY_CRTC_CHANGE) {
xcb_randr_crtc_change_t crtc = event->u.cc;
xcb_screen_t *xcbScreen = xcbScreenForRootWindow(crtc.window);
if (!xcbScreen)
QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(crtc.window);
if (!virtualDesktop)
// Not for us
return;
@ -218,9 +214,8 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event)
} else if (event->subCode == XCB_RANDR_NOTIFY_OUTPUT_CHANGE) {
xcb_randr_output_change_t output = event->u.oc;
int xcbScreenNumber = 0;
xcb_screen_t *xcbScreen = xcbScreenForRootWindow(output.window, &xcbScreenNumber);
if (!xcbScreen)
QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(output.window);
if (!virtualDesktop)
// Not for us
return;
@ -248,7 +243,7 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event)
QScopedPointer<xcb_randr_get_output_info_reply_t, QScopedPointerPodDeleter> outputInfo(
xcb_randr_get_output_info_reply(xcb_connection(), outputInfoCookie, NULL));
screen = createScreen(xcbScreenNumber, xcbScreen, output.output, outputInfo.data());
screen = createScreen(virtualDesktop, output.output, outputInfo.data());
qCDebug(lcQpaScreen) << "output" << screen->name() << "is connected and enabled";
screen->setPrimary(checkOutputIsPrimary(output.window, output.output));
@ -299,14 +294,15 @@ void QXcbConnection::initializeScreens()
xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup);
int xcbScreenNumber = 0; // screen number in the xcb sense
QXcbScreen* primaryScreen = Q_NULLPTR;
xcb_screen_t *xcbScreen = Q_NULLPTR;
bool hasOutputs = false;
while (it.rem) {
// Each "screen" in xcb terminology is a virtual desktop,
// potentially a collection of separate juxtaposed monitors.
// But we want a separate QScreen for each output (e.g. DVI-I-1, VGA-1, etc.)
// which will become virtual siblings.
xcbScreen = it.data;
xcb_screen_t *xcbScreen = it.data;
QXcbVirtualDesktop *virtualDesktop = new QXcbVirtualDesktop(this, xcbScreen, xcbScreenNumber);
m_virtualDesktops.append(virtualDesktop);
QList<QPlatformScreen *> siblings;
int outputCount = 0;
int connectedOutputCount = 0;
@ -376,7 +372,7 @@ void QXcbConnection::initializeScreens()
continue;
}
QXcbScreen *screen = createScreen(xcbScreenNumber, xcbScreen, outputs[i], output.data());
QXcbScreen *screen = createScreen(virtualDesktop, outputs[i], output.data());
siblings << screen;
++connectedOutputCount;
hasOutputs = true;
@ -411,8 +407,9 @@ void QXcbConnection::initializeScreens()
// but the dimensions are known anyway, and we don't already have any lingering
// (possibly disconnected) screens, then showing windows should be possible,
// so create one screen. (QTBUG-31389)
if (xcbScreen && !hasOutputs && xcbScreen->width_in_pixels > 0 && xcbScreen->height_in_pixels > 0 && m_screens.isEmpty()) {
QXcbScreen *screen = createScreen(0, xcbScreen, 0, Q_NULLPTR);
QXcbVirtualDesktop *virtualDesktop = m_virtualDesktops.value(0);
if (virtualDesktop && !hasOutputs && !virtualDesktop->size().isEmpty() && m_screens.isEmpty()) {
QXcbScreen *screen = createScreen(virtualDesktop, 0, Q_NULLPTR);
screen->setVirtualSiblings(QList<QPlatformScreen *>() << screen);
m_screens << screen;
primaryScreen = screen;
@ -583,6 +580,9 @@ QXcbConnection::~QXcbConnection()
while (!m_screens.isEmpty())
integration->destroyScreen(m_screens.takeLast());
while (!m_virtualDesktops.isEmpty())
delete m_virtualDesktops.takeLast();
delete m_glIntegration;
#ifdef XCB_USE_XLIB

View File

@ -80,6 +80,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaXInput)
Q_DECLARE_LOGGING_CATEGORY(lcQpaXInputDevices)
Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen)
class QXcbVirtualDesktop;
class QXcbScreen;
class QXcbWindow;
class QXcbDrag;
@ -494,12 +495,12 @@ private:
void initializeXShape();
void initializeXKB();
void handleClientMessageEvent(const xcb_client_message_event_t *event);
QXcbScreen* createScreen(int screenNumber, xcb_screen_t* xcbScreen,
QXcbScreen* createScreen(QXcbVirtualDesktop *virtualDesktop,
xcb_randr_output_t outputId = XCB_NONE,
xcb_randr_get_output_info_reply_t *output = 0);
QXcbScreen* findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc);
QXcbScreen* findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output);
xcb_screen_t* xcbScreenForRootWindow(xcb_window_t rootWindow, int *xcbScreenNumber = 0);
QXcbVirtualDesktop* virtualDesktopForRootWindow(xcb_window_t rootWindow);
bool checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_output_t output);
void initializeScreens();
void updateScreens(const xcb_randr_notify_event_t *event);
@ -564,6 +565,7 @@ private:
const xcb_setup_t *m_setup;
bool m_canGrabServer;
QList<QXcbVirtualDesktop *> m_virtualDesktops;
QList<QXcbScreen *> m_screens;
int m_primaryScreenNumber;

View File

@ -502,7 +502,7 @@ bool updateCursorTheme(void *dpy, const QByteArray &theme) {
return setTheme;
}
void QXcbCursor::cursorThemePropertyChanged(QXcbScreen *screen, const QByteArray &name, const QVariant &property, void *handle)
void QXcbCursor::cursorThemePropertyChanged(QXcbVirtualDesktop *screen, const QByteArray &name, const QVariant &property, void *handle)
{
Q_UNUSED(screen);
Q_UNUSED(name);

View File

@ -91,7 +91,7 @@ private:
CursorHash m_cursorHash;
#endif
#ifdef XCB_USE_XLIB
static void cursorThemePropertyChanged(QXcbScreen *screen,
static void cursorThemePropertyChanged(QXcbVirtualDesktop *screen,
const QByteArray &name,
const QVariant &property,
void *handle);

View File

@ -47,11 +47,33 @@
QT_BEGIN_NAMESPACE
QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr,
xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output,
QString outputName, int number)
QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t *screen, int number)
: QXcbObject(connection)
, m_screen(scr)
, m_screen(screen)
, m_number(number)
, m_xSettings(Q_NULLPTR)
{
}
QXcbVirtualDesktop::~QXcbVirtualDesktop()
{
delete m_xSettings;
}
QXcbXSettings *QXcbVirtualDesktop::xSettings() const
{
if (!m_xSettings) {
QXcbVirtualDesktop *self = const_cast<QXcbVirtualDesktop *>(this);
self->m_xSettings = new QXcbXSettings(self);
}
return m_xSettings;
}
QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop,
xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output,
QString outputName)
: QXcbObject(connection)
, m_virtualDesktop(virtualDesktop)
, m_output(outputId)
, m_crtc(output ? output->crtc : 0)
, m_mode(XCB_NONE)
@ -59,10 +81,9 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr,
, m_rotation(XCB_RANDR_ROTATION_ROTATE_0)
, m_outputName(outputName)
, m_outputSizeMillimeters(output ? QSize(output->mm_width, output->mm_height) : QSize())
, m_virtualSize(scr->width_in_pixels, scr->height_in_pixels)
, m_virtualSizeMillimeters(scr->width_in_millimeters, scr->height_in_millimeters)
, m_virtualSize(virtualDesktop->size())
, m_virtualSizeMillimeters(virtualDesktop->physicalSize())
, m_orientation(Qt::PrimaryOrientation)
, m_number(number)
, m_refreshRate(60)
, m_forcedDpi(-1)
, m_devicePixelRatio(1)
@ -70,7 +91,6 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr,
, m_noFontHinting(false)
, m_subpixelType(QFontEngine::SubpixelAntialiasingType(-1))
, m_antialiasingEnabled(-1)
, m_xSettings(0)
{
if (connection->hasXRandr()) {
xcb_randr_select_input(xcb_connection(), screen()->root, true);
@ -215,7 +235,7 @@ QXcbScreen::~QXcbScreen()
QWindow *QXcbScreen::topLevelAt(const QPoint &p) const
{
xcb_window_t root = m_screen->root;
xcb_window_t root = screen()->root;
int dpr = int(devicePixelRatio());
int x = p.x() / dpr;
@ -496,7 +516,7 @@ void QXcbScreen::updateRefreshRate(xcb_randr_mode_t mode)
// we can safely use get_screen_resources_current here, because in order to
// get here, we must have called get_screen_resources before
xcb_randr_get_screen_resources_current_cookie_t resourcesCookie =
xcb_randr_get_screen_resources_current_unchecked(xcb_connection(), m_screen->root);
xcb_randr_get_screen_resources_current_unchecked(xcb_connection(), screen()->root);
xcb_randr_get_screen_resources_current_reply_t *resources =
xcb_randr_get_screen_resources_current_reply(xcb_connection(), resourcesCookie, NULL);
if (resources) {
@ -707,11 +727,7 @@ void QXcbScreen::readXResources()
QXcbXSettings *QXcbScreen::xSettings() const
{
if (!m_xSettings) {
QXcbScreen *self = const_cast<QXcbScreen *>(this);
self->m_xSettings = new QXcbXSettings(self);
}
return m_xSettings;
return m_virtualDesktop->xSettings();
}
static inline void formatRect(QDebug &debug, const QRect r)

View File

@ -54,12 +54,32 @@ class QXcbXSettings;
class QDebug;
#endif
class QXcbVirtualDesktop : public QXcbObject
{
public:
QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t *screen, int number);
~QXcbVirtualDesktop();
xcb_screen_t *screen() const { return m_screen; }
int number() const { return m_number; }
QSize size() const { return QSize(m_screen->width_in_pixels, m_screen->height_in_pixels); }
QSize physicalSize() const { return QSize(m_screen->width_in_millimeters, m_screen->height_in_millimeters); }
QXcbXSettings *xSettings() const;
private:
xcb_screen_t *m_screen;
int m_number;
QXcbXSettings *m_xSettings;
};
class Q_XCB_EXPORT QXcbScreen : public QXcbObject, public QPlatformScreen
{
public:
QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen,
QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop,
xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output,
QString outputName, int number);
QString outputName);
~QXcbScreen();
QPixmap grabWindow(WId window, int x, int y, int width, int height) const Q_DECL_OVERRIDE;
@ -69,7 +89,7 @@ public:
QRect geometry() const Q_DECL_OVERRIDE { return m_geometry; }
QRect nativeGeometry() const { return m_nativeGeometry; }
QRect availableGeometry() const Q_DECL_OVERRIDE {return m_availableGeometry;}
int depth() const Q_DECL_OVERRIDE { return m_screen->root_depth; }
int depth() const Q_DECL_OVERRIDE { return screen()->root_depth; }
QImage::Format format() const Q_DECL_OVERRIDE;
QSizeF physicalSize() const Q_DECL_OVERRIDE { return m_sizeMillimeters; }
QSize virtualSize() const { return m_virtualSize; }
@ -87,10 +107,10 @@ public:
void setPrimary(bool primary) { m_primary = primary; }
bool isPrimary() const { return m_primary; }
int screenNumber() const { return m_number; }
int screenNumber() const { return m_virtualDesktop->number(); }
xcb_screen_t *screen() const { return m_screen; }
xcb_window_t root() const { return m_screen->root; }
xcb_screen_t *screen() const { return m_virtualDesktop->screen(); }
xcb_window_t root() const { return screen()->root; }
xcb_randr_output_t output() const { return m_output; }
xcb_randr_crtc_t crtc() const { return m_crtc; }
xcb_randr_mode_t mode() const { return m_mode; }
@ -126,7 +146,7 @@ private:
QByteArray &stringValue);
void sendStartupMessage(const QByteArray &message) const;
xcb_screen_t *m_screen;
QXcbVirtualDesktop *m_virtualDesktop;
xcb_randr_output_t m_output;
xcb_randr_crtc_t m_crtc;
xcb_randr_mode_t m_mode;
@ -143,7 +163,6 @@ private:
QSizeF m_virtualSizeMillimeters;
QList<QPlatformScreen *> m_siblings;
Qt::ScreenOrientation m_orientation;
int m_number;
QString m_windowManagerName;
bool m_syncRequestSupported;
xcb_window_t m_clientLeader;
@ -157,7 +176,6 @@ private:
bool m_noFontHinting;
QFontEngine::SubpixelAntialiasingType m_subpixelType;
int m_antialiasingEnabled;
QXcbXSettings *m_xSettings;
};
#ifndef QT_NO_DEBUG_STREAM

View File

@ -63,7 +63,7 @@ public:
: last_change_serial(-1)
{}
void updateValue(QXcbScreen *screen, const QByteArray &name, const QVariant &value, int last_change_serial)
void updateValue(QXcbVirtualDesktop *screen, const QByteArray &name, const QVariant &value, int last_change_serial)
{
if (last_change_serial <= this->last_change_serial)
return;
@ -92,7 +92,7 @@ public:
class QXcbXSettingsPrivate
{
public:
QXcbXSettingsPrivate(QXcbScreen *screen)
QXcbXSettingsPrivate(QXcbVirtualDesktop *screen)
: screen(screen)
, initialized(false)
{
@ -217,18 +217,18 @@ public:
}
#endif //XCB_USE_XLIB
QXcbScreen *screen;
QXcbVirtualDesktop *screen;
xcb_window_t x_settings_window;
QMap<QByteArray, QXcbXSettingsPropertyValue> settings;
bool initialized;
};
QXcbXSettings::QXcbXSettings(QXcbScreen *screen)
QXcbXSettings::QXcbXSettings(QXcbVirtualDesktop *screen)
: d_ptr(new QXcbXSettingsPrivate(screen))
{
QByteArray settings_atom_for_screen("_XSETTINGS_S");
settings_atom_for_screen.append(QByteArray::number(screen->screenNumber()));
settings_atom_for_screen.append(QByteArray::number(screen->number()));
xcb_intern_atom_cookie_t atom_cookie = xcb_intern_atom(screen->xcb_connection(),
true,
settings_atom_for_screen.length(),

View File

@ -44,13 +44,13 @@ class QXcbXSettings : public QXcbWindowEventListener
{
Q_DECLARE_PRIVATE(QXcbXSettings)
public:
QXcbXSettings(QXcbScreen *screen);
QXcbXSettings(QXcbVirtualDesktop *screen);
~QXcbXSettings();
bool initialized() const;
QVariant setting(const QByteArray &property) const;
typedef void (*PropertyChangeFunc)(QXcbScreen *screen, const QByteArray &name, const QVariant &property, void *handle);
typedef void (*PropertyChangeFunc)(QXcbVirtualDesktop *screen, const QByteArray &name, const QVariant &property, void *handle);
void registerCallbackForProperty(const QByteArray &property, PropertyChangeFunc func, void *handle);
void removeCallbackForHandle(const QByteArray &property, void *handle);
void removeCallbackForHandle(void *handle);