Provide sensible defaults for QCoreApplication::applicationVersion
[ChangeLog][QtCore] QCoreApplication::applicationVersion now defaults to an appropriate platform-specific value. On Windows, it defaults to the PRODUCTVERSION parameter of the VERSIONINFO resource for classic desktop apps, and the version attribute of the application package manifest for Univeral Windows Platform apps. On Apple Platforms (macOS, iOS, tvOS, watchOS), it defaults to the CFBundleVersion property of the information property list (Info.plist) file. On Android, it defaults to the android:versionName attribute of the AndroidManifest.xml manifest element. On other platforms, the default remains an empty string. Task-number: QTBUG-57715 Change-Id: I26f83dd00737e06f4321cf962aa5fab8398104ec Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
5865e582fd
commit
2b928ef6f9
@ -88,6 +88,8 @@ win32 {
|
|||||||
SOURCES += kernel/qeventdispatcher_win.cpp
|
SOURCES += kernel/qeventdispatcher_win.cpp
|
||||||
HEADERS += kernel/qeventdispatcher_win_p.h
|
HEADERS += kernel/qeventdispatcher_win_p.h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
!winrt: LIBS_PRIVATE += -lversion
|
||||||
}
|
}
|
||||||
|
|
||||||
winrt {
|
winrt {
|
||||||
|
@ -95,6 +95,11 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif // QT_NO_QOBJECT
|
#endif // QT_NO_QOBJECT
|
||||||
|
|
||||||
|
#if defined(Q_OS_ANDROID)
|
||||||
|
# include <private/qjni_p.h>
|
||||||
|
# include <private/qjnihelpers_p.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
# include "qcore_mac_p.h"
|
# include "qcore_mac_p.h"
|
||||||
#endif
|
#endif
|
||||||
@ -144,11 +149,13 @@ int QCoreApplicationPrivate::app_compile_version = 0x050000; //we don't know exa
|
|||||||
bool QCoreApplicationPrivate::setuidAllowed = false;
|
bool QCoreApplicationPrivate::setuidAllowed = false;
|
||||||
|
|
||||||
#if !defined(Q_OS_WIN)
|
#if !defined(Q_OS_WIN)
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_DARWIN
|
||||||
QString QCoreApplicationPrivate::macMenuBarName()
|
QString QCoreApplicationPrivate::infoDictionaryStringProperty(const QString &propertyName)
|
||||||
{
|
{
|
||||||
QString bundleName;
|
QString bundleName;
|
||||||
CFTypeRef string = CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), CFSTR("CFBundleName"));
|
QCFString cfPropertyName = propertyName.toCFString();
|
||||||
|
CFTypeRef string = CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(),
|
||||||
|
cfPropertyName);
|
||||||
if (string)
|
if (string)
|
||||||
bundleName = QString::fromCFString(static_cast<CFStringRef>(string));
|
bundleName = QString::fromCFString(static_cast<CFStringRef>(string));
|
||||||
return bundleName;
|
return bundleName;
|
||||||
@ -157,8 +164,8 @@ QString QCoreApplicationPrivate::macMenuBarName()
|
|||||||
QString QCoreApplicationPrivate::appName() const
|
QString QCoreApplicationPrivate::appName() const
|
||||||
{
|
{
|
||||||
QString applicationName;
|
QString applicationName;
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_DARWIN
|
||||||
applicationName = macMenuBarName();
|
applicationName = infoDictionaryStringProperty(QStringLiteral("CFBundleName"));
|
||||||
#endif
|
#endif
|
||||||
if (applicationName.isEmpty() && argv[0]) {
|
if (applicationName.isEmpty() && argv[0]) {
|
||||||
char *p = strrchr(argv[0], '/');
|
char *p = strrchr(argv[0], '/');
|
||||||
@ -167,6 +174,34 @@ QString QCoreApplicationPrivate::appName() const
|
|||||||
|
|
||||||
return applicationName;
|
return applicationName;
|
||||||
}
|
}
|
||||||
|
QString QCoreApplicationPrivate::appVersion() const
|
||||||
|
{
|
||||||
|
QString applicationVersion;
|
||||||
|
#ifndef QT_BOOTSTRAPPED
|
||||||
|
# ifdef Q_OS_DARWIN
|
||||||
|
applicationVersion = infoDictionaryStringProperty(QStringLiteral("CFBundleVersion"));
|
||||||
|
# elif defined(Q_OS_ANDROID)
|
||||||
|
QJNIObjectPrivate context(QtAndroidPrivate::context());
|
||||||
|
if (context.isValid()) {
|
||||||
|
QJNIObjectPrivate pm = context.callObjectMethod(
|
||||||
|
"getPackageManager", "()Landroid/content/pm/PackageManager;");
|
||||||
|
QJNIObjectPrivate pn = context.callObjectMethod<jstring>("getPackageName");
|
||||||
|
if (pm.isValid() && pn.isValid()) {
|
||||||
|
QJNIObjectPrivate packageInfo = pm.callObjectMethod(
|
||||||
|
"getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;",
|
||||||
|
pn.object(), 0);
|
||||||
|
if (packageInfo.isValid()) {
|
||||||
|
QJNIObjectPrivate versionName = packageInfo.getObjectField(
|
||||||
|
"versionName", "Ljava/lang/String;");
|
||||||
|
if (versionName.isValid())
|
||||||
|
return versionName.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
return applicationVersion;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QString *QCoreApplicationPrivate::cachedApplicationFilePath = 0;
|
QString *QCoreApplicationPrivate::cachedApplicationFilePath = 0;
|
||||||
@ -332,6 +367,7 @@ uint QCoreApplicationPrivate::attribs =
|
|||||||
struct QCoreApplicationData {
|
struct QCoreApplicationData {
|
||||||
QCoreApplicationData() Q_DECL_NOTHROW {
|
QCoreApplicationData() Q_DECL_NOTHROW {
|
||||||
applicationNameSet = false;
|
applicationNameSet = false;
|
||||||
|
applicationVersionSet = false;
|
||||||
}
|
}
|
||||||
~QCoreApplicationData() {
|
~QCoreApplicationData() {
|
||||||
#ifndef QT_NO_QOBJECT
|
#ifndef QT_NO_QOBJECT
|
||||||
@ -347,6 +383,7 @@ struct QCoreApplicationData {
|
|||||||
QString application; // application name, initially from argv[0], can then be modified.
|
QString application; // application name, initially from argv[0], can then be modified.
|
||||||
QString applicationVersion;
|
QString applicationVersion;
|
||||||
bool applicationNameSet; // true if setApplicationName was called
|
bool applicationNameSet; // true if setApplicationName was called
|
||||||
|
bool applicationVersionSet; // true if setApplicationVersion was called
|
||||||
|
|
||||||
#ifndef QT_NO_LIBRARY
|
#ifndef QT_NO_LIBRARY
|
||||||
QScopedPointer<QStringList> app_libpaths;
|
QScopedPointer<QStringList> app_libpaths;
|
||||||
@ -742,10 +779,13 @@ void QCoreApplicationPrivate::init()
|
|||||||
Q_ASSERT_X(!QCoreApplication::self, "QCoreApplication", "there should be only one application object");
|
Q_ASSERT_X(!QCoreApplication::self, "QCoreApplication", "there should be only one application object");
|
||||||
QCoreApplication::self = q;
|
QCoreApplication::self = q;
|
||||||
|
|
||||||
// Store app name (so it's still available after QCoreApplication is destroyed)
|
// Store app name/version (so they're still available after QCoreApplication is destroyed)
|
||||||
if (!coreappdata()->applicationNameSet)
|
if (!coreappdata()->applicationNameSet)
|
||||||
coreappdata()->application = appName();
|
coreappdata()->application = appName();
|
||||||
|
|
||||||
|
if (!coreappdata()->applicationVersionSet)
|
||||||
|
coreappdata()->applicationVersion = appVersion();
|
||||||
|
|
||||||
QLoggingRegistry::instance()->init();
|
QLoggingRegistry::instance()->init();
|
||||||
|
|
||||||
#ifndef QT_NO_LIBRARY
|
#ifndef QT_NO_LIBRARY
|
||||||
@ -2403,6 +2443,29 @@ Q_CORE_EXPORT QString qt_applicationName_noFallback()
|
|||||||
\since 4.4
|
\since 4.4
|
||||||
\brief the version of this application
|
\brief the version of this application
|
||||||
|
|
||||||
|
If not set, the application version defaults to a platform-specific value
|
||||||
|
determined from the main application executable or package (since Qt 5.9):
|
||||||
|
|
||||||
|
\table
|
||||||
|
\header
|
||||||
|
\li Platform
|
||||||
|
\li Source
|
||||||
|
\row
|
||||||
|
\li Windows (classic desktop)
|
||||||
|
\li PRODUCTVERSION parameter of the VERSIONINFO resource
|
||||||
|
\row
|
||||||
|
\li Universal Windows Platform
|
||||||
|
\li version attribute of the application package manifest
|
||||||
|
\row
|
||||||
|
\li macOS, iOS, tvOS, watchOS
|
||||||
|
\li CFBundleVersion property of the information property list
|
||||||
|
\row
|
||||||
|
\li Android
|
||||||
|
\li android:versionName property of the AndroidManifest.xml manifest element
|
||||||
|
\endtable
|
||||||
|
|
||||||
|
On other platforms, the default is the empty string.
|
||||||
|
|
||||||
\sa applicationName, organizationName, organizationDomain
|
\sa applicationName, organizationName, organizationDomain
|
||||||
*/
|
*/
|
||||||
/*!
|
/*!
|
||||||
@ -2413,9 +2476,13 @@ Q_CORE_EXPORT QString qt_applicationName_noFallback()
|
|||||||
*/
|
*/
|
||||||
void QCoreApplication::setApplicationVersion(const QString &version)
|
void QCoreApplication::setApplicationVersion(const QString &version)
|
||||||
{
|
{
|
||||||
if (coreappdata()->applicationVersion == version)
|
coreappdata()->applicationVersionSet = !version.isEmpty();
|
||||||
|
QString newVersion = version;
|
||||||
|
if (newVersion.isEmpty() && QCoreApplication::self)
|
||||||
|
newVersion = QCoreApplication::self->d_func()->appVersion();
|
||||||
|
if (coreappdata()->applicationVersion == newVersion)
|
||||||
return;
|
return;
|
||||||
coreappdata()->applicationVersion = version;
|
coreappdata()->applicationVersion = newVersion;
|
||||||
#ifndef QT_NO_QOBJECT
|
#ifndef QT_NO_QOBJECT
|
||||||
if (QCoreApplication::self)
|
if (QCoreApplication::self)
|
||||||
emit QCoreApplication::self->applicationVersionChanged();
|
emit QCoreApplication::self->applicationVersionChanged();
|
||||||
@ -2424,7 +2491,7 @@ void QCoreApplication::setApplicationVersion(const QString &version)
|
|||||||
|
|
||||||
QString QCoreApplication::applicationVersion()
|
QString QCoreApplication::applicationVersion()
|
||||||
{
|
{
|
||||||
return coreappdata()->applicationVersion;
|
return coreappdata() ? coreappdata()->applicationVersion : QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef QT_NO_LIBRARY
|
#ifndef QT_NO_LIBRARY
|
||||||
|
@ -83,9 +83,10 @@ public:
|
|||||||
void init();
|
void init();
|
||||||
|
|
||||||
QString appName() const;
|
QString appName() const;
|
||||||
|
QString appVersion() const;
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_DARWIN
|
||||||
static QString macMenuBarName();
|
static QString infoDictionaryStringProperty(const QString &propertyName);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void initLocale();
|
static void initLocale();
|
||||||
|
@ -51,6 +51,16 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <qt_windows.h>
|
#include <qt_windows.h>
|
||||||
|
|
||||||
|
#ifdef Q_OS_WINRT
|
||||||
|
#include <qfunctions_winrt.h>
|
||||||
|
#include <wrl.h>
|
||||||
|
#include <Windows.ApplicationModel.core.h>
|
||||||
|
#include <windows.foundation.h>
|
||||||
|
using namespace ABI::Windows::ApplicationModel;
|
||||||
|
using namespace Microsoft::WRL;
|
||||||
|
using namespace Microsoft::WRL::Wrappers;
|
||||||
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
int appCmdShow = 0;
|
int appCmdShow = 0;
|
||||||
@ -118,6 +128,64 @@ QString QCoreApplicationPrivate::appName() const
|
|||||||
return QFileInfo(qAppFileName()).baseName();
|
return QFileInfo(qAppFileName()).baseName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString QCoreApplicationPrivate::appVersion() const
|
||||||
|
{
|
||||||
|
QString applicationVersion;
|
||||||
|
#ifndef QT_BOOTSTRAPPED
|
||||||
|
# ifdef Q_OS_WINRT
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
ComPtr<IPackageStatics> packageFactory;
|
||||||
|
hr = RoGetActivationFactory(
|
||||||
|
HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Package).Get(),
|
||||||
|
IID_PPV_ARGS(&packageFactory));
|
||||||
|
RETURN_IF_FAILED("Failed to create package instance", return QString());
|
||||||
|
|
||||||
|
ComPtr<IPackage> package;
|
||||||
|
packageFactory->get_Current(&package);
|
||||||
|
RETURN_IF_FAILED("Failed to get current application package", return QString());
|
||||||
|
|
||||||
|
ComPtr<IPackageId> packageId;
|
||||||
|
package->get_Id(&packageId);
|
||||||
|
RETURN_IF_FAILED("Failed to get current application package ID", return QString());
|
||||||
|
|
||||||
|
PackageVersion version;
|
||||||
|
packageId->get_Version(&version);
|
||||||
|
RETURN_IF_FAILED("Failed to get current application package version", return QString());
|
||||||
|
|
||||||
|
applicationVersion = QStringLiteral("%1.%2.%3.%4")
|
||||||
|
.arg(version.Major)
|
||||||
|
.arg(version.Minor)
|
||||||
|
.arg(version.Build)
|
||||||
|
.arg(version.Revision);
|
||||||
|
# else
|
||||||
|
const QString appFileName = qAppFileName();
|
||||||
|
QVarLengthArray<wchar_t> buffer(appFileName.size() + 1);
|
||||||
|
buffer[appFileName.toWCharArray(buffer.data())] = 0;
|
||||||
|
|
||||||
|
DWORD versionInfoSize = GetFileVersionInfoSize(buffer.data(), nullptr);
|
||||||
|
if (versionInfoSize) {
|
||||||
|
QVarLengthArray<BYTE> info(static_cast<int>(versionInfoSize));
|
||||||
|
if (GetFileVersionInfo(buffer.data(), 0, versionInfoSize, info.data())) {
|
||||||
|
UINT size;
|
||||||
|
DWORD *fi;
|
||||||
|
|
||||||
|
if (VerQueryValue(info.data(), __TEXT("\\"),
|
||||||
|
reinterpret_cast<void **>(&fi), &size) && size) {
|
||||||
|
const VS_FIXEDFILEINFO *verInfo = reinterpret_cast<const VS_FIXEDFILEINFO *>(fi);
|
||||||
|
applicationVersion = QStringLiteral("%1.%2.%3.%4")
|
||||||
|
.arg(HIWORD(verInfo->dwProductVersionMS))
|
||||||
|
.arg(LOWORD(verInfo->dwProductVersionMS))
|
||||||
|
.arg(HIWORD(verInfo->dwProductVersionLS))
|
||||||
|
.arg(LOWORD(verInfo->dwProductVersionLS));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
return applicationVersion;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // !(defined(Q_OS_WINRT) && _MSC_VER < 1900)
|
#endif // !(defined(Q_OS_WINRT) && _MSC_VER < 1900)
|
||||||
|
|
||||||
#ifndef Q_OS_WINRT
|
#ifndef Q_OS_WINRT
|
||||||
|
8
tests/auto/corelib/kernel/qcoreapplication/Info.plist
Normal file
8
tests/auto/corelib/kernel/qcoreapplication/Info.plist
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1.2.3</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
@ -3,4 +3,7 @@ TARGET = tst_qcoreapplication
|
|||||||
QT = core testlib core-private
|
QT = core testlib core-private
|
||||||
SOURCES = tst_qcoreapplication.cpp
|
SOURCES = tst_qcoreapplication.cpp
|
||||||
HEADERS = tst_qcoreapplication.h
|
HEADERS = tst_qcoreapplication.h
|
||||||
|
win32: VERSION = 1.2.3.4
|
||||||
|
else: VERSION = 1.2.3
|
||||||
|
darwin: QMAKE_LFLAGS += -Wl,-sectcreate,__TEXT,__info_plist,$$shell_quote($$PWD/Info.plist)
|
||||||
requires(qtConfig(private_tests))
|
requires(qtConfig(private_tests))
|
||||||
|
@ -153,6 +153,41 @@ void tst_QCoreApplication::qAppName()
|
|||||||
QCOMPARE(QCoreApplication::applicationName(), QString());
|
QCOMPARE(QCoreApplication::applicationName(), QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QCoreApplication::qAppVersion()
|
||||||
|
{
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
const char appVersion[] = "1.2.3.4";
|
||||||
|
#elif defined(Q_OS_DARWIN) || defined(Q_OS_ANDROID)
|
||||||
|
const char appVersion[] = "1.2.3";
|
||||||
|
#else
|
||||||
|
const char appVersion[] = "";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{
|
||||||
|
int argc = 0;
|
||||||
|
char *argv[] = { nullptr };
|
||||||
|
TestApplication app(argc, argv);
|
||||||
|
QCOMPARE(QCoreApplication::applicationVersion(), QString::fromLatin1(appVersion));
|
||||||
|
}
|
||||||
|
// The application version should still be available after destruction
|
||||||
|
QCOMPARE(QCoreApplication::applicationVersion(), QString::fromLatin1(appVersion));
|
||||||
|
|
||||||
|
// Setting the appversion before creating the application should work
|
||||||
|
const QString wantedAppVersion("0.0.1");
|
||||||
|
{
|
||||||
|
int argc = 0;
|
||||||
|
char *argv[] = { nullptr };
|
||||||
|
QCoreApplication::setApplicationVersion(wantedAppVersion);
|
||||||
|
TestApplication app(argc, argv);
|
||||||
|
QCOMPARE(QCoreApplication::applicationVersion(), wantedAppVersion);
|
||||||
|
}
|
||||||
|
QCOMPARE(QCoreApplication::applicationVersion(), wantedAppVersion);
|
||||||
|
|
||||||
|
// Restore to initial value
|
||||||
|
QCoreApplication::setApplicationVersion(QString());
|
||||||
|
QCOMPARE(QCoreApplication::applicationVersion(), QString());
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QCoreApplication::argc()
|
void tst_QCoreApplication::argc()
|
||||||
{
|
{
|
||||||
#if defined(Q_OS_WINRT)
|
#if defined(Q_OS_WINRT)
|
||||||
|
@ -39,6 +39,7 @@ private slots:
|
|||||||
void sendEventsOnProcessEvents(); // this must be the first test
|
void sendEventsOnProcessEvents(); // this must be the first test
|
||||||
void getSetCheck();
|
void getSetCheck();
|
||||||
void qAppName();
|
void qAppName();
|
||||||
|
void qAppVersion();
|
||||||
void argc();
|
void argc();
|
||||||
void postEvent();
|
void postEvent();
|
||||||
void removePostedEvents();
|
void removePostedEvents();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user