Make it possible to use the -visual argument

for xcb applications to use a specific visual id when creating windows.

Also make it possible to retrieve the visual id of a specific window
with QXcbWindowFunctions::visualId(QWindow *window).

UINT_MAX is used as an invalid visualId.

Change-Id: If62ada119ce8f9174cc211f53bbf1ce1bb7d021a
Reviewed-by: Andy Shaw <andy.shaw@digia.com>
This commit is contained in:
Jørgen Lind 2015-04-10 12:57:02 +02:00
parent 7432c7c08a
commit d605883b5e
8 changed files with 119 additions and 28 deletions

View File

@ -72,6 +72,17 @@ public:
if (func)
func(window, type);
}
typedef uint (*VisualId)(QWindow *window);
static const QByteArray visualIdIdentifier() { return QByteArrayLiteral("XcbVisualId"); }
static uint visualId(QWindow *window)
{
QXcbWindowFunctions::VisualId func = reinterpret_cast<VisualId>(QGuiApplication::platformFunction(visualIdIdentifier()));
if (func)
return func(window);
return UINT_MAX;
}
};

View File

@ -66,6 +66,7 @@
#include <X11/Xlib.h>
#include <X11/Xlib-xcb.h>
#include <X11/Xlibint.h>
#include <X11/Xutil.h>
#endif
#if defined(XCB_USE_XINPUT2)
@ -437,9 +438,10 @@ void QXcbConnection::initializeScreens()
qCDebug(lcQpaScreen) << "primary output is" << m_screens.first()->name();
}
QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, const char *displayName)
QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, xcb_visualid_t defaultVisualId, const char *displayName)
: m_connection(0)
, m_canGrabServer(canGrabServer)
, m_defaultVisualId(defaultVisualId)
, m_primaryScreenNumber(0)
, m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY"))
, m_nativeInterface(nativeInterface)
@ -1351,6 +1353,21 @@ void *QXcbConnection::xlib_display() const
{
return m_xlib_display;
}
void *QXcbConnection::createVisualInfoForDefaultVisualId() const
{
if (m_defaultVisualId == UINT_MAX)
return 0;
XVisualInfo info;
memset(&info, 0, sizeof info);
info.visualid = m_defaultVisualId;
int count = 0;
XVisualInfo *retVisual = XGetVisualInfo(DISPLAY_FROM_XCB(this), VisualIDMask, &info, &count);
Q_ASSERT(count < 2);
return retVisual;
}
#endif
void QXcbConnection::processXcbEvents()

View File

@ -370,7 +370,7 @@ class Q_XCB_EXPORT QXcbConnection : public QObject
{
Q_OBJECT
public:
QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, const char *displayName = 0);
QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, xcb_visualid_t defaultVisualId, const char *displayName = 0);
~QXcbConnection();
QXcbConnection *connection() const { return const_cast<QXcbConnection *>(this); }
@ -400,8 +400,13 @@ public:
QXcbWMSupport *wmSupport() const { return m_wmSupport.data(); }
xcb_window_t rootWindow();
bool hasDefaultVisualId() const { return m_defaultVisualId != UINT_MAX; }
xcb_visualid_t defaultVisualId() const { return m_defaultVisualId; }
#ifdef XCB_USE_XLIB
void *xlib_display() const;
void *createVisualInfoForDefaultVisualId() const;
#endif
#if defined(XCB_USE_XINPUT2)
@ -564,6 +569,7 @@ private:
xcb_connection_t *m_connection;
const xcb_setup_t *m_setup;
bool m_canGrabServer;
xcb_visualid_t m_defaultVisualId;
QList<QXcbVirtualDesktop *> m_virtualDesktops;
QList<QXcbScreen *> m_screens;
@ -632,6 +638,7 @@ private:
};
#define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display()))
#define CREATE_VISUALINFO_FROM_DEFAULT_VISUALID(object) ((XVisualInfo *)(object->connection()->createVisualInfoForDefaultVisualId()))
template<typename T>
xcb_generic_event_t *QXcbConnection::checkEvent(T &checker)

View File

