diff options
author | Neil Hodgson <nyamatongwe@gmail.com> | 2022-01-31 20:05:46 +1100 |
---|---|---|
committer | Neil Hodgson <nyamatongwe@gmail.com> | 2022-01-31 20:05:46 +1100 |
commit | 6b3871584c3f32a8c9bd603b03c255ba01ab5059 (patch) | |
tree | c44b13fb7d40464c62b2c51e294748fff79193b4 /gtk | |
parent | 185ab609951ba9d9fc14cdb42e4ddb4e015d5a36 (diff) | |
download | scintilla-mirror-6b3871584c3f32a8c9bd603b03c255ba01ab5059.tar.gz |
Implement more unique_ptr allocation wrappers and place in new Wrappers.h header.
Diffstat (limited to 'gtk')
-rwxr-xr-x | gtk/PlatGTK.cxx | 239 | ||||
-rwxr-xr-x | gtk/ScintillaGTK.cxx | 148 | ||||
-rwxr-xr-x | gtk/ScintillaGTK.h | 4 | ||||
-rw-r--r-- | gtk/ScintillaGTKAccessible.cxx | 1 | ||||
-rw-r--r-- | gtk/Wrappers.h | 109 | ||||
-rw-r--r-- | gtk/deps.mak | 3 |
6 files changed, 247 insertions, 257 deletions
diff --git a/gtk/PlatGTK.cxx b/gtk/PlatGTK.cxx index c303b66bf..c85670350 100755 --- a/gtk/PlatGTK.cxx +++ b/gtk/PlatGTK.cxx @@ -39,6 +39,7 @@ #include "XPM.h" #include "UniConversion.h" +#include "Wrappers.h" #include "Converter.h" #ifdef _MSC_VER @@ -69,26 +70,10 @@ 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); } -struct GObjectReleaser { - // Called by unique_ptr to destroy/free the object - template <class T> - void operator()(T *object) noexcept { - g_object_unref(object); - } -}; - -using UniquePangoContext = std::unique_ptr<PangoContext, GObjectReleaser>; -using UniquePangoLayout = std::unique_ptr<PangoLayout, GObjectReleaser>; -using UniquePangoFontMap = std::unique_ptr<PangoFontMap, GObjectReleaser>; - void SetFractionalPositions([[maybe_unused]] PangoContext *pcontext) noexcept { #if PANGO_VERSION_CHECK(1,44,3) pango_context_set_round_glyph_positions(pcontext, FALSE); @@ -104,35 +89,19 @@ 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, pango_units_from_double(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 @@ -157,9 +126,9 @@ class SurfaceImpl : public Surface { EncodingType et= EncodingType::singleByte; WindowID widSave = nullptr; cairo_t *context = nullptr; - cairo_surface_t *psurf = nullptr; + UniqueCairo pixmapContext; + UniqueCairoSurface surf; bool inited = false; - bool createdGC = false; UniquePangoContext pcontext; double resolution = 1.0; PangoDirection direction = PANGO_DIRECTION_LTR; @@ -168,6 +137,7 @@ class SurfaceImpl : public Surface { UniquePangoLayout layout; Converter conv; CharacterSet characterSet = static_cast<CharacterSet>(-1); + void PenColourAlpha(ColourRGBA fore) noexcept; void SetConverter(CharacterSet characterSet_); void CairoRectangle(PRectangle rc) noexcept; @@ -179,7 +149,7 @@ public: SurfaceImpl(SurfaceImpl&&) = delete; SurfaceImpl&operator=(const SurfaceImpl&) = delete; SurfaceImpl&operator=(SurfaceImpl&&) = delete; - ~SurfaceImpl() override; + ~SurfaceImpl() override = default; void GetContextState() noexcept; UniquePangoContext MeasuringContext(); @@ -190,7 +160,6 @@ public: void SetMode(SurfaceMode mode_) override; - void Clear() noexcept; void Release() noexcept override; int SupportsFeature(Supports feature) noexcept override; bool Initialised() override; @@ -328,10 +297,11 @@ 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); + CAIRO_CONTENT_COLOR_ALPHA, width, height)); + pixmapContext.reset(cairo_create(surf.get())); + context = pixmapContext.get(); pcontext.reset(gtk_widget_create_pango_context(PWidget(wid))); PLATFORM_ASSERT(pcontext); SetFractionalPositions(pcontext.get()); @@ -342,26 +312,16 @@ SurfaceImpl::SurfaceImpl(cairo_t *context_, int width, int height, SurfaceMode m 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); - } + pixmapContext.reset(); context = nullptr; - if (psurf) - cairo_surface_destroy(psurf); - psurf = nullptr; + surf.reset(); layout.reset(); // fontOptions and language are owned by original context and don't need to be freed fontOptions = nullptr; @@ -370,11 +330,6 @@ void SurfaceImpl::Clear() noexcept { conv.Close(); characterSet = static_cast<CharacterSet>(-1); inited = false; - createdGC = false; -} - -void SurfaceImpl::Release() noexcept { - Clear(); } bool SurfaceImpl::Initialised() { @@ -424,9 +379,7 @@ void SurfaceImpl::Init(WindowID 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.reset(gtk_widget_create_pango_context(PWidget(wid))); PLATFORM_ASSERT(pcontext); SetFractionalPositions(pcontext.get()); @@ -449,7 +402,6 @@ void SurfaceImpl::Init(SurfaceID sid, WindowID wid) { GetContextState(); layout.reset(pango_layout_new(pcontext.get())); cairo_set_line_width(context, 1); - createdGC = true; inited = true; } @@ -564,9 +516,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); @@ -670,12 +622,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) { @@ -749,10 +699,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); @@ -823,7 +773,7 @@ void SurfaceImpl::DrawTextBase(PRectangle rc, const Font *font_, XYPOSITION ybas if (context) { PenColourAlpha(fore); const XYPOSITION xText = rc.left; - if (PFont(font_)->pfd) { + if (PFont(font_)->fd) { std::string utfForm; if (et == EncodingType::utf8) { LayoutSetText(layout.get(), text); @@ -835,7 +785,7 @@ void SurfaceImpl::DrawTextBase(PRectangle rc, const Font *font_, XYPOSITION ybas } LayoutSetText(layout.get(), utfForm); } - pango_layout_set_font_description(layout.get(), PFont(font_)->pfd); + 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); @@ -869,36 +819,28 @@ void SurfaceImpl::DrawTextTransparent(PRectangle rc, const Font *font_, XYPOSITI } class ClusterIterator { - PangoLayoutIter *iter; - PangoRectangle pos; + 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(static_cast<int>(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)); + 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); + 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); + curIndex = pango_layout_iter_get_index(iter.get()); } else { finished = true; position = pango_units_to_double(pos.x + pos.width); @@ -909,17 +851,16 @@ public: }; void SurfaceImpl::MeasureWidths(const Font *font_, std::string_view text, XYPOSITION *positions) { - if (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_)->pfd); + 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; - LayoutSetText(layoutMeasure.get(), text); - ClusterIterator iti(layoutMeasure.get(), text.length()); + ClusterIterator iti(layoutMeasure.get(), text); while (!iti.finished) { iti.Next(); const int places = iti.curIndex - i; @@ -943,10 +884,9 @@ void SurfaceImpl::MeasureWidths(const Font *font_, std::string_view text, XYPOSI // Loop through UTF-8 and DBCS forms, taking account of different // character byte lengths. Converter convMeasure("UCS-2", CharacterSetID(characterSet), false); - LayoutSetText(layoutMeasure.get(), utfForm); int i = 0; int clusterStart = 0; - ClusterIterator iti(layoutMeasure.get(), utfForm.length()); + ClusterIterator iti(layoutMeasure.get(), utfForm); while (!iti.finished) { iti.Next(); const int clusterEnd = iti.curIndex; @@ -975,12 +915,11 @@ void SurfaceImpl::MeasureWidths(const Font *font_, std::string_view text, XYPOSI if (utfForm.empty()) { utfForm = UTF8FromLatin1(text); } - LayoutSetText(layoutMeasure.get(), utfForm); 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(layoutMeasure.get(), utfForm.length()); + ClusterIterator iti(layoutMeasure.get(), utfForm); while (!iti.finished) { iti.Next(); const int clusterEnd = iti.curIndex; @@ -1017,9 +956,9 @@ void SurfaceImpl::MeasureWidths(const Font *font_, std::string_view text, XYPOSI } XYPOSITION SurfaceImpl::WidthText(const Font *font_, std::string_view text) { - if (PFont(font_)->pfd) { + if (PFont(font_)->fd) { std::string utfForm; - pango_layout_set_font_description(layout.get(), PFont(font_)->pfd); + pango_layout_set_font_description(layout.get(), PFont(font_)->fd.get()); if (et == EncodingType::utf8) { LayoutSetText(layout.get(), text); } else { @@ -1043,9 +982,9 @@ void SurfaceImpl::DrawTextBaseUTF8(PRectangle rc, const Font *font_, XYPOSITION if (context) { PenColourAlpha(fore); const XYPOSITION xText = rc.left; - if (PFont(font_)->pfd) { + if (PFont(font_)->fd) { LayoutSetText(layout.get(), text); - pango_layout_set_font_description(layout.get(), PFont(font_)->pfd); + 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); @@ -1079,16 +1018,15 @@ 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) { + 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_)->pfd); + pango_layout_set_font_description(layoutMeasure.get(), PFont(font_)->fd.get()); // Simple and direct as UTF-8 is native Pango encoding int i = 0; - LayoutSetText(layoutMeasure.get(), text); - ClusterIterator iti(layoutMeasure.get(), text.length()); + ClusterIterator iti(layoutMeasure.get(), text); while (!iti.finished) { iti.Next(); const int places = iti.curIndex - i; @@ -1111,8 +1049,8 @@ void SurfaceImpl::MeasureWidthsUTF8(const Font *font_, std::string_view text, XY } XYPOSITION SurfaceImpl::WidthTextUTF8(const Font *font_, std::string_view text) { - if (PFont(font_)->pfd) { - pango_layout_set_font_description(layout.get(), PFont(font_)->pfd); + 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{}; @@ -1125,30 +1063,22 @@ XYPOSITION SurfaceImpl::WidthTextUTF8(const Font *font_, std::string_view text) // 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.get(), - PFont(font_)->pfd, language); - ascent = std::ceil(pango_units_to_double( - 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.get(), - PFont(font_)->pfd, language); - const XYPOSITION descent = std::ceil(pango_units_to_double( - 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 *) { @@ -1345,11 +1275,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 @@ -1416,7 +1342,7 @@ class ListBoxX : public ListBox { 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; @@ -1426,9 +1352,6 @@ public: 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. @@ -1445,12 +1368,6 @@ public: 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; @@ -1646,7 +1563,7 @@ 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 @@ -1675,7 +1592,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 @@ -1722,11 +1639,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) << "; "; @@ -1743,11 +1660,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); @@ -2202,7 +2119,7 @@ void Platform::DebugDisplay(const char *s) noexcept { fprintf(stderr, "%s", s); } -//#define TRACE +#define TRACE #ifdef TRACE void Platform::DebugPrintf(const char *format, ...) noexcept { diff --git a/gtk/ScintillaGTK.cxx b/gtk/ScintillaGTK.cxx index 8a188d769..5c6161cc2 100755 --- a/gtk/ScintillaGTK.cxx +++ b/gtk/ScintillaGTK.cxx @@ -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,9 +183,9 @@ 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 @@ -205,7 +193,6 @@ FontOptions::FontOptions(GtkWidget *widget) noexcept { 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,10 +259,6 @@ ScintillaGTK::~ScintillaGTK() { g_source_remove(styleIdleID); styleIdleID = 0; } - if (evbtn) { - gdk_event_free(evbtn); - evbtn = nullptr; - } ClearPrimarySelection(); wPreedit.Destroy(); if (settingsHandlerId) { @@ -317,7 +299,6 @@ 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); @@ -325,19 +306,19 @@ void ScintillaGTK::RealizeThis(GtkWidget *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)); + 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 +369,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); @@ -504,8 +484,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 +518,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; @@ -765,14 +745,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 } @@ -1221,15 +1201,14 @@ public: 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; } } @@ -1256,14 +1235,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 +1257,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 +1285,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); } } @@ -1849,10 +1819,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(); @@ -2249,7 +2216,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 +2274,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 +2284,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 +2304,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 +2324,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 +2419,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 +2460,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 +2475,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 +2534,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); @@ -2797,12 +2759,12 @@ gboolean ScintillaGTK::ExposeTextThis(GtkWidget * /*widget*/, GdkEventExpose *os 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(); @@ -3105,12 +3067,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 } diff --git a/gtk/ScintillaGTK.h b/gtk/ScintillaGTK.h index 36e6a78a8..9e9858c55 100755 --- a/gtk/ScintillaGTK.h +++ b/gtk/ScintillaGTK.h @@ -36,7 +36,7 @@ class ScintillaGTK : public ScintillaBase { SelectionText primary; SelectionPosition posPrimary; - GdkEvent *evbtn; + UniqueGdkEvent evbtn; guint buttonMouse; bool capturedMouse; bool dragWasDropped; @@ -60,7 +60,7 @@ class ScintillaGTK : public ScintillaBase { bool preeditInitialized; Window wPreedit; Window wPreeditDraw; - GtkIMContext *im_context; + UniqueIMContext im_context; GUnicodeScript lastNonCommonScript; GtkSettings *settings; diff --git a/gtk/ScintillaGTKAccessible.cxx b/gtk/ScintillaGTKAccessible.cxx index e3c50e510..3e234ae2c 100644 --- a/gtk/ScintillaGTKAccessible.cxx +++ b/gtk/ScintillaGTKAccessible.cxx @@ -131,6 +131,7 @@ #include "AutoComplete.h" #include "ScintillaBase.h" +#include "Wrappers.h" #include "ScintillaGTK.h" #include "ScintillaGTKAccessible.h" diff --git a/gtk/Wrappers.h b/gtk/Wrappers.h new file mode 100644 index 000000000..a22605a03 --- /dev/null +++ b/gtk/Wrappers.h @@ -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 diff --git a/gtk/deps.mak b/gtk/deps.mak index a13c592cf..a754d3471 100644 --- a/gtk/deps.mak +++ b/gtk/deps.mak @@ -11,6 +11,7 @@ PlatGTK.o: \ ../include/ScintillaWidget.h \ ../src/XPM.h \ ../src/UniConversion.h \ + Wrappers.h \ Converter.h ScintillaGTK.o: \ ScintillaGTK.cxx \ @@ -53,6 +54,7 @@ ScintillaGTK.o: \ ../src/Editor.h \ ../src/AutoComplete.h \ ../src/ScintillaBase.h \ + Wrappers.h \ ScintillaGTK.h \ scintilla-marshal.h \ ScintillaGTKAccessible.h \ @@ -98,6 +100,7 @@ ScintillaGTKAccessible.o: \ ../src/Editor.h \ ../src/AutoComplete.h \ ../src/ScintillaBase.h \ + Wrappers.h \ ScintillaGTK.h \ ScintillaGTKAccessible.h AutoComplete.o: \ |