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