@ -116,6 +116,7 @@ QXcbIntegration::QXcbIntegration(const QStringList &parameters, int &argc, char
: m_services(new QGenericUnixServices)
, m_instanceName(0)
, m_canGrab(true)
, m_defaultVisualId(UINT_MAX)
{
m_instance = this;
@ -143,6 +144,12 @@ QXcbIntegration::QXcbIntegration(const QStringList &parameters, int &argc, char
noGrabArg = true;
else if (arg == "-dograb")
doGrabArg = true;
else if (arg == "-visual" && i < argc - 1) {
bool ok = false;
m_defaultVisualId = QByteArray(argv[++i]).toUInt(&ok, 0);
if (!ok)
m_defaultVisualId = UINT_MAX;
}
else
argv[j++] = argv[i];
}
@ -167,12 +174,12 @@ QXcbIntegration::QXcbIntegration(const QStringList &parameters, int &argc, char
if (canNotGrabEnv)
m_canGrab = false;
m_connections << new QXcbConnection(m_nativeInterface.data(), m_canGrab, displayName);
m_connections << new QXcbConnection(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, displayName);
for (int i = 0; i < parameters.size() - 1; i += 2) {
qCDebug(lcQpaScreen) << "connecting to additional display: " << parameters.at(i) << parameters.at(i+1);
QString display = parameters.at(i) + QLatin1Char(':') + parameters.at(i+1);
m_connections << new QXcbConnection(m_nativeInterface.data(), m_canGrab, display.toLatin1().constData());
m_connections << new QXcbConnection(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, display.toLatin1().constData());
}
m_fontDatabase.reset(new QGenericUnixFontDatabase());

View File

@ -39,6 +39,8 @@
#include "qxcbexport.h"
#include <xcb/xcb.h>
QT_BEGIN_NAMESPACE
class QXcbConnection;
@ -123,6 +125,7 @@ private:
mutable QByteArray m_wmClass;
const char *m_instanceName;
bool m_canGrab;
xcb_visualid_t m_defaultVisualId;
static QXcbIntegration *m_instance;
};

View File

@ -392,6 +392,9 @@ QFunctionPointer QXcbNativeInterface::platformFunction(const QByteArray &functio
if (function == QXcbWindowFunctions::setWmWindowTypeIdentifier()) {
return QFunctionPointer(QXcbWindow::setWmWindowTypeStatic);
}
if (function == QXcbWindowFunctions::visualIdIdentifier()) {
return QFunctionPointer(QXcbWindowFunctions::VisualId(QXcbWindow::visualIdStatic));
}
return Q_NULLPTR;
}

View File

@ -388,7 +388,16 @@ void QXcbWindow::create()
m_window = platformScreen->root();
m_depth = platformScreen->screen()->root_depth;
m_visualId = platformScreen->screen()->root_visual;
const xcb_visualtype_t *visual = platformScreen->visualForId(m_visualId);
const xcb_visualtype_t *visual = 0;
if (connection()->hasDefaultVisualId()) {
visual = platformScreen->visualForId(connection()->defaultVisualId());
if (visual)
m_visualId = connection()->defaultVisualId();
if (!visual)
qWarning() << "Could not use default visual id. Falling back to root_visual for screen.";
}
if (!visual)
visual = platformScreen->visualForId(m_visualId);
m_imageFormat = imageFormatForVisual(m_depth, visual->red_mask, visual->blue_mask, &m_imageRgbSwap);
connection()->addWindowEventListener(m_window, this);
return;
@ -442,7 +451,12 @@ void QXcbWindow::create()
#ifdef XCB_USE_XLIB
if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) {
XVisualInfo *visualInfo = static_cast<XVisualInfo *>(createVisual());
XVisualInfo *visualInfo = Q_NULLPTR;
if (connection()->hasDefaultVisualId())
visualInfo = CREATE_VISUALINFO_FROM_DEFAULT_VISUALID(this);
if (!visualInfo)
visualInfo = static_cast<XVisualInfo *>(createVisual());
if (!visualInfo && window()->surfaceType() == QSurface::OpenGLSurface)
qFatal("Could not initialize OpenGL");
@ -477,35 +491,49 @@ void QXcbWindow::create()
if (!m_window)
{
m_window = xcb_generate_id(xcb_connection());
m_visualId = platformScreen->screen()->root_visual;
m_visualId = UINT_MAX;
const xcb_visualtype_t *visual = Q_NULLPTR;
m_depth = platformScreen->screen()->root_depth;
uint32_t mask = 0;
uint32_t values[3];
if (m_format.alphaBufferSize() == 8) {
xcb_depth_iterator_t depthIter = xcb_screen_allowed_depths_iterator(platformScreen->screen());
while (depthIter.rem) {
if (depthIter.data->depth == 32) {
xcb_visualtype_iterator_t visualIter = xcb_depth_visuals_iterator(depthIter.data);
if (visualIter.rem) {
m_visualId = visualIter.data->visual_id;
m_depth = 32;
uint32_t colormap = xcb_generate_id(xcb_connection());
xcb_create_colormap(xcb_connection(), XCB_COLORMAP_ALLOC_NONE, colormap,
xcb_parent_id, m_visualId);
mask |= XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP;
values[0] = platformScreen->screen()->white_pixel;
values[1] = platformScreen->screen()->black_pixel;
values[2] = colormap;
break;
}
}
xcb_depth_next(&depthIter);
}
if (connection()->hasDefaultVisualId()) {
m_visualId = connection()->defaultVisualId();
visual = platformScreen->visualForId(m_visualId);
}
if (!visual) {
if (connection()->hasDefaultVisualId())
qWarning("Failed to use default visual id. Falling back to using screens root_visual");
m_visualId = platformScreen->screen()->root_visual;
if (m_format.alphaBufferSize() == 8) {
xcb_depth_iterator_t depthIter = xcb_screen_allowed_depths_iterator(platformScreen->screen());
while (depthIter.rem) {
if (depthIter.data->depth == 32) {
xcb_visualtype_iterator_t visualIter = xcb_depth_visuals_iterator(depthIter.data);
if (visualIter.rem) {
m_visualId = visualIter.data->visual_id;
m_depth = 32;
uint32_t colormap = xcb_generate_id(xcb_connection());
xcb_create_colormap(xcb_connection(), XCB_COLORMAP_ALLOC_NONE, colormap,
xcb_parent_id, m_visualId);
mask |= XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP;
values[0] = platformScreen->screen()->white_pixel;
values[1] = platformScreen->screen()->black_pixel;
values[2] = colormap;
break;
}
}
xcb_depth_next(&depthIter);
}
}
visual = platformScreen->visualForId(m_visualId);
}
const xcb_visualtype_t *visual = platformScreen->visualForId(m_visualId);
m_imageFormat = imageFormatForVisual(m_depth, visual->red_mask, visual->blue_mask, &m_imageRgbSwap);
const QRect xRect = mapToNative(rect, platformScreen);
@ -1680,6 +1708,13 @@ void QXcbWindow::setWmWindowTypeStatic(QWindow *window, QXcbWindowFunctions::WmW
window->setProperty(wm_window_type_property_id, QVariant::fromValue(static_cast<int>(windowTypes)));
}
uint QXcbWindow::visualIdStatic(QWindow *window)
{
if (window && window->handle())
return static_cast<QXcbWindow *>(window->handle())->visualId();
return UINT_MAX;
}
QXcbWindowFunctions::WmWindowTypes QXcbWindow::wmWindowTypes() const
{
QXcbWindowFunctions::WmWindowTypes result(0);
@ -2531,6 +2566,11 @@ void QXcbWindow::setAlertState(bool enabled)
changeNetWmState(enabled, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION));
}
uint QXcbWindow::visualId() const
{
return m_visualId;
}
bool QXcbWindow::needsSync() const
{
return m_syncState == SyncAndConfigureReceived;

View File

@ -139,10 +139,13 @@ public:
void updateNetWmUserTime(xcb_timestamp_t timestamp);
static void setWmWindowTypeStatic(QWindow *window, QXcbWindowFunctions::WmWindowTypes windowTypes);
static uint visualIdStatic(QWindow *window);
QXcbWindowFunctions::WmWindowTypes wmWindowTypes() const;
void setWmWindowType(QXcbWindowFunctions::WmWindowTypes types);
uint visualId() const;
bool needsSync() const;
void postSyncWindowRequest();