diff options
Diffstat (limited to 'src/platformsupport')
38 files changed, 1905 insertions, 276 deletions
diff --git a/src/platformsupport/devicediscovery/qdevicediscovery_p.h b/src/platformsupport/devicediscovery/qdevicediscovery_p.h index d4962fb7d6..e3c22b0b37 100644 --- a/src/platformsupport/devicediscovery/qdevicediscovery_p.h +++ b/src/platformsupport/devicediscovery/qdevicediscovery_p.h @@ -68,7 +68,6 @@ QT_BEGIN_NAMESPACE class QDeviceDiscovery : public QObject { Q_OBJECT - Q_ENUMS(QDeviceType) public: enum QDeviceType { @@ -84,6 +83,7 @@ public: Device_InputMask = Device_Mouse | Device_Touchpad | Device_Touchscreen | Device_Keyboard | Device_Tablet | Device_Joystick, Device_VideoMask = Device_DRM }; + Q_ENUM(QDeviceType) Q_DECLARE_FLAGS(QDeviceTypes, QDeviceType) static QDeviceDiscovery *create(QDeviceTypes type, QObject *parent = 0); diff --git a/src/platformsupport/devicediscovery/qdevicediscovery_static.cpp b/src/platformsupport/devicediscovery/qdevicediscovery_static.cpp index 5c72dbe7e2..a1575677f5 100644 --- a/src/platformsupport/devicediscovery/qdevicediscovery_static.cpp +++ b/src/platformsupport/devicediscovery/qdevicediscovery_static.cpp @@ -47,7 +47,11 @@ #include <QLoggingCategory> #include <QtCore/private/qcore_unix_p.h> +#ifdef Q_OS_FREEBSD +#include <dev/evdev/input.h> +#else #include <linux/input.h> +#endif #include <fcntl.h> /* android (and perhaps some other linux-derived stuff) don't define everything diff --git a/src/platformsupport/eglconvenience/qeglconvenience.cpp b/src/platformsupport/eglconvenience/qeglconvenience.cpp index da41cfeabf..020d035bf7 100644 --- a/src/platformsupport/eglconvenience/qeglconvenience.cpp +++ b/src/platformsupport/eglconvenience/qeglconvenience.cpp @@ -100,18 +100,24 @@ QVector<EGLint> q_createConfigAttributesFromFormat(const QSurfaceFormat &format) configAttributes.append(EGL_ALPHA_SIZE); configAttributes.append(alphaSize > 0 ? alphaSize : 0); - configAttributes.append(EGL_DEPTH_SIZE); - configAttributes.append(depthSize > 0 ? depthSize : 0); - - configAttributes.append(EGL_STENCIL_SIZE); - configAttributes.append(stencilSize > 0 ? stencilSize : 0); - configAttributes.append(EGL_SAMPLES); configAttributes.append(sampleCount > 0 ? sampleCount : 0); configAttributes.append(EGL_SAMPLE_BUFFERS); configAttributes.append(sampleCount > 0); + if (format.renderableType() != QSurfaceFormat::OpenVG) { + configAttributes.append(EGL_DEPTH_SIZE); + configAttributes.append(depthSize > 0 ? depthSize : 0); + + configAttributes.append(EGL_STENCIL_SIZE); + configAttributes.append(stencilSize > 0 ? stencilSize : 0); + } else { + // OpenVG needs alpha mask for clipping + configAttributes.append(EGL_ALPHA_MASK_SIZE); + configAttributes.append(8); + } + return configAttributes; } diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp index 6a3bc25418..674ab29012 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp @@ -167,6 +167,13 @@ void QEGLPlatformContext::init(const QSurfaceFormat &format, QPlatformOpenGLCont : EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR); } } + + // Special Options for OpenVG surfaces + if (m_format.renderableType() == QSurfaceFormat::OpenVG) { + contextAttrs.append(EGL_ALPHA_MASK_SIZE); + contextAttrs.append(8); + } + contextAttrs.append(EGL_NONE); m_contextAttrs = contextAttrs; @@ -450,7 +457,352 @@ QFunctionPointer QEGLPlatformContext::getProcAddress(const char *procName) #if !defined(Q_OS_WIN) && !defined(Q_OS_INTEGRITY) if (!proc) proc = (QFunctionPointer) dlsym(RTLD_DEFAULT, procName); +#elif !defined(QT_OPENGL_DYNAMIC) + // On systems without KHR_get_all_proc_addresses and without + // dynamic linking there still has to be a way to access the + // standard GLES functions. QOpenGL(Extra)Functions never makes + // direct GL API calls since Qt 5.7, so all such workarounds are + // expected to be handled in the platform plugin. + if (!proc) { + static struct StdFunc { + const char *name; + QFunctionPointer func; + } standardFuncs[] = { +#ifdef QT_OPENGL_ES_2 + { "glBindTexture", (QFunctionPointer) ::glBindTexture }, + { "glBlendFunc", (QFunctionPointer) ::glBlendFunc }, + { "glClear", (QFunctionPointer) ::glClear }, + { "glClearColor", (QFunctionPointer) ::glClearColor }, + { "glClearStencil", (QFunctionPointer) ::glClearStencil }, + { "glColorMask", (QFunctionPointer) ::glColorMask }, + { "glCopyTexImage2D", (QFunctionPointer) ::glCopyTexImage2D }, + { "glCopyTexSubImage2D", (QFunctionPointer) ::glCopyTexSubImage2D }, + { "glCullFace", (QFunctionPointer) ::glCullFace }, + { "glDeleteTextures", (QFunctionPointer) ::glDeleteTextures }, + { "glDepthFunc", (QFunctionPointer) ::glDepthFunc }, + { "glDepthMask", (QFunctionPointer) ::glDepthMask }, + { "glDisable", (QFunctionPointer) ::glDisable }, + { "glDrawArrays", (QFunctionPointer) ::glDrawArrays }, + { "glDrawElements", (QFunctionPointer) ::glDrawElements }, + { "glEnable", (QFunctionPointer) ::glEnable }, + { "glFinish", (QFunctionPointer) ::glFinish }, + { "glFlush", (QFunctionPointer) ::glFlush }, + { "glFrontFace", (QFunctionPointer) ::glFrontFace }, + { "glGenTextures", (QFunctionPointer) ::glGenTextures }, + { "glGetBooleanv", (QFunctionPointer) ::glGetBooleanv }, + { "glGetError", (QFunctionPointer) ::glGetError }, + { "glGetFloatv", (QFunctionPointer) ::glGetFloatv }, + { "glGetIntegerv", (QFunctionPointer) ::glGetIntegerv }, + { "glGetString", (QFunctionPointer) ::glGetString }, + { "glGetTexParameterfv", (QFunctionPointer) ::glGetTexParameterfv }, + { "glGetTexParameteriv", (QFunctionPointer) ::glGetTexParameteriv }, + { "glHint", (QFunctionPointer) ::glHint }, + { "glIsEnabled", (QFunctionPointer) ::glIsEnabled }, + { "glIsTexture", (QFunctionPointer) ::glIsTexture }, + { "glLineWidth", (QFunctionPointer) ::glLineWidth }, + { "glPixelStorei", (QFunctionPointer) ::glPixelStorei }, + { "glPolygonOffset", (QFunctionPointer) ::glPolygonOffset }, + { "glReadPixels", (QFunctionPointer) ::glReadPixels }, + { "glScissor", (QFunctionPointer) ::glScissor }, + { "glStencilFunc", (QFunctionPointer) ::glStencilFunc }, + { "glStencilMask", (QFunctionPointer) ::glStencilMask }, + { "glStencilOp", (QFunctionPointer) ::glStencilOp }, + { "glTexImage2D", (QFunctionPointer) ::glTexImage2D }, + { "glTexParameterf", (QFunctionPointer) ::glTexParameterf }, + { "glTexParameterfv", (QFunctionPointer) ::glTexParameterfv }, + { "glTexParameteri", (QFunctionPointer) ::glTexParameteri }, + { "glTexParameteriv", (QFunctionPointer) ::glTexParameteriv }, + { "glTexSubImage2D", (QFunctionPointer) ::glTexSubImage2D }, + { "glViewport", (QFunctionPointer) ::glViewport }, + + { "glActiveTexture", (QFunctionPointer) ::glActiveTexture }, + { "glAttachShader", (QFunctionPointer) ::glAttachShader }, + { "glBindAttribLocation", (QFunctionPointer) ::glBindAttribLocation }, + { "glBindBuffer", (QFunctionPointer) ::glBindBuffer }, + { "glBindFramebuffer", (QFunctionPointer) ::glBindFramebuffer }, + { "glBindRenderbuffer", (QFunctionPointer) ::glBindRenderbuffer }, + { "glBlendColor", (QFunctionPointer) ::glBlendColor }, + { "glBlendEquation", (QFunctionPointer) ::glBlendEquation }, + { "glBlendEquationSeparate", (QFunctionPointer) ::glBlendEquationSeparate }, + { "glBlendFuncSeparate", (QFunctionPointer) ::glBlendFuncSeparate }, + { "glBufferData", (QFunctionPointer) ::glBufferData }, + { "glBufferSubData", (QFunctionPointer) ::glBufferSubData }, + { "glCheckFramebufferStatus", (QFunctionPointer) ::glCheckFramebufferStatus }, + { "glCompileShader", (QFunctionPointer) ::glCompileShader }, + { "glCompressedTexImage2D", (QFunctionPointer) ::glCompressedTexImage2D }, + { "glCompressedTexSubImage2D", (QFunctionPointer) ::glCompressedTexSubImage2D }, + { "glCreateProgram", (QFunctionPointer) ::glCreateProgram }, + { "glCreateShader", (QFunctionPointer) ::glCreateShader }, + { "glDeleteBuffers", (QFunctionPointer) ::glDeleteBuffers }, + { "glDeleteFramebuffers", (QFunctionPointer) ::glDeleteFramebuffers }, + { "glDeleteProgram", (QFunctionPointer) ::glDeleteProgram }, + { "glDeleteRenderbuffers", (QFunctionPointer) ::glDeleteRenderbuffers }, + { "glDeleteShader", (QFunctionPointer) ::glDeleteShader }, + { "glDetachShader", (QFunctionPointer) ::glDetachShader }, + { "glDisableVertexAttribArray", (QFunctionPointer) ::glDisableVertexAttribArray }, + { "glEnableVertexAttribArray", (QFunctionPointer) ::glEnableVertexAttribArray }, + { "glFramebufferRenderbuffer", (QFunctionPointer) ::glFramebufferRenderbuffer }, + { "glFramebufferTexture2D", (QFunctionPointer) ::glFramebufferTexture2D }, + { "glGenBuffers", (QFunctionPointer) ::glGenBuffers }, + { "glGenerateMipmap", (QFunctionPointer) ::glGenerateMipmap }, + { "glGenFramebuffers", (QFunctionPointer) ::glGenFramebuffers }, + { "glGenRenderbuffers", (QFunctionPointer) ::glGenRenderbuffers }, + { "glGetActiveAttrib", (QFunctionPointer) ::glGetActiveAttrib }, + { "glGetActiveUniform", (QFunctionPointer) ::glGetActiveUniform }, + { "glGetAttachedShaders", (QFunctionPointer) ::glGetAttachedShaders }, + { "glGetAttribLocation", (QFunctionPointer) ::glGetAttribLocation }, + { "glGetBufferParameteriv", (QFunctionPointer) ::glGetBufferParameteriv }, + { "glGetFramebufferAttachmentParameteriv", (QFunctionPointer) ::glGetFramebufferAttachmentParameteriv }, + { "glGetProgramiv", (QFunctionPointer) ::glGetProgramiv }, + { "glGetProgramInfoLog", (QFunctionPointer) ::glGetProgramInfoLog }, + { "glGetRenderbufferParameteriv", (QFunctionPointer) ::glGetRenderbufferParameteriv }, + { "glGetShaderiv", (QFunctionPointer) ::glGetShaderiv }, + { "glGetShaderInfoLog", (QFunctionPointer) ::glGetShaderInfoLog }, + { "glGetShaderPrecisionFormat", (QFunctionPointer) ::glGetShaderPrecisionFormat }, + { "glGetShaderSource", (QFunctionPointer) ::glGetShaderSource }, + { "glGetUniformfv", (QFunctionPointer) ::glGetUniformfv }, + { "glGetUniformiv", (QFunctionPointer) ::glGetUniformiv }, + { "glGetUniformLocation", (QFunctionPointer) ::glGetUniformLocation }, + { "glGetVertexAttribfv", (QFunctionPointer) ::glGetVertexAttribfv }, + { "glGetVertexAttribiv", (QFunctionPointer) ::glGetVertexAttribiv }, + { "glGetVertexAttribPointerv", (QFunctionPointer) ::glGetVertexAttribPointerv }, + { "glIsBuffer", (QFunctionPointer) ::glIsBuffer }, + { "glIsFramebuffer", (QFunctionPointer) ::glIsFramebuffer }, + { "glIsProgram", (QFunctionPointer) ::glIsProgram }, + { "glIsRenderbuffer", (QFunctionPointer) ::glIsRenderbuffer }, + { "glIsShader", (QFunctionPointer) ::glIsShader }, + { "glLinkProgram", (QFunctionPointer) ::glLinkProgram }, + { "glReleaseShaderCompiler", (QFunctionPointer) ::glReleaseShaderCompiler }, + { "glRenderbufferStorage", (QFunctionPointer) ::glRenderbufferStorage }, + { "glSampleCoverage", (QFunctionPointer) ::glSampleCoverage }, + { "glShaderBinary", (QFunctionPointer) ::glShaderBinary }, + { "glShaderSource", (QFunctionPointer) ::glShaderSource }, + { "glStencilFuncSeparate", (QFunctionPointer) ::glStencilFuncSeparate }, + { "glStencilMaskSeparate", (QFunctionPointer) ::glStencilMaskSeparate }, + { "glStencilOpSeparate", (QFunctionPointer) ::glStencilOpSeparate }, + { "glUniform1f", (QFunctionPointer) ::glUniform1f }, + { "glUniform1fv", (QFunctionPointer) ::glUniform1fv }, + { "glUniform1i", (QFunctionPointer) ::glUniform1i }, + { "glUniform1iv", (QFunctionPointer) ::glUniform1iv }, + { "glUniform2f", (QFunctionPointer) ::glUniform2f }, + { "glUniform2fv", (QFunctionPointer) ::glUniform2fv }, + { "glUniform2i", (QFunctionPointer) ::glUniform2i }, + { "glUniform2iv", (QFunctionPointer) ::glUniform2iv }, + { "glUniform3f", (QFunctionPointer) ::glUniform3f }, + { "glUniform3fv", (QFunctionPointer) ::glUniform3fv }, + { "glUniform3i", (QFunctionPointer) ::glUniform3i }, + { "glUniform3iv", (QFunctionPointer) ::glUniform3iv }, + { "glUniform4f", (QFunctionPointer) ::glUniform4f }, + { "glUniform4fv", (QFunctionPointer) ::glUniform4fv }, + { "glUniform4i", (QFunctionPointer) ::glUniform4i }, + { "glUniform4iv", (QFunctionPointer) ::glUniform4iv }, + { "glUniformMatrix2fv", (QFunctionPointer) ::glUniformMatrix2fv }, + { "glUniformMatrix3fv", (QFunctionPointer) ::glUniformMatrix3fv }, + { "glUniformMatrix4fv", (QFunctionPointer) ::glUniformMatrix4fv }, + { "glUseProgram", (QFunctionPointer) ::glUseProgram }, + { "glValidateProgram", (QFunctionPointer) ::glValidateProgram }, + { "glVertexAttrib1f", (QFunctionPointer) ::glVertexAttrib1f }, + { "glVertexAttrib1fv", (QFunctionPointer) ::glVertexAttrib1fv }, + { "glVertexAttrib2f", (QFunctionPointer) ::glVertexAttrib2f }, + { "glVertexAttrib2fv", (QFunctionPointer) ::glVertexAttrib2fv }, + { "glVertexAttrib3f", (QFunctionPointer) ::glVertexAttrib3f }, + { "glVertexAttrib3fv", (QFunctionPointer) ::glVertexAttrib3fv }, + { "glVertexAttrib4f", (QFunctionPointer) ::glVertexAttrib4f }, + { "glVertexAttrib4fv", (QFunctionPointer) ::glVertexAttrib4fv }, + { "glVertexAttribPointer", (QFunctionPointer) ::glVertexAttribPointer }, + + { "glClearDepthf", (QFunctionPointer) ::glClearDepthf }, + { "glDepthRangef", (QFunctionPointer) ::glDepthRangef }, +#endif // QT_OPENGL_ES_2 + +#ifdef QT_OPENGL_ES_3 + { "glBeginQuery", (QFunctionPointer) ::glBeginQuery }, + { "glBeginTransformFeedback", (QFunctionPointer) ::glBeginTransformFeedback }, + { "glBindBufferBase", (QFunctionPointer) ::glBindBufferBase }, + { "glBindBufferRange", (QFunctionPointer) ::glBindBufferRange }, + { "glBindSampler", (QFunctionPointer) ::glBindSampler }, + { "glBindTransformFeedback", (QFunctionPointer) ::glBindTransformFeedback }, + { "glBindVertexArray", (QFunctionPointer) ::glBindVertexArray }, + { "glBlitFramebuffer", (QFunctionPointer) ::glBlitFramebuffer }, + { "glClearBufferfi", (QFunctionPointer) ::glClearBufferfi }, + { "glClearBufferfv", (QFunctionPointer) ::glClearBufferfv }, + { "glClearBufferiv", (QFunctionPointer) ::glClearBufferiv }, + { "glClearBufferuiv", (QFunctionPointer) ::glClearBufferuiv }, + { "glClientWaitSync", (QFunctionPointer) ::glClientWaitSync }, + { "glCompressedTexImage3D", (QFunctionPointer) ::glCompressedTexImage3D }, + { "glCompressedTexSubImage3D", (QFunctionPointer) ::glCompressedTexSubImage3D }, + { "glCopyBufferSubData", (QFunctionPointer) ::glCopyBufferSubData }, + { "glCopyTexSubImage3D", (QFunctionPointer) ::glCopyTexSubImage3D }, + { "glDeleteQueries", (QFunctionPointer) ::glDeleteQueries }, + { "glDeleteSamplers", (QFunctionPointer) ::glDeleteSamplers }, + { "glDeleteSync", (QFunctionPointer) ::glDeleteSync }, + { "glDeleteTransformFeedbacks", (QFunctionPointer) ::glDeleteTransformFeedbacks }, + { "glDeleteVertexArrays", (QFunctionPointer) ::glDeleteVertexArrays }, + { "glDrawArraysInstanced", (QFunctionPointer) ::glDrawArraysInstanced }, + { "glDrawBuffers", (QFunctionPointer) ::glDrawBuffers }, + { "glDrawElementsInstanced", (QFunctionPointer) ::glDrawElementsInstanced }, + { "glDrawRangeElements", (QFunctionPointer) ::glDrawRangeElements }, + { "glEndQuery", (QFunctionPointer) ::glEndQuery }, + { "glEndTransformFeedback", (QFunctionPointer) ::glEndTransformFeedback }, + { "glFenceSync", (QFunctionPointer) ::glFenceSync }, + { "glFlushMappedBufferRange", (QFunctionPointer) ::glFlushMappedBufferRange }, + { "glFramebufferTextureLayer", (QFunctionPointer) ::glFramebufferTextureLayer }, + { "glGenQueries", (QFunctionPointer) ::glGenQueries }, + { "glGenSamplers", (QFunctionPointer) ::glGenSamplers }, + { "glGenTransformFeedbacks", (QFunctionPointer) ::glGenTransformFeedbacks }, + { "glGenVertexArrays", (QFunctionPointer) ::glGenVertexArrays }, + { "glGetActiveUniformBlockName", (QFunctionPointer) ::glGetActiveUniformBlockName }, + { "glGetActiveUniformBlockiv", (QFunctionPointer) ::glGetActiveUniformBlockiv }, + { "glGetActiveUniformsiv", (QFunctionPointer) ::glGetActiveUniformsiv }, + { "glGetBufferParameteri64v", (QFunctionPointer) ::glGetBufferParameteri64v }, + { "glGetBufferPointerv", (QFunctionPointer) ::glGetBufferPointerv }, + { "glGetFragDataLocation", (QFunctionPointer) ::glGetFragDataLocation }, + { "glGetInteger64i_v", (QFunctionPointer) ::glGetInteger64i_v }, + { "glGetInteger64v", (QFunctionPointer) ::glGetInteger64v }, + { "glGetIntegeri_v", (QFunctionPointer) ::glGetIntegeri_v }, + { "glGetInternalformativ", (QFunctionPointer) ::glGetInternalformativ }, + { "glGetProgramBinary", (QFunctionPointer) ::glGetProgramBinary }, + { "glGetQueryObjectuiv", (QFunctionPointer) ::glGetQueryObjectuiv }, + { "glGetQueryiv", (QFunctionPointer) ::glGetQueryiv }, + { "glGetSamplerParameterfv", (QFunctionPointer) ::glGetSamplerParameterfv }, + { "glGetSamplerParameteriv", (QFunctionPointer) ::glGetSamplerParameteriv }, + { "glGetStringi", (QFunctionPointer) ::glGetStringi }, + { "glGetSynciv", (QFunctionPointer) ::glGetSynciv }, + { "glGetTransformFeedbackVarying", (QFunctionPointer) ::glGetTransformFeedbackVarying }, + { "glGetUniformBlockIndex", (QFunctionPointer) ::glGetUniformBlockIndex }, + { "glGetUniformIndices", (QFunctionPointer) ::glGetUniformIndices }, + { "glGetUniformuiv", (QFunctionPointer) ::glGetUniformuiv }, + { "glGetVertexAttribIiv", (QFunctionPointer) ::glGetVertexAttribIiv }, + { "glGetVertexAttribIuiv", (QFunctionPointer) ::glGetVertexAttribIuiv }, + { "glInvalidateFramebuffer", (QFunctionPointer) ::glInvalidateFramebuffer }, + { "glInvalidateSubFramebuffer", (QFunctionPointer) ::glInvalidateSubFramebuffer }, + { "glIsQuery", (QFunctionPointer) ::glIsQuery }, + { "glIsSampler", (QFunctionPointer) ::glIsSampler }, + { "glIsSync", (QFunctionPointer) ::glIsSync }, + { "glIsTransformFeedback", (QFunctionPointer) ::glIsTransformFeedback }, + { "glIsVertexArray", (QFunctionPointer) ::glIsVertexArray }, + { "glMapBufferRange", (QFunctionPointer) ::glMapBufferRange }, + { "glPauseTransformFeedback", (QFunctionPointer) ::glPauseTransformFeedback }, + { "glProgramBinary", (QFunctionPointer) ::glProgramBinary }, + { "glProgramParameteri", (QFunctionPointer) ::glProgramParameteri }, + { "glReadBuffer", (QFunctionPointer) ::glReadBuffer }, + { "glRenderbufferStorageMultisample", (QFunctionPointer) ::glRenderbufferStorageMultisample }, + { "glResumeTransformFeedback", (QFunctionPointer) ::glResumeTransformFeedback }, + { "glSamplerParameterf", (QFunctionPointer) ::glSamplerParameterf }, + { "glSamplerParameterfv", (QFunctionPointer) ::glSamplerParameterfv }, + { "glSamplerParameteri", (QFunctionPointer) ::glSamplerParameteri }, + { "glSamplerParameteriv", (QFunctionPointer) ::glSamplerParameteriv }, + { "glTexImage3D", (QFunctionPointer) ::glTexImage3D }, + { "glTexStorage2D", (QFunctionPointer) ::glTexStorage2D }, + { "glTexStorage3D", (QFunctionPointer) ::glTexStorage3D }, + { "glTexSubImage3D", (QFunctionPointer) ::glTexSubImage3D }, + { "glTransformFeedbackVaryings", (QFunctionPointer) ::glTransformFeedbackVaryings }, + { "glUniform1ui", (QFunctionPointer) ::glUniform1ui }, + { "glUniform1uiv", (QFunctionPointer) ::glUniform1uiv }, + { "glUniform2ui", (QFunctionPointer) ::glUniform2ui }, + { "glUniform2uiv", (QFunctionPointer) ::glUniform2uiv }, + { "glUniform3ui", (QFunctionPointer) ::glUniform3ui }, + { "glUniform3uiv", (QFunctionPointer) ::glUniform3uiv }, + { "glUniform4ui", (QFunctionPointer) ::glUniform4ui }, + { "glUniform4uiv", (QFunctionPointer) ::glUniform4uiv }, + { "glUniformBlockBinding", (QFunctionPointer) ::glUniformBlockBinding }, + { "glUniformMatrix2x3fv", (QFunctionPointer) ::glUniformMatrix2x3fv }, + { "glUniformMatrix2x4fv", (QFunctionPointer) ::glUniformMatrix2x4fv }, + { "glUniformMatrix3x2fv", (QFunctionPointer) ::glUniformMatrix3x2fv }, + { "glUniformMatrix3x4fv", (QFunctionPointer) ::glUniformMatrix3x4fv }, + { "glUniformMatrix4x2fv", (QFunctionPointer) ::glUniformMatrix4x2fv }, + { "glUniformMatrix4x3fv", (QFunctionPointer) ::glUniformMatrix4x3fv }, + { "glUnmapBuffer", (QFunctionPointer) ::glUnmapBuffer }, + { "glVertexAttribDivisor", (QFunctionPointer) ::glVertexAttribDivisor }, + { "glVertexAttribI4i", (QFunctionPointer) ::glVertexAttribI4i }, + { "glVertexAttribI4iv", (QFunctionPointer) ::glVertexAttribI4iv }, + { "glVertexAttribI4ui", (QFunctionPointer) ::glVertexAttribI4ui }, + { "glVertexAttribI4uiv", (QFunctionPointer) ::glVertexAttribI4uiv }, + { "glVertexAttribIPointer", (QFunctionPointer) ::glVertexAttribIPointer }, + { "glWaitSync", (QFunctionPointer) ::glWaitSync }, +#endif // QT_OPENGL_ES_3 + +#ifdef QT_OPENGL_ES_3_1 + { "glActiveShaderProgram", (QFunctionPointer) ::glActiveShaderProgram }, + { "glBindImageTexture", (QFunctionPointer) ::glBindImageTexture }, + { "glBindProgramPipeline", (QFunctionPointer) ::glBindProgramPipeline }, + { "glBindVertexBuffer", (QFunctionPointer) ::glBindVertexBuffer }, + { "glCreateShaderProgramv", (QFunctionPointer) ::glCreateShaderProgramv }, + { "glDeleteProgramPipelines", (QFunctionPointer) ::glDeleteProgramPipelines }, + { "glDispatchCompute", (QFunctionPointer) ::glDispatchCompute }, + { "glDispatchComputeIndirect", (QFunctionPointer) ::glDispatchComputeIndirect }, + { "glDrawArraysIndirect", (QFunctionPointer) ::glDrawArraysIndirect }, + { "glDrawElementsIndirect", (QFunctionPointer) ::glDrawElementsIndirect }, + { "glFramebufferParameteri", (QFunctionPointer) ::glFramebufferParameteri }, + { "glGenProgramPipelines", (QFunctionPointer) ::glGenProgramPipelines }, + { "glGetBooleani_v", (QFunctionPointer) ::glGetBooleani_v }, + { "glGetFramebufferParameteriv", (QFunctionPointer) ::glGetFramebufferParameteriv }, + { "glGetMultisamplefv", (QFunctionPointer) ::glGetMultisamplefv }, + { "glGetProgramInterfaceiv", (QFunctionPointer) ::glGetProgramInterfaceiv }, + { "glGetProgramPipelineInfoLog", (QFunctionPointer) ::glGetProgramPipelineInfoLog }, + { "glGetProgramPipelineiv", (QFunctionPointer) ::glGetProgramPipelineiv }, + { "glGetProgramResourceIndex", (QFunctionPointer) ::glGetProgramResourceIndex }, + { "glGetProgramResourceLocation", (QFunctionPointer) ::glGetProgramResourceLocation }, + { "glGetProgramResourceName", (QFunctionPointer) ::glGetProgramResourceName }, + { "glGetProgramResourceiv", (QFunctionPointer) ::glGetProgramResourceiv }, + { "glGetTexLevelParameterfv", (QFunctionPointer) ::glGetTexLevelParameterfv }, + { "glGetTexLevelParameteriv", (QFunctionPointer) ::glGetTexLevelParameteriv }, + { "glIsProgramPipeline", (QFunctionPointer) ::glIsProgramPipeline }, + { "glMemoryBarrier", (QFunctionPointer) ::glMemoryBarrier }, + { "glMemoryBarrierByRegion", (QFunctionPointer) ::glMemoryBarrierByRegion }, + { "glProgramUniform1f", (QFunctionPointer) ::glProgramUniform1f }, + { "glProgramUniform1fv", (QFunctionPointer) ::glProgramUniform1fv }, + { "glProgramUniform1i", (QFunctionPointer) ::glProgramUniform1i }, + { "glProgramUniform1iv", (QFunctionPointer) ::glProgramUniform1iv }, + { "glProgramUniform1ui", (QFunctionPointer) ::glProgramUniform1ui }, + { "glProgramUniform1uiv", (QFunctionPointer) ::glProgramUniform1uiv }, + { "glProgramUniform2f", (QFunctionPointer) ::glProgramUniform2f }, + { "glProgramUniform2fv", (QFunctionPointer) ::glProgramUniform2fv }, + { "glProgramUniform2i", (QFunctionPointer) ::glProgramUniform2i }, + { "glProgramUniform2iv", (QFunctionPointer) ::glProgramUniform2iv }, + { "glProgramUniform2ui", (QFunctionPointer) ::glProgramUniform2ui }, + { "glProgramUniform2uiv", (QFunctionPointer) ::glProgramUniform2uiv }, + { "glProgramUniform3f", (QFunctionPointer) ::glProgramUniform3f }, + { "glProgramUniform3fv", (QFunctionPointer) ::glProgramUniform3fv }, + { "glProgramUniform3i", (QFunctionPointer) ::glProgramUniform3i }, + { "glProgramUniform3iv", (QFunctionPointer) ::glProgramUniform3iv }, + { "glProgramUniform3ui", (QFunctionPointer) ::glProgramUniform3ui }, + { "glProgramUniform3uiv", (QFunctionPointer) ::glProgramUniform3uiv }, + { "glProgramUniform4f", (QFunctionPointer) ::glProgramUniform4f }, + { "glProgramUniform4fv", (QFunctionPointer) ::glProgramUniform4fv }, + { "glProgramUniform4i", (QFunctionPointer) ::glProgramUniform4i }, + { "glProgramUniform4iv", (QFunctionPointer) ::glProgramUniform4iv }, + { "glProgramUniform4ui", (QFunctionPointer) ::glProgramUniform4ui }, + { "glProgramUniform4uiv", (QFunctionPointer) ::glProgramUniform4uiv }, + { "glProgramUniformMatrix2fv", (QFunctionPointer) ::glProgramUniformMatrix2fv }, + { "glProgramUniformMatrix2x3fv", (QFunctionPointer) ::glProgramUniformMatrix2x3fv }, + { "glProgramUniformMatrix2x4fv", (QFunctionPointer) ::glProgramUniformMatrix2x4fv }, + { "glProgramUniformMatrix3fv", (QFunctionPointer) ::glProgramUniformMatrix3fv }, + { "glProgramUniformMatrix3x2fv", (QFunctionPointer) ::glProgramUniformMatrix3x2fv }, + { "glProgramUniformMatrix3x4fv", (QFunctionPointer) ::glProgramUniformMatrix3x4fv }, + { "glProgramUniformMatrix4fv", (QFunctionPointer) ::glProgramUniformMatrix4fv }, + { "glProgramUniformMatrix4x2fv", (QFunctionPointer) ::glProgramUniformMatrix4x2fv }, + { "glProgramUniformMatrix4x3fv", (QFunctionPointer) ::glProgramUniformMatrix4x3fv }, + { "glSampleMaski", (QFunctionPointer) ::glSampleMaski }, + { "glTexStorage2DMultisample", (QFunctionPointer) ::glTexStorage2DMultisample }, + { "glUseProgramStages", (QFunctionPointer) ::glUseProgramStages }, + { "glValidateProgramPipeline", (QFunctionPointer) ::glValidateProgramPipeline }, + { "glVertexAttribBinding", (QFunctionPointer) ::glVertexAttribBinding }, + { "glVertexAttribFormat", (QFunctionPointer) ::glVertexAttribFormat }, + { "glVertexAttribIFormat", (QFunctionPointer) ::glVertexAttribIFormat }, + { "glVertexBindingDivisor", (QFunctionPointer) ::glVertexBindingDivisor }, +#endif // QT_OPENGL_ES_3_1 + }; + + for (size_t i = 0; i < sizeof(standardFuncs) / sizeof(StdFunc); ++i) { + if (!qstrcmp(procName, standardFuncs[i].name)) { + proc = standardFuncs[i].func; + break; + } + } + } #endif + return proc; } diff --git a/src/platformsupport/fbconvenience/qfbcursor.cpp b/src/platformsupport/fbconvenience/qfbcursor.cpp index 004c586de3..7daf3f4d0c 100644 --- a/src/platformsupport/fbconvenience/qfbcursor.cpp +++ b/src/platformsupport/fbconvenience/qfbcursor.cpp @@ -60,8 +60,8 @@ QFbCursor::QFbCursor(QFbScreen *screen) mScreen(screen), mDirty(false), mOnScreen(false), - mGraphic(0), - mDeviceListener(0) + mCursorImage(nullptr), + mDeviceListener(nullptr) { QByteArray hideCursorVal = qgetenv("QT_QPA_FB_HIDECURSOR"); if (!hideCursorVal.isEmpty()) @@ -69,7 +69,7 @@ QFbCursor::QFbCursor(QFbScreen *screen) if (!mVisible) return; - mGraphic = new QPlatformCursorImage(0, 0, 0, 0, 0, 0); + mCursorImage = new QPlatformCursorImage(0, 0, 0, 0, 0, 0); setCursor(Qt::ArrowCursor); mDeviceListener = new QFbCursorDeviceListener(this); @@ -85,8 +85,8 @@ QFbCursor::~QFbCursor() QRect QFbCursor::getCurrentRect() { - QRect rect = mGraphic->image()->rect().translated(-mGraphic->hotspot().x(), - -mGraphic->hotspot().y()); + QRect rect = mCursorImage->image()->rect().translated(-mCursorImage->hotspot().x(), + -mCursorImage->hotspot().y()); rect.translate(m_pos); QPoint mScreenOffset = mScreen->geometry().topLeft(); rect.translate(-mScreenOffset); // global to local translation @@ -133,7 +133,7 @@ QRect QFbCursor::drawCursor(QPainter & painter) return QRect(); mPrevRect = mCurrentRect; - painter.drawImage(mPrevRect, *mGraphic->image()); + painter.drawImage(mPrevRect, *mCursorImage->image()); mOnScreen = true; return mPrevRect; } @@ -149,17 +149,17 @@ QRect QFbCursor::dirtyRect() void QFbCursor::setCursor(Qt::CursorShape shape) { - mGraphic->set(shape); + mCursorImage->set(shape); } void QFbCursor::setCursor(const QImage &image, int hotx, int hoty) { - mGraphic->set(image, hotx, hoty); + mCursorImage->set(image, hotx, hoty); } void QFbCursor::setCursor(const uchar *data, const uchar *mask, int width, int height, int hotX, int hotY) { - mGraphic->set(data, mask, width, height, hotX, hotY); + mCursorImage->set(data, mask, width, height, hotX, hotY); } #ifndef QT_NO_CURSOR diff --git a/src/platformsupport/fbconvenience/qfbcursor_p.h b/src/platformsupport/fbconvenience/qfbcursor_p.h index f08babd45b..beda10a5f3 100644 --- a/src/platformsupport/fbconvenience/qfbcursor_p.h +++ b/src/platformsupport/fbconvenience/qfbcursor_p.h @@ -87,11 +87,11 @@ public: virtual QRect drawCursor(QPainter &painter); // input methods - void pointerEvent(const QMouseEvent &event) Q_DECL_OVERRIDE; - QPoint pos() const Q_DECL_OVERRIDE; - void setPos(const QPoint &pos) Q_DECL_OVERRIDE; + void pointerEvent(const QMouseEvent &event) override; + QPoint pos() const override; + void setPos(const QPoint &pos) override; #ifndef QT_NO_CURSOR - void changeCursor(QCursor *widgetCursor, QWindow *window) Q_DECL_OVERRIDE; + void changeCursor(QCursor *widgetCursor, QWindow *window) override; #endif virtual void setDirty(); @@ -113,7 +113,7 @@ private: QRect mPrevRect; // last place the cursor was drawn bool mDirty; bool mOnScreen; - QPlatformCursorImage *mGraphic; + QPlatformCursorImage *mCursorImage; QFbCursorDeviceListener *mDeviceListener; QPoint m_pos; }; @@ -121,4 +121,3 @@ private: QT_END_NAMESPACE #endif // QFBCURSOR_P_H - diff --git a/src/platformsupport/fbconvenience/qfbscreen.cpp b/src/platformsupport/fbconvenience/qfbscreen.cpp index 216f2722a4..2b4498157c 100644 --- a/src/platformsupport/fbconvenience/qfbscreen.cpp +++ b/src/platformsupport/fbconvenience/qfbscreen.cpp @@ -51,19 +51,23 @@ QT_BEGIN_NAMESPACE -QFbScreen::QFbScreen() : mUpdatePending(false), mCursor(0), mGeometry(), mDepth(16), mFormat(QImage::Format_RGB16), mScreenImage(0), mCompositePainter(0), mIsUpToDate(false) +QFbScreen::QFbScreen() + : mUpdatePending(false), + mCursor(0), + mDepth(16), + mFormat(QImage::Format_RGB16), + mPainter(nullptr) { } QFbScreen::~QFbScreen() { - delete mCompositePainter; - delete mScreenImage; + delete mPainter; } void QFbScreen::initializeCompositor() { - mScreenImage = new QImage(mGeometry.size(), mFormat); + mScreenImage = QImage(mGeometry.size(), mFormat); scheduleUpdate(); } @@ -93,7 +97,6 @@ void QFbScreen::addWindow(QFbWindow *window) } } } - invalidateRectCache(); setDirty(window->geometry()); QWindow *w = topWindow(); QWindowSystemInterface::handleWindowActivated(w); @@ -103,7 +106,6 @@ void QFbScreen::addWindow(QFbWindow *window) void QFbScreen::removeWindow(QFbWindow *window) { mWindowStack.removeOne(window); - invalidateRectCache(); setDirty(window->geometry()); QWindow *w = topWindow(); QWindowSystemInterface::handleWindowActivated(w); @@ -116,7 +118,6 @@ void QFbScreen::raise(QFbWindow *window) if (index <= 0) return; mWindowStack.move(index, 0); - invalidateRectCache(); setDirty(window->geometry()); QWindow *w = topWindow(); QWindowSystemInterface::handleWindowActivated(w); @@ -129,7 +130,6 @@ void QFbScreen::lower(QFbWindow *window) if (index == -1 || index == (mWindowStack.size() - 1)) return; mWindowStack.move(index, mWindowStack.size() - 1); - invalidateRectCache(); setDirty(window->geometry()); QWindow *w = topWindow(); QWindowSystemInterface::handleWindowActivated(w); @@ -142,7 +142,7 @@ QWindow *QFbScreen::topWindow() const if (fbw->window()->type() == Qt::Window || fbw->window()->type() == Qt::Dialog) return fbw->window(); } - return 0; + return nullptr; } QWindow *QFbScreen::topLevelAt(const QPoint & p) const @@ -151,14 +151,19 @@ QWindow *QFbScreen::topLevelAt(const QPoint & p) const if (fbw->geometry().contains(p, false) && fbw->window()->isVisible()) return fbw->window(); } - return 0; + return nullptr; +} + +int QFbScreen::windowCount() const +{ + return mWindowStack.count(); } void QFbScreen::setDirty(const QRect &rect) { - QRect intersection = rect.intersected(mGeometry); - QPoint screenOffset = mGeometry.topLeft(); - mRepaintRegion += intersection.translated(-screenOffset); // global to local translation + const QRect intersection = rect.intersected(mGeometry); + const QPoint screenOffset = mGeometry.topLeft(); + mRepaintRegion += intersection.translated(-screenOffset); // global to local translation scheduleUpdate(); } @@ -177,141 +182,81 @@ void QFbScreen::setPhysicalSize(const QSize &size) void QFbScreen::setGeometry(const QRect &rect) { - delete mCompositePainter; - mCompositePainter = 0; - delete mScreenImage; + delete mPainter; + mPainter = nullptr; mGeometry = rect; - mScreenImage = new QImage(mGeometry.size(), mFormat); - invalidateRectCache(); + mScreenImage = QImage(mGeometry.size(), mFormat); QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(), availableGeometry()); resizeMaximizedWindows(); } -void QFbScreen::generateRects() +bool QFbScreen::initialize() { - mCachedRects.clear(); - QPoint screenOffset = mGeometry.topLeft(); - QRegion remainingScreen(mGeometry.translated(-screenOffset)); // global to local translation - - for (int i = 0; i < mWindowStack.length(); i++) { - if (remainingScreen.isEmpty()) - break; -#if 0 - if (!mWindowStack[i]->isVisible()) - continue; - if (mWindowStack[i]->isMinimized()) - continue; - - if (!mWindowStack[i]->testAttribute(Qt::WA_TranslucentBackground)) { - QRect localGeometry = mWindowStack.at(i)->geometry().translated(-screenOffset); // global to local translation - remainingScreen -= localGeometry; - QRegion windowRegion(localGeometry); - windowRegion -= remainingScreen; - for (const QRect &rect : windowRegion) - mCachedRects += QPair<QRect, int>(rect, i); - } -#endif - } - mCachedRects.reserve(mCachedRects.count() + remainingScreen.rectCount()); - for (const QRect &rect : remainingScreen) - mCachedRects += QPair<QRect, int>(rect, -1); - mIsUpToDate = true; + return true; } QRegion QFbScreen::doRedraw() { - QPoint screenOffset = mGeometry.topLeft(); + const QPoint screenOffset = mGeometry.topLeft(); QRegion touchedRegion; if (mCursor && mCursor->isDirty() && mCursor->isOnScreen()) { - QRect lastCursor = mCursor->dirtyRect(); + const QRect lastCursor = mCursor->dirtyRect(); mRepaintRegion += lastCursor; } - if (mRepaintRegion.isEmpty() && (!mCursor || !mCursor->isDirty())) { + if (mRepaintRegion.isEmpty() && (!mCursor || !mCursor->isDirty())) return touchedRegion; - } - QVector<QRect> rects = mRepaintRegion.rects(); - - if (!mIsUpToDate) - generateRects(); - - if (!mCompositePainter) - mCompositePainter = new QPainter(mScreenImage); + if (!mPainter) + mPainter = new QPainter(&mScreenImage); + const QVector<QRect> rects = mRepaintRegion.rects(); + const QRect screenRect = mGeometry.translated(-screenOffset); for (int rectIndex = 0; rectIndex < mRepaintRegion.rectCount(); rectIndex++) { - QRegion rectRegion = rects[rectIndex]; + const QRect rect = rects[rectIndex].intersected(screenRect); + if (rect.isEmpty()) + continue; - for (int i = 0; i < mCachedRects.length(); i++) { - QRect screenSubRect = mCachedRects[i].first; - int layer = mCachedRects[i].second; - QRegion intersect = rectRegion.intersected(screenSubRect); + mPainter->setCompositionMode(QPainter::CompositionMode_Source); + mPainter->fillRect(rect, mScreenImage.hasAlphaChannel() ? Qt::transparent : Qt::black); - if (intersect.isEmpty()) + for (int layerIndex = mWindowStack.size() - 1; layerIndex != -1; layerIndex--) { + if (!mWindowStack[layerIndex]->window()->isVisible()) continue; - rectRegion -= intersect; - - // we only expect one rectangle, but defensive coding... - for (const QRect &rect : intersect) { - bool firstLayer = true; - if (layer == -1) { - mCompositePainter->setCompositionMode(QPainter::CompositionMode_Source); - mCompositePainter->fillRect(rect, mScreenImage->hasAlphaChannel() ? Qt::transparent : Qt::black); - firstLayer = false; - layer = mWindowStack.size() - 1; - } - - for (int layerIndex = layer; layerIndex != -1; layerIndex--) { - if (!mWindowStack[layerIndex]->window()->isVisible()) - continue; - // if (mWindowStack[layerIndex]->isMinimized()) - // continue; - - QRect windowRect = mWindowStack[layerIndex]->geometry().translated(-screenOffset); - QRect windowIntersect = rect.translated(-windowRect.left(), - -windowRect.top()); - - - QFbBackingStore *backingStore = mWindowStack[layerIndex]->backingStore(); - - if (backingStore) { - backingStore->lock(); - mCompositePainter->drawImage(rect, backingStore->image(), windowIntersect); - backingStore->unlock(); - } - if (firstLayer) { - firstLayer = false; - } - } + const QRect windowRect = mWindowStack[layerIndex]->geometry().translated(-screenOffset); + const QRect windowIntersect = rect.translated(-windowRect.left(), -windowRect.top()); + QFbBackingStore *backingStore = mWindowStack[layerIndex]->backingStore(); + if (backingStore) { + backingStore->lock(); + mPainter->drawImage(rect, backingStore->image(), windowIntersect); + backingStore->unlock(); } } } - QRect cursorRect; if (mCursor && (mCursor->isDirty() || mRepaintRegion.intersects(mCursor->lastPainted()))) { - mCompositePainter->setCompositionMode(QPainter::CompositionMode_SourceOver); - cursorRect = mCursor->drawCursor(*mCompositePainter); - touchedRegion += cursorRect; + mPainter->setCompositionMode(QPainter::CompositionMode_SourceOver); + touchedRegion += mCursor->drawCursor(*mPainter); } touchedRegion += mRepaintRegion; mRepaintRegion = QRegion(); - - -// qDebug() << "QFbScreen::doRedraw" << mWindowStack.size() << mScreenImage->size() << touchedRegion; - return touchedRegion; } QFbWindow *QFbScreen::windowForId(WId wid) const { - for (int i = 0; i < mWindowStack.count(); ++i) + for (int i = 0; i < mWindowStack.count(); ++i) { if (mWindowStack[i]->winId() == wid) return mWindowStack[i]; + } + return nullptr; +} +QFbScreen::Flags QFbScreen::flags() const +{ return 0; } QT_END_NAMESPACE - diff --git a/src/platformsupport/fbconvenience/qfbscreen_p.h b/src/platformsupport/fbconvenience/qfbscreen_p.h index e9b570aa1c..1c27a941cc 100644 --- a/src/platformsupport/fbconvenience/qfbscreen_p.h +++ b/src/platformsupport/fbconvenience/qfbscreen_p.h @@ -66,10 +66,18 @@ class QFbBackingStore; class QFbScreen : public QObject, public QPlatformScreen { Q_OBJECT + public: + enum Flag { + DontForceFirstWindowToFullScreen = 0x01 + }; + Q_DECLARE_FLAGS(Flags, Flag) + QFbScreen(); ~QFbScreen(); + virtual bool initialize(); + QRect geometry() const Q_DECL_OVERRIDE { return mGeometry; } int depth() const Q_DECL_OVERRIDE { return mDepth; } QImage::Format format() const Q_DECL_OVERRIDE { return mFormat; } @@ -85,6 +93,8 @@ public: virtual void raise(QFbWindow *window); virtual void lower(QFbWindow *window); virtual void topWindowChanged(QWindow *) {} + virtual int windowCount() const; + virtual Flags flags() const; void addPendingBackingStore(QFbBackingStore *bs) { mPendingBackingStores << bs; } @@ -112,20 +122,17 @@ protected: int mDepth; QImage::Format mFormat; QSizeF mPhysicalSize; - QImage *mScreenImage; + QImage mScreenImage; private: - void invalidateRectCache() { mIsUpToDate = false; } - void generateRects(); - - QPainter *mCompositePainter; - QVector<QPair<QRect, int> > mCachedRects; + QPainter *mPainter; QList<QFbBackingStore*> mPendingBackingStores; friend class QFbWindow; - bool mIsUpToDate; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QFbScreen::Flags) + QT_END_NAMESPACE #endif // QFBSCREEN_P_H diff --git a/src/platformsupport/fbconvenience/qfbwindow.cpp b/src/platformsupport/fbconvenience/qfbwindow.cpp index 2d5570fe5d..7e016f2f49 100644 --- a/src/platformsupport/fbconvenience/qfbwindow.cpp +++ b/src/platformsupport/fbconvenience/qfbwindow.cpp @@ -66,41 +66,55 @@ void QFbWindow::setGeometry(const QRect &rect) // store previous geometry for screen update mOldGeometry = geometry(); - platformScreen()->invalidateRectCache(); QWindowSystemInterface::handleGeometryChange(window(), rect); QPlatformWindow::setGeometry(rect); + + if (mOldGeometry != rect) + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size())); } void QFbWindow::setVisible(bool visible) { + QRect newGeom; + QFbScreen *fbScreen = platformScreen(); if (visible) { - if (mWindowState & Qt::WindowFullScreen) - setGeometry(platformScreen()->geometry()); + bool convOk = false; + static bool envDisableForceFullScreen = qEnvironmentVariableIntValue("QT_QPA_FB_FORCE_FULLSCREEN", &convOk) == 0 && convOk; + const bool platformDisableForceFullScreen = fbScreen->flags().testFlag(QFbScreen::DontForceFirstWindowToFullScreen); + const bool forceFullScreen = !envDisableForceFullScreen && !platformDisableForceFullScreen && fbScreen->windowCount() == 0; + if (forceFullScreen || (mWindowState & Qt::WindowFullScreen)) + newGeom = platformScreen()->geometry(); else if (mWindowState & Qt::WindowMaximized) - setGeometry(platformScreen()->availableGeometry()); + newGeom = platformScreen()->availableGeometry(); } QPlatformWindow::setVisible(visible); if (visible) - platformScreen()->addWindow(this); + fbScreen->addWindow(this); else - platformScreen()->removeWindow(this); -} + fbScreen->removeWindow(this); + if (!newGeom.isEmpty()) + setGeometry(newGeom); // may or may not generate an expose + + if (newGeom.isEmpty() || newGeom == mOldGeometry) { + // QWindow::isExposed() maps to QWindow::visible() by default so simply + // generating an expose event regardless of this being a show or hide is + // just what is needed here. + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size())); + } +} void QFbWindow::setWindowState(Qt::WindowState state) { QPlatformWindow::setWindowState(state); mWindowState = state; - platformScreen()->invalidateRectCache(); } - void QFbWindow::setWindowFlags(Qt::WindowFlags flags) { mWindowFlags = flags; - platformScreen()->invalidateRectCache(); } Qt::WindowFlags QFbWindow::windowFlags() const @@ -111,29 +125,26 @@ Qt::WindowFlags QFbWindow::windowFlags() const void QFbWindow::raise() { platformScreen()->raise(this); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size())); } void QFbWindow::lower() { platformScreen()->lower(this); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size())); } void QFbWindow::repaint(const QRegion ®ion) { - QRect currentGeometry = geometry(); - - QRect dirtyClient = region.boundingRect(); - QRect dirtyRegion(currentGeometry.left() + dirtyClient.left(), - currentGeometry.top() + dirtyClient.top(), - dirtyClient.width(), - dirtyClient.height()); - QRect mOldGeometryLocal = mOldGeometry; + const QRect currentGeometry = geometry(); + const QRect dirtyClient = region.boundingRect(); + const QRect dirtyRegion = dirtyClient.translated(currentGeometry.topLeft()); + const QRect oldGeometryLocal = mOldGeometry; mOldGeometry = currentGeometry; // If this is a move, redraw the previous location - if (mOldGeometryLocal != currentGeometry) - platformScreen()->setDirty(mOldGeometryLocal); + if (oldGeometryLocal != currentGeometry) + platformScreen()->setDirty(oldGeometryLocal); platformScreen()->setDirty(dirtyRegion); } QT_END_NAMESPACE - diff --git a/src/platformsupport/fontdatabases/basic/qfontengine_ft.cpp b/src/platformsupport/fontdatabases/basic/qfontengine_ft.cpp index de6da88245..03e72546eb 100644 --- a/src/platformsupport/fontdatabases/basic/qfontengine_ft.cpp +++ b/src/platformsupport/fontdatabases/basic/qfontengine_ft.cpp @@ -61,17 +61,19 @@ #include FT_TRUETYPE_TABLES_H #include FT_TYPE1_TABLES_H #include FT_GLYPH_H +#include FT_MODULE_H #if defined(FT_LCD_FILTER_H) #include FT_LCD_FILTER_H +#define QT_USE_FREETYPE_LCDFILTER #endif #if defined(FT_CONFIG_OPTIONS_H) #include FT_CONFIG_OPTIONS_H #endif -#if defined(FT_LCD_FILTER_H) -#define QT_USE_FREETYPE_LCDFILTER +#if defined(FT_FONT_FORMATS_H) +#include FT_FONT_FORMATS_H #endif #ifdef QT_LINUXBASE @@ -151,6 +153,14 @@ QtFreetypeData *qt_getFreetypeData() QtFreetypeData *&freetypeData = theFreetypeData()->localData(); if (!freetypeData) freetypeData = new QtFreetypeData; + if (!freetypeData->library) { + FT_Init_FreeType(&freetypeData->library); +#if defined(FT_FONT_FORMATS_H) + // Freetype defaults to disabling stem-darkening on CFF, we re-enable it. + FT_Bool no_darkening = false; + FT_Property_Set(freetypeData->library, "cff", "no-stem-darkening", &no_darkening); +#endif + } return freetypeData; } #endif @@ -158,8 +168,7 @@ QtFreetypeData *qt_getFreetypeData() FT_Library qt_getFreetype() { QtFreetypeData *freetypeData = qt_getFreetypeData(); - if (!freetypeData->library) - FT_Init_FreeType(&freetypeData->library); + Q_ASSERT(freetypeData->library); return freetypeData->library; } @@ -218,8 +227,6 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id, return 0; QtFreetypeData *freetypeData = qt_getFreetypeData(); - if (!freetypeData->library) - FT_Init_FreeType(&freetypeData->library); QFreetypeFace *freetype = freetypeData->faces.value(face_id, 0); if (freetype) { @@ -687,6 +694,7 @@ QFontEngineFT::QFontEngineFT(const QFontDef &fd) cacheEnabled = env.isEmpty() || env.toInt() == 0; m_subPixelPositionCount = 4; forceAutoHint = false; + stemDarkeningDriver = false; } QFontEngineFT::~QFontEngineFT() @@ -798,6 +806,17 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format, } } } +#if defined(FT_FONT_FORMATS_H) + const char *fmt = FT_Get_Font_Format(face); + if (fmt && qstrncmp(fmt, "CFF", 4) == 0) { + FT_Bool no_stem_darkening = true; + FT_Error err = FT_Property_Get(qt_getFreetype(), "cff", "no-stem-darkening", &no_stem_darkening); + if (err == FT_Err_Ok) + stemDarkeningDriver = !no_stem_darkening; + else + stemDarkeningDriver = false; + } +#endif fontDef.styleName = QString::fromUtf8(face->style_name); @@ -841,6 +860,11 @@ void QFontEngineFT::setDefaultHintStyle(HintStyle style) default_hint_style = style; } +bool QFontEngineFT::expectsGammaCorrectedBlending() const +{ + return stemDarkeningDriver; +} + int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags, bool &hsubpixel, int &vfactor) const { diff --git a/src/platformsupport/fontdatabases/basic/qfontengine_ft_p.h b/src/platformsupport/fontdatabases/basic/qfontengine_ft_p.h index c5f3b0443e..3b751eae3e 100644 --- a/src/platformsupport/fontdatabases/basic/qfontengine_ft_p.h +++ b/src/platformsupport/fontdatabases/basic/qfontengine_ft_p.h @@ -246,6 +246,7 @@ private: QPoint *offset) Q_DECL_OVERRIDE; bool hasInternalCaching() const Q_DECL_OVERRIDE { return cacheEnabled; } void unlockAlphaMapForGlyph() Q_DECL_OVERRIDE; + bool expectsGammaCorrectedBlending() const Q_DECL_OVERRIDE; void removeGlyphFromCache(glyph_t glyph) Q_DECL_OVERRIDE; int glyphMargin(QFontEngine::GlyphFormat /* format */) Q_DECL_OVERRIDE { return 0; } @@ -305,6 +306,7 @@ protected: bool embeddedbitmap; bool cacheEnabled; bool forceAutoHint; + bool stemDarkeningDriver; private: friend class QFontEngineFTRawFont; diff --git a/src/platformsupport/fontdatabases/fontdatabases.pro b/src/platformsupport/fontdatabases/fontdatabases.pro index 9376c3b702..49dead4668 100644 --- a/src/platformsupport/fontdatabases/fontdatabases.pro +++ b/src/platformsupport/fontdatabases/fontdatabases.pro @@ -7,7 +7,7 @@ CONFIG += static internal_module DEFINES += QT_NO_CAST_FROM_ASCII PRECOMPILED_HEADER = ../../corelib/global/qt_pch.h -darwin:!if(watchos:CONFIG(simulator, simulator|device)) { +darwin { include($$PWD/mac/coretext.pri) } else { qtConfig(freetype) { diff --git a/src/platformsupport/fontdatabases/mac/coretext.pri b/src/platformsupport/fontdatabases/mac/coretext.pri index 50dafc3f89..f73e22eb1a 100644 --- a/src/platformsupport/fontdatabases/mac/coretext.pri +++ b/src/platformsupport/fontdatabases/mac/coretext.pri @@ -11,6 +11,21 @@ uikit: \ # On iOS/tvOS/watchOS CoreText and CoreGraphics are stand-alone frameworks LIBS_PRIVATE += -framework CoreText -framework CoreGraphics else: \ - # On Mac OS they are part of the ApplicationServices umbrella framework, - # even in 10.8 where they were also made available stand-alone. - LIBS_PRIVATE += -framework ApplicationServices + # On macOS they are re-exported by the AppKit framework + LIBS_PRIVATE += -framework AppKit + +# CoreText is documented to be available on watchOS, but the headers aren't present +# in the watchOS Simulator SDK like they are supposed to be. Work around the problem +# by adding the device SDK's headers to the search path as a fallback. +# rdar://25314492, rdar://27844864 +watchos:simulator { + simulator_system_frameworks = $$xcodeSDKInfo(Path, $${simulator.sdk})/System/Library/Frameworks + device_system_frameworks = $$xcodeSDKInfo(Path, $${device.sdk})/System/Library/Frameworks + for (arch, QMAKE_APPLE_SIMULATOR_ARCHS) { + QMAKE_CXXFLAGS += \ + -Xarch_$${arch} \ + -F$$simulator_system_frameworks \ + -Xarch_$${arch} \ + -F$$device_system_frameworks + } +} diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index 3d94982f60..2b9e928266 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -708,71 +708,71 @@ static CTFontUIFontType fontTypeFromTheme(QPlatformTheme::Font f) { switch (f) { case QPlatformTheme::SystemFont: - return kCTFontSystemFontType; + return kCTFontUIFontSystem; case QPlatformTheme::MenuFont: case QPlatformTheme::MenuBarFont: case QPlatformTheme::MenuItemFont: - return kCTFontMenuItemFontType; + return kCTFontUIFontMenuItem; case QPlatformTheme::MessageBoxFont: - return kCTFontEmphasizedSystemFontType; + return kCTFontUIFontEmphasizedSystem; case QPlatformTheme::LabelFont: - return kCTFontSystemFontType; + return kCTFontUIFontSystem; case QPlatformTheme::TipLabelFont: return kCTFontToolTipFontType; case QPlatformTheme::StatusBarFont: - return kCTFontSystemFontType; + return kCTFontUIFontSystem; case QPlatformTheme::TitleBarFont: - return kCTFontWindowTitleFontType; + return kCTFontUIFontWindowTitle; case QPlatformTheme::MdiSubWindowTitleFont: case QPlatformTheme::DockWidgetTitleFont: - return kCTFontSystemFontType; + return kCTFontUIFontSystem; case QPlatformTheme::PushButtonFont: - return kCTFontPushButtonFontType; + return kCTFontUIFontPushButton; case QPlatformTheme::CheckBoxFont: case QPlatformTheme::RadioButtonFont: - return kCTFontSystemFontType; + return kCTFontUIFontSystem; case QPlatformTheme::ToolButtonFont: - return kCTFontSmallToolbarFontType; + return kCTFontUIFontSmallToolbar; case QPlatformTheme::ItemViewFont: - return kCTFontSystemFontType; + return kCTFontUIFontSystem; case QPlatformTheme::ListViewFont: - return kCTFontViewsFontType; + return kCTFontUIFontViews; case QPlatformTheme::HeaderViewFont: - return kCTFontSmallSystemFontType; + return kCTFontUIFontSmallSystem; case QPlatformTheme::ListBoxFont: - return kCTFontViewsFontType; + return kCTFontUIFontViews; case QPlatformTheme::ComboMenuItemFont: - return kCTFontSystemFontType; + return kCTFontUIFontSystem; case QPlatformTheme::ComboLineEditFont: - return kCTFontViewsFontType; + return kCTFontUIFontViews; case QPlatformTheme::SmallFont: - return kCTFontSmallSystemFontType; + return kCTFontUIFontSmallSystem; case QPlatformTheme::MiniFont: - return kCTFontMiniSystemFontType; + return kCTFontUIFontMiniSystem; case QPlatformTheme::FixedFont: - return kCTFontUserFixedPitchFontType; + return kCTFontUIFontUserFixedPitch; default: - return kCTFontSystemFontType; + return kCTFontUIFontSystem; } } @@ -848,7 +848,7 @@ QFont *QCoreTextFontDatabase::themeFont(QPlatformTheme::Font f) const QFont QCoreTextFontDatabase::defaultFont() const { if (defaultFontName.isEmpty()) { - QCFType<CTFontRef> font = CTFontCreateUIFontForLanguage(kCTFontSystemFontType, 12.0, NULL); + QCFType<CTFontRef> font = CTFontCreateUIFontForLanguage(kCTFontUIFontSystem, 12.0, NULL); defaultFontName = (QString) QCFString(CTFontCopyFullName(font)); } diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm index 7a06d5f1c9..c8ae342f16 100644 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm +++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm @@ -141,7 +141,7 @@ static void loadAdvancesForGlyphs(CTFontRef ctfont, { Q_UNUSED(flags); QVarLengthArray<CGSize> advances(len); - CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, cgGlyphs.data(), advances.data(), len); + CTFontGetAdvancesForGlyphs(ctfont, kCTFontOrientationHorizontal, cgGlyphs.data(), advances.data(), len); for (int i = 0; i < len; ++i) { if (glyphs->glyphs[i] & 0xff000000) @@ -320,7 +320,7 @@ bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout * return true; QVarLengthArray<CGSize> advances(glyph_pos); - CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, cgGlyphs.data(), advances.data(), glyph_pos); + CTFontGetAdvancesForGlyphs(ctfont, kCTFontOrientationHorizontal, cgGlyphs.data(), advances.data(), glyph_pos); for (int i = 0; i < glyph_pos; ++i) { if (glyphs->glyphs[i] & 0xff000000) @@ -351,7 +351,7 @@ glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph) { glyph_metrics_t ret; CGGlyph g = glyph; - CGRect rect = CTFontGetBoundingRectsForGlyphs(ctfont, kCTFontHorizontalOrientation, &g, 0, 1); + CGRect rect = CTFontGetBoundingRectsForGlyphs(ctfont, kCTFontOrientationHorizontal, &g, 0, 1); if (synthesisFlags & QFontEngine::SynthesizedItalic) { rect.size.width += rect.size.height * SYNTHETIC_ITALIC_SKEW; } @@ -360,7 +360,7 @@ glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph) ret.x = QFixed::fromReal(rect.origin.x); ret.y = -QFixed::fromReal(rect.origin.y) - ret.height; CGSize advances[1]; - CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, &g, advances, 1); + CTFontGetAdvancesForGlyphs(ctfont, kCTFontOrientationHorizontal, &g, advances, 1); ret.xoff = QFixed::fromReal(advances[0].width); ret.yoff = QFixed::fromReal(advances[0].height); @@ -602,6 +602,11 @@ glyph_metrics_t QCoreTextFontEngine::alphaMapBoundingBox(glyph_t glyph, QFixed s return br; } +bool QCoreTextFontEngine::expectsGammaCorrectedBlending() const +{ + // Only works well when font-smoothing is enabled + return (glyphFormat == Format_A32) && !(fontDef.styleStrategy & (QFont::NoAntialias | QFont::NoSubpixelAntialias)); +} QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, bool aa, const QTransform &matrix) { diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h index d9ffbb5697..0074790e43 100644 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h +++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h @@ -110,6 +110,7 @@ public: void doKerning(QGlyphLayout *g, ShaperFlags flags) const Q_DECL_OVERRIDE; bool supportsTransformation(const QTransform &transform) const Q_DECL_OVERRIDE; + bool expectsGammaCorrectedBlending() const Q_DECL_OVERRIDE; QFontEngine *cloneWithSize(qreal pixelSize) const Q_DECL_OVERRIDE; Qt::HANDLE handle() const Q_DECL_OVERRIDE; diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp index c457246354..d3e4daa341 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp @@ -591,12 +591,7 @@ namespace { */ QWindowsFontEngineData::QWindowsFontEngineData() - : clearTypeEnabled(false) - , fontSmoothingGamma(QWindowsFontDatabase::fontSmoothingGamma()) -#if !defined(QT_NO_DIRECTWRITE) - , directWriteFactory(0) - , directWriteGdiInterop(0) -#endif + : fontSmoothingGamma(QWindowsFontDatabase::fontSmoothingGamma()) { // from qapplication_win.cpp UINT result = 0; @@ -1221,8 +1216,6 @@ QWindowsFontEngineDataPtr sharedFontData() } #endif // QT_NO_THREAD -extern Q_GUI_EXPORT bool qt_needs_a8_gamma_correction; - QWindowsFontDatabase::QWindowsFontDatabase() { // Properties accessed by QWin32PrintEngine (Qt Print Support) @@ -1236,7 +1229,6 @@ QWindowsFontDatabase::QWindowsFontDatabase() qCDebug(lcQpaFonts) << __FUNCTION__ << "Clear type: " << data->clearTypeEnabled << "gamma: " << data->fontSmoothingGamma; } - qt_needs_a8_gamma_correction = true; } QWindowsFontDatabase::~QWindowsFontDatabase() diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h index 325f522335..15172c09da 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h @@ -74,12 +74,12 @@ public: uint pow_gamma[256]; - bool clearTypeEnabled; + bool clearTypeEnabled = false; qreal fontSmoothingGamma; - HDC hdc; + HDC hdc = 0; #if !defined(QT_NO_DIRECTWRITE) - IDWriteFactory *directWriteFactory; - IDWriteGdiInterop *directWriteGdiInterop; + IDWriteFactory *directWriteFactory = nullptr; + IDWriteGdiInterop *directWriteGdiInterop = nullptr; #endif }; diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp index 08ebbc3be0..5f55dba9da 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp @@ -239,21 +239,9 @@ QWindowsFontEngine::QWindowsFontEngine(const QString &name, : QFontEngine(Win), m_fontEngineData(fontEngineData), _name(name), - hfont(0), m_logfont(lf), ttf(0), - hasOutline(0), - cmap(0), - cmapSize(0), - lbearing(SHRT_MIN), - rbearing(SHRT_MIN), - x_height(-1), - synthesized_flags(-1), - lineWidth(-1), - widthCache(0), - widthCacheSize(0), - designAdvances(0), - designAdvancesSize(0) + hasOutline(0) { qCDebug(lcQpaFonts) << __FUNCTION__ << name << lf.lfHeight; hfont = CreateFontIndirect(&m_logfont); diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h index 709de7d11d..5119adc0eb 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h @@ -145,29 +145,29 @@ private: const QString _name; QString uniqueFamilyName; - HFONT hfont; + HFONT hfont = 0; const LOGFONT m_logfont; uint ttf : 1; uint hasOutline : 1; uint hasUnreliableOutline : 1; uint cffTable : 1; TEXTMETRIC tm; - const unsigned char *cmap; - int cmapSize; + const unsigned char *cmap = nullptr; + int cmapSize = 0; QByteArray cmapTable; - mutable qreal lbearing; - mutable qreal rbearing; + mutable qreal lbearing = SHRT_MIN; + mutable qreal rbearing = SHRT_MIN; QFixed designToDevice; - int unitsPerEm; - QFixed x_height; + int unitsPerEm = 0; + QFixed x_height = -1; FaceId _faceId; - mutable int synthesized_flags; - mutable QFixed lineWidth; - mutable unsigned char *widthCache; - mutable uint widthCacheSize; - mutable QFixed *designAdvances; - mutable int designAdvancesSize; + mutable int synthesized_flags = -1; + mutable QFixed lineWidth = -1; + mutable unsigned char *widthCache = nullptr; + mutable uint widthCacheSize = 0; + mutable QFixed *designAdvances = nullptr; + mutable int designAdvancesSize = 0; }; class QWindowsMultiFontEngine : public QFontEngineMulti diff --git a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage.cpp b/src/platformsupport/fontdatabases/windows/qwindowsnativeimage.cpp index 7022615511..f8fcff952a 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsnativeimage.cpp @@ -110,9 +110,7 @@ static inline HBITMAP createDIB(HDC hdc, int width, int height, QWindowsNativeImage::QWindowsNativeImage(int width, int height, QImage::Format format) : - m_hdc(createDC()), - m_bitmap(0), - m_null_bitmap(0) + m_hdc(createDC()) { if (width != 0 && height != 0) { uchar *bits; diff --git a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h b/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h index c27c0d1e98..6c47a527d2 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h +++ b/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h @@ -80,8 +80,8 @@ private: const HDC m_hdc; QImage m_image; - HBITMAP m_bitmap; - HBITMAP m_null_bitmap; + HBITMAP m_bitmap = 0; + HBITMAP m_null_bitmap = 0; }; QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/windows/windows.pri b/src/platformsupport/fontdatabases/windows/windows.pri index 4ca0080ad9..0e64084cf1 100644 --- a/src/platformsupport/fontdatabases/windows/windows.pri +++ b/src/platformsupport/fontdatabases/windows/windows.pri @@ -26,3 +26,4 @@ qtConfig(directwrite) { } LIBS += -lole32 -lgdi32 -luser32 -ladvapi32 +mingw: LIBS += -luuid diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboard_defaultmap_p.h b/src/platformsupport/input/evdevkeyboard/qevdevkeyboard_defaultmap_p.h index bc0485232d..17bf0fb797 100644 --- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboard_defaultmap_p.h +++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboard_defaultmap_p.h @@ -52,7 +52,11 @@ // #include "qnamespace.h" +#ifdef Q_OS_FREEBSD +#include <dev/evdev/input.h> +#else #include "linux/input.h" +#endif // no QT_BEGIN_NAMESPACE, since we include it internally... diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp index 0eb6fc0847..5c87cb7c9c 100644 --- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp +++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp @@ -49,7 +49,11 @@ #include <qpa/qwindowsysteminterface.h> #include <private/qcore_unix_p.h> +#ifdef Q_OS_FREEBSD +#include <dev/evdev/input.h> +#else #include <linux/input.h> +#endif QT_BEGIN_NAMESPACE diff --git a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp index d5ea04bee8..9b4bcf1575 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp +++ b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp @@ -53,8 +53,12 @@ #include <errno.h> +#ifdef Q_OS_FREEBSD +#include <dev/evdev/input.h> +#else #include <linux/kd.h> #include <linux/input.h> +#endif #define TEST_BIT(array, bit) (array[bit/8] & (1<<(bit%8))) diff --git a/src/platformsupport/input/evdevtablet/qevdevtablethandler.cpp b/src/platformsupport/input/evdevtablet/qevdevtablethandler.cpp index dc03daedda..86f8a00b13 100644 --- a/src/platformsupport/input/evdevtablet/qevdevtablethandler.cpp +++ b/src/platformsupport/input/evdevtablet/qevdevtablethandler.cpp @@ -45,7 +45,11 @@ #include <QLoggingCategory> #include <QtCore/private/qcore_unix_p.h> #include <qpa/qwindowsysteminterface.h> +#ifdef Q_OS_FREEBSD +#include <dev/evdev/input.h> +#else #include <linux/input.h> +#endif QT_BEGIN_NAMESPACE diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchfilter_p.h b/src/platformsupport/input/evdevtouch/qevdevtouchfilter_p.h new file mode 100644 index 0000000000..ff6085d725 --- /dev/null +++ b/src/platformsupport/input/evdevtouch/qevdevtouchfilter_p.h @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qglobal.h> + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +struct QEvdevTouchFilter +{ + QEvdevTouchFilter(); + + void initialize(float pos, float velocity); + void update(float pos, float velocity, float timeDelta); + + float position() const { return x.x; } + float velocity() const { return x.y; } + +private: + struct vec2 { + vec2(float x = 0.0f, float y = 0.0f) : x(x), y(y) { } + float x, y; + + vec2 operator-(vec2 v) { + return vec2(x - v.x, y - v.y); + } + + vec2 operator+(vec2 v) { + return vec2(x + v.x, y + v.y); + } + }; + + struct mat2 { + float a, b, c, d; + mat2(float a = 1.0f, float b = 0.0f, float c = 0.0f, float d = 1.0f) + : a(a) + , b(b) + , c(c) + , d(d) + { + } + + mat2 transposed() const { + return mat2(a, c, + b, d); + } + + mat2 inverted() const { + float det = 1.0f / (a * d - b * c); + return mat2( d * det, -b * det, + -c * det, a * det); + } + + mat2 operator+(mat2 m) const { + return mat2(a + m.a, b + m.b, + c + m.c, d + m.d); + } + + mat2 operator-(mat2 m) const { + return mat2(a - m.a, b - m.b, + c - m.c, d - m.d); + } + + vec2 operator*(vec2 v) const { + return vec2(a * v.x + b * v.y, + c * v.x + d * v.y); + } + + mat2 operator*(mat2 M) const { + return mat2(a * M.a + b * M.c, + a * M.b + b * M.d, + c * M.a + d * M.c, + c * M.b + d * M.d); + } + }; + + vec2 x; + mat2 A; + mat2 P; + mat2 Q; + mat2 R; + mat2 H; +}; + +inline QEvdevTouchFilter::QEvdevTouchFilter() +{ +} + +inline void QEvdevTouchFilter::initialize(float pos, float velocity) +{ + x = vec2(pos, velocity); + + P = mat2(0.0f, 0.0f, + 0.0f, 0.0f); + + Q = mat2(0.0f, 0.0f, + 0.0f, 0.1f); + R = mat2(0.1f, 0.0f, + 0.0f, 0.1f); +} + +inline void QEvdevTouchFilter::update(float pos, float velocity, float dT) +{ + A.b = dT; + + // Prediction setp + x = A * x; + P = A * P * A.transposed() + Q; + + // Correction step (complete with H) + // mat2 S = H * P * H.transposed() + R; + // mat2 K = P * H.transposed() * S.inverted(); + // vec2 m(pos, velocity); + // vec2 y = m - H * x; + // x = x + K * y; + // P = (mat2() - K * H) * P; + + // Correction step (without H as H is currently set to I, so we can ignore + // it in the calculations...) + mat2 S = P + R; + mat2 K = P * S.inverted(); + vec2 m(pos, velocity); + vec2 y = m - x; + x = x + K * y; + P = (mat2() - K) * P; + +} + +QT_END_NAMESPACE diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp index d53a317fc5..11f7311bb7 100644 --- a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp +++ b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com> ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins module of the Qt Toolkit. @@ -48,7 +49,11 @@ #include <QtCore/private/qcore_unix_p.h> #include <QtGui/private/qhighdpiscaling_p.h> #include <QtGui/private/qguiapplication_p.h> +#ifdef Q_OS_FREEBSD +#include <dev/evdev/input.h> +#else #include <linux/input.h> +#endif #if QT_CONFIG(mtdev) extern "C" { @@ -96,6 +101,7 @@ public: QEvdevTouchScreenHandler *q; int m_lastEventType; QList<QWindowSystemInterface::TouchPoint> m_touchPoints; + QList<QWindowSystemInterface::TouchPoint> m_lastTouchPoints; struct Contact { int trackingId; @@ -114,11 +120,16 @@ public: Contact m_currentData; int m_currentSlot; + double m_timeStamp; + double m_lastTimeStamp; + int findClosestContact(const QHash<int, Contact> &contacts, int x, int y, int *dist); void addTouchPoint(const Contact &contact, Qt::TouchPointStates *combinedStates); void reportPoints(); void loadMultiScreenMappings(); + QRect screenGeometry() const; + int hw_range_x_min; int hw_range_x_max; int hw_range_y_min; @@ -132,19 +143,40 @@ public: QTransform m_rotate; bool m_singleTouch; QString m_screenName; - QPointer<QScreen> m_screen; + mutable QPointer<QScreen> m_screen; + + // Touch filtering and prediction are part of the same thing. The default + // prediction is 0ms, but sensible results can be acheived by setting it + // to, for instance, 16ms. + // For filtering to work well, the QPA plugin should provide a dead-steady + // implementation of QPlatformWindow::requestUpdate(). + bool m_filtered; + int m_prediction; + + // When filtering is enabled, protect the access to current and last + // timeStamp and touchPoints, as these are being read on the gui thread. + QMutex m_mutex; }; QEvdevTouchScreenData::QEvdevTouchScreenData(QEvdevTouchScreenHandler *q_ptr, const QStringList &args) : q(q_ptr), m_lastEventType(-1), m_currentSlot(0), + m_timeStamp(0), m_lastTimeStamp(0), hw_range_x_min(0), hw_range_x_max(0), hw_range_y_min(0), hw_range_y_max(0), hw_pressure_min(0), hw_pressure_max(0), - m_typeB(false), m_singleTouch(false) + m_forceToActiveWindow(false), m_typeB(false), m_singleTouch(false), + m_filtered(false), m_prediction(0) { - m_forceToActiveWindow = args.contains(QLatin1String("force_window")); + for (const QString &arg : args) { + if (arg == QStringLiteral("force_window")) + m_forceToActiveWindow = true; + else if (arg == QStringLiteral("filtered")) + m_filtered = true; + else if (arg.startsWith(QStringLiteral("prediction="))) + m_prediction = arg.mid(11).toInt(); + } } #define LONG_BITS (sizeof(long) << 3) @@ -228,9 +260,14 @@ QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &device, const #endif d->deviceNode = device; - - qCDebug(qLcEvdevTouch, "evdevtouch: %s: Protocol type %c %s (%s)", qPrintable(d->deviceNode), - d->m_typeB ? 'B' : 'A', mtdevStr, d->m_singleTouch ? "single" : "multi"); + qCDebug(qLcEvdevTouch, + "evdevtouch: %s: Protocol type %c %s (%s), filtered=%s", + qPrintable(d->deviceNode), + d->m_typeB ? 'B' : 'A', mtdevStr, + d->m_singleTouch ? "single" : "multi", + d->m_filtered ? "yes" : "no"); + if (d->m_filtered) + qCDebug(qLcEvdevTouch, " - prediction=%d", d->m_prediction); input_absinfo absInfo; memset(&absInfo, 0, sizeof(input_absinfo)); @@ -327,6 +364,11 @@ QEvdevTouchScreenHandler::~QEvdevTouchScreenHandler() unregisterTouchDevice(); } +bool QEvdevTouchScreenHandler::isFiltered() const +{ + return d->m_filtered; +} + QTouchDevice *QEvdevTouchScreenHandler::touchDevice() const { return m_device; @@ -516,6 +558,14 @@ void QEvdevTouchScreenData::processInputEvent(input_event *data) if (!m_contacts.isEmpty() && m_contacts.constBegin().value().trackingId == -1) assignIds(); + if (m_filtered) + m_mutex.lock(); + + // update timestamps + m_lastTimeStamp = m_timeStamp; + m_timeStamp = data->time.tv_sec + data->time.tv_usec / 1000000.0; + + m_lastTouchPoints = m_touchPoints; m_touchPoints.clear(); Qt::TouchPointStates combinedStates; @@ -593,8 +643,12 @@ void QEvdevTouchScreenData::processInputEvent(input_event *data) if (!m_typeB && !m_singleTouch) m_contacts.clear(); + if (!m_touchPoints.isEmpty() && combinedStates != Qt::TouchPointStationary) reportPoints(); + + if (m_filtered) + m_mutex.unlock(); } m_lastEventType = data->type; @@ -653,41 +707,45 @@ void QEvdevTouchScreenData::assignIds() m_contacts = newContacts; } -void QEvdevTouchScreenData::reportPoints() +QRect QEvdevTouchScreenData::screenGeometry() const { - QRect winRect; if (m_forceToActiveWindow) { QWindow *win = QGuiApplication::focusWindow(); - if (!win) - return; - winRect = QHighDpi::toNativePixels(win->geometry(), win); - } else { - // Now it becomes tricky. Traditionally we picked the primaryScreen() - // and were done with it. But then, enter multiple screens, and - // suddenly it was all broken. - // - // For now we only support the display configuration of the KMS/DRM - // backends of eglfs. See QTouchOutputMapping. - // - // The good news it that once winRect refers to the correct screen - // geometry in the full virtual desktop space, there is nothing else - // left to do since qguiapp will handle the rest. - QScreen *screen = QGuiApplication::primaryScreen(); - if (!m_screenName.isEmpty()) { - if (!m_screen) { - const QList<QScreen *> screens = QGuiApplication::screens(); - for (QScreen *s : screens) { - if (s->name() == m_screenName) { - m_screen = s; - break; - } + return win ? QHighDpi::toNativePixels(win->geometry(), win) : QRect(); + } + + // Now it becomes tricky. Traditionally we picked the primaryScreen() + // and were done with it. But then, enter multiple screens, and + // suddenly it was all broken. + // + // For now we only support the display configuration of the KMS/DRM + // backends of eglfs. See QTouchOutputMapping. + // + // The good news it that once winRect refers to the correct screen + // geometry in the full virtual desktop space, there is nothing else + // left to do since qguiapp will handle the rest. + QScreen *screen = QGuiApplication::primaryScreen(); + if (!m_screenName.isEmpty()) { + if (!m_screen) { + const QList<QScreen *> screens = QGuiApplication::screens(); + for (QScreen *s : screens) { + if (s->name() == m_screenName) { + m_screen = s; + break; } } - if (m_screen) - screen = m_screen; } - winRect = QHighDpi::toNativePixels(screen->geometry(), screen); + if (m_screen) + screen = m_screen; } + return QHighDpi::toNativePixels(screen->geometry(), screen); +} + +void QEvdevTouchScreenData::reportPoints() +{ + QRect winRect = screenGeometry(); + if (winRect.isNull()) + return; const int hw_w = hw_range_x_max - hw_range_x_min; const int hw_h = hw_range_y_max - hw_range_y_min; @@ -718,13 +776,17 @@ void QEvdevTouchScreenData::reportPoints() } // Let qguiapp pick the target window. - QWindowSystemInterface::handleTouchEvent(Q_NULLPTR, q->touchDevice(), m_touchPoints); + if (m_filtered) + emit q->touchPointsUpdated(); + else + QWindowSystemInterface::handleTouchEvent(Q_NULLPTR, q->touchDevice(), m_touchPoints); } - - QEvdevTouchScreenHandlerThread::QEvdevTouchScreenHandlerThread(const QString &device, const QString &spec, QObject *parent) : QDaemonThread(parent), m_device(device), m_spec(spec), m_handler(Q_NULLPTR), m_touchDeviceRegistered(false) + , m_touchUpdatePending(false) + , m_filterWindow(Q_NULLPTR) + , m_touchRate(-1) { start(); } @@ -738,6 +800,10 @@ QEvdevTouchScreenHandlerThread::~QEvdevTouchScreenHandlerThread() void QEvdevTouchScreenHandlerThread::run() { m_handler = new QEvdevTouchScreenHandler(m_device, m_spec); + + if (m_handler->isFiltered()) + connect(m_handler, &QEvdevTouchScreenHandler::touchPointsUpdated, this, &QEvdevTouchScreenHandlerThread::scheduleTouchPointUpdate); + // Report the registration to the parent thread by invoking the method asynchronously QMetaObject::invokeMethod(this, "notifyTouchDeviceRegistered", Qt::QueuedConnection); @@ -758,5 +824,137 @@ void QEvdevTouchScreenHandlerThread::notifyTouchDeviceRegistered() emit touchDeviceRegistered(); } +void QEvdevTouchScreenHandlerThread::scheduleTouchPointUpdate() +{ + QWindow *window = QGuiApplication::focusWindow(); + if (window != m_filterWindow) { + if (m_filterWindow) + m_filterWindow->removeEventFilter(this); + m_filterWindow = window; + if (m_filterWindow) + m_filterWindow->installEventFilter(this); + } + if (m_filterWindow) { + m_touchUpdatePending = true; + m_filterWindow->requestUpdate(); + } +} + +bool QEvdevTouchScreenHandlerThread::eventFilter(QObject *object, QEvent *event) +{ + if (m_touchUpdatePending && object == m_filterWindow && event->type() == QEvent::UpdateRequest) { + m_touchUpdatePending = false; + filterAndSendTouchPoints(); + } + return false; +} + +void QEvdevTouchScreenHandlerThread::filterAndSendTouchPoints() +{ + QRect winRect = m_handler->d->screenGeometry(); + if (winRect.isNull()) + return; + + float vsyncDelta = 1.0f / QGuiApplication::primaryScreen()->refreshRate(); + + QHash<int, FilteredTouchPoint> filteredPoints; + + m_handler->d->m_mutex.lock(); + + double time = m_handler->d->m_timeStamp; + double lastTime = m_handler->d->m_lastTimeStamp; + double touchDelta = time - lastTime; + if (m_touchRate < 0 || touchDelta > vsyncDelta) { + // We're at the very start, with nothing to go on, so make a guess + // that the touch rate will be somewhere in the range of half a vsync. + // This doesn't have to be accurate as we will calibrate it over time, + // but it gives us a better starting point so calibration will be + // slightly quicker. If, on the other hand, we already have an + // estimate, we'll leave it as is and keep it. + if (m_touchRate < 0) + m_touchRate = (1.0 / QGuiApplication::primaryScreen()->refreshRate()) / 2.0; + + } else { + // Update our estimate for the touch rate. We're making the assumption + // that this value will be mostly accurate with the occational bump, + // so we're weighting the existing value high compared to the update. + const double ratio = 0.9; + m_touchRate = sqrt(m_touchRate * m_touchRate * ratio + touchDelta * touchDelta * (1.0 - ratio)); + } + + QList<QWindowSystemInterface::TouchPoint> points = m_handler->d->m_touchPoints; + const QList<QWindowSystemInterface::TouchPoint> &lastPoints = m_handler->d->m_lastTouchPoints; + + m_handler->d->m_mutex.unlock(); + + for (int i=0; i<points.size(); ++i) { + QWindowSystemInterface::TouchPoint &tp = points[i]; + QPointF pos = tp.normalPosition; + FilteredTouchPoint f; + + QWindowSystemInterface::TouchPoint ltp; + ltp.id = -1; + for (int j=0; j<lastPoints.size(); ++j) { + if (lastPoints.at(j).id == tp.id) { + ltp = lastPoints.at(j); + break; + } + } + + QPointF velocity; + if (lastTime != 0 && ltp.id >= 0) + velocity = (pos - ltp.normalPosition) / m_touchRate; + if (m_filteredPoints.contains(tp.id)) { + f = m_filteredPoints.take(tp.id); + f.x.update(pos.x(), velocity.x(), vsyncDelta); + f.y.update(pos.y(), velocity.y(), vsyncDelta); + pos = QPointF(f.x.position(), f.y.position()); + } else { + f.x.initialize(pos.x(), velocity.x()); + f.y.initialize(pos.y(), velocity.y()); + // Make sure the first instance of a touch point we send has the + // 'pressed' state. + if (tp.state != Qt::TouchPointPressed) + tp.state = Qt::TouchPointPressed; + } + + tp.velocity = QVector2D(f.x.velocity() * winRect.width(), f.y.velocity() * winRect.height()); + + qreal filteredNormalizedX = f.x.position() + f.x.velocity() * m_handler->d->m_prediction / 1000.0; + qreal filteredNormalizedY = f.y.position() + f.y.velocity() * m_handler->d->m_prediction / 1000.0; + + // Clamp to the screen + tp.normalPosition = QPointF(qBound<qreal>(0, filteredNormalizedX, 1), + qBound<qreal>(0, filteredNormalizedY, 1)); + + qreal x = winRect.x() + (tp.normalPosition.x() * (winRect.width() - 1)); + qreal y = winRect.y() + (tp.normalPosition.y() * (winRect.height() - 1)); + + tp.area.moveCenter(QPointF(x, y)); + + // Store the touch point for later so we can release it if we've + // missed the actual release between our last update and this. + f.touchPoint = tp; + + // Don't store the point for future reference if it is a release. + if (tp.state != Qt::TouchPointReleased) + filteredPoints[tp.id] = f; + } + + for (QHash<int, FilteredTouchPoint>::const_iterator it = m_filteredPoints.constBegin(), end = m_filteredPoints.constEnd(); it != end; ++it) { + const FilteredTouchPoint &f = it.value(); + QWindowSystemInterface::TouchPoint tp = f.touchPoint; + tp.state = Qt::TouchPointReleased; + tp.velocity = QVector2D(); + points.append(tp); + } + + m_filteredPoints = filteredPoints; + + QWindowSystemInterface::handleTouchEvent(Q_NULLPTR, + m_handler->touchDevice(), + points); +} + QT_END_NAMESPACE diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h b/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h index 6554d4998c..d22aca3266 100644 --- a/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h +++ b/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com> ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins module of the Qt Toolkit. @@ -58,6 +59,7 @@ #include <QThread> #include <QtCore/private/qthread_p.h> #include <qpa/qwindowsysteminterface.h> +#include "qevdevtouchfilter_p.h" #if QT_CONFIG(mtdev) struct mtdev; @@ -78,10 +80,18 @@ public: QTouchDevice *touchDevice() const; + bool isFiltered() const; + private slots: void readData(); +signals: + void touchPointsUpdated(); + private: + friend class QEvdevTouchScreenData; + friend class QEvdevTouchScreenHandlerThread; + void registerTouchDevice(); void unregisterTouchDevice(); @@ -104,16 +114,36 @@ public: bool isTouchDeviceRegistered() const; + bool eventFilter(QObject *object, QEvent *event) Q_DECL_OVERRIDE; + +public slots: + void scheduleTouchPointUpdate(); + signals: void touchDeviceRegistered(); private: Q_INVOKABLE void notifyTouchDeviceRegistered(); + void filterAndSendTouchPoints(); + QRect targetScreenGeometry() const; + QString m_device; QString m_spec; QEvdevTouchScreenHandler *m_handler; bool m_touchDeviceRegistered; + + bool m_touchUpdatePending; + QWindow *m_filterWindow; + + struct FilteredTouchPoint { + QEvdevTouchFilter x; + QEvdevTouchFilter y; + QWindowSystemInterface::TouchPoint touchPoint; + }; + QHash<int, FilteredTouchPoint> m_filteredPoints; + + float m_touchRate; }; QT_END_NAMESPACE diff --git a/src/platformsupport/kmsconvenience/kmsconvenience.pro b/src/platformsupport/kmsconvenience/kmsconvenience.pro new file mode 100644 index 0000000000..d0ff0d4efb --- /dev/null +++ b/src/platformsupport/kmsconvenience/kmsconvenience.pro @@ -0,0 +1,20 @@ +TARGET = QtKmsSupport +MODULE = kms_support + +QT = core-private gui-private +CONFIG += static internal_module + +DEFINES += QT_NO_CAST_FROM_ASCII +PRECOMPILED_HEADER = ../../corelib/global/qt_pch.h + +HEADERS += + qkmsdevice_p.h + +SOURCES += \ + qkmsdevice.cpp + +QMAKE_USE += drm + +LIBS_PRIVATE += $$QMAKE_LIBS_DYNLOAD + +load(qt_module) diff --git a/src/platformsupport/kmsconvenience/qkmsdevice.cpp b/src/platformsupport/kmsconvenience/qkmsdevice.cpp new file mode 100644 index 0000000000..669abab331 --- /dev/null +++ b/src/platformsupport/kmsconvenience/qkmsdevice.cpp @@ -0,0 +1,662 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Pelagicore AG +** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qkmsdevice_p.h" + +#include <QtCore/QJsonDocument> +#include <QtCore/QJsonObject> +#include <QtCore/QJsonArray> +#include <QtCore/QFile> +#include <QtCore/QLoggingCategory> + +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(qLcKmsDebug, "qt.qpa.eglfs.kms") + +enum OutputConfiguration { + OutputConfigOff, + OutputConfigPreferred, + OutputConfigCurrent, + OutputConfigMode, + OutputConfigModeline +}; + +int QKmsDevice::crtcForConnector(drmModeResPtr resources, drmModeConnectorPtr connector) +{ + for (int i = 0; i < connector->count_encoders; i++) { + drmModeEncoderPtr encoder = drmModeGetEncoder(m_dri_fd, connector->encoders[i]); + if (!encoder) { + qWarning("Failed to get encoder"); + continue; + } + + quint32 possibleCrtcs = encoder->possible_crtcs; + drmModeFreeEncoder(encoder); + + for (int j = 0; j < resources->count_crtcs; j++) { + bool isPossible = possibleCrtcs & (1 << j); + bool isAvailable = !(m_crtc_allocator & 1 << resources->crtcs[j]); + + if (isPossible && isAvailable) + return j; + } + } + + return -1; +} + +static const char * const connector_type_names[] = { // must match DRM_MODE_CONNECTOR_* + "None", + "VGA", + "DVI", + "DVI", + "DVI", + "Composite", + "TV", + "LVDS", + "CTV", + "DIN", + "DP", + "HDMI", + "HDMI", + "TV", + "eDP", + "Virtual", + "DSI" +}; + +static QByteArray nameForConnector(const drmModeConnectorPtr connector) +{ + QByteArray connectorName("UNKNOWN"); + + if (connector->connector_type < ARRAY_LENGTH(connector_type_names)) + connectorName = connector_type_names[connector->connector_type]; + + connectorName += QByteArray::number(connector->connector_type_id); + + return connectorName; +} + +static bool parseModeline(const QByteArray &text, drmModeModeInfoPtr mode) +{ + char hsync[16]; + char vsync[16]; + float fclock; + + mode->type = DRM_MODE_TYPE_USERDEF; + mode->hskew = 0; + mode->vscan = 0; + mode->vrefresh = 0; + mode->flags = 0; + + if (sscanf(text.constData(), "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s", + &fclock, + &mode->hdisplay, + &mode->hsync_start, + &mode->hsync_end, + &mode->htotal, + &mode->vdisplay, + &mode->vsync_start, + &mode->vsync_end, + &mode->vtotal, hsync, vsync) != 11) + return false; + + mode->clock = fclock * 1000; + + if (strcmp(hsync, "+hsync") == 0) + mode->flags |= DRM_MODE_FLAG_PHSYNC; + else if (strcmp(hsync, "-hsync") == 0) + mode->flags |= DRM_MODE_FLAG_NHSYNC; + else + return false; + + if (strcmp(vsync, "+vsync") == 0) + mode->flags |= DRM_MODE_FLAG_PVSYNC; + else if (strcmp(vsync, "-vsync") == 0) + mode->flags |= DRM_MODE_FLAG_NVSYNC; + else + return false; + + return true; +} + +QPlatformScreen *QKmsDevice::createScreenForConnector(drmModeResPtr resources, + drmModeConnectorPtr connector, + VirtualDesktopInfo *vinfo) +{ + const QByteArray connectorName = nameForConnector(connector); + + const int crtc = crtcForConnector(resources, connector); + if (crtc < 0) { + qWarning() << "No usable crtc/encoder pair for connector" << connectorName; + return Q_NULLPTR; + } + + OutputConfiguration configuration; + QSize configurationSize; + drmModeModeInfo configurationModeline; + + auto userConfig = m_screenConfig->outputSettings(); + auto userConnectorConfig = userConfig.value(QString::fromUtf8(connectorName)); + // default to the preferred mode unless overridden in the config + const QByteArray mode = userConnectorConfig.value(QStringLiteral("mode"), QStringLiteral("preferred")) + .toByteArray().toLower(); + if (mode == "off") { + configuration = OutputConfigOff; + } else if (mode == "preferred") { + configuration = OutputConfigPreferred; + } else if (mode == "current") { + configuration = OutputConfigCurrent; + } else if (sscanf(mode.constData(), "%dx%d", &configurationSize.rwidth(), &configurationSize.rheight()) == 2) { + configuration = OutputConfigMode; + } else if (parseModeline(mode, &configurationModeline)) { + configuration = OutputConfigModeline; + } else { + qWarning("Invalid mode \"%s\" for output %s", mode.constData(), connectorName.constData()); + configuration = OutputConfigPreferred; + } + if (vinfo) { + *vinfo = VirtualDesktopInfo(); + vinfo->virtualIndex = userConnectorConfig.value(QStringLiteral("virtualIndex"), INT_MAX).toInt(); + if (userConnectorConfig.contains(QStringLiteral("virtualPos"))) { + const QByteArray vpos = userConnectorConfig.value(QStringLiteral("virtualPos")).toByteArray(); + const QByteArrayList vposComp = vpos.split(','); + if (vposComp.count() == 2) + vinfo->virtualPos = QPoint(vposComp[0].trimmed().toInt(), vposComp[1].trimmed().toInt()); + } + if (userConnectorConfig.value(QStringLiteral("primary")).toBool()) + vinfo->isPrimary = true; + } + + const uint32_t crtc_id = resources->crtcs[crtc]; + + if (configuration == OutputConfigOff) { + qCDebug(qLcKmsDebug) << "Turning off output" << connectorName; + drmModeSetCrtc(m_dri_fd, crtc_id, 0, 0, 0, 0, 0, Q_NULLPTR); + return Q_NULLPTR; + } + + // Skip disconnected output + if (configuration == OutputConfigPreferred && connector->connection == DRM_MODE_DISCONNECTED) { + qCDebug(qLcKmsDebug) << "Skipping disconnected output" << connectorName; + return Q_NULLPTR; + } + + // Get the current mode on the current crtc + drmModeModeInfo crtc_mode; + memset(&crtc_mode, 0, sizeof crtc_mode); + if (drmModeEncoderPtr encoder = drmModeGetEncoder(m_dri_fd, connector->connector_id)) { + drmModeCrtcPtr crtc = drmModeGetCrtc(m_dri_fd, encoder->crtc_id); + drmModeFreeEncoder(encoder); + + if (!crtc) + return Q_NULLPTR; + + if (crtc->mode_valid) + crtc_mode = crtc->mode; + + drmModeFreeCrtc(crtc); + } + + QList<drmModeModeInfo> modes; + modes.reserve(connector->count_modes); + qCDebug(qLcKmsDebug) << connectorName << "mode count:" << connector->count_modes; + for (int i = 0; i < connector->count_modes; i++) { + const drmModeModeInfo &mode = connector->modes[i]; + qCDebug(qLcKmsDebug) << "mode" << i << mode.hdisplay << "x" << mode.vdisplay + << '@' << mode.vrefresh << "hz"; + modes << connector->modes[i]; + } + + int preferred = -1; + int current = -1; + int configured = -1; + int best = -1; + + for (int i = modes.size() - 1; i >= 0; i--) { + const drmModeModeInfo &m = modes.at(i); + + if (configuration == OutputConfigMode && + m.hdisplay == configurationSize.width() && + m.vdisplay == configurationSize.height()) { + configured = i; + } + + if (!memcmp(&crtc_mode, &m, sizeof m)) + current = i; + + if (m.type & DRM_MODE_TYPE_PREFERRED) + preferred = i; + + best = i; + } + + if (configuration == OutputConfigModeline) { + modes << configurationModeline; + configured = modes.size() - 1; + } + + if (current < 0 && crtc_mode.clock != 0) { + modes << crtc_mode; + current = mode.size() - 1; + } + + if (configuration == OutputConfigCurrent) + configured = current; + + int selected_mode = -1; + + if (configured >= 0) + selected_mode = configured; + else if (preferred >= 0) + selected_mode = preferred; + else if (current >= 0) + selected_mode = current; + else if (best >= 0) + selected_mode = best; + + if (selected_mode < 0) { + qWarning() << "No modes available for output" << connectorName; + return Q_NULLPTR; + } else { + int width = modes[selected_mode].hdisplay; + int height = modes[selected_mode].vdisplay; + int refresh = modes[selected_mode].vrefresh; + qCDebug(qLcKmsDebug) << "Selected mode" << selected_mode << ":" << width << "x" << height + << '@' << refresh << "hz for output" << connectorName; + } + + // physical size from connector < config values < env vars + int pwidth = qEnvironmentVariableIntValue("QT_QPA_EGLFS_PHYSICAL_WIDTH"); + if (!pwidth) + pwidth = qEnvironmentVariableIntValue("QT_QPA_PHYSICAL_WIDTH"); + int pheight = qEnvironmentVariableIntValue("QT_QPA_EGLFS_PHYSICAL_HEIGHT"); + if (!pheight) + pheight = qEnvironmentVariableIntValue("QT_QPA_PHYSICAL_HEIGHT"); + QSizeF physSize(pwidth, pheight); + if (physSize.isEmpty()) { + physSize = QSize(userConnectorConfig.value(QStringLiteral("physicalWidth")).toInt(), + userConnectorConfig.value(QStringLiteral("physicalHeight")).toInt()); + if (physSize.isEmpty()) { + physSize.setWidth(connector->mmWidth); + physSize.setHeight(connector->mmHeight); + } + } + qCDebug(qLcKmsDebug) << "Physical size is" << physSize << "mm" << "for output" << connectorName; + + QKmsOutput output = { + QString::fromUtf8(connectorName), + connector->connector_id, + crtc_id, + physSize, + selected_mode, + false, + drmModeGetCrtc(m_dri_fd, crtc_id), + modes, + connector->subpixel, + connectorProperty(connector, QByteArrayLiteral("DPMS")), + false, + 0, + false + }; + + bool ok; + int idx = qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_PLANE_INDEX", &ok); + if (ok) { + drmModePlaneRes *planeResources = drmModeGetPlaneResources(m_dri_fd); + if (planeResources) { + if (idx >= 0 && idx < int(planeResources->count_planes)) { + drmModePlane *plane = drmModeGetPlane(m_dri_fd, planeResources->planes[idx]); + if (plane) { + output.wants_plane = true; + output.plane_id = plane->plane_id; + qCDebug(qLcKmsDebug, "Forcing plane index %d, plane id %u (belongs to crtc id %u)", + idx, plane->plane_id, plane->crtc_id); + drmModeFreePlane(plane); + } + } else { + qWarning("Invalid plane index %d, must be between 0 and %u", idx, planeResources->count_planes - 1); + } + } + } + + m_crtc_allocator |= (1 << output.crtc_id); + m_connector_allocator |= (1 << output.connector_id); + + return createScreen(output); +} + +drmModePropertyPtr QKmsDevice::connectorProperty(drmModeConnectorPtr connector, const QByteArray &name) +{ + drmModePropertyPtr prop; + + for (int i = 0; i < connector->count_props; i++) { + prop = drmModeGetProperty(m_dri_fd, connector->props[i]); + if (!prop) + continue; + if (strcmp(prop->name, name.constData()) == 0) + return prop; + drmModeFreeProperty(prop); + } + + return Q_NULLPTR; +} + +QKmsDevice::QKmsDevice(QKmsScreenConfig *screenConfig, const QString &path) + : m_screenConfig(screenConfig) + , m_path(path) + , m_dri_fd(-1) + , m_crtc_allocator(0) + , m_connector_allocator(0) +{ + if (m_path.isEmpty()) { + m_path = m_screenConfig->devicePath(); + qCDebug(qLcKmsDebug, "Using DRM device %s specified in config file", qPrintable(m_path)); + if (m_path.isEmpty()) + qFatal("No DRM device given"); + } else { + qCDebug(qLcKmsDebug, "Using backend-provided DRM device %s", qPrintable(m_path)); + } +} + +QKmsDevice::~QKmsDevice() +{ +} + +struct OrderedScreen +{ + OrderedScreen() : screen(nullptr) { } + OrderedScreen(QPlatformScreen *screen, const QKmsDevice::VirtualDesktopInfo &vinfo) + : screen(screen), vinfo(vinfo) { } + QPlatformScreen *screen; + QKmsDevice::VirtualDesktopInfo vinfo; +}; + +QDebug operator<<(QDebug dbg, const OrderedScreen &s) +{ + QDebugStateSaver saver(dbg); + dbg.nospace() << "OrderedScreen(QPlatformScreen=" << s.screen << " (" << s.screen->name() << ") : " + << s.vinfo.virtualIndex + << " / " << s.vinfo.virtualPos + << " / primary: " << s.vinfo.isPrimary + << ")"; + return dbg; +} + +static bool orderedScreenLessThan(const OrderedScreen &a, const OrderedScreen &b) +{ + return a.vinfo.virtualIndex < b.vinfo.virtualIndex; +} + +void QKmsDevice::createScreens() +{ + drmModeResPtr resources = drmModeGetResources(m_dri_fd); + if (!resources) { + qWarning("drmModeGetResources failed"); + return; + } + + QVector<OrderedScreen> screens; + + int wantedConnectorIndex = -1; + bool ok; + int idx = qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_CONNECTOR_INDEX", &ok); + if (ok) { + if (idx >= 0 && idx < resources->count_connectors) + wantedConnectorIndex = idx; + else + qWarning("Invalid connector index %d, must be between 0 and %u", idx, resources->count_connectors - 1); + } + + for (int i = 0; i < resources->count_connectors; i++) { + if (wantedConnectorIndex >= 0 && i != wantedConnectorIndex) + continue; + + drmModeConnectorPtr connector = drmModeGetConnector(m_dri_fd, resources->connectors[i]); + if (!connector) + continue; + + VirtualDesktopInfo vinfo; + QPlatformScreen *screen = createScreenForConnector(resources, connector, &vinfo); + if (screen) + screens.append(OrderedScreen(screen, vinfo)); + + drmModeFreeConnector(connector); + } + + drmModeFreeResources(resources); + + // Use stable sort to preserve the original (DRM connector) order + // for outputs with unspecified indices. + std::stable_sort(screens.begin(), screens.end(), orderedScreenLessThan); + qCDebug(qLcKmsDebug) << "Sorted screen list:" << screens; + + QPoint pos(0, 0); + QList<QPlatformScreen *> siblings; + QVector<QPoint> virtualPositions; + int primarySiblingIdx = -1; + + for (const OrderedScreen &orderedScreen : screens) { + QPlatformScreen *s = orderedScreen.screen; + QPoint virtualPos(0, 0); + // set up a horizontal or vertical virtual desktop + if (orderedScreen.vinfo.virtualPos.isNull()) { + virtualPos = pos; + if (m_screenConfig->virtualDesktopLayout() == QKmsScreenConfig::VirtualDesktopLayoutVertical) + pos.ry() += s->geometry().height(); + else + pos.rx() += s->geometry().width(); + } else { + virtualPos = orderedScreen.vinfo.virtualPos; + } + qCDebug(qLcKmsDebug) << "Adding QPlatformScren" << s << "(" << s->name() << ")" + << "to QPA with geometry" << s->geometry() + << "and isPrimary=" << orderedScreen.vinfo.isPrimary; + // The order in qguiapp's screens list will match the order set by + // virtualIndex. This is not only handy but also required since for instance + // evdevtouch relies on it when performing touch device - screen mapping. + if (!m_screenConfig->separateScreens()) { + siblings.append(s); + virtualPositions.append(virtualPos); + if (orderedScreen.vinfo.isPrimary) + primarySiblingIdx = siblings.count() - 1; + } else { + registerScreen(s, orderedScreen.vinfo.isPrimary, virtualPos, QList<QPlatformScreen *>() << s); + } + } + + if (!m_screenConfig->separateScreens()) { + // enable the virtual desktop + for (int i = 0; i < siblings.count(); ++i) + registerScreen(siblings[i], i == primarySiblingIdx, virtualPositions[i], siblings); + } +} + +int QKmsDevice::fd() const +{ + return m_dri_fd; +} + +QString QKmsDevice::devicePath() const +{ + return m_path; +} + +void QKmsDevice::setFd(int fd) +{ + m_dri_fd = fd; +} + +QKmsScreenConfig *QKmsDevice::screenConfig() const +{ + return m_screenConfig; +} + +QKmsScreenConfig::QKmsScreenConfig() + : m_hwCursor(true) + , m_separateScreens(false) + , m_pbuffers(false) + , m_virtualDesktopLayout(VirtualDesktopLayoutHorizontal) +{ + loadConfig(); +} + +void QKmsScreenConfig::loadConfig() +{ + QByteArray json = qgetenv("QT_QPA_EGLFS_KMS_CONFIG"); + if (json.isEmpty()) { + json = qgetenv("QT_QPA_KMS_CONFIG"); + if (json.isEmpty()) + return; + } + + qCDebug(qLcKmsDebug) << "Loading KMS setup from" << json; + + QFile file(QString::fromUtf8(json)); + if (!file.open(QFile::ReadOnly)) { + qCWarning(qLcKmsDebug) << "Could not open config file" + << json << "for reading"; + return; + } + + const QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); + if (!doc.isObject()) { + qCWarning(qLcKmsDebug) << "Invalid config file" << json + << "- no top-level JSON object"; + return; + } + + const QJsonObject object = doc.object(); + + m_hwCursor = object.value(QLatin1String("hwcursor")).toBool(m_hwCursor); + m_pbuffers = object.value(QLatin1String("pbuffers")).toBool(m_pbuffers); + m_devicePath = object.value(QLatin1String("device")).toString(); + m_separateScreens = object.value(QLatin1String("separateScreens")).toBool(m_separateScreens); + + const QString vdOriString = object.value(QLatin1String("virtualDesktopLayout")).toString(); + if (!vdOriString.isEmpty()) { + if (vdOriString == QLatin1String("horizontal")) + m_virtualDesktopLayout = VirtualDesktopLayoutHorizontal; + else if (vdOriString == QLatin1String("vertical")) + m_virtualDesktopLayout = VirtualDesktopLayoutVertical; + else + qCWarning(qLcKmsDebug) << "Unknown virtualDesktopOrientation value" << vdOriString; + } + + const QJsonArray outputs = object.value(QLatin1String("outputs")).toArray(); + for (int i = 0; i < outputs.size(); i++) { + const QVariantMap outputSettings = outputs.at(i).toObject().toVariantMap(); + + if (outputSettings.contains(QStringLiteral("name"))) { + const QString name = outputSettings.value(QStringLiteral("name")).toString(); + + if (m_outputSettings.contains(name)) { + qCDebug(qLcKmsDebug) << "Output" << name << "configured multiple times!"; + } + + m_outputSettings.insert(name, outputSettings); + } + } + + qCDebug(qLcKmsDebug) << "Requested configuration (some settings may be ignored):\n" + << "\thwcursor:" << m_hwCursor << "\n" + << "\tpbuffers:" << m_pbuffers << "\n" + << "\tseparateScreens:" << m_separateScreens << "\n" + << "\tvirtualDesktopLayout:" << m_virtualDesktopLayout << "\n" + << "\toutputs:" << m_outputSettings; +} + +void QKmsOutput::restoreMode(QKmsDevice *device) +{ + if (mode_set && saved_crtc) { + drmModeSetCrtc(device->fd(), + saved_crtc->crtc_id, + saved_crtc->buffer_id, + 0, 0, + &connector_id, 1, + &saved_crtc->mode); + mode_set = false; + } +} + +void QKmsOutput::cleanup(QKmsDevice *device) +{ + if (dpms_prop) { + drmModeFreeProperty(dpms_prop); + dpms_prop = nullptr; + } + + restoreMode(device); + + if (saved_crtc) { + drmModeFreeCrtc(saved_crtc); + saved_crtc = nullptr; + } +} + +QPlatformScreen::SubpixelAntialiasingType QKmsOutput::subpixelAntialiasingTypeHint() const +{ + switch (subpixel) { + default: + case DRM_MODE_SUBPIXEL_UNKNOWN: + case DRM_MODE_SUBPIXEL_NONE: + return QPlatformScreen::Subpixel_None; + case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB: + return QPlatformScreen::Subpixel_RGB; + case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR: + return QPlatformScreen::Subpixel_BGR; + case DRM_MODE_SUBPIXEL_VERTICAL_RGB: + return QPlatformScreen::Subpixel_VRGB; + case DRM_MODE_SUBPIXEL_VERTICAL_BGR: + return QPlatformScreen::Subpixel_VBGR; + } +} + +void QKmsOutput::setPowerState(QKmsDevice *device, QPlatformScreen::PowerState state) +{ + if (dpms_prop) + drmModeConnectorSetProperty(device->fd(), connector_id, + dpms_prop->prop_id, (int) state); +} + +QT_END_NAMESPACE diff --git a/src/platformsupport/kmsconvenience/qkmsdevice_p.h b/src/platformsupport/kmsconvenience/qkmsdevice_p.h new file mode 100644 index 0000000000..35a51c18b1 --- /dev/null +++ b/src/platformsupport/kmsconvenience/qkmsdevice_p.h @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Pelagicore AG +** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QKMSDEVICE_P_H +#define QKMSDEVICE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <qpa/qplatformscreen.h> +#include <QtCore/QMap> +#include <QtCore/QVariant> + +#include <xf86drm.h> +#include <xf86drmMode.h> + +QT_BEGIN_NAMESPACE + +class QKmsDevice; + +class QKmsScreenConfig +{ +public: + enum VirtualDesktopLayout { + VirtualDesktopLayoutHorizontal, + VirtualDesktopLayoutVertical + }; + + QKmsScreenConfig(); + + QString devicePath() const { return m_devicePath; } + + bool hwCursor() const { return m_hwCursor; } + bool separateScreens() const { return m_separateScreens; } + bool supportsPBuffers() const { return m_pbuffers; } + VirtualDesktopLayout virtualDesktopLayout() const { return m_virtualDesktopLayout; } + + QMap<QString, QVariantMap> outputSettings() const { return m_outputSettings; } + +private: + void loadConfig(); + + QString m_devicePath; + bool m_hwCursor; + bool m_separateScreens; + bool m_pbuffers; + VirtualDesktopLayout m_virtualDesktopLayout; + QMap<QString, QVariantMap> m_outputSettings; +}; + +struct QKmsOutput +{ + QString name; + uint32_t connector_id; + uint32_t crtc_id; + QSizeF physical_size; + int mode; // index of selected mode in list below + bool mode_set; + drmModeCrtcPtr saved_crtc; + QList<drmModeModeInfo> modes; + int subpixel; + drmModePropertyPtr dpms_prop; + bool wants_plane; + uint32_t plane_id; + bool plane_set; + + void restoreMode(QKmsDevice *device); + void cleanup(QKmsDevice *device); + QPlatformScreen::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const; + void setPowerState(QKmsDevice *device, QPlatformScreen::PowerState state); +}; + +class QKmsDevice +{ +public: + struct VirtualDesktopInfo { + VirtualDesktopInfo() : virtualIndex(0), isPrimary(false) { } + int virtualIndex; + QPoint virtualPos; + bool isPrimary; + }; + + QKmsDevice(QKmsScreenConfig *screenConfig, const QString &path = QString()); + virtual ~QKmsDevice(); + + virtual bool open() = 0; + virtual void close() = 0; + virtual void *nativeDisplay() const = 0; + + void createScreens(); + + int fd() const; + QString devicePath() const; + + QKmsScreenConfig *screenConfig() const; + +protected: + virtual QPlatformScreen *createScreen(const QKmsOutput &output) = 0; + virtual void registerScreen(QPlatformScreen *screen, + bool isPrimary, + const QPoint &virtualPos, + const QList<QPlatformScreen *> &virtualSiblings) = 0; + + void setFd(int fd); + int crtcForConnector(drmModeResPtr resources, drmModeConnectorPtr connector); + QPlatformScreen *createScreenForConnector(drmModeResPtr resources, + drmModeConnectorPtr connector, + VirtualDesktopInfo *vinfo); + drmModePropertyPtr connectorProperty(drmModeConnectorPtr connector, const QByteArray &name); + + QKmsScreenConfig *m_screenConfig; + QString m_path; + int m_dri_fd; + + quint32 m_crtc_allocator; + quint32 m_connector_allocator; + +private: + Q_DISABLE_COPY(QKmsDevice) +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/platformsupport/linuxaccessibility/atspiadaptor.cpp b/src/platformsupport/linuxaccessibility/atspiadaptor.cpp index 70c4aa563c..6561e95a0d 100644 --- a/src/platformsupport/linuxaccessibility/atspiadaptor.cpp +++ b/src/platformsupport/linuxaccessibility/atspiadaptor.cpp @@ -1398,7 +1398,7 @@ bool AtSpiAdaptor::accessibleInterface(QAccessibleInterface *interface, const QS sendReply(connection, message, QVariant::fromValue( QDBusVariant(QVariant::fromValue(QSpiObjectReference(connection, QDBusObjectPath(path)))))); } else if (function == QLatin1String("GetChildAtIndex")) { - int index = message.arguments().first().toInt(); + const int index = message.arguments().at(0).toInt(); if (index < 0) { sendReply(connection, message, QVariant::fromValue( QSpiObjectReference(connection, QDBusObjectPath(ATSPI_DBUS_PATH_NULL)))); diff --git a/src/platformsupport/platformcompositor/qopenglcompositor_p.h b/src/platformsupport/platformcompositor/qopenglcompositor_p.h index dece41f676..41a3288240 100644 --- a/src/platformsupport/platformcompositor/qopenglcompositor_p.h +++ b/src/platformsupport/platformcompositor/qopenglcompositor_p.h @@ -65,6 +65,7 @@ class QPlatformTextureList; class QOpenGLCompositorWindow { public: + virtual ~QOpenGLCompositorWindow() { } virtual QWindow *sourceWindow() const = 0; virtual const QPlatformTextureList *textures() const = 0; virtual void beginCompositing() { } diff --git a/src/platformsupport/platformsupport.pro b/src/platformsupport/platformsupport.pro index 09e2922505..7a97a12bae 100644 --- a/src/platformsupport/platformsupport.pro +++ b/src/platformsupport/platformsupport.pro @@ -7,7 +7,7 @@ SUBDIRS = \ fbconvenience \ themes -qtConfig(freetype)|if(darwin:!if(watchos:CONFIG(simulator, simulator|device)))|win32: \ +qtConfig(freetype)|darwin|win32: \ SUBDIRS += fontdatabases qtConfig(evdev)|qtConfig(tslib)|qtConfig(libinput) { @@ -24,6 +24,8 @@ qtConfig(egl): \ SUBDIRS += eglconvenience qtConfig(xlib):qtConfig(opengl):!qtConfig(opengles2): \ SUBDIRS += glxconvenience +qtConfig(kms): \ + SUBDIRS += kmsconvenience qtConfig(accessibility) { SUBDIRS += accessibility diff --git a/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection.cpp b/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection.cpp index 352e4dfd56..09470bccc6 100644 --- a/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection.cpp +++ b/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection.cpp @@ -37,6 +37,8 @@ ** ****************************************************************************/ +#include <QtGui/qtgui-config.h> + #ifndef QT_NO_SYSTEMTRAYICON #include "qdbustrayicon_p.h" #endif diff --git a/src/platformsupport/themes/genericunix/genericunix.pri b/src/platformsupport/themes/genericunix/genericunix.pri index 27019b4aa2..11da533bc4 100644 --- a/src/platformsupport/themes/genericunix/genericunix.pri +++ b/src/platformsupport/themes/genericunix/genericunix.pri @@ -3,5 +3,8 @@ SOURCES += $$PWD/qgenericunixthemes.cpp qtConfig(dbus) { include(dbusmenu/dbusmenu.pri) - include(dbustray/dbustray.pri) + + qtConfig(systemtrayicon) { + include(dbustray/dbustray.pri) + } } |