Branch: refs/heads/master Author: Thomas Martitz thomas.martitz@mailbox.org Committer: GitHub noreply@github.com Date: Wed, 04 Oct 2023 20:48:02 UTC Commit: 4af1965d3435af338382c6de33c028b52e2f1a5f https://github.com/geany/geany/commit/4af1965d3435af338382c6de33c028b52e2f1a...
Log Message: ----------- Merge pull request #3551 from kugel-/scintilla
* Update Scintilla to version 5.3.7 and Lexilla to 5.2.7 * Implement change bar feature and enable by default * New styling options for python, R and Ruby
Modified Paths: -------------- data/filedefs/filetypes.gdscript data/filedefs/filetypes.python.in data/filedefs/filetypes.r data/geany.glade meson.build scintilla/Makefile.am scintilla/README scintilla/gtk/Converter.h scintilla/gtk/PlatGTK.cxx scintilla/gtk/ScintillaGTK.cxx scintilla/gtk/ScintillaGTK.h scintilla/gtk/ScintillaGTKAccessible.cxx scintilla/gtk/Wrappers.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/lexilla/include/Lexilla.h scintilla/lexilla/include/SciLexer.h scintilla/lexilla/lexers/LexBash.cxx scintilla/lexilla/lexers/LexBatch.cxx scintilla/lexilla/lexers/LexCPP.cxx scintilla/lexilla/lexers/LexCmake.cxx scintilla/lexilla/lexers/LexCoffeeScript.cxx scintilla/lexilla/lexers/LexDiff.cxx scintilla/lexilla/lexers/LexGDScript.cxx scintilla/lexilla/lexers/LexHTML.cxx scintilla/lexilla/lexers/LexJulia.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/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/LexVHDL.cxx scintilla/lexilla/lexers/LexVerilog.cxx scintilla/lexilla/lexers/LexYAML.cxx scintilla/lexilla/lexlib/CatalogueModules.h scintilla/lexilla/lexlib/CharacterCategory.cxx scintilla/lexilla/lexlib/CharacterSet.h scintilla/lexilla/lexlib/DefaultLexer.cxx scintilla/lexilla/lexlib/LexAccessor.cxx scintilla/lexilla/lexlib/LexAccessor.h scintilla/lexilla/lexlib/LexerModule.cxx scintilla/lexilla/lexlib/LexerModule.h scintilla/lexilla/lexlib/OptionSet.h scintilla/lexilla/lexlib/PropSetSimple.cxx 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/scintilla_changes.patch scintilla/src/CallTip.cxx scintilla/src/CallTip.h scintilla/src/CaseConvert.cxx scintilla/src/CaseFolder.cxx scintilla/src/CaseFolder.h scintilla/src/CellBuffer.cxx scintilla/src/CellBuffer.h scintilla/src/ChangeHistory.cxx scintilla/src/ChangeHistory.h scintilla/src/CharacterCategoryMap.cxx scintilla/src/ContractionState.cxx scintilla/src/ContractionState.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/Geometry.cxx scintilla/src/Geometry.h scintilla/src/Indicator.cxx scintilla/src/KeyMap.cxx scintilla/src/KeyMap.h scintilla/src/LineMarker.cxx 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/PositionCache.cxx scintilla/src/PositionCache.h scintilla/src/RESearch.cxx scintilla/src/RESearch.h scintilla/src/RunStyles.cxx scintilla/src/RunStyles.h scintilla/src/ScintillaBase.cxx scintilla/src/ScintillaBase.h 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/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/editor.c src/editor.h src/highlightingmappings.h src/keyfile.c src/plugindata.h
Modified: data/filedefs/filetypes.gdscript 3 lines changed, 2 insertions(+), 1 deletions(-) =================================================================== @@ -16,7 +16,8 @@ identifier=identifier_1 commentblock=comment stringeol=string_eol word2=keyword_2 -decorator=decorator +annotation=annotation +notepath=string_2
[keywords] # all items must be in one line
Modified: data/filedefs/filetypes.python.in 3 lines changed, 3 insertions(+), 0 deletions(-) =================================================================== @@ -21,6 +21,7 @@ fstring=string_1 fcharacter=character ftriple=string_2 ftripledouble=string_2 +attribute=identifier_1
[keywords] # all items must be in one line @@ -34,6 +35,8 @@ identifiers=ArithmeticError AssertionError AttributeError BaseException Blocking [lexer_properties] fold.quotes.python=1 lexer.python.keywords2.no.sub.identifiers=1 +lexer.python.identifier.attributes=1 +lexer.python.identifier.decorator=1
[settings] # default extension used when saving files
Modified: data/filedefs/filetypes.r 9 lines changed, 8 insertions(+), 1 deletions(-) =================================================================== @@ -13,6 +13,10 @@ string2=string_2 identifier=identifier infix=function infixeol=function +backticks=backticks +stringraw=string_2 +stringraw=string_2 +escapesequence=string_1
[keywords] # all items must be in one line @@ -23,6 +27,10 @@ primary=attach break detach else for function if in library new next repeat requ package=F FALSE Inf NA NA_integer_ NA_real_ NA_character_ NA_complex_ NaN NULL T TRUE package_other=
+[lexer_properties] +# https://github.com/ScintillaOrg/lexilla/issues/206 +#lexer.r.escape.sequence=1 + [settings] # default extension used when saving files extension=R @@ -52,4 +60,3 @@ context_action_cmd= #width=4 # 0 is spaces, 1 is tabs, 2 is tab & spaces #type=1 -
Modified: data/geany.glade 63 lines changed, 63 insertions(+), 0 deletions(-) =================================================================== @@ -4294,6 +4294,69 @@ <property name="position">2</property> </packing> </child> + <child> + <object class="GtkFrame"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="label-xalign">0</property> + <property name="shadow-type">none</property> + <child> + <object class="GtkAlignment"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="left-padding">12</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkCheckButton" id="check_change_history_markers"> + <property name="label" translatable="yes">Show in markers margin</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">False</property> + <property name="draw-indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="check_change_history_indicators"> + <property name="label" translatable="yes">Show as underline indicators</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">False</property> + <property name="draw-indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label252"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="label" translatable="yes"><b>Change History</b></property> + <property name="use-markup">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> </object> <packing> <property name="position">3</property>
Modified: meson.build 3 lines changed, 3 insertions(+), 0 deletions(-) =================================================================== @@ -347,6 +347,7 @@ scintilla = static_library('scintilla', 'scintilla/gtk/ScintillaGTK.h', 'scintilla/gtk/scintilla-marshal.c', 'scintilla/gtk/scintilla-marshal.h', + 'scintilla/gtk/Wrappers.h', 'scintilla/include/ILexer.h', 'scintilla/include/ILoader.h', 'scintilla/include/ScintillaCall.h', @@ -366,6 +367,8 @@ scintilla = static_library('scintilla', 'scintilla/src/CaseFolder.h', 'scintilla/src/CellBuffer.cxx', 'scintilla/src/CellBuffer.h', + 'scintilla/src/ChangeHistory.cxx', + 'scintilla/src/ChangeHistory.h', 'scintilla/src/CharacterCategoryMap.cxx', 'scintilla/src/CharacterCategoryMap.h', 'scintilla/src/CharacterType.cxx',
Modified: scintilla/Makefile.am 3 lines changed, 3 insertions(+), 0 deletions(-) =================================================================== @@ -110,6 +110,7 @@ gtk/ScintillaGTKAccessible.cxx \ gtk/ScintillaGTKAccessible.h \ gtk/scintilla-marshal.c \ gtk/scintilla-marshal.h \ +gtk/Wrappers.h \ src/AutoComplete.cxx \ src/AutoComplete.h \ src/CallTip.cxx \ @@ -120,6 +121,8 @@ src/CaseFolder.cxx \ src/CaseFolder.h \ src/CellBuffer.cxx \ src/CellBuffer.h \ +src/ChangeHistory.cxx \ +src/ChangeHistory.h \ src/CharacterCategoryMap.cxx \ src/CharacterCategoryMap.h \ src/CharacterType.cxx \
Modified: scintilla/README 98 lines changed, 87 insertions(+), 11 deletions(-) =================================================================== @@ -1,16 +1,92 @@ -These files are from the Scintilla project, http://www.scintilla.org. +README for building of Scintilla, Lexilla, and SciTE
-See License.txt for the Scintilla license. +Scintilla and Lexilla can be built by themselves. +To build SciTE, Scintilla and Lexilla should first be built.
-We try to keep these files in sync with the official project; any -changes should be sent there first. Otherwise changes could cause -conflicts when we next update Scintilla. +See lexilla/README for information on building Lexilla.
+*** GTK+/Linux version ***
-Public header constants (include/*.h) -------------------------------------- -You should not add constants in header files - instead use -Scintilla.iface and HFacer.py. +You must first have GTK+ 2.24 or later and GCC (7.1 or better) installed. +Clang may be used by adding CLANG=1 to the make command line. +Other C++ compilers may work but may require tweaking the make file. +Either GTK+ 2.x or 3.x may be used with 2.x the default and 3.x +chosen with the make argument GTK3=1.
-Do not change the value of constants in header files as this will -break Scintilla's ABI. +To build Scintilla, use the makefile located in the scintilla/gtk directory + cd scintilla/gtk + make + cd ../.. + +To build and install SciTE, use the makefile located in the scite/gtk directory + cd scite/gtk + make + sudo make install + +This installs SciTE into $prefix/bin. The value of $prefix is determined from +the location of Gnome if it is installed. This is usually /usr if installed +with Linux or /usr/local if built from source. If Gnome is not installed +/usr/bin is used as the prefix. The prefix can be overridden on the command +line like "make prefix=/opt" but the same value should be used for both make +and make install as this location is compiled into the executable. The global +properties file is installed at $prefix/share/scite/SciTEGlobal.properties. +The language specific properties files are also installed into this directory. + +To remove SciTE + sudo make uninstall + +To clean the object files which may be needed to change $prefix + make clean + +The current make file supports static and dynamic linking between SciTE, Scintilla, and Lexilla. + + +*** Windows version *** + +A C++ 17 compiler is required. +Visual Studio 2019 is the development system used for most development +although Mingw-w64 9.2 is also supported. + +To build Scintilla, make in the scintilla/win32 directory + cd scintilla\win32 +GCC: mingw32-make +Visual C++: nmake -f scintilla.mak + cd .... + +To build SciTE, use the makefiles located in the scite/win32 directory + cd scite\win32 +GCC: mingw32-make +Visual C++: nmake -f scite.mak + +An executable SciTE will now be in scite/bin. + +*** GTK+/Windows version *** + +Mingw-w64 is known to work. Other compilers will probably not work. + +Only Scintilla will build with GTK+ on Windows. SciTE will not work. + +Make builds both a static library version of Scintilla with lexers (scintilla.a) and +a shared library without lexers (libscintilla.so or or libscintilla.dll). + +To build Scintilla, make in the scintilla/gtk directory + cd scintilla\gtk + mingw32-make + +*** macOS Cocoa version *** + +Xcode 9.2 or later may be used to build Scintilla on macOS. + +There is no open source version of SciTE for macOS but there is a commercial +version available through the App Store. + +To build Scintilla, run xcodebuild in the scintilla/cocoa/ScintillaFramework or +scintilla/cocoa/Scintilla directory + + cd cocoa/Scintilla + + xcodebuild + +*** Qt version *** + +See the qt/README file to build Scintilla with Qt.
Modified: scintilla/gtk/Converter.h 7 lines changed, 2 insertions(+), 5 deletions(-) =================================================================== @@ -14,19 +14,16 @@ const gsize sizeFailure = static_cast<gsize>(-1); * Encapsulate g_iconv safely. */ class Converter { - GIConv iconvh; + GIConv iconvh = iconvhBad; void OpenHandle(const char *fullDestination, const char *charSetSource) noexcept { iconvh = g_iconv_open(fullDestination, charSetSource); } bool Succeeded() const noexcept { return iconvh != iconvhBad; } public: - Converter() noexcept { - iconvh = iconvhBad; - } + Converter() noexcept = default; Converter(const char *charSetDestination, const char *charSetSource, bool transliterations) { - iconvh = iconvhBad; Open(charSetDestination, charSetSource, transliterations); } // Deleted so Converter objects can not be copied.
Modified: scintilla/gtk/PlatGTK.cxx 497 lines changed, 261 insertions(+), 236 deletions(-) =================================================================== @@ -39,6 +39,7 @@ #include "XPM.h" #include "UniConversion.h"
+#include "Wrappers.h" #include "Converter.h"
#ifdef _MSC_VER @@ -55,17 +56,6 @@ 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. - -constexpr int pangoUnitsFromDouble(double d) noexcept { - return static_cast<int>(d * PANGO_SCALE + 0.5); -} - -constexpr float floatFromPangoUnits(int pu) noexcept { - return static_cast<float>(pu) / PANGO_SCALE; -} - struct IntegerRectangle { int left; int top; @@ -80,48 +70,38 @@ struct IntegerRectangle { int Height() const noexcept { return bottom - top; } };
-GdkWindow *WindowFromWidget(GtkWidget *w) noexcept { - return gtk_widget_get_window(w); -} - GtkWidget *PWidget(WindowID wid) noexcept { return static_cast<GtkWidget *>(wid); }
+void SetFractionalPositions([[maybe_unused]] PangoContext *pcontext) noexcept { +#if PANGO_VERSION_CHECK(1,44,3) + pango_context_set_round_glyph_positions(pcontext, FALSE); +#endif +} + +void LayoutSetText(PangoLayout *layout, std::string_view text) noexcept { + pango_layout_set_text(layout, text.data(), static_cast<int>(text.length())); +} + enum class EncodingType { singleByte, utf8, dbcs };
// Holds a PangoFontDescription*. class FontHandle : public Font { public: - PangoFontDescription *pfd = nullptr; + UniquePangoFontDescription fd; CharacterSet characterSet; - FontHandle() noexcept : pfd(nullptr), characterSet(CharacterSet::Ansi) { - } - 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, + explicit FontHandle(const FontParameters &fp) : + fd(pango_font_description_new()), characterSet(fp.characterSet) { + if (fd) { + pango_font_description_set_family(fd.get(), (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); + pango_font_description_set_size(fd.get(), pango_units_from_double(fp.size)); + pango_font_description_set_weight(fd.get(), static_cast<PangoWeight>(fp.weight)); + pango_font_description_set_style(fd.get(), 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; - FontHandle &operator=(const FontHandle &) = delete; - FontHandle &operator=(FontHandle &&) = delete; - ~FontHandle() override { - if (pfd) - pango_font_description_free(pfd); - pfd = nullptr; } + ~FontHandle() override = default; };
// X has a 16 bit coordinate space, so stop drawing here to avoid wrapping @@ -137,7 +117,6 @@ 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* @@ -146,13 +125,18 @@ class SurfaceImpl : public Surface { EncodingType et= EncodingType::singleByte; WindowID widSave = nullptr; cairo_t *context = nullptr; - cairo_surface_t *psurf = nullptr; + UniqueCairo cairoOwned; + UniqueCairoSurface surf; bool inited = false; - bool createdGC = false; - PangoContext *pcontext = nullptr; - PangoLayout *layout = nullptr; + UniquePangoContext pcontext; + double resolution = 1.0; + PangoDirection direction = PANGO_DIRECTION_LTR; + const cairo_font_options_t *fontOptions = nullptr; + PangoLanguage *language = nullptr; + UniquePangoLayout layout; Converter conv; CharacterSet characterSet = static_cast<CharacterSet>(-1); + void PenColourAlpha(ColourRGBA fore) noexcept; void SetConverter(CharacterSet characterSet_); void CairoRectangle(PRectangle rc) noexcept; @@ -164,15 +148,17 @@ class SurfaceImpl : public Surface { SurfaceImpl(SurfaceImpl&&) = delete; SurfaceImpl&operator=(const SurfaceImpl&) = delete; SurfaceImpl&operator=(SurfaceImpl&&) = delete; - ~SurfaceImpl() override; + ~SurfaceImpl() override = default; + + void GetContextState() noexcept; + UniquePangoContext MeasuringContext();
void Init(WindowID wid) override; void Init(SurfaceID sid, WindowID wid) override; std::unique_ptr<Surface> AllocatePixMap(int width, int height) override;
void SetMode(SurfaceMode mode_) override;
- void Clear() noexcept; void Release() noexcept override; int SupportsFeature(Supports feature) noexcept override; bool Initialised() override; @@ -228,6 +214,7 @@ const Supports SupportsGTK[] = { Supports::FractionalStrokeWidth, Supports::TranslucentStroke, Supports::PixelModification, + Supports::ThreadSafeMeasureWidths, };
} @@ -310,52 +297,39 @@ 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( + surf.reset(cairo_surface_create_similar( psurfContext, - CAIRO_CONTENT_COLOR_ALPHA, width, height); - context = cairo_create(psurf); - pcontext = gtk_widget_create_pango_context(PWidget(wid)); + CAIRO_CONTENT_COLOR_ALPHA, width, height)); + cairoOwned.reset(cairo_create(surf.get())); + context = cairoOwned.get(); + pcontext.reset(gtk_widget_create_pango_context(PWidget(wid))); PLATFORM_ASSERT(pcontext); - layout = pango_layout_new(pcontext); + SetFractionalPositions(pcontext.get()); + GetContextState(); + layout.reset(pango_layout_new(pcontext.get())); 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 { +void SurfaceImpl::Release() noexcept { et = EncodingType::singleByte; - if (createdGC) { - createdGC = false; - cairo_destroy(context); - } + cairoOwned.reset(); context = nullptr; - if (psurf) - cairo_surface_destroy(psurf); - psurf = nullptr; - if (layout) - g_object_unref(layout); - layout = nullptr; - if (pcontext) - g_object_unref(pcontext); - pcontext = nullptr; + surf.reset(); + layout.reset(); + // fontOptions and language are owned by original context and don't need to be freed + fontOptions = nullptr; + language = nullptr; + pcontext.reset(); conv.Close(); characterSet = static_cast<CharacterSet>(-1); inited = false; - createdGC = false; -} - -void SurfaceImpl::Release() noexcept { - Clear(); }
bool SurfaceImpl::Initialised() { @@ -378,17 +352,39 @@ bool SurfaceImpl::Initialised() { return inited; }
+void SurfaceImpl::GetContextState() noexcept { + resolution = pango_cairo_context_get_resolution(pcontext.get()); + direction = pango_context_get_base_dir(pcontext.get()); + fontOptions = pango_cairo_context_get_font_options(pcontext.get()); + language = pango_context_get_language(pcontext.get()); +} + +UniquePangoContext SurfaceImpl::MeasuringContext() { + UniquePangoFontMap fmMeasure(pango_cairo_font_map_get_default()); + PLATFORM_ASSERT(fmMeasure); + UniquePangoContext contextMeasure(pango_font_map_create_context(fmMeasure.release())); + PLATFORM_ASSERT(contextMeasure); + SetFractionalPositions(contextMeasure.get()); + + pango_cairo_context_set_resolution(contextMeasure.get(), resolution); + pango_context_set_base_dir(contextMeasure.get(), direction); + pango_cairo_context_set_font_options(contextMeasure.get(), fontOptions); + pango_context_set_language(contextMeasure.get(), language); + + return contextMeasure; +} + 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 - psurf = nullptr; context = nullptr; - createdGC = false; - pcontext = gtk_widget_create_pango_context(PWidget(wid)); + pcontext.reset(gtk_widget_create_pango_context(PWidget(wid))); PLATFORM_ASSERT(pcontext); - layout = pango_layout_new(pcontext); + SetFractionalPositions(pcontext.get()); + GetContextState(); + layout.reset(pango_layout_new(pcontext.get())); PLATFORM_ASSERT(layout); inited = true; } @@ -398,13 +394,15 @@ void SurfaceImpl::Init(SurfaceID sid, WindowID wid) { PLATFORM_ASSERT(sid); Release(); PLATFORM_ASSERT(wid); - context = cairo_reference(static_cast<cairo_t *>(sid)); - pcontext = gtk_widget_create_pango_context(PWidget(wid)); + cairoOwned.reset(cairo_reference(static_cast<cairo_t *>(sid))); + context = cairoOwned.get(); + pcontext.reset(gtk_widget_create_pango_context(PWidget(wid))); + SetFractionalPositions(pcontext.get()); // update the Pango context in case sid isn't the widget's surface - pango_cairo_update_context(context, pcontext); - layout = pango_layout_new(pcontext); + pango_cairo_update_context(context, pcontext.get()); + GetContextState(); + layout.reset(pango_layout_new(pcontext.get())); cairo_set_line_width(context, 1); - createdGC = true; inited = true; }
@@ -519,9 +517,9 @@ void SurfaceImpl::FillRectangleAligned(PRectangle rc, Fill fill) {
void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) { SurfaceImpl &surfi = dynamic_cast<SurfaceImpl &>(surfacePattern); - if (context && surfi.psurf) { + if (context && surfi.surf) { // Tile pattern over rectangle - cairo_set_source_surface(context, surfi.psurf, rc.left, rc.top); + cairo_set_source_surface(context, surfi.surf.get(), rc.left, rc.top); cairo_pattern_set_extend(cairo_get_source(context), CAIRO_EXTEND_REPEAT); cairo_rectangle(context, rc.left, rc.top, rc.Width(), rc.Height()); cairo_fill(context); @@ -558,8 +556,8 @@ static void PathRoundRectangle(cairo_t *context, double left, double top, double
void SurfaceImpl::AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke) { if (context && rc.Width() > 0) { - const float halfStroke = fillStroke.stroke.width / 2.0f; - const float doubleStroke = fillStroke.stroke.width * 2.0f; + const XYPOSITION halfStroke = fillStroke.stroke.width / 2.0; + const XYPOSITION doubleStroke = fillStroke.stroke.width * 2.0; PenColourAlpha(fillStroke.fill.colour); if (cornerSize > 0) PathRoundRectangle(context, rc.left + fillStroke.stroke.width, rc.top + fillStroke.stroke.width, @@ -609,6 +607,8 @@ void SurfaceImpl::GradientRectangle(PRectangle rc, const std::vector<ColourStop>
void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) { PLATFORM_ASSERT(context); + if (width == 0) + return; if (rc.Width() > width) rc.left += (rc.Width() - width) / 2; rc.right = rc.left + width; @@ -625,12 +625,10 @@ void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsi pixelsImage += RGBAImage::bytesPerPixel * width; }
- cairo_surface_t *psurfImage = cairo_image_surface_create_for_data(&image[0], CAIRO_FORMAT_ARGB32, width, height, stride); - cairo_set_source_surface(context, psurfImage, rc.left, rc.top); + UniqueCairoSurface surfImage(cairo_image_surface_create_for_data(&image[0], CAIRO_FORMAT_ARGB32, width, height, stride)); + cairo_set_source_surface(context, surfImage.get(), rc.left, rc.top); cairo_rectangle(context, rc.left, rc.top, rc.Width(), rc.Height()); cairo_fill(context); - - cairo_surface_destroy(psurfImage); }
void SurfaceImpl::Ellipse(PRectangle rc, FillStroke fillStroke) { @@ -704,10 +702,10 @@ void SurfaceImpl::Stadium(PRectangle rc, FillStroke fillStroke, Ends ends) {
void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) { SurfaceImpl &surfi = static_cast<SurfaceImpl &>(surfaceSource); - const bool canDraw = surfi.psurf != nullptr; + const bool canDraw = surfi.surf != nullptr; if (canDraw) { PLATFORM_ASSERT(context); - cairo_set_source_surface(context, surfi.psurf, + cairo_set_source_surface(context, surfi.surf.get(), rc.left - from.x, rc.top - from.y); cairo_rectangle(context, rc.left, rc.top, rc.Width(), rc.Height()); cairo_fill(context); @@ -778,21 +776,20 @@ void SurfaceImpl::DrawTextBase(PRectangle rc, const Font *font_, XYPOSITION ybas if (context) { PenColourAlpha(fore); const XYPOSITION xText = rc.left; - if (PFont(font_)->pfd) { - std::string utfForm; + if (PFont(font_)->fd) { if (et == EncodingType::utf8) { - pango_layout_set_text(layout, text.data(), text.length()); + LayoutSetText(layout.get(), text); } else { SetConverter(PFont(font_)->characterSet); - utfForm = UTF8FromIconv(conv, text); + std::string 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()); + LayoutSetText(layout.get(), utfForm); } - pango_layout_set_font_description(layout, PFont(font_)->pfd); - pango_cairo_update_layout(context, layout); - PangoLayoutLine *pll = pango_layout_get_line_readonly(layout, 0); + pango_layout_set_font_description(layout.get(), PFont(font_)->fd.get()); + pango_cairo_update_layout(context, layout.get()); + PangoLayoutLine *pll = pango_layout_get_line_readonly(layout.get(), 0); cairo_move_to(context, xText, ybase); pango_cairo_show_layout_line(context, pll); } @@ -823,54 +820,69 @@ void SurfaceImpl::DrawTextTransparent(PRectangle rc, const Font *font_, XYPOSITI } }
+namespace { + class ClusterIterator { - PangoLayoutIter *iter; - PangoRectangle pos; - size_t lenPositions; + UniquePangoLayoutIter iter; + PangoRectangle pos {}; + int lenPositions; public: - bool finished; - XYPOSITION positionStart; - XYPOSITION position; - XYPOSITION distance; - int curIndex; - 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); - } - // Deleted so ClusterIterator objects can not be copied. - ClusterIterator(const ClusterIterator&) = delete; - ClusterIterator(ClusterIterator&&) = delete; - ClusterIterator&operator=(const ClusterIterator&) = delete; - ClusterIterator&operator=(ClusterIterator&&) = delete; - - ~ClusterIterator() { - pango_layout_iter_free(iter); + bool finished = false; + XYPOSITION positionStart = 0.0; + XYPOSITION position = 0.0; + XYPOSITION distance = 0.0; + int curIndex = 0; + ClusterIterator(PangoLayout *layout, std::string_view text) noexcept : + lenPositions(static_cast<int>(text.length())) { + LayoutSetText(layout, text); + iter.reset(pango_layout_get_iter(layout)); + curIndex = pango_layout_iter_get_index(iter.get()); + pango_layout_iter_get_cluster_extents(iter.get(), nullptr, &pos); }
void Next() noexcept { positionStart = position; - if (pango_layout_iter_next_cluster(iter)) { - pango_layout_iter_get_cluster_extents(iter, nullptr, &pos); - position = floatFromPangoUnits(pos.x); - curIndex = pango_layout_iter_get_index(iter); + if (pango_layout_iter_next_cluster(iter.get())) { + pango_layout_iter_get_cluster_extents(iter.get(), nullptr, &pos); + position = pango_units_to_double(pos.x); + curIndex = pango_layout_iter_get_index(iter.get()); } else { finished = true; - position = floatFromPangoUnits(pos.x + pos.width); - curIndex = lenPositions; + position = pango_units_to_double(pos.x + pos.width); + curIndex = pango_layout_iter_get_index(iter.get()); } distance = position - positionStart; } };
+// Something has gone wrong so set all the characters as equally spaced. +void EquallySpaced(PangoLayout *layout, XYPOSITION *positions, size_t lenPositions) { + int widthLayout = 0; + pango_layout_get_size(layout, &widthLayout, nullptr); + const XYPOSITION widthTotal = pango_units_to_double(widthLayout); + for (size_t bytePos=0; bytePos<lenPositions; bytePos++) { + positions[bytePos] = widthTotal / lenPositions * (bytePos + 1); + } +} + +} + 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 (PFont(font_)->fd) { + UniquePangoContext contextMeasure = MeasuringContext(); + UniquePangoLayout layoutMeasure(pango_layout_new(contextMeasure.get())); + PLATFORM_ASSERT(layoutMeasure); + + pango_layout_set_font_description(layoutMeasure.get(), PFont(font_)->fd.get()); 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()); + ClusterIterator iti(layoutMeasure.get(), text); + int i = iti.curIndex; + if (i != 0) { + // Unexpected start to iteration, could be bidirectional text + EquallySpaced(layoutMeasure.get(), positions, text.length()); + return; + } while (!iti.finished) { iti.Next(); const int places = iti.curIndex - i; @@ -886,22 +898,46 @@ void SurfaceImpl::MeasureWidths(const Font *font_, std::string_view text, XYPOSI PLATFORM_ASSERT(static_cast<size_t>(i) == text.length()); } else { int positionsCalculated = 0; + const char *charSetID = CharacterSetID(PFont(font_)->characterSet); + std::string utfForm; + { + gsize bytesRead = 0; + gsize bytesWritten = 0; + GError *error = nullptr; + UniqueStr textInUTF8(g_convert(text.data(), text.length(), + "UTF-8", charSetID, + &bytesRead, + &bytesWritten, + &error)); + if ((bytesWritten > 0) && (bytesRead == text.length()) && !error) { + // Extra allocation here but avoiding it makes code more complex + utfForm.assign(textInUTF8.get(), bytesWritten); + } + if (error) { +#ifdef DEBUG + fprintf(stderr, "MeasureWidths: %s.\n", error->message); +#endif + g_error_free(error); + } + } 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())); + Converter convMeasure("UCS-2", charSetID, false); int i = 0; - int clusterStart = 0; - ClusterIterator iti(layout, strlen(utfForm.c_str())); + ClusterIterator iti(layoutMeasure.get(), utfForm); + int clusterStart = iti.curIndex; + if (clusterStart != 0) { + // Unexpected start to iteration, could be bidirectional text + EquallySpaced(layoutMeasure.get(), positions, text.length()); + return; + } while (!iti.finished) { iti.Next(); const int clusterEnd = iti.curIndex; - const int places = g_utf8_strlen(utfForm.c_str() + clusterStart, clusterEnd - clusterStart); + const int places = g_utf8_strlen(utfForm.data() + clusterStart, clusterEnd - clusterStart); int place = 1; while (clusterStart < clusterEnd) { size_t lenChar = MultiByteLenFromIconv(convMeasure, text.data()+i, text.length()-i); @@ -919,31 +955,35 @@ void SurfaceImpl::MeasureWidths(const Font *font_, std::string_view text, XYPOSI 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); +#ifdef DEBUG + fprintf(stderr, "MeasureWidths: Fall back to Latin1 [%s]\n", utfForm.c_str()); +#endif } - 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()); + ClusterIterator iti(layoutMeasure.get(), utfForm); + int clusterStart = iti.curIndex; + if (clusterStart != 0) { + // Unexpected start to iteration, could be bidirectional text + EquallySpaced(layoutMeasure.get(), positions, lenPositions); + return; + } 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))) { + const int ligatureLength = g_utf8_strlen(utfForm.data() + clusterStart, clusterEnd - clusterStart); + if (((i + ligatureLength) > lenPositions) || + (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); - } +#ifdef DEBUG + fprintf(stderr, "MeasureWidths: result too long.\n"); +#endif + EquallySpaced(layoutMeasure.get(), positions, lenPositions); return; } PLATFORM_ASSERT(ligatureLength > 0 && ligatureLength <= 3); @@ -962,29 +1002,28 @@ void SurfaceImpl::MeasureWidths(const Font *font_, std::string_view text, XYPOSI } else { // No font so return an ascending range of values for (size_t i = 0; i < text.length(); i++) { - positions[i] = i + 1; + positions[i] = i + 1.0; } } }
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 (PFont(font_)->fd) { + pango_layout_set_font_description(layout.get(), PFont(font_)->fd.get()); if (et == EncodingType::utf8) { - pango_layout_set_text(layout, text.data(), text.length()); + LayoutSetText(layout.get(), text); } else { SetConverter(PFont(font_)->characterSet); - utfForm = UTF8FromIconv(conv, text); + std::string 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()); + LayoutSetText(layout.get(), utfForm); } - PangoLayoutLine *pangoLine = pango_layout_get_line_readonly(layout, 0); + PangoLayoutLine *pangoLine = pango_layout_get_line_readonly(layout.get(), 0); PangoRectangle pos {}; pango_layout_line_get_extents(pangoLine, nullptr, &pos); - return floatFromPangoUnits(pos.width); + return pango_units_to_double(pos.width); } return 1; } @@ -994,11 +1033,11 @@ void SurfaceImpl::DrawTextBaseUTF8(PRectangle rc, const Font *font_, XYPOSITION if (context) { PenColourAlpha(fore); const XYPOSITION xText = rc.left; - if (PFont(font_)->pfd) { - pango_layout_set_text(layout, text.data(), text.length()); - pango_layout_set_font_description(layout, PFont(font_)->pfd); - pango_cairo_update_layout(context, layout); - PangoLayoutLine *pll = pango_layout_get_line_readonly(layout, 0); + if (PFont(font_)->fd) { + LayoutSetText(layout.get(), text); + pango_layout_set_font_description(layout.get(), PFont(font_)->fd.get()); + pango_cairo_update_layout(context, layout.get()); + PangoLayoutLine *pll = pango_layout_get_line_readonly(layout.get(), 0); cairo_move_to(context, xText, ybase); pango_cairo_show_layout_line(context, pll); } @@ -1030,12 +1069,20 @@ void SurfaceImpl::DrawTextTransparentUTF8(PRectangle rc, const Font *font_, XYPO }
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); + if (PFont(font_)->fd) { + UniquePangoContext contextMeasure = MeasuringContext(); + UniquePangoLayout layoutMeasure(pango_layout_new(contextMeasure.get())); + PLATFORM_ASSERT(layoutMeasure); + + pango_layout_set_font_description(layoutMeasure.get(), PFont(font_)->fd.get()); // 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()); + ClusterIterator iti(layoutMeasure.get(), text); + int i = iti.curIndex; + if (i != 0) { + // Unexpected start to iteration, could be bidirectional text + EquallySpaced(layoutMeasure.get(), positions, text.length()); + return; + } while (!iti.finished) { iti.Next(); const int places = iti.curIndex - i; @@ -1052,50 +1099,42 @@ void SurfaceImpl::MeasureWidthsUTF8(const Font *font_, std::string_view text, XY } else { // No font so return an ascending range of values for (size_t i = 0; i < text.length(); i++) { - positions[i] = i + 1; + positions[i] = i + 1.0; } } }
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); + if (PFont(font_)->fd) { + pango_layout_set_font_description(layout.get(), PFont(font_)->fd.get()); + LayoutSetText(layout.get(), text); + PangoLayoutLine *pangoLine = pango_layout_get_line_readonly(layout.get(), 0); PangoRectangle pos{}; pango_layout_line_get_extents(pangoLine, nullptr, &pos); - return floatFromPangoUnits(pos.width); + return pango_units_to_double(pos.width); } return 1; }
// Ascent and descent determined by Pango font metrics.
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 = std::ceil(floatFromPangoUnits( - pango_font_metrics_get_ascent(metrics))); - pango_font_metrics_unref(metrics); + if (!PFont(font_)->fd) { + return 1.0; } - if (ascent == 0) { - ascent = 1; - } - return ascent; + UniquePangoFontMetrics metrics(pango_context_get_metrics(pcontext.get(), + PFont(font_)->fd.get(), language)); + return std::max(1.0, std::ceil(pango_units_to_double( + pango_font_metrics_get_ascent(metrics.get())))); }
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 = std::ceil(floatFromPangoUnits( - pango_font_metrics_get_descent(metrics))); - pango_font_metrics_unref(metrics); - return descent; + if (!PFont(font_)->fd) { + return 0.0; } - return 0; + UniquePangoFontMetrics metrics(pango_context_get_metrics(pcontext.get(), + PFont(font_)->fd.get(), language)); + return std::ceil(pango_units_to_double(pango_font_metrics_get_descent(metrics.get()))); }
XYPOSITION SurfaceImpl::InternalLeading(const Font *) { @@ -1292,11 +1331,7 @@ void Window::SetCursor(Cursor curs) {
if (WindowFromWidget(PWidget(wid))) gdk_window_set_cursor(WindowFromWidget(PWidget(wid)), gdkCurs); -#if GTK_CHECK_VERSION(3,0,0) - g_object_unref(gdkCurs); -#else - gdk_cursor_unref(gdkCurs); -#endif + UnRefCursor(gdkCurs); }
/* Returns rectangle of monitor pt is on, both rect and pt are in Window's @@ -1316,7 +1351,7 @@ PRectangle Window::GetMonitorRect(Point pt) { #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); + static_cast<gint>(pt.x) + x_offset, static_cast<gint>(pt.y) + y_offset); gdk_screen_get_monitor_geometry(screen, monitor_num, &rect); #endif rect.x -= x_offset; @@ -1355,15 +1390,15 @@ class ListBoxX : public ListBox { WindowID frame; WindowID list; WindowID scroller; - void *pixhash; + GHashTable *pixhash; GtkCellRenderer *pixbuf_renderer; GtkCellRenderer *renderer; RGBAImageSet images; int desiredVisibleRows; unsigned int maxItemCharacters; unsigned int aveCharWidth; #if GTK_CHECK_VERSION(3,0,0) - GtkCssProvider *cssProvider; + std::unique_ptr<GtkCssProvider, GObjectReleaser> cssProvider; #endif public: IListBoxDelegate *delegate; @@ -1373,9 +1408,6 @@ class ListBoxX : public ListBox { renderer(nullptr), desiredVisibleRows(5), maxItemCharacters(0), aveCharWidth(1), -#if GTK_CHECK_VERSION(3,0,0) - cssProvider(nullptr), -#endif delegate(nullptr) { } // Deleted so ListBoxX objects can not be copied. @@ -1385,19 +1417,13 @@ class ListBoxX : public ListBox { ListBoxX&operator=(ListBoxX&&) = delete; ~ListBoxX() noexcept override { if (pixhash) { - g_hash_table_foreach((GHashTable *) pixhash, list_image_free, nullptr); - g_hash_table_destroy((GHashTable *) pixhash); + g_hash_table_foreach(pixhash, list_image_free, nullptr); + g_hash_table_destroy(pixhash); } if (widCached) { gtk_widget_destroy(GTK_WIDGET(widCached)); wid = widCached = nullptr; } -#if GTK_CHECK_VERSION(3,0,0) - if (cssProvider) { - g_object_unref(cssProvider); - cssProvider = nullptr; - } -#endif } void SetFont(const Font *font) override; void Create(Window &parent, int ctrlID, Point location_, int lineHeight_, bool unicodeMode_, Technology technology_) override; @@ -1506,7 +1532,7 @@ static void small_scroller_class_init(SmallScrollerClass *klass) {
static void small_scroller_init(SmallScroller *) {}
-static gboolean ButtonPress(GtkWidget *, GdkEventButton *ev, gpointer p) { +static gboolean ButtonPress(GtkWidget *, const GdkEventButton *ev, gpointer p) { try { ListBoxX *lb = static_cast<ListBoxX *>(p); if (ev->type == GDK_2BUTTON_PRESS && lb->delegate) { @@ -1521,7 +1547,7 @@ static gboolean ButtonPress(GtkWidget *, GdkEventButton *ev, gpointer p) { return FALSE; }
-static gboolean ButtonRelease(GtkWidget *, GdkEventButton *ev, gpointer p) { +static gboolean ButtonRelease(GtkWidget *, const GdkEventButton *ev, gpointer p) { try { ListBoxX *lb = static_cast<ListBoxX *>(p); if (ev->type != GDK_2BUTTON_PRESS && lb->delegate) { @@ -1593,11 +1619,12 @@ void ListBoxX::Create(Window &parent, int, Point, int, bool, Technology) {
#if GTK_CHECK_VERSION(3,0,0) if (!cssProvider) { - cssProvider = gtk_css_provider_new(); + cssProvider.reset(gtk_css_provider_new()); } #endif
wid = widCached = gtk_window_new(GTK_WINDOW_POPUP); + gtk_window_set_type_hint(GTK_WINDOW(wid), GDK_WINDOW_TYPE_HINT_POPUP_MENU);
frame = gtk_frame_new(nullptr); gtk_widget_show(PWidget(frame)); @@ -1622,7 +1649,7 @@ void ListBoxX::Create(Window &parent, int, Point, int, bool, Technology) { #if GTK_CHECK_VERSION(3,0,0) GtkStyleContext *styleContext = gtk_widget_get_style_context(GTK_WIDGET(list)); if (styleContext) { - gtk_style_context_add_provider(styleContext, GTK_STYLE_PROVIDER(cssProvider), + gtk_style_context_add_provider(styleContext, GTK_STYLE_PROVIDER(cssProvider.get()), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); } #endif @@ -1669,11 +1696,11 @@ void ListBoxX::Create(Window &parent, int, Point, int, bool, Technology) {
void ListBoxX::SetFont(const Font *font) { // Only do for Pango font as there have been crashes for GDK fonts - if (Created() && PFont(font)->pfd) { + if (Created() && PFont(font)->fd) { // Current font is Pango font #if GTK_CHECK_VERSION(3,0,0) if (cssProvider) { - PangoFontDescription *pfd = PFont(font)->pfd; + PangoFontDescription *pfd = PFont(font)->fd.get(); std::ostringstream ssFontSetting; ssFontSetting << "GtkTreeView, treeview { "; ssFontSetting << "font-family: " << pango_font_description_get_family(pfd) << "; "; @@ -1690,11 +1717,11 @@ void ListBoxX::SetFont(const Font *font) { } ssFontSetting << "font-weight:"<< pango_font_description_get_weight(pfd) << "; "; ssFontSetting << "}"; - gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(cssProvider), + gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(cssProvider.get()), ssFontSetting.str().c_str(), -1, nullptr); } #else - gtk_widget_modify_font(PWidget(list), PFont(font)->pfd); + gtk_widget_modify_font(PWidget(list), PFont(font)->fd.get()); #endif gtk_cell_renderer_text_set_fixed_height_from_font(GTK_CELL_RENDERER_TEXT(renderer), -1); gtk_cell_renderer_text_set_fixed_height_from_font(GTK_CELL_RENDERER_TEXT(renderer), 1); @@ -1778,9 +1805,7 @@ PRectangle ListBoxX::GetDesiredRect() { #endif rc.bottom = height;
- int width = maxItemCharacters; - if (width < 12) - width = 12; + const unsigned int width = std::max(maxItemCharacters, 12U); rc.right = width * (aveCharWidth + aveCharWidth / 3); // Add horizontal padding and borders int horizontal_separator=0; @@ -1847,7 +1872,7 @@ static void init_pixmap(ListImage *list_image) noexcept { void ListBoxX::Append(char *s, int type) { ListImage *list_image = nullptr; if ((type >= 0) && pixhash) { - list_image = static_cast<ListImage *>(g_hash_table_lookup((GHashTable *) pixhash, + list_image = static_cast<ListImage *>(g_hash_table_lookup(pixhash, GINT_TO_POINTER(type))); } GtkTreeIter iter {}; @@ -1877,7 +1902,7 @@ void ListBoxX::Append(char *s, int type) { gtk_list_store_set(GTK_LIST_STORE(store), &iter, TEXT_COLUMN, s, -1); } - const size_t len = strlen(s); + const unsigned int len = static_cast<unsigned int>(strlen(s)); if (maxItemCharacters < len) maxItemCharacters = len; } @@ -1913,7 +1938,7 @@ void ListBoxX::Select(int n) { GtkAdjustment *adj = 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)) + gdouble value = (static_cast<gdouble>(n) / total) * (gtk_adjustment_get_upper(adj) - gtk_adjustment_get_lower(adj)) + gtk_adjustment_get_lower(adj) - gtk_adjustment_get_page_size(adj) / 2; // Get cell height const int row_height = GetRowHeight(); @@ -2008,7 +2033,7 @@ void ListBoxX::RegisterRGBA(int type, std::unique_ptr<RGBAImage> image) { if (!pixhash) { pixhash = g_hash_table_new(g_direct_hash, g_direct_equal); } - ListImage *list_image = static_cast<ListImage *>(g_hash_table_lookup((GHashTable *) pixhash, + ListImage *list_image = static_cast<ListImage *>(g_hash_table_lookup(pixhash, GINT_TO_POINTER(type))); if (list_image) { // Drop icon already registered @@ -2019,7 +2044,7 @@ void ListBoxX::RegisterRGBA(int type, std::unique_ptr<RGBAImage> image) { } else { list_image = g_new0(ListImage, 1); list_image->rgba_data = observe; - g_hash_table_insert((GHashTable *) pixhash, GINT_TO_POINTER(type), + g_hash_table_insert(pixhash, GINT_TO_POINTER(type), (gpointer) list_image); } } @@ -2087,7 +2112,7 @@ void Menu::Destroy() noexcept {
#if !GTK_CHECK_VERSION(3,22,0) static void MenuPositionFunc(GtkMenu *, gint *x, gint *y, gboolean *, gpointer userData) noexcept { - sptr_t intFromPointer = GPOINTER_TO_INT(userData); + const gint intFromPointer = GPOINTER_TO_INT(userData); *x = intFromPointer & 0xffff; *y = intFromPointer >> 16; } @@ -2158,7 +2183,7 @@ void Platform::DebugPrintf(const char *format, ...) noexcept { char buffer[2000]; va_list pArguments; va_start(pArguments, format); - vsprintf(buffer, format, pArguments); + vsnprintf(buffer, std::size(buffer), format, pArguments); va_end(pArguments); Platform::DebugDisplay(buffer); }
Modified: scintilla/gtk/ScintillaGTK.cxx 291 lines changed, 177 insertions(+), 114 deletions(-) =================================================================== @@ -80,10 +80,10 @@ #include "AutoComplete.h" #include "ScintillaBase.h"
+#include "Wrappers.h" #include "ScintillaGTK.h" #include "scintilla-marshal.h" #include "ScintillaGTKAccessible.h" - #include "Converter.h"
#define IS_WIDGET_REALIZED(w) (gtk_widget_get_realized(GTK_WIDGET(w))) @@ -135,10 +135,6 @@ constexpr gint nClipboardPasteTargets = static_cast<gint>(std::size(clipboardPas
const GdkDragAction actionCopyOrMove = static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE);
-GdkWindow *WindowFromWidget(GtkWidget *w) noexcept { - return gtk_widget_get_window(w); -} - GtkWidget *PWidget(const Window &w) noexcept { return static_cast<GtkWidget *>(w.GetID()); } @@ -148,14 +144,6 @@ GdkWindow *PWindow(const Window &w) noexcept { 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)) && @@ -195,17 +183,16 @@ bool SettingGet(GtkSettings *settings, const gchar *name, gpointer value) noexce }
FontOptions::FontOptions(GtkWidget *widget) noexcept { - PangoContext *pcontext = gtk_widget_create_pango_context(widget); + UniquePangoContext pcontext(gtk_widget_create_pango_context(widget)); PLATFORM_ASSERT(pcontext); - const cairo_font_options_t *options = pango_cairo_context_get_font_options(pcontext); + const cairo_font_options_t *options = pango_cairo_context_get_font_options(pcontext.get()); // 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 { @@ -222,7 +209,6 @@ ScintillaGTK *ScintillaGTK::FromWidget(GtkWidget *widget) noexcept { ScintillaGTK::ScintillaGTK(_ScintillaObject *sci_) : adjustmentv(nullptr), adjustmenth(nullptr), verticalScrollBarWidth(30), horizontalScrollBarHeight(30), - evbtn(nullptr), buttonMouse(0), capturedMouse(false), dragWasDropped(false), lastKey(0), rectangularSelectionModifier(SCMOD_CTRL), @@ -273,9 +259,9 @@ ScintillaGTK::~ScintillaGTK() { g_source_remove(styleIdleID); styleIdleID = 0; } - if (evbtn) { - gdk_event_free(evbtn); - evbtn = nullptr; + if (scrollBarIdleID) { + g_source_remove(scrollBarIdleID); + scrollBarIdleID = 0; } ClearPrimarySelection(); wPreedit.Destroy(); @@ -317,27 +303,30 @@ void ScintillaGTK::RealizeThis(GtkWidget *widget) { gtk_widget_get_window(widget)); #endif gdk_window_show(gtk_widget_get_window(widget)); - UnRefCursor(cursor); #else widget->window = gdk_window_new(gtk_widget_get_parent_window(widget), &attrs, GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_CURSOR); gdk_window_set_user_data(widget->window, widget); widget->style = gtk_style_attach(widget->style, widget->window); gdk_window_set_background(widget->window, &widget->style->bg[GTK_STATE_NORMAL]); gdk_window_show(widget->window); - UnRefCursor(cursor); #endif + UnRefCursor(cursor);
preeditInitialized = false; gtk_widget_realize(PWidget(wPreedit)); gtk_widget_realize(PWidget(wPreeditDraw));
- im_context = gtk_im_multicontext_new(); - g_signal_connect(G_OBJECT(im_context), "commit", + im_context.reset(gtk_im_multicontext_new()); + g_signal_connect(G_OBJECT(im_context.get()), "commit", G_CALLBACK(Commit), this); - g_signal_connect(G_OBJECT(im_context), "preedit_changed", + g_signal_connect(G_OBJECT(im_context.get()), "preedit_changed", G_CALLBACK(PreeditChanged), this); - gtk_im_context_set_client_window(im_context, WindowFromWidget(widget)); + g_signal_connect(G_OBJECT(im_context.get()), "retrieve-surrounding", + G_CALLBACK(RetrieveSurrounding), this); + g_signal_connect(G_OBJECT(im_context.get()), "delete-surrounding", + G_CALLBACK(DeleteSurrounding), this); + gtk_im_context_set_client_window(im_context.get(), WindowFromWidget(widget));
GtkWidget *widtxt = PWidget(wText); // // No code inside the G_OBJECT macro g_signal_connect_after(G_OBJECT(widtxt), "style_set", @@ -388,8 +377,7 @@ void ScintillaGTK::UnRealizeThis(GtkWidget *widget) { gtk_widget_unrealize(PWidget(scrollbarh)); gtk_widget_unrealize(PWidget(wPreedit)); gtk_widget_unrealize(PWidget(wPreeditDraw)); - g_object_unref(im_context); - im_context = nullptr; + im_context.reset(); if (GTK_WIDGET_CLASS(parentClass)->unrealize) GTK_WIDGET_CLASS(parentClass)->unrealize(widget);
@@ -414,6 +402,7 @@ void ScintillaGTK::MapThis() { wMain.SetCursor(Window::Cursor::arrow); scrollbarv.SetCursor(Window::Cursor::arrow); scrollbarh.SetCursor(Window::Cursor::arrow); + SetClientRectangle(); ChangeSize(); gdk_window_show(PWindow(wMain)); } catch (...) { @@ -504,8 +493,8 @@ gint ScintillaGTK::FocusInThis(GtkWidget *) { SetFocusState(true);
if (im_context) { - gtk_im_context_focus_in(im_context); - PreEditString pes(im_context); + gtk_im_context_focus_in(im_context.get()); + PreEditString pes(im_context.get()); if (PWidget(wPreedit)) { if (!preeditInitialized) { GtkWidget *top = gtk_widget_get_toplevel(PWidget(wMain)); @@ -538,7 +527,7 @@ gint ScintillaGTK::FocusOutThis(GtkWidget *) { if (PWidget(wPreedit)) gtk_widget_hide(PWidget(wPreedit)); if (im_context) - gtk_im_context_focus_out(im_context); + gtk_im_context_focus_out(im_context.get());
} catch (...) { errorStatus = Status::Failure; @@ -552,7 +541,7 @@ gint ScintillaGTK::FocusOut(GtkWidget *widget, GdkEventFocus * /*event*/) { }
void ScintillaGTK::SizeRequest(GtkWidget *widget, GtkRequisition *requisition) { - ScintillaGTK *sciThis = FromWidget(widget); + const ScintillaGTK *sciThis = FromWidget(widget); requisition->width = 1; requisition->height = 1; GtkRequisition child_requisition; @@ -684,6 +673,7 @@ void ScintillaGTK::Init() {
/* create pre-edit window */ wPreedit = gtk_window_new(GTK_WINDOW_POPUP); + gtk_window_set_type_hint(GTK_WINDOW(PWidget(wPreedit)), GDK_WINDOW_TYPE_HINT_POPUP_MENU); wPreeditDraw = gtk_drawing_area_new(); GtkWidget *predrw = PWidget(wPreeditDraw); // No code inside the G_OBJECT macro #if GTK_CHECK_VERSION(3,0,0) @@ -765,14 +755,14 @@ void ScintillaGTK::StartDrag() { tl, actionCopyOrMove, buttonMouse, - evbtn, + evbtn.get(), -1, -1); #else gtk_drag_begin(GTK_WIDGET(PWidget(wMain)), tl, actionCopyOrMove, buttonMouse, - evbtn); + evbtn.get()); #endif }
@@ -1073,8 +1063,12 @@ void ScintillaGTK::FullPaint() { wText.InvalidateAll(); }
+void ScintillaGTK::SetClientRectangle() { + rectangleClient = wMain.GetClientPosition(); +} + PRectangle ScintillaGTK::GetClientRectangle() const { - PRectangle rc = wMain.GetClientPosition(); + PRectangle rc = rectangleClient; if (verticalScrollBarVisible) rc.right -= verticalScrollBarWidth; if (horizontalScrollBarVisible && !Wrapping()) @@ -1129,6 +1123,7 @@ bool ScintillaGTK::ModifyScrollBars(Sci::Line nMax, Sci::Line nPage) { #if !GTK_CHECK_VERSION(3,18,0) gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmentv)); #endif + gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmentv), static_cast<gdouble>(topLine)); modified = true; }
@@ -1150,6 +1145,7 @@ bool ScintillaGTK::ModifyScrollBars(Sci::Line nMax, Sci::Line nPage) { #if !GTK_CHECK_VERSION(3,18,0) gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmenth)); #endif + gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmenth), xOffset); modified = true; } if (modified && (paintState == PaintState::painting)) { @@ -1164,6 +1160,27 @@ void ScintillaGTK::ReconfigureScrollBars() { Resize(static_cast<int>(rc.Width()), static_cast<int>(rc.Height())); }
+void ScintillaGTK::SetScrollBars() { + if (scrollBarIdleID) { + // Only allow one scroll bar change to be queued + return; + } + constexpr gint priorityScrollBar = GDK_PRIORITY_REDRAW + 5; + // On GTK, unlike other platforms, modifying scrollbars inside some events including + // resizes causes problems. Deferring the modification to a lower priority (125) idle + // event avoids the problems. This code did not always work when the priority was + // higher than GTK's resize (GTK_PRIORITY_RESIZE=110) or redraw + // (GDK_PRIORITY_REDRAW=120) idle tasks. + scrollBarIdleID = gdk_threads_add_idle_full(priorityScrollBar, + [](gpointer pSci) -> gboolean { + ScintillaGTK *sciThis = static_cast<ScintillaGTK *>(pSci); + sciThis->ChangeScrollBars(); + sciThis->scrollBarIdleID = 0; + return FALSE; + }, + this, nullptr); +} + void ScintillaGTK::NotifyChange() { g_signal_emit(G_OBJECT(sci), scintilla_signals[COMMAND_SIGNAL], 0, Platform::LongFromTwoShorts(GetCtrlID(), SCEN_CHANGE), PWidget(wMain)); @@ -1207,11 +1224,12 @@ const char *ScintillaGTK::CharacterSetID() const { return ::CharacterSetID(vs.styles[STYLE_DEFAULT].characterSet); }
+namespace { + class CaseFolderDBCS : public CaseFolderTable { const char *charSet; public: explicit CaseFolderDBCS(const char *charSet_) noexcept : charSet(charSet_) { - StandardASCII(); } size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) override { if ((lenMixed == 1) && (sizeFolded > 0)) { @@ -1221,15 +1239,14 @@ class CaseFolderDBCS : public CaseFolderTable { std::string sUTF8 = ConvertText(mixed, lenMixed, "UTF-8", charSet, false); if (!sUTF8.empty()) { - gchar *mapped = g_utf8_casefold(sUTF8.c_str(), sUTF8.length()); - size_t lenMapped = strlen(mapped); + UniqueStr mapped(g_utf8_casefold(sUTF8.c_str(), sUTF8.length())); + size_t lenMapped = strlen(mapped.get()); if (lenMapped < sizeFolded) { - memcpy(folded, mapped, lenMapped); + memcpy(folded, mapped.get(), lenMapped); } else { folded[0] = '\0'; lenMapped = 1; } - g_free(mapped); return lenMapped; } } @@ -1239,6 +1256,8 @@ class CaseFolderDBCS : public CaseFolderTable { } };
+} + std::unique_ptr<CaseFolder> ScintillaGTK::CaseFolderForEncoding() { if (pdoc->dbcsCodePage == SC_CP_UTF8) { return std::make_unique<CaseFolderUnicode>(); @@ -1247,7 +1266,6 @@ std::unique_ptr<CaseFolder> ScintillaGTK::CaseFolderForEncoding() { if (charSetBuffer) { if (pdoc->dbcsCodePage == 0) { std::unique_ptr<CaseFolderTable> pcf = std::make_unique<CaseFolderTable>(); - pcf->StandardASCII(); // Only for single byte encodings for (int i=0x80; i<0x100; i++) { char sCharacter[2] = "A"; @@ -1256,14 +1274,13 @@ std::unique_ptr<CaseFolder> ScintillaGTK::CaseFolderForEncoding() { std::string sUTF8 = ConvertText(sCharacter, 1, "UTF-8", charSetBuffer, false, true); if (!sUTF8.empty()) { - gchar *mapped = g_utf8_casefold(sUTF8.c_str(), sUTF8.length()); + UniqueStr mapped(g_utf8_casefold(sUTF8.c_str(), sUTF8.length())); if (mapped) { - std::string mappedBack = ConvertText(mapped, strlen(mapped), + std::string mappedBack = ConvertText(mapped.get(), strlen(mapped.get()), charSetBuffer, "UTF-8", false, true); if ((mappedBack.length() == 1) && (mappedBack[0] != sCharacter[0])) { pcf->SetTranslation(sCharacter[0], mappedBack[0]); } - g_free(mapped); } } } @@ -1279,22 +1296,14 @@ std::unique_ptr<CaseFolder> ScintillaGTK::CaseFolderForEncoding() { namespace {
struct CaseMapper { - gchar *mapped; // Must be freed with g_free + UniqueStr mapped; CaseMapper(const std::string &sUTF8, bool toUpperCase) noexcept { if (toUpperCase) { - mapped = g_utf8_strup(sUTF8.c_str(), sUTF8.length()); + mapped.reset(g_utf8_strup(sUTF8.c_str(), sUTF8.length())); } else { - mapped = g_utf8_strdown(sUTF8.c_str(), sUTF8.length()); + mapped.reset(g_utf8_strdown(sUTF8.c_str(), sUTF8.length())); } } - // Deleted so CaseMapper objects can not be copied. - CaseMapper(const CaseMapper&) = delete; - CaseMapper(CaseMapper&&) = delete; - CaseMapper&operator=(const CaseMapper&) = delete; - CaseMapper&operator=(CaseMapper&&) = delete; - ~CaseMapper() noexcept { - g_free(mapped); - } };
} @@ -1315,13 +1324,13 @@ std::string ScintillaGTK::CaseMapString(const std::string &s, CaseMapping caseMa
if (!*charSetBuffer) { CaseMapper mapper(s, caseMapping == CaseMapping::upper); - return std::string(mapper.mapped, strlen(mapper.mapped)); + return std::string(mapper.mapped.get()); } else { // Change text to UTF-8 std::string sUTF8 = ConvertText(s.c_str(), s.length(), "UTF-8", charSetBuffer, false); CaseMapper mapper(sUTF8, caseMapping == CaseMapping::upper); - return ConvertText(mapper.mapped, strlen(mapper.mapped), charSetBuffer, "UTF-8", false); + return ConvertText(mapper.mapped.get(), strlen(mapper.mapped.get()), charSetBuffer, "UTF-8", false); } }
@@ -1398,6 +1407,7 @@ void ScintillaGTK::Paste() { void ScintillaGTK::CreateCallTipWindow(PRectangle rc) { if (!ct.wCallTip.Created()) { ct.wCallTip = gtk_window_new(GTK_WINDOW_POPUP); + gtk_window_set_type_hint(GTK_WINDOW(PWidget(ct.wCallTip)), GDK_WINDOW_TYPE_HINT_TOOLTIP); ct.wDraw = gtk_drawing_area_new(); GtkWidget *widcdrw = PWidget(ct.wDraw); // // No code inside the G_OBJECT macro gtk_container_add(GTK_CONTAINER(PWidget(ct.wCallTip)), widcdrw); @@ -1785,8 +1795,15 @@ void ScintillaGTK::Resize(int width, int height) { gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarv))); verticalScrollBarWidth = 0; } + SetClientRectangle(); if (IS_WIDGET_MAPPED(PWidget(wMain))) { ChangeSize(); + } else { + const PRectangle rcTextArea = GetTextRectangle(); + if (wrapWidth != rcTextArea.Width()) { + wrapWidth = rcTextArea.Width(); + NeedWrapping(); + } }
alloc.x = 0; @@ -1849,10 +1866,7 @@ gint ScintillaGTK::PressThis(GdkEventButton *event) { if (event->type != GDK_BUTTON_PRESS) return FALSE;
- if (evbtn) { - gdk_event_free(evbtn); - } - evbtn = gdk_event_copy(reinterpret_cast<GdkEvent *>(event)); + evbtn.reset(gdk_event_copy(reinterpret_cast<GdkEvent *>(event))); buttonMouse = event->button; const Point pt = PointOfEvent(event); const PRectangle rcClient = GetClientRectangle(); @@ -1994,11 +2008,11 @@ gint ScintillaGTK::ScrollEvent(GtkWidget *widget, GdkEventScroll *event) { // Compute amount and direction to scroll (even tho on win32 there is // intensity of scrolling info in the native message, gtk doesn't // support this so we simulate similarly adaptive scrolling) - // Note that this is disabled on OS X (Darwin) with the X11 backend + // Note that this is disabled on macOS (Darwin) with the X11 backend // where the X11 server already has an adaptive scrolling algorithm // that fights with this one int cLineScroll; -#if defined(__APPLE__) && !defined(GDK_WINDOWING_QUARTZ) +#if (defined(__APPLE__) || defined(PLAT_GTK_WIN32)) && !defined(GDK_WINDOWING_QUARTZ) cLineScroll = sciThis->linesPerScroll; if (cLineScroll == 0) cLineScroll = 4; @@ -2028,11 +2042,6 @@ gint ScintillaGTK::ScrollEvent(GtkWidget *widget, GdkEventScroll *event) { // issues spurious button 2 mouse events during wheeling, which can cause // problems (a patch for both was submitted by archaeopteryx.com on 13Jun2001)
- // Data zoom not supported - if (event->state & GDK_SHIFT_MASK) { - return FALSE; - } - #if GTK_CHECK_VERSION(3,4,0) // Smooth scrolling not supported if (event->direction == GDK_SCROLL_SMOOTH) { @@ -2041,8 +2050,10 @@ gint ScintillaGTK::ScrollEvent(GtkWidget *widget, GdkEventScroll *event) { #endif
// Horizontal scrolling - if (event->direction == GDK_SCROLL_LEFT || event->direction == GDK_SCROLL_RIGHT) { - sciThis->HorizontalScrollTo(sciThis->xOffset + cLineScroll); + if (event->direction == GDK_SCROLL_LEFT || event->direction == GDK_SCROLL_RIGHT || event->state & GDK_SHIFT_MASK) { + int hScroll = gtk_adjustment_get_step_increment(sciThis->adjustmenth); + hScroll *= cLineScroll; // scroll by this many characters + sciThis->HorizontalScrollTo(sciThis->xOffset + hScroll);
// Text font size zoom } else if (event->state & GDK_CONTROL_MASK) { @@ -2249,7 +2260,7 @@ gboolean ScintillaGTK::KeyThis(GdkEventKey *event) { try { //fprintf(stderr, "SC-key: %d %x [%s]\n", // event->keyval, event->state, (event->length > 0) ? event->string : "empty"); - if (gtk_im_context_filter_keypress(im_context, event)) { + if (gtk_im_context_filter_keypress(im_context.get(), event)) { return 1; } if (!event->keyval) { @@ -2307,7 +2318,7 @@ gboolean ScintillaGTK::KeyPress(GtkWidget *widget, GdkEventKey *event) { gboolean ScintillaGTK::KeyRelease(GtkWidget *widget, GdkEventKey *event) { //Platform::DebugPrintf("SC-keyrel: %d %x %3s\n",event->keyval, event->state, event->string); ScintillaGTK *sciThis = FromWidget(widget); - if (gtk_im_context_filter_keypress(sciThis->im_context, event)) { + if (gtk_im_context_filter_keypress(sciThis->im_context.get(), event)) { return TRUE; } return FALSE; @@ -2317,14 +2328,12 @@ gboolean ScintillaGTK::KeyRelease(GtkWidget *widget, GdkEventKey *event) {
gboolean ScintillaGTK::DrawPreeditThis(GtkWidget *, cairo_t *cr) { try { - PreEditString pes(im_context); - PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), pes.str); - pango_layout_set_attributes(layout, pes.attrs); + PreEditString pes(im_context.get()); + UniquePangoLayout layout(gtk_widget_create_pango_layout(PWidget(wText), pes.str)); + pango_layout_set_attributes(layout.get(), pes.attrs);
cairo_move_to(cr, 0, 0); - pango_cairo_show_layout(cr, layout); - - g_object_unref(layout); + pango_cairo_show_layout(cr, layout.get()); } catch (...) { errorStatus = Status::Failure; } @@ -2339,15 +2348,13 @@ gboolean ScintillaGTK::DrawPreedit(GtkWidget *widget, cairo_t *cr, ScintillaGTK
gboolean ScintillaGTK::ExposePreeditThis(GtkWidget *widget, GdkEventExpose *) { try { - PreEditString pes(im_context); - PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), pes.str); - pango_layout_set_attributes(layout, pes.attrs); - - cairo_t *context = gdk_cairo_create(WindowFromWidget(widget)); - cairo_move_to(context, 0, 0); - pango_cairo_show_layout(context, layout); - cairo_destroy(context); - g_object_unref(layout); + PreEditString pes(im_context.get()); + UniquePangoLayout layout(gtk_widget_create_pango_layout(PWidget(wText), pes.str)); + pango_layout_set_attributes(layout.get(), pes.attrs); + + UniqueCairo context(gdk_cairo_create(WindowFromWidget(widget))); + cairo_move_to(context.get(), 0, 0); + pango_cairo_show_layout(context.get(), layout.get()); } catch (...) { errorStatus = Status::Failure; } @@ -2361,7 +2368,7 @@ gboolean ScintillaGTK::ExposePreedit(GtkWidget *widget, GdkEventExpose *ose, Sci #endif
bool ScintillaGTK::KoreanIME() { - PreEditString pes(im_context); + PreEditString pes(im_context.get()); if (pes.pscript != G_UNICODE_SCRIPT_COMMON) lastNonCommonScript = pes.pscript; return lastNonCommonScript == G_UNICODE_SCRIPT_HANGUL; @@ -2456,7 +2463,7 @@ void ScintillaGTK::SetCandidateWindowPos() { imeBox.y = static_cast<gint>(pt.y + std::max(4, vs.lineHeight/4)); // prevent overlapping with current line imeBox.height = vs.lineHeight; - gtk_im_context_set_cursor_location(im_context, &imeBox); + gtk_im_context_set_cursor_location(im_context.get(), &imeBox); }
void ScintillaGTK::CommitThis(char *commitStr) { @@ -2497,7 +2504,7 @@ void ScintillaGTK::PreeditChangedInlineThis() { // Great thanks for my foreruners, jiniya and BLUEnLIVE try { if (pdoc->IsReadOnly() || SelectionContainsProtected()) { - gtk_im_context_reset(im_context); + gtk_im_context_reset(im_context.get()); return; }
@@ -2512,7 +2519,7 @@ void ScintillaGTK::PreeditChangedInlineThis() { initialCompose = true; }
- PreEditString preeditStr(im_context); + PreEditString preeditStr(im_context.get()); const char *charSetSource = CharacterSetID();
if (!preeditStr.validUTF8 || (charSetSource == nullptr)) { @@ -2571,16 +2578,15 @@ void ScintillaGTK::PreeditChangedInlineThis() {
void ScintillaGTK::PreeditChangedWindowedThis() { try { - PreEditString pes(im_context); + PreEditString pes(im_context.get()); if (strlen(pes.str) > 0) { SetCandidateWindowPos();
- PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), pes.str); - pango_layout_set_attributes(layout, pes.attrs); + UniquePangoLayout layout(gtk_widget_create_pango_layout(PWidget(wText), pes.str)); + pango_layout_set_attributes(layout.get(), pes.attrs);
gint w, h; - pango_layout_get_pixel_size(layout, &w, &h); - g_object_unref(layout); + pango_layout_get_pixel_size(layout.get(), &w, &h);
gint x, y; gdk_window_get_origin(PWindow(wText), &x, &y); @@ -2611,6 +2617,65 @@ void ScintillaGTK::PreeditChanged(GtkIMContext *, ScintillaGTK *sciThis) { } }
+bool ScintillaGTK::RetrieveSurroundingThis(GtkIMContext *context) { + try { + const Sci::Position pos = CurrentPosition(); + const int line = pdoc->LineFromPosition(pos); + const Sci::Position startByte = pdoc->LineStart(line); + const Sci::Position endByte = pdoc->LineEnd(line); + + std::string utf8Text; + gint cursorIndex; // index of the cursor inside utf8Text, in bytes + const char *charSetBuffer; + + if (IsUnicodeMode() || ! *(charSetBuffer = CharacterSetID())) { + utf8Text = RangeText(startByte, endByte); + cursorIndex = pos - startByte; + } else { + // Need to convert + std::string tmpbuf = RangeText(startByte, pos); + utf8Text = ConvertText(&tmpbuf[0], tmpbuf.length(), "UTF-8", charSetBuffer, false); + cursorIndex = utf8Text.length(); + if (endByte > pos) { + tmpbuf = RangeText(pos, endByte); + utf8Text += ConvertText(&tmpbuf[0], tmpbuf.length(), "UTF-8", charSetBuffer, false); + } + } + + gtk_im_context_set_surrounding(context, &utf8Text[0], utf8Text.length(), cursorIndex); + + return true; + } catch (...) { + errorStatus = Status::Failure; + } + return false; +} + +gboolean ScintillaGTK::RetrieveSurrounding(GtkIMContext *context, ScintillaGTK *sciThis) { + return sciThis->RetrieveSurroundingThis(context); +} + +bool ScintillaGTK::DeleteSurroundingThis(GtkIMContext *, gint characterOffset, gint characterCount) { + try { + const Sci::Position startByte = pdoc->GetRelativePosition(CurrentPosition(), characterOffset); + if (startByte == INVALID_POSITION) + return false; + + const Sci::Position endByte = pdoc->GetRelativePosition(startByte, characterCount); + if (endByte == INVALID_POSITION) + return false; + + return pdoc->DeleteChars(startByte, endByte - startByte); + } catch (...) { + errorStatus = Status::Failure; + } + return false; +} + +gboolean ScintillaGTK::DeleteSurrounding(GtkIMContext *context, gint characterOffset, gint characterCount, ScintillaGTK *sciThis) { + return sciThis->DeleteSurroundingThis(context, characterOffset, characterCount); +} + void ScintillaGTK::StyleSetText(GtkWidget *widget, GtkStyle *, void *) { RealizeText(widget, nullptr); } @@ -2690,13 +2755,13 @@ gboolean ScintillaGTK::DrawTextThis(cairo_t *cr) {
rcPaint = GetClientRectangle();
- PLATFORM_ASSERT(rgnUpdate == nullptr); + cairo_rectangle_list_t *oldRgnUpdate = rgnUpdate; rgnUpdate = cairo_copy_clip_rectangle_list(cr); if (rgnUpdate && rgnUpdate->status != CAIRO_STATUS_SUCCESS) { // If not successful then ignore fprintf(stderr, "DrawTextThis failed to copy update region %d [%d]\n", rgnUpdate->status, rgnUpdate->num_rectangles); cairo_rectangle_list_destroy(rgnUpdate); - rgnUpdate = 0; + rgnUpdate = nullptr; }
double x1, y1, x2, y2; @@ -2721,7 +2786,7 @@ gboolean ScintillaGTK::DrawTextThis(cairo_t *cr) { if (rgnUpdate) { cairo_rectangle_list_destroy(rgnUpdate); } - rgnUpdate = 0; + rgnUpdate = oldRgnUpdate; paintState = PaintState::notPainting; } catch (...) { errorStatus = Status::Failure; @@ -2793,16 +2858,16 @@ gboolean ScintillaGTK::ExposeTextThis(GtkWidget * /*widget*/, GdkEventExpose *os ose->area.x + ose->area.width, ose->area.y + ose->area.height);
- PLATFORM_ASSERT(rgnUpdate == nullptr); + GdkRegion *oldRgnUpdate = rgnUpdate; rgnUpdate = gdk_region_copy(ose->region); const PRectangle rcClient = GetClientRectangle(); paintingAllText = rcPaint.Contains(rcClient); - std::unique_ptr<Surface> surfaceWindow(Surface::Allocate(Technology::Default)); - cairo_t *cr = gdk_cairo_create(PWindow(wText)); - surfaceWindow->Init(cr, PWidget(wText)); - Paint(surfaceWindow.get(), rcPaint); - surfaceWindow->Release(); - cairo_destroy(cr); + { + std::unique_ptr<Surface> surfaceWindow(Surface::Allocate(Technology::Default)); + UniqueCairo cr(gdk_cairo_create(PWindow(wText))); + surfaceWindow->Init(cr.get(), PWidget(wText)); + Paint(surfaceWindow.get(), rcPaint); + } if ((paintState == PaintState::abandoned) || repaintFullWindow) { // Painting area was insufficient to cover new styling or brace highlight positions FullPaint(); @@ -2813,7 +2878,7 @@ gboolean ScintillaGTK::ExposeTextThis(GtkWidget * /*widget*/, GdkEventExpose *os if (rgnUpdate) { gdk_region_destroy(rgnUpdate); } - rgnUpdate = nullptr; + rgnUpdate = oldRgnUpdate; } catch (...) { errorStatus = Status::Failure; } @@ -3105,12 +3170,10 @@ gboolean ScintillaGTK::DrawCT(GtkWidget *widget, cairo_t *cr, CallTip *ctip) { gboolean ScintillaGTK::ExposeCT(GtkWidget *widget, GdkEventExpose * /*ose*/, CallTip *ctip) { try { std::unique_ptr<Surface> surfaceWindow(Surface::Allocate(Technology::Default)); - cairo_t *cr = gdk_cairo_create(WindowFromWidget(widget)); - surfaceWindow->Init(cr, widget); + UniqueCairo cr(gdk_cairo_create(WindowFromWidget(widget))); + surfaceWindow->Init(cr.get(), widget); surfaceWindow->SetMode(SurfaceMode(ctip->codePage, false)); ctip->PaintCT(surfaceWindow.get()); - surfaceWindow->Release(); - cairo_destroy(cr); } catch (...) { // No pointer back to Scintilla to save status } @@ -3249,9 +3312,9 @@ void ScintillaGTK::ClassInit(OBJECT_CLASS *object_class, GtkWidgetClass *widget_
static void scintilla_class_init(ScintillaClass *klass) { try { - OBJECT_CLASS *object_class = (OBJECT_CLASS *) klass; - GtkWidgetClass *widget_class = (GtkWidgetClass *) klass; - GtkContainerClass *container_class = (GtkContainerClass *) klass; + OBJECT_CLASS *object_class = reinterpret_cast<OBJECT_CLASS *>(klass); + GtkWidgetClass *widget_class = reinterpret_cast<GtkWidgetClass *>(klass); + GtkContainerClass *container_class = reinterpret_cast<GtkContainerClass *>(klass);
const GSignalFlags sigflags = static_cast<GSignalFlags>(G_SIGNAL_ACTION | G_SIGNAL_RUN_LAST); scintilla_signals[COMMAND_SIGNAL] = g_signal_new(
Modified: scintilla/gtk/ScintillaGTK.h 14 lines changed, 12 insertions(+), 2 deletions(-) =================================================================== @@ -33,10 +33,12 @@ class ScintillaGTK : public ScintillaBase { int verticalScrollBarWidth; int horizontalScrollBarHeight;
+ PRectangle rectangleClient; + SelectionText primary; SelectionPosition posPrimary;
- GdkEvent *evbtn; + UniqueGdkEvent evbtn; guint buttonMouse; bool capturedMouse; bool dragWasDropped; @@ -60,7 +62,7 @@ class ScintillaGTK : public ScintillaBase { bool preeditInitialized; Window wPreedit; Window wPreeditDraw; - GtkIMContext *im_context; + UniqueIMContext im_context; GUnicodeScript lastNonCommonScript;
GtkSettings *settings; @@ -82,6 +84,7 @@ class ScintillaGTK : public ScintillaBase { bool repaintFullWindow;
guint styleIdleID; + guint scrollBarIdleID = 0; FontOptions fontOptionsPrevious; int accessibilityEnabled; AtkObject *accessible; @@ -127,12 +130,14 @@ class ScintillaGTK : public ScintillaBase { bool HaveMouseCapture() override; bool PaintContains(PRectangle rc) override; void FullPaint(); + void SetClientRectangle(); PRectangle GetClientRectangle() const override; void ScrollText(Sci::Line linesToMove) override; void SetVerticalScrollPos() override; void SetHorizontalScrollPos() override; bool ModifyScrollBars(Sci::Line nMax, Sci::Line nPage) override; void ReconfigureScrollBars() override; + void SetScrollBars() override; void NotifyChange() override; void NotifyFocus(bool focus) override; void NotifyParent(Scintilla::NotificationData scn) override; @@ -233,6 +238,11 @@ class ScintillaGTK : public ScintillaBase { void PreeditChangedInlineThis(); void PreeditChangedWindowedThis(); static void PreeditChanged(GtkIMContext *context, ScintillaGTK *sciThis); + bool RetrieveSurroundingThis(GtkIMContext *context); + static gboolean RetrieveSurrounding(GtkIMContext *context, ScintillaGTK *sciThis); + bool DeleteSurroundingThis(GtkIMContext *context, gint characterOffset, gint characterCount); + static gboolean DeleteSurrounding(GtkIMContext *context, gint characterOffset, gint characterCount, + ScintillaGTK *sciThis); void MoveImeCarets(Sci::Position pos); void DrawImeIndicator(int indicator, Sci::Position len); void SetCandidateWindowPos();
Modified: scintilla/gtk/ScintillaGTKAccessible.cxx 9 lines changed, 5 insertions(+), 4 deletions(-) =================================================================== @@ -131,6 +131,7 @@ #include "AutoComplete.h" #include "ScintillaBase.h"
+#include "Wrappers.h" #include "ScintillaGTK.h" #include "ScintillaGTKAccessible.h"
@@ -187,15 +188,15 @@ gchar *ScintillaGTKAccessible::GetTextRangeUTF8(Sci::Position startByte, Sci::Po // like TargetAsUTF8, but avoids a double conversion if (sci->IsUnicodeMode() || ! *(charSetBuffer = sci->CharacterSetID())) { int len = endByte - startByte; - utf8Text = (char *) g_malloc(len + 1); + utf8Text = static_cast<gchar *>(g_malloc(len + 1)); sci->pdoc->GetCharRange(utf8Text, startByte, len); utf8Text[len] = '\0'; } else { // Need to convert std::string s = sci->RangeText(startByte, endByte); std::string tmputf = ConvertText(&s[0], s.length(), "UTF-8", charSetBuffer, false); size_t len = tmputf.length(); - utf8Text = (char *) g_malloc(len + 1); + utf8Text = static_cast<gchar *>(g_malloc(len + 1)); memcpy(utf8Text, tmputf.c_str(), len); utf8Text[len] = '\0'; } @@ -1084,11 +1085,11 @@ static GType scintilla_object_accessible_get_type(GType parent_type G_GNUC_UNUSE static AtkObject *scintilla_object_accessible_new(GType parent_type, GObject *obj) { g_return_val_if_fail(SCINTILLA_IS_OBJECT(obj), nullptr);
- AtkObject *accessible = (AtkObject *) g_object_new(scintilla_object_accessible_get_type(parent_type), + AtkObject *accessible = static_cast<AtkObject *>(g_object_new(scintilla_object_accessible_get_type(parent_type), #if HAVE_WIDGET_SET_UNSET "widget", obj, #endif - nullptr); + nullptr)); atk_object_initialize(accessible, obj);
return accessible;
Modified: scintilla/gtk/Wrappers.h 109 lines changed, 109 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,109 @@ +// Scintilla source code edit control +// Wrappers.h - Encapsulation of GLib, GObject, Pango, Cairo, GTK, and GDK types +// Copyright 2022 by Neil Hodgson neilh@scintilla.org +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef WRAPPERS_H +#define WRAPPERS_H + +namespace Scintilla::Internal { + +// GLib + +struct GFreeReleaser { + template <class T> + void operator()(T *object) noexcept { + g_free(object); + } +}; + +using UniqueStr = std::unique_ptr<gchar, GFreeReleaser>; + +// GObject + +struct GObjectReleaser { + // Called by unique_ptr to destroy/free the object + template <class T> + void operator()(T *object) noexcept { + g_object_unref(object); + } +}; + +// Pango + +using UniquePangoContext = std::unique_ptr<PangoContext, GObjectReleaser>; +using UniquePangoLayout = std::unique_ptr<PangoLayout, GObjectReleaser>; +using UniquePangoFontMap = std::unique_ptr<PangoFontMap, GObjectReleaser>; + +struct FontDescriptionReleaser { + void operator()(PangoFontDescription *fontDescription) noexcept { + pango_font_description_free(fontDescription); + } +}; + +using UniquePangoFontDescription = std::unique_ptr<PangoFontDescription, FontDescriptionReleaser>; + +struct FontMetricsReleaser { + void operator()(PangoFontMetrics *metrics) noexcept { + pango_font_metrics_unref(metrics); + } +}; + +using UniquePangoFontMetrics = std::unique_ptr<PangoFontMetrics, FontMetricsReleaser>; + +struct LayoutIterReleaser { + // Called by unique_ptr to destroy/free the object + void operator()(PangoLayoutIter *iter) noexcept { + pango_layout_iter_free(iter); + } +}; + +using UniquePangoLayoutIter = std::unique_ptr<PangoLayoutIter, LayoutIterReleaser>; + +// Cairo + +struct CairoReleaser { + void operator()(cairo_t *context) noexcept { + cairo_destroy(context); + } +}; + +using UniqueCairo = std::unique_ptr<cairo_t, CairoReleaser>; + +struct CairoSurfaceReleaser { + void operator()(cairo_surface_t *psurf) noexcept { + cairo_surface_destroy(psurf); + } +}; + +using UniqueCairoSurface = std::unique_ptr<cairo_surface_t, CairoSurfaceReleaser>; + +// GTK + +using UniqueIMContext = std::unique_ptr<GtkIMContext, GObjectReleaser>; + +// GDK + +struct GdkEventReleaser { + void operator()(GdkEvent *ev) noexcept { + gdk_event_free(ev); + } +}; + +using UniqueGdkEvent = std::unique_ptr<GdkEvent, GdkEventReleaser>; + +inline void UnRefCursor(GdkCursor *cursor) noexcept { +#if GTK_CHECK_VERSION(3,0,0) + g_object_unref(cursor); +#else + gdk_cursor_unref(cursor); +#endif +} + +[[nodiscard]] inline GdkWindow *WindowFromWidget(GtkWidget *w) noexcept { + return gtk_widget_get_window(w); +} + +} + +#endif
Modified: scintilla/include/Scintilla.h 60 lines changed, 59 insertions(+), 1 deletions(-) =================================================================== @@ -57,11 +57,13 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP #define SCI_GETCURRENTPOS 2008 #define SCI_GETANCHOR 2009 #define SCI_GETSTYLEAT 2010 +#define SCI_GETSTYLEINDEXAT 2038 #define SCI_REDO 2011 #define SCI_SETUNDOCOLLECTION 2012 #define SCI_SELECTALL 2013 #define SCI_SETSAVEPOINT 2014 #define SCI_GETSTYLEDTEXT 2015 +#define SCI_GETSTYLEDTEXTFULL 2778 #define SCI_CANREDO 2016 #define SCI_MARKERLINEFROMHANDLE 2017 #define SCI_MARKERDELETEHANDLE 2018 @@ -151,7 +153,12 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP #define SC_MARK_RGBAIMAGE 30 #define SC_MARK_BOOKMARK 31 #define SC_MARK_VERTICALBOOKMARK 32 +#define SC_MARK_BAR 33 #define SC_MARK_CHARACTER 10000 +#define SC_MARKNUM_HISTORY_REVERTED_TO_ORIGIN 21 +#define SC_MARKNUM_HISTORY_SAVED 22 +#define SC_MARKNUM_HISTORY_MODIFIED 23 +#define SC_MARKNUM_HISTORY_REVERTED_TO_MODIFIED 24 #define SC_MARKNUM_FOLDEREND 25 #define SC_MARKNUM_FOLDEROPENMID 26 #define SC_MARKNUM_FOLDERMIDTAIL 27 @@ -274,6 +281,8 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP #define SCI_STYLESETHOTSPOT 2409 #define SCI_STYLESETCHECKMONOSPACED 2254 #define SCI_STYLEGETCHECKMONOSPACED 2255 +#define SCI_STYLESETINVISIBLEREPRESENTATION 2256 +#define SCI_STYLEGETINVISIBLEREPRESENTATION 2257 #define SC_ELEMENT_LIST 0 #define SC_ELEMENT_LIST_BACK 1 #define SC_ELEMENT_LIST_SELECTED 2 @@ -352,14 +361,23 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP #define INDIC_POINTCHARACTER 19 #define INDIC_GRADIENT 20 #define INDIC_GRADIENTCENTRE 21 +#define INDIC_POINT_TOP 22 #define INDIC_CONTAINER 8 #define INDIC_IME 32 #define INDIC_IME_MAX 35 #define INDIC_MAX 35 #define INDICATOR_CONTAINER 8 #define INDICATOR_IME 32 #define INDICATOR_IME_MAX 35 -#define INDICATOR_MAX 35 +#define INDICATOR_HISTORY_REVERTED_TO_ORIGIN_INSERTION 36 +#define INDICATOR_HISTORY_REVERTED_TO_ORIGIN_DELETION 37 +#define INDICATOR_HISTORY_SAVED_INSERTION 38 +#define INDICATOR_HISTORY_SAVED_DELETION 39 +#define INDICATOR_HISTORY_MODIFIED_INSERTION 40 +#define INDICATOR_HISTORY_MODIFIED_DELETION 41 +#define INDICATOR_HISTORY_REVERTED_TO_MODIFIED_INSERTION 42 +#define INDICATOR_HISTORY_REVERTED_TO_MODIFIED_DELETION 43 +#define INDICATOR_MAX 43 #define SCI_INDICSETSTYLE 2080 #define SCI_INDICGETSTYLE 2081 #define SCI_INDICSETFORE 2082 @@ -473,7 +491,15 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP #define SCFIND_POSIX 0x00400000 #define SCFIND_CXX11REGEX 0x00800000 #define SCI_FINDTEXT 2150 +#define SCI_FINDTEXTFULL 2196 #define SCI_FORMATRANGE 2151 +#define SCI_FORMATRANGEFULL 2777 +#define SC_CHANGE_HISTORY_DISABLED 0 +#define SC_CHANGE_HISTORY_ENABLED 1 +#define SC_CHANGE_HISTORY_MARKERS 2 +#define SC_CHANGE_HISTORY_INDICATORS 4 +#define SCI_SETCHANGEHISTORY 2780 +#define SCI_GETCHANGEHISTORY 2781 #define SCI_GETFIRSTVISIBLELINE 2152 #define SCI_GETLINE 2153 #define SCI_GETLINECOUNT 2154 @@ -486,7 +512,9 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP #define SCI_SETSEL 2160 #define SCI_GETSELTEXT 2161 #define SCI_GETTEXTRANGE 2162 +#define SCI_GETTEXTRANGEFULL 2039 #define SCI_HIDESELECTION 2163 +#define SCI_GETSELECTIONHIDDEN 2088 #define SCI_POINTXFROMPOSITION 2164 #define SCI_POINTYFROMPOSITION 2165 #define SCI_LINEFROMPOSITION 2166 @@ -529,6 +557,7 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP #define SCI_TARGETWHOLEDOCUMENT 2690 #define SCI_REPLACETARGET 2194 #define SCI_REPLACETARGETRE 2195 +#define SCI_REPLACETARGETMINIMAL 2779 #define SCI_SEARCHINTARGET 2197 #define SCI_SETSEARCHFLAGS 2198 #define SCI_GETSEARCHFLAGS 2199 @@ -573,6 +602,7 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP #define SC_FOLDACTION_CONTRACT 0 #define SC_FOLDACTION_EXPAND 1 #define SC_FOLDACTION_TOGGLE 2 +#define SC_FOLDACTION_CONTRACT_EVERY_LEVEL 4 #define SCI_FOLDLINE 2237 #define SCI_FOLDCHILDREN 2238 #define SCI_EXPANDCHILDREN 2239 @@ -924,6 +954,8 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP #define SCI_INDICATOREND 2509 #define SCI_SETPOSITIONCACHE 2514 #define SCI_GETPOSITIONCACHE 2515 +#define SCI_SETLAYOUTTHREADS 2775 +#define SCI_GETLAYOUTTHREADS 2776 #define SCI_COPYALLOWLINE 2519 #define SCI_GETCHARACTERPOINTER 2520 #define SCI_GETRANGEPOINTER 2643 @@ -1101,6 +1133,7 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP #define SC_SUPPORTS_FRACTIONAL_STROKE_WIDTH 2 #define SC_SUPPORTS_TRANSLUCENT_STROKE 3 #define SC_SUPPORTS_PIXEL_MODIFICATION 4 +#define SC_SUPPORTS_THREAD_SAFE_MEASURE_WIDTHS 5 #define SCI_SUPPORTSFEATURE 2750 #define SC_LINECHARACTERINDEX_NONE 0 #define SC_LINECHARACTERINDEX_UTF32 1 @@ -1208,6 +1241,7 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP #define SC_AC_TAB 3 #define SC_AC_NEWLINE 4 #define SC_AC_COMMAND 5 +#define SC_AC_SINGLE_CHOICE 6 #define SC_CHARACTERSOURCE_DIRECT_INPUT 0 #define SC_CHARACTERSOURCE_TENTATIVE_INPUT 1 #define SC_CHARACTERSOURCE_IME_RESULT 2 @@ -1263,17 +1297,33 @@ struct Sci_CharacterRange { Sci_PositionCR cpMax; };
+struct Sci_CharacterRangeFull { + Sci_Position cpMin; + Sci_Position cpMax; +}; + struct Sci_TextRange { struct Sci_CharacterRange chrg; char *lpstrText; };
+struct Sci_TextRangeFull { + struct Sci_CharacterRangeFull chrg; + char *lpstrText; +}; + struct Sci_TextToFind { struct Sci_CharacterRange chrg; const char *lpstrText; struct Sci_CharacterRange chrgText; };
+struct Sci_TextToFindFull { + struct Sci_CharacterRangeFull chrg; + const char *lpstrText; + struct Sci_CharacterRangeFull chrgText; +}; + typedef void *Sci_SurfaceID;
struct Sci_Rectangle { @@ -1294,6 +1344,14 @@ struct Sci_RangeToFormat { struct Sci_CharacterRange chrg; };
+struct Sci_RangeToFormatFull { + Sci_SurfaceID hdc; + Sci_SurfaceID hdcTarget; + struct Sci_Rectangle rc; + struct Sci_Rectangle rcPage; + struct Sci_CharacterRangeFull chrg; +}; + #ifndef __cplusplus /* For the GTK+ platform, g-ir-scanner needs to have these typedefs. This * is not required in C++ code and actually seems to break ScintillaEditPy */
Modified: scintilla/include/Scintilla.iface 80 lines changed, 74 insertions(+), 6 deletions(-) =================================================================== @@ -60,9 +60,12 @@ ## cells -> pointer to array of cells, each cell containing a style byte and character byte ## pointer -> void* pointer that may point to a document, loader, internal text storage or similar ## textrange -> range of a min and a max position with an output string +## textrangefull -> range of a min and a max position with an output string - supports 64-bit ## findtext -> searchrange, text -> foundposition +## findtextfull -> searchrange, text -> foundposition ## keymod -> integer containing key in low half and modifiers in high half ## formatrange +## formatrangefull ## Enumeration types always start with a capital letter ## Types no longer used: ## findtextex -> searchrange @@ -130,6 +133,9 @@ get position GetAnchor=2009(,) # Returns the style byte at the position. get int GetStyleAt=2010(position pos,)
+# Returns the unsigned style byte at the position. +get int GetStyleIndexAt=2038(position pos,) + # Redoes the next action on the undo history. fun void Redo=2011(,)
@@ -148,6 +154,10 @@ fun void SetSavePoint=2014(,) # Returns the number of bytes in the buffer not including terminating NULs. fun position GetStyledText=2015(, textrange tr)
+# Retrieve a buffer of cells that can be past 2GB. +# Returns the number of bytes in the buffer not including terminating NULs. +fun position GetStyledTextFull=2778(, textrangefull tr) + # Are there any redoable actions in the undo history? fun bool CanRedo=2016(,)
@@ -352,6 +362,7 @@ val SC_MARK_UNDERLINE=29 val SC_MARK_RGBAIMAGE=30 val SC_MARK_BOOKMARK=31 val SC_MARK_VERTICALBOOKMARK=32 +val SC_MARK_BAR=33
val SC_MARK_CHARACTER=10000
@@ -379,7 +390,11 @@ ali SC_MARK_RGBAIMAGE=RGBA_IMAGE ali SC_MARK_VERTICALBOOKMARK=VERTICAL_BOOKMARK
enu MarkerOutline=SC_MARKNUM_ -# Markers used for outlining column. +# Markers used for outlining and change history columns. +val SC_MARKNUM_HISTORY_REVERTED_TO_ORIGIN=21 +val SC_MARKNUM_HISTORY_SAVED=22 +val SC_MARKNUM_HISTORY_MODIFIED=23 +val SC_MARKNUM_HISTORY_REVERTED_TO_MODIFIED=24 val SC_MARKNUM_FOLDEREND=25 val SC_MARKNUM_FOLDEROPENMID=26 val SC_MARKNUM_FOLDERMIDTAIL=27 @@ -683,6 +698,12 @@ set void StyleSetCheckMonospaced=2254(int style, bool checkMonospaced) # Get whether a style may be monospaced. get bool StyleGetCheckMonospaced=2255(int style,)
+# Set the invisible representation for a style. +set void StyleSetInvisibleRepresentation=2256(int style, string representation) + +# Get the invisible representation for a style. +get int StyleGetInvisibleRepresentation=2257(int style, stringresult representation) + enu Element=SC_ELEMENT_ val SC_ELEMENT_LIST=0 val SC_ELEMENT_LIST_BACK=1 @@ -836,6 +857,7 @@ val INDIC_POINT=18 val INDIC_POINTCHARACTER=19 val INDIC_GRADIENT=20 val INDIC_GRADIENTCENTRE=21 +val INDIC_POINT_TOP=22
# INDIC_CONTAINER, INDIC_IME, INDIC_IME_MAX, and INDIC_MAX are indicator numbers, # not IndicatorStyles so should not really be in the INDIC_ enumeration. @@ -849,7 +871,15 @@ enu IndicatorNumbers=INDICATOR_ val INDICATOR_CONTAINER=8 val INDICATOR_IME=32 val INDICATOR_IME_MAX=35 -val INDICATOR_MAX=35 +val INDICATOR_HISTORY_REVERTED_TO_ORIGIN_INSERTION=36 +val INDICATOR_HISTORY_REVERTED_TO_ORIGIN_DELETION=37 +val INDICATOR_HISTORY_SAVED_INSERTION=38 +val INDICATOR_HISTORY_SAVED_DELETION=39 +val INDICATOR_HISTORY_MODIFIED_INSERTION=40 +val INDICATOR_HISTORY_MODIFIED_DELETION=41 +val INDICATOR_HISTORY_REVERTED_TO_MODIFIED_INSERTION=42 +val INDICATOR_HISTORY_REVERTED_TO_MODIFIED_DELETION=43 +val INDICATOR_MAX=43
ali INDIC_TT=T_T ali INDIC_ROUNDBOX=ROUND_BOX @@ -1209,9 +1239,27 @@ ali SCFIND_CXX11REGEX=CXX11_REG_EX # Find some text in the document. fun position FindText=2150(FindOption searchFlags, findtext ft)
-# On Windows, will draw the document into a display context such as a printer. +# Find some text in the document. +fun position FindTextFull=2196(FindOption searchFlags, findtextfull ft) + +# Draw the document into a display context such as a printer. fun position FormatRange=2151(bool draw, formatrange fr)
+# Draw the document into a display context such as a printer. +fun position FormatRangeFull=2777(bool draw, formatrangefull fr) + +enu ChangeHistoryOption=SC_CHANGE_HISTORY_ +val SC_CHANGE_HISTORY_DISABLED=0 +val SC_CHANGE_HISTORY_ENABLED=1 +val SC_CHANGE_HISTORY_MARKERS=2 +val SC_CHANGE_HISTORY_INDICATORS=4 + +# Enable or disable change history. +set void SetChangeHistory=2780(ChangeHistoryOption changeHistory,) + +# Report change history status. +get ChangeHistoryOption GetChangeHistory=2781(,) + # Retrieve the display line at the top of the display. get line GetFirstVisibleLine=2152(,)
@@ -1252,9 +1300,16 @@ fun position GetSelText=2161(, stringresult text) # Return the length of the text. fun position GetTextRange=2162(, textrange tr)
+# Retrieve a range of text that can be past 2GB. +# Return the length of the text. +fun position GetTextRangeFull=2039(, textrangefull tr) + # Draw the selection either highlighted or in normal (non-highlighted) style. fun void HideSelection=2163(bool hide,)
+#Is the selection visible or hidden? +get bool GetSelectionHidden=2088(,) + # Retrieve the x value of the point in the window where a position is displayed. fun int PointXFromPosition=2164(, position pos)
@@ -1395,6 +1450,10 @@ fun position ReplaceTarget=2194(position length, string text) # caused by processing the \d patterns. fun position ReplaceTargetRE=2195(position length, string text)
+# Replace the target text with the argument text but ignore prefix and suffix that +# are the same as current. +fun position ReplaceTargetMinimal=2779(position length, string text) + # Search for a counted string in the target and set the target to the found # range. Text is counted so it can contain NULs. # Returns start of found range or -1 for failure in which case target is not moved. @@ -1518,6 +1577,7 @@ enu FoldAction=SC_FOLDACTION_ val SC_FOLDACTION_CONTRACT=0 val SC_FOLDACTION_EXPAND=1 val SC_FOLDACTION_TOGGLE=2 +val SC_FOLDACTION_CONTRACT_EVERY_LEVEL=4
# Expand or contract a fold header. fun void FoldLine=2237(line line, FoldAction action) @@ -2535,6 +2595,12 @@ set void SetPositionCache=2514(int size,) # How many entries are allocated to the position cache? get int GetPositionCache=2515(,)
+# Set maximum number of threads used for layout +set void SetLayoutThreads=2775(int threads,) + +# Get maximum number of threads used for layout +get int GetLayoutThreads=2776(,) + # Copy the selection, if selection empty copy the line with the caret fun void CopyAllowLine=2519(,)
@@ -2924,13 +2990,13 @@ get Technology GetTechnology=2631(,) # Create an ILoader*. fun pointer CreateLoader=2632(position bytes, DocumentOption documentOptions)
-# On OS X, show a find indicator. +# On macOS, show a find indicator. fun void FindIndicatorShow=2640(position start, position end)
-# On OS X, flash a find indicator, then fade out. +# On macOS, flash a find indicator, then fade out. fun void FindIndicatorFlash=2641(position start, position end)
-# On OS X, hide the find indicator. +# On macOS, hide the find indicator. fun void FindIndicatorHide=2642(,)
# Move caret to before first visible character on display line. @@ -3040,6 +3106,7 @@ val SC_SUPPORTS_PIXEL_DIVISIONS=1 val SC_SUPPORTS_FRACTIONAL_STROKE_WIDTH=2 val SC_SUPPORTS_TRANSLUCENT_STROKE=3 val SC_SUPPORTS_PIXEL_MODIFICATION=4 +val SC_SUPPORTS_THREAD_SAFE_MEASURE_WIDTHS=5
# Get whether a feature is supported get bool SupportsFeature=2750(Supports feature,) @@ -3287,6 +3354,7 @@ val SC_AC_DOUBLECLICK=2 val SC_AC_TAB=3 val SC_AC_NEWLINE=4 val SC_AC_COMMAND=5 +val SC_AC_SINGLE_CHOICE=6
ali SC_AC_FILLUP=FILL_UP ali SC_AC_DOUBLECLICK=DOUBLE_CLICK
Modified: scintilla/include/ScintillaCall.h 21 lines changed, 21 insertions(+), 0 deletions(-) =================================================================== @@ -15,6 +15,11 @@ namespace Scintilla {
enum class Message; // Declare in case ScintillaMessages.h not included
+// Declare in case ScintillaStructures.h not included +struct TextRangeFull; +struct TextToFindFull; +struct RangeToFormatFull; + using FunctionDirect = intptr_t(*)(intptr_t ptr, unsigned int iMessage, uintptr_t wParam, intptr_t lParam, int *pStatus);
struct Failure { @@ -68,8 +73,10 @@ class ScintillaCall { char CharacterAt(Position position); int UnsignedStyleAt(Position position); std::string StringOfSpan(Span span); + std::string StringOfRange(Span span); Position ReplaceTarget(std::string_view text); Position ReplaceTargetRE(std::string_view text); + Position ReplaceTargetMinimal(std::string_view text); Position SearchInTarget(std::string_view text); Span SpanSearchInTarget(std::string_view text);
@@ -88,11 +95,13 @@ class ScintillaCall { Position CurrentPos(); Position Anchor(); int StyleAt(Position pos); + int StyleIndexAt(Position pos); void Redo(); void SetUndoCollection(bool collectUndo); void SelectAll(); void SetSavePoint(); Position GetStyledText(void *tr); + Position GetStyledTextFull(TextRangeFull *tr); bool CanRedo(); Line MarkerLineFromHandle(int markerHandle); void MarkerDeleteHandle(int markerHandle); @@ -198,6 +207,9 @@ class ScintillaCall { void StyleSetHotSpot(int style, bool hotspot); void StyleSetCheckMonospaced(int style, bool checkMonospaced); bool StyleGetCheckMonospaced(int style); + void StyleSetInvisibleRepresentation(int style, const char *representation); + int StyleGetInvisibleRepresentation(int style, char *representation); + std::string StyleGetInvisibleRepresent@@ Diff output truncated at 100000 characters. @@
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).