aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNeil Hodgson <nyamatongwe@gmail.com>2022-01-31 20:05:46 +1100
committerNeil Hodgson <nyamatongwe@gmail.com>2022-01-31 20:05:46 +1100
commit6b3871584c3f32a8c9bd603b03c255ba01ab5059 (patch)
treec44b13fb7d40464c62b2c51e294748fff79193b4
parent185ab609951ba9d9fc14cdb42e4ddb4e015d5a36 (diff)
downloadscintilla-mirror-6b3871584c3f32a8c9bd603b03c255ba01ab5059.tar.gz
Implement more unique_ptr allocation wrappers and place in new Wrappers.h header.
-rwxr-xr-xgtk/PlatGTK.cxx239
-rwxr-xr-xgtk/ScintillaGTK.cxx148
-rwxr-xr-xgtk/ScintillaGTK.h4
-rw-r--r--gtk/ScintillaGTKAccessible.cxx1
-rw-r--r--gtk/Wrappers.h109
-rw-r--r--gtk/deps.mak3
-rw-r--r--scripts/HeaderOrder.txt1
7 files changed, 248 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: \
diff --git a/scripts/HeaderOrder.txt b/scripts/HeaderOrder.txt
index 5ec0646a6..33beb4d7e 100644
--- a/scripts/HeaderOrder.txt
+++ b/scripts/HeaderOrder.txt
@@ -153,6 +153,7 @@
#include "ScintillaWin.h"
// gtk
+#include "Wrappers.h"
#include "ScintillaGTK.h"
#include "scintilla-marshal.h"
#include "ScintillaGTKAccessible.h"