summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorOswald Buddenhagen <oswald.buddenhagen@qt.io>2017-11-20 13:48:33 +0100
committerOswald Buddenhagen <oswald.buddenhagen@qt.io>2017-11-20 13:48:33 +0100
commitbb3872d60975724a50ff910b6dd108d1944db597 (patch)
treece1c96729a1a4691a322b36cfd5429c020403ccc /src
parentb72b5cd76004e54dc00c0f1133f4d59192ef154a (diff)
parent8e387e7fa758ded3f0d096dcf5fe13a22521dad7 (diff)
Merge 5.10 into 5.10.0
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/libpng/ANNOUNCE77
-rw-r--r--src/3rdparty/libpng/CHANGES51
-rw-r--r--src/3rdparty/libpng/LICENSE4
-rw-r--r--src/3rdparty/libpng/README2
-rw-r--r--src/3rdparty/libpng/libpng-manual.txt21
-rw-r--r--src/3rdparty/libpng/png.c32
-rw-r--r--src/3rdparty/libpng/png.h28
-rw-r--r--src/3rdparty/libpng/pngconf.h2
-rw-r--r--src/3rdparty/libpng/pnglibconf.h4
-rw-r--r--src/3rdparty/libpng/pngread.c14
-rw-r--r--src/3rdparty/libpng/pngrtran.c22
-rw-r--r--src/3rdparty/libpng/pngrutil.c47
-rw-r--r--src/3rdparty/libpng/pngtrans.c6
-rw-r--r--src/3rdparty/libpng/pngwrite.c2
-rw-r--r--src/3rdparty/libpng/qt_attribution.json2
-rw-r--r--src/corelib/global/qcompilerdetection.h6
-rw-r--r--src/corelib/global/qfloat16.h2
-rw-r--r--src/corelib/global/qrandom.cpp926
-rw-r--r--src/corelib/global/qrandom.h183
-rw-r--r--src/corelib/global/qrandom_p.h18
-rw-r--r--src/corelib/io/qfilesystemwatcher_win.cpp4
-rw-r--r--src/corelib/io/qiodevice.cpp2
-rw-r--r--src/corelib/io/qprocess_win.cpp7
-rw-r--r--src/corelib/io/qstorageinfo_unix.cpp34
-rw-r--r--src/corelib/io/qtemporaryfile.cpp2
-rw-r--r--src/corelib/thread/qmutex.h6
-rw-r--r--src/corelib/thread/qsemaphore.h6
-rw-r--r--src/corelib/tools/qhash.cpp1
-rw-r--r--src/corelib/tools/qsimd.cpp26
-rw-r--r--src/corelib/tools/qversionnumber.cpp4
-rw-r--r--src/gui/image/qpixmap_blitter.cpp3
-rw-r--r--src/gui/kernel/qhighdpiscaling_p.h3
-rw-r--r--src/gui/kernel/qopenglcontext.cpp1
-rw-r--r--src/gui/kernel/qwindow.cpp5
-rw-r--r--src/gui/opengl/qopenglgradientcache.cpp3
-rw-r--r--src/gui/painting/qcoregraphics.mm1
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp3
-rw-r--r--src/gui/painting/qtextureglyphcache.cpp3
-rw-r--r--src/gui/text/qfont.cpp22
-rw-r--r--src/network/access/qhttp2protocolhandler.cpp2
-rw-r--r--src/network/kernel/kernel.pri2
-rw-r--r--src/network/kernel/qdnslookup.cpp11
-rw-r--r--src/network/socket/qnativesocketengine_win.cpp20
-rw-r--r--src/opengl/gl2paintengineex/qglgradientcache.cpp3
-rw-r--r--src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp30
-rw-r--r--src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.h6
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm32
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm16
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.mm11
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm15
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm1
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration.cpp32
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration.h3
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.cpp8
-rw-r--r--src/plugins/platforms/windows/qwindowssystemtrayicon.cpp2
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp2
-rw-r--r--src/plugins/sqldrivers/oci/qsql_oci.cpp2
-rw-r--r--src/plugins/sqldrivers/psql/qsql_psql.cpp191
-rw-r--r--src/plugins/sqldrivers/psql/qsql_psql_p.h24
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac.mm567
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac_p.h4
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac_p_p.h72
-rw-r--r--src/testlib/qtesthelpers_p.h112
-rw-r--r--src/testlib/testlib.pro3
-rw-r--r--src/widgets/itemviews/qheaderview.cpp8
-rw-r--r--src/widgets/itemviews/qlistview.cpp15
-rw-r--r--src/widgets/kernel/qshortcut.cpp2
-rw-r--r--src/widgets/kernel/qwidget.cpp2
-rw-r--r--src/widgets/widgets/qabstractbutton.cpp3
-rw-r--r--src/widgets/widgets/qmainwindow.cpp1
-rw-r--r--src/widgets/widgets/qmenu.cpp114
-rw-r--r--src/widgets/widgets/qmenu_p.h151
-rw-r--r--src/widgets/widgets/qmenubar.cpp54
-rw-r--r--src/widgets/widgets/qmenubar_p.h4
78 files changed, 1883 insertions, 1237 deletions
diff --git a/src/3rdparty/libpng/ANNOUNCE b/src/3rdparty/libpng/ANNOUNCE
index 3cbe5a926e..0f66c0d1da 100644
--- a/src/3rdparty/libpng/ANNOUNCE
+++ b/src/3rdparty/libpng/ANNOUNCE
@@ -1,4 +1,4 @@
-Libpng 1.6.32 - August 24, 2017
+Libpng 1.6.34 - September 29, 2017
This is a public release of libpng, intended for use in production codes.
@@ -7,79 +7,24 @@ Files available for download:
Source files with LF line endings (for Unix/Linux) and with a
"configure" script
- libpng-1.6.32.tar.xz (LZMA-compressed, recommended)
- libpng-1.6.32.tar.gz
+ libpng-1.6.34.tar.xz (LZMA-compressed, recommended)
+ libpng-1.6.34.tar.gz
Source files with CRLF line endings (for Windows), without the
"configure" script
- lpng1632.7z (LZMA-compressed, recommended)
- lpng1632.zip
+ lpng1634.7z (LZMA-compressed, recommended)
+ lpng1634.zip
Other information:
- libpng-1.6.32-README.txt
- libpng-1.6.32-LICENSE.txt
- libpng-1.6.32-*.asc (armored detached GPG signatures)
+ libpng-1.6.34-README.txt
+ libpng-1.6.34-LICENSE.txt
+ libpng-1.6.34-*.asc (armored detached GPG signatures)
-Changes since the last public release (1.6.31):
- Avoid possible NULL dereference in png_handle_eXIf when benign_errors
- are allowed. Avoid leaking the input buffer "eXIf_buf".
- Eliminated png_ptr->num_exif member from pngstruct.h and added num_exif
- to arguments for png_get_eXIf() and png_set_eXIf().
- Added calls to png_handle_eXIf(() in pngread.c and png_write_eXIf() in
- pngwrite.c, and made various other fixes to png_write_eXIf().
- Changed name of png_get_eXIF and png_set_eXIf() to png_get_eXIf_1() and
- png_set_eXIf_1(), respectively, to avoid breaking API compatibility
- with libpng-1.6.31.
- Updated contrib/libtests/pngunknown.c with eXIf chunk.
- Initialized btoa[] in pngstest.c
- Stop memory leak when returning from png_handle_eXIf() with an error
- (Bug report from the OSS-fuzz project).
- Replaced local eXIf_buf with info_ptr-eXIf_buf in png_handle_eXIf().
- Update libpng.3 and libpng-manual.txt about eXIf functions.
- Restored png_get_eXIf() and png_set_eXIf() to maintain API compatability.
- Removed png_get_eXIf_1() and png_set_eXIf_1().
- Check length of all chunks except IDAT against user limit to fix an
- OSS-fuzz issue.
- Check length of IDAT against maximum possible IDAT size, accounting
- for height, rowbytes, interlacing and zlib/deflate overhead.
- Restored png_get_eXIf_1() and png_set_eXIf_1(), because strlen(eXIf_buf)
- does not work (the eXIf chunk data can contain zeroes).
- Require cmake-2.8.8 in CMakeLists.txt. Revised symlink creation,
- no longer using deprecated cmake LOCATION feature (Clifford Yapp).
- Fixed five-byte error in the calculation of IDAT maximum possible size.
- Moved chunk-length check into a png_check_chunk_length() private
- function (Suggested by Max Stepin).
- Moved bad pngs from tests to contrib/libtests/crashers
- Moved testing of bad pngs into a separate tests/pngtest-badpngs script
- Added the --xfail (expected FAIL) option to pngtest.c. It writes XFAIL
- in the output but PASS for the libpng test.
- Require cmake-3.0.2 in CMakeLists.txt (Clifford Yapp).
- Fix "const" declaration info_ptr argument to png_get_eXIf_1() and the
- num_exif argument to png_get_eXIf_1() (Github Issue 171).
- Added "eXIf" to "chunks_to_ignore[]" in png_set_keep_unknown_chunks().
- Added huge_IDAT.png and empty_ancillary_chunks.png to testpngs/crashers.
- Make pngtest --strict, --relax, --xfail options imply -m (multiple).
- Removed unused chunk_name parameter from png_check_chunk_length().
- Relocated setting free_me for eXIf data, to stop an OSS-fuzz leak.
- Initialize profile_header[] in png_handle_iCCP() to fix OSS-fuzz issue.
- Initialize png_ptr->row_buf[0] to 255 in png_read_row() to fix OSS-fuzz UMR.
- Attempt to fix a UMR in png_set_text_2() to fix OSS-fuzz issue.
- Increase minimum zlib stream from 9 to 14 in png_handle_iCCP(), to account
- for the minimum 'deflate' stream, and relocate the test to a point
- after the keyword has been read.
- Check that the eXIf chunk has at least 2 bytes and begins with "II" or "MM".
- Added a set of "huge_xxxx_chunk.png" files to contrib/testpngs/crashers,
- one for each known chunk type, with length = 2GB-1.
- Check for 0 return from png_get_rowbytes() and added some (size_t) typecasts
- in contrib/pngminus/*.c to stop some Coverity issues (162705, 162706,
- and 162707).
- Renamed chunks in contrib/testpngs/crashers to avoid having files whose
- names differ only in case; this causes problems with some platforms
- (github issue #172).
- Added contrib/oss-fuzz directory which contains files used by the oss-fuzz
- project (https://github.com/google/oss-fuzz/tree/master/projects/libpng).
+Changes since the last public release (1.6.33):
+ Removed contrib/pngsuite/i*.png; some of these were incorrect and caused
+ test failures.
Send comments/corrections/commendations to png-mng-implement at lists.sf.net
(subscription required; visit
diff --git a/src/3rdparty/libpng/CHANGES b/src/3rdparty/libpng/CHANGES
index 14e60dd269..4b82118910 100644
--- a/src/3rdparty/libpng/CHANGES
+++ b/src/3rdparty/libpng/CHANGES
@@ -833,7 +833,7 @@ Version 1.0.7beta11 [May 7, 2000]
Removed the new PNG_CREATED_READ_STRUCT and PNG_CREATED_WRITE_STRUCT modes
which are no longer used.
Eliminated the three new members of png_text when PNG_LEGACY_SUPPORTED is
- defined or when neither PNG_READ_iTXt_SUPPORTED nor PNG_WRITE_iTXT_SUPPORTED
+ defined or when neither PNG_READ_iTXt_SUPPORTED nor PNG_WRITE_iTXt_SUPPORTED
is defined.
Made PNG_NO_READ|WRITE_iTXt the default setting, to avoid memory
overrun when old applications fill the info_ptr->text structure directly.
@@ -5939,7 +5939,7 @@ Version 1.6.32beta06 [August 2, 2017]
Version 1.6.32beta07 [August 3, 2017]
Check length of all chunks except IDAT against user limit to fix an
- OSS-fuzz issue.
+ OSS-fuzz issue (Fixes CVE-2017-12652).
Version 1.6.32beta08 [August 3, 2017]
Check length of IDAT against maximum possible IDAT size, accounting
@@ -5994,6 +5994,53 @@ Version 1.6.32rc02 [August 22, 2017]
Version 1.6.32 [August 24, 2017]
No changes.
+Version 1.6.33beta01 [August 28, 2017]
+ Added PNGMINUS_UNUSED macro to contrib/pngminus/p*.c and added missing
+ parenthesis in contrib/pngminus/pnm2png.c (bug report by Christian Hesse).
+ Fixed off-by-one error in png_do_check_palette_indexes() (Bug report
+ by Mick P., Source Forge Issue #269).
+
+Version 1.6.33beta02 [September 3, 2017]
+ Initialize png_handler.row_ptr in contrib/oss-fuzz/libpng_read_fuzzer.cc
+ to fix shortlived oss-fuzz issue 3234.
+ Compute a larger limit on IDAT because some applications write a deflate
+ buffer for each row (Bug report by Andrew Church).
+ Use current date (DATE) instead of release-date (RDATE) in last
+ changed date of contrib/oss-fuzz files.
+ Enabled ARM support in CMakeLists.txt (Bernd Kuhls).
+
+Version 1.6.33beta03 [September 14, 2017]
+ Fixed incorrect typecast of some arguments to png_malloc() and
+ png_calloc() that were png_uint_32 instead of png_alloc_size_t
+ (Bug report by "irwir" in Github libpng issue #175).
+ Use pnglibconf.h.prebuilt when building for ANDROID with cmake (Github
+ issue 162, by rcdailey).
+
+Version 1.6.33rc01 [September 20, 2017]
+ Initialize memory allocated by png_inflate to zero, using memset, to
+ stop an oss-fuzz "use of uninitialized value" detection in png_set_text_2()
+ due to truncated iTXt or zTXt chunk.
+ Initialize memory allocated by png_read_buffer to zero, using memset, to
+ stop an oss-fuzz "use of uninitialized value" detection in
+ png_icc_check_tag_table() due to truncated iCCP chunk.
+ Removed a redundant test (suggested by "irwir" in Github issue #180).
+
+Version 1.6.33rc02 [September 23, 2017]
+ Added an interlaced version of each file in contrib/pngsuite.
+ Relocate new memset() call in pngrutil.c.
+ Removed more redundant tests (suggested by "irwir" in Github issue #180).
+ Add support for loading images with associated alpha in the Simplified
+ API (Samuel Williams).
+
+Version 1.6.33 [September 28, 2017]
+ Revert contrib/oss-fuzz/libpng_read_fuzzer.cc to libpng-1.6.32 state.
+ Initialize png_handler.row_ptr in contrib/oss-fuzz/libpng_read_fuzzer.cc
+ Add end_info structure and png_read_end() to the libpng fuzzer.
+
+Version 1.6.34 [September 29, 2017]
+ Removed contrib/pngsuite/i*.png; some of these were incorrect and caused
+ test failures.
+
Send comments/corrections/commendations to png-mng-implement at lists.sf.net
(subscription required; visit
https://lists.sourceforge.net/lists/listinfo/png-mng-implement
diff --git a/src/3rdparty/libpng/LICENSE b/src/3rdparty/libpng/LICENSE
index e803911d37..4cda4fa0ad 100644
--- a/src/3rdparty/libpng/LICENSE
+++ b/src/3rdparty/libpng/LICENSE
@@ -10,7 +10,7 @@ this sentence.
This code is released under the libpng license.
-libpng versions 1.0.7, July 1, 2000 through 1.6.32, August 24, 2017 are
+libpng versions 1.0.7, July 1, 2000 through 1.6.34, September 29, 2017 are
Copyright (c) 2000-2002, 2004, 2006-2017 Glenn Randers-Pehrson, are
derived from libpng-1.0.6, and are distributed according to the same
disclaimer and license as libpng-1.0.6 with the following individuals
@@ -130,4 +130,4 @@ any encryption software. See the EAR, paragraphs 734.3(b)(3) and
Glenn Randers-Pehrson
glennrp at users.sourceforge.net
-April 1, 2017
+September 29, 2017
diff --git a/src/3rdparty/libpng/README b/src/3rdparty/libpng/README
index 71292715eb..0da5a5ef83 100644
--- a/src/3rdparty/libpng/README
+++ b/src/3rdparty/libpng/README
@@ -1,4 +1,4 @@
-README for libpng version 1.6.32 - August 24, 2017 (shared library 16.0)
+README for libpng version 1.6.34 - September 29, 2017 (shared library 16.0)
See the note about version numbers near the top of png.h
See INSTALL for instructions on how to install libpng.
diff --git a/src/3rdparty/libpng/libpng-manual.txt b/src/3rdparty/libpng/libpng-manual.txt
index e34b1436f5..d4407ef2ea 100644
--- a/src/3rdparty/libpng/libpng-manual.txt
+++ b/src/3rdparty/libpng/libpng-manual.txt
@@ -1,6 +1,6 @@
libpng-manual.txt - A description on how to use and modify libpng
- libpng version 1.6.32 - August 24, 2017
+ libpng version 1.6.34 - September 29, 2017
Updated and distributed by Glenn Randers-Pehrson
<glennrp at users.sourceforge.net>
Copyright (c) 1998-2017 Glenn Randers-Pehrson
@@ -11,7 +11,7 @@ libpng-manual.txt - A description on how to use and modify libpng
Based on:
- libpng versions 0.97, January 1998, through 1.6.32 - August 24, 2017
+ libpng versions 0.97, January 1998, through 1.6.34 - September 29, 2017
Updated and distributed by Glenn Randers-Pehrson
Copyright (c) 1998-2017 Glenn Randers-Pehrson
@@ -986,8 +986,17 @@ premultiplication.
png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);
-This is the default libpng handling of the alpha channel - it is not
-pre-multiplied into the color components. In addition the call states
+Choices for the alpha_mode are
+
+ PNG_ALPHA_PNG 0 /* according to the PNG standard */
+ PNG_ALPHA_STANDARD 1 /* according to Porter/Duff */
+ PNG_ALPHA_ASSOCIATED 1 /* as above; this is the normal practice */
+ PNG_ALPHA_PREMULTIPLIED 1 /* as above */
+ PNG_ALPHA_OPTIMIZED 2 /* 'PNG' for opaque pixels, else 'STANDARD' */
+ PNG_ALPHA_BROKEN 3 /* the alpha channel is gamma encoded */
+
+PNG_ALPHA_PNG is the default libpng handling of the alpha channel. It is not
+pre-multiplied into the color components. In addition the call states
that the output is for a sRGB system and causes all PNG files without gAMA
chunks to be assumed to be encoded using sRGB.
@@ -1002,7 +1011,7 @@ early Mac systems behaved.
This is the classic Jim Blinn approach and will work in academic
environments where everything is done by the book. It has the shortcoming
of assuming that input PNG data with no gamma information is linear - this
-is unlikely to be correct unless the PNG files where generated locally.
+is unlikely to be correct unless the PNG files were generated locally.
Most of the time the output precision will be so low as to show
significant banding in dark areas of the image.
@@ -5405,7 +5414,7 @@ Since the PNG Development group is an ad-hoc body, we can't make
an official declaration.
This is your unofficial assurance that libpng from version 0.71 and
-upward through 1.6.32 are Y2K compliant. It is my belief that earlier
+upward through 1.6.34 are Y2K compliant. It is my belief that earlier
versions were also Y2K compliant.
Libpng only has two year fields. One is a 2-byte unsigned integer
diff --git a/src/3rdparty/libpng/png.c b/src/3rdparty/libpng/png.c
index 2352df13cb..ff02c56518 100644
--- a/src/3rdparty/libpng/png.c
+++ b/src/3rdparty/libpng/png.c
@@ -1,7 +1,7 @@
/* png.c - location for general purpose libpng functions
*
- * Last changed in libpng 1.6.32 [August 24, 2017]
+ * Last changed in libpng 1.6.33 [September 28, 2017]
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -14,7 +14,7 @@
#include "pngpriv.h"
/* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_32 Your_png_h_is_not_version_1_6_32;
+typedef png_libpng_version_1_6_34 Your_png_h_is_not_version_1_6_34;
#ifdef __GNUC__
/* The version tests may need to be added to, but the problem warning has
@@ -816,14 +816,14 @@ png_get_copyright(png_const_structrp png_ptr)
#else
# ifdef __STDC__
return PNG_STRING_NEWLINE \
- "libpng version 1.6.32 - August 24, 2017" PNG_STRING_NEWLINE \
+ "libpng version 1.6.34 - September 29, 2017" PNG_STRING_NEWLINE \
"Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson" \
PNG_STRING_NEWLINE \
"Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
"Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
PNG_STRING_NEWLINE;
# else
- return "libpng version 1.6.32 - August 24, 2017\
+ return "libpng version 1.6.34 - September 29, 2017\
Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson\
Copyright (c) 1996-1997 Andreas Dilger\
Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";
@@ -1913,12 +1913,12 @@ png_colorspace_set_sRGB(png_const_structrp png_ptr, png_colorspacerp colorspace,
*/
if (intent < 0 || intent >= PNG_sRGB_INTENT_LAST)
return png_icc_profile_error(png_ptr, colorspace, "sRGB",
- (unsigned)intent, "invalid sRGB rendering intent");
+ (png_alloc_size_t)intent, "invalid sRGB rendering intent");
if ((colorspace->flags & PNG_COLORSPACE_HAVE_INTENT) != 0 &&
colorspace->rendering_intent != intent)
return png_icc_profile_error(png_ptr, colorspace, "sRGB",
- (unsigned)intent, "inconsistent rendering intents");
+ (png_alloc_size_t)intent, "inconsistent rendering intents");
if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0)
{
@@ -1979,7 +1979,6 @@ icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace,
if (profile_length < 132)
return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
"too short");
-
return 1;
}
@@ -2224,22 +2223,23 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
* being in range. All defined tag types have an 8 byte header - a 4 byte
* type signature then 0.
*/
+
+ /* This is a hard error; potentially it can cause read outside the
+ * profile.
+ */
+ if (tag_start > profile_length || tag_length > profile_length - tag_start)
+ return png_icc_profile_error(png_ptr, colorspace, name, tag_id,
+ "ICC profile tag outside profile");
+
if ((tag_start & 3) != 0)
{
- /* CNHP730S.icc shipped with Microsoft Windows 64 violates this, it is
+ /* CNHP730S.icc shipped with Microsoft Windows 64 violates this; it is
* only a warning here because libpng does not care about the
* alignment.
*/
(void)png_icc_profile_error(png_ptr, NULL, name, tag_id,
"ICC profile tag start not a multiple of 4");
}
-
- /* This is a hard error; potentially it can cause read outside the
- * profile.
- */
- if (tag_start > profile_length || tag_length > profile_length - tag_start)
- return png_icc_profile_error(png_ptr, colorspace, name, tag_id,
- "ICC profile tag outside profile");
}
return 1; /* success, maybe with warnings */
@@ -3761,7 +3761,7 @@ png_log16bit(png_uint_32 x)
* of getting this accuracy in practice.
*
* To deal with this the following exp() function works out the exponent of the
- * frational part of the logarithm by using an accurate 32-bit value from the
+ * fractional part of the logarithm by using an accurate 32-bit value from the
* top four fractional bits then multiplying in the remaining bits.
*/
static const png_uint_32
diff --git a/src/3rdparty/libpng/png.h b/src/3rdparty/libpng/png.h
index 51ac8abe74..4c873f5c22 100644
--- a/src/3rdparty/libpng/png.h
+++ b/src/3rdparty/libpng/png.h
@@ -1,7 +1,7 @@
/* png.h - header file for PNG reference library
*
- * libpng version 1.6.32, August 24, 2017
+ * libpng version 1.6.34, September 29, 2017
*
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
@@ -12,7 +12,7 @@
* Authors and maintainers:
* libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat
* libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
- * libpng versions 0.97, January 1998, through 1.6.32, August 24, 2017:
+ * libpng versions 0.97, January 1998, through 1.6.34, September 29, 2017:
* Glenn Randers-Pehrson.
* See also "Contributing Authors", below.
*/
@@ -25,7 +25,7 @@
*
* This code is released under the libpng license.
*
- * libpng versions 1.0.7, July 1, 2000 through 1.6.32, August 24, 2017 are
+ * libpng versions 1.0.7, July 1, 2000 through 1.6.34, September 29, 2017 are
* Copyright (c) 2000-2002, 2004, 2006-2017 Glenn Randers-Pehrson, are
* derived from libpng-1.0.6, and are distributed according to the same
* disclaimer and license as libpng-1.0.6 with the following individuals
@@ -209,11 +209,11 @@
* ...
* 1.0.19 10 10019 10.so.0.19[.0]
* ...
- * 1.2.57 13 10257 12.so.0.57[.0]
+ * 1.2.59 13 10257 12.so.0.59[.0]
* ...
- * 1.5.28 15 10527 15.so.15.28[.0]
+ * 1.5.30 15 10527 15.so.15.30[.0]
* ...
- * 1.6.32 16 10632 16.so.16.32[.0]
+ * 1.6.34 16 10633 16.so.16.34[.0]
*
* Henceforth the source version will match the shared-library major
* and minor numbers; the shared-library major version number will be
@@ -241,13 +241,13 @@
* Y2K compliance in libpng:
* =========================
*
- * August 24, 2017
+ * September 29, 2017
*
* Since the PNG Development group is an ad-hoc body, we can't make
* an official declaration.
*
* This is your unofficial assurance that libpng from version 0.71 and
- * upward through 1.6.32 are Y2K compliant. It is my belief that
+ * upward through 1.6.34 are Y2K compliant. It is my belief that
* earlier versions were also Y2K compliant.
*
* Libpng only has two year fields. One is a 2-byte unsigned integer
@@ -309,8 +309,8 @@
*/
/* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.32"
-#define PNG_HEADER_VERSION_STRING " libpng version 1.6.32 - August 24, 2017\n"
+#define PNG_LIBPNG_VER_STRING "1.6.34"
+#define PNG_HEADER_VERSION_STRING " libpng version 1.6.34 - September 29, 2017\n"
#define PNG_LIBPNG_VER_SONUM 16
#define PNG_LIBPNG_VER_DLLNUM 16
@@ -318,7 +318,7 @@
/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
#define PNG_LIBPNG_VER_MAJOR 1
#define PNG_LIBPNG_VER_MINOR 6
-#define PNG_LIBPNG_VER_RELEASE 32
+#define PNG_LIBPNG_VER_RELEASE 34
/* This should match the numeric part of the final component of
* PNG_LIBPNG_VER_STRING, omitting any leading zero:
@@ -349,7 +349,7 @@
* version 1.0.0 was mis-numbered 100 instead of 10000). From
* version 1.0.1 it's xxyyzz, where x=major, y=minor, z=release
*/
-#define PNG_LIBPNG_VER 10632 /* 1.6.32 */
+#define PNG_LIBPNG_VER 10634 /* 1.6.34 */
/* Library configuration: these options cannot be changed after
* the library has been built.
@@ -459,7 +459,7 @@ extern "C" {
/* This triggers a compiler error in png.c, if png.c and png.h
* do not agree upon the version number.
*/
-typedef char* png_libpng_version_1_6_32;
+typedef char* png_libpng_version_1_6_34;
/* Basic control structions. Read libpng-manual.txt or libpng.3 for more info.
*
@@ -2819,6 +2819,8 @@ typedef struct
# define PNG_FORMAT_FLAG_AFIRST 0x20U /* alpha channel comes first */
#endif
+#define PNG_FORMAT_FLAG_ASSOCIATED_ALPHA 0x40U /* alpha channel is associated */
+
/* Commonly used formats have predefined macros.
*
* First the single byte (sRGB) formats:
diff --git a/src/3rdparty/libpng/pngconf.h b/src/3rdparty/libpng/pngconf.h
index c0f15547be..d13b13e57a 100644
--- a/src/3rdparty/libpng/pngconf.h
+++ b/src/3rdparty/libpng/pngconf.h
@@ -1,7 +1,7 @@
/* pngconf.h - machine configurable file for libpng
*
- * libpng version 1.6.32, August 24, 2017
+ * libpng version 1.6.34, September 29, 2017
*
* Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
diff --git a/src/3rdparty/libpng/pnglibconf.h b/src/3rdparty/libpng/pnglibconf.h
index 9e45f73129..53b5e442c4 100644
--- a/src/3rdparty/libpng/pnglibconf.h
+++ b/src/3rdparty/libpng/pnglibconf.h
@@ -1,8 +1,8 @@
-/* libpng 1.6.32 STANDARD API DEFINITION */
+/* libpng 1.6.34 STANDARD API DEFINITION */
/* pnglibconf.h - library build configuration */
-/* Libpng version 1.6.32 - August 24, 2017 */
+/* Libpng version 1.6.34 - September 29, 2017 */
/* Copyright (c) 1998-2017 Glenn Randers-Pehrson */
diff --git a/src/3rdparty/libpng/pngread.c b/src/3rdparty/libpng/pngread.c
index e34ddd99a0..da32e9ad9c 100644
--- a/src/3rdparty/libpng/pngread.c
+++ b/src/3rdparty/libpng/pngread.c
@@ -1,7 +1,7 @@
/* pngread.c - read a PNG file
*
- * Last changed in libpng 1.6.32 [August 24, 2017]
+ * Last changed in libpng 1.6.33 [September 28, 2017]
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -3759,7 +3759,13 @@ png_image_read_direct(png_voidp argument)
mode = PNG_ALPHA_PNG;
output_gamma = PNG_DEFAULT_sRGB;
}
-
+
+ if ((change & PNG_FORMAT_FLAG_ASSOCIATED_ALPHA) != 0)
+ {
+ mode = PNG_ALPHA_OPTIMIZED;
+ change &= ~PNG_FORMAT_FLAG_ASSOCIATED_ALPHA;
+ }
+
/* If 'do_local_background' is set check for the presence of gamma
* correction; this is part of the work-round for the libpng bug
* described above.
@@ -3985,6 +3991,10 @@ png_image_read_direct(png_voidp argument)
else if (do_local_compose != 0) /* internal error */
png_error(png_ptr, "png_image_read: alpha channel lost");
+ if ((format & PNG_FORMAT_FLAG_ASSOCIATED_ALPHA) != 0) {
+ info_format |= PNG_FORMAT_FLAG_ASSOCIATED_ALPHA;
+ }
+
if (info_ptr->bit_depth == 16)
info_format |= PNG_FORMAT_FLAG_LINEAR;
diff --git a/src/3rdparty/libpng/pngrtran.c b/src/3rdparty/libpng/pngrtran.c
index 9a30ddf22b..c189650313 100644
--- a/src/3rdparty/libpng/pngrtran.c
+++ b/src/3rdparty/libpng/pngrtran.c
@@ -1,7 +1,7 @@
/* pngrtran.c - transforms the data in a row for PNG readers
*
- * Last changed in libpng 1.6.31 [July 27, 2017]
+ * Last changed in libpng 1.6.33 [September 28, 2017]
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -430,7 +430,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
int i;
png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)((png_uint_32)num_palette * (sizeof (png_byte))));
+ (png_alloc_size_t)((png_uint_32)num_palette * (sizeof (png_byte))));
for (i = 0; i < num_palette; i++)
png_ptr->quantize_index[i] = (png_byte)i;
}
@@ -447,7 +447,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
/* Initialize an array to sort colors */
png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)((png_uint_32)num_palette * (sizeof (png_byte))));
+ (png_alloc_size_t)((png_uint_32)num_palette * (sizeof (png_byte))));
/* Initialize the quantize_sort array */
for (i = 0; i < num_palette; i++)
@@ -581,9 +581,11 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
/* Initialize palette index arrays */
png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)((png_uint_32)num_palette * (sizeof (png_byte))));
+ (png_alloc_size_t)((png_uint_32)num_palette *
+ (sizeof (png_byte))));
png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)((png_uint_32)num_palette * (sizeof (png_byte))));
+ (png_alloc_size_t)((png_uint_32)num_palette *
+ (sizeof (png_byte))));
/* Initialize the sort array */
for (i = 0; i < num_palette; i++)
@@ -592,7 +594,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
png_ptr->palette_to_index[i] = (png_byte)i;
}
- hash = (png_dsortpp)png_calloc(png_ptr, (png_uint_32)(769 *
+ hash = (png_dsortpp)png_calloc(png_ptr, (png_alloc_size_t)(769 *
(sizeof (png_dsortp))));
num_new_palette = num_palette;
@@ -623,7 +625,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
{
t = (png_dsortp)png_malloc_warn(png_ptr,
- (png_uint_32)(sizeof (png_dsort)));
+ (png_alloc_size_t)(sizeof (png_dsort)));
if (t == NULL)
break;
@@ -748,9 +750,9 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
png_size_t num_entries = ((png_size_t)1 << total_bits);
png_ptr->palette_lookup = (png_bytep)png_calloc(png_ptr,
- (png_uint_32)(num_entries * (sizeof (png_byte))));
+ (png_alloc_size_t)(num_entries * (sizeof (png_byte))));
- distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries *
+ distance = (png_bytep)png_malloc(png_ptr, (png_alloc_size_t)(num_entries *
(sizeof (png_byte))));
memset(distance, 0xff, num_entries * (sizeof (png_byte)));
@@ -3322,7 +3324,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr)
== png_ptr->trans_color.gray)
{
unsigned int tmp = *sp & (0x0f0f >> (4 - shift));
- tmp |=
+ tmp |=
(unsigned int)(png_ptr->background.gray << shift);
*sp = (png_byte)(tmp & 0xff);
}
diff --git a/src/3rdparty/libpng/pngrutil.c b/src/3rdparty/libpng/pngrutil.c
index a4fa71457b..8692933bd8 100644
--- a/src/3rdparty/libpng/pngrutil.c
+++ b/src/3rdparty/libpng/pngrutil.c
@@ -1,7 +1,7 @@
/* pngrutil.c - utilities to read a PNG file
*
- * Last changed in libpng 1.6.32 [August 24, 2017]
+ * Last changed in libpng 1.6.33 [September 28, 2017]
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -314,6 +314,7 @@ png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn)
if (buffer != NULL)
{
+ memset(buffer, 0, new_size); /* just in case */
png_ptr->read_buffer = buffer;
png_ptr->read_buffer_size = new_size;
}
@@ -673,6 +674,8 @@ png_decompress_chunk(png_structrp png_ptr,
if (text != NULL)
{
+ memset(text, 0, buffer_size);
+
ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/,
png_ptr->read_buffer + prefix_size, &lzsize,
text + prefix_size, newlength);
@@ -736,9 +739,7 @@ png_decompress_chunk(png_structrp png_ptr,
{
/* inflateReset failed, store the error message */
png_zstream_error(png_ptr, ret);
-
- if (ret == Z_STREAM_END)
- ret = PNG_UNEXPECTED_ZLIB_RETURN;
+ ret = PNG_UNEXPECTED_ZLIB_RETURN;
}
}
@@ -1476,7 +1477,7 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
/* Now read the tag table; a variable size buffer is
* needed at this point, allocate one for the whole
* profile. The header check has already validated
- * that none of these stuff will overflow.
+ * that none of this stuff will overflow.
*/
const png_uint_32 tag_count = png_get_uint_32(
profile_header+128);
@@ -1583,19 +1584,11 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
return;
}
}
-
- else if (size > 0)
- errmsg = "truncated";
-
-#ifndef __COVERITY__
- else
+ if (errmsg == NULL)
errmsg = png_ptr->zstream.msg;
-#endif
}
-
/* else png_icc_check_tag_table output an error */
}
-
else /* profile truncated */
errmsg = png_ptr->zstream.msg;
}
@@ -3144,28 +3137,28 @@ png_check_chunk_length(png_const_structrp png_ptr, const png_uint_32 length)
{
png_alloc_size_t limit = PNG_UINT_31_MAX;
- if (png_ptr->chunk_name != png_IDAT)
- {
# ifdef PNG_SET_USER_LIMITS_SUPPORTED
- if (png_ptr->user_chunk_malloc_max > 0 &&
- png_ptr->user_chunk_malloc_max < limit)
- limit = png_ptr->user_chunk_malloc_max;
+ if (png_ptr->user_chunk_malloc_max > 0 &&
+ png_ptr->user_chunk_malloc_max < limit)
+ limit = png_ptr->user_chunk_malloc_max;
# elif PNG_USER_CHUNK_MALLOC_MAX > 0
- if (PNG_USER_CHUNK_MALLOC_MAX < limit)
- limit = PNG_USER_CHUNK_MALLOC_MAX;
+ if (PNG_USER_CHUNK_MALLOC_MAX < limit)
+ limit = PNG_USER_CHUNK_MALLOC_MAX;
# endif
- }
- else
+ if (png_ptr->chunk_name == png_IDAT)
{
+ png_alloc_size_t idat_limit = PNG_UINT_31_MAX;
size_t row_factor =
(png_ptr->width * png_ptr->channels * (png_ptr->bit_depth > 8? 2: 1)
+ 1 + (png_ptr->interlaced? 6: 0));
if (png_ptr->height > PNG_UINT_32_MAX/row_factor)
- limit=PNG_UINT_31_MAX;
+ idat_limit=PNG_UINT_31_MAX;
else
- limit = png_ptr->height * row_factor;
- limit += 6 + 5*(limit/32566+1); /* zlib+deflate overhead */
- limit=limit < PNG_UINT_31_MAX? limit : PNG_UINT_31_MAX;
+ idat_limit = png_ptr->height * row_factor;
+ row_factor = row_factor > 32566? 32566 : row_factor;
+ idat_limit += 6 + 5*(idat_limit/row_factor+1); /* zlib+deflate overhead */
+ idat_limit=idat_limit < PNG_UINT_31_MAX? idat_limit : PNG_UINT_31_MAX;
+ limit = limit < idat_limit? idat_limit : limit;
}
if (length > limit)
diff --git a/src/3rdparty/libpng/pngtrans.c b/src/3rdparty/libpng/pngtrans.c
index 326ac33f0e..6882f0fd7b 100644
--- a/src/3rdparty/libpng/pngtrans.c
+++ b/src/3rdparty/libpng/pngtrans.c
@@ -1,7 +1,7 @@
/* pngtrans.c - transforms the data in a row (used by both readers and writers)
*
- * Last changed in libpng 1.6.30 [June 28, 2017]
+ * Last changed in libpng 1.6.33 [September 28, 2017]
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -609,7 +609,7 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
return; /* The filler channel has gone already */
/* Fix the rowbytes value. */
- row_info->rowbytes = (unsigned int)(dp-row);
+ row_info->rowbytes = (png_size_t)(dp-row);
}
#endif
@@ -708,7 +708,7 @@ png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info)
* forms produced on either GCC or MSVC.
*/
int padding = PNG_PADBITS(row_info->pixel_depth, row_info->width);
- png_bytep rp = png_ptr->row_buf + row_info->rowbytes;
+ png_bytep rp = png_ptr->row_buf + row_info->rowbytes - 1;
switch (row_info->bit_depth)
{
diff --git a/src/3rdparty/libpng/pngwrite.c b/src/3rdparty/libpng/pngwrite.c
index a7662acb71..a16d77ce00 100644
--- a/src/3rdparty/libpng/pngwrite.c
+++ b/src/3rdparty/libpng/pngwrite.c
@@ -1940,7 +1940,7 @@ png_image_write_main(png_voidp argument)
int colormap = (format & PNG_FORMAT_FLAG_COLORMAP);
int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR); /* input */
int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA);
- int write_16bit = linear && !colormap && (display->convert_to_8bit == 0);
+ int write_16bit = linear && (display->convert_to_8bit == 0);
# ifdef PNG_BENIGN_ERRORS_SUPPORTED
/* Make sure we error out on any bad situation */
diff --git a/src/3rdparty/libpng/qt_attribution.json b/src/3rdparty/libpng/qt_attribution.json
index 7b2d776978..23fb903bdd 100644
--- a/src/3rdparty/libpng/qt_attribution.json
+++ b/src/3rdparty/libpng/qt_attribution.json
@@ -6,7 +6,7 @@
"Description": "libpng is the official PNG reference library.",
"Homepage": "http://www.libpng.org/pub/png/libpng.html",
- "Version": "1.6.32",
+ "Version": "1.6.34",
"License": "libpng License",
"LicenseId": "Libpng",
"LicenseFile": "LICENSE",
diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h
index 2c58ff87e9..231ac2c9b0 100644
--- a/src/corelib/global/qcompilerdetection.h
+++ b/src/corelib/global/qcompilerdetection.h
@@ -1347,12 +1347,12 @@
} while (false)
#if defined(__cplusplus)
-#if QT_HAS_CPP_ATTRIBUTE(fallthrough)
-# define Q_FALLTHROUGH() [[fallthrough]]
-#elif QT_HAS_CPP_ATTRIBUTE(clang::fallthrough)
+#if QT_HAS_CPP_ATTRIBUTE(clang::fallthrough)
# define Q_FALLTHROUGH() [[clang::fallthrough]]
#elif QT_HAS_CPP_ATTRIBUTE(gnu::fallthrough)
# define Q_FALLTHROUGH() [[gnu::fallthrough]]
+#elif QT_HAS_CPP_ATTRIBUTE(fallthrough)
+# define Q_FALLTHROUGH() [[fallthrough]]
#endif
#endif
#ifndef Q_FALLTHROUGH
diff --git a/src/corelib/global/qfloat16.h b/src/corelib/global/qfloat16.h
index 10598adb1d..a36852fc22 100644
--- a/src/corelib/global/qfloat16.h
+++ b/src/corelib/global/qfloat16.h
@@ -121,7 +121,7 @@ inline qfloat16::qfloat16(float f) Q_DECL_NOTHROW
__m128i packhalf = _mm_cvtps_ph(packsingle, 0);
b16 = _mm_extract_epi16(packhalf, 0);
#elif defined (__ARM_FP16_FORMAT_IEEE)
- __fp16 f16 = f;
+ __fp16 f16 = __fp16(f);
memcpy(&b16, &f16, sizeof(quint16));
#else
quint32 u;
diff --git a/src/corelib/global/qrandom.cpp b/src/corelib/global/qrandom.cpp
index 9abb9ece7f..72ac8d332b 100644
--- a/src/corelib/global/qrandom.cpp
+++ b/src/corelib/global/qrandom.cpp
@@ -43,10 +43,8 @@
#include "qrandom.h"
#include "qrandom_p.h"
#include <qobjectdefs.h>
+#include <qmutex.h>
#include <qthreadstorage.h>
-#include <private/qsimd_p.h>
-
-#include <random>
#include <errno.h>
@@ -86,6 +84,7 @@ DECLSPEC_IMPORT BOOLEAN WINAPI SystemFunction036(PVOID RandomBuffer, ULONG Rando
#undef Q_ASSERT_X
#undef Q_ASSERT
#define Q_ASSERT(cond) assert(cond)
+#define Q_ASSERT_X(cond, x, msg) assert(cond && msg)
#if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS)
# define NDEBUG 1
#endif
@@ -122,14 +121,21 @@ static QT_FUNCTION_TARGET(RDRND) qssize_t qt_random_cpu(void *buffer, qssize_t c
out:
return ptr - reinterpret_cast<unsigned *>(buffer);
}
+#else
+static qssize_t qt_random_cpu(void *, qssize_t)
+{
+ return 0;
+}
#endif
-namespace {
-#if QT_CONFIG(getentropy)
-class SystemRandom
+enum {
+ // may be "overridden" by a member enum
+ FillBufferNoexcept = true
+};
+
+struct QRandomGenerator::SystemGenerator
{
-public:
- enum { EfficientBufferFill = true };
+#if QT_CONFIG(getentropy)
static qssize_t fillBuffer(void *buffer, qssize_t count) Q_DECL_NOTHROW
{
// getentropy can read at most 256 bytes, so break the reading
@@ -147,96 +153,93 @@ public:
Q_UNUSED(ret);
return count;
}
-};
#elif defined(Q_OS_UNIX)
-class SystemRandom
-{
- static QBasicAtomicInt s_fdp1; // "file descriptor plus 1"
- static int openDevice();
-#ifdef Q_CC_GNU
- // If it's not GCC or GCC-like, then we'll leak the file descriptor
- __attribute__((destructor))
-#endif
- static void closeDevice();
- SystemRandom() {}
-public:
- enum { EfficientBufferFill = true };
- static qssize_t fillBuffer(void *buffer, qssize_t count);
-};
-QBasicAtomicInt SystemRandom::s_fdp1 = Q_BASIC_ATOMIC_INITIALIZER(0);
+ enum { FillBufferNoexcept = false };
-void SystemRandom::closeDevice()
-{
- int fd = s_fdp1.loadAcquire() - 1;
- if (fd >= 0)
- qt_safe_close(fd);
-}
+ QBasicAtomicInt fdp1; // "file descriptor plus 1"
+ int openDevice()
+ {
+ int fd = fdp1.loadAcquire() - 1;
+ if (fd != -1)
+ return fd;
+
+ fd = qt_safe_open("/dev/urandom", O_RDONLY);
+ if (fd == -1)
+ fd = qt_safe_open("/dev/random", O_RDONLY | O_NONBLOCK);
+ if (fd == -1) {
+ // failed on both, set to -2 so we won't try again
+ fd = -2;
+ }
-int SystemRandom::openDevice()
-{
- int fd = s_fdp1.loadAcquire() - 1;
- if (fd != -1)
- return fd;
-
- fd = qt_safe_open("/dev/urandom", O_RDONLY);
- if (fd == -1)
- fd = qt_safe_open("/dev/random", O_RDONLY | O_NONBLOCK);
- if (fd == -1) {
- // failed on both, set to -2 so we won't try again
- fd = -2;
+ int opened_fdp1;
+ if (fdp1.testAndSetOrdered(0, fd + 1, opened_fdp1))
+ return fd;
+
+ // failed, another thread has opened the file descriptor
+ if (fd >= 0)
+ qt_safe_close(fd);
+ return opened_fdp1 - 1;
}
- int opened_fdp1;
- if (s_fdp1.testAndSetOrdered(0, fd + 1, opened_fdp1)) {
- if (fd >= 0) {
- static const SystemRandom closer;
- Q_UNUSED(closer);
- }
- return fd;
+#ifdef Q_CC_GNU
+ // If it's not GCC or GCC-like, then we'll leak the file descriptor
+ __attribute__((destructor))
+#endif
+ static void closeDevice()
+ {
+ int fd = self().fdp1.load() - 1;
+ if (fd >= 0)
+ qt_safe_close(fd);
}
- // failed, another thread has opened the file descriptor
- if (fd >= 0)
- qt_safe_close(fd);
- return opened_fdp1 - 1;
-}
+ Q_DECL_CONSTEXPR SystemGenerator() : fdp1 Q_BASIC_ATOMIC_INITIALIZER(0) {}
-qssize_t SystemRandom::fillBuffer(void *buffer, qssize_t count)
-{
- int fd = openDevice();
- if (Q_UNLIKELY(fd < 0))
- return 0;
+ qssize_t fillBuffer(void *buffer, qssize_t count)
+ {
+ int fd = openDevice();
+ if (Q_UNLIKELY(fd < 0))
+ return 0;
- qint64 n = qt_safe_read(fd, buffer, count);
- return qMax<qssize_t>(n, 0); // ignore any errors
-}
-#endif // Q_OS_UNIX
+ qint64 n = qt_safe_read(fd, buffer, count);
+ return qMax<qssize_t>(n, 0); // ignore any errors
+ }
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
-class SystemRandom
-{
-public:
- enum { EfficientBufferFill = true };
- static qssize_t fillBuffer(void *buffer, qssize_t count) Q_DECL_NOTHROW
+#elif defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ qssize_t fillBuffer(void *buffer, qssize_t count) Q_DECL_NOTHROW
{
auto RtlGenRandom = SystemFunction036;
return RtlGenRandom(buffer, ULONG(count)) ? count: 0;
}
-};
#elif defined(Q_OS_WINRT)
-class SystemRandom
-{
-public:
- enum { EfficientBufferFill = false };
- static qssize_t fillBuffer(void *, qssize_t) Q_DECL_NOTHROW
+ qssize_t fillBuffer(void *, qssize_t) Q_DECL_NOTHROW
{
// always use the fallback
return 0;
}
-};
#endif // Q_OS_WINRT
-} // unnamed namespace
+
+ static SystemGenerator &self();
+ void generate(quint32 *begin, quint32 *end) Q_DECL_NOEXCEPT_EXPR(FillBufferNoexcept);
+
+ // For std::mersenne_twister_engine implementations that use something
+ // other than quint32 (unsigned int) to fill their buffers.
+ template <typename T> void generate(T *begin, T *end)
+ {
+ Q_STATIC_ASSERT(sizeof(T) >= sizeof(quint32));
+ if (sizeof(T) == sizeof(quint32)) {
+ // Microsoft Visual Studio uses unsigned long, but that's still 32-bit
+ generate(reinterpret_cast<quint32 *>(begin), reinterpret_cast<quint32 *>(end));
+ } else {
+ // Slow path. Fix your C++ library.
+ std::generate(begin, end, [this]() {
+ quint32 datum;
+ generate(&datum, &datum + 1);
+ return datum;
+ });
+ }
+ }
+};
#if defined(Q_OS_WIN)
static void fallback_update_seed(unsigned) {}
@@ -255,6 +258,7 @@ static void fallback_update_seed(unsigned) {}
static void fallback_fill(quint32 *, qssize_t) Q_DECL_NOTHROW
{
// no fallback necessary, getentropy cannot fail under normal circumstances
+ Q_UNREACHABLE();
}
#elif defined(Q_OS_BSD4)
static void fallback_update_seed(unsigned) {}
@@ -350,31 +354,25 @@ static void fallback_fill(quint32 *ptr, qssize_t left) Q_DECL_NOTHROW
}
#endif
-static qssize_t fill_cpu(quint32 *buffer, qssize_t count) Q_DECL_NOTHROW
+Q_NEVER_INLINE void QRandomGenerator::SystemGenerator::generate(quint32 *begin, quint32 *end)
+ Q_DECL_NOEXCEPT_EXPR(FillBufferNoexcept)
{
-#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
- if (qCpuHasFeature(RDRND) && (uint(qt_randomdevice_control) & SkipHWRNG) == 0)
- return qt_random_cpu(buffer, count);
-#else
- Q_UNUSED(buffer);
- Q_UNUSED(count);
-#endif
- return 0;
-}
+ quint32 *buffer = begin;
+ qssize_t count = end - begin;
-static void fill_internal(quint32 *buffer, qssize_t count)
- Q_DECL_NOEXCEPT_EXPR(noexcept(SystemRandom::fillBuffer(buffer, count)))
-{
if (Q_UNLIKELY(uint(qt_randomdevice_control) & SetRandomData)) {
uint value = uint(qt_randomdevice_control) & RandomDataMask;
std::fill_n(buffer, count, value);
return;
}
- qssize_t filled = fill_cpu(buffer, count);
+ qssize_t filled = 0;
+ if (qt_has_hwrng() && (uint(qt_randomdevice_control) & SkipHWRNG) == 0)
+ filled += qt_random_cpu(buffer, count);
+
if (filled != count && (uint(qt_randomdevice_control) & SkipSystemRNG) == 0) {
qssize_t bytesFilled =
- SystemRandom::fillBuffer(buffer + filled, (count - filled) * qssize_t(sizeof(*buffer)));
+ fillBuffer(buffer + filled, (count - filled) * qssize_t(sizeof(*buffer)));
filled += bytesFilled / qssize_t(sizeof(*buffer));
}
if (filled)
@@ -386,147 +384,262 @@ static void fill_internal(quint32 *buffer, qssize_t count)
}
}
-static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
- Q_DECL_NOEXCEPT_EXPR(noexcept(fill_internal(static_cast<quint32 *>(buffer), 1)))
+struct QRandomGenerator::SystemAndGlobalGenerators
{
- struct ThreadState {
- enum {
- DesiredBufferByteSize = 32,
- BufferCount = DesiredBufferByteSize / sizeof(quint32)
- };
- quint32 buffer[BufferCount];
- int idx = BufferCount;
- };
-
- // Verify that the pointers are properly aligned for 32-bit
- Q_ASSERT(quintptr(buffer) % sizeof(quint32) == 0);
- Q_ASSERT(quintptr(bufferEnd) % sizeof(quint32) == 0);
+ // Construction notes:
+ // 1) The global PRNG state is in a different cacheline compared to the
+ // mutex that protects it. This avoids any false cacheline sharing of
+ // the state in case another thread tries to lock the mutex. It's not
+ // a common scenario, but since sizeof(QRandomGenerator) >= 2560, the
+ // overhead is actually acceptable.
+ // 2) We use both Q_DECL_ALIGN and std::aligned_storage<..., 64> because
+ // some implementations of std::aligned_storage can't align to more
+ // than a primitive type's alignment.
+ // 3) We don't store the entire system QRandomGenerator, only the space
+ // used by the QRandomGenerator::type member. This is fine because we
+ // (ab)use the common initial sequence exclusion to aliasing rules.
+ QBasicMutex globalPRNGMutex;
+ struct ShortenedSystem { uint type; } system_;
+ SystemGenerator sys;
+ Q_DECL_ALIGN(64) std::aligned_storage<sizeof(QRandomGenerator64), 64>::type global_;
+
+#ifdef Q_COMPILER_CONSTEXPR
+ constexpr SystemAndGlobalGenerators()
+ : globalPRNGMutex{}, system_{0}, sys{}, global_{}
+ {}
+#endif
- quint32 *ptr = reinterpret_cast<quint32 *>(buffer);
- quint32 * const end = reinterpret_cast<quint32 *>(bufferEnd);
+ void confirmLiteral()
+ {
+#if defined(Q_COMPILER_CONSTEXPR) && !defined(Q_CC_MSVC) && !defined(Q_OS_INTEGRITY)
+ // Currently fails to compile with MSVC 2017, saying QBasicMutex is not
+ // a literal type. Disassembly with MSVC 2013 and 2015 shows it is
+ // actually a literal; MSVC 2017 has a bug relating to this, so we're
+ // withhold judgement for now. Integrity's compiler is unable to
+ // guarantee g's alignment for some reason.
+
+ constexpr SystemAndGlobalGenerators g = {};
+ Q_UNUSED(g);
+ Q_STATIC_ASSERT(std::is_literal_type<SystemAndGlobalGenerators>::value);
+#endif
+ }
-#if defined(Q_COMPILER_THREAD_LOCAL) && !defined(QT_BOOTSTRAPPED)
- if (SystemRandom::EfficientBufferFill && (end - ptr) < ThreadState::BufferCount
- && uint(qt_randomdevice_control) == 0) {
- thread_local ThreadState state;
- qssize_t itemsAvailable = ThreadState::BufferCount - state.idx;
+ static SystemAndGlobalGenerators *self()
+ {
+ static SystemAndGlobalGenerators g;
+ Q_STATIC_ASSERT(sizeof(g) > sizeof(QRandomGenerator64));
+ return &g;
+ }
- // copy as much as we already have
- qssize_t itemsToCopy = qMin(qssize_t(end - ptr), itemsAvailable);
- memcpy(ptr, state.buffer + state.idx, size_t(itemsToCopy) * sizeof(*ptr));
- ptr += itemsToCopy;
+ static QRandomGenerator64 *system()
+ {
+ // Though we never call the constructor, the system QRandomGenerator is
+ // properly initialized by the zero initialization performed in self().
+ // Though QRandomGenerator is has non-vacuous initialization, we
+ // consider it initialized because of the common initial sequence.
+ return reinterpret_cast<QRandomGenerator64 *>(&self()->system_);
+ }
- if (ptr != end) {
- // refill the buffer and try again
- fill_internal(state.buffer, ThreadState::BufferCount);
- state.idx = 0;
+ static QRandomGenerator64 *globalNoInit()
+ {
+ // This function returns the pointer to the global QRandomGenerator,
+ // but does not initialize it. Only call it directly if you meant to do
+ // a pointer comparison.
+ return reinterpret_cast<QRandomGenerator64 *>(&self()->global_);
+ }
- itemsToCopy = end - ptr;
- memcpy(ptr, state.buffer + state.idx, size_t(itemsToCopy) * sizeof(*ptr));
- ptr = end;
- }
+ static void securelySeed(QRandomGenerator *rng)
+ {
+ // force reconstruction, just to be pedantic
+ new (rng) QRandomGenerator{System{}};
- // erase what we copied and advance
-# ifdef Q_OS_WIN
- // Microsoft recommends this
- SecureZeroMemory(state.buffer + state.idx, size_t(itemsToCopy) * sizeof(*ptr));
-# else
- // We're quite confident the compiler will not optimize this out because
- // we're writing to a thread-local buffer
- memset(state.buffer + state.idx, 0, size_t(itemsToCopy) * sizeof(*ptr));
-# endif
- state.idx += itemsToCopy;
+ rng->type = MersenneTwister;
+ new (&rng->storage.engine()) RandomEngine(self()->sys);
}
-#endif // Q_COMPILER_THREAD_LOCAL && !QT_BOOTSTRAPPED
- if (ptr != end) {
- // fill directly in the user buffer
- fill_internal(ptr, end - ptr);
- }
+ struct PRNGLocker {
+ const bool locked;
+ PRNGLocker(const QRandomGenerator *that)
+ : locked(that == globalNoInit())
+ {
+ if (locked)
+ self()->globalPRNGMutex.lock();
+ }
+ ~PRNGLocker()
+ {
+ if (locked)
+ self()->globalPRNGMutex.unlock();
+ }
+ };
+};
+
+inline QRandomGenerator::SystemGenerator &QRandomGenerator::SystemGenerator::self()
+{
+ return SystemAndGlobalGenerators::self()->sys;
}
/*!
\class QRandomGenerator
\inmodule QtCore
+ \reentrant
\since 5.10
\brief The QRandomGenerator class allows one to obtain random values from a
- high-quality, seed-less Random Number Generator.
+ high-quality Random Number Generator.
QRandomGenerator may be used to generate random values from a high-quality
- random number generator. Unlike qrand(), QRandomGenerator does not need to be
- seeded. That also means it is not possible to force it to produce a
- reliable sequence, which may be needed for debugging.
+ random number generator. Like the C++ random engines, QRandomGenerator can
+ be seeded with user-provided values through the constructor.
+ When seeded, the sequence of numbers generated by this
+ class is deterministic. That is to say, given the same seed data,
+ QRandomGenerator will generate the same sequence of numbers. But given
+ different seeds, the results should be considerably different.
+
+ QRandomGenerator::securelySeeded() can be used to create a QRandomGenerator
+ that is securely seeded with QRandomGenerator::system(), meaning that the
+ sequence of numbers it generates cannot be easily predicted. Additionally,
+ QRandomGenerator::global() returns a global instance of QRandomGenerator
+ that Qt will ensure to be securely seeded. This object is thread-safe, may
+ be shared for most uses, and is always seeded from
+ QRandomGenerator::system()
+
+ QRandomGenerator::system() may be used to access the system's
+ cryptographically-safe random generator. On Unix systems, it's equivalent
+ to reading from \c {/dev/urandom} or the \c {getrandom()} or \c
+ {getentropy()} system calls.
The class can generate 32-bit or 64-bit quantities, or fill an array of
those. The most common way of generating new values is to call the generate(),
generate64() or fillRange() functions. One would use it as:
\code
- quint32 value = QRandomGenerator::generate();
+ quint32 value = QRandomGenerator::global()->generate();
\endcode
- Additionally, it provides a floating-point function generateDouble() that returns
- a number in the range [0, 1) (that is, inclusive of zero and exclusive of
- 1). There's also a set of convenience functions that facilitate obtaining a
- random number in a bounded, integral range.
+ Additionally, it provides a floating-point function generateDouble() that
+ returns a number in the range [0, 1) (that is, inclusive of zero and
+ exclusive of 1). There's also a set of convenience functions that
+ facilitate obtaining a random number in a bounded, integral range.
- \warning This class is not suitable for bulk data creation. See below for the
- technical reasons.
+ \section1 Seeding and determinism
+
+ QRandomGenerator may be seeded with specific seed data. When that is done,
+ the numbers generated by the object will always be the same, as in the
+ following example:
+
+ \code
+ QRandomGenerator prng1(1234), prng2(1234);
+ Q_ASSERT(prng1.generate32() == prng2.generate32());
+ Q_ASSERT(prng1.generate64() == prng2.generate64());
+ \endcode
- \section1 Frequency and entropy exhaustion
+ The seed data takes the form of one or more 32-bit words. The ideal seed
+ size is approximately equal to the size of the QRandomGenerator class
+ itself. Due to mixing of the seed data, QRandomGenerator cannot guarantee
+ that distinct seeds will produce different sequences.
+
+ QRandomGenerator::global(), like all generators created by
+ QRandomGenerator::securelySeeded(), is always seeded from
+ QRandomGenerator::system(), so it's not possible to make it produce
+ identical sequences.
+
+ \section1 Bulk data
+
+ When operating in deterministic mode, QRandomGenerator may be used for bulk
+ data generation. In fact, applications that do not need
+ cryptographically-secure or true random data are advised to use a regular
+ QRandomGenerator instead of QRandomGenerator::system() for their random
+ data needs.
+
+ For ease of use, QRandomGenerator provides a global object that can
+ be easily used, as in the following example:
+
+ \code
+ int x = QRandomGenerator::global()->generate32();
+ int y = QRandomGenerator::global()->generate32();
+ int w = QRandomGenerator::global()->bounded(16384);
+ int h = QRandomGenerator::global()->bounded(16384);
+ \endcode
- QRandomGenerator does not need to be seeded and instead uses operating system
- or hardware facilities to generate random numbers. On some systems and with
- certain hardware, those facilities are true Random Number Generators.
- However, if they are true RNGs, those facilities have finite entropy source
- and thus may fail to produce any results if the entropy pool is exhausted.
+ \section1 System-wide random number generator
+
+ QRandomGenerator::system() may be used to access the system-wide random
+ number generator, which is cryptographically-safe on all systems that Qt
+ runs on. This function will use hardware facilities to generate random
+ numbers where available. On such systems, those facilities are true Random
+ Number Generators. However, if they are true RNGs, those facilities have
+ finite entropy sources and thus may fail to produce any results if their
+ entropy pool is exhausted.
If that happens, first the operating system then QRandomGenerator will fall
back to Pseudo Random Number Generators of decreasing qualities (Qt's
- fallback generator being the simplest). Therefore, QRandomGenerator should
- not be used for high-frequency random number generation, lest the entropy
- pool become empty. As a rule of thumb, this class should not be called upon
- to generate more than a kilobyte per second of random data (note: this may
- vary from system to system).
+ fallback generator being the simplest). Whether those generators are still
+ of cryptographic quality is implementation-defined. Therefore,
+ QRandomGenerator::system() should not be used for high-frequency random
+ number generation, lest the entropy pool become empty. As a rule of thumb,
+ this class should not be called upon to generate more than a kilobyte per
+ second of random data (note: this may vary from system to system).
If an application needs true RNG data in bulk, it should use the operating
- system facilities (such as \c{/dev/random} on Unix systems) directly and
- wait for entropy to become available. If true RNG is not required,
- applications should instead use a PRNG engines and can use QRandomGenerator to
- seed those.
+ system facilities (such as \c{/dev/random} on Linux) directly and wait for
+ entropy to become available. If the application requires PRNG engines of
+ cryptographic quality but not of true randomness,
+ QRandomGenerator::system() may still be used (see section below).
+
+ If neither a true RNG nor a cryptographically secure PRNG are required,
+ applications should instead use PRNG engines like QRandomGenerator's
+ deterministic mode and those from the C++ Standard Library.
+ QRandomGenerator::system() can be used to seed those.
+
+ \section2 Fallback quality
+
+ QRandomGenerator::system() uses the operating system facilities to obtain
+ random numbers, which attempt to collect real entropy from the surrounding
+ environment to produce true random numbers. However, it's possible that the
+ entropy pool becomes exhausted, in which case the operating system will
+ fall back to a pseudo-random engine for a time. Under no circumstances will
+ QRandomGenerator::system() block, waiting for more entropy to be collected.
+
+ The following operating systems guarantee that the results from their
+ random-generation API will be of at least cryptographically-safe quality,
+ even if the entropy pool is exhausted: Apple OSes (Darwin), BSDs, Linux,
+ Windows. Barring a system installation problem (such as \c{/dev/urandom}
+ not being readable by the current process), QRandomGenerator::system() will
+ therefore have the same guarantees.
+
+ On other operating systems, QRandomGenerator will fall back to a PRNG of
+ good numeric distribution, but it cannot guarantee proper seeding in all
+ cases. Please consult the OS documentation for more information.
+
+ Applications that require QRandomGenerator not to fall back to
+ non-cryptographic quality generators are advised to check their operating
+ system documentation or restrict their deployment to one of the above.
+
+ \section1 Reentrancy and thread-safety
+
+ QRandomGenerator is reentrant, meaning that multiple threads can operate on
+ this class at the same time, so long as they operate on different objects.
+ If multiple threads need to share one PRNG sequence, external locking by a
+ mutex is required.
+
+ The exceptions are the objects returned by QRandomGenerator::global() and
+ QRandomGenerator::system(): those objects are thread-safe and may be used
+ by any thread without external locking. Note that thread-safety does not
+ extend to copying those objects: they should always be used by reference.
\section1 Standard C++ Library compatibility
- QRandomGenerator is modeled after
- \c{\l{http://en.cppreference.com/w/cpp/numeric/random/random_device}{std::random_device}}
- and may be used in almost all contexts that the Standard Library can.
- QRandomGenerator attempts to use either the same engine that backs
- \c{std::random_device} or a better one. Note that \c{std::random_device} is
- also allowed to fail if the source entropy pool becomes exhausted, in which
- case it will throw an exception. QRandomGenerator never throws, but may abort
- program execution instead.
-
- Like the Standard Library class, QRandomGenerator can be used to seed Standard
- Library deterministic random engines from \c{<random>}, such as the
- Mersenne Twister. Unlike \c{std::random_device}, QRandomGenerator also
- implements the API of
- \c{\l{http://en.cppreference.com/w/cpp/numeric/random/seed_seq}{std::seed_seq}},
- allowing it to seed the deterministic engines directly.
-
- The following code can be used to create and seed the
- implementation-defined default deterministic PRNG, then use it to fill a
- block range:
-
- \code
- QRandomGenerator rd;
- std::default_random_engine rng(rd);
- std::generate(block.begin(), block.end(), rng);
+ QRandomGenerator is modeled after the requirements for random number
+ engines in the C++ Standard Library and may be used in almost all contexts
+ that the Standard Library engines can. Exceptions to the requirements are
+ the following:
- // equivalent to:
- for (auto &v : block)
- v = rng();
- \endcode
+ \list
+ \li QRandomGenerator does not support seeding from another seed
+ sequence-like class besides std::seed_seq itself;
+ \li QRandomGenerator is not comparable (but is copyable) or
+ streamable to \c{std::ostream} or from \c{std::istream}.
+ \endlist
QRandomGenerator is also compatible with the uniform distribution classes
\c{std::uniform_int_distribution} and \c{std:uniform_real_distribution}, as
@@ -535,57 +648,129 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
[1, 2.5):
\code
- QRandomGenerator64 rd;
std::uniform_real_distribution dist(1, 2.5);
- return dist(rd);
+ return dist(*QRandomGenerator::global());
\endcode
- Note the use of the QRandomGenerator64 class instead of QRandomGenerator to
- obtain 64 bits of random data in a single call, though it is not required
- to make the algorithm work (the Standard Library functions will make as
- many calls as required to obtain enough bits of random data for the desired
- range).
-
\sa QRandomGenerator64, qrand()
*/
/*!
- \fn QRandomGenerator::QRandomGenerator()
- \internal
- Defaulted constructor, does nothing.
+ \fn QRandomGenerator::QRandomGenerator(quint32 seedValue)
+
+ Initializes this QRandomGenerator object with the value \a seedValue as
+ the seed. Two objects constructed or reseeded with the same seed value will
+ produce the same number sequence.
+
+ \sa seed(), securelySeeded()
*/
/*!
- \typedef QRandomGenerator::result_type
+ \fn QRandomGenerator::QRandomGenerator(const quint32 (&seedBuffer)[N])
+ \overload
- A typedef to the type that operator()() returns. That is, quint32.
+ Initializes this QRandomGenerator object with the values found in the
+ array \a seedBuffer as the seed. Two objects constructed or reseeded with
+ the same seed value will produce the same number sequence.
- \sa operator()()
+ \sa seed(), securelySeeded()
*/
/*!
- \fn result_type QRandomGenerator::operator()()
+ \fn QRandomGenerator::QRandomGenerator(const quint32 *seedBuffer, qssize_t len)
+ \overload
- Generates a 32-bit random quantity and returns it.
+ Initializes this QRandomGenerator object with \a len values found in
+ the array \a seedBuffer as the seed. Two objects constructed or reseeded
+ with the same seed value will produce the same number sequence.
- \sa QRandomGenerator::generate(), QRandomGenerator::generate64()
+ This constructor is equivalent to:
+ \code
+ std::seed_seq sseq(seedBuffer, seedBuffer + len);
+ QRandomGenerator generator(sseq);
+ \endcode
+
+ \sa seed(), securelySeeded()
*/
/*!
- \fn double QRandomGenerator::entropy() const
+ \fn QRandomGenerator::QRandomGenerator(const quint32 *begin, const quin32 *end)
+ \overload
+
+ Initializes this QRandomGenerator object with the values found in the range
+ from \a begin to \a end as the seed. Two objects constructed or reseeded
+ with the same seed value will produce the same number sequence.
- Returns the estimate of the entropy in the random generator source.
+ This constructor is equivalent to:
+ \code
+ std::seed_seq sseq(begin, end);
+ QRandomGenerator generator(sseq);
+ \endcode
+
+ \sa seed(), securelySeeded()
+ */
+
+/*!
+ \fn QRandomGenerator::QRandomGenerator(std::seed_seq &sseq)
+ \overload
- This function exists to comply with the Standard Library requirements for
- \c{\l{http://en.cppreference.com/w/cpp/numeric/random/random_device}{std::random_device}}
- but it does not and cannot ever work. It is not possible to obtain a
- reliable entropy value in a shared entropy pool in a multi-tasking system,
- as other processes or threads may use that entropy. Any value non-zero
- value that this function could return would be obsolete by the time the
- user code reached it.
+ Initializes this QRandomGenerator object with the seed sequence \a
+ sseq as the seed. Two objects constructed or reseeded with the same seed
+ value will produce the same number sequence.
- Since QRandomGenerator attempts to use a hardware Random Number Generator,
- this function always returns 0.0.
+ \sa seed(), securelySeeded()
+ */
+
+/*!
+ \fn QRandomGenerator::QRandomGenerator(const QRandomGenerator &other)
+
+ Creates a copy of the generator state in the \a other object. If \a other is
+ QRandomGenerator::system() or a copy of that, this object will also read
+ from the operating system random-generating facilities. In that case, the
+ sequences generated by the two objects will be different.
+
+ In all other cases, the new QRandomGenerator object will start at the same
+ position in the deterministic sequence as the \a other object was. Both
+ objects will generate the same sequence from this point on.
+
+ For that reason, it is not adviseable to create a copy of
+ QRandomGenerator::global(). If one needs an exclusive deterministic
+ generator, consider instead using securelySeeded() to obtain a new object
+ that shares no relationship with the QRandomGenerator::global().
+ */
+
+/*!
+ \fn bool operator==(const QRandomGenerator &rng1, const QRandomGenerator &rng2)
+ \relates QRandomGenerator
+
+ Returns true if the two the two engines \a rng1 and \a rng2 are at the same
+ state or if they are both reading from the operating system facilities,
+ false otherwise.
+*/
+
+/*!
+ \fn bool operator!=(const QRandomGenerator &rng1, const QRandomGenerator &rng2)
+ \relates QRandomGenerator
+
+ Returns true if the two the two engines \a rng1 and \a rng2 are at
+ different states or if one of them is reading from the operating system
+ facilities and the other is not, false otherwise.
+*/
+
+/*!
+ \typedef QRandomGenerator::result_type
+
+ A typedef to the type that operator()() returns. That is, quint32.
+
+ \sa operator()()
+ */
+
+/*!
+ \fn result_type QRandomGenerator::operator()()
+
+ Generates a 32-bit random quantity and returns it.
+
+ \sa generate(), generate64()
*/
/*!
@@ -593,7 +778,7 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
Returns the minimum value that QRandomGenerator may ever generate. That is, 0.
- \sa max(), QRandomGenerator64::max()
+ \sa max(), QRandomGenerator64::min()
*/
/*!
@@ -606,13 +791,38 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
+ \fn void QRandomGenerator::seed(quint32 seed)
+
+ Reseeds this object using the value \a seed as the seed.
+ */
+
+/*!
+ \fn void QRandomGenerator::seed(std::seed_seq &seed)
+ \overload
+
+ Reseeds this object using the seed sequence \a sseq as the seed.
+ */
+
+/*!
+ \fn void QRandomGenerator::discard(unsigned long long z)
+
+ Discards the next \a z entries from the sequence. This method is equivalent
+ to calling generate() \a z times and discarding the result, as in:
+
+ \code
+ while (z--)
+ generator.generate();
+ \endcode
+*/
+
+/*!
\fn void QRandomGenerator::generate(ForwardIterator begin, ForwardIterator end)
Generates 32-bit quantities and stores them in the range between \a begin
and \a end. This function is equivalent to (and is implemented as):
\code
- std::generate(begin, end, []() { return generate(); });
+ std::generate(begin, end, [this]() { return generate(); });
\endcode
This function complies with the requirements for the function
@@ -625,7 +835,7 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
quantities, one can write:
\code
- std::generate(begin, end, []() { return QRandomGenerator::generate64(); });
+ std::generate(begin, end, []() { return QRandomGenerator::global()->generate64(); });
\endcode
If the range refers to contiguous memory (such as an array or the data from
@@ -703,26 +913,26 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
- \fn qreal QRandomGenerator::bounded(qreal sup)
+ \fn qreal QRandomGenerator::bounded(qreal highest)
Generates one random qreal in the range between 0 (inclusive) and \a
- sup (exclusive). This function is equivalent to and is implemented as:
+ highest (exclusive). This function is equivalent to and is implemented as:
\code
- return generateDouble() * sup;
+ return generateDouble() * highest;
\endcode
\sa generateDouble(), bounded()
*/
/*!
- \fn quint32 QRandomGenerator::bounded(quint32 sup)
+ \fn quint32 QRandomGenerator::bounded(quint32 highest)
\overload
Generates one random 32-bit quantity in the range between 0 (inclusive) and
- \a sup (exclusive). The same result may also be obtained by using
+ \a highest (exclusive). The same result may also be obtained by using
\c{\l{http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution}{std::uniform_int_distribution}}
- with parameters 0 and \c{sup - 1}. That class can also be used to obtain
+ with parameters 0 and \c{highest - 1}. That class can also be used to obtain
quantities larger than 32 bits.
For example, to obtain a value between 0 and 255 (inclusive), one would write:
@@ -741,11 +951,11 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
- \fn quint32 QRandomGenerator::bounded(int sup)
+ \fn quint32 QRandomGenerator::bounded(int highest)
\overload
Generates one random 32-bit quantity in the range between 0 (inclusive) and
- \a sup (exclusive). \a sup must not be negative.
+ \a highest (exclusive). \a highest must not be negative.
Note that this function cannot be used to obtain values in the full 32-bit
range of int. Instead, use generate() and cast to int.
@@ -754,13 +964,13 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
- \fn quint32 QRandomGenerator::bounded(quint32 min, quint32 sup)
+ \fn quint32 QRandomGenerator::bounded(quint32 lowest, quint32 highest)
\overload
- Generates one random 32-bit quantity in the range between \a min (inclusive)
- and \a sup (exclusive). The same result may also be obtained by using
+ Generates one random 32-bit quantity in the range between \a lowest (inclusive)
+ and \a highest (exclusive). The same result may also be obtained by using
\c{\l{http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution}{std::uniform_int_distribution}}
- with parameters \a min and \c{\a sup - 1}. That class can also be used to
+ with parameters \a lowest and \c{\a highest - 1}. That class can also be used to
obtain quantities larger than 32 bits.
For example, to obtain a value between 1000 (incl.) and 2000 (excl.), one
@@ -778,11 +988,11 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
- \fn quint32 QRandomGenerator::bounded(int min, int sup)
+ \fn quint32 QRandomGenerator::bounded(int lowest, int highest)
\overload
- Generates one random 32-bit quantity in the range between \a min
- (inclusive) and \a sup (exclusive), both of which may be negative.
+ Generates one random 32-bit quantity in the range between \a lowest
+ (inclusive) and \a highest (exclusive), both of which may be negative.
Note that this function cannot be used to obtain values in the full 32-bit
range of int. Instead, use generate() and cast to int.
@@ -791,6 +1001,72 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
+ \fn QRandomGenerator *QRandomGenerator::system()
+ \threadsafe
+
+ Returns a pointer to a shared QRandomGenerator that always uses the
+ facilities provided by the operating system to generate random numbers. The
+ system facilities are considered to be cryptographically safe on at least
+ the following operating systems: Apple OSes (Darwin), BSDs, Linux, Windows.
+ That may also be the case on other operating systems.
+
+ They are also possibly backed by a true hardware random number generator.
+ For that reason, the QRandomGenerator returned by this function should not
+ be used for bulk data generation. Instead, use it to seed QRandomGenerator
+ or a random engine from the <random> header.
+
+ The object returned by this function is thread-safe and may be used in any
+ thread without locks. It may also be copied and the resulting
+ QRandomGenerator will also access the operating system facilities, but they
+ will not generate the same sequence.
+
+ \sa securelySeeded(), global()
+*/
+
+/*!
+ \fn QRandomGenerator *QRandomGenerator::global()
+ \threadsafe
+
+ Returns a pointer to a shared QRandomGenerator that was seeded using
+ securelySeeded(). This function should be used to create random data
+ without the expensive creation of a securely-seeded QRandomGenerator
+ for a specific use or storing the rather large QRandomGenerator object.
+
+ For example, the following creates a random RGB color:
+
+ \code
+ return QColor::fromRgb(QRandomGenerator::global()->generate());
+ \endcode
+
+ Accesses to this object are thread-safe and it may therefore be used in any
+ thread without locks. The object may also be copied and the sequence
+ produced by the copy will be the same as the shared object will produce.
+ Note, however, that if there are other threads accessing the global object,
+ those threads may obtain samples at unpredictable intervals.
+
+ \sa securelySeeded(), system()
+*/
+
+/*!
+ \fn QRandomGenerator QRandomGenerator::securelySeeded()
+
+ Returns a new QRandomGenerator object that was securely seeded with
+ QRandomGenerator::system(). This function will obtain the ideal seed size
+ for the algorithm that QRandomGenerator uses and is therefore the
+ recommended way for creating a new QRandomGenerator object that will be
+ kept for some time.
+
+ Given the amount of data required to securely seed the deterministic
+ engine, this function is somewhat expensive and should not be used for
+ short-term uses of QRandomGenerator (using it to generate fewer than 2600
+ bytes of random data is effectively a waste of resources). If the use
+ doesn't require that much data, consider using QRandomGenerator::global()
+ and not storing a QRandomGenerator object instead.
+
+ \sa global(), system()
+ */
+
+/*!
\class QRandomGenerator64
\inmodule QtCore
\since 5.10
@@ -811,10 +1087,11 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
- \fn QRandomGenerator64::QRandomGenerator64()
- \internal
- Defaulted constructor, does nothing.
- */
+ \fn QRandomGenerator64::QRandomGenerator64(const QRandomGenerator &other)
+ \internal
+
+ Creates a copy.
+*/
/*!
\typedef QRandomGenerator64::result_type
@@ -849,80 +1126,119 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
\sa QRandomGenerator::generate(), QRandomGenerator::generate64()
*/
-/*!
- \fn double QRandomGenerator64::entropy() const
+Q_DECL_CONSTEXPR QRandomGenerator::Storage::Storage()
+ : dummy(0)
+{
+ // nothing
+}
- Returns the estimate of the entropy in the random generator source.
+inline QRandomGenerator64::QRandomGenerator64(System s)
+ : QRandomGenerator(s)
+{
+}
- This function exists to comply with the Standard Library requirements for
- \c{\l{http://en.cppreference.com/w/cpp/numeric/random/random_device}{std::random_device}}
- but it does not and cannot ever work. It is not possible to obtain a
- reliable entropy value in a shared entropy pool in a multi-tasking system,
- as other processes or threads may use that entropy. Any value non-zero
- value that this function could return would be obsolete by the time the
- user code reached it.
+QRandomGenerator64 *QRandomGenerator64::system()
+{
+ auto self = SystemAndGlobalGenerators::system();
+ Q_ASSERT(self->type == SystemRNG);
+ return self;
+}
- Since QRandomGenerator64 attempts to use a hardware Random Number Generator,
- this function always returns 0.0.
- */
+QRandomGenerator64 *QRandomGenerator64::global()
+{
+ auto self = SystemAndGlobalGenerators::globalNoInit();
-/*!
- \fn result_type QRandomGenerator64::min()
+ // Yes, this is a double-checked lock.
+ // We can return even if the type is not completely initialized yet:
+ // any thread trying to actually use the contents of the random engine
+ // will necessarily wait on the lock.
+ if (Q_LIKELY(self->type != SystemRNG))
+ return self;
- Returns the minimum value that QRandomGenerator64 may ever generate. That is, 0.
+ SystemAndGlobalGenerators::PRNGLocker locker(self);
+ if (self->type == SystemRNG)
+ SystemAndGlobalGenerators::securelySeed(self);
- \sa max(), QRandomGenerator::max()
- */
+ return self;
+}
-/*!
- \fn result_type QRandomGenerator64::max()
+QRandomGenerator64 QRandomGenerator64::securelySeeded()
+{
+ QRandomGenerator64 result(System{});
+ SystemAndGlobalGenerators::securelySeed(&result);
+ return result;
+}
- Returns the maximum value that QRandomGenerator64 may ever generate. That is,
- \c {std::numeric_limits<result_type>::max()}.
+/// \internal
+inline QRandomGenerator::QRandomGenerator(System)
+ : type(SystemRNG)
+{
+ // don't touch storage
+}
- \sa min(), QRandomGenerator::max()
- */
+QRandomGenerator::QRandomGenerator(const QRandomGenerator &other)
+ : type(other.type)
+{
+ Q_ASSERT(this != system());
+ Q_ASSERT(this != SystemAndGlobalGenerators::globalNoInit());
-/*!
- Generates one 32-bit random value and returns it.
+ if (type != SystemRNG) {
+ SystemAndGlobalGenerators::PRNGLocker lock(&other);
+ storage.engine() = other.storage.engine();
+ }
+}
- Note about casting to a signed integer: all bits returned by this function
- are random, so there's a 50% chance that the most significant bit will be
- set. If you wish to cast the returned value to int and keep it positive,
- you should mask the sign bit off:
+QRandomGenerator &QRandomGenerator::operator=(const QRandomGenerator &other)
+{
+ if (Q_UNLIKELY(this == system()) || Q_UNLIKELY(this == SystemAndGlobalGenerators::globalNoInit()))
+ qFatal("Attempted to overwrite a QRandomGenerator to system() or global().");
- \code
- int value = QRandomGenerator::generate() & std::numeric_limits<int>::max();
- \endcode
+ if ((type = other.type) != SystemRNG) {
+ SystemAndGlobalGenerators::PRNGLocker lock(&other);
+ storage.engine() = other.storage.engine();
+ }
+ return *this;
+}
- \sa generate64(), generateDouble()
- */
-quint32 QRandomGenerator::generate()
+QRandomGenerator::QRandomGenerator(std::seed_seq &sseq) Q_DECL_NOTHROW
+ : type(MersenneTwister)
{
- quint32 ret;
- fill(&ret, &ret + 1);
- return ret;
+ Q_ASSERT(this != system());
+ Q_ASSERT(this != SystemAndGlobalGenerators::globalNoInit());
+
+ new (&storage.engine()) RandomEngine(sseq);
}
-/*!
- Generates one 64-bit random value and returns it.
+QRandomGenerator::QRandomGenerator(const quint32 *begin, const quint32 *end)
+ : type(MersenneTwister)
+{
+ Q_ASSERT(this != system());
+ Q_ASSERT(this != SystemAndGlobalGenerators::globalNoInit());
- Note about casting to a signed integer: all bits returned by this function
- are random, so there's a 50% chance that the most significant bit will be
- set. If you wish to cast the returned value to qint64 and keep it positive,
- you should mask the sign bit off:
+ std::seed_seq s(begin, end);
+ new (&storage.engine()) RandomEngine(s);
+}
- \code
- qint64 value = QRandomGenerator::generate64() & std::numeric_limits<qint64>::max();
- \endcode
+void QRandomGenerator::discard(unsigned long long z)
+{
+ if (Q_UNLIKELY(type == SystemRNG))
+ return;
- \sa generate(), generateDouble(), QRandomGenerator64
- */
-quint64 QRandomGenerator::generate64()
+ SystemAndGlobalGenerators::PRNGLocker lock(this);
+ storage.engine().discard(z);
+}
+
+bool operator==(const QRandomGenerator &rng1, const QRandomGenerator &rng2)
{
- quint64 ret;
- fill(&ret, &ret + 1);
- return ret;
+ if (rng1.type != rng2.type)
+ return false;
+ if (rng1.type == SystemRNG)
+ return true;
+
+ // Lock global() if either is it (otherwise this locking is a no-op)
+ using PRNGLocker = QRandomGenerator::SystemAndGlobalGenerators::PRNGLocker;
+ PRNGLocker locker(&rng1 == QRandomGenerator::global() ? &rng1 : &rng2);
+ return rng1.storage.engine() == rng2.storage.engine();
}
/*!
@@ -931,9 +1247,19 @@ quint64 QRandomGenerator::generate64()
Fills the range pointed by \a buffer and \a bufferEnd with 32-bit random
values. The buffer must be correctly aligned.
*/
-void QRandomGenerator::fillRange_helper(void *buffer, void *bufferEnd)
+void QRandomGenerator::_fillRange(void *buffer, void *bufferEnd)
{
- fill(buffer, bufferEnd);
+ // Verify that the pointers are properly aligned for 32-bit
+ Q_ASSERT(quintptr(buffer) % sizeof(quint32) == 0);
+ Q_ASSERT(quintptr(bufferEnd) % sizeof(quint32) == 0);
+ quint32 *begin = static_cast<quint32 *>(buffer);
+ quint32 *end = static_cast<quint32 *>(bufferEnd);
+
+ if (type == SystemRNG || Q_UNLIKELY(uint(qt_randomdevice_control) & (UseSystemRNG|SetRandomData)))
+ return SystemGenerator::self().generate(begin, end);
+
+ SystemAndGlobalGenerators::PRNGLocker lock(this);
+ std::generate(begin, end, [this]() { return storage.engine()(); });
}
#if defined(Q_OS_ANDROID) && (__ANDROID_API__ < 21)
diff --git a/src/corelib/global/qrandom.h b/src/corelib/global/qrandom.h
index 049495d4e8..bde64646a4 100644
--- a/src/corelib/global/qrandom.h
+++ b/src/corelib/global/qrandom.h
@@ -42,6 +42,7 @@
#include <QtCore/qglobal.h>
#include <algorithm> // for std::generate
+#include <random> // for std::mt19937
QT_BEGIN_NAMESPACE
@@ -51,19 +52,43 @@ class QRandomGenerator
template <typename UInt> using IfValidUInt =
typename std::enable_if<std::is_unsigned<UInt>::value && sizeof(UInt) >= sizeof(uint), bool>::type;
public:
- static QRandomGenerator system() { return {}; }
- static QRandomGenerator global() { return {}; }
- QRandomGenerator() = default;
-
- // ### REMOVE BEFORE 5.10
- QRandomGenerator *operator->() { return this; }
- static quint32 get32() { return generate(); }
- static quint64 get64() { return generate64(); }
- static qreal getReal() { return generateDouble(); }
-
- static Q_CORE_EXPORT quint32 generate();
- static Q_CORE_EXPORT quint64 generate64();
- static double generateDouble()
+ QRandomGenerator(quint32 seedValue = 1)
+ : QRandomGenerator(&seedValue, 1)
+ {}
+ template <qssize_t N> QRandomGenerator(const quint32 (&seedBuffer)[N])
+ : QRandomGenerator(seedBuffer, seedBuffer + N)
+ {}
+ QRandomGenerator(const quint32 *seedBuffer, qssize_t len)
+ : QRandomGenerator(seedBuffer, seedBuffer + len)
+ {}
+ Q_CORE_EXPORT QRandomGenerator(std::seed_seq &sseq) Q_DECL_NOTHROW;
+ Q_CORE_EXPORT QRandomGenerator(const quint32 *begin, const quint32 *end);
+
+ // copy constructor & assignment operator (move unnecessary)
+ Q_CORE_EXPORT QRandomGenerator(const QRandomGenerator &other);
+ Q_CORE_EXPORT QRandomGenerator &operator=(const QRandomGenerator &other);
+
+ friend Q_CORE_EXPORT bool operator==(const QRandomGenerator &rng1, const QRandomGenerator &rng2);
+ friend bool operator!=(const QRandomGenerator &rng1, const QRandomGenerator &rng2)
+ {
+ return !(rng1 == rng2);
+ }
+
+ quint32 generate()
+ {
+ quint32 ret;
+ fillRange(&ret, 1);
+ return ret;
+ }
+
+ quint64 generate64()
+ {
+ quint32 buf[2];
+ fillRange(buf);
+ return buf[0] | (quint64(buf[1]) << 32);
+ }
+
+ double generateDouble()
{
// IEEE 754 double precision has:
// 1 bit sign
@@ -77,87 +102,161 @@ public:
return double(x) / double(limit);
}
- static qreal bounded(qreal sup)
+ double bounded(double highest)
{
- return generateDouble() * sup;
+ return generateDouble() * highest;
}
- static quint32 bounded(quint32 sup)
+ quint32 bounded(quint32 highest)
{
quint64 value = generate();
- value *= sup;
+ value *= highest;
value /= (max)() + quint64(1);
return quint32(value);
}
- static int bounded(int sup)
+ int bounded(int highest)
{
- return int(bounded(quint32(sup)));
+ return int(bounded(quint32(highest)));
}
- static quint32 bounded(quint32 min, quint32 sup)
+ quint32 bounded(quint32 lowest, quint32 highest)
{
- return bounded(sup - min) + min;
+ return bounded(highest - lowest) + lowest;
}
- static int bounded(int min, int sup)
+ int bounded(int lowest, int highest)
{
- return bounded(sup - min) + min;
+ return bounded(highest - lowest) + lowest;
}
template <typename UInt, IfValidUInt<UInt> = true>
- static void fillRange(UInt *buffer, qssize_t count)
+ void fillRange(UInt *buffer, qssize_t count)
{
- fillRange_helper(buffer, buffer + count);
+ _fillRange(buffer, buffer + count);
}
template <typename UInt, size_t N, IfValidUInt<UInt> = true>
- static void fillRange(UInt (&buffer)[N])
+ void fillRange(UInt (&buffer)[N])
{
- fillRange_helper(buffer, buffer + N);
+ _fillRange(buffer, buffer + N);
}
// API like std::seed_seq
template <typename ForwardIterator>
void generate(ForwardIterator begin, ForwardIterator end)
{
- auto generator = static_cast<quint32 (*)()>(&QRandomGenerator::generate);
- std::generate(begin, end, generator);
+ std::generate(begin, end, [this]() { return generate(); });
}
void generate(quint32 *begin, quint32 *end)
{
- fillRange_helper(begin, end);
+ _fillRange(begin, end);
}
- // API like std::random_device
+ // API like std:: random engines
typedef quint32 result_type;
result_type operator()() { return generate(); }
- double entropy() const Q_DECL_NOTHROW { return 0.0; }
+ void seed(quint32 s = 1) { *this = { s }; }
+ void seed(std::seed_seq &sseq) Q_DECL_NOTHROW { *this = { sseq }; }
+ Q_CORE_EXPORT void discard(unsigned long long z);
static Q_DECL_CONSTEXPR result_type min() { return (std::numeric_limits<result_type>::min)(); }
static Q_DECL_CONSTEXPR result_type max() { return (std::numeric_limits<result_type>::max)(); }
+ static inline Q_DECL_CONST_FUNCTION QRandomGenerator *system();
+ static inline Q_DECL_CONST_FUNCTION QRandomGenerator *global();
+ static inline QRandomGenerator securelySeeded();
+
+protected:
+ enum System {};
+ QRandomGenerator(System);
+
private:
- static Q_CORE_EXPORT void fillRange_helper(void *buffer, void *bufferEnd);
+ Q_CORE_EXPORT void _fillRange(void *buffer, void *bufferEnd);
+
+ friend class QRandomGenerator64;
+ struct SystemGenerator;
+ struct SystemAndGlobalGenerators;
+ typedef std::mt19937 RandomEngine;
+
+ union Storage {
+ uint dummy;
+#ifdef Q_COMPILER_UNRESTRICTED_UNIONS
+ RandomEngine twister;
+ RandomEngine &engine() { return twister; }
+ const RandomEngine &engine() const { return twister; }
+#else
+ std::aligned_storage<sizeof(RandomEngine), Q_ALIGNOF(RandomEngine)>::type buffer;
+ RandomEngine &engine() { return reinterpret_cast<RandomEngine &>(buffer); }
+ const RandomEngine &engine() const { return reinterpret_cast<const RandomEngine &>(buffer); }
+#endif
+
+ Q_STATIC_ASSERT_X(std::is_trivially_destructible<RandomEngine>::value,
+ "std::mersenne_twister not trivially destructible as expected");
+ Q_DECL_CONSTEXPR Storage();
+ };
+ uint type;
+ Storage storage;
};
-class QRandomGenerator64
+class QRandomGenerator64 : public QRandomGenerator
{
+ QRandomGenerator64(System);
public:
- static QRandomGenerator64 system() { return {}; }
- static QRandomGenerator64 global() { return {}; }
- QRandomGenerator64() = default;
+ // unshadow generate() overloads, since we'll override.
+ using QRandomGenerator::generate;
+ quint64 generate() { return generate64(); }
- static quint64 generate() { return QRandomGenerator::generate64(); }
-
- // API like std::random_device
typedef quint64 result_type;
- result_type operator()() { return QRandomGenerator::generate64(); }
- double entropy() const Q_DECL_NOTHROW { return 0.0; }
+ result_type operator()() { return generate64(); }
+
+#ifndef Q_QDOC
+ QRandomGenerator64(quint32 seedValue = 1)
+ : QRandomGenerator(seedValue)
+ {}
+ template <qssize_t N> QRandomGenerator64(const quint32 (&seedBuffer)[N])
+ : QRandomGenerator(seedBuffer)
+ {}
+ QRandomGenerator64(const quint32 *seedBuffer, qssize_t len)
+ : QRandomGenerator(seedBuffer, len)
+ {}
+ QRandomGenerator64(std::seed_seq &sseq) Q_DECL_NOTHROW
+ : QRandomGenerator(sseq)
+ {}
+ QRandomGenerator64(const quint32 *begin, const quint32 *end)
+ : QRandomGenerator(begin, end)
+ {}
+ QRandomGenerator64(const QRandomGenerator &other) : QRandomGenerator(other) {}
+
+ void discard(unsigned long long z)
+ {
+ Q_ASSERT_X(z * 2 > z, "QRandomGenerator64::discard",
+ "Overflow. Are you sure you want to skip over 9 quintillion samples?");
+ QRandomGenerator::discard(z * 2);
+ }
+
static Q_DECL_CONSTEXPR result_type min() { return (std::numeric_limits<result_type>::min)(); }
static Q_DECL_CONSTEXPR result_type max() { return (std::numeric_limits<result_type>::max)(); }
+ static Q_DECL_CONST_FUNCTION Q_CORE_EXPORT QRandomGenerator64 *system();
+ static Q_DECL_CONST_FUNCTION Q_CORE_EXPORT QRandomGenerator64 *global();
+ static Q_CORE_EXPORT QRandomGenerator64 securelySeeded();
+#endif // Q_QDOC
};
+inline QRandomGenerator *QRandomGenerator::system()
+{
+ return QRandomGenerator64::system();
+}
+
+inline QRandomGenerator *QRandomGenerator::global()
+{
+ return QRandomGenerator64::global();
+}
+
+QRandomGenerator QRandomGenerator::securelySeeded()
+{
+ return QRandomGenerator64::securelySeeded();
+}
QT_END_NAMESPACE
diff --git a/src/corelib/global/qrandom_p.h b/src/corelib/global/qrandom_p.h
index 6ac2904e1b..917a91098e 100644
--- a/src/corelib/global/qrandom_p.h
+++ b/src/corelib/global/qrandom_p.h
@@ -52,11 +52,12 @@
//
#include "qglobal_p.h"
+#include <private/qsimd_p.h>
QT_BEGIN_NAMESPACE
enum QRandomGeneratorControl {
- SkipMemfill = 1,
+ UseSystemRNG = 1,
SkipSystemRNG = 2,
SkipHWRNG = 4,
SetRandomData = 8,
@@ -65,6 +66,11 @@ enum QRandomGeneratorControl {
RandomDataMask = 0xfffffff0
};
+enum RNGType {
+ SystemRNG = 0,
+ MersenneTwister = 1
+};
+
#if defined(QT_BUILD_INTERNAL) && defined(QT_BUILD_CORE_LIB)
Q_CORE_EXPORT QBasicAtomicInteger<uint> qt_randomdevice_control = Q_BASIC_ATOMIC_INITIALIZER(0U);
#elif defined(QT_BUILD_INTERNAL)
@@ -73,6 +79,16 @@ extern Q_CORE_EXPORT QBasicAtomicInteger<uint> qt_randomdevice_control;
enum { qt_randomdevice_control = 0 };
#endif
+inline bool qt_has_hwrng()
+{
+#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
+ return qCpuHasFeature(RDRND);
+#else
+ return false;
+#endif
+}
+
+
QT_END_NAMESPACE
#endif // QRANDOM_P_H
diff --git a/src/corelib/io/qfilesystemwatcher_win.cpp b/src/corelib/io/qfilesystemwatcher_win.cpp
index cdb79e7c97..9e43d11e71 100644
--- a/src/corelib/io/qfilesystemwatcher_win.cpp
+++ b/src/corelib/io/qfilesystemwatcher_win.cpp
@@ -308,7 +308,7 @@ void QWindowsRemovableDriveListener::addPath(const QString &p)
notify.dbch_size = sizeof(notify);
notify.dbch_devicetype = DBT_DEVTYP_HANDLE;
notify.dbch_handle = volumeHandle;
- QEventDispatcherWin32 *winEventDispatcher = static_cast<QEventDispatcherWin32 *>(QCoreApplication::eventDispatcher());
+ QEventDispatcherWin32 *winEventDispatcher = static_cast<QEventDispatcherWin32 *>(QAbstractEventDispatcher::instance());
re.devNotify = RegisterDeviceNotification(winEventDispatcher->internalHwnd(),
&notify, DEVICE_NOTIFY_WINDOW_HANDLE);
// Empirically found: The notifications also work when the handle is immediately
@@ -336,7 +336,7 @@ QWindowsFileSystemWatcherEngine::QWindowsFileSystemWatcherEngine(QObject *parent
: QFileSystemWatcherEngine(parent)
{
#ifndef Q_OS_WINRT
- if (QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher()) {
+ if (QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance()) {
m_driveListener = new QWindowsRemovableDriveListener(this);
eventDispatcher->installNativeEventFilter(m_driveListener);
parent->setProperty("_q_driveListener",
diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp
index 82fc34c537..0a3e83206b 100644
--- a/src/corelib/io/qiodevice.cpp
+++ b/src/corelib/io/qiodevice.cpp
@@ -775,6 +775,7 @@ bool QIODevice::open(OpenMode mode)
d->writeBuffers.clear();
d->setReadChannelCount(isReadable() ? 1 : 0);
d->setWriteChannelCount(isWritable() ? 1 : 0);
+ d->errorString.clear();
#if defined QIODEVICE_DEBUG
printf("%p QIODevice::open(0x%x)\n", this, quint32(mode));
#endif
@@ -801,7 +802,6 @@ void QIODevice::close()
emit aboutToClose();
#endif
d->openMode = NotOpen;
- d->errorString.clear();
d->pos = 0;
d->transactionStarted = false;
d->transactionPos = 0;
diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp
index 2bbc4eddd0..8da6d6b16e 100644
--- a/src/corelib/io/qprocess_win.cpp
+++ b/src/corelib/io/qprocess_win.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
+** Copyright (C) 2017 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -48,6 +48,7 @@
#include <qdir.h>
#include <qelapsedtimer.h>
#include <qfileinfo.h>
+#include <qrandom.h>
#include <qregexp.h>
#include <qwineventnotifier.h>
#include <private/qsystemlibrary_p.h>
@@ -99,10 +100,8 @@ static void qt_create_pipe(Q_PIPE *pipe, bool isInputPipe)
wchar_t pipeName[256];
unsigned int attempts = 1000;
forever {
- // ### The user must make sure to call qsrand() to make the pipe names less predictable.
- // ### Replace the call to qrand() with a secure version, once we have it in Qt.
_snwprintf(pipeName, sizeof(pipeName) / sizeof(pipeName[0]),
- L"\\\\.\\pipe\\qt-%X", qrand());
+ L"\\\\.\\pipe\\qt-%X", QRandomGenerator::global()->generate());
DWORD dwOpenMode = FILE_FLAG_OVERLAPPED;
DWORD dwOutputBufferSize = 0;
diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp
index 9072b34f54..1fc32e0f2d 100644
--- a/src/corelib/io/qstorageinfo_unix.cpp
+++ b/src/corelib/io/qstorageinfo_unix.cpp
@@ -544,6 +544,38 @@ void QStorageInfoPrivate::initRootPath()
}
}
+#ifdef Q_OS_LINUX
+// udev encodes the labels with ID_LABEL_FS_ENC which is done with
+// blkid_encode_string(). Within this function some 1-byte utf-8
+// characters not considered safe (e.g. '\' or ' ') are encoded as hex
+static QString decodeFsEncString(const QString &str)
+{
+ QString decoded;
+ decoded.reserve(str.size());
+
+ int i = 0;
+ while (i < str.size()) {
+ if (i <= str.size() - 4) { // we need at least four characters \xAB
+ if (str.at(i) == QLatin1Char('\\') &&
+ str.at(i+1) == QLatin1Char('x')) {
+ bool bOk;
+ const int code = str.midRef(i+2, 2).toInt(&bOk, 16);
+ // only decode characters between 0x20 and 0x7f but not
+ // the backslash to prevent collisions
+ if (bOk && code >= 0x20 && code < 0x80 && code != '\\') {
+ decoded += QChar(code);
+ i += 4;
+ continue;
+ }
+ }
+ }
+ decoded += str.at(i);
+ ++i;
+ }
+ return decoded;
+}
+#endif
+
static inline QString retrieveLabel(const QByteArray &device)
{
#ifdef Q_OS_LINUX
@@ -557,7 +589,7 @@ static inline QString retrieveLabel(const QByteArray &device)
it.next();
QFileInfo fileInfo(it.fileInfo());
if (fileInfo.isSymLink() && fileInfo.symLinkTarget() == devicePath)
- return fileInfo.fileName();
+ return decodeFsEncString(fileInfo.fileName());
}
#elif defined Q_OS_HAIKU
fs_info fsInfo;
diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp
index 5865d9e19a..b8d3e859cf 100644
--- a/src/corelib/io/qtemporaryfile.cpp
+++ b/src/corelib/io/qtemporaryfile.cpp
@@ -165,7 +165,7 @@ QFileSystemEntry::NativePath QTemporaryFileName::generateNext()
Char *rIter = placeholderEnd;
while (rIter != placeholderStart) {
- quint32 rnd = QRandomGenerator::generate();
+ quint32 rnd = QRandomGenerator::global()->generate();
auto applyOne = [&]() {
quint32 v = rnd & ((1 << BitsPerCharacter) - 1);
rnd >>= BitsPerCharacter;
diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h
index 607cc13a2f..3d24379fa9 100644
--- a/src/corelib/thread/qmutex.h
+++ b/src/corelib/thread/qmutex.h
@@ -67,6 +67,12 @@ class QMutexData;
class Q_CORE_EXPORT QBasicMutex
{
public:
+#ifdef Q_COMPILER_CONSTEXPR
+ constexpr QBasicMutex()
+ : d_ptr(nullptr)
+ {}
+#endif
+
// BasicLockable concept
inline void lock() QT_MUTEX_LOCK_NOEXCEPT {
if (!fastTryLock())
diff --git a/src/corelib/thread/qsemaphore.h b/src/corelib/thread/qsemaphore.h
index a92740c8ce..9de23173e8 100644
--- a/src/corelib/thread/qsemaphore.h
+++ b/src/corelib/thread/qsemaphore.h
@@ -71,8 +71,6 @@ private:
class QSemaphoreReleaser
{
- QSemaphore *m_sem = nullptr;
- int m_n;
public:
QSemaphoreReleaser() = default;
explicit QSemaphoreReleaser(QSemaphore &sem, int n = 1) Q_DECL_NOTHROW
@@ -106,6 +104,10 @@ public:
m_sem = nullptr;
return old;
}
+
+private:
+ QSemaphore *m_sem = nullptr;
+ int m_n;
};
#endif // QT_NO_THREAD
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index ded9ad354e..501f0d345f 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -339,6 +339,7 @@ static void qt_initialize_qhash_seed()
*/
int qGlobalQHashSeed()
{
+ qt_initialize_qhash_seed();
return qt_qhash_seed.load();
}
diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp
index 4c6f08c774..25340f2d02 100644
--- a/src/corelib/tools/qsimd.cpp
+++ b/src/corelib/tools/qsimd.cpp
@@ -652,32 +652,6 @@ Q_CORE_EXPORT QBasicAtomicInteger<unsigned> qt_cpu_features[2] = { Q_BASIC_ATOMI
void qDetectCpuFeatures()
{
-#if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && !defined(Q_CC_INTEL)
-# if Q_CC_GNU < 403
- // GCC 4.2 (at least the one that comes with Apple's XCode, on Mac) is
- // known to be broken beyond repair in dealing with the inline assembly
- // above. It will generate bad code that could corrupt important registers
- // like the PIC register. The behaviour of code after this function would
- // be totally unpredictable.
- //
- // For that reason, simply forego the CPUID check at all and return the set
- // of features that we found at compile time, through the #defines from the
- // compiler. This should at least allow code to execute, even if none of
- // the specialized code found in Qt GUI and elsewhere will ever be enabled
- // (it's the user's fault for using a broken compiler).
- //
- // This also disables the runtime checking that the processor actually
- // contains all the features that the code required. Qt 4 ran for years
- // like that, so it shouldn't be a problem.
-
- qt_cpu_features[0].store(minFeature | quint32(QSimdInitialized));
-#ifndef Q_ATOMIC_INT64_IS_SUPPORTED
- qt_cpu_features[1].store(minFeature >> 32);
-#endif
-
- return;
-# endif
-#endif
quint64 f = detectProcessorFeatures();
QByteArray disable = qgetenv("QT_NO_CPU_FEATURE");
if (!disable.isEmpty()) {
diff --git a/src/corelib/tools/qversionnumber.cpp b/src/corelib/tools/qversionnumber.cpp
index 0f237bce87..b96e48252e 100644
--- a/src/corelib/tools/qversionnumber.cpp
+++ b/src/corelib/tools/qversionnumber.cpp
@@ -388,7 +388,7 @@ QVersionNumber QVersionNumber::commonPrefix(const QVersionNumber &v1,
/*!
\fn QString QVersionNumber::toString() const
- Returns a string with all of the segments delimited by a '.'.
+ Returns a string with all of the segments delimited by a period (\c{.}).
\sa majorVersion(), minorVersion(), microVersion(), segments()
*/
@@ -409,7 +409,7 @@ QString QVersionNumber::toString() const
#if QT_STRINGVIEW_LEVEL < 2
/*!
Constructs a QVersionNumber from a specially formatted \a string of
- non-negative decimal numbers delimited by '.'.
+ non-negative decimal numbers delimited by a period (\c{.}).
Once the numerical segments have been parsed, the remainder of the string
is considered to be the suffix string. The start index of that string will be
diff --git a/src/gui/image/qpixmap_blitter.cpp b/src/gui/image/qpixmap_blitter.cpp
index de32327071..d694352fc1 100644
--- a/src/gui/image/qpixmap_blitter.cpp
+++ b/src/gui/image/qpixmap_blitter.cpp
@@ -41,6 +41,7 @@
#include <qpainter.h>
#include <qimage.h>
+#include <qrandom.h>
#include <qscreen.h>
#include <private/qguiapplication_p.h>
@@ -252,7 +253,7 @@ QImage *QBlittablePlatformPixmap::overlay()
m_rasterOverlay->size() != QSize(w,h)){
m_rasterOverlay = new QImage(w,h,QImage::Format_ARGB32_Premultiplied);
m_rasterOverlay->fill(0x00000000);
- uint color = (qrand() % 11)+7;
+ uint color = QRandomGenerator::global()->bounded(11)+7;
m_overlayColor = QColor(Qt::GlobalColor(color));
m_overlayColor.setAlpha(0x88);
diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h
index 0a060a2d2c..83fc9452c5 100644
--- a/src/gui/kernel/qhighdpiscaling_p.h
+++ b/src/gui/kernel/qhighdpiscaling_p.h
@@ -402,7 +402,8 @@ inline QRegion fromNativeLocalExposedRegion(const QRegion &pixelRegion, const QW
const QPointF topLeftP = rect.topLeft() / scaleFactor;
const QSizeF sizeP = rect.size() / scaleFactor;
pointRegion += QRect(QPoint(qFloor(topLeftP.x()), qFloor(topLeftP.y())),
- QSize(qCeil(sizeP.width()), qCeil(sizeP.height())));
+ QPoint(qCeil(topLeftP.x() + sizeP.width() - 1.0),
+ qCeil(topLeftP.y() + sizeP.height() - 1.0)));
}
return pointRegion;
}
diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp
index 406fcdd226..6298dd5f45 100644
--- a/src/gui/kernel/qopenglcontext.cpp
+++ b/src/gui/kernel/qopenglcontext.cpp
@@ -1008,6 +1008,7 @@ bool QOpenGLContext::makeCurrent(QSurface *surface)
|| qstrncmp(rendererString, "Adreno 4xx", 8) == 0 // Same as above but without the '(TM)'
|| qstrcmp(rendererString, "GC800 core") == 0
|| qstrcmp(rendererString, "GC1000 core") == 0
+ || strstr(rendererString, "GC2000") != 0
|| qstrcmp(rendererString, "Immersion.16") == 0;
}
needsWorkaroundSet = true;
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index 369f3ea3ab..fea55e459d 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -55,6 +55,7 @@
# include "qaccessible.h"
#endif
#include "qhighdpiscaling_p.h"
+#include "qshapedpixmapdndwindow_p.h"
#include <private/qevent_p.h>
@@ -379,7 +380,9 @@ void QWindowPrivate::setVisible(bool visible)
QGuiApplicationPrivate::showModalWindow(q);
else
QGuiApplicationPrivate::hideModalWindow(q);
- } else if (visible && QGuiApplication::modalWindow()) {
+ // QShapedPixmapWindow is used on some platforms for showing a drag pixmap, so don't block
+ // input to this window as it is performing a drag - QTBUG-63846
+ } else if (visible && QGuiApplication::modalWindow() && !qobject_cast<QShapedPixmapWindow *>(q)) {
QGuiApplicationPrivate::updateBlockedStatus(q);
}
diff --git a/src/gui/opengl/qopenglgradientcache.cpp b/src/gui/opengl/qopenglgradientcache.cpp
index 58dcbed50a..3aa4c0d2e6 100644
--- a/src/gui/opengl/qopenglgradientcache.cpp
+++ b/src/gui/opengl/qopenglgradientcache.cpp
@@ -42,6 +42,7 @@
#include <private/qopenglcontext_p.h>
#include <private/qrgba64_p.h>
#include <QtCore/qmutex.h>
+#include <QtCore/qrandom.h>
#include "qopenglfunctions.h"
#include "qopenglextensions_p.h"
@@ -137,7 +138,7 @@ GLuint QOpenGL2GradientCache::addCacheElement(quint64 hash_val, const QGradient
{
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
if (cache.size() == maxCacheSize()) {
- int elem_to_remove = qrand() % maxCacheSize();
+ int elem_to_remove = QRandomGenerator::global()->bounded(maxCacheSize());
quint64 key = cache.keys()[elem_to_remove];
// need to call glDeleteTextures on each removed cache entry:
diff --git a/src/gui/painting/qcoregraphics.mm b/src/gui/painting/qcoregraphics.mm
index a234a12bf0..e1601d87dc 100644
--- a/src/gui/painting/qcoregraphics.mm
+++ b/src/gui/painting/qcoregraphics.mm
@@ -110,6 +110,7 @@ NSImage *qt_mac_create_nsimage(const QPixmap &pm)
QImage image = pm.toImage();
CGImageRef cgImage = qt_mac_toCGImage(image);
NSImage *nsImage = qt_mac_cgimage_to_nsimage(cgImage);
+ nsImage.size = (pm.size() / pm.devicePixelRatioF()).toCGSize();
CGImageRelease(cgImage);
return nsImage;
}
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 68554c6579..d0d948bbb7 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -50,6 +50,7 @@
#include <qdebug.h>
#include <qbitmap.h>
#include <qmath.h>
+#include <qrandom.h>
// #include <private/qdatabuffer_p.h>
// #include <private/qpainter_p.h>
@@ -4229,7 +4230,7 @@ protected:
QSharedPointer<const CacheInfo> addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) {
if (cache.size() == maxCacheSize()) {
// may remove more than 1, but OK
- cache.erase(cache.begin() + (qrand() % maxCacheSize()));
+ cache.erase(cache.begin() + QRandomGenerator::global()->bounded(maxCacheSize()));
}
auto cache_entry = QSharedPointer<CacheInfo>::create(gradient.stops(), opacity, gradient.interpolationMode());
generateGradientColorTable(gradient, cache_entry->buffer64, paletteSize(), opacity);
diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp
index 86a53c21a3..2a7e0eaa0c 100644
--- a/src/gui/painting/qtextureglyphcache.cpp
+++ b/src/gui/painting/qtextureglyphcache.cpp
@@ -318,11 +318,12 @@ void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g, QFixed subP
return;
}
#endif
+ Q_ASSERT(mask.width() <= c.w && mask.height() <= c.h);
if (m_format == QFontEngine::Format_A32
|| m_format == QFontEngine::Format_ARGB) {
QImage ref(m_image.bits() + (c.x * 4 + c.y * m_image.bytesPerLine()),
- qMax(mask.width(), c.w), qMax(mask.height(), c.h), m_image.bytesPerLine(),
+ qMin(mask.width(), c.w), qMin(mask.height(), c.h), m_image.bytesPerLine(),
m_image.format());
QPainter p(&ref);
p.setCompositionMode(QPainter::CompositionMode_Source);
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index f0a5053196..438cd3de3a 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -727,11 +727,9 @@ void QFont::setFamily(const QString &family)
/*!
\since 4.8
- Returns the requested font style name, it will be used to match the
+ Returns the requested font style name. This can be used to match the
font with irregular styles (that can't be normalized in other style
- properties). It depends on system font support, thus only works for
- \macos and X11 so far. On Windows irregular styles will be added
- as separate font families so there is no need for this.
+ properties).
\sa setFamily(), setStyle()
*/
@@ -744,7 +742,12 @@ QString QFont::styleName() const
\since 4.8
Sets the style name of the font to \a styleName. When set, other style properties
- like \l style() and \l weight() will be ignored for font matching.
+ like \l style() and \l weight() will be ignored for font matching, though they may be
+ simulated afterwards if supported by the platform's font engine.
+
+ Due to the lower quality of artificially simulated styles, and the lack of full cross
+ platform support, it is not recommended to use matching by style name together with
+ matching by style properties
\sa styleName()
*/
@@ -985,6 +988,10 @@ int QFont::pixelSize() const
Sets the style() of the font to QFont::StyleItalic if \a enable is true;
otherwise the style is set to QFont::StyleNormal.
+ \note If styleName() is set, this value may be ignored, or if supported
+ on the platform, the font may be rendered tilted instead of picking a
+ designed italic font-variant.
+
\sa italic(), QFontInfo
*/
@@ -1050,6 +1057,8 @@ int QFont::weight() const
Sets the weight of the font to \a weight, using the scale defined by
\l QFont::Weight enumeration.
+ \note If styleName() is set, this value may be ignored for font selection.
+
\sa weight(), QFontInfo
*/
void QFont::setWeight(int weight)
@@ -1083,6 +1092,9 @@ void QFont::setWeight(int weight)
For finer boldness control use setWeight().
+ \note If styleName() is set, this value may be ignored, or if supported
+ on the platform, the font artificially embolded.
+
\sa bold(), setWeight()
*/
diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp
index 4b330c491a..42f1343c52 100644
--- a/src/network/access/qhttp2protocolhandler.cpp
+++ b/src/network/access/qhttp2protocolhandler.cpp
@@ -1103,7 +1103,7 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader
QByteArray binder(", ");
if (name == "set-cookie")
binder = "\n";
- httpReply->setHeaderField(name, value.replace('\0', binder));
+ httpReplyPrivate->fields.append(qMakePair(name, value.replace('\0', binder)));
}
}
diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri
index 54b61f3ad3..b822a70e88 100644
--- a/src/network/kernel/kernel.pri
+++ b/src/network/kernel/kernel.pri
@@ -6,7 +6,7 @@ INCLUDEPATH += $$PWD
HEADERS += kernel/qtnetworkglobal.h \
kernel/qtnetworkglobal_p.h \
kernel/qauthenticator.h \
- kernel/qauthenticator_p.h \
+ kernel/qauthenticator_p.h \
kernel/qdnslookup.h \
kernel/qdnslookup_p.h \
kernel/qhostaddress.h \
diff --git a/src/network/kernel/qdnslookup.cpp b/src/network/kernel/qdnslookup.cpp
index 6203ba37b3..10ff35b72c 100644
--- a/src/network/kernel/qdnslookup.cpp
+++ b/src/network/kernel/qdnslookup.cpp
@@ -42,7 +42,7 @@
#include <qcoreapplication.h>
#include <qdatetime.h>
-#include <qthreadstorage.h>
+#include <qrandom.h>
#include <qurl.h>
#include <algorithm>
@@ -50,7 +50,6 @@
QT_BEGIN_NAMESPACE
Q_GLOBAL_STATIC(QDnsLookupThreadPool, theDnsLookupThreadPool);
-Q_GLOBAL_STATIC(QThreadStorage<bool *>, theDnsLookupSeedStorage);
static bool qt_qdnsmailexchangerecord_less_than(const QDnsMailExchangeRecord &r1, const QDnsMailExchangeRecord &r2)
{
@@ -85,7 +84,7 @@ static void qt_qdnsmailexchangerecord_sort(QList<QDnsMailExchangeRecord> &record
// Randomize the slice of records.
while (!slice.isEmpty()) {
- const unsigned int pos = qrand() % slice.size();
+ const unsigned int pos = QRandomGenerator::global()->bounded(slice.size());
records[i++] = slice.takeAt(pos);
}
}
@@ -134,7 +133,7 @@ static void qt_qdnsservicerecord_sort(QList<QDnsServiceRecord> &records)
// Order the slice of records.
while (!slice.isEmpty()) {
- const unsigned int weightThreshold = qrand() % (sliceWeight + 1);
+ const unsigned int weightThreshold = QRandomGenerator::global()->bounded(sliceWeight + 1);
unsigned int summedWeight = 0;
for (int j = 0; j < slice.size(); ++j) {
summedWeight += slice.at(j).weight();
@@ -1011,10 +1010,6 @@ void QDnsLookupRunnable::run()
query(requestType, requestName, nameserver, &reply);
// Sort results.
- if (!theDnsLookupSeedStorage()->hasLocalData()) {
- qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()) ^ reinterpret_cast<quintptr>(this));
- theDnsLookupSeedStorage()->setLocalData(new bool(true));
- }
qt_qdnsmailexchangerecord_sort(reply.mailExchangeRecords);
qt_qdnsservicerecord_sort(reply.serviceRecords);
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
index 7556bb98f4..bd368ac42f 100644
--- a/src/network/socket/qnativesocketengine_win.cpp
+++ b/src/network/socket/qnativesocketengine_win.cpp
@@ -408,13 +408,13 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
// get the pointer to sendmsg and recvmsg
DWORD bytesReturned;
GUID recvmsgguid = WSAID_WSARECVMSG;
- if (WSAIoctl(socketDescriptor, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ if (WSAIoctl(socket, SIO_GET_EXTENSION_FUNCTION_POINTER,
&recvmsgguid, sizeof(recvmsgguid),
&recvmsg, sizeof(recvmsg), &bytesReturned, NULL, NULL) == SOCKET_ERROR)
recvmsg = 0;
GUID sendmsgguid = WSAID_WSASENDMSG;
- if (WSAIoctl(socketDescriptor, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ if (WSAIoctl(socket, SIO_GET_EXTENSION_FUNCTION_POINTER,
&sendmsgguid, sizeof(sendmsgguid),
&sendmsg, sizeof(sendmsg), &bytesReturned, NULL, NULL) == SOCKET_ERROR)
sendmsg = 0;
@@ -1255,26 +1255,28 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxL
qt_socket_getPortAndAddress(socketDescriptor, &aa, &header->senderPort, &header->senderAddress);
}
- if (ret != -1 && recvmsg) {
+ if (ret != -1 && recvmsg && options != QAbstractSocketEngine::WantNone) {
// get the ancillary data
+ header->destinationPort = localPort;
WSACMSGHDR *cmsgptr;
for (cmsgptr = WSA_CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
cmsgptr = WSA_CMSG_NXTHDR(&msg, cmsgptr)) {
if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_PKTINFO
&& cmsgptr->cmsg_len >= WSA_CMSG_LEN(sizeof(in6_pktinfo))) {
in6_pktinfo *info = reinterpret_cast<in6_pktinfo *>(WSA_CMSG_DATA(cmsgptr));
- QHostAddress target(reinterpret_cast<quint8 *>(&info->ipi6_addr));
- if (info->ipi6_ifindex)
- target.setScopeId(QString::number(info->ipi6_ifindex));
+
+ header->destinationAddress.setAddress(reinterpret_cast<quint8 *>(&info->ipi6_addr));
+ header->ifindex = info->ipi6_ifindex;
+ if (header->ifindex)
+ header->destinationAddress.setScopeId(QString::number(info->ipi6_ifindex));
}
if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_PKTINFO
&& cmsgptr->cmsg_len >= WSA_CMSG_LEN(sizeof(in_pktinfo))) {
in_pktinfo *info = reinterpret_cast<in_pktinfo *>(WSA_CMSG_DATA(cmsgptr));
u_long addr;
WSANtohl(socketDescriptor, info->ipi_addr.s_addr, &addr);
- QHostAddress target(addr);
- if (info->ipi_ifindex)
- target.setScopeId(QString::number(info->ipi_ifindex));
+ header->destinationAddress.setAddress(addr);
+ header->ifindex = info->ipi_ifindex;
}
if (cmsgptr->cmsg_len == WSA_CMSG_LEN(sizeof(int))
diff --git a/src/opengl/gl2paintengineex/qglgradientcache.cpp b/src/opengl/gl2paintengineex/qglgradientcache.cpp
index b4ca49514f..fc5e236ca6 100644
--- a/src/opengl/gl2paintengineex/qglgradientcache.cpp
+++ b/src/opengl/gl2paintengineex/qglgradientcache.cpp
@@ -41,6 +41,7 @@
#include <private/qdrawhelper_p.h>
#include <private/qgl_p.h>
#include <QtCore/qmutex.h>
+#include <QtCore/qrandom.h>
QT_BEGIN_NAMESPACE
@@ -130,7 +131,7 @@ GLuint QGL2GradientCache::addCacheElement(quint64 hash_val, const QGradient &gra
{
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
if (cache.size() == maxCacheSize()) {
- int elem_to_remove = qrand() % maxCacheSize();
+ int elem_to_remove = QRandomGenerator::global()->bounded(maxCacheSize());
quint64 key = cache.keys()[elem_to_remove];
// need to call glDeleteTextures on each removed cache entry:
diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
index 4a197fd6ef..73def00017 100644
--- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
+++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
@@ -1771,15 +1771,25 @@ QFixed QFontEngineFT::scaledBitmapMetrics(QFixed m) const
return m * scalableBitmapScaleFactor;
}
-glyph_metrics_t QFontEngineFT::scaledBitmapMetrics(const glyph_metrics_t &m) const
+glyph_metrics_t QFontEngineFT::scaledBitmapMetrics(const glyph_metrics_t &m, const QTransform &t) const
{
+ QTransform trans(t);
+ const qreal scaleFactor = scalableBitmapScaleFactor.toReal();
+ trans.scale(scaleFactor, scaleFactor);
+
+ QRectF rect(m.x.toReal(), m.y.toReal(), m.width.toReal(), m.height.toReal());
+ QPointF offset(m.xoff.toReal(), m.yoff.toReal());
+
+ rect = trans.mapRect(rect);
+ offset = trans.map(offset);
+
glyph_metrics_t metrics;
- metrics.x = scaledBitmapMetrics(m.x);
- metrics.y = scaledBitmapMetrics(m.y);
- metrics.width = scaledBitmapMetrics(m.width);
- metrics.height = scaledBitmapMetrics(m.height);
- metrics.xoff = scaledBitmapMetrics(m.xoff);
- metrics.yoff = scaledBitmapMetrics(m.yoff);
+ metrics.x = QFixed::fromReal(rect.x());
+ metrics.y = QFixed::fromReal(rect.y());
+ metrics.width = QFixed::fromReal(rect.width());
+ metrics.height = QFixed::fromReal(rect.height());
+ metrics.xoff = QFixed::fromReal(offset.x());
+ metrics.yoff = QFixed::fromReal(offset.y());
return metrics;
}
@@ -1873,7 +1883,7 @@ glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
unlockFace();
if (isScalableBitmap())
- overall = scaledBitmapMetrics(overall);
+ overall = scaledBitmapMetrics(overall, QTransform());
return overall;
}
@@ -1912,7 +1922,7 @@ glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
unlockFace();
if (isScalableBitmap())
- overall = scaledBitmapMetrics(overall);
+ overall = scaledBitmapMetrics(overall, QTransform());
return overall;
}
@@ -1950,7 +1960,7 @@ glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixe
}
if (isScalableBitmap())
- overall = scaledBitmapMetrics(overall);
+ overall = scaledBitmapMetrics(overall, matrix);
return overall;
}
diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h b/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h
index 2993e3b616..c063f5df30 100644
--- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h
+++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h
@@ -321,7 +321,7 @@ private:
int loadFlags(QGlyphSet *set, GlyphFormat format, int flags, bool &hsubpixel, int &vfactor) const;
bool shouldUseDesignMetrics(ShaperFlags flags) const;
QFixed scaledBitmapMetrics(QFixed m) const;
- glyph_metrics_t scaledBitmapMetrics(const glyph_metrics_t &m) const;
+ glyph_metrics_t scaledBitmapMetrics(const glyph_metrics_t &m, const QTransform &matrix) const;
GlyphFormat defaultFormat;
FT_Matrix matrix;
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h
index dc7c5916a3..2fc5156d24 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.h
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.h
@@ -60,8 +60,9 @@ QT_BEGIN_NAMESPACE
class QCocoaScreen;
-class QCocoaIntegration : public QPlatformIntegration
+class QCocoaIntegration : public QObject, public QPlatformIntegration
{
+ Q_OBJECT
public:
enum Option {
UseFreeTypeFontEngine = 0x1
@@ -120,6 +121,9 @@ public:
void beep() const Q_DECL_OVERRIDE;
+private Q_SLOTS:
+ void focusWindowChanged(QWindow *);
+
private:
static QCocoaIntegration *mInstance;
Options mOptions;
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index d185905782..55b3805df3 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -179,6 +179,9 @@ QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
QMacInternalPasteboardMime::initializeMimeTypes();
QCocoaMimeTypes::initializeMimeTypes();
QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
+
+ connect(qGuiApp, &QGuiApplication::focusWindowChanged,
+ this, &QCocoaIntegration::focusWindowChanged);
}
QCocoaIntegration::~QCocoaIntegration()
@@ -510,4 +513,33 @@ void QCocoaIntegration::beep() const
NSBeep();
}
+void QCocoaIntegration::focusWindowChanged(QWindow *focusWindow)
+{
+ // Don't revert icon just because we lost focus
+ if (!focusWindow)
+ return;
+
+ static bool hasDefaultApplicationIcon = [](){
+ NSImage *genericApplicationIcon = [[NSWorkspace sharedWorkspace]
+ iconForFileType:NSFileTypeForHFSTypeCode(kGenericApplicationIcon)];
+ NSImage *applicationIcon = [NSImage imageNamed:NSImageNameApplicationIcon];
+
+ NSRect rect = NSMakeRect(0, 0, 32, 32);
+ return [applicationIcon CGImageForProposedRect:&rect context:nil hints:nil]
+ == [genericApplicationIcon CGImageForProposedRect:&rect context:nil hints:nil];
+ }();
+
+ // Don't let the window icon override an explicit application icon set in the Info.plist
+ if (!hasDefaultApplicationIcon)
+ return;
+
+ // Or an explicit application icon set on QGuiApplication
+ if (!qGuiApp->windowIcon().isNull())
+ return;
+
+ setApplicationIcon(focusWindow->icon());
+}
+
+#include "moc_qcocoaintegration.cpp"
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.h b/src/plugins/platforms/cocoa/qcocoamenu.h
index 484f185fc0..5081fc78c6 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.h
+++ b/src/plugins/platforms/cocoa/qcocoamenu.h
@@ -93,6 +93,8 @@ public:
void timerEvent(QTimerEvent *e) Q_DECL_OVERRIDE;
+ void syncMenuItem_helper(QPlatformMenuItem *menuItem, bool menubarUpdate);
+
private:
QCocoaMenuItem *itemOrNull(int index) const;
void insertNative(QCocoaMenuItem *item, QCocoaMenuItem *beforeItem);
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index eeb4c01791..a54284dbae 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -434,6 +434,11 @@ void QCocoaMenu::timerEvent(QTimerEvent *e)
void QCocoaMenu::syncMenuItem(QPlatformMenuItem *menuItem)
{
+ syncMenuItem_helper(menuItem, false /*menubarUpdate*/);
+}
+
+void QCocoaMenu::syncMenuItem_helper(QPlatformMenuItem *menuItem, bool menubarUpdate)
+{
QMacAutoReleasePool pool;
QCocoaMenuItem *cocoaItem = static_cast<QCocoaMenuItem *>(menuItem);
if (!m_menuItems.contains(cocoaItem)) {
@@ -443,8 +448,9 @@ void QCocoaMenu::syncMenuItem(QPlatformMenuItem *menuItem)
const bool wasMerged = cocoaItem->isMerged();
NSMenuItem *oldItem = cocoaItem->nsItem();
+ NSMenuItem *syncedItem = cocoaItem->sync();
- if (cocoaItem->sync() != oldItem) {
+ if (syncedItem != oldItem) {
// native item was changed for some reason
if (oldItem) {
if (wasMerged) {
@@ -462,6 +468,14 @@ void QCocoaMenu::syncMenuItem(QPlatformMenuItem *menuItem)
// when an item's enabled state changes after menuWillOpen:
scheduleUpdate();
}
+
+ // This may be a good moment to attach this item's eventual submenu to the
+ // synced item, but only on the condition we're all currently hooked to the
+ // menunbar. A good indicator of this being the right moment is knowing that
+ // we got called from QCocoaMenuBar::updateMenuBarImmediately().
+ if (menubarUpdate)
+ if (QCocoaMenu *submenu = cocoaItem->menu())
+ submenu->setAttachedItem(syncedItem);
}
void QCocoaMenu::syncSeparatorsCollapsible(bool enable)
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.h b/src/plugins/platforms/cocoa/qcocoamenubar.h
index 0725e9db68..a4ee531e91 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.h
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.h
@@ -72,6 +72,8 @@ public:
QList<QCocoaMenuItem*> merged() const;
NSMenuItem *itemForRole(QPlatformMenuItem::MenuRole r);
+ void syncMenu_helper(QPlatformMenu *menu, bool menubarUpdate);
+
private:
static QCocoaWindow *findWindowForMenubar();
static QCocoaMenuBar *findGlobalMenubar();
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm
index 3e466c9587..a4cd465dae 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm
@@ -155,7 +155,7 @@ void QCocoaMenuBar::insertMenu(QPlatformMenu *platformMenu, QPlatformMenu *befor
}
}
- syncMenu(menu);
+ syncMenu_helper(menu, false /*internaCall*/);
if (needsImmediateUpdate())
updateMenuBarImmediately();
@@ -183,11 +183,16 @@ void QCocoaMenuBar::removeMenu(QPlatformMenu *platformMenu)
void QCocoaMenuBar::syncMenu(QPlatformMenu *menu)
{
+ syncMenu_helper(menu, false /*internaCall*/);
+}
+
+void QCocoaMenuBar::syncMenu_helper(QPlatformMenu *menu, bool menubarUpdate)
+{
QMacAutoReleasePool pool;
QCocoaMenu *cocoaMenu = static_cast<QCocoaMenu *>(menu);
Q_FOREACH (QCocoaMenuItem *item, cocoaMenu->items())
- cocoaMenu->syncMenuItem(item);
+ cocoaMenu->syncMenuItem_helper(item, menubarUpdate);
BOOL shouldHide = YES;
if (cocoaMenu->isVisible()) {
@@ -357,7 +362,7 @@ void QCocoaMenuBar::updateMenuBarImmediately()
menu->setAttachedItem(item);
menu->setMenuParent(mb);
// force a sync?
- mb->syncMenu(menu);
+ mb->syncMenu_helper(menu, true /*menubarUpdate*/);
menu->propagateEnabledState(!disableForModal);
}
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
index 606f1ed215..eaf310ec51 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
@@ -149,10 +149,6 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu)
QMacAutoReleasePool pool;
m_menu = static_cast<QCocoaMenu *>(menu);
if (m_menu) {
- if (m_native) {
- // Skip automatic menu item validation
- m_native.action = nil;
- }
m_menu->setMenuParent(this);
m_menu->propagateEnabledState(isEnabled());
} else {
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index af44564968..d1f19f2de9 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -1442,6 +1442,21 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel)
applyContentBorderThickness(nsWindow);
+ // Prevent CoreGraphics RGB32 -> RGB64 backing store conversions on deep color
+ // displays by forcing 8-bit components, unless a deep color format has been
+ // requested. This conversion uses significant CPU time.
+ QSurface::SurfaceType surfaceType = QPlatformWindow::window()->surfaceType();
+ bool usesCoreGraphics = surfaceType == QSurface::RasterSurface || surfaceType == QSurface::RasterGLSurface;
+ QSurfaceFormat surfaceFormat = QPlatformWindow::window()->format();
+ bool usesDeepColor = surfaceFormat.redBufferSize() > 8 ||
+ surfaceFormat.greenBufferSize() > 8 ||
+ surfaceFormat.blueBufferSize() > 8;
+ bool usesLayer = view().layer;
+ if (usesCoreGraphics && !usesDeepColor && !usesLayer) {
+ [nsWindow setDynamicDepthLimit:NO];
+ [nsWindow setDepthLimit:NSWindowDepthTwentyfourBitRGB];
+ }
+
return nsWindow;
}
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 9708aa4ce6..28ffcf8718 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -1884,6 +1884,7 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
}
else {
NSImage *nsimage = qt_mac_create_nsimage(pixmapCursor);
+ nsimage.size = NSSizeFromCGSize((pixmapCursor.size() / pixmapCursor.devicePixelRatioF()).toCGSize());
nativeCursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSZeroPoint];
[nsimage release];
}
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
index 3eb8675d77..75bb786b28 100644
--- a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
@@ -61,6 +61,7 @@
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatforminputcontextfactory_p.h>
#include <qpa/qplatforminputcontext.h>
+#include <qpa/qplatformtheme.h>
#include <qpa/qplatformservices.h>
@@ -167,6 +168,37 @@ QAbstractEventDispatcher *QOffscreenIntegration::createEventDispatcher() const
#endif
}
+static QString themeName() { return QStringLiteral("offscreen"); }
+
+QStringList QOffscreenIntegration::themeNames() const
+{
+ return QStringList(themeName());
+}
+
+// Restrict the styles to "fusion" to prevent native styles requiring native
+// window handles (eg Windows Vista style) from being used.
+class OffscreenTheme : public QPlatformTheme
+{
+public:
+ OffscreenTheme() {}
+
+ QVariant themeHint(ThemeHint h) const override
+ {
+ switch (h) {
+ case StyleNames:
+ return QVariant(QStringList(QStringLiteral("fusion")));
+ default:
+ break;
+ }
+ return QPlatformTheme::themeHint(h);
+ }
+};
+
+QPlatformTheme *QOffscreenIntegration::createPlatformTheme(const QString &name) const
+{
+ return name == themeName() ? new OffscreenTheme() : nullptr;
+}
+
QPlatformFontDatabase *QOffscreenIntegration::fontDatabase() const
{
return m_fontDatabase.data();
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.h b/src/plugins/platforms/offscreen/qoffscreenintegration.h
index 569ec8fc28..f72587d11a 100644
--- a/src/plugins/platforms/offscreen/qoffscreenintegration.h
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration.h
@@ -69,6 +69,9 @@ public:
QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE;
QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE;
+ QStringList themeNames() const;
+ QPlatformTheme *createPlatformTheme(const QString &name) const;
+
static QOffscreenIntegration *createOffscreenIntegration();
private:
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
index 26779f0c01..e713debf5b 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
@@ -992,7 +992,9 @@ void QWindowsNativeFileDialogBase::setMode(QFileDialogOptions::FileMode mode,
break;
case QFileDialogOptions::Directory:
case QFileDialogOptions::DirectoryOnly:
- flags |= FOS_PICKFOLDERS | FOS_FILEMUSTEXIST;
+ // QTBUG-63645: Restrict to file system items, as Qt cannot deal with
+ // places like 'Network', etc.
+ flags |= FOS_PICKFOLDERS | FOS_FILEMUSTEXIST | FOS_FORCEFILESYSTEM;
break;
case QFileDialogOptions::ExistingFiles:
flags |= FOS_FILEMUSTEXIST | FOS_ALLOWMULTISELECT;
@@ -1201,6 +1203,8 @@ void QWindowsNativeFileDialogBase::onSelectionChange()
{
const QList<QUrl> current = selectedFiles();
m_data.setSelectedFiles(current);
+ qDebug() << __FUNCTION__ << current << current.size();
+
if (current.size() == 1)
emit currentChanged(current.front());
}
@@ -1397,7 +1401,7 @@ QList<QUrl> QWindowsNativeOpenFileDialog::dialogResult() const
for (IShellItem *item : QWindowsShellItem::itemsFromItemArray(items)) {
QWindowsShellItem qItem(item);
const QString path = qItem.path();
- if (path.isEmpty()) {
+ if (path.isEmpty() && !qItem.isDir()) {
const QString temporaryCopy = createTemporaryItemCopy(qItem);
if (temporaryCopy.isEmpty())
qWarning() << "Unable to create a local copy of" << qItem;
diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
index 3ee591de8c..901d132ea5 100644
--- a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
+++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
@@ -354,7 +354,7 @@ HICON QWindowsSystemTrayIcon::createIcon(const QIcon &icon)
m_hIcon = nullptr;
if (icon.isNull())
return oldIcon;
- const QSize requestedSize(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
+ const QSize requestedSize = QSize(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
const QSize size = icon.actualSize(requestedSize);
const QPixmap pm = icon.pixmap(size);
if (!pm.isNull())
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index 58e99ef3de..f90f189146 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -249,7 +249,7 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting)
isTablet = true;
tabletData.pointerType = QTabletEvent::Eraser;
dbgType = QLatin1String("eraser");
- } else if (name.contains("cursor")) {
+ } else if (name.contains("cursor") && !(name.contains("cursor controls") && name.contains("trackball"))) {
isTablet = true;
tabletData.pointerType = QTabletEvent::Cursor;
dbgType = QLatin1String("cursor");
diff --git a/src/plugins/sqldrivers/oci/qsql_oci.cpp b/src/plugins/sqldrivers/oci/qsql_oci.cpp
index a4793351de..9ce2fc1b55 100644
--- a/src/plugins/sqldrivers/oci/qsql_oci.cpp
+++ b/src/plugins/sqldrivers/oci/qsql_oci.cpp
@@ -2603,7 +2603,7 @@ QSqlIndex QOCIDriver::primaryIndex(const QString& tablename) const
QString stmt(QLatin1String("select b.column_name, b.index_name, a.table_name, a.owner "
"from all_constraints a, all_ind_columns b "
"where a.constraint_type='P' "
- "and b.index_name = a.constraint_name "
+ "and b.index_name = a.index_name "
"and b.index_owner = a.owner"));
bool buildIndex = false;
diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp
index a3aa0f6593..0f4b7a80af 100644
--- a/src/plugins/sqldrivers/psql/qsql_psql.cpp
+++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp
@@ -181,13 +181,14 @@ public:
QPSQLDriver::Protocol getPSQLVersion();
bool setEncodingUtf8();
void setDatestyle();
+ void setByteaOutput();
void detectBackslashEscape();
};
void QPSQLDriverPrivate::appendTables(QStringList &tl, QSqlQuery &t, QChar type)
{
QString query;
- if (pro >= QPSQLDriver::Version73) {
+ if (pro >= QPSQLDriver::Version7_3) {
query = QString::fromLatin1("select pg_class.relname, pg_namespace.nspname from pg_class "
"left join pg_namespace on (pg_class.relnamespace = pg_namespace.oid) "
"where (pg_class.relkind = '%1') and (pg_class.relname !~ '^Inv') "
@@ -525,7 +526,7 @@ int QPSQLResult::numRowsAffected()
QVariant QPSQLResult::lastInsertId() const
{
Q_D(const QPSQLResult);
- if (d->drv_d_func()->pro >= QPSQLDriver::Version81) {
+ if (d->drv_d_func()->pro >= QPSQLDriver::Version8_1) {
QSqlQuery qry(driver()->createResult());
// Most recent sequence value obtained from nextval
if (qry.exec(QLatin1String("SELECT lastval();")) && qry.next())
@@ -698,11 +699,25 @@ void QPSQLDriverPrivate::setDatestyle()
PQclear(result);
}
+void QPSQLDriverPrivate::setByteaOutput()
+{
+ if (pro >= QPSQLDriver::Version9) {
+ // Server version before QPSQLDriver::Version9 only supports escape mode for bytea type,
+ // but bytea format is set to hex by default in PSQL 9 and above. So need to force the
+ // server to use the old escape mode when connects to the new server.
+ PGresult *result = exec("SET bytea_output TO escape");
+ int status = PQresultStatus(result);
+ if (status != PGRES_COMMAND_OK)
+ qWarning("%s", PQerrorMessage(connection));
+ PQclear(result);
+ }
+}
+
void QPSQLDriverPrivate::detectBackslashEscape()
{
// standard_conforming_strings option introduced in 8.2
// http://www.postgresql.org/docs/8.2/static/runtime-config-compatible.html
- if (pro < QPSQLDriver::Version82) {
+ if (pro < QPSQLDriver::Version8_2) {
hasBackslashEscape = true;
} else {
hasBackslashEscape = false;
@@ -724,11 +739,11 @@ static QPSQLDriver::Protocol qMakePSQLVersion(int vMaj, int vMin)
{
switch (vMin) {
case 1:
- return QPSQLDriver::Version71;
+ return QPSQLDriver::Version7_1;
case 3:
- return QPSQLDriver::Version73;
+ return QPSQLDriver::Version7_3;
case 4:
- return QPSQLDriver::Version74;
+ return QPSQLDriver::Version7_4;
default:
return QPSQLDriver::Version7;
}
@@ -738,76 +753,102 @@ static QPSQLDriver::Protocol qMakePSQLVersion(int vMaj, int vMin)
{
switch (vMin) {
case 1:
- return QPSQLDriver::Version81;
+ return QPSQLDriver::Version8_1;
case 2:
- return QPSQLDriver::Version82;
+ return QPSQLDriver::Version8_2;
case 3:
- return QPSQLDriver::Version83;
+ return QPSQLDriver::Version8_3;
case 4:
- return QPSQLDriver::Version84;
+ return QPSQLDriver::Version8_4;
default:
return QPSQLDriver::Version8;
}
break;
}
case 9:
- return QPSQLDriver::Version9;
+ {
+ switch (vMin) {
+ case 1:
+ return QPSQLDriver::Version9_1;
+ case 2:
+ return QPSQLDriver::Version9_2;
+ case 3:
+ return QPSQLDriver::Version9_3;
+ case 4:
+ return QPSQLDriver::Version9_4;
+ case 5:
+ return QPSQLDriver::Version9_5;
+ case 6:
+ return QPSQLDriver::Version9_6;
+ default:
+ return QPSQLDriver::Version9;
+ }
break;
+ }
+ case 10:
+ return QPSQLDriver::Version10;
default:
+ if (vMaj > 10)
+ return QPSQLDriver::UnknownLaterVersion;
break;
}
return QPSQLDriver::VersionUnknown;
}
+static QPSQLDriver::Protocol qFindPSQLVersion(const QString &versionString)
+{
+ const QRegExp rx(QStringLiteral("(\\d+)(?:\\.(\\d+))?"));
+ if (rx.indexIn(versionString) != -1) {
+ // Beginning with PostgreSQL version 10, a major release is indicated by
+ // increasing the first part of the version, e.g. 10 to 11.
+ // Before version 10, a major release was indicated by increasing either
+ // the first or second part of the version number, e.g. 9.5 to 9.6.
+ int vMaj = rx.cap(1).toInt();
+ int vMin;
+ if (vMaj >= 10) {
+ vMin = 0;
+ } else {
+ if (rx.cap(2).isEmpty())
+ return QPSQLDriver::VersionUnknown;
+ vMin = rx.cap(2).toInt();
+ }
+ return qMakePSQLVersion(vMaj, vMin);
+ }
+
+ return QPSQLDriver::VersionUnknown;
+}
+
QPSQLDriver::Protocol QPSQLDriverPrivate::getPSQLVersion()
{
QPSQLDriver::Protocol serverVersion = QPSQLDriver::Version6;
PGresult* result = exec("select version()");
int status = PQresultStatus(result);
if (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK) {
- QString val = QString::fromLatin1(PQgetvalue(result, 0, 0));
-
- QRegExp rx(QLatin1String("(\\d+)\\.(\\d+)"));
- rx.setMinimal(true); // enforce non-greedy RegExp
+ serverVersion = qFindPSQLVersion(
+ QString::fromLatin1(PQgetvalue(result, 0, 0)));
+ }
+ PQclear(result);
- if (rx.indexIn(val) != -1) {
- int vMaj = rx.cap(1).toInt();
- int vMin = rx.cap(2).toInt();
- serverVersion = qMakePSQLVersion(vMaj, vMin);
+ QPSQLDriver::Protocol clientVersion =
#if defined(PG_MAJORVERSION)
- if (rx.indexIn(QLatin1String(PG_MAJORVERSION)) != -1)
+ qFindPSQLVersion(QLatin1String(PG_MAJORVERSION));
#elif defined(PG_VERSION)
- if (rx.indexIn(QLatin1String(PG_VERSION)) != -1)
+ qFindPSQLVersion(QLatin1String(PG_VERSION));
#else
- if (0)
+ QPSQLDriver::VersionUnknown;
#endif
- {
- vMaj = rx.cap(1).toInt();
- vMin = rx.cap(2).toInt();
- QPSQLDriver::Protocol clientVersion = qMakePSQLVersion(vMaj, vMin);
-
- if (serverVersion >= QPSQLDriver::Version9 && clientVersion < QPSQLDriver::Version9) {
- //Client version before QPSQLDriver::Version9 only supports escape mode for bytea type,
- //but bytea format is set to hex by default in PSQL 9 and above. So need to force the
- //server use the old escape mode when connects to the new server with old client library.
- PQclear(result);
- result = exec("SET bytea_output=escape; ");
- status = PQresultStatus(result);
- } else if (serverVersion == QPSQLDriver::VersionUnknown) {
- serverVersion = clientVersion;
- if (serverVersion != QPSQLDriver::VersionUnknown)
- qWarning("The server version of this PostgreSQL is unknown, falling back to the client version.");
- }
- }
- }
+
+ if (serverVersion == QPSQLDriver::VersionUnknown) {
+ serverVersion = clientVersion;
+ if (serverVersion != QPSQLDriver::VersionUnknown)
+ qWarning("The server version of this PostgreSQL is unknown, falling back to the client version.");
}
- PQclear(result);
- //keep the old behavior unchanged
+ // Keep the old behavior unchanged
if (serverVersion == QPSQLDriver::VersionUnknown)
serverVersion = QPSQLDriver::Version6;
- if (serverVersion < QPSQLDriver::Version71) {
+ if (serverVersion < QPSQLDriver::Version7_3) {
qWarning("This version of PostgreSQL is not supported and may not work.");
}
@@ -857,7 +898,7 @@ bool QPSQLDriver::hasFeature(DriverFeature f) const
return true;
case PreparedQueries:
case PositionalPlaceholders:
- return d->pro >= QPSQLDriver::Version82;
+ return d->pro >= QPSQLDriver::Version8_2;
case BatchOperations:
case NamedPlaceholders:
case SimpleLocking:
@@ -866,7 +907,7 @@ bool QPSQLDriver::hasFeature(DriverFeature f) const
case CancelQuery:
return false;
case BLOB:
- return d->pro >= QPSQLDriver::Version71;
+ return d->pro >= QPSQLDriver::Version7_1;
case Unicode:
return d->isUtf8;
}
@@ -929,6 +970,7 @@ bool QPSQLDriver::open(const QString & db,
d->detectBackslashEscape();
d->isUtf8 = d->setEncodingUtf8();
d->setDatestyle();
+ d->setByteaOutput();
setOpen(true);
setOpenError(false);
@@ -993,12 +1035,7 @@ bool QPSQLDriver::commitTransaction()
// This hack is used to tell if the transaction has succeeded for the protocol versions of
// PostgreSQL below. For 7.x and other protocol versions we are left in the dark.
// This hack can dissapear once there is an API to query this sort of information.
- if (d->pro == QPSQLDriver::Version8 ||
- d->pro == QPSQLDriver::Version81 ||
- d->pro == QPSQLDriver::Version82 ||
- d->pro == QPSQLDriver::Version83 ||
- d->pro == QPSQLDriver::Version84 ||
- d->pro == QPSQLDriver::Version9) {
+ if (d->pro >= QPSQLDriver::Version8) {
transaction_failed = qstrcmp(PQcmdStatus(res), "ROLLBACK") == 0;
}
@@ -1085,8 +1122,7 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const
else
schema = std::move(schema).toLower();
- switch(d->pro) {
- case QPSQLDriver::Version6:
+ if (d->pro == QPSQLDriver::Version6) {
stmt = QLatin1String("select pg_att1.attname, int(pg_att1.atttypid), pg_cl.relname "
"from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind "
"where pg_cl.relname = '%1_pkey' "
@@ -1095,9 +1131,7 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const
"and pg_att1.attrelid = pg_ind.indrelid "
"and pg_att1.attnum = pg_ind.indkey[pg_att2.attnum-1] "
"order by pg_att2.attnum");
- break;
- case QPSQLDriver::Version7:
- case QPSQLDriver::Version71:
+ } else if (d->pro == QPSQLDriver::Version7 || d->pro == QPSQLDriver::Version7_1) {
stmt = QLatin1String("select pg_att1.attname, pg_att1.atttypid::int, pg_cl.relname "
"from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind "
"where pg_cl.relname = '%1_pkey' "
@@ -1106,15 +1140,7 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const
"and pg_att1.attrelid = pg_ind.indrelid "
"and pg_att1.attnum = pg_ind.indkey[pg_att2.attnum-1] "
"order by pg_att2.attnum");
- break;
- case QPSQLDriver::Version73:
- case QPSQLDriver::Version74:
- case QPSQLDriver::Version8:
- case QPSQLDriver::Version81:
- case QPSQLDriver::Version82:
- case QPSQLDriver::Version83:
- case QPSQLDriver::Version84:
- case QPSQLDriver::Version9:
+ } else if (d->pro >= QPSQLDriver::Version7_3) {
stmt = QLatin1String("SELECT pg_attribute.attname, pg_attribute.atttypid::int, "
"pg_class.relname "
"FROM pg_attribute, pg_class "
@@ -1129,10 +1155,8 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const
else
stmt = stmt.arg(QString::fromLatin1("pg_class.relnamespace = (select oid from "
"pg_namespace where pg_namespace.nspname = '%1') AND ").arg(schema));
- break;
- case QPSQLDriver::VersionUnknown:
- qFatal("PSQL version is unknown");
- break;
+ } else {
+ qFatal("QPSQLDriver::primaryIndex(tablename): unknown PSQL version, query statement not set");
}
i.exec(stmt.arg(tbl));
@@ -1166,8 +1190,7 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const
schema = std::move(schema).toLower();
QString stmt;
- switch(d->pro) {
- case QPSQLDriver::Version6:
+ if (d->pro == QPSQLDriver::Version6) {
stmt = QLatin1String("select pg_attribute.attname, int(pg_attribute.atttypid), "
"pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, "
"int(pg_attribute.attrelid), pg_attribute.attnum "
@@ -1175,8 +1198,7 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const
"where pg_class.relname = '%1' "
"and pg_attribute.attnum > 0 "
"and pg_attribute.attrelid = pg_class.oid ");
- break;
- case QPSQLDriver::Version7:
+ } else if (d->pro == QPSQLDriver::Version7) {
stmt = QLatin1String("select pg_attribute.attname, pg_attribute.atttypid::int, "
"pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, "
"pg_attribute.attrelid::int, pg_attribute.attnum "
@@ -1184,8 +1206,7 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const
"where pg_class.relname = '%1' "
"and pg_attribute.attnum > 0 "
"and pg_attribute.attrelid = pg_class.oid ");
- break;
- case QPSQLDriver::Version71:
+ } else if (d->pro == QPSQLDriver::Version7_1) {
stmt = QLatin1String("select pg_attribute.attname, pg_attribute.atttypid::int, "
"pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, "
"pg_attrdef.adsrc "
@@ -1196,15 +1217,7 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const
"and pg_attribute.attnum > 0 "
"and pg_attribute.attrelid = pg_class.oid "
"order by pg_attribute.attnum ");
- break;
- case QPSQLDriver::Version73:
- case QPSQLDriver::Version74:
- case QPSQLDriver::Version8:
- case QPSQLDriver::Version81:
- case QPSQLDriver::Version82:
- case QPSQLDriver::Version83:
- case QPSQLDriver::Version84:
- case QPSQLDriver::Version9:
+ } else if (d->pro >= QPSQLDriver::Version7_3) {
stmt = QLatin1String("select pg_attribute.attname, pg_attribute.atttypid::int, "
"pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, "
"pg_attrdef.adsrc "
@@ -1222,15 +1235,13 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const
else
stmt = stmt.arg(QString::fromLatin1("pg_class.relnamespace = (select oid from "
"pg_namespace where pg_namespace.nspname = '%1')").arg(schema));
- break;
- case QPSQLDriver::VersionUnknown:
- qFatal("PSQL version is unknown");
- break;
+ } else {
+ qFatal("QPSQLDriver::record(tablename): unknown PSQL version, query statement not set");
}
QSqlQuery query(createResult());
query.exec(stmt.arg(tbl));
- if (d->pro >= QPSQLDriver::Version71) {
+ if (d->pro >= QPSQLDriver::Version7_1) {
while (query.next()) {
int len = query.value(3).toInt();
int precision = query.value(4).toInt();
diff --git a/src/plugins/sqldrivers/psql/qsql_psql_p.h b/src/plugins/sqldrivers/psql/qsql_psql_p.h
index 8468b9af93..f5cb2e9bd0 100644
--- a/src/plugins/sqldrivers/psql/qsql_psql_p.h
+++ b/src/plugins/sqldrivers/psql/qsql_psql_p.h
@@ -76,15 +76,23 @@ public:
VersionUnknown = -1,
Version6 = 6,
Version7 = 7,
- Version71 = 8,
- Version73 = 9,
- Version74 = 10,
+ Version7_1 = 8,
+ Version7_3 = 9,
+ Version7_4 = 10,
Version8 = 11,
- Version81 = 12,
- Version82 = 13,
- Version83 = 14,
- Version84 = 15,
- Version9 = 16
+ Version8_1 = 12,
+ Version8_2 = 13,
+ Version8_3 = 14,
+ Version8_4 = 15,
+ Version9 = 16,
+ Version9_1 = 17,
+ Version9_2 = 18,
+ Version9_3 = 19,
+ Version9_4 = 20,
+ Version9_5 = 21,
+ Version9_6 = 22,
+ Version10 = 23,
+ UnknownLaterVersion = 100000
};
explicit QPSQLDriver(QObject *parent=0);
diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm
index b24ecee102..c6ae7c1b79 100644
--- a/src/plugins/styles/mac/qmacstyle_mac.mm
+++ b/src/plugins/styles/mac/qmacstyle_mac.mm
@@ -311,6 +311,9 @@ static const QColor tabBarCloseButtonCrossSelected(115, 115, 115);
static const int closeButtonSize = 14;
static const qreal closeButtonCornerRadius = 2.0;
+static const int headerSectionArrowHeight = 6;
+static const int headerSectionSeparatorInset = 2;
+
#if QT_CONFIG(tabbar)
static bool isVerticalTabs(const QTabBar::Shape shape) {
return (shape == QTabBar::RoundedEast
@@ -569,7 +572,6 @@ static inline ThemeTabDirection getTabDirection(QTabBar::Shape shape)
case QTabBar::TriangularSouth:
ttd = kThemeTabSouth;
break;
- default: // Added to remove the warning, since all values are taken care of, really!
case QTabBar::RoundedNorth:
case QTabBar::TriangularNorth:
ttd = kThemeTabNorth;
@@ -622,47 +624,6 @@ static QString qt_mac_removeMnemonics(const QString &original)
return returnText;
}
-OSStatus qt_mac_shape2QRegionHelper(int inMessage, HIShapeRef, const CGRect *inRect, void *inRefcon)
-{
- QRegion *region = static_cast<QRegion *>(inRefcon);
- if (!region)
- return paramErr;
-
- switch (inMessage) {
- case kHIShapeEnumerateRect:
- *region += QRect(inRect->origin.x, inRect->origin.y,
- inRect->size.width, inRect->size.height);
- break;
- case kHIShapeEnumerateInit:
- // Assume the region is already setup correctly
- case kHIShapeEnumerateTerminate:
- default:
- break;
- }
- return noErr;
-}
-
-/*!
- \internal
- Create's a mutable shape, it's the caller's responsibility to release.
- WARNING: this function clamps the coordinates to SHRT_MIN/MAX on 10.4 and below.
-*/
-HIMutableShapeRef qt_mac_toHIMutableShape(const QRegion &region)
-{
- HIMutableShapeRef shape = HIShapeCreateMutable();
- if (region.rectCount() < 2 ) {
- QRect qtRect = region.boundingRect();
- CGRect cgRect = CGRectMake(qtRect.x(), qtRect.y(), qtRect.width(), qtRect.height());
- HIShapeUnionWithRect(shape, &cgRect);
- } else {
- for (const QRect &qtRect : region) {
- CGRect cgRect = CGRectMake(qtRect.x(), qtRect.y(), qtRect.width(), qtRect.height());
- HIShapeUnionWithRect(shape, &cgRect);
- }
- }
- return shape;
-}
-
bool qt_macWindowIsTextured(const QWidget *window)
{
if (QWindow *w = window->windowHandle())
@@ -1518,18 +1479,6 @@ void QMacStylePrivate::initHIThemePushButton(const QStyleOptionButton *btn,
}
}
-#if QT_CONFIG(pushbutton)
-bool qt_mac_buttonIsRenderedFlat(const QPushButton *pushButton, const QStyleOptionButton *option)
-{
- QMacStyle *macStyle = qobject_cast<QMacStyle *>(pushButton->style());
- if (!macStyle)
- return false;
- HIThemeButtonDrawInfo bdi;
- macStyle->d_func()->initHIThemePushButton(option, pushButton, kThemeStateActive, &bdi);
- return bdi.kind == kThemeBevelButton;
-}
-#endif
-
/**
Creates a HIThemeButtonDrawInfo structure that specifies the correct button
kind and other details to use for drawing the given combobox. Which button
@@ -1537,6 +1486,7 @@ bool qt_mac_buttonIsRenderedFlat(const QPushButton *pushButton, const QStyleOpti
explicit user style settings, etc.
*/
void QMacStylePrivate::initComboboxBdi(const QStyleOptionComboBox *combo, HIThemeButtonDrawInfo *bdi,
+ CocoaControl *cw,
const QWidget *widget, const ThemeDrawState &tds) const
{
bdi->version = qt_mac_hitheme_version;
@@ -1550,6 +1500,8 @@ void QMacStylePrivate::initComboboxBdi(const QStyleOptionComboBox *combo, HIThem
bdi->state = tds;
QStyleHelper::WidgetSizePolicy aSize = aquaSizeConstrain(combo, widget);
+ cw->first = combo->editable ? ComboBox : Button_PopupButton;
+ cw->second = aSize;
switch (aSize) {
case QStyleHelper::SizeMini:
bdi->kind = combo->editable ? ThemeButtonKind(kThemeComboBoxMini)
@@ -1579,21 +1531,29 @@ void QMacStylePrivate::initComboboxBdi(const QStyleOptionComboBox *combo, HIThem
// them forever). So anyway, the height threshold should be smaller
// in this case, or the style gets confused when it needs to render
// or return any subcontrol size of the poor thing.
- if (h < 9)
+ if (h < 9) {
bdi->kind = kThemeComboBoxMini;
- else if (h < 22)
+ cw->second = QStyleHelper::SizeMini;
+ } else if (h < 22) {
bdi->kind = kThemeComboBoxSmall;
- else
+ cw->second = QStyleHelper::SizeSmall;
+ } else {
bdi->kind = kThemeComboBox;
+ cw->second = QStyleHelper::SizeLarge;
+ }
} else
#endif
{
- if (h < 21)
+ if (h < 21) {
bdi->kind = kThemeComboBoxMini;
- else if (h < 26)
+ cw->second = QStyleHelper::SizeMini;
+ } else if (h < 26) {
bdi->kind = kThemeComboBoxSmall;
- else
+ cw->second = QStyleHelper::SizeSmall;
+ } else {
bdi->kind = kThemeComboBox;
+ cw->second = QStyleHelper::SizeLarge;
+ }
}
} else {
// Even if we specify that we want the kThemePopupButton, Carbon
@@ -1601,12 +1561,16 @@ void QMacStylePrivate::initComboboxBdi(const QStyleOptionComboBox *combo, HIThem
// do the same size check explicit to have the size of the inner
// text field be correct. Therefore, do this even if the user specifies
// the use of LargeButtons explicit.
- if (h < 21)
+ if (h < 21) {
bdi->kind = kThemePopupButtonMini;
- else if (h < 26)
+ cw->second = QStyleHelper::SizeMini;
+ } else if (h < 26) {
bdi->kind = kThemePopupButtonSmall;
- else
+ cw->second = QStyleHelper::SizeSmall;
+ } else {
bdi->kind = kThemePopupButton;
+ cw->second = QStyleHelper::SizeLarge;
+ }
}
break;
}
@@ -1616,51 +1580,54 @@ void QMacStylePrivate::initComboboxBdi(const QStyleOptionComboBox *combo, HIThem
Carbon draws comboboxes (and other views) outside the rect given as argument. Use this function to obtain
the corresponding inner rect for drawing the same combobox so that it stays inside the given outerBounds.
*/
-CGRect QMacStylePrivate::comboboxInnerBounds(const CGRect &outerBounds, int buttonKind)
+CGRect QMacStylePrivate::comboboxInnerBounds(const CGRect &outerBounds, const CocoaControl &cocoaWidget)
{
CGRect innerBounds = outerBounds;
// Carbon draw parts of the view outside the rect.
// So make the rect a bit smaller to compensate
// (I wish HIThemeGetButtonBackgroundBounds worked)
- switch (buttonKind){
- case kThemePopupButton:
- innerBounds.origin.x += 2;
- innerBounds.origin.y += 2;
- innerBounds.size.width -= 5;
- innerBounds.size.height -= 6;
- break;
- case kThemePopupButtonSmall:
- innerBounds.origin.x += 3;
- innerBounds.origin.y += 3;
- innerBounds.size.width -= 6;
- innerBounds.size.height -= 7;
- break;
- case kThemePopupButtonMini:
- innerBounds.origin.x += 2;
- innerBounds.origin.y += 2;
- innerBounds.size.width -= 5;
- innerBounds.size.height -= 6;
- break;
- case kThemeComboBox:
- innerBounds.origin.x += 3;
- innerBounds.origin.y += 2;
- innerBounds.size.width -= 6;
- innerBounds.size.height -= 8;
- break;
- case kThemeComboBoxSmall:
- innerBounds.origin.x += 3;
- innerBounds.origin.y += 3;
- innerBounds.size.width -= 7;
- innerBounds.size.height -= 8;
- break;
- case kThemeComboBoxMini:
- innerBounds.origin.x += 3;
- innerBounds.origin.y += 3;
- innerBounds.size.width -= 4;
- innerBounds.size.height -= 8;
- break;
- default:
- break;
+ if (cocoaWidget.first == Button_PopupButton) {
+ switch (cocoaWidget.second) {
+ case QStyleHelper::SizeSmall:
+ innerBounds.origin.x += 3;
+ innerBounds.origin.y += 3;
+ innerBounds.size.width -= 6;
+ innerBounds.size.height -= 7;
+ break;
+ case QStyleHelper::SizeMini:
+ innerBounds.origin.x += 2;
+ innerBounds.origin.y += 2;
+ innerBounds.size.width -= 5;
+ innerBounds.size.height -= 6;
+ break;
+ case QStyleHelper::SizeLarge:
+ case QStyleHelper::SizeDefault:
+ innerBounds.origin.x += 2;
+ innerBounds.origin.y += 2;
+ innerBounds.size.width -= 5;
+ innerBounds.size.height -= 6;
+ }
+ } else if (cocoaWidget.first == ComboBox) {
+ switch (cocoaWidget.second) {
+ case QStyleHelper::SizeSmall:
+ innerBounds.origin.x += 3;
+ innerBounds.origin.y += 3;
+ innerBounds.size.width -= 7;
+ innerBounds.size.height -= 8;
+ break;
+ case QStyleHelper::SizeMini:
+ innerBounds.origin.x += 3;
+ innerBounds.origin.y += 3;
+ innerBounds.size.width -= 4;
+ innerBounds.size.height -= 8;
+ break;
+ case QStyleHelper::SizeLarge:
+ case QStyleHelper::SizeDefault:
+ innerBounds.origin.x += 3;
+ innerBounds.origin.y += 2;
+ innerBounds.size.width -= 6;
+ innerBounds.size.height -= 8;
+ }
}
return innerBounds;
@@ -1704,11 +1671,11 @@ QRect QMacStylePrivate::comboboxEditBounds(const QRect &outerBounds, const HIThe
create it manually by drawing a small Carbon combo onto a pixmap (use pixmap cache), chop
it up, and copy it back onto the widget. Othervise, draw the combobox supplied by Carbon directly.
*/
-void QMacStylePrivate::drawCombobox(const CGRect &outerBounds, const HIThemeButtonDrawInfo &bdi, QPainter *p)
+void QMacStylePrivate::drawCombobox(const CGRect &outerBounds, const HIThemeButtonDrawInfo &bdi, const CocoaControl &cw, QPainter *p)
{
if (!(bdi.kind == kThemeComboBox && outerBounds.size.height > 28)){
// We have an unscaled combobox, or popup-button; use Carbon directly.
- const CGRect innerBounds = QMacStylePrivate::comboboxInnerBounds(outerBounds, bdi.kind);
+ const CGRect innerBounds = QMacStylePrivate::comboboxInnerBounds(outerBounds, cw);
HIThemeDrawButton(&innerBounds, &bdi, QMacCGContext(p), kHIThemeOrientationNormal, 0);
} else {
QPixmap buffer;
@@ -1751,69 +1718,6 @@ void QMacStylePrivate::drawCombobox(const CGRect &outerBounds, const HIThemeButt
}
}
-/**
- Carbon tableheaders don't scale (sight). So create it manually by drawing a small Carbon header
- onto a pixmap (use pixmap cache), chop it up, and copy it back onto the widget.
-*/
-void QMacStylePrivate::drawTableHeader(const CGRect &outerBounds,
- bool drawTopBorder, bool drawLeftBorder, const HIThemeButtonDrawInfo &bdi, QPainter *p)
-{
- static int headerHeight = qt_mac_aqua_get_metric(ListHeaderHeight);
-
- QPixmap buffer;
- QString key = QString(QLatin1String("$qt_tableh%1-%2-%3")).arg(int(bdi.state)).arg(int(bdi.adornment)).arg(int(bdi.value));
- if (!QPixmapCache::find(key, buffer)) {
- CGRect headerNormalRect = {{0., 0.}, {16., CGFloat(headerHeight)}};
- buffer = QPixmap(headerNormalRect.size.width, headerNormalRect.size.height);
- buffer.fill(Qt::transparent);
- QPainter buffPainter(&buffer);
- HIThemeDrawButton(&headerNormalRect, &bdi, QMacCGContext(&buffPainter), kHIThemeOrientationNormal, 0);
- buffPainter.end();
- QPixmapCache::insert(key, buffer);
- }
- const int buttonw = qRound(outerBounds.size.width);
- const int buttonh = qRound(outerBounds.size.height);
- const int framew = 1;
- const int frameh_n = 4;
- const int frameh_s = 3;
- const int transh = buffer.height() - frameh_n - frameh_s;
- int center = buttonh - frameh_s - int(transh / 2.0f) + 1; // Align bottom;
-
- int skipTopBorder = 0;
- if (!drawTopBorder)
- skipTopBorder = 1;
-
- p->translate(outerBounds.origin.x, outerBounds.origin.y);
-
- p->drawPixmap(QRect(QRect(0, -skipTopBorder, buttonw - framew , frameh_n)), buffer, QRect(framew, 0, 1, frameh_n));
- p->drawPixmap(QRect(0, buttonh - frameh_s, buttonw - framew, frameh_s), buffer, QRect(framew, buffer.height() - frameh_s, 1, frameh_s));
- // Draw upper and lower center blocks
- p->drawPixmap(QRect(0, frameh_n - skipTopBorder, buttonw - framew, center - frameh_n + skipTopBorder), buffer, QRect(framew, frameh_n, 1, 1));
- p->drawPixmap(QRect(0, center, buttonw - framew, buttonh - center - frameh_s), buffer, QRect(framew, buffer.height() - frameh_s, 1, 1));
- // Draw right center block borders
- p->drawPixmap(QRect(buttonw - framew, frameh_n - skipTopBorder, framew, center - frameh_n), buffer, QRect(buffer.width() - framew, frameh_n, framew, 1));
- p->drawPixmap(QRect(buttonw - framew, center, framew, buttonh - center - 1), buffer, QRect(buffer.width() - framew, buffer.height() - frameh_s, framew, 1));
- // Draw right corners
- p->drawPixmap(QRect(buttonw - framew, -skipTopBorder, framew, frameh_n), buffer, QRect(buffer.width() - framew, 0, framew, frameh_n));
- p->drawPixmap(QRect(buttonw - framew, buttonh - frameh_s, framew, frameh_s), buffer, QRect(buffer.width() - framew, buffer.height() - frameh_s, framew, frameh_s));
- // Draw center transition block
- p->drawPixmap(QRect(0, center - qRound(transh / 2.0f), buttonw - framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(framew, frameh_n + 1, 1, transh));
- // Draw right center transition block border
- p->drawPixmap(QRect(buttonw - framew, center - qRound(transh / 2.0f), framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(buffer.width() - framew, frameh_n + 1, framew, transh));
- if (drawLeftBorder){
- // Draw left center block borders
- p->drawPixmap(QRect(0, frameh_n - skipTopBorder, framew, center - frameh_n + skipTopBorder), buffer, QRect(0, frameh_n, framew, 1));
- p->drawPixmap(QRect(0, center, framew, buttonh - center - 1), buffer, QRect(0, buffer.height() - frameh_s, framew, 1));
- // Draw left corners
- p->drawPixmap(QRect(0, -skipTopBorder, framew, frameh_n), buffer, QRect(0, 0, framew, frameh_n));
- p->drawPixmap(QRect(0, buttonh - frameh_s, framew, frameh_s), buffer, QRect(0, buffer.height() - frameh_s, framew, frameh_s));
- // Draw left center transition block border
- p->drawPixmap(QRect(0, center - qRound(transh / 2.0f), framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(0, frameh_n + 1, framew, transh));
- }
-
- p->translate(-outerBounds.origin.x, -outerBounds.origin.y);
-}
-
QMacStylePrivate::QMacStylePrivate()
: backingStoreNSView(nil)
{
@@ -1849,36 +1753,36 @@ ThemeDrawState QMacStylePrivate::getDrawState(QStyle::State flags)
return tds;
}
-static QCocoaWidget cocoaWidgetFromHIThemeButtonKind(ThemeButtonKind kind)
+ QMacStylePrivate::CocoaControl QMacStylePrivate::cocoaControlFromHIThemeButtonKind(ThemeButtonKind kind)
{
- QCocoaWidget w;
+ CocoaControl w;
switch (kind) {
case kThemePopupButton:
case kThemePopupButtonSmall:
case kThemePopupButtonMini:
- w.first = QCocoaPopupButton;
+ w.first = Button_PopupButton;
break;
case kThemeComboBox:
- w.first = QCocoaComboBox;
+ w.first = ComboBox;
break;
case kThemeArrowButton:
- w.first = QCocoaDisclosureButton;
+ w.first = Button_Disclosure;
break;
case kThemeCheckBox:
case kThemeCheckBoxSmall:
case kThemeCheckBoxMini:
- w.first = QCocoaCheckBox;
+ w.first = Button_CheckBox;
break;
case kThemeRadioButton:
case kThemeRadioButtonSmall:
case kThemeRadioButtonMini:
- w.first = QCocoaRadioButton;
+ w.first = Button_RadioButton;
break;
case kThemePushButton:
case kThemePushButtonSmall:
case kThemePushButtonMini:
- w.first = QCocoaPushButton;
+ w.first = Button_PushButton;
break;
default:
break;
@@ -1914,13 +1818,13 @@ static NSButton *makeButton(NSButtonType type, NSBezelStyle style)
return b;
}
-NSView *QMacStylePrivate::cocoaControl(QCocoaWidget widget) const
+NSView *QMacStylePrivate::cocoaControl(CocoaControl widget) const
{
NSView *bv = cocoaControls.value(widget, nil);
if (!bv) {
switch (widget.first) {
- case QCocoaBox: {
+ case Box: {
NSBox *bc = [[NSBox alloc] init];
bc.title = @"";
bc.titlePosition = NSNoTitle;
@@ -1929,48 +1833,48 @@ NSView *QMacStylePrivate::cocoaControl(QCocoaWidget widget) const
bv = bc;
break;
}
- case QCocoaCheckBox:
+ case Button_CheckBox:
bv = makeButton(NSSwitchButton, NSRegularSquareBezelStyle);
break;
- case QCocoaDisclosureButton:
+ case Button_Disclosure:
bv = makeButton(NSOnOffButton, NSDisclosureBezelStyle);
break;
- case QCocoaPopupButton:
- case QCocoaPullDownButton: {
+ case Button_PopupButton:
+ case Button_PullDown: {
NSPopUpButton *bc = [[NSPopUpButton alloc] init];
bc.title = @"";
- if (widget.first == QCocoaPullDownButton)
+ if (widget.first == Button_PullDown)
bc.pullsDown = YES;
bv = bc;
break;
}
- case QCocoaPushButton:
+ case Button_PushButton:
bv = makeButton(NSMomentaryLightButton, NSRoundedBezelStyle);
break;
- case QCocoaRadioButton:
+ case Button_RadioButton:
bv = makeButton(NSRadioButton, NSRegularSquareBezelStyle);
break;
- case QCocoaComboBox:
+ case ComboBox:
bv = [[NSComboBox alloc] init];
break;
- case QCocoaProgressIndicator:
+ case ProgressIndicator_Determinate:
bv = [[NSProgressIndicator alloc] init];
break;
- case QCocoaIndeterminateProgressIndicator:
+ case ProgressIndicator_Indeterminate:
bv = [[QIndeterminateProgressIndicator alloc] init];
break;
- case QCocoaHorizontalScroller:
+ case Scroller_Horizontal:
bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
break;
- case QCocoaVerticalScroller:
+ case Scroller_Vertical:
// Cocoa sets the orientation from the view's frame
// at construction time, and it cannot be changed later.
bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)];
break;
- case QCocoaHorizontalSlider:
+ case Slider_Horizontal:
bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
break;
- case QCocoaVerticalSlider:
+ case Slider_Vertical:
// Cocoa sets the orientation from the view's frame
// at construction time, and it cannot be changed later.
bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)];
@@ -1991,10 +1895,10 @@ NSView *QMacStylePrivate::cocoaControl(QCocoaWidget widget) const
default:
break;
}
- } else if (widget.first == QCocoaProgressIndicator ||
- widget.first == QCocoaIndeterminateProgressIndicator) {
+ } else if (widget.first == ProgressIndicator_Determinate ||
+ widget.first == ProgressIndicator_Indeterminate) {
auto *pi = static_cast<NSProgressIndicator *>(bv);
- pi.indeterminate = (widget.first == QCocoaIndeterminateProgressIndicator);
+ pi.indeterminate = (widget.first == ProgressIndicator_Indeterminate);
switch (widget.second) {
case QStyleHelper::SizeSmall:
pi.controlSize = NSSmallControlSize;
@@ -2013,15 +1917,15 @@ NSView *QMacStylePrivate::cocoaControl(QCocoaWidget widget) const
return bv;
}
-NSCell *QMacStylePrivate::cocoaCell(QCocoaWidget widget) const
+NSCell *QMacStylePrivate::cocoaCell(CocoaControl widget) const
{
NSCell *cell = cocoaCells[widget];
if (!cell) {
switch (widget.first) {
- case QCocoaStepper:
+ case Stepper:
cell = [[NSStepperCell alloc] init];
break;
- case QCocoaDisclosureButton: {
+ case Button_Disclosure: {
NSButtonCell *bc = [[NSButtonCell alloc] init];
bc.buttonType = NSOnOffButton;
bc.bezelStyle = NSDisclosureBezelStyle;
@@ -2049,31 +1953,31 @@ NSCell *QMacStylePrivate::cocoaCell(QCocoaWidget widget) const
return cell;
}
-void QMacStylePrivate::drawNSViewInRect(QCocoaWidget widget, NSView *view, const QRect &qtRect, QPainter *p, bool isQWidget, QCocoaDrawRectBlock drawRectBlock) const
+void QMacStylePrivate::drawNSViewInRect(CocoaControl widget, NSView *view, const QRect &qtRect, QPainter *p, bool isQWidget, DrawRectBlock drawRectBlock) const
{
QPoint offset;
- if (widget == QCocoaWidget(QCocoaRadioButton, QStyleHelper::SizeLarge))
+ if (widget == CocoaControl(Button_RadioButton, QStyleHelper::SizeLarge))
offset.setY(2);
- else if (widget == QCocoaWidget(QCocoaRadioButton, QStyleHelper::SizeSmall))
+ else if (widget == CocoaControl(Button_RadioButton, QStyleHelper::SizeSmall))
offset = QPoint(-1, 2);
- else if (widget == QCocoaWidget(QCocoaRadioButton, QStyleHelper::SizeMini))
+ else if (widget == CocoaControl(Button_RadioButton, QStyleHelper::SizeMini))
offset.setY(2);
- else if (widget == QCocoaWidget(QCocoaPopupButton, QStyleHelper::SizeSmall)
- || widget == QCocoaWidget(QCocoaCheckBox, QStyleHelper::SizeLarge))
+ else if (widget == CocoaControl(Button_PopupButton, QStyleHelper::SizeSmall)
+ || widget == CocoaControl(Button_CheckBox, QStyleHelper::SizeLarge))
offset.setY(1);
- else if (widget == QCocoaWidget(QCocoaCheckBox, QStyleHelper::SizeSmall))
+ else if (widget == CocoaControl(Button_CheckBox, QStyleHelper::SizeSmall))
offset.setX(-1);
- else if (widget == QCocoaWidget(QCocoaCheckBox, QStyleHelper::SizeMini))
+ else if (widget == CocoaControl(Button_CheckBox, QStyleHelper::SizeMini))
offset = QPoint(7, 5);
- else if (widget == QCocoaWidget(QCocoaPopupButton, QStyleHelper::SizeMini))
+ else if (widget == CocoaControl(Button_PopupButton, QStyleHelper::SizeMini))
offset = QPoint(2, -1);
- else if (widget == QCocoaWidget(QCocoaPullDownButton, QStyleHelper::SizeLarge))
+ else if (widget == CocoaControl(Button_PullDown, QStyleHelper::SizeLarge))
offset = isQWidget ? QPoint(3, -1) : QPoint(-1, -3);
- else if (widget == QCocoaWidget(QCocoaPullDownButton, QStyleHelper::SizeSmall))
+ else if (widget == CocoaControl(Button_PullDown, QStyleHelper::SizeSmall))
offset = QPoint(2, 1);
- else if (widget == QCocoaWidget(QCocoaPullDownButton, QStyleHelper::SizeMini))
+ else if (widget == CocoaControl(Button_PullDown, QStyleHelper::SizeMini))
offset = QPoint(5, 0);
- else if (widget == QCocoaWidget(QCocoaComboBox, QStyleHelper::SizeLarge))
+ else if (widget == CocoaControl(ComboBox, QStyleHelper::SizeLarge))
offset = QPoint(3, 0);
QMacCGContext ctx(p);
@@ -2094,12 +1998,12 @@ void QMacStylePrivate::drawNSViewInRect(QCocoaWidget widget, NSView *view, const
restoreNSGraphicsContext(ctx);
}
-void QMacStylePrivate::resolveCurrentNSView(QWindow *window)
+void QMacStylePrivate::resolveCurrentNSView(QWindow *window) const
{
backingStoreNSView = window ? (NSView *)window->winId() : nil;
}
-void QMacStylePrivate::drawColorlessButton(const CGRect &macRect, HIThemeButtonDrawInfo *bdi,
+void QMacStylePrivate::drawColorlessButton(const CGRect &macRect, HIThemeButtonDrawInfo *bdi, const CocoaControl &cw,
QPainter *p, const QStyleOption *opt) const
{
int xoff = 0,
@@ -2147,7 +2051,7 @@ void QMacStylePrivate::drawColorlessButton(const CGRect &macRect, HIThemeButtonD
// Carbon combos don't scale. Therefore we draw it
// ourselves, if a scaled version is needed.
QPainter tmpPainter(&activePixmap);
- QMacStylePrivate::drawCombobox(macRect, *bdi, &tmpPainter);
+ QMacStylePrivate::drawCombobox(macRect, *bdi, cw, &tmpPainter);
} else {
QMacCGContext cg(&activePixmap);
CGRect newRect = CGRectMake(xoff, yoff, macRect.size.width, macRect.size.height);
@@ -2162,7 +2066,7 @@ void QMacStylePrivate::drawColorlessButton(const CGRect &macRect, HIThemeButtonD
if (!combo && !button && bdi->value == kThemeButtonOff) {
pm = activePixmap;
} else if ((combo && !editableCombo) || button) {
- QCocoaWidget cw = cocoaWidgetFromHIThemeButtonKind(bdi->kind);
+ CocoaControl cw = cocoaControlFromHIThemeButtonKind(bdi->kind);
NSButton *bc = (NSButton *)cocoaControl(cw);
[bc highlight:pressed];
bc.enabled = bdi->state != kThemeStateUnavailable && bdi->state != kThemeStateUnavailableInactive;
@@ -3131,7 +3035,7 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
QMacCGContext cg(p);
QWindow *window = w && w->window() ? w->window()->windowHandle() :
QStyleHelper::styleObjectWindow(opt->styleObject);
- const_cast<QMacStylePrivate *>(d)->resolveCurrentNSView(window);
+ d->resolveCurrentNSView(window);
switch (pe) {
case PE_IndicatorArrowUp:
case PE_IndicatorArrowDown:
@@ -3139,7 +3043,17 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
case PE_IndicatorArrowLeft: {
p->save();
p->setRenderHint(QPainter::Antialiasing);
- int xOffset = opt->direction == Qt::LeftToRight ? 2 : -1;
+ const int xOffset = 1; // FIXME: opt->direction == Qt::LeftToRight ? 2 : -1;
+ qreal halfSize = 0.5 * qMin(opt->rect.width(), opt->rect.height());
+ const qreal penWidth = qMax(halfSize / 3.0, 1.25);
+#if QT_CONFIG(toolbutton)
+ if (const QToolButton *tb = qobject_cast<const QToolButton *>(w)) {
+ // When stroking the arrow, make sure it fits in the tool button
+ if (tb->arrowType() != Qt::NoArrow)
+ halfSize -= penWidth;
+ }
+#endif
+
QMatrix matrix;
matrix.translate(opt->rect.center().x() + xOffset, opt->rect.center().y() + 2);
QPainterPath path;
@@ -3157,13 +3071,15 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
matrix.rotate(-90);
break;
}
- path.moveTo(0, 5);
- path.lineTo(-4, -3);
- path.lineTo(4, -3);
p->setMatrix(matrix);
- p->setPen(Qt::NoPen);
- p->setBrush(QColor(0, 0, 0, 135));
- p->drawPath(path);
+
+ path.moveTo(-halfSize, -halfSize * 0.5);
+ path.lineTo(0.0, halfSize * 0.5);
+ path.lineTo(halfSize, -halfSize * 0.5);
+
+ const QPen arrowPen(opt->palette.text(), penWidth,
+ Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
+ p->strokePath(path, arrowPen);
p->restore();
break; }
#if QT_CONFIG(tabbar)
@@ -3211,7 +3127,7 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
if (groupBox->features & QStyleOptionFrame::Flat) {
QCommonStyle::drawPrimitive(pe, groupBox, p, w);
} else {
- const auto cw = QCocoaWidget(QCocoaBox, QStyleHelper::SizeDefault);
+ const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Box, QStyleHelper::SizeDefault);
auto *box = static_cast<NSBox *>(d->cocoaControl(cw));
d->drawNSViewInRect(cw, box, groupBox->rect, p, w != nullptr, ^(CGContextRef ctx, const CGRect &rect) {
CGContextTranslateCTM(ctx, 0, rect.origin.y + rect.size.height);
@@ -3386,10 +3302,11 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
else
bdi.value = kThemeButtonOff;
CGRect macRect = opt->rect.toCGRect();
+ const QMacStylePrivate::CocoaControl cw = QMacStylePrivate::cocoaControlFromHIThemeButtonKind(bdi.kind);
if (!drawColorless)
HIThemeDrawButton(&macRect, &bdi, cg, kHIThemeOrientationNormal, 0);
else
- d->drawColorlessButton(macRect, &bdi, p, opt);
+ d->drawColorlessButton(macRect, &bdi, cw, p, opt);
break; }
case PE_FrameFocusRect:
// Use the our own focus widget stuff.
@@ -3397,7 +3314,8 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
case PE_IndicatorBranch: {
if (!(opt->state & State_Children))
break;
- NSButtonCell *triangleCell = static_cast<NSButtonCell *>(d->cocoaCell(QCocoaWidget(QCocoaDisclosureButton, QStyleHelper::SizeLarge)));
+ const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Button_Disclosure, QStyleHelper::SizeLarge);
+ NSButtonCell *triangleCell = static_cast<NSButtonCell *>(d->cocoaCell(cw));
[triangleCell setState:(opt->state & State_Open) ? NSOnState : NSOffState];
bool viewHasFocus = (w && w->hasFocus()) || (opt->state & State_HasFocus);
[triangleCell setBackgroundStyle:((opt->state & State_Selected) && viewHasFocus) ? NSBackgroundStyleDark : NSBackgroundStyleLight];
@@ -3627,70 +3545,15 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
QMacCGContext cg(p);
QWindow *window = w && w->window() ? w->window()->windowHandle() :
QStyleHelper::styleObjectWindow(opt->styleObject);
- const_cast<QMacStylePrivate *>(d)->resolveCurrentNSView(window);
+ d->resolveCurrentNSView(window);
switch (ce) {
case CE_HeaderSection:
if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
- HIThemeButtonDrawInfo bdi;
- bdi.version = qt_mac_hitheme_version;
State flags = header->state;
QRect ir = header->rect;
- bdi.kind = kThemeListHeaderButton;
- bdi.adornment = kThemeAdornmentNone;
- bdi.state = kThemeStateActive;
- if (flags & State_On)
- bdi.value = kThemeButtonOn;
- else
- bdi.value = kThemeButtonOff;
-
- if (header->orientation == Qt::Horizontal){
- switch (header->position) {
- case QStyleOptionHeader::Beginning:
- ir.adjust(-1, -1, 0, 0);
- break;
- case QStyleOptionHeader::Middle:
- ir.adjust(-1, -1, 0, 0);
- break;
- case QStyleOptionHeader::OnlyOneSection:
- case QStyleOptionHeader::End:
- ir.adjust(-1, -1, 1, 0);
- break;
- default:
- break;
- }
-
- if (header->position != QStyleOptionHeader::Beginning
- && header->position != QStyleOptionHeader::OnlyOneSection) {
- bdi.adornment = header->direction == Qt::LeftToRight
- ? kThemeAdornmentHeaderButtonLeftNeighborSelected
- : kThemeAdornmentHeaderButtonRightNeighborSelected;
- }
- }
-
- if (flags & State_Active) {
- if (!(flags & State_Enabled))
- bdi.state = kThemeStateUnavailable;
- else if (flags & State_Sunken)
- bdi.state = kThemeStatePressed;
- } else {
- if (flags & State_Enabled)
- bdi.state = kThemeStateInactive;
- else
- bdi.state = kThemeStateUnavailableInactive;
- }
-
- if (header->sortIndicator != QStyleOptionHeader::None) {
- bdi.value = kThemeButtonOn;
- if (header->sortIndicator == QStyleOptionHeader::SortDown)
- bdi.adornment = kThemeAdornmentHeaderButtonSortUp;
- }
- if (flags & State_HasFocus)
- bdi.adornment = kThemeAdornmentFocus;
-
- ir = visualRect(header->direction, header->rect, ir);
- CGRect bounds = ir.toCGRect();
+#if 0 // FIXME: What's this solving exactly?
bool noVerticalHeader = true;
#if QT_CONFIG(tableview)
if (w)
@@ -3698,12 +3561,22 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
noVerticalHeader = !table->verticalHeader()->isVisible();
#endif
- bool drawTopBorder = header->orientation == Qt::Horizontal;
- bool drawLeftBorder = header->orientation == Qt::Vertical
- || header->position == QStyleOptionHeader::OnlyOneSection
- || (header->position == QStyleOptionHeader::Beginning && noVerticalHeader);
- d->drawTableHeader(bounds, drawTopBorder, drawLeftBorder, bdi, p);
+ const bool drawLeftBorder = header->orientation == Qt::Vertical
+ || header->position == QStyleOptionHeader::OnlyOneSection
+ || (header->position == QStyleOptionHeader::Beginning && noVerticalHeader);
+#endif
+
+ const bool pressed = (flags & State_Sunken) && !(flags & State_On);
+ p->fillRect(ir, pressed ? header->palette.dark() : header->palette.button());
+ p->setPen(QPen(header->palette.dark(), 1.0));
+ if (header->orientation == Qt::Horizontal)
+ p->drawLine(QLineF(ir.right() + 0.5, ir.top() + headerSectionSeparatorInset,
+ ir.right() + 0.5, ir.bottom() - headerSectionSeparatorInset));
+ else
+ p->drawLine(QLineF(ir.left() + headerSectionSeparatorInset, ir.bottom(),
+ ir.right() - headerSectionSeparatorInset, ir.bottom()));
}
+
break;
case CE_HeaderLabel:
if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
@@ -3820,12 +3693,11 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
} else {
QCommonStyle::drawControl(ce, &myTb, p, w);
}
- } else {
+ } else
+#endif // QT_NO_ACCESSIBILITY
+ {
QCommonStyle::drawControl(ce, &myTb, p, w);
}
-#else
- Q_UNUSED(tb)
-#endif
}
break;
case CE_ToolBoxTabShape:
@@ -3883,9 +3755,10 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
newRect.size.width -= QMacStylePrivate::PushButtonRightOffset - 4;
}
+ QMacStylePrivate::CocoaControl cw = QMacStylePrivate::cocoaControlFromHIThemeButtonKind(bdi.kind);
+ if (hasMenu)
+ cw.first = QMacStylePrivate::Button_PullDown;
if (hasMenu && bdi.kind != kThemeBevelButton) {
- QCocoaWidget cw = cocoaWidgetFromHIThemeButtonKind(bdi.kind);
- cw.first = QCocoaPullDownButton;
NSPopUpButton *pdb = (NSPopUpButton *)d->cocoaControl(cw);
[pdb highlight:(bdi.state == kThemeStatePressed)];
pdb.enabled = bdi.state != kThemeStateUnavailable && bdi.state != kThemeStateUnavailableInactive;
@@ -3893,7 +3766,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
rect.adjust(0, 0, cw.second == QStyleHelper::SizeSmall ? -4 : cw.second == QStyleHelper::SizeMini ? -9 : -6, 0);
d->drawNSViewInRect(cw, pdb, rect, p, w != 0);
} else if (hasMenu && bdi.state == kThemeStatePressed)
- d->drawColorlessButton(newRect, &bdi, p, opt);
+ d->drawColorlessButton(newRect, &bdi, cw, p, opt);
else
HIThemeDrawButton(&newRect, &bdi, cg, kHIThemeOrientationNormal, 0);
@@ -4451,7 +4324,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
const QProgressStyleAnimation *animation = qobject_cast<QProgressStyleAnimation*>(d->animation(opt->styleObject));
QIndeterminateProgressIndicator *ipi = nil;
if (isIndeterminate || animation)
- ipi = static_cast<QIndeterminateProgressIndicator *>(d->cocoaControl({ QCocoaIndeterminateProgressIndicator, aquaSize }));
+ ipi = static_cast<QIndeterminateProgressIndicator *>(d->cocoaControl({ QMacStylePrivate::ProgressIndicator_Indeterminate, aquaSize }));
if (isIndeterminate) {
// QIndeterminateProgressIndicator derives from NSProgressIndicator. We use a single
// instance that we start animating as soon as one of the progress bars is indeterminate.
@@ -4478,7 +4351,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
[ipi stopAnimation];
}
- const QCocoaWidget cw = { QCocoaProgressIndicator, aquaSize };
+ const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::ProgressIndicator_Determinate, aquaSize);
auto *pi = static_cast<NSProgressIndicator *>(d->cocoaControl(cw));
d->drawNSViewInRect(cw, pi, rect, p, w != nullptr, ^(CGContextRef ctx, const CGRect &rect) {
d->setupVerticalInvertedXform(ctx, reverse, vertical, rect);
@@ -4691,14 +4564,31 @@ QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt,
// Subtract width needed for arrow, if there is one
if (header->sortIndicator != QStyleOptionHeader::None) {
if (opt->state & State_Horizontal)
- rect.setWidth(rect.width() - (opt->rect.height() / 2) - (margin * 2));
+ rect.setWidth(rect.width() - (headerSectionArrowHeight) - (margin * 2));
else
- rect.setHeight(rect.height() - (opt->rect.width() / 2) - (margin * 2));
+ rect.setHeight(rect.height() - (headerSectionArrowHeight) - (margin * 2));
}
}
rect = visualRect(opt->direction, opt->rect, rect);
break;
}
+ case SE_HeaderArrow: {
+ int h = opt->rect.height();
+ int w = opt->rect.width();
+ int x = opt->rect.x();
+ int y = opt->rect.y();
+ int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt, widget);
+
+ if (opt->state & State_Horizontal) {
+ rect.setRect(x + w - margin * 2 - headerSectionArrowHeight, y + 5,
+ headerSectionArrowHeight, h - margin * 2 - 5);
+ } else {
+ rect.setRect(x + 5, y + h - margin * 2 - headerSectionArrowHeight,
+ w - margin * 2 - 5, headerSectionArrowHeight);
+ }
+ rect = visualRect(opt->direction, opt->rect, rect);
+ break;
+ }
case SE_ProgressBarGroove:
// Wrong in the secondary dimension, but accurate enough in the main dimension.
rect = opt->rect;
@@ -5159,7 +5049,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
QMacCGContext cg(p);
QWindow *window = widget && widget->window() ? widget->window()->windowHandle() :
QStyleHelper::styleObjectWindow(opt->styleObject);
- const_cast<QMacStylePrivate *>(d)->resolveCurrentNSView(window);
+ d->resolveCurrentNSView(window);
switch (cc) {
case CC_ScrollBar:
if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
@@ -5265,7 +5155,8 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
d->setupNSGraphicsContext(cg, NO /* flipped */);
- const QCocoaWidget cw(isHorizontal ? QCocoaHorizontalScroller : QCocoaVerticalScroller, cocoaSize);
+ const auto controlType = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
+ const auto cw = QMacStylePrivate::CocoaControl(controlType, cocoaSize);
NSScroller *scroller = static_cast<NSScroller *>(d->cocoaControl(cw));
if (isTransient) {
@@ -5347,8 +5238,9 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
case CC_Slider:
if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
const bool isHorizontal = sl->orientation == Qt::Horizontal;
+ const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
- const auto cw = QCocoaWidget(isHorizontal ? QCocoaHorizontalSlider : QCocoaVerticalSlider, cs);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
auto *slider = static_cast<NSSlider *>(d->cocoaControl(cw));
if (!setupSlider(slider, sl))
break;
@@ -5483,7 +5375,8 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
d->setupNSGraphicsContext(cg, NO);
const auto aquaSize = d->effectiveAquaSizeConstrain(opt, widget);
- NSStepperCell *cell = static_cast<NSStepperCell *>(d->cocoaCell(QCocoaWidget(QCocoaStepper, aquaSize)));
+ const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Stepper, aquaSize);
+ NSStepperCell *cell = static_cast<NSStepperCell *>(d->cocoaCell(cw));
cell.enabled = (sb->state & State_Enabled);
const CGRect newRect = [cell drawingRectForBounds:updown.toCGRect()];
@@ -5511,19 +5404,20 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
case CC_ComboBox:
if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)){
HIThemeButtonDrawInfo bdi;
- d->initComboboxBdi(combo, &bdi, widget, tds);
+ QMacStylePrivate::CocoaControl cw;
+ d->initComboboxBdi(combo, &bdi, &cw, widget, tds);
CGRect rect = combo->rect.toCGRect();
if (combo->editable)
rect.origin.y += tds == kThemeStateInactive ? 1 : 2;
if (tds != kThemeStateInactive)
- QMacStylePrivate::drawCombobox(rect, bdi, p);
+ QMacStylePrivate::drawCombobox(rect, bdi, cw, p);
else if (!widget && combo->editable) {
- QCocoaWidget cw = cocoaWidgetFromHIThemeButtonKind(bdi.kind);
+ const auto cw = QMacStylePrivate::cocoaControlFromHIThemeButtonKind(bdi.kind);
NSView *cb = d->cocoaControl(cw);
QRect r = combo->rect.adjusted(3, 0, 0, 0);
d->drawNSViewInRect(cw, cb, r, p, widget != 0);
} else
- d->drawColorlessButton(rect, &bdi, p, opt);
+ d->drawColorlessButton(rect, &bdi, cw, p, opt);
}
break;
case CC_TitleBar:
@@ -5703,7 +5597,9 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
p->fillPath(path, brush);
}
proxy()->drawControl(CE_ToolButtonLabel, opt, p, widget);
- } else {
+ } else
+#endif // QT_NO_ACCESSIBILITY
+ {
ThemeButtonKind bkind = kThemeBevelButton;
switch (d->aquaSizeConstrain(opt, widget)) {
case QStyleHelper::SizeDefault:
@@ -5786,7 +5682,6 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
label.rect = buttonRect.adjusted(fw, fw, -fw, -fw);
proxy()->drawControl(CE_ToolButtonLabel, &label, p, widget);
}
-#endif
}
break;
#if QT_CONFIG(dial)
@@ -5822,8 +5717,9 @@ QStyle::SubControl QMacStyle::hitTestComplexControl(ComplexControl cc,
const bool hasTicks = sl->tickPosition != QSlider::NoTicks;
const bool isHorizontal = sl->orientation == Qt::Horizontal;
+ const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
- const auto cw = QCocoaWidget(isHorizontal ? QCocoaHorizontalSlider : QCocoaVerticalSlider, cs);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
auto *slider = static_cast<NSSlider *>(d->cocoaControl(cw));
if (!setupSlider(slider, sl))
break;
@@ -5848,9 +5744,10 @@ QStyle::SubControl QMacStyle::hitTestComplexControl(ComplexControl cc,
break;
}
- const auto controlSize = d->effectiveAquaSizeConstrain(opt, widget);
const bool isHorizontal = sb->orientation == Qt::Horizontal;
- const auto cw = QCocoaWidget(isHorizontal ? QCocoaHorizontalScroller : QCocoaVerticalScroller, controlSize);
+ const auto ct = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
+ const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
auto *scroller = static_cast<NSScroller *>(d->cocoaControl(cw));
if (!setupScroller(scroller, sb)) {
sc = SC_None;
@@ -5956,8 +5853,9 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op
// And nothing else since 10.7
if (part != NSScrollerNoPart) {
- const auto controlSize = d->effectiveAquaSizeConstrain(opt, widget);
- const auto cw = QCocoaWidget(isHorizontal ? QCocoaHorizontalScroller : QCocoaVerticalScroller, controlSize);
+ const auto ct = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
+ const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
auto *scroller = static_cast<NSScroller *>(d->cocoaControl(cw));
if (setupScroller(scroller, sb))
ret = QRectF::fromCGRect([scroller rectForPart:part]).toRect();
@@ -5968,8 +5866,9 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op
if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
const bool hasTicks = sl->tickPosition != QSlider::NoTicks;
const bool isHorizontal = sl->orientation == Qt::Horizontal;
+ const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
- const auto cw = QCocoaWidget(isHorizontal ? QCocoaHorizontalSlider : QCocoaVerticalSlider, cs);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
auto *slider = static_cast<NSSlider *>(d->cocoaControl(cw));
if (!setupSlider(slider, sl))
break;
@@ -6063,7 +5962,8 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op
case CC_ComboBox:
if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
HIThemeButtonDrawInfo bdi;
- d->initComboboxBdi(combo, &bdi, widget, d->getDrawState(opt->state));
+ QMacStylePrivate::CocoaControl cw;
+ d->initComboboxBdi(combo, &bdi, &cw, widget, d->getDrawState(opt->state));
switch (sc) {
case SC_ComboBoxEditField:{
@@ -6078,7 +5978,7 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op
break; }
case SC_ComboBoxListBoxPopup:{
if (combo->editable) {
- const CGRect inner = QMacStylePrivate::comboboxInnerBounds(combo->rect.toCGRect(), bdi.kind);
+ const CGRect inner = QMacStylePrivate::comboboxInnerBounds(combo->rect.toCGRect(), cw);
QRect editRect = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi);
const int comboTop = combo->rect.top();
ret = QRect(qRound(inner.origin.x),
@@ -6230,7 +6130,8 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op
Q_UNREACHABLE();
}
- NSStepperCell *cell = static_cast<NSStepperCell *>(d->cocoaCell(QCocoaWidget(QCocoaStepper, aquaSize)));
+ const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Stepper, aquaSize);
+ NSStepperCell *cell = static_cast<NSStepperCell *>(d->cocoaCell(cw));
const CGRect outRect = [cell drawingRectForBounds:ret.toCGRect()];
ret = QRectF::fromCGRect(outRect).toRect();
@@ -6554,20 +6455,10 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
// We compensate for this by adding some extra space here to make room for the frame when drawing:
if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)){
const auto widgetSize = d->aquaSizeConstrain(opt, widget);
- int bkind = 0;
- switch (widgetSize) {
- default:
- case QStyleHelper::SizeLarge:
- bkind = combo->editable ? kThemeComboBox : kThemePopupButton;
- break;
- case QStyleHelper::SizeSmall:
- bkind = combo->editable ? int(kThemeComboBoxSmall) : int(kThemePopupButtonSmall);
- break;
- case QStyleHelper::SizeMini:
- bkind = combo->editable ? kThemeComboBoxMini : kThemePopupButtonMini;
- break;
- }
- const CGRect diffRect = QMacStylePrivate::comboboxInnerBounds(CGRectZero, bkind);
+ QMacStylePrivate::CocoaControl cw;
+ cw.first = combo->editable ? QMacStylePrivate::ComboBox : QMacStylePrivate::Button_PopupButton;
+ cw.second = widgetSize;
+ const CGRect diffRect = QMacStylePrivate::comboboxInnerBounds(CGRectZero, cw);
sz.rwidth() -= qRound(diffRect.size.width);
sz.rheight() -= qRound(diffRect.size.height);
} else if (ct == CT_PushButton || ct == CT_ToolButton){
@@ -6808,16 +6699,4 @@ int QMacStyle::layoutSpacing(QSizePolicy::ControlType control1,
return_SIZE(10, 8, 6); // guess
}
-/*
-FontHash::FontHash()
-{
- QHash<QByteArray, QFont>::operator=(QGuiApplicationPrivate::platformIntegration()->fontDatabase()->defaultFonts());
-}
-
-Q_GLOBAL_STATIC(FontHash, app_fonts)
-FontHash *qt_app_fonts_hash()
-{
- return app_fonts();
-}
-*/
QT_END_NAMESPACE
diff --git a/src/plugins/styles/mac/qmacstyle_mac_p.h b/src/plugins/styles/mac/qmacstyle_mac_p.h
index 6011baeea2..d6874001d3 100644
--- a/src/plugins/styles/mac/qmacstyle_mac_p.h
+++ b/src/plugins/styles/mac/qmacstyle_mac_p.h
@@ -117,10 +117,6 @@ public:
private:
Q_DISABLE_COPY(QMacStyle)
Q_DECLARE_PRIVATE(QMacStyle)
-
-#if QT_CONFIG(pushbutton)
- friend bool qt_mac_buttonIsRenderedFlat(const QPushButton *pushButton, const QStyleOptionButton *option);
-#endif
};
QT_END_NAMESPACE
diff --git a/src/plugins/styles/mac/qmacstyle_mac_p_p.h b/src/plugins/styles/mac/qmacstyle_mac_p_p.h
index 528edfcda1..078509d551 100644
--- a/src/plugins/styles/mac/qmacstyle_mac_p_p.h
+++ b/src/plugins/styles/mac/qmacstyle_mac_p_p.h
@@ -167,28 +167,6 @@ QT_BEGIN_NAMESPACE
#define CT1(c) CT2(c, c)
#define CT2(c1, c2) ((uint(c1) << 16) | uint(c2))
-enum QCocoaWidgetKind {
- QCocoaBox, // QGroupBox
- QCocoaCheckBox,
- QCocoaComboBox, // Editable QComboBox
- QCocoaDisclosureButton, // Disclosure triangle, like in QTreeView
- QCocoaPopupButton, // Non-editable QComboBox
- QCocoaProgressIndicator,
- QCocoaIndeterminateProgressIndicator,
- QCocoaPullDownButton, // QPushButton with menu
- QCocoaPushButton,
- QCocoaRadioButton,
- QCocoaHorizontalScroller,
- QCocoaVerticalScroller,
- QCocoaHorizontalSlider,
- QCocoaVerticalSlider,
- QCocoaStepper // QSpinBox buttons
-};
-
-typedef QPair<QCocoaWidgetKind, QStyleHelper::WidgetSizePolicy> QCocoaWidget;
-
-typedef void (^QCocoaDrawRectBlock)(CGContextRef, const CGRect &);
-
#define SIZE(large, small, mini) \
(controlSize == QStyleHelper::SizeLarge ? (large) : controlSize == QStyleHelper::SizeSmall ? (small) : (mini))
@@ -199,14 +177,32 @@ typedef void (^QCocoaDrawRectBlock)(CGContextRef, const CGRect &);
return sizes[controlSize]; \
} while (false)
-#if QT_CONFIG(pushbutton)
-bool qt_mac_buttonIsRenderedFlat(const QPushButton *pushButton, const QStyleOptionButton *option);
-#endif
-
class QMacStylePrivate : public QCommonStylePrivate
{
Q_DECLARE_PUBLIC(QMacStyle)
public:
+ enum CocoaControlType {
+ Box, // QGroupBox
+ Button_CheckBox,
+ Button_Disclosure, // Disclosure triangle, like in QTreeView
+ Button_PopupButton, // Non-editable QComboBox
+ Button_PullDown, // QPushButton with menu
+ Button_PushButton,
+ Button_RadioButton,
+ ComboBox, // Editable QComboBox
+ ProgressIndicator_Determinate,
+ ProgressIndicator_Indeterminate,
+ Scroller_Horizontal,
+ Scroller_Vertical,
+ Slider_Horizontal,
+ Slider_Vertical,
+ Stepper // QSpinBox buttons
+ };
+
+ typedef QPair<CocoaControlType, QStyleHelper::WidgetSizePolicy> CocoaControl;
+
+ typedef void (^DrawRectBlock)(CGContextRef, const CGRect &);
+
QMacStylePrivate();
~QMacStylePrivate();
@@ -235,6 +231,7 @@ public:
// Utility functions
void drawColorlessButton(const CGRect &macRect, HIThemeButtonDrawInfo *bdi,
+ const CocoaControl &cw,
QPainter *p, const QStyleOption *opt) const;
QSize pushButtonSizeFromContents(const QStyleOptionButton *btn) const;
@@ -243,15 +240,14 @@ public:
const HIThemeButtonDrawInfo *bdi) const;
void initComboboxBdi(const QStyleOptionComboBox *combo, HIThemeButtonDrawInfo *bdi,
+ CocoaControl *cw,
const QWidget *widget, const ThemeDrawState &tds) const;
- static CGRect comboboxInnerBounds(const CGRect &outerBounds, int buttonKind);
+ static CGRect comboboxInnerBounds(const CGRect &outerBounds, const CocoaControl &cocoaWidget);
static QRect comboboxEditBounds(const QRect &outerBounds, const HIThemeButtonDrawInfo &bdi);
- static void drawCombobox(const CGRect &outerBounds, const HIThemeButtonDrawInfo &bdi, QPainter *p);
- static void drawTableHeader(const CGRect &outerBounds, bool drawTopBorder, bool drawLeftBorder,
- const HIThemeButtonDrawInfo &bdi, QPainter *p);
+ static void drawCombobox(const CGRect &outerBounds, const HIThemeButtonDrawInfo &bdi, const CocoaControl &cw, QPainter *p);
bool contentFitsInPushButton(const QStyleOptionButton *btn, HIThemeButtonDrawInfo *bdi,
ThemeButtonKind buttonKindToCheck) const;
void initHIThemePushButton(const QStyleOptionButton *btn, const QWidget *widget,
@@ -260,16 +256,18 @@ public:
void setAutoDefaultButton(QObject *button) const;
- NSView *cocoaControl(QCocoaWidget widget) const;
- NSCell *cocoaCell(QCocoaWidget widget) const;
+ NSView *cocoaControl(CocoaControl widget) const;
+ NSCell *cocoaCell(CocoaControl widget) const;
+
+ static CocoaControl cocoaControlFromHIThemeButtonKind(ThemeButtonKind kind);
void setupNSGraphicsContext(CGContextRef cg, bool flipped) const;
void restoreNSGraphicsContext(CGContextRef cg) const;
void setupVerticalInvertedXform(CGContextRef cg, bool reverse, bool vertical, const CGRect &rect) const;
- void drawNSViewInRect(QCocoaWidget widget, NSView *view, const QRect &rect, QPainter *p, bool isQWidget = true, QCocoaDrawRectBlock drawRectBlock = nil) const;
- void resolveCurrentNSView(QWindow *window);
+ void drawNSViewInRect(CocoaControl widget, NSView *view, const QRect &rect, QPainter *p, bool isQWidget = true, DrawRectBlock drawRectBlock = nil) const;
+ void resolveCurrentNSView(QWindow *window) const;
void drawFocusRing(QPainter *p, const QRect &targetRect, int hMargin, int vMargin, qreal radius = 0) const;
@@ -283,9 +281,9 @@ public:
mutable QPointer<QFocusFrame> focusWidget;
QT_MANGLE_NAMESPACE(NotificationReceiver) *receiver;
- NSView *backingStoreNSView;
- mutable QHash<QCocoaWidget, NSView *> cocoaControls;
- mutable QHash<QCocoaWidget, NSCell *> cocoaCells;
+ mutable NSView *backingStoreNSView;
+ mutable QHash<CocoaControl, NSView *> cocoaControls;
+ mutable QHash<CocoaControl, NSCell *> cocoaCells;
QFont smallSystemFont;
QFont miniSystemFont;
diff --git a/src/testlib/qtesthelpers_p.h b/src/testlib/qtesthelpers_p.h
new file mode 100644
index 0000000000..0e39f7aea2
--- /dev/null
+++ b/src/testlib/qtesthelpers_p.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtTest 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$
+**
+****************************************************************************/
+
+#ifndef QTESTHELPERS_P_H
+#define QTESTHELPERS_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 <QtCore/QFile>
+#include <QtCore/QString>
+#include <QtCore/QChar>
+#include <QtCore/QPoint>
+
+#ifdef QT_GUI_LIB
+#include <QtGui/QGuiApplication>
+#include <QtGui/QScreen>
+#endif
+
+#ifdef QT_WIDGETS_LIB
+#include <QtWidgets/QWidget>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace QTestPrivate {
+
+static inline bool canHandleUnicodeFileNames()
+{
+#if defined(Q_OS_WIN)
+ return true;
+#else
+ // Check for UTF-8 by converting the Euro symbol (see tst_utf8)
+ return QFile::encodeName(QString(QChar(0x20AC))) == QByteArrayLiteral("\342\202\254");
+#endif
+}
+
+#ifdef QT_WIDGETS_LIB
+static inline void centerOnScreen(QWidget *w, const QSize &size)
+{
+ const QPoint offset = QPoint(size.width() / 2, size.height() / 2);
+ w->move(QGuiApplication::primaryScreen()->availableGeometry().center() - offset);
+}
+
+static inline void centerOnScreen(QWidget *w)
+{
+ centerOnScreen(w, w->geometry().size());
+}
+
+/*! \internal
+
+ Make a widget frameless to prevent size constraints of title bars from interfering (Windows).
+*/
+static inline void setFrameless(QWidget *w)
+{
+ Qt::WindowFlags flags = w->windowFlags();
+ flags |= Qt::FramelessWindowHint;
+ flags &= ~(Qt::WindowTitleHint | Qt::WindowSystemMenuHint
+ | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
+ w->setWindowFlags(flags);
+}
+#endif // QT_WIDGETS_LIB
+
+} // namespace QTestPrivate
+
+QT_END_NAMESPACE
+
+#endif // QTESTHELPERS_P_H
diff --git a/src/testlib/testlib.pro b/src/testlib/testlib.pro
index e11e25e1da..f99f28ca84 100644
--- a/src/testlib/testlib.pro
+++ b/src/testlib/testlib.pro
@@ -37,7 +37,8 @@ HEADERS = qbenchmark.h \
qtestspontaneevent.h \
qtestsystem.h \
qtesttouch.h \
- qtestblacklist_p.h
+ qtestblacklist_p.h \
+ qtesthelpers_p.h
SOURCES = qtestcase.cpp \
qtestlog.cpp \
diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp
index d6db7deee7..463ed7e58c 100644
--- a/src/widgets/itemviews/qheaderview.cpp
+++ b/src/widgets/itemviews/qheaderview.cpp
@@ -3376,7 +3376,7 @@ void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool
// because it isn't stretch, determine its width and remove that from lengthToStretch
int sectionSize = 0;
if (resizeMode == QHeaderView::Interactive || resizeMode == QHeaderView::Fixed) {
- sectionSize = headerSectionSize(i);
+ sectionSize = qBound(q->minimumSectionSize(), headerSectionSize(i), q->maximumSectionSize());
} else { // resizeMode == QHeaderView::ResizeToContents
int logicalIndex = q->logicalIndex(i);
sectionSize = qMax(viewSectionSizeHint(logicalIndex),
@@ -3551,6 +3551,8 @@ void QHeaderViewPrivate::cascadingResize(int visual, int newSize)
// cascade the section size change
for (int i = visual + 1; i < sectionCount(); ++i) {
+ if (isVisualIndexHidden(i))
+ continue;
if (!sectionIsCascadable(i))
continue;
int currentSectionSize = headerSectionSize(i);
@@ -3593,6 +3595,8 @@ void QHeaderViewPrivate::cascadingResize(int visual, int newSize)
// cascade the section size change
if (delta < 0 && newSize < minimumSize) {
for (int i = visual - 1; i >= 0; --i) {
+ if (isVisualIndexHidden(i))
+ continue;
if (!sectionIsCascadable(i))
continue;
int sectionSize = headerSectionSize(i);
@@ -3607,6 +3611,8 @@ void QHeaderViewPrivate::cascadingResize(int visual, int newSize)
// let the next section get the space from the resized section
if (!sectionResized) {
for (int i = visual + 1; i < sectionCount(); ++i) {
+ if (isVisualIndexHidden(i))
+ continue;
if (!sectionIsCascadable(i))
continue;
int currentSectionSize = headerSectionSize(i);
diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp
index 0efee755a2..7f027595b7 100644
--- a/src/widgets/itemviews/qlistview.cpp
+++ b/src/widgets/itemviews/qlistview.cpp
@@ -2873,10 +2873,19 @@ void QIconModeViewBase::scrollContentsBy(int dx, int dy, bool scrollElasticBand)
void QIconModeViewBase::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
if (column() >= topLeft.column() && column() <= bottomRight.column()) {
- QStyleOptionViewItem option = viewOptions();
- int bottom = qMin(items.count(), bottomRight.row() + 1);
+ const QStyleOptionViewItem option = viewOptions();
+ const int bottom = qMin(items.count(), bottomRight.row() + 1);
+ const bool useItemSize = !dd->grid.isValid();
for (int row = topLeft.row(); row < bottom; ++row)
- items[row].resize(itemSize(option, modelIndex(row)));
+ {
+ QSize s = itemSize(option, modelIndex(row));
+ if (!useItemSize)
+ {
+ s.setWidth(qMin(dd->grid.width(), s.width()));
+ s.setHeight(qMin(dd->grid.height(), s.height()));
+ }
+ items[row].resize(s);
+ }
}
}
diff --git a/src/widgets/kernel/qshortcut.cpp b/src/widgets/kernel/qshortcut.cpp
index f944a7097b..32600d4152 100644
--- a/src/widgets/kernel/qshortcut.cpp
+++ b/src/widgets/kernel/qshortcut.cpp
@@ -205,7 +205,7 @@ static bool correctWidgetContext(Qt::ShortcutContext context, QWidget *w, QWidge
#if defined(DEBUG_QSHORTCUTMAP)
qDebug().nospace() << "..true [Pass-through]";
#endif
- return true;
+ return QApplicationPrivate::tryModalHelper(w, nullptr);
}
#if QT_CONFIG(graphicsview)
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index 3369548f18..2ee9d307c9 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -1374,6 +1374,8 @@ void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow)
d->setWindowIconText_helper(d->topData()->iconText);
if (isWindow() && !d->topData()->caption.isEmpty())
d->setWindowTitle_helper(d->topData()->caption);
+ if (isWindow() && !d->topData()->filePath.isEmpty())
+ d->setWindowFilePath_helper(d->topData()->filePath);
if (windowType() != Qt::Desktop) {
d->updateSystemBackground();
diff --git a/src/widgets/widgets/qabstractbutton.cpp b/src/widgets/widgets/qabstractbutton.cpp
index dbd94e890d..5854472ff0 100644
--- a/src/widgets/widgets/qabstractbutton.cpp
+++ b/src/widgets/widgets/qabstractbutton.cpp
@@ -991,13 +991,14 @@ void QAbstractButton::mousePressEvent(QMouseEvent *e)
void QAbstractButton::mouseReleaseEvent(QMouseEvent *e)
{
Q_D(QAbstractButton);
- d->pressed = false;
if (e->button() != Qt::LeftButton) {
e->ignore();
return;
}
+ d->pressed = false;
+
if (!d->down) {
// refresh is required by QMacStyle to resume the default button animation
d->refresh();
diff --git a/src/widgets/widgets/qmainwindow.cpp b/src/widgets/widgets/qmainwindow.cpp
index d97fedadab..00ee0a9d10 100644
--- a/src/widgets/widgets/qmainwindow.cpp
+++ b/src/widgets/widgets/qmainwindow.cpp
@@ -545,6 +545,7 @@ void QMainWindow::setMenuBar(QMenuBar *menuBar)
menuBar->setCornerWidget(cornerWidget, Qt::TopRightCorner);
}
oldMenuBar->hide();
+ oldMenuBar->setParent(nullptr);
oldMenuBar->deleteLater();
}
topLayout->setMenuBar(menuBar);
diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp
index ded218de73..c5b912e35b 100644
--- a/src/widgets/widgets/qmenu.cpp
+++ b/src/widgets/widgets/qmenu.cpp
@@ -234,9 +234,6 @@ void QMenuPrivate::setPlatformMenu(QPlatformMenu *menu)
}
}
-// forward declare function
-static void copyActionToPlatformItem(const QAction *action, QPlatformMenuItem *item, QPlatformMenu *itemsMenu);
-
void QMenuPrivate::syncPlatformMenu()
{
Q_Q(QMenu);
@@ -246,19 +243,64 @@ void QMenuPrivate::syncPlatformMenu()
QPlatformMenuItem *beforeItem = Q_NULLPTR;
const QList<QAction*> actions = q->actions();
for (QList<QAction*>::const_reverse_iterator it = actions.rbegin(), end = actions.rend(); it != end; ++it) {
- QPlatformMenuItem *menuItem = platformMenu->createMenuItem();
- QAction *action = *it;
- menuItem->setTag(reinterpret_cast<quintptr>(action));
- QObject::connect(menuItem, SIGNAL(activated()), action, SLOT(trigger()), Qt::QueuedConnection);
- QObject::connect(menuItem, SIGNAL(hovered()), action, SIGNAL(hovered()), Qt::QueuedConnection);
- copyActionToPlatformItem(action, menuItem, platformMenu.data());
- platformMenu->insertMenuItem(menuItem, beforeItem);
+ QPlatformMenuItem *menuItem = insertActionInPlatformMenu(*it, beforeItem);
beforeItem = menuItem;
}
platformMenu->syncSeparatorsCollapsible(collapsibleSeparators);
platformMenu->setEnabled(q->isEnabled());
}
+void QMenuPrivate::copyActionToPlatformItem(const QAction *action, QPlatformMenuItem *item)
+{
+ item->setText(action->text());
+ item->setIsSeparator(action->isSeparator());
+ if (action->isIconVisibleInMenu()) {
+ item->setIcon(action->icon());
+ if (QWidget *w = action->parentWidget()) {
+ QStyleOption opt;
+ opt.init(w);
+ item->setIconSize(w->style()->pixelMetric(QStyle::PM_SmallIconSize, &opt, w));
+ } else {
+ QStyleOption opt;
+ item->setIconSize(qApp->style()->pixelMetric(QStyle::PM_SmallIconSize, &opt, 0));
+ }
+ } else {
+ item->setIcon(QIcon());
+ }
+ item->setVisible(action->isVisible());
+#if QT_CONFIG(shortcut)
+ item->setShortcut(action->shortcut());
+#endif
+ item->setCheckable(action->isCheckable());
+ item->setChecked(action->isChecked());
+ item->setHasExclusiveGroup(action->actionGroup() && action->actionGroup()->isExclusive());
+ item->setFont(action->font());
+ item->setRole((QPlatformMenuItem::MenuRole) action->menuRole());
+ item->setEnabled(action->isEnabled());
+
+ if (action->menu()) {
+ if (!action->menu()->platformMenu())
+ action->menu()->setPlatformMenu(platformMenu->createSubMenu());
+ item->setMenu(action->menu()->platformMenu());
+ } else {
+ item->setMenu(0);
+ }
+}
+
+QPlatformMenuItem * QMenuPrivate::insertActionInPlatformMenu(const QAction *action, QPlatformMenuItem *beforeItem)
+{
+ QPlatformMenuItem *menuItem = platformMenu->createMenuItem();
+ Q_ASSERT(menuItem);
+
+ menuItem->setTag(reinterpret_cast<quintptr>(action));
+ QObject::connect(menuItem, &QPlatformMenuItem::activated, action, &QAction::trigger, Qt::QueuedConnection);
+ QObject::connect(menuItem, &QPlatformMenuItem::hovered, action, &QAction::hovered, Qt::QueuedConnection);
+ copyActionToPlatformItem(action, menuItem);
+ platformMenu->insertMenuItem(menuItem, beforeItem);
+
+ return menuItem;
+}
+
int QMenuPrivate::scrollerHeight() const
{
Q_Q(const QMenu);
@@ -2339,6 +2381,12 @@ void QMenu::popup(const QPoint &p, QAction *atAction)
d->updateLayoutDirection();
d->adjustMenuScreen(p);
+ const bool contextMenu = d->isContextMenu();
+ if (d->lastContextMenu != contextMenu) {
+ d->itemsDirty = true;
+ d->lastContextMenu = contextMenu;
+ }
+
#if QT_CONFIG(menubar)
// if this menu is part of a chain attached to a QMenuBar, set the
// _NET_WM_WINDOW_TYPE_DROPDOWN_MENU X11 window type
@@ -3477,43 +3525,6 @@ QMenu::timerEvent(QTimerEvent *e)
}
}
-static void copyActionToPlatformItem(const QAction *action, QPlatformMenuItem *item, QPlatformMenu *itemsMenu)
-{
- item->setText(action->text());
- item->setIsSeparator(action->isSeparator());
- if (action->isIconVisibleInMenu()) {
- item->setIcon(action->icon());
- if (QWidget *w = action->parentWidget()) {
- QStyleOption opt;
- opt.init(w);
- item->setIconSize(w->style()->pixelMetric(QStyle::PM_SmallIconSize, &opt, w));
- } else {
- QStyleOption opt;
- item->setIconSize(qApp->style()->pixelMetric(QStyle::PM_SmallIconSize, &opt, 0));
- }
- } else {
- item->setIcon(QIcon());
- }
- item->setVisible(action->isVisible());
-#ifndef QT_NO_SHORTCUT
- item->setShortcut(action->shortcut());
-#endif
- item->setCheckable(action->isCheckable());
- item->setChecked(action->isChecked());
- item->setHasExclusiveGroup(action->actionGroup() && action->actionGroup()->isExclusive());
- item->setFont(action->font());
- item->setRole((QPlatformMenuItem::MenuRole) action->menuRole());
- item->setEnabled(action->isEnabled());
-
- if (action->menu()) {
- if (!action->menu()->platformMenu())
- action->menu()->setPlatformMenu(itemsMenu->createSubMenu());
- item->setMenu(action->menu()->platformMenu());
- } else {
- item->setMenu(0);
- }
-}
-
/*!
\reimp
*/
@@ -3567,15 +3578,10 @@ void QMenu::actionEvent(QActionEvent *e)
if (!d->platformMenu.isNull()) {
if (e->type() == QEvent::ActionAdded) {
- QPlatformMenuItem *menuItem = d->platformMenu->createMenuItem();
- menuItem->setTag(reinterpret_cast<quintptr>(e->action()));
- QObject::connect(menuItem, SIGNAL(activated()), e->action(), SLOT(trigger()));
- QObject::connect(menuItem, SIGNAL(hovered()), e->action(), SIGNAL(hovered()));
- copyActionToPlatformItem(e->action(), menuItem, d->platformMenu);
QPlatformMenuItem *beforeItem = e->before()
? d->platformMenu->menuItemForTag(reinterpret_cast<quintptr>(e->before()))
: nullptr;
- d->platformMenu->insertMenuItem(menuItem, beforeItem);
+ d->insertActionInPlatformMenu(e->action(), beforeItem);
} else if (e->type() == QEvent::ActionRemoved) {
QPlatformMenuItem *menuItem = d->platformMenu->menuItemForTag(reinterpret_cast<quintptr>(e->action()));
d->platformMenu->removeMenuItem(menuItem);
@@ -3583,7 +3589,7 @@ void QMenu::actionEvent(QActionEvent *e)
} else if (e->type() == QEvent::ActionChanged) {
QPlatformMenuItem *menuItem = d->platformMenu->menuItemForTag(reinterpret_cast<quintptr>(e->action()));
if (menuItem) {
- copyActionToPlatformItem(e->action(), menuItem, d->platformMenu);
+ d->copyActionToPlatformItem(e->action(), menuItem);
d->platformMenu->syncMenuItem(menuItem);
}
}
diff --git a/src/widgets/widgets/qmenu_p.h b/src/widgets/widgets/qmenu_p.h
index 5869bc8420..ce5134958e 100644
--- a/src/widgets/widgets/qmenu_p.h
+++ b/src/widgets/widgets/qmenu_p.h
@@ -91,19 +91,10 @@ class QMenuSloppyState
Q_DISABLE_COPY(QMenuSloppyState)
public:
QMenuSloppyState()
- : m_menu(Q_NULLPTR)
- , m_enabled(false)
+ : m_enabled(false)
, m_uni_directional(false)
, m_select_other_actions(false)
- , m_first_mouse(true)
- , m_init_guard(false)
, m_use_reset_action(true)
- , m_uni_dir_discarded_count(0)
- , m_uni_dir_fail_at_count(0)
- , m_timeout(0)
- , m_reset_action(Q_NULLPTR)
- , m_origin_action(Q_NULLPTR)
- , m_parent(Q_NULLPTR)
{ }
~QMenuSloppyState() { reset(); }
@@ -252,44 +243,46 @@ public:
QMenu *subMenu() const { return m_sub_menu; }
private:
- QMenu *m_menu;
- bool m_enabled;
- bool m_uni_directional;
- bool m_select_other_actions;
- bool m_first_mouse;
- bool m_init_guard;
- bool m_discard_state_when_entering_parent;
- bool m_dont_start_time_on_leave;
- bool m_use_reset_action;
- short m_uni_dir_discarded_count;
- short m_uni_dir_fail_at_count;
- short m_timeout;
- QBasicTimer m_time;
- QAction *m_reset_action;
- QAction *m_origin_action;
+ QMenu *m_menu = nullptr;
+ QAction *m_reset_action = nullptr;
+ QAction *m_origin_action = nullptr;
QRectF m_action_rect;
QPointF m_previous_point;
QPointer<QMenu> m_sub_menu;
- QMenuSloppyState *m_parent;
+ QMenuSloppyState *m_parent = nullptr;
+ QBasicTimer m_time;
+ short m_uni_dir_discarded_count = 0;
+ short m_uni_dir_fail_at_count = 0;
+ short m_timeout = 0;
+ bool m_init_guard = false;
+ bool m_first_mouse = true;
+
+ bool m_enabled : 1;
+ bool m_uni_directional : 1;
+ bool m_select_other_actions : 1;
+ bool m_discard_state_when_entering_parent : 1;
+ bool m_dont_start_time_on_leave : 1;
+ bool m_use_reset_action : 1;
};
class QMenuPrivate : public QWidgetPrivate
{
Q_DECLARE_PUBLIC(QMenu)
public:
- QMenuPrivate() : itemsDirty(0), maxIconWidth(0), tabWidth(0), ncols(0),
- collapsibleSeparators(true), toolTipsVisible(false),
- activationRecursionGuard(false), delayedPopupGuard(false),
- hasReceievedEnter(false),
- hasHadMouse(0), aboutToHide(0), motions(0),
- currentAction(0),
-#ifdef QT_KEYPAD_NAVIGATION
- selectAction(0),
- cancelAction(0),
-#endif
- scroll(0), eventLoop(0), tearoff(0), tornoff(0), tearoffHighlighted(0),
- hasCheckableItems(0), doChildEffects(false), platformMenu(0),
- scrollUpTearOffItem(nullptr), scrollDownItem(nullptr)
+ QMenuPrivate() :
+ itemsDirty(false),
+ hasCheckableItems(false),
+ lastContextMenu(false),
+ collapsibleSeparators(true),
+ toolTipsVisible(false),
+ delayedPopupGuard(false),
+ hasReceievedEnter(false),
+ hasHadMouse(false),
+ aboutToHide(false),
+ tearoff(false),
+ tornoff(false),
+ tearoffHighlighted(false),
+ doChildEffects(false)
{ }
~QMenuPrivate()
@@ -302,6 +295,9 @@ public:
QPlatformMenu *createPlatformMenu();
void setPlatformMenu(QPlatformMenu *menu);
void syncPlatformMenu();
+ void copyActionToPlatformItem(const QAction *action, QPlatformMenuItem *item);
+ QPlatformMenuItem *insertActionInPlatformMenu(const QAction *action, QPlatformMenuItem *beforeItem);
+
#ifdef Q_OS_OSX
void moveWidgetToPlatformItem(QWidget *w, QPlatformMenuItem* item);
#endif
@@ -312,8 +308,6 @@ public:
bool isContextMenu() const;
//item calculations
- mutable uint itemsDirty : 1;
- mutable uint maxIconWidth, tabWidth;
QRect actionRect(QAction *) const;
mutable QVector<QRect> actionRects;
@@ -322,31 +316,19 @@ public:
void updateActionRects(const QRect &screen) const;
QRect popupGeometry() const;
QRect popupGeometry(int screen) const;
- mutable uint ncols : 4; //4 bits is probably plenty
- uint collapsibleSeparators : 1;
- uint toolTipsVisible : 1;
int getLastVisibleAction() const;
- bool activationRecursionGuard;
- bool delayedPopupGuard;
- bool hasReceievedEnter;
-
//selection
static QMenu *mouseDown;
QPoint mousePopupPos;
- uint hasHadMouse : 1;
- uint aboutToHide : 1;
- int motions;
- int mousePopupDelay;
- QAction *currentAction;
+
+ QAction *currentAction = nullptr;
#ifdef QT_KEYPAD_NAVIGATION
- QAction *selectAction;
- QAction *cancelAction;
+ QAction *selectAction = nullptr;
+ QAction *cancelAction = nullptr;
#endif
struct DelayState {
DelayState()
- : parent(0)
- , action(0)
{ }
void initialize(QMenu *parent)
{
@@ -366,9 +348,9 @@ public:
timer.stop();
}
- QMenu *parent;
+ QMenu *parent = nullptr;
+ QAction *action = nullptr;
QBasicTimer timer;
- QAction *action;
} delayState;
enum SelectionReason {
SelectedFromKeyboard,
@@ -385,19 +367,20 @@ public:
struct QMenuScroller {
enum ScrollLocation { ScrollStay, ScrollBottom, ScrollTop, ScrollCenter };
enum ScrollDirection { ScrollNone=0, ScrollUp=0x01, ScrollDown=0x02 };
- uint scrollFlags : 2, scrollDirection : 2;
- int scrollOffset;
+ int scrollOffset = 0;
QBasicTimer scrollTimer;
+ quint8 scrollFlags = ScrollNone;
+ quint8 scrollDirection = ScrollNone;
- QMenuScroller() : scrollFlags(ScrollNone), scrollDirection(ScrollNone), scrollOffset(0) { }
+ QMenuScroller() { }
~QMenuScroller() { }
- } *scroll;
+ } *scroll = nullptr;
void scrollMenu(QMenuScroller::ScrollLocation location, bool active=false);
void scrollMenu(QMenuScroller::ScrollDirection direction, bool page=false, bool active=false);
void scrollMenu(QAction *action, QMenuScroller::ScrollLocation location, bool active=false);
//synchronous operation (ie exec())
- QEventLoop *eventLoop;
+ QEventLoop *eventLoop = nullptr;
QPointer<QAction> syncAction;
//search buffer
@@ -423,18 +406,15 @@ public:
inline int indexOf(QAction *act) const { return q_func()->actions().indexOf(act); }
//tear off support
- uint tearoff : 1, tornoff : 1, tearoffHighlighted : 1;
QPointer<QTornOffMenu> tornPopup;
- mutable bool hasCheckableItems;
-
QMenuSloppyState sloppyState;
//default action
QPointer<QAction> defaultAction;
- QAction *menuAction;
- QAction *defaultMenuAction;
+ QAction *menuAction = nullptr;
+ QAction *defaultMenuAction = nullptr;
void setOverrideMenuAction(QAction *);
void _q_overrideMenuActionDestroyed();
@@ -452,9 +432,6 @@ public:
void adjustMenuScreen(const QPoint &p);
void updateLayoutDirection();
- //menu fading/scrolling effects
- bool doChildEffects;
-
QPointer<QPlatformMenu> platformMenu;
QPointer<QAction> actionAboutToTrigger;
@@ -473,12 +450,38 @@ public:
QMenuPrivate *menuPrivate;
Type scrollType;
};
- ScrollerTearOffItem *scrollUpTearOffItem;
- ScrollerTearOffItem *scrollDownItem;
+ ScrollerTearOffItem *scrollUpTearOffItem = nullptr;
+ ScrollerTearOffItem *scrollDownItem = nullptr;
void drawScroller(QPainter *painter, ScrollerTearOffItem::Type type, const QRect &rect);
void drawTearOff(QPainter *painter, const QRect &rect);
QRect rect() const;
+
+ mutable uint maxIconWidth = 0;
+ mutable uint tabWidth = 0;
+ int motions = 0;
+ int mousePopupDelay = 0;
+
+ bool activationRecursionGuard = false;
+
+ mutable quint8 ncols = 0; // "255cols ought to be enough for anybody."
+
+ mutable bool itemsDirty : 1;
+ mutable bool hasCheckableItems : 1;
+ bool lastContextMenu : 1;
+ bool collapsibleSeparators : 1;
+ bool toolTipsVisible : 1;
+ bool delayedPopupGuard : 1;
+ bool hasReceievedEnter : 1;
+ // Selection
+ bool hasHadMouse : 1;
+ bool aboutToHide : 1;
+ // Tear-off menus
+ bool tearoff : 1;
+ bool tornoff : 1;
+ bool tearoffHighlighted : 1;
+ //menu fading/scrolling effects
+ bool doChildEffects : 1;
};
QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp
index cc6f39c439..ece2a0a9c9 100644
--- a/src/widgets/widgets/qmenubar.cpp
+++ b/src/widgets/widgets/qmenubar.cpp
@@ -1188,7 +1188,7 @@ void QMenuBar::leaveEvent(QEvent *)
d->setCurrentAction(0);
}
-QPlatformMenu *QMenuBarPrivate::getPlatformMenu(QAction *action)
+QPlatformMenu *QMenuBarPrivate::getPlatformMenu(const QAction *action)
{
if (!action || !action->menu())
return 0;
@@ -1203,6 +1203,29 @@ QPlatformMenu *QMenuBarPrivate::getPlatformMenu(QAction *action)
return platformMenu;
}
+QPlatformMenu *QMenuBarPrivate::findInsertionPlatformMenu(const QAction *action)
+{
+ Q_Q(QMenuBar);
+ QPlatformMenu *beforeMenu = nullptr;
+ for (int beforeIndex = indexOf(const_cast<QAction *>(action)) + 1;
+ !beforeMenu && (beforeIndex < q->actions().size());
+ ++beforeIndex) {
+ beforeMenu = getPlatformMenu(q->actions().at(beforeIndex));
+ }
+
+ return beforeMenu;
+}
+
+void QMenuBarPrivate::copyActionToPlatformMenu(const QAction *action, QPlatformMenu *menu)
+{
+ const auto tag = reinterpret_cast<quintptr>(action);
+ if (menu->tag() != tag)
+ menu->setTag(tag);
+ menu->setText(action->text());
+ menu->setVisible(action->isVisible());
+ menu->setEnabled(action->isEnabled());
+}
+
/*!
\reimp
*/
@@ -1219,16 +1242,9 @@ void QMenuBar::actionEvent(QActionEvent *e)
if (e->type() == QEvent::ActionAdded) {
QPlatformMenu *menu = d->getPlatformMenu(e->action());
if (menu) {
- QPlatformMenu* beforeMenu = NULL;
- for (int beforeIndex = d->indexOf(e->action()) + 1;
- !beforeMenu && (beforeIndex < actions().size());
- ++beforeIndex)
- {
- beforeMenu = d->getPlatformMenu(actions().at(beforeIndex));
- }
+ d->copyActionToPlatformMenu(e->action(), menu);
- menu->setTag(reinterpret_cast<quintptr>(e->action()));
- menu->setText(e->action()->text());
+ QPlatformMenu *beforeMenu = d->findInsertionPlatformMenu(e->action());
d->platformMenuBar->insertMenu(menu, beforeMenu);
}
} else if (e->type() == QEvent::ActionRemoved) {
@@ -1236,7 +1252,7 @@ void QMenuBar::actionEvent(QActionEvent *e)
if (menu)
d->platformMenuBar->removeMenu(menu);
} else if (e->type() == QEvent::ActionChanged) {
- QPlatformMenu* cur = d->platformMenuBar->menuForTag(reinterpret_cast<quintptr>(e->action()));
+ QPlatformMenu *cur = d->platformMenuBar->menuForTag(reinterpret_cast<quintptr>(e->action()));
QPlatformMenu *menu = d->getPlatformMenu(e->action());
// the menu associated with the action can change, need to
@@ -1245,21 +1261,13 @@ void QMenuBar::actionEvent(QActionEvent *e)
if (cur)
d->platformMenuBar->removeMenu(cur);
if (menu) {
- menu->setTag(reinterpret_cast<quintptr>(e->action()));
-
- QPlatformMenu* beforeMenu = NULL;
- for (int beforeIndex = d->indexOf(e->action()) + 1;
- !beforeMenu && (beforeIndex < actions().size());
- ++beforeIndex)
- {
- beforeMenu = d->getPlatformMenu(actions().at(beforeIndex));
- }
+ d->copyActionToPlatformMenu(e->action(), menu);
+
+ QPlatformMenu *beforeMenu = d->findInsertionPlatformMenu(e->action());
d->platformMenuBar->insertMenu(menu, beforeMenu);
}
} else if (menu) {
- menu->setText(e->action()->text());
- menu->setVisible(e->action()->isVisible());
- menu->setEnabled(e->action()->isEnabled());
+ d->copyActionToPlatformMenu(e->action(), menu);
d->platformMenuBar->syncMenu(menu);
}
}
diff --git a/src/widgets/widgets/qmenubar_p.h b/src/widgets/widgets/qmenubar_p.h
index 01d8793a3a..c276a4512d 100644
--- a/src/widgets/widgets/qmenubar_p.h
+++ b/src/widgets/widgets/qmenubar_p.h
@@ -132,7 +132,9 @@ public:
QBasicTimer autoReleaseTimer;
QPlatformMenuBar *platformMenuBar;
- QPlatformMenu *getPlatformMenu(QAction *action);
+ QPlatformMenu *getPlatformMenu(const QAction *action);
+ QPlatformMenu *findInsertionPlatformMenu(const QAction *action);
+ void copyActionToPlatformMenu(const QAction *e, QPlatformMenu *menu);
inline int indexOf(QAction *act) const { return q_func()->actions().indexOf(act); }
};