[geany/geany] 7694aa: Update to Scintilla5 (#2867)

Thomas Martitz git-noreply at xxxxx
Sat Oct 9 23:46:37 UTC 2021


Branch:      refs/heads/master
Author:      Thomas Martitz <thomas.martitz at mailbox.org>
Committer:   GitHub <noreply at github.com>
Date:        Sat, 09 Oct 2021 23:46:37 UTC
Commit:      7694aa5acb730fb7d0bbd1b4212140e63d315215
             https://github.com/geany/geany/commit/7694aa5acb730fb7d0bbd1b4212140e63d315215

Log Message:
-----------
Update to Scintilla5  (#2867)

* Update Scintilla to version 5.1.1

A few notes:
- C++17 is required
  Not exactly new since we already imported the latest julia lexer.
- upstream split out lexers into a lexilla library
  We do "comply" by building a separate static library. So in effect, all
  lexers are built-in like before. In the future it may be possible to add
  lexer plugins at runtime.
- Lexer IDs are deprecated in favor of names
  For now we use LexerNameFromID() to map IDs to names but we should
  transition to names soon.
  That being said, the upstream transition seems also not complete.
  There is no name-based version of SCI_GETLEXER, so we're stuck with IDs
  there.

Closes #2824

* Update scintilla_changes.patch

The "which lexers" part is now a separate function that should be less
of a pain when updating to scintilla version that adds lexers.

* Update update-scintilla.sh

You need to extract lexilla sources too now and pass it to the script.
Also the script calls dos2unix for the files, kill that CRLF!


Modified Paths:
--------------
    configure.ac
    plugins/Makefile.am
    scintilla/License.txt
    scintilla/Makefile.am
    scintilla/gtk/PlatGTK.cxx
    scintilla/gtk/ScintillaGTK.cxx
    scintilla/gtk/ScintillaGTK.h
    scintilla/gtk/ScintillaGTKAccessible.cxx
    scintilla/gtk/ScintillaGTKAccessible.h
    scintilla/include/Compat.h
    scintilla/include/ILexer.h
    scintilla/include/ILoader.h
    scintilla/include/Makefile.am
    scintilla/include/Platform.h
    scintilla/include/Scintilla.h
    scintilla/include/Scintilla.iface
    scintilla/include/ScintillaCall.h
    scintilla/include/ScintillaMessages.h
    scintilla/include/ScintillaStructures.h
    scintilla/include/ScintillaTypes.h
    scintilla/julia_lexilla_v5.patch
    scintilla/lexilla/License.txt
    scintilla/lexilla/include/LexicalStyles.iface
    scintilla/lexilla/include/Lexilla.h
    scintilla/lexilla/include/SciLexer.h
    scintilla/lexilla/lexers/LexAbaqus.cxx
    scintilla/lexilla/lexers/LexAda.cxx
    scintilla/lexilla/lexers/LexAsm.cxx
    scintilla/lexilla/lexers/LexBash.cxx
    scintilla/lexilla/lexers/LexBasic.cxx
    scintilla/lexilla/lexers/LexBatch.cxx
    scintilla/lexilla/lexers/LexCOBOL.cxx
    scintilla/lexilla/lexers/LexCPP.cxx
    scintilla/lexilla/lexers/LexCSS.cxx
    scintilla/lexilla/lexers/LexCaml.cxx
    scintilla/lexilla/lexers/LexCmake.cxx
    scintilla/lexilla/lexers/LexCoffeeScript.cxx
    scintilla/lexilla/lexers/LexD.cxx
    scintilla/lexilla/lexers/LexDiff.cxx
    scintilla/lexilla/lexers/LexErlang.cxx
    scintilla/lexilla/lexers/LexForth.cxx
    scintilla/lexilla/lexers/LexFortran.cxx
    scintilla/lexilla/lexers/LexHTML.cxx
    scintilla/lexilla/lexers/LexHaskell.cxx
    scintilla/lexilla/lexers/LexJulia.cxx
    scintilla/lexilla/lexers/LexLaTeX.cxx
    scintilla/lexilla/lexers/LexLisp.cxx
    scintilla/lexilla/lexers/LexLua.cxx
    scintilla/lexilla/lexers/LexMake.cxx
    scintilla/lexilla/lexers/LexMarkdown.cxx
    scintilla/lexilla/lexers/LexMatlab.cxx
    scintilla/lexilla/lexers/LexNsis.cxx
    scintilla/lexilla/lexers/LexNull.cxx
    scintilla/lexilla/lexers/LexPO.cxx
    scintilla/lexilla/lexers/LexPascal.cxx
    scintilla/lexilla/lexers/LexPerl.cxx
    scintilla/lexilla/lexers/LexPowerShell.cxx
    scintilla/lexilla/lexers/LexProps.cxx
    scintilla/lexilla/lexers/LexPython.cxx
    scintilla/lexilla/lexers/LexR.cxx
    scintilla/lexilla/lexers/LexRuby.cxx
    scintilla/lexilla/lexers/LexRust.cxx
    scintilla/lexilla/lexers/LexSQL.cxx
    scintilla/lexilla/lexers/LexSmalltalk.cxx
    scintilla/lexilla/lexers/LexTCL.cxx
    scintilla/lexilla/lexers/LexTxt2tags.cxx
    scintilla/lexilla/lexers/LexVHDL.cxx
    scintilla/lexilla/lexers/LexVerilog.cxx
    scintilla/lexilla/lexers/LexYAML.cxx
    scintilla/lexilla/lexlib/Accessor.cxx
    scintilla/lexilla/lexlib/Accessor.h
    scintilla/lexilla/lexlib/CatalogueModules.h
    scintilla/lexilla/lexlib/CharacterCategory.cxx
    scintilla/lexilla/lexlib/CharacterCategory.h
    scintilla/lexilla/lexlib/CharacterSet.cxx
    scintilla/lexilla/lexlib/CharacterSet.h
    scintilla/lexilla/lexlib/DefaultLexer.cxx
    scintilla/lexilla/lexlib/DefaultLexer.h
    scintilla/lexilla/lexlib/LexAccessor.cxx
    scintilla/lexilla/lexlib/LexAccessor.h
    scintilla/lexilla/lexlib/LexerBase.cxx
    scintilla/lexilla/lexlib/LexerBase.h
    scintilla/lexilla/lexlib/LexerModule.cxx
    scintilla/lexilla/lexlib/LexerModule.h
    scintilla/lexilla/lexlib/LexerNoExceptions.cxx
    scintilla/lexilla/lexlib/LexerNoExceptions.h
    scintilla/lexilla/lexlib/LexerSimple.cxx
    scintilla/lexilla/lexlib/LexerSimple.h
    scintilla/lexilla/lexlib/OptionSet.h
    scintilla/lexilla/lexlib/PropSetSimple.cxx
    scintilla/lexilla/lexlib/PropSetSimple.h
    scintilla/lexilla/lexlib/SparseState.h
    scintilla/lexilla/lexlib/StringCopy.h
    scintilla/lexilla/lexlib/StyleContext.cxx
    scintilla/lexilla/lexlib/StyleContext.h
    scintilla/lexilla/lexlib/SubStyles.h
    scintilla/lexilla/lexlib/WordList.cxx
    scintilla/lexilla/lexlib/WordList.h
    scintilla/lexilla/src/Lexilla.cxx
    scintilla/lexilla/version.txt
    scintilla/lexlib/PropSetSimple.cxx
    scintilla/lexlib/PropSetSimple.h
    scintilla/scintilla_changes.patch
    scintilla/src/AutoComplete.cxx
    scintilla/src/AutoComplete.h
    scintilla/src/CallTip.cxx
    scintilla/src/CallTip.h
    scintilla/src/CaseConvert.cxx
    scintilla/src/CaseConvert.h
    scintilla/src/CaseFolder.cxx
    scintilla/src/CaseFolder.h
    scintilla/src/Catalogue.cxx
    scintilla/src/Catalogue.h
    scintilla/src/CellBuffer.cxx
    scintilla/src/CellBuffer.h
    scintilla/src/CharClassify.cxx
    scintilla/src/CharClassify.h
    scintilla/src/CharacterCategoryMap.cxx
    scintilla/src/CharacterCategoryMap.h
    scintilla/src/CharacterType.cxx
    scintilla/src/CharacterType.h
    scintilla/src/ContractionState.cxx
    scintilla/src/ContractionState.h
    scintilla/src/DBCS.cxx
    scintilla/src/DBCS.h
    scintilla/src/Debugging.h
    scintilla/src/Decoration.cxx
    scintilla/src/Decoration.h
    scintilla/src/Document.cxx
    scintilla/src/Document.h
    scintilla/src/EditModel.cxx
    scintilla/src/EditModel.h
    scintilla/src/EditView.cxx
    scintilla/src/EditView.h
    scintilla/src/Editor.cxx
    scintilla/src/Editor.h
    scintilla/src/ElapsedPeriod.h
    scintilla/src/ExternalLexer.cxx
    scintilla/src/ExternalLexer.h
    scintilla/src/FontQuality.h
    scintilla/src/Geometry.cxx
    scintilla/src/Geometry.h
    scintilla/src/Indicator.cxx
    scintilla/src/Indicator.h
    scintilla/src/IntegerRectangle.h
    scintilla/src/KeyMap.cxx
    scintilla/src/KeyMap.h
    scintilla/src/LineMarker.cxx
    scintilla/src/LineMarker.h
    scintilla/src/MarginView.cxx
    scintilla/src/MarginView.h
    scintilla/src/Partitioning.h
    scintilla/src/PerLine.cxx
    scintilla/src/PerLine.h
    scintilla/src/Platform.h
    scintilla/src/Position.h
    scintilla/src/PositionCache.cxx
    scintilla/src/PositionCache.h
    scintilla/src/RESearch.cxx
    scintilla/src/RESearch.h
    scintilla/src/RunStyles.cxx
    scintilla/src/RunStyles.h
    scintilla/src/SVector.h
    scintilla/src/ScintillaBase.cxx
    scintilla/src/ScintillaBase.h
    scintilla/src/Selection.cxx
    scintilla/src/Selection.h
    scintilla/src/SparseVector.h
    scintilla/src/SplitVector.h
    scintilla/src/Style.cxx
    scintilla/src/Style.h
    scintilla/src/UniConversion.cxx
    scintilla/src/UniConversion.h
    scintilla/src/UnicodeFromUTF8.h
    scintilla/src/UniqueString.cxx
    scintilla/src/UniqueString.h
    scintilla/src/ViewStyle.cxx
    scintilla/src/ViewStyle.h
    scintilla/src/XPM.cxx
    scintilla/src/XPM.h
    scintilla/version.txt
    scripts/update-scintilla.sh
    src/Makefile.am
    src/sciwrappers.c

Modified: configure.ac
1 lines changed, 0 insertions(+), 1 deletions(-)
===================================================================
@@ -167,7 +167,6 @@ AC_CONFIG_FILES([
 		icons/tango/scalable/Makefile
 		ctags/Makefile
 		scintilla/Makefile
-		scintilla/include/Makefile
 		src/Makefile
 		src/tagmanager/Makefile
 		plugins/Makefile


Modified: plugins/Makefile.am
1 lines changed, 1 insertions(+), 0 deletions(-)
===================================================================
@@ -74,6 +74,7 @@ AM_CPPFLAGS += \
 	-DGTK \
 	-I$(top_srcdir)/src \
 	-I$(top_srcdir)/src/tagmanager \
+	-I$(top_srcdir)/scintilla/lexilla/include \
 	-I$(top_srcdir)/scintilla/include \
 	$(GTK_CFLAGS) \
 	$(PLUGIN_CFLAGS)


Modified: scintilla/License.txt
4 lines changed, 2 insertions(+), 2 deletions(-)
===================================================================
@@ -1,6 +1,6 @@
-License for Scintilla and SciTE
+License for Lexilla, Scintilla, and SciTE
 
-Copyright 1998-2003 by Neil Hodgson <neilh at scintilla.org>
+Copyright 1998-2021 by Neil Hodgson <neilh at scintilla.org>
 
 All Rights Reserved
 


Modified: scintilla/Makefile.am
341 lines changed, 182 insertions(+), 159 deletions(-)
===================================================================
@@ -1,171 +1,194 @@
+noinst_LTLIBRARIES = libscintilla.la liblexilla.la
 
-SUBDIRS = include
+AM_CXXFLAGS = -DNDEBUG -DGTK -DSCI_LEXER -DNO_CXX11_REGEX -std=c++17
+AM_CPPFLAGS = @GTK_CFLAGS@ @LIBGEANY_CFLAGS@
 
-noinst_LTLIBRARIES=libscintilla.la
+scintilla_includedir = $(includedir)/geany/scintilla/
+scintilla_include_HEADERS =            \
+include/Scintilla.h                    \
+include/Scintilla.iface                \
+include/ScintillaWidget.h              \
+include/Sci_Position.h
 
-AM_CXXFLAGS = -DNDEBUG -DGTK -DSCI_LEXER -DNO_CXX11_REGEX
+LEXER_SRCS =                           \
+lexilla/lexers/LexAbaqus.cxx           \
+lexilla/lexers/LexAda.cxx              \
+lexilla/lexers/LexAsm.cxx              \
+lexilla/lexers/LexBash.cxx             \
+lexilla/lexers/LexBasic.cxx            \
+lexilla/lexers/LexBatch.cxx            \
+lexilla/lexers/LexCOBOL.cxx            \
+lexilla/lexers/LexCPP.cxx              \
+lexilla/lexers/LexCSS.cxx              \
+lexilla/lexers/LexCaml.cxx             \
+lexilla/lexers/LexCmake.cxx            \
+lexilla/lexers/LexCoffeeScript.cxx     \
+lexilla/lexers/LexD.cxx                \
+lexilla/lexers/LexDiff.cxx             \
+lexilla/lexers/LexErlang.cxx           \
+lexilla/lexers/LexForth.cxx            \
+lexilla/lexers/LexFortran.cxx          \
+lexilla/lexers/LexHTML.cxx             \
+lexilla/lexers/LexHaskell.cxx          \
+lexilla/lexers/LexJulia.cxx            \
+lexilla/lexers/LexLaTeX.cxx            \
+lexilla/lexers/LexLisp.cxx             \
+lexilla/lexers/LexLua.cxx              \
+lexilla/lexers/LexMake.cxx             \
+lexilla/lexers/LexMarkdown.cxx         \
+lexilla/lexers/LexMatlab.cxx           \
+lexilla/lexers/LexNsis.cxx             \
+lexilla/lexers/LexNull.cxx             \
+lexilla/lexers/LexPascal.cxx           \
+lexilla/lexers/LexPerl.cxx             \
+lexilla/lexers/LexPowerShell.cxx       \
+lexilla/lexers/LexProps.cxx            \
+lexilla/lexers/LexPython.cxx           \
+lexilla/lexers/LexPO.cxx               \
+lexilla/lexers/LexR.cxx                \
+lexilla/lexers/LexRuby.cxx             \
+lexilla/lexers/LexRust.cxx             \
+lexilla/lexers/LexSmalltalk.cxx        \
+lexilla/lexers/LexSQL.cxx              \
+lexilla/lexers/LexTCL.cxx              \
+lexilla/lexers/LexTxt2tags.cxx         \
+lexilla/lexers/LexVHDL.cxx             \
+lexilla/lexers/LexVerilog.cxx          \
+lexilla/lexers/LexYAML.cxx
 
-LEXER_SRCS= \
-lexers/LexAbaqus.cxx \
-lexers/LexAda.cxx \
-lexers/LexAsm.cxx \
-lexers/LexBash.cxx \
-lexers/LexBasic.cxx \
-lexers/LexBatch.cxx \
-lexers/LexCOBOL.cxx \
-lexers/LexCPP.cxx \
-lexers/LexCSS.cxx \
-lexers/LexCaml.cxx \
-lexers/LexCmake.cxx \
-lexers/LexCoffeeScript.cxx \
-lexers/LexD.cxx \
-lexers/LexDiff.cxx \
-lexers/LexErlang.cxx \
-lexers/LexForth.cxx \
-lexers/LexFortran.cxx \
-lexers/LexHTML.cxx \
-lexers/LexHaskell.cxx \
-lexers/LexJulia.cxx \
-lexers/LexLaTeX.cxx \
-lexers/LexLisp.cxx \
-lexers/LexLua.cxx \
-lexers/LexMake.cxx \
-lexers/LexMarkdown.cxx \
-lexers/LexMatlab.cxx \
-lexers/LexNsis.cxx \
-lexers/LexNull.cxx \
-lexers/LexPascal.cxx \
-lexers/LexPerl.cxx \
-lexers/LexPowerShell.cxx \
-lexers/LexProps.cxx \
-lexers/LexPython.cxx \
-lexers/LexPO.cxx \
-lexers/LexR.cxx \
-lexers/LexRuby.cxx \
-lexers/LexRust.cxx \
-lexers/LexSmalltalk.cxx \
-lexers/LexSQL.cxx \
-lexers/LexTCL.cxx \
-lexers/LexTxt2tags.cxx \
-lexers/LexVHDL.cxx \
-lexers/LexVerilog.cxx \
-lexers/LexYAML.cxx
+LEXLIB_SRCS =                          \
+lexilla/include/LexicalStyles.iface    \
+lexilla/include/Lexilla.h              \
+lexilla/include/SciLexer.h             \
+lexilla/lexlib/Accessor.cxx            \
+lexilla/lexlib/Accessor.h              \
+lexilla/lexlib/CatalogueModules.h      \
+lexilla/lexlib/CharacterCategory.cxx   \
+lexilla/lexlib/CharacterCategory.h     \
+lexilla/lexlib/CharacterSet.cxx        \
+lexilla/lexlib/CharacterSet.h          \
+lexilla/lexlib/DefaultLexer.cxx        \
+lexilla/lexlib/DefaultLexer.h          \
+lexilla/lexlib/LexAccessor.cxx         \
+lexilla/lexlib/LexAccessor.h           \
+lexilla/lexlib/LexerBase.cxx           \
+lexilla/lexlib/LexerBase.h             \
+lexilla/lexlib/LexerModule.cxx         \
+lexilla/lexlib/LexerModule.h           \
+lexilla/lexlib/LexerNoExceptions.cxx   \
+lexilla/lexlib/LexerNoExceptions.h     \
+lexilla/lexlib/LexerSimple.cxx         \
+lexilla/lexlib/LexerSimple.h           \
+lexilla/lexlib/OptionSet.h             \
+lexilla/lexlib/PropSetSimple.cxx       \
+lexilla/lexlib/PropSetSimple.h         \
+lexilla/lexlib/SparseState.h           \
+lexilla/lexlib/StringCopy.h            \
+lexilla/lexlib/StyleContext.cxx        \
+lexilla/lexlib/StyleContext.h          \
+lexilla/lexlib/SubStyles.h             \
+lexilla/lexlib/WordList.cxx            \
+lexilla/lexlib/WordList.h              \
+lexilla/src/Lexilla.cxx
 
-SRCS= \
-gtk/Converter.h \
-gtk/PlatGTK.cxx \
-gtk/ScintillaGTK.cxx \
-gtk/ScintillaGTK.h \
-gtk/ScintillaGTKAccessible.cxx \
-gtk/ScintillaGTKAccessible.h \
-gtk/scintilla-marshal.c \
-gtk/scintilla-marshal.h \
-lexlib/Accessor.cxx \
-lexlib/Accessor.h \
-lexlib/CatalogueModules.h \
-lexlib/CharacterCategory.cxx \
-lexlib/CharacterCategory.h \
-lexlib/CharacterSet.cxx \
-lexlib/CharacterSet.h \
-lexlib/DefaultLexer.cxx \
-lexlib/DefaultLexer.h \
-lexlib/LexAccessor.h \
-lexlib/LexerBase.cxx \
-lexlib/LexerBase.h \
-lexlib/LexerModule.cxx \
-lexlib/LexerModule.h \
-lexlib/LexerNoExceptions.cxx \
-lexlib/LexerNoExceptions.h \
-lexlib/LexerSimple.cxx \
-lexlib/LexerSimple.h \
-lexlib/OptionSet.h \
-lexlib/PropSetSimple.cxx \
-lexlib/PropSetSimple.h \
-lexlib/SparseState.h \
-lexlib/StringCopy.h \
-lexlib/StyleContext.cxx \
-lexlib/StyleContext.h \
-lexlib/SubStyles.h \
-lexlib/WordList.cxx \
-lexlib/WordList.h \
-src/AutoComplete.cxx \
-src/AutoComplete.h \
-src/CallTip.cxx \
-src/CallTip.h \
-src/CaseConvert.cxx \
-src/CaseConvert.h \
-src/CaseFolder.cxx \
-src/CaseFolder.h \
-src/Catalogue.cxx \
-src/Catalogue.h \
-src/CellBuffer.cxx \
-src/CellBuffer.h \
-src/CharClassify.cxx \
-src/CharClassify.h \
-src/ContractionState.cxx \
-src/ContractionState.h \
-src/DBCS.cxx \
-src/DBCS.h \
-src/Decoration.cxx \
-src/Decoration.h \
-src/Document.cxx \
-src/Document.h \
-src/Editor.cxx \
-src/Editor.h \
-src/EditModel.cxx \
-src/EditModel.h \
-src/EditView.cxx \
-src/EditView.h \
-src/ElapsedPeriod.h \
-src/ExternalLexer.cxx \
-src/ExternalLexer.h \
-src/FontQuality.h \
-src/Indicator.cxx \
-src/Indicator.h \
-src/IntegerRectangle.h \
-src/KeyMap.cxx \
-src/KeyMap.h \
-src/LineMarker.cxx \
-src/LineMarker.h \
-src/MarginView.cxx \
-src/MarginView.h \
-src/Partitioning.h \
-src/PerLine.cxx \
-src/PerLine.h \
-src/Position.h \
-src/PositionCache.cxx \
-src/PositionCache.h \
-src/RESearch.cxx \
-src/RESearch.h \
-src/RunStyles.cxx \
-src/RunStyles.h \
-src/SVector.h \
-src/ScintillaBase.cxx \
-src/ScintillaBase.h \
-src/Selection.cxx \
-src/Selection.h \
-src/SparseVector.h \
-src/SplitVector.h \
-src/Style.cxx \
-src/Style.h \
-src/UniConversion.cxx \
-src/UniConversion.h \
-src/UnicodeFromUTF8.h \
-src/UniqueString.cxx \
-src/UniqueString.h \
-src/ViewStyle.cxx \
-src/ViewStyle.h \
-src/XPM.cxx \
-src/XPM.h \
-$(LEXER_SRCS)
+SRCS =                                 \
+include/ILexer.h                       \
+include/ILoader.h                      \
+include/ScintillaCall.h                \
+include/ScintillaMessages.h            \
+include/ScintillaStructures.h          \
+include/ScintillaTypes.h               \
+include/ScintillaWidget.h              \
+gtk/Converter.h                        \
+gtk/PlatGTK.cxx                        \
+gtk/ScintillaGTK.cxx                   \
+gtk/ScintillaGTK.h                     \
+gtk/ScintillaGTKAccessible.cxx         \
+gtk/ScintillaGTKAccessible.h           \
+gtk/scintilla-marshal.c                \
+gtk/scintilla-marshal.h                \
+src/AutoComplete.cxx                   \
+src/AutoComplete.h                     \
+src/CallTip.cxx                        \
+src/CallTip.h                          \
+src/CaseConvert.cxx                    \
+src/CaseConvert.h                      \
+src/CaseFolder.cxx                     \
+src/CaseFolder.h                       \
+src/CellBuffer.cxx                     \
+src/CellBuffer.h                       \
+src/CharacterCategoryMap.cxx           \
+src/CharacterCategoryMap.h             \
+src/CharacterType.cxx                  \
+src/CharacterType.h                    \
+src/CharClassify.cxx                   \
+src/CharClassify.h                     \
+src/ContractionState.cxx               \
+src/ContractionState.h                 \
+src/DBCS.cxx                           \
+src/DBCS.h                             \
+src/Debugging.h                        \
+src/Decoration.cxx                     \
+src/Decoration.h                       \
+src/Document.cxx                       \
+src/Document.h                         \
+src/EditModel.cxx                      \
+src/EditModel.h                        \
+src/Editor.cxx                         \
+src/Editor.h                           \
+src/EditView.cxx                       \
+src/EditView.h                         \
+src/ElapsedPeriod.h                    \
+src/FontQuality.h                      \
+src/Geometry.cxx                       \
+src/Geometry.h                         \
+src/Indicator.cxx                      \
+src/Indicator.h                        \
+src/KeyMap.cxx                         \
+src/KeyMap.h                           \
+src/LineMarker.cxx                     \
+src/LineMarker.h                       \
+src/MarginView.cxx                     \
+src/MarginView.h                       \
+src/Partitioning.h                     \
+src/PerLine.cxx                        \
+src/PerLine.h                          \
+src/Platform.h                         \
+src/PositionCache.cxx                  \
+src/PositionCache.h                    \
+src/Position.h                         \
+src/RESearch.cxx                       \
+src/RESearch.h                         \
+src/RunStyles.cxx                      \
+src/RunStyles.h                        \
+src/ScintillaBase.cxx                  \
+src/ScintillaBase.h                    \
+src/Selection.cxx                      \
+src/Selection.h                        \
+src/SparseVector.h                     \
+src/SplitVector.h                      \
+src/Style.cxx                          \
+src/Style.h                            \
+src/UniConversion.cxx                  \
+src/UniConversion.h                    \
+src/UniqueString.cxx                   \
+src/UniqueString.h                     \
+src/ViewStyle.cxx                      \
+src/ViewStyle.h                        \
+src/XPM.cxx                            \
+src/XPM.h
 
-libscintilla_la_SOURCES = $(SRCS)
+liblexilla_la_CPPFLAGS = $(AM_CPPFLAGS)
+liblexilla_la_CPPFLAGS += -I$(srcdir)/lexilla/include -I$(srcdir)/lexilla/lexlib -I$(srcdir)/include
+liblexilla_la_SOURCES = $(LEXLIB_SRCS) $(LEXER_SRCS)
 
-AM_CPPFLAGS = -I$(top_srcdir) -I$(srcdir)/include -I$(srcdir)/src -I$(srcdir)/lexlib \
-	@GTK_CFLAGS@ @LIBGEANY_CFLAGS@
+libscintilla_la_CPPFLAGS = $(AM_CPPFLAGS)
+libscintilla_la_CPPFLAGS += -I$(srcdir)/src -I$(srcdir)/include -I$(srcdir)/lexilla/include
+libscintilla_la_SOURCES = $(SRCS)
 
 marshallers: gtk/scintilla-marshal.list
 	glib-genmarshal --prefix scintilla_marshal gtk/scintilla-marshal.list --header > gtk/scintilla-marshal.h
 	glib-genmarshal --prefix scintilla_marshal gtk/scintilla-marshal.list --body > gtk/scintilla-marshal.c
 
-EXTRA_DIST=gtk/scintilla-marshal.list License.txt README version.txt
+EXTRA_DIST = gtk/scintilla-marshal.list License.txt README version.txt
+EXTRA_DIST += lexilla/License.txt lexilla/version.txt


Modified: scintilla/gtk/PlatGTK.cxx
1211 lines changed, 667 insertions(+), 544 deletions(-)
===================================================================
@@ -10,8 +10,10 @@
 #include <cmath>
 
 #include <string>
+#include <string_view>
 #include <vector>
 #include <map>
+#include <optional>
 #include <algorithm>
 #include <memory>
 #include <sstream>
@@ -22,12 +24,15 @@
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
 
+#include "ScintillaTypes.h"
+#include "ScintillaMessages.h"
+
+#include "Debugging.h"
+#include "Geometry.h"
 #include "Platform.h"
 
 #include "Scintilla.h"
 #include "ScintillaWidget.h"
-#include "StringCopy.h"
-#include "IntegerRectangle.h"
 #include "XPM.h"
 #include "UniConversion.h"
 
@@ -39,11 +44,14 @@
 #endif
 
 using namespace Scintilla;
+using namespace Scintilla::Internal;
 
 namespace {
 
 constexpr double kPi = 3.14159265358979323846;
 
+constexpr double degrees = kPi / 180.0;
+
 // The Pango version guard for pango_units_from_double and pango_units_to_double
 // is more complex than simply implementing these here.
 
@@ -55,9 +63,19 @@ constexpr float floatFromPangoUnits(int pu) noexcept {
 	return static_cast<float>(pu) / PANGO_SCALE;
 }
 
-cairo_surface_t *CreateSimilarSurface(GdkWindow *window, cairo_content_t content, int width, int height) noexcept {
-	return gdk_window_create_similar_surface(window, content, width, height);
-}
+struct IntegerRectangle {
+	int left;
+	int top;
+	int right;
+	int bottom;
+
+	explicit IntegerRectangle(PRectangle rc) noexcept :
+		left(static_cast<int>(rc.left)), top(static_cast<int>(rc.top)),
+		right(static_cast<int>(rc.right)), bottom(static_cast<int>(rc.bottom)) {
+	}
+	int Width() const noexcept { return right - left; }
+	int Height() const noexcept { return bottom - top; }
+};
 
 GdkWindow *WindowFromWidget(GtkWidget *w) noexcept {
 	return gtk_widget_get_window(w);
@@ -67,19 +85,30 @@ GtkWidget *PWidget(WindowID wid) noexcept {
 	return static_cast<GtkWidget *>(wid);
 }
 
-enum encodingType { singleByte, UTF8, dbcs };
+enum class EncodingType { singleByte, utf8, dbcs };
 
 // Holds a PangoFontDescription*.
-class FontHandle {
+class FontHandle : public Font {
 public:
-	PangoFontDescription *pfd;
-	int characterSet;
-	FontHandle() noexcept : pfd(nullptr), characterSet(-1) {
+	PangoFontDescription *pfd = nullptr;
+	CharacterSet characterSet;
+	FontHandle() noexcept : pfd(nullptr), characterSet(CharacterSet::Ansi) {
 	}
-	FontHandle(PangoFontDescription *pfd_, int characterSet_) noexcept {
+	FontHandle(PangoFontDescription *pfd_, CharacterSet characterSet_) noexcept {
 		pfd = pfd_;
 		characterSet = characterSet_;
 	}
+	FontHandle(const FontParameters &fp) {
+		pfd = pango_font_description_new();
+		if (pfd) {
+			pango_font_description_set_family(pfd,
+				(fp.faceName[0] == '!') ? fp.faceName + 1 : fp.faceName);
+			pango_font_description_set_size(pfd, pangoUnitsFromDouble(fp.size));
+			pango_font_description_set_weight(pfd, static_cast<PangoWeight>(fp.weight));
+			pango_font_description_set_style(pfd, fp.italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL);
+		}
+		characterSet = fp.characterSet;
+	}
 	// Deleted so FontHandle objects can not be copied.
 	FontHandle(const FontHandle &) = delete;
 	FontHandle(FontHandle &&) = delete;
@@ -90,66 +119,43 @@ class FontHandle {
 			pango_font_description_free(pfd);
 		pfd = nullptr;
 	}
-	static FontHandle *CreateNewFont(const FontParameters &fp);
 };
 
-FontHandle *FontHandle::CreateNewFont(const FontParameters &fp) {
-	PangoFontDescription *pfd = pango_font_description_new();
-	if (pfd) {
-		pango_font_description_set_family(pfd,
-			(fp.faceName[0] == '!') ? fp.faceName+1 : fp.faceName);
-		pango_font_description_set_size(pfd, pangoUnitsFromDouble(fp.size));
-		pango_font_description_set_weight(pfd, static_cast<PangoWeight>(fp.weight));
-		pango_font_description_set_style(pfd, fp.italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL);
-		return new FontHandle(pfd, fp.characterSet);
-	}
-
-	return nullptr;
-}
-
 // X has a 16 bit coordinate space, so stop drawing here to avoid wrapping
 constexpr int maxCoordinate = 32000;
 
-FontHandle *PFont(const Font &f) noexcept {
-	return static_cast<FontHandle *>(f.GetID());
+const FontHandle *PFont(const Font *f) noexcept {
+	return dynamic_cast<const FontHandle *>(f);
 }
 
 }
 
-Font::Font() noexcept : fid(nullptr) {}
-
-Font::~Font() {}
-
-void Font::Create(const FontParameters &fp) {
-	Release();
-	fid = FontHandle::CreateNewFont(fp);
-}
-
-void Font::Release() {
-	if (fid)
-		delete static_cast<FontHandle *>(fid);
-	fid = nullptr;
+std::shared_ptr<Font> Font::Allocate(const FontParameters &fp) {
+	return std::make_shared<FontHandle>(fp);
 }
 
 // Required on OS X
 namespace Scintilla {
 
 // SurfaceID is a cairo_t*
 class SurfaceImpl : public Surface {
-	encodingType et;
-	cairo_t *context;
-	cairo_surface_t *psurf;
-	int x;
-	int y;
-	bool inited;
-	bool createdGC;
-	PangoContext *pcontext;
-	PangoLayout *layout;
+	SurfaceMode mode;
+	EncodingType et= EncodingType::singleByte;
+	WindowID widSave = nullptr;
+	cairo_t *context = nullptr;
+	cairo_surface_t *psurf = nullptr;
+	bool inited = false;
+	bool createdGC = false;
+	PangoContext *pcontext = nullptr;
+	PangoLayout *layout = nullptr;
 	Converter conv;
-	int characterSet;
-	void SetConverter(int characterSet_);
+	CharacterSet characterSet = static_cast<CharacterSet>(-1);
+	void PenColourAlpha(ColourRGBA fore) noexcept;
+	void SetConverter(CharacterSet characterSet_);
+	void CairoRectangle(PRectangle rc) noexcept;
 public:
 	SurfaceImpl() noexcept;
+	SurfaceImpl(cairo_t *context_, int width, int height, SurfaceMode mode_, WindowID wid) noexcept;
 	// Deleted so SurfaceImpl objects can not be copied.
 	SurfaceImpl(const SurfaceImpl&) = delete;
 	SurfaceImpl(SurfaceImpl&&) = delete;
@@ -159,119 +165,172 @@ class SurfaceImpl : public Surface {
 
 	void Init(WindowID wid) override;
 	void Init(SurfaceID sid, WindowID wid) override;
-	void InitPixMap(int width, int height, Surface *surface_, WindowID wid) override;
+	std::unique_ptr<Surface> AllocatePixMap(int width, int height) override;
+
+	void SetMode(SurfaceMode mode_) override;
 
 	void Clear() noexcept;
-	void Release() override;
+	void Release() noexcept override;
+	int SupportsFeature(Supports feature) noexcept override;
 	bool Initialised() override;
-	void PenColour(ColourDesired fore) override;
 	int LogPixelsY() override;
+	int PixelDivisions() override;
 	int DeviceHeightFont(int points) override;
-	void MoveTo(int x_, int y_) override;
-	void LineTo(int x_, int y_) override;
-	void Polygon(Point *pts, size_t npts, ColourDesired fore, ColourDesired back) override;
-	void RectangleDraw(PRectangle rc, ColourDesired fore, ColourDesired back) override;
-	void FillRectangle(PRectangle rc, ColourDesired back) override;
+	void LineDraw(Point start, Point end, Stroke stroke) override;
+	void PolyLine(const Point *pts, size_t npts, Stroke stroke) override;
+	void Polygon(const Point *pts, size_t npts, FillStroke fillStroke) override;
+	void RectangleDraw(PRectangle rc, FillStroke fillStroke) override;
+	void RectangleFrame(PRectangle rc, Stroke stroke) override;
+	void FillRectangle(PRectangle rc, Fill fill) override;
+	void FillRectangleAligned(PRectangle rc, Fill fill) override;
 	void FillRectangle(PRectangle rc, Surface &surfacePattern) override;
-	void RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesired back) override;
-	void AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill,
-		ColourDesired outline, int alphaOutline, int flags) override;
+	void RoundedRectangle(PRectangle rc, FillStroke fillStroke) override;
+	void AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke) override;
 	void GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions options) override;
 	void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) override;
-	void Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back) override;
+	void Ellipse(PRectangle rc, FillStroke fillStroke) override;
+	void Stadium(PRectangle rc, FillStroke fillStroke, Ends ends) override;
 	void Copy(PRectangle rc, Point from, Surface &surfaceSource) override;
 
-	void DrawTextBase(PRectangle rc, const Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore);
-	void DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back) override;
-	void DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back) override;
-	void DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore) override;
-	void MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions) override;
-	XYPOSITION WidthText(Font &font_, const char *s, int len) override;
-	XYPOSITION Ascent(Font &font_) override;
-	XYPOSITION Descent(Font &font_) override;
-	XYPOSITION InternalLeading(Font &font_) override;
-	XYPOSITION Height(Font &font_) override;
-	XYPOSITION AverageCharWidth(Font &font_) override;
+	std::unique_ptr<IScreenLineLayout> Layout(const IScreenLine *screenLine) override;
+
+	void DrawTextBase(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourRGBA fore);
+	void DrawTextNoClip(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourRGBA fore, ColourRGBA back) override;
+	void DrawTextClipped(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourRGBA fore, ColourRGBA back) override;
+	void DrawTextTransparent(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourRGBA fore) override;
+	void MeasureWidths(const Font *font_, std::string_view text, XYPOSITION *positions) override;
+	XYPOSITION WidthText(const Font *font_, std::string_view text) override;
+
+	void DrawTextBaseUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourRGBA fore);
+	void DrawTextNoClipUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourRGBA fore, ColourRGBA back) override;
+	void DrawTextClippedUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourRGBA fore, ColourRGBA back) override;
+	void DrawTextTransparentUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourRGBA fore) override;
+	void MeasureWidthsUTF8(const Font *font_, std::string_view text, XYPOSITION *positions) override;
+	XYPOSITION WidthTextUTF8(const Font *font_, std::string_view text) override;
+
+	XYPOSITION Ascent(const Font *font_) override;
+	XYPOSITION Descent(const Font *font_) override;
+	XYPOSITION InternalLeading(const Font *font_) override;
+	XYPOSITION Height(const Font *font_) override;
+	XYPOSITION AverageCharWidth(const Font *font_) override;
 
 	void SetClip(PRectangle rc) override;
