1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qoperatingsystemversion.h"
41#if !defined(Q_OS_DARWIN) && !defined(Q_OS_WIN)
42#include "qoperatingsystemversion_p.h"
43#endif
44
45#if defined(Q_OS_DARWIN)
46#include <QtCore/private/qcore_mac_p.h>
47#endif
48
49#include <qversionnumber.h>
50#include <qdebug.h>
51
52#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
53#include <private/qjni_p.h>
54#endif
55
56QT_BEGIN_NAMESPACE
57
58/*!
59 \class QOperatingSystemVersion
60 \inmodule QtCore
61 \since 5.9
62 \brief The QOperatingSystemVersion class provides information about the
63 operating system version.
64
65 Unlike other version functions in QSysInfo, QOperatingSystemVersion provides
66 access to the full version number that \a developers typically use to vary
67 behavior or determine whether to enable APIs or features based on the
68 operating system version (as opposed to the kernel version number or
69 marketing version).
70
71 This class is also a complete replacement for QSysInfo::macVersion and
72 QSysInfo::windowsVersion, additionally providing access to the third (micro)
73 version number component.
74
75 Presently, Android, Apple Platforms (iOS, macOS, tvOS, and watchOS),
76 and Windows are supported.
77
78 The \a majorVersion(), \a minorVersion(), and \a microVersion() functions
79 return the parts of the operating system version number based on:
80
81 \table
82 \header
83 \li Platforms
84 \li Value
85 \row
86 \li Android
87 \li result of parsing
88 \l{https://developer.android.com/reference/android/os/Build.VERSION.html#RELEASE}{android.os.Build.VERSION.RELEASE}
89 using QVersionNumber, with a fallback to
90 \l{https://developer.android.com/reference/android/os/Build.VERSION.html#SDK_INT}{android.os.Build.VERSION.SDK_INT}
91 to determine the major and minor version component if the former
92 fails
93 \row
94 \li Apple Platforms
95 \li majorVersion, minorVersion, and patchVersion from
96 \l{https://developer.apple.com/reference/foundation/nsprocessinfo/1410906-operatingsystemversion?language=objc}{NSProcessInfo.operatingSystemVersion}
97 \row
98 \li Windows
99 \li dwMajorVersion, dwMinorVersion, and dwBuildNumber from
100 \l{https://msdn.microsoft.com/en-us/library/mt723418.aspx}{RtlGetVersion} -
101 note that this function ALWAYS return the version number of the
102 underlying operating system, as opposed to the shim underneath
103 GetVersionEx that hides the real version number if the
104 application is not manifested for that version of the OS
105 \endtable
106
107 Because QOperatingSystemVersion stores both a version number and an OS type, the OS type
108 can be taken into account when performing comparisons. For example, on a macOS system running
109 macOS Sierra (v10.12), the following expression will return \c false even though the
110 major version number component of the object on the left hand side of the expression (10) is
111 greater than that of the object on the right (9):
112
113 \snippet code/src_corelib_global_qoperatingsystemversion.cpp 0
114
115 This allows expressions for multiple operating systems to be joined with a logical OR operator
116 and still work as expected. For example:
117
118 \snippet code/src_corelib_global_qoperatingsystemversion.cpp 1
119
120 A more naive comparison algorithm might incorrectly return true on all versions of macOS,
121 including Mac OS 9. This behavior is achieved by overloading the comparison operators to return
122 \c false whenever the OS types of the QOperatingSystemVersion instances being compared do not
123 match. Be aware that due to this it can be the case \c x >= y and \c x < y are BOTH \c false
124 for the same instances of \c x and \c y.
125*/
126
127/*!
128 \enum QOperatingSystemVersion::OSType
129
130 This enum provides symbolic names for the various operating
131 system families supported by QOperatingSystemVersion.
132
133 \value Android The Google Android operating system.
134 \value IOS The Apple iOS operating system.
135 \value MacOS The Apple macOS operating system.
136 \value TvOS The Apple tvOS operating system.
137 \value WatchOS The Apple watchOS operating system.
138 \value Windows The Microsoft Windows operating system.
139
140 \value Unknown An unknown or unsupported operating system.
141*/
142
143/*!
144 \fn QOperatingSystemVersion::QOperatingSystemVersion(OSType osType, int vmajor, int vminor = -1, int vmicro = -1)
145
146 Constructs a QOperatingSystemVersion consisting of the OS type \a osType, and
147 major, minor, and micro version numbers \a vmajor, \a vminor and \a vmicro, respectively.
148*/
149
150/*!
151 \fn QOperatingSystemVersion QOperatingSystemVersion::current()
152
153 Returns a QOperatingSystemVersion indicating the current OS and its version number.
154
155 \sa currentType()
156*/
157#if !defined(Q_OS_DARWIN) && !defined(Q_OS_WIN)
158QOperatingSystemVersion QOperatingSystemVersion::current()
159{
160 QOperatingSystemVersion version;
161 version.m_os = currentType();
162#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
163#ifndef QT_BOOTSTRAPPED
164 const QVersionNumber v = QVersionNumber::fromString(QJNIObjectPrivate::getStaticObjectField(
165 "android/os/Build$VERSION", "RELEASE", "Ljava/lang/String;").toString());
166 if (!v.isNull()) {
167 version.m_major = v.majorVersion();
168 version.m_minor = v.minorVersion();
169 version.m_micro = v.microVersion();
170 return version;
171 }
172#endif
173
174 version.m_major = -1;
175 version.m_minor = -1;
176
177 static const struct {
178 uint major : 4;
179 uint minor : 4;
180 } versions[] = {
181 { 1, 0 }, // API level 1
182 { 1, 1 }, // API level 2
183 { 1, 5 }, // API level 3
184 { 1, 6 }, // API level 4
185 { 2, 0 }, // API level 5
186 { 2, 0 }, // API level 6
187 { 2, 1 }, // API level 7
188 { 2, 2 }, // API level 8
189 { 2, 3 }, // API level 9
190 { 2, 3 }, // API level 10
191 { 3, 0 }, // API level 11
192 { 3, 1 }, // API level 12
193 { 3, 2 }, // API level 13
194 { 4, 0 }, // API level 14
195 { 4, 0 }, // API level 15
196 { 4, 1 }, // API level 16
197 { 4, 2 }, // API level 17
198 { 4, 3 }, // API level 18
199 { 4, 4 }, // API level 19
200 { 4, 4 }, // API level 20
201 { 5, 0 }, // API level 21
202 { 5, 1 }, // API level 22
203 { 6, 0 }, // API level 23
204 { 7, 0 }, // API level 24
205 { 7, 1 }, // API level 25
206 { 8, 0 }, // API level 26
207 };
208
209 // This will give us at least the first 2 version components
210 const size_t versionIdx = size_t(QJNIObjectPrivate::getStaticField<jint>(
211 "android/os/Build$VERSION", "SDK_INT")) - 1;
212 if (versionIdx < sizeof(versions) / sizeof(versions[0])) {
213 version.m_major = versions[versionIdx].major;
214 version.m_minor = versions[versionIdx].minor;
215 }
216
217 // API level 6 was exactly version 2.0.1
218 version.m_micro = versionIdx == 5 ? 1 : -1;
219#else
220 version.m_major = -1;
221 version.m_minor = -1;
222 version.m_micro = -1;
223#endif
224 return version;
225}
226#endif
227
228static inline int compareVersionComponents(int lhs, int rhs)
229{
230 return lhs >= 0 && rhs >= 0 ? lhs - rhs : 0;
231}
232
233int QOperatingSystemVersion::compare(const QOperatingSystemVersion &v1,
234 const QOperatingSystemVersion &v2)
235{
236 if (v1.m_major == v2.m_major) {
237 if (v1.m_minor == v2.m_minor) {
238 return compareVersionComponents(lhs: v1.m_micro, rhs: v2.m_micro);
239 }
240 return compareVersionComponents(lhs: v1.m_minor, rhs: v2.m_minor);
241 }
242 return compareVersionComponents(lhs: v1.m_major, rhs: v2.m_major);
243}
244
245/*!
246 \fn int QOperatingSystemVersion::majorVersion() const
247
248 Returns the major version number, that is, the first segment of the
249 operating system's version number.
250
251 See the main class documentation for what the major version number is on a given
252 operating system.
253
254 -1 indicates an unknown or absent version number component.
255
256 \sa minorVersion(), microVersion()
257*/
258
259/*!
260 \fn int QOperatingSystemVersion::minorVersion() const
261
262 Returns the minor version number, that is, the second segment of the
263 operating system's version number.
264
265 See the main class documentation for what the minor version number is on a given
266 operating system.
267
268 -1 indicates an unknown or absent version number component.
269
270 \sa majorVersion(), microVersion()
271*/
272
273/*!
274 \fn int QOperatingSystemVersion::microVersion() const
275
276 Returns the micro version number, that is, the third segment of the
277 operating system's version number.
278
279 See the main class documentation for what the micro version number is on a given
280 operating system.
281
282 -1 indicates an unknown or absent version number component.
283
284 \sa majorVersion(), minorVersion()
285*/
286
287/*!
288 \fn int QOperatingSystemVersion::segmentCount() const
289
290 Returns the number of integers stored in the version number.
291*/
292
293/*!
294 \fn QOperatingSystemVersion::OSType QOperatingSystemVersion::type() const
295
296 Returns the OS type identified by the QOperatingSystemVersion.
297
298 \sa name()
299*/
300
301/*!
302 \fn QOperatingSystemVersion::OSType QOperatingSystemVersion::currentType()
303
304 Returns the current OS type without constructing a QOperatingSystemVersion instance.
305
306 \since 5.10
307
308 \sa current()
309*/
310
311/*!
312 \fn QString QOperatingSystemVersion::name() const
313
314 Returns a string representation of the OS type identified by the QOperatingSystemVersion.
315
316 \sa type()
317*/
318QString QOperatingSystemVersion::name() const
319{
320 switch (type()) {
321 case QOperatingSystemVersion::Windows:
322 return QStringLiteral("Windows");
323 case QOperatingSystemVersion::MacOS: {
324 if (majorVersion() < 10)
325 return QStringLiteral("Mac OS");
326 if (majorVersion() == 10 && minorVersion() < 8)
327 return QStringLiteral("Mac OS X");
328 if (majorVersion() == 10 && minorVersion() < 12)
329 return QStringLiteral("OS X");
330 return QStringLiteral("macOS");
331 }
332 case QOperatingSystemVersion::IOS: {
333 if (majorVersion() < 4)
334 return QStringLiteral("iPhone OS");
335 return QStringLiteral("iOS");
336 }
337 case QOperatingSystemVersion::TvOS:
338 return QStringLiteral("tvOS");
339 case QOperatingSystemVersion::WatchOS:
340 return QStringLiteral("watchOS");
341 case QOperatingSystemVersion::Android:
342 return QStringLiteral("Android");
343 case QOperatingSystemVersion::Unknown:
344 default:
345 return QString();
346 }
347}
348
349/*!
350 \fn bool QOperatingSystemVersion::isAnyOfType(std::initializer_list<OSType> types) const
351
352 Returns whether the OS type identified by the QOperatingSystemVersion
353 matches any of the OS types in \a types.
354*/
355bool QOperatingSystemVersion::isAnyOfType(std::initializer_list<OSType> types) const
356{
357 for (const auto &t : qAsConst(t&: types)) {
358 if (type() == t)
359 return true;
360 }
361 return false;
362}
363
364/*!
365 \variable QOperatingSystemVersion::Windows7
366 \brief a version corresponding to Windows 7 (version 6.1).
367 \since 5.9
368 */
369const QOperatingSystemVersion QOperatingSystemVersion::Windows7 =
370 QOperatingSystemVersion(QOperatingSystemVersion::Windows, 6, 1);
371
372/*!
373 \variable QOperatingSystemVersion::Windows8
374 \brief a version corresponding to Windows 8 (version 6.2).
375 \since 5.9
376 */
377const QOperatingSystemVersion QOperatingSystemVersion::Windows8 =
378 QOperatingSystemVersion(QOperatingSystemVersion::Windows, 6, 2);
379
380/*!
381 \variable QOperatingSystemVersion::Windows8_1
382 \brief a version corresponding to Windows 8.1 (version 6.3).
383 \since 5.9
384 */
385const QOperatingSystemVersion QOperatingSystemVersion::Windows8_1 =
386 QOperatingSystemVersion(QOperatingSystemVersion::Windows, 6, 3);
387
388/*!
389 \variable QOperatingSystemVersion::Windows10
390 \brief a version corresponding to Windows 10 (version 10.0).
391 \since 5.9
392 */
393const QOperatingSystemVersion QOperatingSystemVersion::Windows10 =
394 QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10);
395
396/*!
397 \variable QOperatingSystemVersion::OSXMavericks
398 \brief a version corresponding to OS X Mavericks (version 10.9).
399 \since 5.9
400 */
401const QOperatingSystemVersion QOperatingSystemVersion::OSXMavericks =
402 QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 9);
403
404/*!
405 \variable QOperatingSystemVersion::OSXYosemite
406 \brief a version corresponding to OS X Yosemite (version 10.10).
407 \since 5.9
408 */
409const QOperatingSystemVersion QOperatingSystemVersion::OSXYosemite =
410 QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 10);
411
412/*!
413 \variable QOperatingSystemVersion::OSXElCapitan
414 \brief a version corresponding to OS X El Capitan (version 10.11).
415 \since 5.9
416 */
417const QOperatingSystemVersion QOperatingSystemVersion::OSXElCapitan =
418 QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 11);
419
420/*!
421 \variable QOperatingSystemVersion::MacOSSierra
422 \brief a version corresponding to macOS Sierra (version 10.12).
423 \since 5.9
424 */
425const QOperatingSystemVersion QOperatingSystemVersion::MacOSSierra =
426 QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 12);
427
428/*!
429 \variable QOperatingSystemVersion::MacOSHighSierra
430 \brief a version corresponding to macOS High Sierra (version 10.13).
431 \since 5.9.1
432 */
433const QOperatingSystemVersion QOperatingSystemVersion::MacOSHighSierra =
434 QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 13);
435
436/*!
437 \variable QOperatingSystemVersion::MacOSMojave
438 \brief a version corresponding to macOS Mojave (version 10.14).
439 \since 5.11.2
440 */
441const QOperatingSystemVersion QOperatingSystemVersion::MacOSMojave =
442 QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 14);
443
444/*!
445 \variable QOperatingSystemVersion::MacOSCatalina
446 \brief a version corresponding to macOS Catalina (version 10.15).
447 \since 5.12.5
448 */
449const QOperatingSystemVersion QOperatingSystemVersion::MacOSCatalina =
450 QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 15);
451
452/*!
453 \variable QOperatingSystemVersion::MacOSBigSur
454 \brief a version corresponding to macOS Big Sur
455
456 The actual version number depends on whether the application was built
457 using the Xcode 12 SDK. If it was, the version number corresponds
458 to macOS 11.0. If not it will correspond to macOS 10.16.
459
460 By comparing QOperatingSystemVersion::current() to this constant
461 you will always end up comparing to the right version number.
462 \since 6.0
463 */
464const QOperatingSystemVersion QOperatingSystemVersion::MacOSBigSur = [] {
465#if defined(Q_OS_DARWIN)
466 if (QMacVersion::buildSDK(QMacVersion::ApplicationBinary) >= QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 16))
467 return QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 11, 0);
468 else
469#endif
470 return QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 16);
471}();
472
473/*!
474 \variable QOperatingSystemVersion::AndroidJellyBean
475 \brief a version corresponding to Android Jelly Bean (version 4.1, API level 16).
476 \since 5.9
477 */
478const QOperatingSystemVersion QOperatingSystemVersion::AndroidJellyBean =
479 QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 1);
480
481/*!
482 \variable QOperatingSystemVersion::AndroidJellyBean_MR1
483 \brief a version corresponding to Android Jelly Bean, maintenance release 1
484 (version 4.2, API level 17).
485 \since 5.9
486 */
487const QOperatingSystemVersion QOperatingSystemVersion::AndroidJellyBean_MR1 =
488 QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 2);
489
490/*!
491 \variable QOperatingSystemVersion::AndroidJellyBean_MR2
492 \brief a version corresponding to Android Jelly Bean, maintenance release 2
493 (version 4.3, API level 18).
494 \since 5.9
495 */
496const QOperatingSystemVersion QOperatingSystemVersion::AndroidJellyBean_MR2 =
497 QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 3);
498
499/*!
500 \variable QOperatingSystemVersion::AndroidKitKat
501 \brief a version corresponding to Android KitKat (versions 4.4 & 4.4W, API levels 19 & 20).
502 \since 5.9
503 */
504const QOperatingSystemVersion QOperatingSystemVersion::AndroidKitKat =
505 QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 4);
506
507/*!
508 \variable QOperatingSystemVersion::AndroidLollipop
509 \brief a version corresponding to Android Lollipop (version 5.0, API level 21).
510 \since 5.9
511 */
512const QOperatingSystemVersion QOperatingSystemVersion::AndroidLollipop =
513 QOperatingSystemVersion(QOperatingSystemVersion::Android, 5, 0);
514
515/*!
516 \variable QOperatingSystemVersion::AndroidLollipop_MR1
517 \brief a version corresponding to Android Lollipop, maintenance release 1
518 (version 5.1, API level 22).
519 \since 5.9
520 */
521const QOperatingSystemVersion QOperatingSystemVersion::AndroidLollipop_MR1 =
522 QOperatingSystemVersion(QOperatingSystemVersion::Android, 5, 1);
523
524/*!
525 \variable QOperatingSystemVersion::AndroidMarshmallow
526 \brief a version corresponding to Android Marshmallow (version 6.0, API level 23).
527 \since 5.9
528 */
529const QOperatingSystemVersion QOperatingSystemVersion::AndroidMarshmallow =
530 QOperatingSystemVersion(QOperatingSystemVersion::Android, 6, 0);
531
532/*!
533 \variable QOperatingSystemVersion::AndroidNougat
534 \brief a version corresponding to Android Nougat (version 7.0, API level 24).
535 \since 5.9
536 */
537const QOperatingSystemVersion QOperatingSystemVersion::AndroidNougat =
538 QOperatingSystemVersion(QOperatingSystemVersion::Android, 7, 0);
539
540/*!
541 \variable QOperatingSystemVersion::AndroidNougat_MR1
542 \brief a version corresponding to Android Nougat, maintenance release 1
543 (version 7.0, API level 25).
544 \since 5.9
545 */
546const QOperatingSystemVersion QOperatingSystemVersion::AndroidNougat_MR1 =
547 QOperatingSystemVersion(QOperatingSystemVersion::Android, 7, 1);
548
549/*!
550 \variable QOperatingSystemVersion::AndroidOreo
551 \brief a version corresponding to Android Oreo (version 8.0, API level 26).
552 \since 5.9.2
553 */
554const QOperatingSystemVersion QOperatingSystemVersion::AndroidOreo =
555 QOperatingSystemVersion(QOperatingSystemVersion::Android, 8, 0);
556
557#ifndef QT_NO_DEBUG_STREAM
558QDebug operator<<(QDebug debug, const QOperatingSystemVersion &ov)
559{
560 QDebugStateSaver saver(debug);
561 debug.nospace();
562 debug << "QOperatingSystemVersion(" << ov.name()
563 << ", " << ov.majorVersion() << '.' << ov.minorVersion()
564 << '.' << ov.microVersion() << ')';
565 return debug;
566}
567#endif // !QT_NO_DEBUG_STREAM
568
569QT_END_NAMESPACE
570

source code of qtbase/src/corelib/global/qoperatingsystemversion.cpp