+	void PopClip() override;
 	void FlushCachedState() override;
+	void FlushDrawing() override;
+};
 
-	void SetUnicodeMode(bool unicodeMode_) override;
-	void SetDBCSMode(int codePage) override;
+const Supports SupportsGTK[] = {
+	Supports::LineDrawsFinal,
+	Supports::FractionalStrokeWidth,
+	Supports::TranslucentStroke,
+	Supports::PixelModification,
 };
+
 }
 
-const char *CharacterSetID(int characterSet) noexcept {
+const char *CharacterSetID(CharacterSet characterSet) noexcept {
 	switch (characterSet) {
-	case SC_CHARSET_ANSI:
+	case CharacterSet::Ansi:
 		return "";
-	case SC_CHARSET_DEFAULT:
+	case CharacterSet::Default:
 		return "ISO-8859-1";
-	case SC_CHARSET_BALTIC:
+	case CharacterSet::Baltic:
 		return "ISO-8859-13";
-	case SC_CHARSET_CHINESEBIG5:
+	case CharacterSet::ChineseBig5:
 		return "BIG-5";
-	case SC_CHARSET_EASTEUROPE:
+	case CharacterSet::EastEurope:
 		return "ISO-8859-2";
-	case SC_CHARSET_GB2312:
+	case CharacterSet::GB2312:
 		return "CP936";
-	case SC_CHARSET_GREEK:
+	case CharacterSet::Greek:
 		return "ISO-8859-7";
-	case SC_CHARSET_HANGUL:
+	case CharacterSet::Hangul:
 		return "CP949";
-	case SC_CHARSET_MAC:
+	case CharacterSet::Mac:
 		return "MACINTOSH";
-	case SC_CHARSET_OEM:
+	case CharacterSet::Oem:
 		return "ASCII";
-	case SC_CHARSET_RUSSIAN:
+	case CharacterSet::Russian:
 		return "KOI8-R";
-	case SC_CHARSET_OEM866:
+	case CharacterSet::Oem866:
 		return "CP866";
-	case SC_CHARSET_CYRILLIC:
+	case CharacterSet::Cyrillic:
 		return "CP1251";
-	case SC_CHARSET_SHIFTJIS:
+	case CharacterSet::ShiftJis:
 		return "SHIFT-JIS";
-	case SC_CHARSET_SYMBOL:
+	case CharacterSet::Symbol:
 		return "";
-	case SC_CHARSET_TURKISH:
+	case CharacterSet::Turkish:
 		return "ISO-8859-9";
-	case SC_CHARSET_JOHAB:
+	case CharacterSet::Johab:
 		return "CP1361";
-	case SC_CHARSET_HEBREW:
+	case CharacterSet::Hebrew:
 		return "ISO-8859-8";
-	case SC_CHARSET_ARABIC:
+	case CharacterSet::Arabic:
 		return "ISO-8859-6";
-	case SC_CHARSET_VIETNAMESE:
+	case CharacterSet::Vietnamese:
 		return "";
-	case SC_CHARSET_THAI:
+	case CharacterSet::Thai:
 		return "ISO-8859-11";
-	case SC_CHARSET_8859_15:
+	case CharacterSet::Iso8859_15:
 		return "ISO-8859-15";
 	default:
 		return "";
 	}
 }
 
-void SurfaceImpl::SetConverter(int characterSet_) {
+void SurfaceImpl::PenColourAlpha(ColourRGBA fore) noexcept {
+	if (context) {
+		cairo_set_source_rgba(context,
+			fore.GetRedComponent(),
+			fore.GetGreenComponent(),
+			fore.GetBlueComponent(),
+			fore.GetAlphaComponent());
+	}
+}
+
+void SurfaceImpl::SetConverter(CharacterSet characterSet_) {
 	if (characterSet != characterSet_) {
 		characterSet = characterSet_;
 		conv.Open("UTF-8", CharacterSetID(characterSet), false);
 	}
 }
 
-SurfaceImpl::SurfaceImpl() noexcept : et(singleByte),
-context(nullptr),
-psurf(nullptr),
-x(0), y(0), inited(false), createdGC(false),
-pcontext(nullptr), layout(nullptr), characterSet(-1) {
+void SurfaceImpl::CairoRectangle(PRectangle rc) noexcept {
+	cairo_rectangle(context, rc.left, rc.top, rc.Width(), rc.Height());
+}
+
+SurfaceImpl::SurfaceImpl() noexcept {
+}
+
+SurfaceImpl::SurfaceImpl(cairo_t *context_, int width, int height, SurfaceMode mode_, WindowID wid) noexcept {
+	if (height > 0 && width > 0) {
+		cairo_surface_t *psurfContext = cairo_get_target(context_);
+		psurf = cairo_surface_create_similar(
+			psurfContext,
+			CAIRO_CONTENT_COLOR_ALPHA, width, height);
+		context = cairo_create(psurf);
+		pcontext = gtk_widget_create_pango_context(PWidget(wid));
+		PLATFORM_ASSERT(pcontext);
+		layout = pango_layout_new(pcontext);
+		PLATFORM_ASSERT(layout);
+		cairo_rectangle(context, 0, 0, width, height);
+		cairo_set_source_rgb(context, 1.0, 0, 0);
+		cairo_fill(context);
+		cairo_set_line_width(context, 1);
+		createdGC = true;
+		inited = true;
+		mode = mode_;
+	}
 }
 
 SurfaceImpl::~SurfaceImpl() {
 	Clear();
 }
 
 void SurfaceImpl::Clear() noexcept {
-	et = singleByte;
+	et = EncodingType::singleByte;
 	if (createdGC) {
 		createdGC = false;
 		cairo_destroy(context);
@@ -287,14 +346,12 @@ void SurfaceImpl::Clear() noexcept {
 		g_object_unref(pcontext);
 	pcontext = nullptr;
 	conv.Close();
-	characterSet = -1;
-	x = 0;
-	y = 0;
+	characterSet = static_cast<CharacterSet>(-1);
 	inited = false;
 	createdGC = false;
 }
 
-void SurfaceImpl::Release() {
+void SurfaceImpl::Release() noexcept {
 	Clear();
 }
 
@@ -319,6 +376,7 @@ bool SurfaceImpl::Initialised() {
 }
 
 void SurfaceImpl::Init(WindowID wid) {
+	widSave = wid;
 	Release();
 	PLATFORM_ASSERT(wid);
 	// if we are only created from a window ID, we can't perform drawing
@@ -333,6 +391,7 @@ void SurfaceImpl::Init(WindowID wid) {
 }
 
 void SurfaceImpl::Init(SurfaceID sid, WindowID wid) {
+	widSave = wid;
 	PLATFORM_ASSERT(sid);
 	Release();
 	PLATFORM_ASSERT(wid);
@@ -346,137 +405,115 @@ void SurfaceImpl::Init(SurfaceID sid, WindowID wid) {
 	inited = true;
 }
 
-void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_, WindowID wid) {
-	PLATFORM_ASSERT(surface_);
-	Release();
-	SurfaceImpl *surfImpl = dynamic_cast<SurfaceImpl *>(surface_);
-	PLATFORM_ASSERT(surfImpl);
-	PLATFORM_ASSERT(wid);
-	context = cairo_reference(surfImpl->context);
-	pcontext = gtk_widget_create_pango_context(PWidget(wid));
-	// update the Pango context in case surface_ isn't the widget's surface
-	pango_cairo_update_context(context, pcontext);
-	PLATFORM_ASSERT(pcontext);
-	layout = pango_layout_new(pcontext);
-	PLATFORM_ASSERT(layout);
-	if (height > 0 && width > 0)
-		psurf = CreateSimilarSurface(
-			WindowFromWidget(PWidget(wid)),
-			CAIRO_CONTENT_COLOR_ALPHA, width, height);
-	cairo_destroy(context);
-	context = cairo_create(psurf);
-	cairo_rectangle(context, 0, 0, width, height);
-	cairo_set_source_rgb(context, 1.0, 0, 0);
-	cairo_fill(context);
-	// This produces sharp drawing more similar to GDK:
-	//cairo_set_antialias(context, CAIRO_ANTIALIAS_NONE);
-	cairo_set_line_width(context, 1);
-	createdGC = true;
-	inited = true;
-	et = surfImpl->et;
+std::unique_ptr<Surface> SurfaceImpl::AllocatePixMap(int width, int height) {
+	// widSave must be alive now so safe for creating a PangoContext
+	return std::make_unique<SurfaceImpl>(context, width, height, mode, widSave);
 }
 
-void SurfaceImpl::PenColour(ColourDesired fore) {
-	if (context) {
-		const ColourDesired cdFore(fore.AsInteger());
-		cairo_set_source_rgb(context,
-			cdFore.GetRed() / 255.0,
-			cdFore.GetGreen() / 255.0,
-			cdFore.GetBlue() / 255.0);
+void SurfaceImpl::SetMode(SurfaceMode mode_) {
+	mode = mode_;
+	if (mode.codePage == SC_CP_UTF8) {
+		et = EncodingType::utf8;
+	} else if (mode.codePage) {
+		et = EncodingType::dbcs;
+	} else {
+		et = EncodingType::singleByte;
+	}
+}
+
+int SurfaceImpl::SupportsFeature(Supports feature) noexcept {
+	for (const Supports f : SupportsGTK) {
+		if (f == feature)
+			return 1;
 	}
+	return 0;
 }
 
 int SurfaceImpl::LogPixelsY() {
 	return 72;
 }
 
+int SurfaceImpl::PixelDivisions() {
+	// GTK uses device pixels.
+	return 1;
+}
+
 int SurfaceImpl::DeviceHeightFont(int points) {
 	const int logPix = LogPixelsY();
 	return (points * logPix + logPix / 2) / 72;
 }
 
-void SurfaceImpl::MoveTo(int x_, int y_) {
-	x = x_;
-	y = y_;
-}
-
-static int Delta(int difference) noexcept {
-	if (difference < 0)
-		return -1;
-	else if (difference > 0)
-		return 1;
-	else
-		return 0;
+void SurfaceImpl::LineDraw(Point start, Point end, Stroke stroke) {
+	PLATFORM_ASSERT(context);
+	if (!context)
+		return;
+	PenColourAlpha(stroke.colour);
+	cairo_set_line_width(context, stroke.width);
+	cairo_move_to(context, start.x, start.y);
+	cairo_line_to(context, end.x, end.y);
+	cairo_stroke(context);
 }
 
-void SurfaceImpl::LineTo(int x_, int y_) {
-	// cairo_line_to draws the end position, unlike Win32 or GDK with GDK_CAP_NOT_LAST.
-	// For simple cases, move back one pixel from end.
-	if (context) {
-		const int xDiff = x_ - x;
-		const int xDelta = Delta(xDiff);
-		const int yDiff = y_ - y;
-		const int yDelta = Delta(yDiff);
-		if ((xDiff == 0) || (yDiff == 0)) {
-			// Horizontal or vertical lines can be more precisely drawn as a filled rectangle
-			const int xEnd = x_ - xDelta;
-			const int left = std::min(x, xEnd);
-			const int width = std::abs(x - xEnd) + 1;
-			const int yEnd = y_ - yDelta;
-			const int top = std::min(y, yEnd);
-			const int height = std::abs(y - yEnd) + 1;
-			cairo_rectangle(context, left, top, width, height);
-			cairo_fill(context);
-		} else if ((std::abs(xDiff) == std::abs(yDiff))) {
-			// 45 degree slope
-			cairo_move_to(context, x + 0.5, y + 0.5);
-			cairo_line_to(context, x_ + 0.5 - xDelta, y_ + 0.5 - yDelta);
-		} else {
-			// Line has a different slope so difficult to avoid last pixel
-			cairo_move_to(context, x + 0.5, y + 0.5);
-			cairo_line_to(context, x_ + 0.5, y_ + 0.5);
-		}
-		cairo_stroke(context);
+void SurfaceImpl::PolyLine(const Point *pts, size_t npts, Stroke stroke) {
+	// TODO: set line joins and caps
+	PLATFORM_ASSERT(context && npts > 1);
+	if (!context)
+		return;
+	PenColourAlpha(stroke.colour);
+	cairo_set_line_width(context, stroke.width);
+	cairo_move_to(context, pts[0].x, pts[0].y);
+	for (size_t i = 1; i < npts; i++) {
+		cairo_line_to(context, pts[i].x, pts[i].y);
 	}
-	x = x_;
-	y = y_;
+	cairo_stroke(context);
 }
 
-void SurfaceImpl::Polygon(Point *pts, size_t npts, ColourDesired fore,
-                          ColourDesired back) {
+void SurfaceImpl::Polygon(const Point *pts, size_t npts, FillStroke fillStroke) {
 	PLATFORM_ASSERT(context);
-	PenColour(back);
-	cairo_move_to(context, pts[0].x + 0.5, pts[0].y + 0.5);
+	PenColourAlpha(fillStroke.fill.colour);
+	cairo_move_to(context, pts[0].x, pts[0].y);
 	for (size_t i = 1; i < npts; i++) {
-		cairo_line_to(context, pts[i].x + 0.5, pts[i].y + 0.5);
+		cairo_line_to(context, pts[i].x, pts[i].y);
 	}
 	cairo_close_path(context);
 	cairo_fill_preserve(context);
-	PenColour(fore);
+	PenColourAlpha(fillStroke.stroke.colour);
+	cairo_set_line_width(context, fillStroke.stroke.width);
 	cairo_stroke(context);
 }
 
-void SurfaceImpl::RectangleDraw(PRectangle rc, ColourDesired fore, ColourDesired back) {
+void SurfaceImpl::RectangleDraw(PRectangle rc, FillStroke fillStroke) {
 	if (context) {
-		cairo_rectangle(context, rc.left + 0.5, rc.top + 0.5,
-				rc.Width() - 1, rc.Height() - 1);
-		PenColour(back);
+		CairoRectangle(rc.Inset(fillStroke.stroke.width / 2));
+		PenColourAlpha(fillStroke.fill.colour);
 		cairo_fill_preserve(context);
-		PenColour(fore);
+		PenColourAlpha(fillStroke.stroke.colour);
+		cairo_set_line_width(context, fillStroke.stroke.width);
+		cairo_stroke(context);
+	}
+}
+
+void SurfaceImpl::RectangleFrame(PRectangle rc, Stroke stroke) {
+	if (context) {
+		CairoRectangle(rc.Inset(stroke.width / 2));
+		PenColourAlpha(stroke.colour);
+		cairo_set_line_width(context, stroke.width);
 		cairo_stroke(context);
 	}
 }
 
-void SurfaceImpl::FillRectangle(PRectangle rc, ColourDesired back) {
-	PenColour(back);
+void SurfaceImpl::FillRectangle(PRectangle rc, Fill fill) {
+	PenColourAlpha(fill.colour);
 	if (context && (rc.left < maxCoordinate)) {	// Protect against out of range
-		rc.left = Sci::round(rc.left);
-		rc.right = Sci::round(rc.right);
-		cairo_rectangle(context, rc.left, rc.top, rc.Width(), rc.Height());
+		CairoRectangle(rc);
 		cairo_fill(context);
 	}
 }
 
+void SurfaceImpl::FillRectangleAligned(PRectangle rc, Fill fill) {
+	FillRectangle(PixelAlign(rc, 1), fill);
+}
+
 void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) {
 	SurfaceImpl &surfi = dynamic_cast<SurfaceImpl &>(surfacePattern);
 	if (context && surfi.psurf) {
@@ -488,28 +525,26 @@ void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) {
 	}
 }
 
-void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesired back) {
+void SurfaceImpl::RoundedRectangle(PRectangle rc, FillStroke fillStroke) {
 	if (((rc.right - rc.left) > 4) && ((rc.bottom - rc.top) > 4)) {
 		// Approximate a round rect with some cut off corners
 		Point pts[] = {
-		                  Point(rc.left + 2, rc.top),
-		                  Point(rc.right - 2, rc.top),
-		                  Point(rc.right, rc.top + 2),
-		                  Point(rc.right, rc.bottom - 2),
-		                  Point(rc.right - 2, rc.bottom),
-		                  Point(rc.left + 2, rc.bottom),
-		                  Point(rc.left, rc.bottom - 2),
-		                  Point(rc.left, rc.top + 2),
-		              };
-		Polygon(pts, Sci::size(pts), fore, back);
+			Point(rc.left + 2, rc.top),
+			Point(rc.right - 2, rc.top),
+			Point(rc.right, rc.top + 2),
+			Point(rc.right, rc.bottom - 2),
+			Point(rc.right - 2, rc.bottom),
+			Point(rc.left + 2, rc.bottom),
+			Point(rc.left, rc.bottom - 2),
+			Point(rc.left, rc.top + 2),
+		};
+		Polygon(pts, std::size(pts), fillStroke);
 	} else {
-		RectangleDraw(rc, fore, back);
+		RectangleDraw(rc, fillStroke);
 	}
 }
 
 static void PathRoundRectangle(cairo_t *context, double left, double top, double width, double height, double radius) noexcept {
-	constexpr double degrees = kPi / 180.0;
-
 	cairo_new_sub_path(context);
 	cairo_arc(context, left + width - radius, top + radius, radius, -90 * degrees, 0 * degrees);
 	cairo_arc(context, left + width - radius, top + height - radius, radius, 0 * degrees, 90 * degrees);
@@ -518,31 +553,27 @@ static void PathRoundRectangle(cairo_t *context, double left, double top, double
 	cairo_close_path(context);
 }
 
-void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill,
-		ColourDesired outline, int alphaOutline, int /*flags*/) {
+void SurfaceImpl::AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke) {
 	if (context && rc.Width() > 0) {
-		const ColourDesired cdFill(fill.AsInteger());
-		cairo_set_source_rgba(context,
-			cdFill.GetRed() / 255.0,
-			cdFill.GetGreen() / 255.0,
-			cdFill.GetBlue() / 255.0,
-			alphaFill / 255.0);
+		const float halfStroke = fillStroke.stroke.width / 2.0f;
+		const float doubleStroke = fillStroke.stroke.width * 2.0f;
+		PenColourAlpha(fillStroke.fill.colour);
 		if (cornerSize > 0)
-			PathRoundRectangle(context, rc.left + 1.0, rc.top + 1.0, rc.Width() - 2.0, rc.Height() - 2.0, cornerSize);
+			PathRoundRectangle(context, rc.left + fillStroke.stroke.width, rc.top + fillStroke.stroke.width,
+				rc.Width() - doubleStroke, rc.Height() - doubleStroke, cornerSize);
 		else
-			cairo_rectangle(context, rc.left + 1.0, rc.top + 1.0, rc.Width() - 2.0, rc.Height() - 2.0);
+			cairo_rectangle(context, rc.left + fillStroke.stroke.width, rc.top + fillStroke.stroke.width,
+				rc.Width() - doubleStroke, rc.Height() - doubleStroke);
 		cairo_fill(context);
 
-		const ColourDesired cdOutline(outline.AsInteger());
-		cairo_set_source_rgba(context,
-			cdOutline.GetRed() / 255.0,
-			cdOutline.GetGreen() / 255.0,
-			cdOutline.GetBlue() / 255.0,
-			alphaOutline / 255.0);
+		PenColourAlpha(fillStroke.stroke.colour);
 		if (cornerSize > 0)
-			PathRoundRectangle(context, rc.left + 0.5, rc.top + 0.5, rc.Width() - 1, rc.Height() - 1, cornerSize);
+			PathRoundRectangle(context, rc.left + halfStroke, rc.top + halfStroke,
+				rc.Width() - fillStroke.stroke.width, rc.Height() - fillStroke.stroke.width, cornerSize);
 		else
-			cairo_rectangle(context, rc.left + 0.5, rc.top + 0.5, rc.Width() - 1, rc.Height() - 1);
+			cairo_rectangle(context, rc.left + halfStroke, rc.top + halfStroke,
+				rc.Width() - fillStroke.stroke.width, rc.Height() - fillStroke.stroke.width);
+		cairo_set_line_width(context, fillStroke.stroke.width);
 		cairo_stroke(context);
 	}
 }
@@ -561,10 +592,10 @@ void SurfaceImpl::GradientRectangle(PRectangle rc, const std::vector<ColourStop>
 		}
 		for (const ColourStop &stop : stops) {
 			cairo_pattern_add_color_stop_rgba(pattern, stop.position,
-				stop.colour.GetRedComponent(),
-				stop.colour.GetGreenComponent(),
-				stop.colour.GetBlueComponent(),
-				stop.colour.GetAlphaComponent());
+							  stop.colour.GetRedComponent(),
+							  stop.colour.GetGreenComponent(),
+							  stop.colour.GetBlueComponent(),
+							  stop.colour.GetAlphaComponent());
 		}
 		cairo_rectangle(context, rc.left, rc.top, rc.Width(), rc.Height());
 		cairo_set_source(context, pattern);
@@ -599,13 +630,72 @@ void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsi
 	cairo_surface_destroy(psurfImage);
 }
 
-void SurfaceImpl::Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back) {
+void SurfaceImpl::Ellipse(PRectangle rc, FillStroke fillStroke) {
 	PLATFORM_ASSERT(context);
-	PenColour(back);
+	PenColourAlpha(fillStroke.fill.colour);
 	cairo_arc(context, (rc.left + rc.right) / 2, (rc.top + rc.bottom) / 2,
-		std::min(rc.Width(), rc.Height()) / 2, 0, 2*kPi);
+		  (std::min(rc.Width(), rc.Height()) - fillStroke.stroke.width) / 2, 0, 2*kPi);
+	cairo_fill_preserve(context);
+	PenColourAlpha(fillStroke.stroke.colour);
+	cairo_set_line_width(context, fillStroke.stroke.width);
+	cairo_stroke(context);
+}
+
+void SurfaceImpl::Stadium(PRectangle rc, FillStroke fillStroke, Ends ends) {
+	const XYPOSITION midLine = rc.Centre().y;
+	const XYPOSITION halfStroke = fillStroke.stroke.width / 2.0f;
+	const XYPOSITION radius = rc.Height() / 2.0f - halfStroke;
+	PRectangle rcInner = rc;
+	rcInner.left += radius;
+	rcInner.right -= radius;
+
+	cairo_new_sub_path(context);
+
+	const Ends leftSide = static_cast<Ends>(static_cast<int>(ends) & 0xf);
+	const Ends rightSide = static_cast<Ends>(static_cast<int>(ends) & 0xf0);
+	switch (leftSide) {
+		case Ends::leftFlat:
+			cairo_move_to(context, rc.left + halfStroke, rc.top + halfStroke);
+			cairo_line_to(context, rc.left + halfStroke, rc.bottom - halfStroke);
+			break;
+		case Ends::leftAngle:
+			cairo_move_to(context, rcInner.left + halfStroke, rc.top + halfStroke);
+			cairo_line_to(context, rc.left + halfStroke, rc.Centre().y);
+			cairo_line_to(context, rcInner.left + halfStroke, rc.bottom - halfStroke);
+			break;
+		case Ends::semiCircles:
+		default:
+			cairo_move_to(context, rcInner.left + halfStroke, rc.top + halfStroke);
+			cairo_arc_negative(context, rcInner.left + halfStroke, midLine, radius,
+				270 * degrees, 90 * degrees);
+			break;
+	}
+
+	switch (rightSide) {
+		case Ends::rightFlat:
+			cairo_line_to(context, rc.right - halfStroke, rc.bottom - halfStroke);
+			cairo_line_to(context, rc.right - halfStroke, rc.top + halfStroke);
+			break;
+		case Ends::rightAngle:
+			cairo_line_to(context, rcInner.right - halfStroke, rc.bottom - halfStroke);
+			cairo_line_to(context, rc.right - halfStroke, rc.Centre().y);
+			cairo_line_to(context, rcInner.right - halfStroke, rc.top + halfStroke);
+			break;
+		case Ends::semiCircles:
+		default:
+			cairo_line_to(context, rcInner.right - halfStroke, rc.bottom - halfStroke);
+			cairo_arc_negative(context, rcInner.right - halfStroke, midLine, radius,
+				90 * degrees, 270 * degrees);
+			break;
+	}
+
+	// Close the path to enclose it for stroking and for filling, then draw it
+	cairo_close_path(context);
+	PenColourAlpha(fillStroke.fill.colour);
 	cairo_fill_preserve(context);
-	PenColour(fore);
+
+	PenColourAlpha(fillStroke.stroke.colour);
+	cairo_set_line_width(context, fillStroke.stroke.width);
 	cairo_stroke(context);
 }
 
@@ -615,17 +705,21 @@ void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) {
 	if (canDraw) {
 		PLATFORM_ASSERT(context);
 		cairo_set_source_surface(context, surfi.psurf,
-			rc.left - from.x, rc.top - from.y);
+					 rc.left - from.x, rc.top - from.y);
 		cairo_rectangle(context, rc.left, rc.top, rc.Width(), rc.Height());
 		cairo_fill(context);
 	}
 }
 
-std::string UTF8FromLatin1(const char *s, int len) {
-	std::string utfForm(len*2 + 1, '\0');
+std::unique_ptr<IScreenLineLayout> SurfaceImpl::Layout(const IScreenLine *) {
+	return {};
+}
+
+std::string UTF8FromLatin1(std::string_view text) {
+	std::string utfForm(text.length()*2 + 1, '\0');
 	size_t lenU = 0;
-	for (int i=0; i<len; i++) {
-		const unsigned char uch = static_cast<unsigned char>(s[i]);
+	for (const char ch : text) {
+		const unsigned char uch = ch;
 		if (uch < 0x80) {
 			utfForm[lenU++] = uch;
 		} else {
@@ -639,14 +733,14 @@ std::string UTF8FromLatin1(const char *s, int len) {
 
 namespace {
 
-std::string UTF8FromIconv(const Converter &conv, const char *s, int len) {
+std::string UTF8FromIconv(const Converter &conv, std::string_view text) {
 	if (conv) {
-		std::string utfForm(len*3+1, '\0');
-		char *pin = const_cast<char *>(s);
-		gsize inLeft = len;
+		std::string utfForm(text.length()*3+1, '\0');
+		char *pin = const_cast<char *>(text.data());
+		gsize inLeft = text.length();
 		char *putf = &utfForm[0];
 		char *pout = putf;
-		gsize outLeft = len*3+1;
+		gsize outLeft = text.length()*3+1;
 		const gsize conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
 		if (conversions != sizeFailure) {
 			*pout = '\0';
@@ -676,20 +770,20 @@ size_t MultiByteLenFromIconv(const Converter &conv, const char *s, size_t len) n
 
 }
 
-void SurfaceImpl::DrawTextBase(PRectangle rc, const Font &font_, XYPOSITION ybase, const char *s, int len,
-                                 ColourDesired fore) {
-	PenColour(fore);
+void SurfaceImpl::DrawTextBase(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+			       ColourRGBA fore) {
 	if (context) {
+		PenColourAlpha(fore);
 		const XYPOSITION xText = rc.left;
 		if (PFont(font_)->pfd) {
 			std::string utfForm;
-			if (et == UTF8) {
-				pango_layout_set_text(layout, s, len);
+			if (et == EncodingType::utf8) {
+				pango_layout_set_text(layout, text.data(), text.length());
 			} else {
 				SetConverter(PFont(font_)->characterSet);
-				utfForm = UTF8FromIconv(conv, s, len);
+				utfForm = UTF8FromIconv(conv, text);
 				if (utfForm.empty()) {	// iconv failed so treat as Latin1
-					utfForm = UTF8FromLatin1(s, len);
+					utfForm = UTF8FromLatin1(text);
 				}
 				pango_layout_set_text(layout, utfForm.c_str(), utfForm.length());
 			}
@@ -702,25 +796,25 @@ void SurfaceImpl::DrawTextBase(PRectangle rc, const Font &font_, XYPOSITION ybas
 	}
 }
 
-void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len,
-                                 ColourDesired fore, ColourDesired back) {
-	FillRectangle(rc, back);
-	DrawTextBase(rc, font_, ybase, s, len, fore);
+void SurfaceImpl::DrawTextNoClip(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+				 ColourRGBA fore, ColourRGBA back) {
+	FillRectangleAligned(rc, back);
+	DrawTextBase(rc, font_, ybase, text, fore);
 }
 
 // On GTK+, exactly same as DrawTextNoClip
-void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len,
-                                  ColourDesired fore, ColourDesired back) {
-	FillRectangle(rc, back);
-	DrawTextBase(rc, font_, ybase, s, len, fore);
+void SurfaceImpl::DrawTextClipped(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+				  ColourRGBA fore, ColourRGBA back) {
+	FillRectangleAligned(rc, back);
+	DrawTextBase(rc, font_, ybase, text, fore);
 }
 
-void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len,
-                                  ColourDesired fore) {
+void SurfaceImpl::DrawTextTransparent(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+				      ColourRGBA fore) {
 	// Avoid drawing spaces in transparent mode
-	for (int i=0; i<len; i++) {
-		if (s[i] != ' ') {
-			DrawTextBase(rc, font_, ybase, s, len, fore);
+	for (size_t i=0; i<text.length(); i++) {
+		if (text[i] != ' ') {
+			DrawTextBase(rc, font_, ybase, text, fore);
 			return;
 		}
 	}
@@ -729,14 +823,14 @@ void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION yba
 class ClusterIterator {
 	PangoLayoutIter *iter;
 	PangoRectangle pos;
-	int lenPositions;
+	size_t lenPositions;
 public:
 	bool finished;
 	XYPOSITION positionStart;
 	XYPOSITION position;
 	XYPOSITION distance;
 	int curIndex;
-	ClusterIterator(PangoLayout *layout, int len) noexcept : lenPositions(len), finished(false),
+	ClusterIterator(PangoLayout *layout, size_t len) noexcept : lenPositions(len), finished(false),
 		positionStart(0), position(0), distance(0), curIndex(0) {
 		iter = pango_layout_get_iter(layout);
 		pango_layout_iter_get_cluster_extents(iter, nullptr, &pos);
@@ -766,149 +860,221 @@ class ClusterIterator {
 	}
 };
 
-void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions) {
-	if (font_.GetID()) {
-		const int lenPositions = len;
-		if (PFont(font_)->pfd) {
-			pango_layout_set_font_description(layout, PFont(font_)->pfd);
-			if (et == UTF8) {
-				// Simple and direct as UTF-8 is native Pango encoding
-				int i = 0;
-				pango_layout_set_text(layout, s, len);
-				ClusterIterator iti(layout, lenPositions);
-				while (!iti.finished) {
-					iti.Next();
-					const int places = iti.curIndex - i;
-					while (i < iti.curIndex) {
-						// Evenly distribute space among bytes of this cluster.
-						// Would be better to find number of characters and then
-						// divide evenly between characters with each byte of a character
-						// being at the same position.
-						positions[i] = iti.position - (iti.curIndex - 1 - i) * iti.distance / places;
-						i++;
-					}
-				}
-				PLATFORM_ASSERT(i == lenPositions);
-			} else {
-				int positionsCalculated = 0;
-				if (et == dbcs) {
-					SetConverter(PFont(font_)->characterSet);
-					std::string utfForm = UTF8FromIconv(conv, s, len);
-					if (!utfForm.empty()) {
-						// Convert to UTF-8 so can ask Pango for widths, then
-						// Loop through UTF-8 and DBCS forms, taking account of different
-						// character byte lengths.
-						Converter convMeasure("UCS-2", CharacterSetID(characterSet), false);
-						pango_layout_set_text(layout, utfForm.c_str(), strlen(utfForm.c_str()));
-						int i = 0;
-						int clusterStart = 0;
-						ClusterIterator iti(layout, strlen(utfForm.c_str()));
-						while (!iti.finished) {
-							iti.Next();
-							const int clusterEnd = iti.curIndex;
-							const int places = g_utf8_strlen(utfForm.c_str() + clusterStart, clusterEnd - clusterStart);
-							int place = 1;
-							while (clusterStart < clusterEnd) {
-								size_t lenChar = MultiByteLenFromIconv(convMeasure, s+i, len-i);
-								while (lenChar--) {
-									positions[i++] = iti.position - (places - place) * iti.distance / places;
-									positionsCalculated++;
-								}
-								clusterStart += UTF8BytesOfLead[static_cast<unsigned char>(utfForm[clusterStart])];
-								place++;
-							}
-						}
-						PLATFORM_ASSERT(i == lenPositions);
-					}
+void SurfaceImpl::MeasureWidths(const Font *font_, std::string_view text, XYPOSITION *positions) {
+	if (PFont(font_)->pfd) {
+		pango_layout_set_font_description(layout, PFont(font_)->pfd);
+		if (et == EncodingType::utf8) {
+			// Simple and direct as UTF-8 is native Pango encoding
+			int i = 0;
+			pango_layout_set_text(layout, text.data(), text.length());
+			ClusterIterator iti(layout, text.length());
+			while (!iti.finished) {
+				iti.Next();
+				const int places = iti.curIndex - i;
+				while (i < iti.curIndex) {
+					// Evenly distribute space among bytes of this cluster.
+					// Would be better to find number of characters and then
+					// divide evenly between characters with each byte of a character
+					// being at the same position.
+					positions[i] = iti.position - (iti.curIndex - 1 - i) * iti.distance / places;
+					i++;
 				}
-				if (positionsCalculated < 1) {
-					// Either 8-bit or DBCS conversion failed so treat as 8-bit.
-					SetConverter(PFont(font_)->characterSet);
-					const bool rtlCheck = PFont(font_)->characterSet == SC_CHARSET_HEBREW ||
-						PFont(font_)->characterSet == SC_CHARSET_ARABIC;
-					std::string utfForm = UTF8FromIconv(conv, s, len);
-					if (utfForm.empty()) {
-						utfForm = UTF8FromLatin1(s, len);
-					}
-					pango_layout_set_text(layout, utfForm.c_str(), utfForm.length());
+			}
+			PLATFORM_ASSERT(static_cast<size_t>(i) == text.length());
+		} else {
+			int positionsCalculated = 0;
+			if (et == EncodingType::dbcs) {
+				SetConverter(PFont(font_)->characterSet);
+				std::string utfForm = UTF8FromIconv(conv, text);
+				if (!utfForm.empty()) {
+					// Convert to UTF-8 so can ask Pango for widths, then
+					// Loop through UTF-8 and DBCS forms, taking account of different
+					// character byte lengths.
+					Converter convMeasure("UCS-2", CharacterSetID(characterSet), false);
+					pango_layout_set_text(layout, utfForm.c_str(), strlen(utfForm.c_str()));
 					int i = 0;
 					int clusterStart = 0;
-					// Each 8-bit input character may take 1 or 2 bytes in UTF-8
-					// and groups of up to 3 may be represented as ligatures.
-					ClusterIterator iti(layout, utfForm.length());
+					ClusterIterator iti(layout, strlen(utfForm.c_str()));
 					while (!iti.finished) {
 						iti.Next();
 						const int clusterEnd = iti.curIndex;
-						const int ligatureLength = g_utf8_strlen(utfForm.c_str() + clusterStart, clusterEnd - clusterStart);
-						if (rtlCheck && ((clusterEnd <= clusterStart) || (ligatureLength == 0) || (ligatureLength > 3))) {
-							// Something has gone wrong: exit quickly but pretend all the characters are equally spaced:
-							int widthLayout = 0;
-							pango_layout_get_size(layout, &widthLayout, nullptr);
-							const XYPOSITION widthTotal = floatFromPangoUnits(widthLayout);
-							for (int bytePos=0; bytePos<lenPositions; bytePos++) {
-								positions[bytePos] = widthTotal / lenPositions * (bytePos + 1);
+						const int places = g_utf8_strlen(utfForm.c_str() + clusterStart, clusterEnd - clusterStart);
+						int place = 1;
+						while (clusterStart < clusterEnd) {
+							size_t lenChar = MultiByteLenFromIconv(convMeasure, text.data()+i, text.length()-i);
+							while (lenChar--) {
+								positions[i++] = iti.position - (places - place) * iti.distance / places;
+								positionsCalculated++;
 							}
-							return;
+							clusterStart += UTF8BytesOfLead[static_cast<unsigned char>(utfForm[clusterStart])];
+							place++;
 						}
-						PLATFORM_ASSERT(ligatureLength > 0 && ligatureLength <= 3);
-						for (int charInLig=0; charInLig<ligatureLength; charInLig++) {
-							positions[i++] = iti.position - (ligatureLength - 1 - charInLig) * iti.distance / ligatureLength;
+					}
+					PLATFORM_ASSERT(static_cast<size_t>(i) == text.length());
+				}
+			}
+			if (positionsCalculated < 1) {
+				const size_t lenPositions = text.length();
+				// Either 8-bit or DBCS conversion failed so treat as 8-bit.
+				SetConverter(PFont(font_)->characterSet);
+				const bool rtlCheck = PFont(font_)->characterSet == CharacterSet::Hebrew ||
+							    PFont(font_)->characterSet == CharacterSet::Arabic;
+				std::string utfForm = UTF8FromIconv(conv, text);
+				if (utfForm.empty()) {
+					utfForm = UTF8FromLatin1(text);
+				}
+				pango_layout_set_text(layout, utfForm.c_str(), utfForm.length());
+				size_t i = 0;
+				int clusterStart = 0;
+				// Each 8-bit input character may take 1 or 2 bytes in UTF-8
+				// and groups of up to 3 may be represented as ligatures.
+				ClusterIterator iti(layout, utfForm.length());
+				while (!iti.finished) {
+					iti.Next();
+					const int clusterEnd = iti.curIndex;
+					const int ligatureLength = g_utf8_strlen(utfForm.c_str() + clusterStart, clusterEnd - clusterStart);
+					if (rtlCheck && ((clusterEnd <= clusterStart) || (ligatureLength == 0) || (ligatureLength > 3))) {
+						// Something has gone wrong: exit quickly but pretend all the characters are equally spaced:
+						int widthLayout = 0;
+						pango_layout_get_size(layout, &widthLayout, nullptr);
+						const XYPOSITION widthTotal = floatFromPangoUnits(widthLayout);
+						for (size_t bytePos=0; bytePos<lenPositions; bytePos++) {
+							positions[bytePos] = widthTotal / lenPositions * (bytePos + 1);
 						}
-						clusterStart = clusterEnd;
+						return;
 					}
-					while (i < lenPositions) {
-						// If something failed, fill in rest of the positions
-						positions[i++] = clusterStart;
+					PLATFORM_ASSERT(ligatureLength > 0 && ligatureLength <= 3);
+					for (int charInLig=0; charInLig<ligatureLength; charInLig++) {
+						positions[i++] = iti.position - (ligatureLength - 1 - charInLig) * iti.distance / ligatureLength;
 					}
-					PLATFORM_ASSERT(i == lenPositions);
+					clusterStart = clusterEnd;
+				}
+				while (i < lenPositions) {
+					// If something failed, fill in rest of the positions
+					positions[i++] = clusterStart;
 				}
+				PLATFORM_ASSERT(i == text.length());
 			}
 		}
 	} else {
 		// No font so return an ascending range of values
-		for (int i = 0; i < len; i++) {
+		for (size_t i = 0; i < text.length(); i++) {
 			positions[i] = i + 1;
 		}
 	}
 }
 
-XYPOSITION SurfaceImpl::WidthText(Font &font_, const char *s, int len) {
-	if (font_.GetID()) {
+XYPOSITION SurfaceImpl::WidthText(const Font *font_, std::string_view text) {
+	if (PFont(font_)->pfd) {
+		std::string utfForm;
+		pango_layout_set_font_description(layout, PFont(font_)->pfd);
+		if (et == EncodingType::utf8) {
+			pango_layout_set_text(layout, text.data(), text.length());
+		} else {
+			SetConverter(PFont(font_)->characterSet);
+			utfForm = UTF8FromIconv(conv, text);
+			if (utfForm.empty()) {	// iconv failed so treat as Latin1
+				utfForm = UTF8FromLatin1(text);
+			}
+			pango_layout_set_text(layout, utfForm.c_str(), utfForm.length());
+		}
+		PangoLayoutLine *pangoLine = pango_layout_get_line_readonly(layout, 0);
+		PangoRectangle pos {};
+		pango_layout_line_get_extents(pangoLine, nullptr, &pos);
+		return floatFromPangoUnits(pos.width);
+	}
+	return 1;
+}
+
+void SurfaceImpl::DrawTextBaseUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+	ColourRGBA fore) {
+	if (context) {
+		PenColourAlpha(fore);
+		const XYPOSITION xText = rc.left;
 		if (PFont(font_)->pfd) {
-			std::string utfForm;
+			pango_layout_set_text(layout, text.data(), text.length());
 			pango_layout_set_font_description(layout, PFont(font_)->pfd);
-			if (et == UTF8) {
-				pango_layout_set_text(layout, s, len);
-			} else {
-				SetConverter(PFont(font_)->characterSet);
-				utfForm = UTF8FromIconv(conv, s, len);
-				if (utfForm.empty()) {	// iconv failed so treat as Latin1
-					utfForm = UTF8FromLatin1(s, len);
-				}
-				pango_layout_set_text(layout, utfForm.c_str(), utfForm.length());
+			pango_cairo_update_layout(context, layout);
+			PangoLayoutLine *pll = pango_layout_get_line_readonly(layout, 0);
+			cairo_move_to(context, xText, ybase);
+			pango_cairo_show_layout_line(context, pll);
+		}
+	}
+}
+
+void SurfaceImpl::DrawTextNoClipUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+	ColourRGBA fore, ColourRGBA back) {
+	FillRectangleAligned(rc, back);
+	DrawTextBaseUTF8(rc, font_, ybase, text, fore);
+}
+
+// On GTK+, exactly same as DrawTextNoClip
+void SurfaceImpl::DrawTextClippedUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+	ColourRGBA fore, ColourRGBA back) {
+	FillRectangleAligned(rc, back);
+	DrawTextBaseUTF8(rc, font_, ybase, text, fore);
+}
+
+void SurfaceImpl::DrawTextTransparentUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+	ColourRGBA fore) {
+	// Avoid drawing spaces in transparent mode
+	for (size_t i = 0; i < text.length(); i++) {
+		if (text[i] != ' ') {
+			DrawTextBaseUTF8(rc, font_, ybase, text, fore);
+			return;
+		}
+	}
+}
+
+void SurfaceImpl::MeasureWidthsUTF8(const Font *font_, std::string_view text, XYPOSITION *positions) {
+	if (PFont(font_)->pfd) {
+		pango_layout_set_font_description(layout, PFont(font_)->pfd);
+		// Simple and direct as UTF-8 is native Pango encoding
+		int i = 0;
+		pango_layout_set_text(layout, text.data(), text.length());
+		ClusterIterator iti(layout, text.length());
+		while (!iti.finished) {
+			iti.Next();
+			const int places = iti.curIndex - i;
+			while (i < iti.curIndex) {
+				// Evenly distribute space among bytes of this cluster.
+				// Would be better to find number of characters and then
+				// divide evenly between characters with each byte of a character
+				// being at the same position.
+				positions[i] = iti.position - (iti.curIndex - 1 - i) * iti.distance / places;
+				i++;
 			}
-			PangoLayoutLine *pangoLine = pango_layout_get_line_readonly(layout, 0);
-			PangoRectangle pos {};
-			pango_layout_line_get_extents(pangoLine, nullptr, &pos);
-			return floatFromPangoUnits(pos.width);
 		}
-		return 1;
+		PLATFORM_ASSERT(static_cast<size_t>(i) == text.length());
 	} else {
-		return 1;
+		// No font so return an ascending range of values
+		for (size_t i = 0; i < text.length(); i++) {
+			positions[i] = i + 1;
+		}
+	}
+}
+
+XYPOSITION SurfaceImpl::WidthTextUTF8(const Font *font_, std::string_view text) {
+	if (PFont(font_)->pfd) {
+		pango_layout_set_font_description(layout, PFont(font_)->pfd);
+		pango_layout_set_text(layout, text.data(), text.length());
+		PangoLayoutLine *pangoLine = pango_layout_get_line_readonly(layout, 0);
+		PangoRectangle pos{};
+		pango_layout_line_get_extents(pangoLine, nullptr, &pos);
+		return floatFromPangoUnits(pos.width);
 	}
+	return 1;
 }
 
 // Ascent and descent determined by Pango font metrics.
 
-XYPOSITION SurfaceImpl::Ascent(Font &font_) {
-	if (!(font_.GetID()))
-		return 1;
+XYPOSITION SurfaceImpl::Ascent(const Font *font_) {
 	XYPOSITION ascent = 0;
 	if (PFont(font_)->pfd) {
 		PangoFontMetrics *metrics = pango_context_get_metrics(pcontext,
-			PFont(font_)->pfd, pango_context_get_language(pcontext));
-		ascent = Sci::round(floatFromPangoUnits(
-			pango_font_metrics_get_ascent(metrics)));
+					    PFont(font_)->pfd, pango_context_get_language(pcontext));
+		ascent = std::round(floatFromPangoUnits(
+					    pango_font_metrics_get_ascent(metrics)));
 		pango_font_metrics_unref(metrics);
 	}
 	if (ascent == 0) {
@@ -917,57 +1083,54 @@ XYPOSITION SurfaceImpl::Ascent(Font &font_) {
 	return ascent;
 }
 
-XYPOSITION SurfaceImpl::Descent(Font &font_) {
-	if (!(font_.GetID()))
-		return 1;
+XYPOSITION SurfaceImpl::Descent(const Font *font_) {
 	if (PFont(font_)->pfd) {
 		PangoFontMetrics *metrics = pango_context_get_metrics(pcontext,
-			PFont(font_)->pfd, pango_context_get_language(pcontext));
-		const XYPOSITION descent = Sci::round(floatFromPangoUnits(
-			pango_font_metrics_get_descent(metrics)));
+					    PFont(font_)->pfd, pango_context_get_language(pcontext));
+		const XYPOSITION descent = std::round(floatFromPangoUnits(
+				pango_font_metrics_get_descent(metrics)));
 		pango_font_metrics_unref(metrics);
 		return descent;
 	}
 	return 0;
 }
 
-XYPOSITION SurfaceImpl::InternalLeading(Font &) {
+XYPOSITION SurfaceImpl::InternalLeading(const Font *) {
 	return 0;
 }
 
-XYPOSITION SurfaceImpl::Height(Font &font_) {
+XYPOSITION SurfaceImpl::Height(const Font *font_) {
 	return Ascent(font_) + Descent(font_);
 }
 
-XYPOSITION SurfaceImpl::AverageCharWidth(Font &font_) {
-	return WidthText(font_, "n", 1);
+XYPOSITION SurfaceImpl::AverageCharWidth(const Font *font_) {
+	return WidthText(font_, "n");
 }
 
 void SurfaceImpl::SetClip(PRectangle rc) {
 	PLATFORM_ASSERT(context);
-	cairo_rectangle(context, rc.left, rc.top, rc.Width(), rc.Height());
+	cairo_save(context);
+	CairoRectangle(rc);
 	cairo_clip(context);
 }
 
-void SurfaceImpl::FlushCachedState() {}
-
-void SurfaceImpl::SetUnicodeMode(bool unicodeMode_) {
-	if (unicodeMode_)
-		et = UTF8;
+void SurfaceImpl::PopClip() {
+	PLATFORM_ASSERT(context);
+	cairo_restore(context);
 }
 
-void SurfaceImpl::SetDBCSMode(int codePage) {
-	if (codePage && (codePage != SC_CP_UTF8))
-		et = dbcs;
+void SurfaceImpl::FlushCachedState() {}
+
+void SurfaceImpl::FlushDrawing() {
 }
 
-Surface *Surface::Allocate(int) {
-	return new SurfaceImpl();
+std::unique_ptr<Surface> Surface::Allocate(Technology) {
+	return std::make_unique<SurfaceImpl>();
 }
 
-Window::~Window() {}
+Window::~Window() noexcept {}
 
-void Window::Destroy() {
+void Window::Destroy() noexcept {
 	if (wid) {
 		ListBox *listbox = dynamic_cast<ListBox *>(this);
 		if (listbox) {
@@ -1001,7 +1164,7 @@ PRectangle Window::GetPosition() const {
 }
 
 void Window::SetPosition(PRectangle rc) {
-	GtkAllocation alloc;
+	GtkAllocation alloc {};
 	alloc.x = static_cast<int>(rc.left);
 	alloc.y = static_cast<int>(rc.top);
 	alloc.width = static_cast<int>(rc.Width());
@@ -1076,15 +1239,11 @@ void Window::InvalidateRectangle(PRectangle rc) {
 	if (wid) {
 		const IntegerRectangle irc(rc);
 		gtk_widget_queue_draw_area(PWidget(wid),
-		                           irc.left, irc.top,
-		                           irc.Width(), irc.Height());
+					   irc.left, irc.top,
+					   irc.Width(), irc.Height());
 	}
 }
 
-void Window::SetFont(Font &) {
-	// Can not be done generically but only needed for ListBox
-}
-
 void Window::SetCursor(Cursor curs) {
 	// We don't set the cursor to same value numerous times under gtk because
 	// it stores the cursor in the window once it's set
@@ -1096,27 +1255,27 @@ void Window::SetCursor(Cursor curs) {
 
 	GdkCursor *gdkCurs;
 	switch (curs) {
-	case cursorText:
+	case Cursor::text:
 		gdkCurs = gdk_cursor_new_for_display(pdisplay, GDK_XTERM);
 		break;
-	case cursorArrow:
+	case Cursor::arrow:
 		gdkCurs = gdk_cursor_new_for_display(pdisplay, GDK_LEFT_PTR);
 		break;
-	case cursorUp:
+	case Cursor::up:
 		gdkCurs = gdk_cursor_new_for_display(pdisplay, GDK_CENTER_PTR);
 		break;
-	case cursorWait:
+	case Cursor::wait:
 		gdkCurs = gdk_cursor_new_for_display(pdisplay, GDK_WATCH);
 		break;
-	case cursorHand:
+	case Cursor::hand:
 		gdkCurs = gdk_cursor_new_for_display(pdisplay, GDK_HAND2);
 		break;
-	case cursorReverseArrow:
+	case Cursor::reverseArrow:
 		gdkCurs = gdk_cursor_new_for_display(pdisplay, GDK_RIGHT_PTR);
 		break;
 	default:
 		gdkCurs = gdk_cursor_new_for_display(pdisplay, GDK_LEFT_PTR);
-		cursorLast = cursorArrow;
+		cursorLast = Cursor::arrow;
 		break;
 	}
 
@@ -1141,12 +1300,12 @@ PRectangle Window::GetMonitorRect(Point pt) {
 #if GTK_CHECK_VERSION(3,22,0)
 	GdkDisplay *pdisplay = gtk_widget_get_display(PWidget(wid));
 	GdkMonitor *monitor = gdk_display_get_monitor_at_point(pdisplay,
-		pt.x + x_offset, pt.y + y_offset);
+			      pt.x + x_offset, pt.y + y_offset);
 	gdk_monitor_get_geometry(monitor, &rect);
 #else
 	GdkScreen *screen = gtk_widget_get_screen(PWidget(wid));
 	const gint monitor_num = gdk_screen_get_monitor_at_point(screen,
-		pt.x + x_offset, pt.y + y_offset);
+				 pt.x + x_offset, pt.y + y_offset);
 	gdk_screen_get_monitor_geometry(screen, monitor_num, &rect);
 #endif
 	rect.x -= x_offset;
@@ -1171,7 +1330,7 @@ static void list_image_free(gpointer, gpointer value, gpointer) noexcept {
 ListBox::ListBox() noexcept {
 }
 
-ListBox::~ListBox() {
+ListBox::~ListBox() noexcept {
 }
 
 enum {
@@ -1213,7 +1372,7 @@ class ListBoxX : public ListBox {
 	ListBoxX(ListBoxX&&) = delete;
 	ListBoxX&operator=(const ListBoxX&) = delete;
 	ListBoxX&operator=(ListBoxX&&) = delete;
-	~ListBoxX() override {
+	~ListBoxX() noexcept override {
 		if (pixhash) {
 			g_hash_table_foreach((GHashTable *) pixhash, list_image_free, nullptr);
 			g_hash_table_destroy((GHashTable *) pixhash);
@@ -1229,32 +1388,32 @@ class ListBoxX : public ListBox {
 		}
 #endif
 	}
-	void SetFont(Font &font) override;
-	void Create(Window &parent, int ctrlID, Point location_, int lineHeight_, bool unicodeMode_, int technology_) override;
+	void SetFont(const Font *font) override;
+	void Create(Window &parent, int ctrlID, Point location_, int lineHeight_, bool unicodeMode_, Technology technology_) override;
 	void SetAverageCharWidth(int width) override;
 	void SetVisibleRows(int rows) override;
 	int GetVisibleRows() const override;
 	int GetRowHeight();
 	PRectangle GetDesiredRect() override;
 	int CaretFromEdge() override;
-	void Clear() override;
+	void Clear() noexcept override;
 	void Append(char *s, int type = -1) override;
 	int Length() override;
 	void Select(int n) override;
 	int GetSelection() override;
 	int Find(const char *prefix) override;
-	void GetValue(int n, char *value, int len) override;
-	void RegisterRGBA(int type, RGBAImage *image);
+	std::string GetValue(int n) override;
+	void RegisterRGBA(int type, std::unique_ptr<RGBAImage> image);
 	void RegisterImage(int type, const char *xpm_data) override;
 	void RegisterRGBAImage(int type, int width, int height, const unsigned char *pixelsImage) override;
 	void ClearRegisteredImages() override;
 	void SetDelegate(IListBoxDelegate *lbDelegate) override;
 	void SetList(const char *listText, char separator, char typesep) override;
+	void SetOptions(ListOptions options_) override;
 };
 
-ListBox *ListBox::Allocate() {
-	ListBoxX *lb = new ListBoxX();
-	return lb;
+std::unique_ptr<ListBox> ListBox::Allocate() {
+	return std::make_unique<ListBoxX>();
 }
 
 static int treeViewGetRowHeight(GtkTreeView *view) {
@@ -1273,8 +1432,8 @@ static int treeViewGetRowHeight(GtkTreeView *view) {
 	GtkTreeViewColumn *column = gtk_tree_view_get_column(view, 0);
 	gtk_tree_view_column_cell_get_size(column, nullptr, nullptr, nullptr, nullptr, &row_height);
 	gtk_widget_style_get(GTK_WIDGET(view),
-		"vertical-separator", &vertical_separator,
-		"expander-size", &expander_size, nullptr);
+			     "vertical-separator", &vertical_separator,
+			     "expander-size", &expander_size, nullptr);
 	row_height += vertical_separator;
 	row_height = std::max(row_height, expander_size);
 	return row_height;
@@ -1415,7 +1574,7 @@ static void StyleSet(GtkWidget *w, GtkStyle *, void *) {
 #endif
 }
 
-void ListBoxX::Create(Window &parent, int, Point, int, bool, int) {
+void ListBoxX::Create(Window &parent, int, Point, int, bool, Technology) {
 	if (widCached != nullptr) {
 		wid = widCached;
 		return;
@@ -1438,7 +1597,7 @@ void ListBoxX::Create(Window &parent, int, Point, int, bool, int) {
 	scroller = g_object_new(small_scroller_get_type(), nullptr);
 	gtk_container_set_border_width(GTK_CONTAINER(scroller), 0);
 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller),
-	                               GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+				       GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
 	gtk_container_add(GTK_CONTAINER(frame), PWidget(scroller));
 	gtk_widget_show(PWidget(scroller));
 
@@ -1453,7 +1612,7 @@ void ListBoxX::Create(Window &parent, int, Point, int, bool, int) {
 	GtkStyleContext *styleContext = gtk_widget_get_style_context(GTK_WIDGET(list));
 	if (styleContext) {
 		gtk_style_context_add_provider(styleContext, GTK_STYLE_PROVIDER(cssProvider),
-			GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+					       GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
 	}
 #endif
 
@@ -1472,13 +1631,13 @@ void ListBoxX::Create(Window &parent, int, Point, int, bool, int) {
 	gtk_cell_renderer_set_fixed_size(pixbuf_renderer, 0, -1);
 	gtk_tree_view_column_pack_start(column, pixbuf_renderer, FALSE);
 	gtk_tree_view_column_add_attribute(column, pixbuf_renderer,
-										"pixbuf", PIXBUF_COLUMN);
+					   "pixbuf", PIXBUF_COLUMN);
 
 	renderer = gtk_cell_renderer_text_new();
 	gtk_cell_renderer_text_set_fixed_height_from_font(GTK_CELL_RENDERER_TEXT(renderer), 1);
 	gtk_tree_view_column_pack_start(column, renderer, TRUE);
 	gtk_tree_view_column_add_attribute(column, renderer,
-										"text", TEXT_COLUMN);
+					   "text", TEXT_COLUMN);
 
 	gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
 	if (g_object_class_find_property(G_OBJECT_GET_CLASS(list), "fixed-height-mode"))
@@ -1488,16 +1647,16 @@ void ListBoxX::Create(Window &parent, int, Point, int, bool, int) {
 	gtk_container_add(GTK_CONTAINER(PWidget(scroller)), widget);
 	gtk_widget_show(widget);
 	g_signal_connect(G_OBJECT(widget), "button_press_event",
-	                   G_CALLBACK(ButtonPress), this);
+			 G_CALLBACK(ButtonPress), this);
 	g_signal_connect(G_OBJECT(widget), "button_release_event",
-	                   G_CALLBACK(ButtonRelease), this);
+			 G_CALLBACK(ButtonRelease), this);
 
 	GtkWidget *top = gtk_widget_get_toplevel(static_cast<GtkWidget *>(parent.GetID()));
 	gtk_window_set_transient_for(GTK_WINDOW(static_cast<GtkWidget *>(wid)),
-		GTK_WINDOW(top));
+				     GTK_WINDOW(top));
 }
 
-void ListBoxX::SetFont(Font &font) {
+void ListBoxX::SetFont(const Font *font) {
 	// Only do for Pango font as there have been crashes for GDK fonts
 	if (Created() && PFont(font)->pfd) {
 		// Current font is Pango font
@@ -1513,15 +1672,15 @@ void ListBoxX::SetFont(Font &font) {
 			// need to use the "px" unit.  Normally we only get fonts in points here, so
 			// don't bother to handle the case the font is actually in pixels on < 3.21.0.
 			if (gtk_check_version(3, 21, 0) != nullptr || // on < 3.21.0
-			    pango_font_description_get_size_is_absolute(pfd)) {
+					pango_font_description_get_size_is_absolute(pfd)) {
 				ssFontSetting << "px; ";
 			} else {
 				ssFontSetting << "pt; ";
 			}
 			ssFontSetting << "font-weight:"<< pango_font_description_get_weight(pfd) << "; ";
 			ssFontSetting << "}";
 			gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(cssProvider),
-				ssFontSetting.str().c_str(), -1, nullptr);
+							ssFontSetting.str().c_str(), -1, nullptr);
 		}
 #else
 		gtk_widget_modify_font(PWidget(list), PFont(font)->pfd);
@@ -1597,14 +1756,14 @@ PRectangle ListBoxX::GetDesiredRect() {
 #	endif
 
 		height = (rows * row_height
-		          + padding.top + padding.bottom
-		          + border.top + border.bottom
-		          + border_border.top + border_border.bottom
-		          + 2 * gtk_container_get_border_width(GTK_CONTAINER(PWidget(list))));
+			  + padding.top + padding.bottom
+			  + border.top + border.bottom
+			  + border_border.top + border_border.bottom
+			  + 2 * gtk_container_get_border_width(GTK_CONTAINER(PWidget(list))));
 #else
 		height = (rows * row_height
-		          + 2 * (PWidget(frame)->style->ythickness
-		                 + GTK_CONTAINER(PWidget(list))->border_width));
+			  + 2 * (PWidget(frame)->style->ythickness
+				 + GTK_CONTAINER(PWidget(list))->border_width));
 #endif
 		rc.bottom = height;
 
@@ -1615,16 +1774,16 @@ PRectangle ListBoxX::GetDesiredRect() {
 		// Add horizontal padding and borders
 		int horizontal_separator=0;
 		gtk_widget_style_get(PWidget(list),
-			"horizontal-separator", &horizontal_separator, nullptr);
+				     "horizontal-separator", &horizontal_separator, nullptr);
 		rc.right += horizontal_separator;
 #if GTK_CHECK_VERSION(3,0,0)
 		rc.right += (padding.left + padding.right
-		             + border.left + border.right
-		             + border_border.left + border_border.right
-		             + 2 * gtk_container_get_border_width(GTK_CONTAINER(PWidget(list))));
+			     + border.left + border.right
+			     + border_border.left + border_border.right
+			     + 2 * gtk_container_get_border_width(GTK_CONTAINER(PWidget(list))));
 #else
 		rc.right += 2 * (PWidget(frame)->style->xthickness
-		                 + GTK_CONTAINER(PWidget(list))->border_width);
+				 + GTK_CONTAINER(PWidget(list))->border_width);
 #endif
 		if (Length() > rows) {
 			// Add the width of the scrollbar
@@ -1644,31 +1803,31 @@ PRectangle ListBoxX::GetDesiredRect() {
 int ListBoxX::CaretFromEdge() {
 	gint renderer_width, renderer_height;
 	gtk_cell_renderer_get_fixed_size(pixbuf_renderer, &renderer_width,
-						&renderer_height);
+					 &renderer_height);
 	return 4 + renderer_width;
 }
 
-void ListBoxX::Clear() {
+void ListBoxX::Clear() noexcept {
 	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list));
 	gtk_list_store_clear(GTK_LIST_STORE(model));
 	maxItemCharacters = 0;
 }
 
-static void init_pixmap(ListImage *list_image) {
+static void init_pixmap(ListImage *list_image) noexcept {
 	if (list_image->rgba_data) {
 		// Drop any existing pixmap/bitmap as data may have changed
 		if (list_image->pixbuf)
 			g_object_unref(list_image->pixbuf);
 		list_image->pixbuf =
 			gdk_pixbuf_new_from_data(list_image->rgba_data->Pixels(),
-                                                         GDK_COLORSPACE_RGB,
-                                                         TRUE,
-                                                         8,
-                                                         list_image->rgba_data->GetWidth(),
-                                                         list_image->rgba_data->GetHeight(),
-                                                         list_image->rgba_data->GetWidth() * 4,
-                                                         nullptr,
-                                                         nullptr);
+						 GDK_COLORSPACE_RGB,
+						 TRUE,
+						 8,
+						 list_image->rgba_data->GetWidth(),
+						 list_image->rgba_data->GetHeight(),
+						 list_image->rgba_data->GetWidth() * 4,
+						 nullptr,
+						 nullptr);
 	}
 }
 
@@ -1689,23 +1848,23 @@ void ListBoxX::Append(char *s, int type) {
 			init_pixmap(list_image);
 		if (list_image->pixbuf) {
 			gtk_list_store_set(GTK_LIST_STORE(store), &iter,
-								PIXBUF_COLUMN, list_image->pixbuf,
-								TEXT_COLUMN, s, -1);
+					   PIXBUF_COLUMN, list_image->pixbuf,
+					   TEXT_COLUMN, s, -1);
 
 			const gint pixbuf_width = gdk_pixbuf_get_width(list_image->pixbuf);
 			gint renderer_height, renderer_width;
 			gtk_cell_renderer_get_fixed_size(pixbuf_renderer,
-								&renderer_width, &renderer_height);
+							 &renderer_width, &renderer_height);
 			if (pixbuf_width > renderer_width)
 				gtk_cell_renderer_set_fixed_size(pixbuf_renderer,
-								pixbuf_width, -1);
+								 pixbuf_width, -1);
 		} else {
 			gtk_list_store_set(GTK_LIST_STORE(store), &iter,
-								TEXT_COLUMN, s, -1);
+					   TEXT_COLUMN, s, -1);
 		}
 	} else {
-			gtk_list_store_set(GTK_LIST_STORE(store), &iter,
-								TEXT_COLUMN, s, -1);
+		gtk_list_store_set(GTK_LIST_STORE(store), &iter,
+				   TEXT_COLUMN, s, -1);
 	}
 	const size_t len = strlen(s);
 	if (maxItemCharacters < len)
@@ -1715,7 +1874,7 @@ void ListBoxX::Append(char *s, int type) {
 int ListBoxX::Length() {
 	if (wid)
 		return gtk_tree_model_iter_n_children(gtk_tree_view_get_model
-											   (GTK_TREE_VIEW(list)), nullptr);
+						      (GTK_TREE_VIEW(list)), nullptr);
 	return 0;
 }
 
@@ -1744,7 +1903,7 @@ void ListBoxX::Select(int n) {
 			gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(list));
 #endif
 		gfloat value = (static_cast<gfloat>(n) / total) * (gtk_adjustment_get_upper(adj) - gtk_adjustment_get_lower(adj))
-							+ gtk_adjustment_get_lower(adj) - gtk_adjustment_get_page_size(adj) / 2;
+			       + gtk_adjustment_get_lower(adj) - gtk_adjustment_get_page_size(adj) / 2;
 		// Get cell height
 		const int row_height = GetRowHeight();
 
@@ -1759,7 +1918,7 @@ void ListBoxX::Select(int n) {
 		// Clamp it.
 		value = (value < 0)? 0 : value;
 		value = (value > (gtk_adjustment_get_upper(adj) - gtk_adjustment_get_page_size(adj)))?
-					(gtk_adjustment_get_upper(adj) - gtk_adjustment_get_page_size(adj)) : value;
+			(gtk_adjustment_get_upper(adj) - gtk_adjustment_get_page_size(adj)) : value;
 
 		// Set it.
 		gtk_adjustment_set_value(adj, value);
@@ -1810,29 +1969,30 @@ int ListBoxX::Find(const char *prefix) {
 	return -1;
 }
 
-void ListBoxX::GetValue(int n, char *value, int len) {
+std::string ListBoxX::GetValue(int n) {
 	char *text = nullptr;
 	GtkTreeIter iter {};
 	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list));
 	const bool valid = gtk_tree_model_iter_nth_child(model, &iter, nullptr, n) != FALSE;
 	if (valid) {
 		gtk_tree_model_get(model, &iter, TEXT_COLUMN, &text, -1);
 	}
-	if (text && len > 0) {
-		g_strlcpy(value, text, len);
-	} else {
-		value[0] = '\0';
+	std::string value;
+	if (text) {
+		value = text;
 	}
 	g_free(text);
+	return value;
 }
 
 // g_return_if_fail causes unnecessary compiler warning in release compile.
 #ifdef _MSC_VER
 #pragma warning(disable: 4127)
 #endif
 
-void ListBoxX::RegisterRGBA(int type, RGBAImage *image) {
-	images.Add(type, image);
+void ListBoxX::RegisterRGBA(int type, std::unique_ptr<RGBAImage> image) {
+	images.AddImage(type, std::move(image));
+	const RGBAImage * const observe = images.Get(type);
 
 	if (!pixhash) {
 		pixhash = g_hash_table_new(g_direct_hash, g_direct_equal);
@@ -1844,23 +2004,23 @@ void ListBoxX::RegisterRGBA(int type, RGBAImage *image) {
 		if (list_image->pixbuf)
 			g_object_unref(list_image->pixbuf);
 		list_image->pixbuf = nullptr;
-		list_image->rgba_data = image;
+		list_image->rgba_data = observe;
 	} else {
 		list_image = g_new0(ListImage, 1);
-		list_image->rgba_data = image;
+		list_image->rgba_data = observe;
 		g_hash_table_insert((GHashTable *) pixhash, GINT_TO_POINTER(type),
-			(gpointer) list_image);
+				    (gpointer) list_image);
 	}
 }
 
 void ListBoxX::RegisterImage(int type, const char *xpm_data) {
 	g_return_if_fail(xpm_data);
 	XPM xpmImage(xpm_data);
-	RegisterRGBA(type, new RGBAImage(xpmImage));
+	RegisterRGBA(type, std::make_unique<RGBAImage>(xpmImage));
 }
 
 void ListBoxX::RegisterRGBAImage(int type, int width, int height, const unsigned char *pixelsImage) {
-	RegisterRGBA(type, new RGBAImage(width, height, 1.0, pixelsImage));
+	RegisterRGBA(type, std::make_unique<RGBAImage>(width, height, 1.0f, pixelsImage));
 }
 
 void ListBoxX::ClearRegisteredImages() {
@@ -1897,6 +2057,9 @@ void ListBoxX::SetList(const char *listText, char separator, char typesep) {
 	}
 }
 
+void ListBoxX::SetOptions(ListOptions) {
+}
+
 Menu::Menu() noexcept : mid(nullptr) {}
 
 void Menu::CreatePopUp() {
@@ -1905,7 +2068,7 @@ void Menu::CreatePopUp() {
 	g_object_ref_sink(G_OBJECT(mid));
 }
 
-void Menu::Destroy() {
+void Menu::Destroy() noexcept {
 	if (mid)
 		g_object_unref(G_OBJECT(mid));
 	mid = nullptr;
@@ -1919,7 +2082,7 @@ static void MenuPositionFunc(GtkMenu *, gint *x, gint *y, gboolean *, gpointer u
 }
 #endif
 
-void Menu::Show(Point pt, Window &w) {
+void Menu::Show(Point pt, const Window &w) {
 	GtkMenu *widget = static_cast<GtkMenu *>(mid);
 	gtk_widget_show_all(GTK_WIDGET(widget));
 #if GTK_CHECK_VERSION(3,22,0)
@@ -1940,57 +2103,17 @@ void Menu::Show(Point pt, Window &w) {
 		pt.y = rcMonitor.y + rcMonitor.height - requisition.height;
 	}
 	gtk_menu_popup(widget, nullptr, nullptr, MenuPositionFunc,
-		GINT_TO_POINTER((static_cast<int>(pt.y) << 16) | static_cast<int>(pt.x)), 0,
-		gtk_get_current_event_time());
+		       GINT_TO_POINTER((static_cast<int>(pt.y) << 16) | static_cast<int>(pt.x)), 0,
+		       gtk_get_current_event_time());
 #endif
 }
 
-class DynamicLibraryImpl : public DynamicLibrary {
-protected:
-	GModule *m;
-public:
-	explicit DynamicLibraryImpl(const char *modulePath) noexcept {
-		m = g_module_open(modulePath, G_MODULE_BIND_LAZY);
-	}
-	// Deleted so DynamicLibraryImpl objects can not be copied.
-	DynamicLibraryImpl(const DynamicLibraryImpl&) = delete;
-	DynamicLibraryImpl(DynamicLibraryImpl&&) = delete;
-	DynamicLibraryImpl&operator=(const DynamicLibraryImpl&) = delete;
-	DynamicLibraryImpl&operator=(DynamicLibraryImpl&&) = delete;
-	~DynamicLibraryImpl() override {
-		if (m != nullptr)
-			g_module_close(m);
-	}
-
-	// Use g_module_symbol to get a pointer to the relevant function.
-	Function FindFunction(const char *name) override {
-		if (m != nullptr) {
-			gpointer fn_address = nullptr;
-			const gboolean status = g_module_symbol(m, name, &fn_address);
-			if (status)
-				return static_cast<Function>(fn_address);
-			else
-				return nullptr;
-		} else {
-			return nullptr;
-		}
-	}
-
-	bool IsValid() override {
-		return m != nullptr;
-	}
-};
-
-DynamicLibrary *DynamicLibrary::Load(const char *modulePath) {
-	return static_cast<DynamicLibrary *>(new DynamicLibraryImpl(modulePath));
-}
-
-ColourDesired Platform::Chrome() {
-	return ColourDesired(0xe0, 0xe0, 0xe0);
+ColourRGBA Platform::Chrome() {
+	return ColourRGBA(0xe0, 0xe0, 0xe0);
 }
 
-ColourDesired Platform::ChromeHighlight() {
-	return ColourDesired(0xff, 0xff, 0xff);
+ColourRGBA Platform::ChromeHighlight() {
+	return ColourRGBA(0xff, 0xff, 0xff);
 }
 
 const char *Platform::DefaultFont() {
@@ -2013,14 +2136,14 @@ unsigned int Platform::DoubleClickTime() {
 	return 500; 	// Half a second
 }
 
-void Platform::DebugDisplay(const char *s) {
+void Platform::DebugDisplay(const char *s) noexcept {
 	fprintf(stderr, "%s", s);
 }
 
 //#define TRACE
 
 #ifdef TRACE
-void Platform::DebugPrintf(const char *format, ...) {
+void Platform::DebugPrintf(const char *format, ...) noexcept {
 	char buffer[2000];
 	va_list pArguments;
 	va_start(pArguments, format);
@@ -2029,20 +2152,20 @@ void Platform::DebugPrintf(const char *format, ...) {
 	Platform::DebugDisplay(buffer);
 }
 #else
-void Platform::DebugPrintf(const char *, ...) {}
+void Platform::DebugPrintf(const char *, ...) noexcept {}
 
 #endif
 
 // Not supported for GTK+
 static bool assertionPopUps = true;
 
-bool Platform::ShowAssertionPopUps(bool assertionPopUps_) {
+bool Platform::ShowAssertionPopUps(bool assertionPopUps_) noexcept {
 	const bool ret = assertionPopUps;
 	assertionPopUps = assertionPopUps_;
 	return ret;
 }
 
-void Platform::Assert(const char *c, const char *file, int line) {
+void Platform::Assert(const char *c, const char *file, int line) noexcept {
 	char buffer[2000];
 	g_snprintf(buffer, sizeof(buffer), "Assertion [%s] failed at %s %d\r\n", c, file, line);
 	Platform::DebugDisplay(buffer);


Modified: scintilla/gtk/ScintillaGTK.cxx
639 lines changed, 372 insertions(+), 267 deletions(-)
===================================================================
@@ -14,8 +14,11 @@
 #include <stdexcept>
 #include <new>
 #include <string>
+#include <string_view>
 #include <vector>
 #include <map>
+#include <set>
+#include <optional>
 #include <algorithm>
 #include <memory>
 
@@ -35,14 +38,19 @@
 #include <windows.h>
 #endif
 
-#include "Platform.h"
-
+#include "ScintillaTypes.h"
+#include "ScintillaMessages.h"
+#include "ScintillaStructures.h"
 #include "ILoader.h"
 #include "ILexer.h"
+
+#include "Debugging.h"
+#include "Geometry.h"
+#include "Platform.h"
+
 #include "Scintilla.h"
 #include "ScintillaWidget.h"
-#include "StringCopy.h"
-#include "CharacterCategory.h"
+#include "CharacterCategoryMap.h"
 #include "Position.h"
 #include "UniqueString.h"
 #include "SplitVector.h"
@@ -85,33 +93,23 @@
 #define SC_INDICATOR_CONVERTED INDICATOR_IME+2
 #define SC_INDICATOR_UNKNOWN INDICATOR_IME_MAX
 
-static GdkWindow *WindowFromWidget(GtkWidget *w) noexcept {
-	return gtk_widget_get_window(w);
-}
-
-#ifdef _MSC_VER
-// Constant conditional expressions are because of GTK+ headers
-#pragma warning(disable: 4127)
-// Ignore unreferenced local functions in GTK+ headers
-#pragma warning(disable: 4505)
-#endif
-
 using namespace Scintilla;
+using namespace Scintilla::Internal;
 
-static GdkWindow *PWindow(const Window &w) noexcept {
-	GtkWidget *widget = static_cast<GtkWidget *>(w.GetID());
-	return gtk_widget_get_window(widget);
-}
+// From PlatGTK.cxx
+extern std::string UTF8FromLatin1(std::string_view text);
+extern void Platform_Initialise();
+extern void Platform_Finalise();
 
-extern std::string UTF8FromLatin1(const char *s, int len);
+namespace {
 
 enum {
 	COMMAND_SIGNAL,
 	NOTIFY_SIGNAL,
 	LAST_SIGNAL
 };
 
-static gint scintilla_signals[LAST_SIGNAL] = { 0 };
+gint scintilla_signals[LAST_SIGNAL] = { 0 };
 
 enum {
 	TARGET_STRING,
@@ -121,31 +119,88 @@ enum {
 	TARGET_URI
 };
 
-GdkAtom ScintillaGTK::atomUTF8 = nullptr;
-GdkAtom ScintillaGTK::atomUTF8Mime = nullptr;
-GdkAtom ScintillaGTK::atomString = nullptr;
-GdkAtom ScintillaGTK::atomUriList = nullptr;
-GdkAtom ScintillaGTK::atomDROPFILES_DND = nullptr;
-
-static const GtkTargetEntry clipboardCopyTargets[] = {
+const GtkTargetEntry clipboardCopyTargets[] = {
 	{ (gchar *) "UTF8_STRING", 0, TARGET_UTF8_STRING },
 	{ (gchar *) "STRING", 0, TARGET_STRING },
 };
-static constexpr gint nClipboardCopyTargets = ELEMENTS(clipboardCopyTargets);
+constexpr gint nClipboardCopyTargets = static_cast<gint>(std::size(clipboardCopyTargets));
 
-static const GtkTargetEntry clipboardPasteTargets[] = {
+const GtkTargetEntry clipboardPasteTargets[] = {
 	{ (gchar *) "text/uri-list", 0, TARGET_URI },
 	{ (gchar *) "UTF8_STRING", 0, TARGET_UTF8_STRING },
 	{ (gchar *) "STRING", 0, TARGET_STRING },
 };
-static constexpr gint nClipboardPasteTargets = ELEMENTS(clipboardPasteTargets);
+constexpr gint nClipboardPasteTargets = static_cast<gint>(std::size(clipboardPasteTargets));
 
-static const GdkDragAction actionCopyOrMove = static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE);
+const GdkDragAction actionCopyOrMove = static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE);
+
+GdkWindow *WindowFromWidget(GtkWidget *w) noexcept {
+	return gtk_widget_get_window(w);
+}
 
-static GtkWidget *PWidget(const Window &w) noexcept {
+GtkWidget *PWidget(const Window &w) noexcept {
 	return static_cast<GtkWidget *>(w.GetID());
 }
 
+GdkWindow *PWindow(const Window &w) noexcept {
+	GtkWidget *widget = static_cast<GtkWidget *>(w.GetID());
+	return gtk_widget_get_window(widget);
+}
+
+void UnRefCursor(GdkCursor *cursor) noexcept {
+#if GTK_CHECK_VERSION(3,0,0)
+	g_object_unref(cursor);
+#else
+	gdk_cursor_unref(cursor);
+#endif
+}
+
+void MapWidget(GtkWidget *widget) noexcept {
+	if (widget &&
+		gtk_widget_get_visible(GTK_WIDGET(widget)) &&
+		!IS_WIDGET_MAPPED(widget)) {
+		gtk_widget_map(widget);
+	}
+}
+
+const guchar *DataOfGSD(GtkSelectionData *sd) noexcept {
+	return gtk_selection_data_get_data(sd);
+}
+
+gint LengthOfGSD(GtkSelectionData *sd) noexcept {
+	return gtk_selection_data_get_length(sd);
+}
+
+GdkAtom TypeOfGSD(GtkSelectionData *sd) noexcept {
+	return gtk_selection_data_get_data_type(sd);
+}
+
+GdkAtom SelectionOfGSD(GtkSelectionData *sd) noexcept {
+	return gtk_selection_data_get_selection(sd);
+}
+
+}
+
+FontOptions::FontOptions(GtkWidget *widget) noexcept {
+	PangoContext *pcontext = gtk_widget_create_pango_context(widget);
+	PLATFORM_ASSERT(pcontext);
+	const cairo_font_options_t *options = pango_cairo_context_get_font_options(pcontext);
+	// options is owned by the PangoContext so must not be freed.
+	if (options) {
+		// options is NULL on Win32
+		antialias = cairo_font_options_get_antialias(options);
+		order = cairo_font_options_get_subpixel_order(options);
+		hint = cairo_font_options_get_hint_style(options);
+	}
+	g_object_unref(pcontext);
+}
+
+bool FontOptions::operator==(const FontOptions &other) const noexcept {
+	return antialias == other.antialias &&
+		order == other.order &&
+		hint == other.hint;
+}
+
 ScintillaGTK *ScintillaGTK::FromWidget(GtkWidget *widget) noexcept {
 	ScintillaObject *scio = SCINTILLA(widget);
 	return static_cast<ScintillaGTK *>(scio->pscin);
@@ -182,7 +237,7 @@ ScintillaGTK::ScintillaGTK(_ScintillaObject *sci_) :
 	// There does not seem to be a real standard for indicating that the clipboard
 	// contains a rectangular selection, so copy Developer Studio.
 	cfColumnSelect = static_cast<CLIPFORMAT>(
-				 ::RegisterClipboardFormat("MSDEVColumnSelect"));
+				 ::RegisterClipboardFormatW(L"MSDEVColumnSelect"));
 
 	// Get intellimouse parameters when running on win32; otherwise use
 	// reasonable default
@@ -193,6 +248,7 @@ ScintillaGTK::ScintillaGTK(_ScintillaObject *sci_) :
 #else
 	linesPerScroll = 4;
 #endif
+	primarySelection = false;
 
 	Init();
 }
@@ -206,21 +262,14 @@ ScintillaGTK::~ScintillaGTK() {
 		gdk_event_free(evbtn);
 		evbtn = nullptr;
 	}
+	ClearPrimarySelection();
 	wPreedit.Destroy();
 }
 
-static void UnRefCursor(GdkCursor *cursor) noexcept {
-#if GTK_CHECK_VERSION(3,0,0)
-	g_object_unref(cursor);
-#else
-	gdk_cursor_unref(cursor);
-#endif
-}
-
 void ScintillaGTK::RealizeThis(GtkWidget *widget) {
 	//Platform::DebugPrintf("ScintillaGTK::realize this\n");
 	gtk_widget_set_realized(widget, TRUE);
-	GdkWindowAttr attrs;
+	GdkWindowAttr attrs {};
 	attrs.window_type = GDK_WINDOW_CHILD;
 	GtkAllocation allocation;
 	gtk_widget_get_allocation(widget, &allocation);
@@ -292,12 +341,6 @@ void ScintillaGTK::RealizeThis(GtkWidget *widget) {
 	cursor = gdk_cursor_new_for_display(pdisplay, GDK_LEFT_PTR);
 	gdk_window_set_cursor(PWindow(scrollbarh), cursor);
 	UnRefCursor(cursor);
-
-	wSelection = gtk_invisible_new();
-	g_signal_connect(PWidget(wSelection), "selection_get", G_CALLBACK(PrimarySelection), (gpointer) this);
-	g_signal_connect(PWidget(wSelection), "selection_clear_event", G_CALLBACK(PrimaryClear), (gpointer) this);
-	gtk_selection_add_targets(PWidget(wSelection), GDK_SELECTION_PRIMARY,
-				  clipboardCopyTargets, nClipboardCopyTargets);
 }
 
 void ScintillaGTK::Realize(GtkWidget *widget) {
@@ -307,9 +350,6 @@ void ScintillaGTK::Realize(GtkWidget *widget) {
 
 void ScintillaGTK::UnRealizeThis(GtkWidget *widget) {
 	try {
-		gtk_selection_clear_targets(PWidget(wSelection), GDK_SELECTION_PRIMARY);
-		wSelection.Destroy();
-
 		if (IS_WIDGET_MAPPED(widget)) {
 			gtk_widget_unmap(widget);
 		}
@@ -328,7 +368,7 @@ void ScintillaGTK::UnRealizeThis(GtkWidget *widget) {
 
 		Finalise();
 	} catch (...) {
-		errorStatus = SC_STATUS_FAILURE;
+		errorStatus = Status::Failure;
 	}
 }
 
@@ -337,28 +377,20 @@ void ScintillaGTK::UnRealize(GtkWidget *widget) {
 	sciThis->UnRealizeThis(widget);
 }
 
-static void MapWidget(GtkWidget *widget) noexcept {
-	if (widget &&
-			gtk_widget_get_visible(GTK_WIDGET(widget)) &&
-			!IS_WIDGET_MAPPED(widget)) {
-		gtk_widget_map(widget);
-	}
-}
-
 void ScintillaGTK::MapThis() {
 	try {
 		//Platform::DebugPrintf("ScintillaGTK::map this\n");
 		gtk_widget_set_mapped(PWidget(wMain), TRUE);
 		MapWidget(PWidget(wText));
 		MapWidget(PWidget(scrollbarh));
 		MapWidget(PWidget(scrollbarv));
-		wMain.SetCursor(Window::cursorArrow);
-		scrollbarv.SetCursor(Window::cursorArrow);
-		scrollbarh.SetCursor(Window::cursorArrow);
+		wMain.SetCursor(Window::Cursor::arrow);
+		scrollbarv.SetCursor(Window::Cursor::arrow);
+		scrollbarh.SetCursor(Window::Cursor::arrow);
 		ChangeSize();
 		gdk_window_show(PWindow(wMain));
 	} catch (...) {
-		errorStatus = SC_STATUS_FAILURE;
+		errorStatus = Status::Failure;
 	}
 }
 
@@ -371,15 +403,15 @@ void ScintillaGTK::UnMapThis() {
 	try {
 		//Platform::DebugPrintf("ScintillaGTK::unmap this\n");
 		gtk_widget_set_mapped(PWidget(wMain), FALSE);
-		DropGraphics(false);
+		DropGraphics();
 		gdk_window_hide(PWindow(wMain));
 		gtk_widget_unmap(PWidget(wText));
 		if (PWidget(scrollbarh))
 			gtk_widget_unmap(PWidget(scrollbarh));
 		if (PWidget(scrollbarv))
 			gtk_widget_unmap(PWidget(scrollbarv));
 	} catch (...) {
-		errorStatus = SC_STATUS_FAILURE;
+		errorStatus = Status::Failure;
 	}
 }
 
@@ -396,12 +428,12 @@ void ScintillaGTK::ForAll(GtkCallback callback, gpointer callback_data) {
 		if (PWidget(scrollbarh))
 			(*callback)(PWidget(scrollbarh), callback_data);
 	} catch (...) {
-		errorStatus = SC_STATUS_FAILURE;
+		errorStatus = Status::Failure;
 	}
 }
 
 void ScintillaGTK::MainForAll(GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data) {
-	ScintillaGTK *sciThis = FromWidget((GtkWidget *)container);
+	ScintillaGTK *sciThis = FromWidget(GTK_WIDGET(container));
 
 	if (callback && include_internals) {
 		sciThis->ForAll(callback, callback_data);
@@ -423,7 +455,7 @@ class PreEditString {
 	explicit PreEditString(GtkIMContext *im_context) noexcept {
 		gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos);
 		validUTF8 = g_utf8_validate(str, strlen(str), nullptr);
-		uniStr = g_utf8_to_ucs4_fast(str, strlen(str), &uniStrLen);
+		uniStr = g_utf8_to_ucs4_fast(str, static_cast<glong>(strlen(str)), &uniStrLen);
 		pscript = g_unichar_get_script(uniStr[0]);
 	}
 	// Deleted so PreEditString objects can not be copied.
@@ -462,7 +494,7 @@ gint ScintillaGTK::FocusInThis(GtkWidget *) {
 			}
 		}
 	} catch (...) {
-		errorStatus = SC_STATUS_FAILURE;
+		errorStatus = Status::Failure;
 	}
 	return FALSE;
 }
@@ -482,7 +514,7 @@ gint ScintillaGTK::FocusOutThis(GtkWidget *) {
 			gtk_im_context_focus_out(im_context);
 
 	} catch (...) {
-		errorStatus = SC_STATUS_FAILURE;
+		errorStatus = Status::Failure;
 	}
 	return FALSE;
 }
@@ -536,7 +568,7 @@ void ScintillaGTK::SizeAllocate(GtkWidget *widget, GtkAllocation *allocation) {
 		sciThis->Resize(allocation->width, allocation->height);
 
 	} catch (...) {
-		sciThis->errorStatus = SC_STATUS_FAILURE;
+		sciThis->errorStatus = Status::Failure;
 	}
 }
 
@@ -655,19 +687,21 @@ void ScintillaGTK::Init() {
 		caret.period = 0;
 	}
 
-	for (TickReason tr = tickCaret; tr <= tickDwell; tr = static_cast<TickReason>(tr + 1)) {
-		timers[tr].reason = tr;
+	for (size_t tr = static_cast<size_t>(TickReason::caret); tr <= static_cast<size_t>(TickReason::dwell); tr++) {
+		timers[tr].reason = static_cast<TickReason>(tr);
 		timers[tr].scintilla = this;
 	}
-	vs.indicators[SC_INDICATOR_UNKNOWN] = Indicator(INDIC_HIDDEN, ColourDesired(0, 0, 0xff));
-	vs.indicators[SC_INDICATOR_INPUT] = Indicator(INDIC_DOTS, ColourDesired(0, 0, 0xff));
-	vs.indicators[SC_INDICATOR_CONVERTED] = Indicator(INDIC_COMPOSITIONTHICK, ColourDesired(0, 0, 0xff));
-	vs.indicators[SC_INDICATOR_TARGET] = Indicator(INDIC_STRAIGHTBOX, ColourDesired(0, 0, 0xff));
+	vs.indicators[SC_INDICATOR_UNKNOWN] = Indicator(IndicatorStyle::Hidden, ColourRGBA(0, 0, 0xff));
+	vs.indicators[SC_INDICATOR_INPUT] = Indicator(IndicatorStyle::Dots, ColourRGBA(0, 0, 0xff));
+	vs.indicators[SC_INDICATOR_CONVERTED] = Indicator(IndicatorStyle::CompositionThick, ColourRGBA(0, 0, 0xff));
+	vs.indicators[SC_INDICATOR_TARGET] = Indicator(IndicatorStyle::StraightBox, ColourRGBA(0, 0, 0xff));
+
+	fontOptionsPrevious = FontOptions(PWidget(wText));
 }
 
 void ScintillaGTK::Finalise() {
-	for (TickReason tr = tickCaret; tr <= tickDwell; tr = static_cast<TickReason>(tr + 1)) {
-		FineTickerCancel(tr);
+	for (size_t tr = static_cast<size_t>(TickReason::caret); tr <= static_cast<size_t>(TickReason::dwell); tr++) {
+		FineTickerCancel(static_cast<TickReason>(tr));
 	}
 	if (accessible) {
 		gtk_accessible_set_widget(GTK_ACCESSIBLE(accessible), nullptr);
@@ -679,28 +713,29 @@ void ScintillaGTK::Finalise() {
 }
 
 bool ScintillaGTK::AbandonPaint() {
-	if ((paintState == painting) && !paintingAllText) {
+	if ((paintState == PaintState::painting) && !paintingAllText) {
 		repaintFullWindow = true;
 	}
 	return false;
 }
 
 void ScintillaGTK::DisplayCursor(Window::Cursor c) {
-	if (cursorMode == SC_CURSORNORMAL)
+	if (cursorMode == CursorShape::Normal)
 		wText.SetCursor(c);
 	else
 		wText.SetCursor(static_cast<Window::Cursor>(cursorMode));
 }
 
 bool ScintillaGTK::DragThreshold(Point ptStart, Point ptNow) {
 	return gtk_drag_check_threshold(GTK_WIDGET(PWidget(wMain)),
-					ptStart.x, ptStart.y, ptNow.x, ptNow.y);
+		static_cast<gint>(ptStart.x), static_cast<gint>(ptStart.y),
+		static_cast<gint>(ptNow.x), static_cast<gint>(ptNow.y));
 }
 
 void ScintillaGTK::StartDrag() {
 	PLATFORM_ASSERT(evbtn);
 	dragWasDropped = false;
-	inDragDrop = ddDragging;
+	inDragDrop = DragDrop::dragging;
 	GtkTargetList *tl = gtk_target_list_new(clipboardCopyTargets, nClipboardCopyTargets);
 #if GTK_CHECK_VERSION(3,10,0)
 	gtk_drag_begin_with_coordinates(GTK_WIDGET(PWidget(wMain)),
@@ -718,7 +753,8 @@ void ScintillaGTK::StartDrag() {
 #endif
 }
 
-namespace Scintilla {
+namespace Scintilla::Internal {
+
 std::string ConvertText(const char *s, size_t len, const char *charSetDest,
 			const char *charSetSource, bool transliterations, bool silent) {
 	// s is not const because of different versions of iconv disagreeing about const
@@ -737,7 +773,7 @@ std::string ConvertText(const char *s, size_t len, const char *charSetDest,
 			if (!silent) {
 				if (len == 1)
 					fprintf(stderr, "iconv %s->%s failed for %0x '%s'\n",
-						charSetSource, charSetDest, (unsigned char)(*s), s);
+						charSetSource, charSet@@ Diff output truncated at 100000 characters. @@

--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).


More information about the Commits mailing list