summaryrefslogtreecommitdiffstats
path: root/scintilla/gtk
diff options
context:
space:
mode:
Diffstat (limited to 'scintilla/gtk')
-rw-r--r--scintilla/gtk/Converter.h70
-rw-r--r--scintilla/gtk/PlatGTK.cxx2577
-rw-r--r--scintilla/gtk/ScintillaGTK.cxx2536
-rw-r--r--scintilla/gtk/deps.mak337
-rw-r--r--scintilla/gtk/makefile89
-rw-r--r--scintilla/gtk/scintilla-marshal.c86
-rw-r--r--scintilla/gtk/scintilla-marshal.h21
-rw-r--r--scintilla/gtk/scintilla-marshal.list1
8 files changed, 5717 insertions, 0 deletions
diff --git a/scintilla/gtk/Converter.h b/scintilla/gtk/Converter.h
new file mode 100644
index 0000000..9c5123b
--- /dev/null
+++ b/scintilla/gtk/Converter.h
@@ -0,0 +1,70 @@
+// Scintilla source code edit control
+// Converter.h - Encapsulation of iconv
+// Copyright 2004 by Neil Hodgson <neilh@scintilla.org>
+// The License.txt file describes the conditions under which this software may be distributed.
+
+typedef GIConv ConverterHandle;
+const ConverterHandle iconvhBad = (ConverterHandle)(-1);
+// Since various versions of iconv can not agree on whether the src argument
+// is char ** or const char ** provide a templatised adaptor.
+template<typename T>
+size_t iconv_adaptor(size_t(*f_iconv)(ConverterHandle, T, size_t *, char **, size_t *),
+ ConverterHandle cd, char** src, size_t *srcleft,
+ char **dst, size_t *dstleft) {
+ return f_iconv(cd, (T)src, srcleft, dst, dstleft);
+}
+/**
+ * Encapsulate iconv safely and avoid iconv_adaptor complexity in client code.
+ */
+class Converter {
+ ConverterHandle iconvh;
+ void OpenHandle(const char *fullDestination, const char *charSetSource) {
+ iconvh = g_iconv_open(fullDestination, charSetSource);
+ }
+ bool Succeeded() const {
+ return iconvh != iconvhBad;
+ }
+public:
+ Converter() {
+ iconvh = iconvhBad;
+ }
+ Converter(const char *charSetDestination, const char *charSetSource, bool transliterations) {
+ iconvh = iconvhBad;
+ Open(charSetDestination, charSetSource, transliterations);
+ }
+ ~Converter() {
+ Close();
+ }
+ operator bool() const {
+ return Succeeded();
+ }
+ void Open(const char *charSetDestination, const char *charSetSource, bool transliterations=true) {
+ Close();
+ if (*charSetSource) {
+ // Try allowing approximate transliterations
+ if (transliterations) {
+ char fullDest[200];
+ strcpy(fullDest, charSetDestination);
+ strcat(fullDest, "//TRANSLIT");
+ OpenHandle(fullDest, charSetSource);
+ }
+ if (!Succeeded()) {
+ // Transliterations failed so try basic name
+ OpenHandle(charSetDestination, charSetSource);
+ }
+ }
+ }
+ void Close() {
+ if (Succeeded()) {
+ g_iconv_close(iconvh);
+ iconvh = iconvhBad;
+ }
+ }
+ size_t Convert(char** src, size_t *srcleft, char **dst, size_t *dstleft) const {
+ if (!Succeeded()) {
+ return (size_t)(-1);
+ } else {
+ return iconv_adaptor(g_iconv, iconvh, src, srcleft, dst, dstleft);
+ }
+ }
+};
diff --git a/scintilla/gtk/PlatGTK.cxx b/scintilla/gtk/PlatGTK.cxx
new file mode 100644
index 0000000..b6e7f7e
--- /dev/null
+++ b/scintilla/gtk/PlatGTK.cxx
@@ -0,0 +1,2577 @@
+// Scintilla source code edit control
+// PlatGTK.cxx - implementation of platform facilities on GTK+/Linux
+// Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org>
+// The License.txt file describes the conditions under which this software may be distributed.
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+#include <glib.h>
+#include <gmodule.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "Platform.h"
+
+#include "Scintilla.h"
+#include "ScintillaWidget.h"
+#include "UniConversion.h"
+#include "XPM.h"
+
+/* GLIB must be compiled with thread support, otherwise we
+ will bail on trying to use locks, and that could lead to
+ problems for someone. `glib-config --libs gthread` needs
+ to be used to get the glib libraries for linking, otherwise
+ g_thread_init will fail */
+#define USE_LOCK defined(G_THREADS_ENABLED) && !defined(G_THREADS_IMPL_NONE)
+/* Use fast way of getting char data on win32 to work around problems
+ with gdk_string_extents. */
+#define FAST_WAY
+
+#include "Converter.h"
+
+#ifdef _MSC_VER
+// Ignore unreferenced local functions in GTK+ headers
+#pragma warning(disable: 4505)
+#endif
+
+#ifdef SCI_NAMESPACE
+using namespace Scintilla;
+#endif
+
+enum encodingType { singleByte, UTF8, dbcs};
+
+struct LOGFONT {
+ int size;
+ bool bold;
+ bool italic;
+ int characterSet;
+ char faceName[300];
+};
+
+#if USE_LOCK
+static GMutex *fontMutex = NULL;
+
+static void InitializeGLIBThreads() {
+ if (!g_thread_supported()) {
+ g_thread_init(NULL);
+ }
+}
+#endif
+
+static void FontMutexAllocate() {
+#if USE_LOCK
+ if (!fontMutex) {
+ InitializeGLIBThreads();
+ fontMutex = g_mutex_new();
+ }
+#endif
+}
+
+static void FontMutexFree() {
+#if USE_LOCK
+ if (fontMutex) {
+ g_mutex_free(fontMutex);
+ fontMutex = NULL;
+ }
+#endif
+}
+
+static void FontMutexLock() {
+#if USE_LOCK
+ g_mutex_lock(fontMutex);
+#endif
+}
+
+static void FontMutexUnlock() {
+#if USE_LOCK
+ if (fontMutex) {
+ g_mutex_unlock(fontMutex);
+ }
+#endif
+}
+
+// On GTK+ 1.x holds a GdkFont* but on GTK+ 2.x can hold a GdkFont* or a
+// PangoFontDescription*.
+class FontHandle {
+ int width[128];
+ encodingType et;
+public:
+ int ascent;
+ GdkFont *pfont;
+ PangoFontDescription *pfd;
+ int characterSet;
+ FontHandle(GdkFont *pfont_) {
+ et = singleByte;
+ ascent = 0;
+ pfont = pfont_;
+ pfd = 0;
+ characterSet = -1;
+ ResetWidths(et);
+ }
+ FontHandle(PangoFontDescription *pfd_, int characterSet_) {
+ et = singleByte;
+ ascent = 0;
+ pfont = 0;
+ pfd = pfd_;
+ characterSet = characterSet_;
+ ResetWidths(et);
+ }
+ ~FontHandle() {
+ if (pfont)
+ gdk_font_unref(pfont);
+ pfont = 0;
+ if (pfd)
+ pango_font_description_free(pfd);
+ pfd = 0;
+ }
+ void ResetWidths(encodingType et_) {
+ et = et_;
+ for (int i=0; i<=127; i++) {
+ width[i] = 0;
+ }
+ }
+ int CharWidth(unsigned char ch, encodingType et_) {
+ int w = 0;
+ FontMutexLock();
+ if ((ch <= 127) && (et == et_)) {
+ w = width[ch];
+ }
+ FontMutexUnlock();
+ return w;
+ }
+ void SetCharWidth(unsigned char ch, int w, encodingType et_) {
+ if (ch <= 127) {
+ FontMutexLock();
+ if (et != et_) {
+ ResetWidths(et_);
+ }
+ width[ch] = w;
+ FontMutexUnlock();
+ }
+ }
+};
+
+// X has a 16 bit coordinate space, so stop drawing here to avoid wrapping
+static const int maxCoordinate = 32000;
+
+static FontHandle *PFont(Font &f) {
+ return reinterpret_cast<FontHandle *>(f.GetID());
+}
+
+static GtkWidget *PWidget(WindowID wid) {
+ return reinterpret_cast<GtkWidget *>(wid);
+}
+
+static GtkWidget *PWidget(Window &w) {
+ return PWidget(w.GetID());
+}
+
+Point Point::FromLong(long lpoint) {
+ return Point(
+ Platform::LowShortFromLong(lpoint),
+ Platform::HighShortFromLong(lpoint));
+}
+
+Palette::Palette() {
+ used = 0;
+ allowRealization = false;
+ allocatedPalette = 0;
+ allocatedLen = 0;
+ size = 100;
+ entries = new ColourPair[size];
+}
+
+Palette::~Palette() {
+ Release();
+ delete []entries;
+ entries = 0;
+}
+
+void Palette::Release() {
+ used = 0;
+ delete [](reinterpret_cast<GdkColor *>(allocatedPalette));
+ allocatedPalette = 0;
+ allocatedLen = 0;
+ delete []entries;
+ size = 100;
+ entries = new ColourPair[size];
+}
+
+// This method either adds a colour to the list of wanted colours (want==true)
+// or retrieves the allocated colour back to the ColourPair.
+// This is one method to make it easier to keep the code for wanting and retrieving in sync.
+void Palette::WantFind(ColourPair &cp, bool want) {
+ if (want) {
+ for (int i=0; i < used; i++) {
+ if (entries[i].desired == cp.desired)
+ return;
+ }
+
+ if (used >= size) {
+ int sizeNew = size * 2;
+ ColourPair *entriesNew = new ColourPair[sizeNew];
+ for (int j=0; j<size; j++) {
+ entriesNew[j] = entries[j];
+ }
+ delete []entries;
+ entries = entriesNew;
+ size = sizeNew;
+ }
+
+ entries[used].desired = cp.desired;
+ entries[used].allocated.Set(cp.desired.AsLong());
+ used++;
+ } else {
+ for (int i=0; i < used; i++) {
+ if (entries[i].desired == cp.desired) {
+ cp.allocated = entries[i].allocated;
+ return;
+ }
+ }
+ cp.allocated.Set(cp.desired.AsLong());
+ }
+}
+
+void Palette::Allocate(Window &w) {
+ if (allocatedPalette) {
+ gdk_colormap_free_colors(gtk_widget_get_colormap(PWidget(w)),
+ reinterpret_cast<GdkColor *>(allocatedPalette),
+ allocatedLen);
+ delete [](reinterpret_cast<GdkColor *>(allocatedPalette));
+ allocatedPalette = 0;
+ allocatedLen = 0;
+ }
+ GdkColor *paletteNew = new GdkColor[used];
+ allocatedPalette = paletteNew;
+ gboolean *successPalette = new gboolean[used];
+ if (paletteNew) {
+ allocatedLen = used;
+ int iPal = 0;
+ for (iPal = 0; iPal < used; iPal++) {
+ paletteNew[iPal].red = entries[iPal].desired.GetRed() * (65535 / 255);
+ paletteNew[iPal].green = entries[iPal].desired.GetGreen() * (65535 / 255);
+ paletteNew[iPal].blue = entries[iPal].desired.GetBlue() * (65535 / 255);
+ paletteNew[iPal].pixel = entries[iPal].desired.AsLong();
+ }
+ gdk_colormap_alloc_colors(gtk_widget_get_colormap(PWidget(w)),
+ paletteNew, allocatedLen, FALSE, TRUE,
+ successPalette);
+ for (iPal = 0; iPal < used; iPal++) {
+ entries[iPal].allocated.Set(paletteNew[iPal].pixel);
+ }
+ }
+ delete []successPalette;
+}
+
+static const char *CharacterSetName(int characterSet) {
+ switch (characterSet) {
+ case SC_CHARSET_ANSI:
+ return "iso8859-*";
+ case SC_CHARSET_DEFAULT:
+ return "iso8859-*";
+ case SC_CHARSET_BALTIC:
+ return "iso8859-13";
+ case SC_CHARSET_CHINESEBIG5:
+ return "*-*";
+ case SC_CHARSET_EASTEUROPE:
+ return "*-2";
+ case SC_CHARSET_GB2312:
+ return "gb2312.1980-*";
+ case SC_CHARSET_GREEK:
+ return "*-7";
+ case SC_CHARSET_HANGUL:
+ return "ksc5601.1987-*";
+ case SC_CHARSET_MAC:
+ return "*-*";
+ case SC_CHARSET_OEM:
+ return "*-*";
+ case SC_CHARSET_RUSSIAN:
+ return "*-r";
+ case SC_CHARSET_CYRILLIC:
+ return "*-cp1251";
+ case SC_CHARSET_SHIFTJIS:
+ return "jisx0208.1983-*";
+ case SC_CHARSET_SYMBOL:
+ return "*-*";
+ case SC_CHARSET_TURKISH:
+ return "*-9";
+ case SC_CHARSET_JOHAB:
+ return "*-*";
+ case SC_CHARSET_HEBREW:
+ return "*-8";
+ case SC_CHARSET_ARABIC:
+ return "*-6";
+ case SC_CHARSET_VIETNAMESE:
+ return "*-*";
+ case SC_CHARSET_THAI:
+ return "iso8859-11";
+ case SC_CHARSET_8859_15:
+ return "iso8859-15";
+ default:
+ return "*-*";
+ }
+}
+
+static bool IsDBCSCharacterSet(int characterSet) {
+ switch (characterSet) {
+ case SC_CHARSET_GB2312:
+ case SC_CHARSET_HANGUL:
+ case SC_CHARSET_SHIFTJIS:
+ case SC_CHARSET_CHINESEBIG5:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static void GenerateFontSpecStrings(const char *fontName, int characterSet,
+ char *foundary, int foundary_len,
+ char *faceName, int faceName_len,
+ char *charset, int charset_len) {
+ // supported font strings include:
+ // foundary-fontface-isoxxx-x
+ // fontface-isoxxx-x
+ // foundary-fontface
+ // fontface
+ if (strchr(fontName, '-')) {
+ char tmp[300];
+ char *d1 = NULL, *d2 = NULL, *d3 = NULL;
+ strncpy(tmp, fontName, sizeof(tmp) - 1);
+ tmp[sizeof(tmp) - 1] = '\0';
+ d1 = strchr(tmp, '-');
+ // we know the first dash exists
+ d2 = strchr(d1 + 1, '-');
+ if (d2)
+ d3 = strchr(d2 + 1, '-');
+ if (d3 && d2) {
+ // foundary-fontface-isoxxx-x
+ *d2 = '\0';
+ foundary[0] = '-';
+ foundary[1] = '\0';
+ strncpy(faceName, tmp, foundary_len - 1);
+ strncpy(charset, d2 + 1, charset_len - 1);
+ } else if (d2) {
+ // fontface-isoxxx-x
+ *d1 = '\0';
+ strcpy(foundary, "-*-");
+ strncpy(faceName, tmp, faceName_len - 1);
+ strncpy(charset, d1 + 1, charset_len - 1);
+ } else {
+ // foundary-fontface
+ foundary[0] = '-';
+ foundary[1] = '\0';
+ strncpy(faceName, tmp, faceName_len - 1);
+ strncpy(charset, CharacterSetName(characterSet), charset_len - 1);
+ }
+ } else {
+ strncpy(foundary, "-*-", foundary_len);
+ strncpy(faceName, fontName, faceName_len - 1);
+ strncpy(charset, CharacterSetName(characterSet), charset_len - 1);
+ }
+}
+
+static void SetLogFont(LOGFONT &lf, const char *faceName, int characterSet, int size, bool bold, bool italic) {
+ memset(&lf, 0, sizeof(lf));
+ lf.size = size;
+ lf.bold = bold;
+ lf.italic = italic;
+ lf.characterSet = characterSet;
+ strncpy(lf.faceName, faceName, sizeof(lf.faceName) - 1);
+}
+
+/**
+ * Create a hash from the parameters for a font to allow easy checking for identity.
+ * If one font is the same as another, its hash will be the same, but if the hash is the
+ * same then they may still be different.
+ */
+static int HashFont(const char *faceName, int characterSet, int size, bool bold, bool italic) {
+ return
+ size ^
+ (characterSet << 10) ^
+ (bold ? 0x10000000 : 0) ^
+ (italic ? 0x20000000 : 0) ^
+ faceName[0];
+}
+
+class FontCached : Font {
+ FontCached *next;
+ int usage;
+ LOGFONT lf;
+ int hash;
+ FontCached(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_);
+ ~FontCached() {}
+ bool SameAs(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_);
+ virtual void Release();
+ static FontID CreateNewFont(const char *fontName, int characterSet,
+ int size, bool bold, bool italic);
+ static FontCached *first;
+public:
+ static FontID FindOrCreate(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_);
+ static void ReleaseId(FontID fid_);
+};
+
+FontCached *FontCached::first = 0;
+
+FontCached::FontCached(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_) :
+next(0), usage(0), hash(0) {
+ ::SetLogFont(lf, faceName_, characterSet_, size_, bold_, italic_);
+ hash = HashFont(faceName_, characterSet_, size_, bold_, italic_);
+ fid = CreateNewFont(faceName_, characterSet_, size_, bold_, italic_);
+ usage = 1;
+}
+
+bool FontCached::SameAs(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_) {
+ return
+ lf.size == size_ &&
+ lf.bold == bold_ &&
+ lf.italic == italic_ &&
+ lf.characterSet == characterSet_ &&
+ 0 == strcmp(lf.faceName, faceName_);
+}
+
+void FontCached::Release() {
+ if (fid)
+ delete PFont(*this);
+ fid = 0;
+}
+
+FontID FontCached::FindOrCreate(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_) {
+ FontID ret = 0;
+ FontMutexLock();
+ int hashFind = HashFont(faceName_, characterSet_, size_, bold_, italic_);
+ for (FontCached *cur = first; cur; cur = cur->next) {
+ if ((cur->hash == hashFind) &&
+ cur->SameAs(faceName_, characterSet_, size_, bold_, italic_)) {
+ cur->usage++;
+ ret = cur->fid;
+ }
+ }
+ if (ret == 0) {
+ FontCached *fc = new FontCached(faceName_, characterSet_, size_, bold_, italic_);
+ if (fc) {
+ fc->next = first;
+ first = fc;
+ ret = fc->fid;
+ }
+ }
+ FontMutexUnlock();
+ return ret;
+}
+
+void FontCached::ReleaseId(FontID fid_) {
+ FontMutexLock();
+ FontCached **pcur = &first;
+ for (FontCached *cur = first; cur; cur = cur->next) {
+ if (cur->fid == fid_) {
+ cur->usage--;
+ if (cur->usage == 0) {
+ *pcur = cur->next;
+ cur->Release();
+ cur->next = 0;
+ delete cur;
+ }
+ break;
+ }
+ pcur = &cur->next;
+ }
+ FontMutexUnlock();
+}
+
+static GdkFont *LoadFontOrSet(const char *fontspec, int characterSet) {
+ if (IsDBCSCharacterSet(characterSet)) {
+ return gdk_fontset_load(fontspec);
+ } else {
+ return gdk_font_load(fontspec);
+ }
+}
+
+FontID FontCached::CreateNewFont(const char *fontName, int characterSet,
+ int size, bool bold, bool italic) {
+ char fontset[1024];
+ char fontspec[300];
+ char foundary[50];
+ char faceName[100];
+ char charset[50];
+ fontset[0] = '\0';
+ fontspec[0] = '\0';
+ foundary[0] = '\0';
+ faceName[0] = '\0';
+ charset[0] = '\0';
+
+ if (fontName[0] == '!') {
+ PangoFontDescription *pfd = pango_font_description_new();
+ if (pfd) {
+ pango_font_description_set_family(pfd, fontName+1);
+ pango_font_description_set_size(pfd, size * PANGO_SCALE);
+ pango_font_description_set_weight(pfd, bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL);
+ pango_font_description_set_style(pfd, italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL);
+ return new FontHandle(pfd, characterSet);
+ }
+ }
+
+ GdkFont *newid = 0;
+ // If name of the font begins with a '-', assume, that it is
+ // a full fontspec.
+ if (fontName[0] == '-') {
+ if (strchr(fontName, ',') || IsDBCSCharacterSet(characterSet)) {
+ newid = gdk_fontset_load(fontName);
+ } else {
+ newid = gdk_font_load(fontName);
+ }
+ if (!newid) {
+ // Font not available so substitute a reasonable code font
+ // iso8859 appears to only allow western characters.
+ newid = LoadFontOrSet("-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-*",
+ characterSet);
+ }
+ return new FontHandle(newid);
+ }
+
+ // it's not a full fontspec, build one.
+
+ // This supports creating a FONT_SET
+ // in a method that allows us to also set size, slant and
+ // weight for the fontset. The expected input is multiple
+ // partial fontspecs seperated by comma
+ // eg. adobe-courier-iso10646-1,*-courier-iso10646-1,*-*-*-*
+ if (strchr(fontName, ',')) {
+ // build a fontspec and use gdk_fontset_load
+ int remaining = sizeof(fontset);
+ char fontNameCopy[1024];
+ strncpy(fontNameCopy, fontName, sizeof(fontNameCopy) - 1);
+ char *fn = fontNameCopy;
+ char *fp = strchr(fn, ',');
+ for (;;) {
+ const char *spec = "%s%s%s%s-*-*-*-%0d-*-*-*-*-%s";
+ if (fontset[0] != '\0') {
+ // if this is not the first font in the list,
+ // append a comma seperator
+ spec = ",%s%s%s%s-*-*-*-%0d-*-*-*-*-%s";
+ }
+
+ if (fp)
+ *fp = '\0'; // nullify the comma
+ GenerateFontSpecStrings(fn, characterSet,
+ foundary, sizeof(foundary),
+ faceName, sizeof(faceName),
+ charset, sizeof(charset));
+
+ g_snprintf(fontspec,
+ sizeof(fontspec) - 1,
+ spec,
+ foundary, faceName,
+ bold ? "-bold" : "-medium",
+ italic ? "-i" : "-r",
+ size * 10,
+ charset);
+
+ // if this is the first font in the list, and
+ // we are doing italic, add an oblique font
+ // to the list
+ if (italic && fontset[0] == '\0') {
+ strncat(fontset, fontspec, remaining - 1);
+ remaining -= strlen(fontset);
+
+ g_snprintf(fontspec,
+ sizeof(fontspec) - 1,
+ ",%s%s%s-o-*-*-*-%0d-*-*-*-*-%s",
+ foundary, faceName,
+ bold ? "-bold" : "-medium",
+ size * 10,
+ charset);
+ }
+
+ strncat(fontset, fontspec, remaining - 1);
+ remaining -= strlen(fontset);
+
+ if (!fp)
+ break;
+
+ fn = fp + 1;
+ fp = strchr(fn, ',');
+ }
+
+ newid = gdk_fontset_load(fontset);
+ if (newid)
+ return new FontHandle(newid);
+
+ // if fontset load failed, fall through, we'll use
+ // the last font entry and continue to try and
+ // get something that matches
+ }
+
+ // single fontspec support
+
+ GenerateFontSpecStrings(fontName, characterSet,
+ foundary, sizeof(foundary),
+ faceName, sizeof(faceName),
+ charset, sizeof(charset));
+
+ g_snprintf(fontspec,
+ sizeof(fontspec) - 1,
+ "%s%s%s%s-*-*-*-%0d-*-*-*-*-%s",
+ foundary, faceName,
+ bold ? "-bold" : "-medium",
+ italic ? "-i" : "-r",
+ size * 10,
+ charset);
+ newid = LoadFontOrSet(fontspec, characterSet);
+ if (!newid) {
+ // some fonts have oblique, not italic
+ g_snprintf(fontspec,
+ sizeof(fontspec) - 1,
+ "%s%s%s%s-*-*-*-%0d-*-*-*-*-%s",
+ foundary, faceName,
+ bold ? "-bold" : "-medium",
+ italic ? "-o" : "-r",
+ size * 10,
+ charset);
+ newid = LoadFontOrSet(fontspec, characterSet);
+ }
+ if (!newid) {
+ g_snprintf(fontspec,
+ sizeof(fontspec) - 1,
+ "-*-*-*-*-*-*-*-%0d-*-*-*-*-%s",
+ size * 10,
+ charset);
+ newid = gdk_font_load(fontspec);
+ }
+ if (!newid) {
+ // Font not available so substitute a reasonable code font
+ // iso8859 appears to only allow western characters.
+ newid = LoadFontOrSet("-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-*",
+ characterSet);
+ }
+ return new FontHandle(newid);
+}
+
+Font::Font() : fid(0) {}
+
+Font::~Font() {}
+
+void Font::Create(const char *faceName, int characterSet, int size,
+ bool bold, bool italic, int) {
+ Release();
+ fid = FontCached::FindOrCreate(faceName, characterSet, size, bold, italic);
+}
+
+void Font::Release() {
+ if (fid)
+ FontCached::ReleaseId(fid);
+ fid = 0;
+}
+
+// Required on OS X
+#ifdef SCI_NAMESPACE
+namespace Scintilla {
+#endif
+class SurfaceImpl : public Surface {
+ encodingType et;
+ GdkDrawable *drawable;
+ GdkGC *gc;
+ GdkPixmap *ppixmap;
+ int x;
+ int y;
+ bool inited;
+ bool createdGC;
+ PangoContext *pcontext;
+ PangoLayout *layout;
+ Converter conv;
+ int characterSet;
+ void SetConverter(int characterSet_);
+public:
+ SurfaceImpl();
+ virtual ~SurfaceImpl();
+
+ void Init(WindowID wid);
+ void Init(SurfaceID sid, WindowID wid);
+ void InitPixMap(int width, int height, Surface *surface_, WindowID wid);
+
+ void Release();
+ bool Initialised();
+ void PenColour(ColourAllocated fore);
+ int LogPixelsY();
+ int DeviceHeightFont(int points);
+ void MoveTo(int x_, int y_);
+ void LineTo(int x_, int y_);
+ void Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back);
+ void RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back);
+ void FillRectangle(PRectangle rc, ColourAllocated back);
+ void FillRectangle(PRectangle rc, Surface &surfacePattern);
+ void RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back);
+ void AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill,
+ ColourAllocated outline, int alphaOutline, int flags);
+ void Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back);
+ void Copy(PRectangle rc, Point from, Surface &surfaceSource);
+
+ void DrawTextBase(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore);
+ void DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back);
+ void DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back);
+ void DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore);
+ void MeasureWidths(Font &font_, const char *s, int len, int *positions);
+ int WidthText(Font &font_, const char *s, int len);
+ int WidthChar(Font &font_, char ch);
+ int Ascent(Font &font_);
+ int Descent(Font &font_);
+ int InternalLeading(Font &font_);
+ int ExternalLeading(Font &font_);
+ int Height(Font &font_);
+ int AverageCharWidth(Font &font_);
+
+ int SetPalette(Palette *pal, bool inBackGround);
+ void SetClip(PRectangle rc);
+ void FlushCachedState();
+
+ void SetUnicodeMode(bool unicodeMode_);
+ void SetDBCSMode(int codePage);
+};
+#ifdef SCI_NAMESPACE
+}
+#endif
+
+const char *CharacterSetID(int characterSet) {
+ switch (characterSet) {
+ case SC_CHARSET_ANSI:
+ return "";
+ case SC_CHARSET_DEFAULT:
+ return "ISO-8859-1";
+ case SC_CHARSET_BALTIC:
+ return "ISO-8859-13";
+ case SC_CHARSET_CHINESEBIG5:
+ return "BIG-5";
+ case SC_CHARSET_EASTEUROPE:
+ return "ISO-8859-2";
+ case SC_CHARSET_GB2312:
+ return "GB2312";
+ case SC_CHARSET_GREEK:
+ return "ISO-8859-7";
+ case SC_CHARSET_HANGUL:
+ return "";
+ case SC_CHARSET_MAC:
+ return "MACINTOSH";
+ case SC_CHARSET_OEM:
+ return "ASCII";
+ case SC_CHARSET_RUSSIAN:
+ return "KOI8-R";
+ case SC_CHARSET_CYRILLIC:
+ return "CP1251";
+ case SC_CHARSET_SHIFTJIS:
+ return "SHIFT-JIS";
+ case SC_CHARSET_SYMBOL:
+ return "";
+ case SC_CHARSET_TURKISH:
+ return "ISO-8859-9";
+ case SC_CHARSET_JOHAB:
+ return "JOHAB";
+ case SC_CHARSET_HEBREW:
+ return "ISO-8859-8";
+ case SC_CHARSET_ARABIC:
+ return "ISO-8859-6";
+ case SC_CHARSET_VIETNAMESE:
+ return "";
+ case SC_CHARSET_THAI:
+ return "ISO-8859-11";
+ case SC_CHARSET_8859_15:
+ return "ISO-8859-15";
+ default:
+ return "";
+ }
+}
+
+void SurfaceImpl::SetConverter(int characterSet_) {
+ if (characterSet != characterSet_) {
+ characterSet = characterSet_;
+ conv.Open("UTF-8", CharacterSetID(characterSet), false);
+ }
+}
+
+SurfaceImpl::SurfaceImpl() : et(singleByte), drawable(0), gc(0), ppixmap(0),
+x(0), y(0), inited(false), createdGC(false)
+, pcontext(0), layout(0), characterSet(-1) {
+}
+
+SurfaceImpl::~SurfaceImpl() {
+ Release();
+}
+
+void SurfaceImpl::Release() {
+ et = singleByte;
+ drawable = 0;
+ if (createdGC) {
+ createdGC = false;
+ gdk_gc_unref(gc);
+ }
+ gc = 0;
+ if (ppixmap)
+ gdk_pixmap_unref(ppixmap);
+ ppixmap = 0;
+ if (layout)
+ g_object_unref(layout);
+ layout = 0;
+ if (pcontext)
+ g_object_unref(pcontext);
+ pcontext = 0;
+ conv.Close();
+ characterSet = -1;
+ x = 0;
+ y = 0;
+ inited = false;
+ createdGC = false;
+}
+
+bool SurfaceImpl::Initialised() {
+ return inited;
+}
+
+void SurfaceImpl::Init(WindowID wid) {
+ Release();
+ PLATFORM_ASSERT(wid);
+ pcontext = gtk_widget_create_pango_context(PWidget(wid));
+ PLATFORM_ASSERT(pcontext);
+ layout = pango_layout_new(pcontext);
+ PLATFORM_ASSERT(layout);
+ inited = true;
+}
+
+void SurfaceImpl::Init(SurfaceID sid, WindowID wid) {
+ PLATFORM_ASSERT(sid);
+ GdkDrawable *drawable_ = reinterpret_cast<GdkDrawable *>(sid);
+ Release();
+ PLATFORM_ASSERT(wid);
+ pcontext = gtk_widget_create_pango_context(PWidget(wid));
+ layout = pango_layout_new(pcontext);
+ drawable = drawable_;
+ gc = gdk_gc_new(drawable_);
+ // Ask for lines that do not paint the last pixel so is like Win32
+ gdk_gc_set_line_attributes(gc, 0, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
+ createdGC = true;
+ inited = true;
+}
+
+void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_, WindowID wid) {
+ PLATFORM_ASSERT(surface_);
+ Release();
+ SurfaceImpl *surfImpl = static_cast<SurfaceImpl *>(surface_);
+ PLATFORM_ASSERT(surfImpl->drawable);
+ PLATFORM_ASSERT(wid);
+ pcontext = gtk_widget_create_pango_context(PWidget(wid));
+ PLATFORM_ASSERT(pcontext);
+ layout = pango_layout_new(pcontext);
+ PLATFORM_ASSERT(layout);
+ if (height > 0 && width > 0)
+ ppixmap = gdk_pixmap_new(surfImpl->drawable, width, height, -1);
+ drawable = ppixmap;
+ gc = gdk_gc_new(surfImpl->drawable);
+ // Ask for lines that do not paint the last pixel so is like Win32
+ gdk_gc_set_line_attributes(gc, 0, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
+ createdGC = true;
+ inited = true;
+}
+
+void SurfaceImpl::PenColour(ColourAllocated fore) {
+ if (gc) {
+ GdkColor co;
+ co.pixel = fore.AsLong();
+ gdk_gc_set_foreground(gc, &co);
+ }
+}
+
+int SurfaceImpl::LogPixelsY() {
+ return 72;
+}
+
+int SurfaceImpl::DeviceHeightFont(int points) {
+ int logPix = LogPixelsY();
+ return (points * logPix + logPix / 2) / 72;
+}
+
+void SurfaceImpl::MoveTo(int x_, int y_) {
+ x = x_;
+ y = y_;
+}
+
+void SurfaceImpl::LineTo(int x_, int y_) {
+ if (drawable && gc) {
+ gdk_draw_line(drawable, gc,
+ x, y,
+ x_, y_);
+ }
+ x = x_;
+ y = y_;
+}
+
+void SurfaceImpl::Polygon(Point *pts, int npts, ColourAllocated fore,
+ ColourAllocated back) {
+ GdkPoint gpts[20];
+ if (npts < static_cast<int>((sizeof(gpts) / sizeof(gpts[0])))) {
+ for (int i = 0;i < npts;i++) {
+ gpts[i].x = pts[i].x;
+ gpts[i].y = pts[i].y;
+ }
+ PenColour(back);
+ gdk_draw_polygon(drawable, gc, 1, gpts, npts);
+ PenColour(fore);
+ gdk_draw_polygon(drawable, gc, 0, gpts, npts);
+ }
+}
+
+void SurfaceImpl::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
+ if (gc && drawable) {
+ PenColour(back);
+ gdk_draw_rectangle(drawable, gc, 1,
+ rc.left + 1, rc.top + 1,
+ rc.right - rc.left - 2, rc.bottom - rc.top - 2);
+
+ PenColour(fore);
+ // The subtraction of 1 off the width and height here shouldn't be needed but
+ // otherwise a different rectangle is drawn than would be done if the fill parameter == 1
+ gdk_draw_rectangle(drawable, gc, 0,
+ rc.left, rc.top,
+ rc.right - rc.left - 1, rc.bottom - rc.top - 1);
+ }
+}
+
+void SurfaceImpl::FillRectangle(PRectangle rc, ColourAllocated back) {
+ PenColour(back);
+ if (drawable && (rc.left < maxCoordinate)) { // Protect against out of range
+ gdk_draw_rectangle(drawable, gc, 1,
+ rc.left, rc.top,
+ rc.right - rc.left, rc.bottom - rc.top);
+ }
+}
+
+void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) {
+ if (static_cast<SurfaceImpl &>(surfacePattern).drawable) {
+ // Tile pattern over rectangle
+ // Currently assumes 8x8 pattern
+ int widthPat = 8;
+ int heightPat = 8;
+ for (int xTile = rc.left; xTile < rc.right; xTile += widthPat) {
+ int widthx = (xTile + widthPat > rc.right) ? rc.right - xTile : widthPat;
+ for (int yTile = rc.top; yTile < rc.bottom; yTile += heightPat) {
+ int heighty = (yTile + heightPat > rc.bottom) ? rc.bottom - yTile : heightPat;
+ gdk_draw_pixmap(drawable,
+ gc,
+ static_cast<SurfaceImpl &>(surfacePattern).drawable,
+ 0, 0,
+ xTile, yTile,
+ widthx, heighty);
+ }
+ }
+ } else {
+ // Something is wrong so try to show anyway
+ // Shows up black because colour not allocated
+ FillRectangle(rc, ColourAllocated(0));
+ }
+}
+
+void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
+ if (((rc.right - rc.left) > 4) && ((rc.bottom - rc.top) > 4)) {
+ // Approximate a round rect with some cut off corners
+ Point pts[] = {
+ Point(rc.left + 2, rc.top),
+ Point(rc.right - 2, rc.top),
+ Point(rc.right, rc.top + 2),
+ Point(rc.right, rc.bottom - 2),
+ Point(rc.right - 2, rc.bottom),
+ Point(rc.left + 2, rc.bottom),
+ Point(rc.left, rc.bottom - 2),
+ Point(rc.left, rc.top + 2),
+ };
+ Polygon(pts, sizeof(pts) / sizeof(pts[0]), fore, back);
+ } else {
+ RectangleDraw(rc, fore, back);
+ }
+}
+
+// Plot a point into a guint32 buffer symetrically to all 4 qudrants
+static void AllFour(guint32 *pixels, int stride, int width, int height, int x, int y, guint32 val) {
+ pixels[y*stride+x] = val;
+ pixels[y*stride+width-1-x] = val;
+ pixels[(height-1-y)*stride+x] = val;
+ pixels[(height-1-y)*stride+width-1-x] = val;
+}
+
+static unsigned int GetRValue(unsigned int co) {
+ return (co >> 16) & 0xff;
+}
+
+static unsigned int GetGValue(unsigned int co) {
+ return (co >> 8) & 0xff;
+}
+
+static unsigned int GetBValue(unsigned int co) {
+ return co & 0xff;
+}
+
+static guint32 u32FromRGBA(guint8 r, guint8 g, guint8 b, guint8 a) {
+ union {
+ guint8 pixVal[4];
+ guint32 val;
+ } converter;
+ converter.pixVal[0] = r;
+ converter.pixVal[1] = g;
+ converter.pixVal[2] = b;
+ converter.pixVal[3] = a;
+ return converter.val;
+}
+
+void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill,
+ ColourAllocated outline, int alphaOutline, int flags) {
+ if (gc && drawable && rc.Width() > 0) {
+ int width = rc.Width();
+ int height = rc.Height();
+ // Ensure not distorted too much by corners when small
+ cornerSize = Platform::Minimum(cornerSize, (Platform::Minimum(width, height) / 2) - 2);
+ // Make a 32 bit deep pixbuf with alpha
+ GdkPixbuf *pixalpha = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
+
+ guint32 valEmpty = u32FromRGBA(0,0,0,0);
+ guint32 valFill = u32FromRGBA(GetRValue(fill.AsLong()),
+ GetGValue(fill.AsLong()), GetBValue(fill.AsLong()), alphaFill);
+ guint32 valOutline = u32FromRGBA(GetRValue(outline.AsLong()),
+ GetGValue(outline.AsLong()), GetBValue(outline.AsLong()), alphaOutline);
+ guint32 *pixels = reinterpret_cast<guint32 *>(gdk_pixbuf_get_pixels(pixalpha));
+ int stride = gdk_pixbuf_get_rowstride(pixalpha) / 4;
+ for (int yr=0; yr<height; yr++) {
+ for (int xr=0; xr<width; xr++) {
+ if ((xr==0) || (xr==width-1) || (yr == 0) || (yr == height-1)) {
+ pixels[yr*stride+xr] = valOutline;
+ } else {
+ pixels[yr*stride+xr] = valFill;
+ }
+ }
+ }
+ for (int c=0;c<cornerSize; c++) {
+ for (int xr=0;xr<c+1; xr++) {
+ AllFour(pixels, stride, width, height, xr, c-xr, valEmpty);
+ }
+ }
+ for (int xr=1;xr<cornerSize; xr++) {
+ AllFour(pixels, stride, width, height, xr, cornerSize-xr, valOutline);
+ }
+
+ // Draw with alpha
+ gdk_draw_pixbuf(drawable, gc, pixalpha,
+ 0,0, rc.left,rc.top, width,height, GDK_RGB_DITHER_NORMAL, 0, 0);
+
+ g_object_unref(pixalpha);
+ }
+}
+
+void SurfaceImpl::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
+ PenColour(back);
+ gdk_draw_arc(drawable, gc, 1,
+ rc.left + 1, rc.top + 1,
+ rc.right - rc.left - 2, rc.bottom - rc.top - 2,
+ 0, 32767);
+
+ // The subtraction of 1 here is similar to the case for RectangleDraw
+ PenColour(fore);
+ gdk_draw_arc(drawable, gc, 0,
+ rc.left, rc.top,
+ rc.right - rc.left - 1, rc.bottom - rc.top - 1,
+ 0, 32767);
+}
+
+void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) {
+ if (static_cast<SurfaceImpl &>(surfaceSource).drawable) {
+ gdk_draw_pixmap(drawable,
+ gc,
+ static_cast<SurfaceImpl &>(surfaceSource).drawable,
+ from.x, from.y,
+ rc.left, rc.top,
+ rc.right - rc.left, rc.bottom - rc.top);
+ }
+}
+
+static size_t UTF8Len(char ch) {
+ unsigned char uch = static_cast<unsigned char>(ch);
+ if (uch < 0x80)
+ return 1;
+ else if (uch < (0x80 + 0x40 + 0x20))
+ return 2;
+ else
+ return 3;
+}
+
+char *UTF8FromLatin1(const char *s, int &len) {
+ char *utfForm = new char[len*2+1];
+ size_t lenU = 0;
+ for (int i=0;i<len;i++) {
+ unsigned int uch = static_cast<unsigned char>(s[i]);
+ if (uch < 0x80) {
+ utfForm[lenU++] = uch;
+ } else {
+ utfForm[lenU++] = static_cast<char>(0xC0 | (uch >> 6));
+ utfForm[lenU++] = static_cast<char>(0x80 | (uch & 0x3f));
+ }
+ }
+ utfForm[lenU] = '\0';
+ len = lenU;
+ return utfForm;
+}
+
+static char *UTF8FromIconv(const Converter &conv, const char *s, int &len) {
+ if (conv) {
+ char *utfForm = new char[len*3+1];
+ char *pin = const_cast<char *>(s);
+ size_t inLeft = len;
+ char *pout = utfForm;
+ size_t outLeft = len*3+1;
+ size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
+ if (conversions != ((size_t)(-1))) {
+ *pout = '\0';
+ len = pout - utfForm;
+ return utfForm;
+ }
+ delete []utfForm;
+ }
+ return 0;
+}
+
+// Work out how many bytes are in a character by trying to convert using iconv,
+// returning the first length that succeeds.
+static size_t MultiByteLenFromIconv(const Converter &conv, const char *s, size_t len) {
+ for (size_t lenMB=1; (lenMB<4) && (lenMB <= len); lenMB++) {
+ char wcForm[2];
+ char *pin = const_cast<char *>(s);
+ size_t inLeft = lenMB;
+ char *pout = wcForm;
+ size_t outLeft = 2;
+ size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
+ if (conversions != ((size_t)(-1))) {
+ return lenMB;
+ }
+ }
+ return 1;
+}
+
+static char *UTF8FromGdkWChar(GdkWChar *wctext, int wclen) {
+ char *utfForm = new char[wclen*3+1]; // Maximum of 3 UTF-8 bytes per character
+ size_t lenU = 0;
+ for (int i = 0; i < wclen && wctext[i]; i++) {
+ unsigned int uch = wctext[i];
+ if (uch < 0x80) {
+ utfForm[lenU++] = static_cast<char>(uch);
+ } else if (uch < 0x800) {
+ utfForm[lenU++] = static_cast<char>(0xC0 | (uch >> 6));
+ utfForm[lenU++] = static_cast<char>(0x80 | (uch & 0x3f));
+ } else {
+ utfForm[lenU++] = static_cast<char>(0xE0 | (uch >> 12));
+ utfForm[lenU++] = static_cast<char>(0x80 | ((uch >> 6) & 0x3f));
+ utfForm[lenU++] = static_cast<char>(0x80 | (uch & 0x3f));
+ }
+ }
+ utfForm[lenU] = '\0';
+ return utfForm;
+}
+
+static char *UTF8FromDBCS(const char *s, int &len) {
+ GdkWChar *wctext = new GdkWChar[len + 1];
+ GdkWChar *wcp = wctext;
+ int wclen = gdk_mbstowcs(wcp, s, len);
+ if (wclen < 1) {
+ // In the annoying case when non-locale chars in the line.
+ // e.g. latin1 chars in Japanese locale.
+ delete []wctext;
+ return 0;
+ }
+
+ char *utfForm = UTF8FromGdkWChar(wctext, wclen);
+ delete []wctext;
+ len = strlen(utfForm);
+ return utfForm;
+}
+
+static size_t UTF8CharLength(const char *s) {
+ const unsigned char *us = reinterpret_cast<const unsigned char *>(s);
+ unsigned char ch = *us;
+ if (ch < 0x80) {
+ return 1;
+ } else if (ch < 0x80 + 0x40 + 0x20) {
+ return 2;
+ } else {
+ return 3;
+ }
+}
+
+// On GTK+, wchar_t is 4 bytes
+
+const int maxLengthTextRun = 10000;
+
+void SurfaceImpl::DrawTextBase(PRectangle rc, Font &font_, int ybase, const char *s, int len,
+ ColourAllocated fore) {
+ PenColour(fore);
+ if (gc && drawable) {
+ int xText = rc.left;
+ if (PFont(font_)->pfd) {
+ char *utfForm = 0;
+ bool useGFree = false;
+ if (et == UTF8) {
+ pango_layout_set_text(layout, s, len);
+ } else {
+ if (!utfForm) {
+ SetConverter(PFont(font_)->characterSet);
+ utfForm = UTF8FromIconv(conv, s, len);
+ }
+ if (!utfForm) { // iconv failed so try DBCS if DBCS mode
+ if (et == dbcs) {
+ // Convert to utf8
+ utfForm = UTF8FromDBCS(s, len);
+ }
+ }
+ if (!utfForm) { // iconv and DBCS failed so treat as Latin1
+ utfForm = UTF8FromLatin1(s, len);
+ }
+ pango_layout_set_text(layout, utfForm, len);
+ }
+ pango_layout_set_font_description(layout, PFont(font_)->pfd);
+#ifdef PANGO_VERSION
+ PangoLayoutLine *pll = pango_layout_get_line_readonly(layout,0);
+#else
+ PangoLayoutLine *pll = pango_layout_get_line(layout,0);
+#endif
+ gdk_draw_layout_line(drawable, gc, xText, ybase, pll);
+ if (useGFree) {
+ g_free(utfForm);
+ } else {
+ delete []utfForm;
+ }
+ return;
+ }
+ // Draw text as a series of segments to avoid limitations in X servers
+ const int segmentLength = 1000;
+ bool draw8bit = true;
+ if (et != singleByte) {
+ GdkWChar wctext[maxLengthTextRun];
+ if (len >= maxLengthTextRun)
+ len = maxLengthTextRun-1;
+ int wclen;
+ if (et == UTF8) {
+ wclen = UTF16FromUTF8(s, len,
+ static_cast<wchar_t *>(static_cast<void *>(wctext)), maxLengthTextRun - 1);
+ } else { // dbcs, so convert using current locale
+ char sMeasure[maxLengthTextRun];
+ memcpy(sMeasure, s, len);
+ sMeasure[len] = '\0';
+ wclen = gdk_mbstowcs(
+ wctext, sMeasure, maxLengthTextRun - 1);
+ }
+ if (wclen > 0) {
+ draw8bit = false;
+ wctext[wclen] = L'\0';
+ GdkWChar *wcp = wctext;
+ while ((wclen > 0) && (xText < maxCoordinate)) {
+ int lenDraw = Platform::Minimum(wclen, segmentLength);
+ gdk_draw_text_wc(drawable, PFont(font_)->pfont, gc,
+ xText, ybase, wcp, lenDraw);
+ wclen -= lenDraw;
+ if (wclen > 0) { // Avoid next calculation if possible as may be expensive
+ xText += gdk_text_width_wc(PFont(font_)->pfont,
+ wcp, lenDraw);
+ }
+ wcp += lenDraw;
+ }
+ }
+ }
+ if (draw8bit) {
+ while ((len > 0) && (xText < maxCoordinate)) {
+ int lenDraw = Platform::Minimum(len, segmentLength);
+ gdk_draw_text(drawable, PFont(font_)->pfont, gc,
+ xText, ybase, s, lenDraw);
+ len -= lenDraw;
+ if (len > 0) { // Avoid next calculation if possible as may be expensive
+ xText += gdk_text_width(PFont(font_)->pfont, s, lenDraw);
+ }
+ s += lenDraw;
+ }
+ }
+ }
+}
+
+void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len,
+ ColourAllocated fore, ColourAllocated back) {
+ FillRectangle(rc, back);
+ DrawTextBase(rc, font_, ybase, s, len, fore);
+}
+
+// On GTK+, exactly same as DrawTextNoClip
+void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len,
+ ColourAllocated fore, ColourAllocated back) {
+ FillRectangle(rc, back);
+ DrawTextBase(rc, font_, ybase, s, len, fore);
+}
+
+void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len,
+ ColourAllocated fore) {
+ // Avoid drawing spaces in transparent mode
+ for (int i=0;i<len;i++) {
+ if (s[i] != ' ') {
+ DrawTextBase(rc, font_, ybase, s, len, fore);
+ return;
+ }
+ }
+}
+
+class ClusterIterator {
+ PangoLayoutIter *iter;
+ PangoRectangle pos;
+ int lenPositions;
+public:
+ bool finished;
+ int positionStart;
+ int position;
+ int distance;
+ int curIndex;
+ ClusterIterator(PangoLayout *layout, int len) : 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, NULL, &pos);
+ }
+ ~ClusterIterator() {
+ pango_layout_iter_free(iter);
+ }
+
+ void Next() {
+ positionStart = position;
+ if (pango_layout_iter_next_cluster(iter)) {
+ pango_layout_iter_get_cluster_extents(iter, NULL, &pos);
+ position = PANGO_PIXELS(pos.x);
+ curIndex = pango_layout_iter_get_index(iter);
+ } else {
+ finished = true;
+ position = PANGO_PIXELS(pos.x + pos.width);
+ curIndex = lenPositions;
+ }
+ distance = position - positionStart;
+ }
+};
+
+void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positions) {
+ if (font_.GetID()) {
+ int totalWidth = 0;
+ const int lenPositions = len;
+ if (PFont(font_)->pfd) {
+ if (len == 1) {
+ int width = PFont(font_)->CharWidth(*s, et);
+ if (width) {
+ positions[0] = width;
+ return;
+ }
+ }
+ pango_layout_set_font_description(layout, PFont(font_)->pfd);
+ if (et == UTF8) {
+ // Simple and direct as UTF-8 is native Pango encoding
+ int i = 0;
+ pango_layout_set_text(layout, s, len);
+ ClusterIterator iti(layout, lenPositions);
+ while (!iti.finished) {
+ iti.Next();
+ int places = iti.curIndex - i;
+ while (i < iti.curIndex) {
+ // Evenly distribute space among bytes of this cluster.
+ // Would be better to find number of characters and then
+ // divide evenly between characters with each byte of a character
+ // being at the same position.
+ positions[i] = iti.position - (iti.curIndex - 1 - i) * iti.distance / places;
+ i++;
+ }
+ }
+ PLATFORM_ASSERT(i == lenPositions);
+ } else {
+ int positionsCalculated = 0;
+ if (et == dbcs) {
+ SetConverter(PFont(font_)->characterSet);
+ char *utfForm = UTF8FromIconv(conv, s, len);
+ if (utfForm) {
+ // 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, strlen(utfForm));
+ int i = 0;
+ int clusterStart = 0;
+ ClusterIterator iti(layout, strlen(utfForm));
+ while (!iti.finished) {
+ iti.Next();
+ int clusterEnd = iti.curIndex;
+ int places = g_utf8_strlen(utfForm + clusterStart, clusterEnd - clusterStart);
+ int place = 1;
+ while (clusterStart < clusterEnd) {
+ size_t lenChar = MultiByteLenFromIconv(convMeasure, s+i, len-i);
+ while (lenChar--) {
+ positions[i++] = iti.position - (places - place) * iti.distance / places;
+ positionsCalculated++;
+ }
+ clusterStart += UTF8CharLength(utfForm+clusterStart);
+ place++;
+ }
+ }
+ delete []utfForm;
+ PLATFORM_ASSERT(i == lenPositions);
+ }
+ }
+ if (positionsCalculated < 1 ) {
+ // Either Latin1 or DBCS conversion failed so treat as Latin1.
+ bool useGFree = false;
+ SetConverter(PFont(font_)->characterSet);
+ char *utfForm = UTF8FromIconv(conv, s, len);
+ if (!utfForm) {
+ utfForm = UTF8FromLatin1(s, len);
+ }
+ pango_layout_set_text(layout, utfForm, len);
+ int i = 0;
+ int clusterStart = 0;
+ // Each Latin1 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, strlen(utfForm));
+ while (!iti.finished) {
+ iti.Next();
+ int clusterEnd = iti.curIndex;
+ int ligatureLength = g_utf8_strlen(utfForm + clusterStart, clusterEnd - clusterStart);
+ PLATFORM_ASSERT(ligatureLength > 0 && ligatureLength <= 3);
+ for (int charInLig=0; charInLig<ligatureLength; charInLig++) {
+ positions[i++] = iti.position - (ligatureLength - 1 - charInLig) * iti.distance / ligatureLength;
+ }
+ clusterStart = clusterEnd;
+ }
+ if (useGFree) {
+ g_free(utfForm);
+ } else {
+ delete []utfForm;
+ }
+ PLATFORM_ASSERT(i == lenPositions);
+ }
+ }
+ if (len == 1) {
+ PFont(font_)->SetCharWidth(*s, positions[0], et);
+ }
+ return;
+ }
+ GdkFont *gf = PFont(font_)->pfont;
+ bool measure8bit = true;
+ if (et != singleByte) {
+ GdkWChar wctext[maxLengthTextRun];
+ if (len >= maxLengthTextRun)
+ len = maxLengthTextRun-1;
+ int wclen;
+ if (et == UTF8) {
+ wclen = UTF16FromUTF8(s, len,
+ static_cast<wchar_t *>(static_cast<void *>(wctext)), maxLengthTextRun - 1);
+ } else { // dbcsMode, so convert using current locale
+ char sDraw[maxLengthTextRun];
+ memcpy(sDraw, s, len);
+ sDraw[len] = '\0';
+ wclen = gdk_mbstowcs(
+ wctext, sDraw, maxLengthTextRun - 1);
+ }
+ if (wclen > 0) {
+ measure8bit = false;
+ wctext[wclen] = L'\0';
+ // Map widths back to utf-8 or DBCS input string
+ int i = 0;
+ for (int iU = 0; iU < wclen; iU++) {
+ int width = gdk_char_width_wc(gf, wctext[iU]);
+ totalWidth += width;
+ int lenChar;
+ if (et == UTF8) {
+ lenChar = UTF8Len(s[i]);
+ } else {
+ lenChar = mblen(s+i, MB_CUR_MAX);
+ if (lenChar < 0)
+ lenChar = 1;
+ }
+ while (lenChar--) {
+ positions[i++] = totalWidth;
+ }
+ }
+ while (i < len) { // In case of problems with lengths
+ positions[i++] = totalWidth;
+ }
+ }
+ }
+ if (measure8bit) {
+ // Either Latin1 or conversion failed so treat as Latin1.
+ for (int i = 0; i < len; i++) {
+ int width = gdk_char_width(gf, s[i]);
+ totalWidth += width;
+ positions[i] = totalWidth;
+ }
+ }
+ } else {
+ // No font so return an ascending range of values
+ for (int i = 0; i < len; i++) {
+ positions[i] = i + 1;
+ }
+ }
+}
+
+int SurfaceImpl::WidthText(Font &font_, const char *s, int len) {
+ if (font_.GetID()) {
+ if (PFont(font_)->pfd) {
+ char *utfForm = 0;
+ pango_layout_set_font_description(layout, PFont(font_)->pfd);
+ PangoRectangle pos;
+ bool useGFree = false;
+ if (et == UTF8) {
+ pango_layout_set_text(layout, s, len);
+ } else {
+ if (et == dbcs) {
+ // Convert to utf8
+ utfForm = UTF8FromDBCS(s, len);
+ }
+ if (!utfForm) { // DBCS failed so treat as iconv
+ SetConverter(PFont(font_)->characterSet);
+ utfForm = UTF8FromIconv(conv, s, len);
+ }
+ if (!utfForm) { // g_locale_to_utf8 failed so treat as Latin1
+ utfForm = UTF8FromLatin1(s, len);
+ }
+ pango_layout_set_text(layout, utfForm, len);
+ }
+#ifdef PANGO_VERSION
+ PangoLayoutLine *pangoLine = pango_layout_get_line_readonly(layout,0);
+#else
+ PangoLayoutLine *pangoLine = pango_layout_get_line(layout,0);
+#endif
+ pango_layout_line_get_extents(pangoLine, NULL, &pos);
+ if (useGFree) {
+ g_free(utfForm);
+ } else {
+ delete []utfForm;
+ }
+ return PANGO_PIXELS(pos.width);
+ }
+ if (et == UTF8) {
+ GdkWChar wctext[maxLengthTextRun];
+ size_t wclen = UTF16FromUTF8(s, len, static_cast<wchar_t *>(static_cast<void *>(wctext)),
+ sizeof(wctext) / sizeof(GdkWChar) - 1);
+ wctext[wclen] = L'\0';
+ return gdk_text_width_wc(PFont(font_)->pfont, wctext, wclen);
+ } else {
+ return gdk_text_width(PFont(font_)->pfont, s, len);
+ }
+ } else {
+ return 1;
+ }
+}
+
+int SurfaceImpl::WidthChar(Font &font_, char ch) {
+ if (font_.GetID()) {
+ if (PFont(font_)->pfd) {
+ return WidthText(font_, &ch, 1);
+ }
+ return gdk_char_width(PFont(font_)->pfont, ch);
+ } else {
+ return 1;
+ }
+}
+
+// Three possible strategies for determining ascent and descent of font:
+// 1) Call gdk_string_extents with string containing all letters, numbers and punctuation.
+// 2) Use the ascent and descent fields of GdkFont.
+// 3) Call gdk_string_extents with string as 1 but also including accented capitals.
+// Smallest values given by 1 and largest by 3 with 2 in between.
+// Techniques 1 and 2 sometimes chop off extreme portions of ascenders and
+// descenders but are mostly OK except for accented characters like Å which are
+// rarely used in code.
+
+// This string contains a good range of characters to test for size.
+//const char largeSizeString[] = "ÂÃÅÄ `~!@#$%^&*()-_=+\\|[]{};:\"\'<,>.?/1234567890"
+// "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+#ifndef FAST_WAY
+const char sizeString[] = "`~!@#$%^&*()-_=+\\|[]{};:\"\'<,>.?/1234567890"
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+#endif
+
+int SurfaceImpl::Ascent(Font &font_) {
+ if (!(font_.GetID()))
+ return 1;
+#ifdef FAST_WAY
+ FontMutexLock();
+ int ascent = PFont(font_)->ascent;
+ if ((ascent == 0) && (PFont(font_)->pfd)) {
+ PangoFontMetrics *metrics = pango_context_get_metrics(pcontext,
+ PFont(font_)->pfd, pango_context_get_language(pcontext));
+ PFont(font_)->ascent =
+ PANGO_PIXELS(pango_font_metrics_get_ascent(metrics));
+ pango_font_metrics_unref(metrics);
+ ascent = PFont(font_)->ascent;
+ }
+ if ((ascent == 0) && (PFont(font_)->pfont)) {
+ ascent = PFont(font_)->pfont->ascent;
+ }
+ if (ascent == 0) {
+ ascent = 1;
+ }
+ FontMutexUnlock();
+ return ascent;
+#else
+
+ gint lbearing;
+ gint rbearing;
+ gint width;
+ gint ascent;
+ gint descent;
+
+ gdk_string_extents(PFont(font_)->pfont, sizeString,
+ &lbearing, &rbearing, &width, &ascent, &descent);
+ return ascent;
+#endif
+}
+
+int SurfaceImpl::Descent(Font &font_) {
+ if (!(font_.GetID()))
+ return 1;
+#ifdef FAST_WAY
+
+ if (PFont(font_)->pfd) {
+ PangoFontMetrics *metrics = pango_context_get_metrics(pcontext,
+ PFont(font_)->pfd, pango_context_get_language(pcontext));
+ int descent = PANGO_PIXELS(pango_font_metrics_get_descent(metrics));
+ pango_font_metrics_unref(metrics);
+ return descent;
+ }
+ return PFont(font_)->pfont->descent;
+#else
+
+ gint lbearing;
+ gint rbearing;
+ gint width;
+ gint ascent;
+ gint descent;
+
+ gdk_string_extents(PFont(font_)->pfont, sizeString,
+ &lbearing, &rbearing, &width, &ascent, &descent);
+ return descent;
+#endif
+}
+
+int SurfaceImpl::InternalLeading(Font &) {
+ return 0;
+}
+
+int SurfaceImpl::ExternalLeading(Font &) {
+ return 0;
+}
+
+int SurfaceImpl::Height(Font &font_) {
+ return Ascent(font_) + Descent(font_);
+}
+
+int SurfaceImpl::AverageCharWidth(Font &font_) {
+ return WidthChar(font_, 'n');
+}
+
+int SurfaceImpl::SetPalette(Palette *, bool) {
+ // Handled in palette allocation for GTK so this does nothing
+ return 0;
+}
+
+void SurfaceImpl::SetClip(PRectangle rc) {
+ GdkRectangle area = {rc.left, rc.top,
+ rc.right - rc.left, rc.bottom - rc.top};
+ gdk_gc_set_clip_rectangle(gc, &area);
+}
+
+void SurfaceImpl::FlushCachedState() {}
+
+void SurfaceImpl::SetUnicodeMode(bool unicodeMode_) {
+ if (unicodeMode_)
+ et = UTF8;
+}
+
+void SurfaceImpl::SetDBCSMode(int codePage) {
+ if (codePage && (codePage != SC_CP_UTF8))
+ et = dbcs;
+}
+
+Surface *Surface::Allocate() {
+ return new SurfaceImpl;
+}
+
+Window::~Window() {}
+
+void Window::Destroy() {
+ if (wid)
+ gtk_widget_destroy(GTK_WIDGET(wid));
+ wid = 0;
+}
+
+bool Window::HasFocus() {
+ return GTK_WIDGET_HAS_FOCUS(wid);
+}
+
+PRectangle Window::GetPosition() {
+ // Before any size allocated pretend its 1000 wide so not scrolled
+ PRectangle rc(0, 0, 1000, 1000);
+ if (wid) {
+ rc.left = PWidget(wid)->allocation.x;
+ rc.top = PWidget(wid)->allocation.y;
+ if (PWidget(wid)->allocation.width > 20) {
+ rc.right = rc.left + PWidget(wid)->allocation.width;
+ rc.bottom = rc.top + PWidget(wid)->allocation.height;
+ }
+ }
+ return rc;
+}
+
+void Window::SetPosition(PRectangle rc) {
+ GtkAllocation alloc;
+ alloc.x = rc.left;
+ alloc.y = rc.top;
+ alloc.width = rc.Width();
+ alloc.height = rc.Height();
+ gtk_widget_size_allocate(PWidget(wid), &alloc);
+}
+
+void Window::SetPositionRelative(PRectangle rc, Window relativeTo) {
+ int ox = 0;
+ int oy = 0;
+ gdk_window_get_origin(PWidget(relativeTo.wid)->window, &ox, &oy);
+ ox += rc.left;
+ if (ox < 0)
+ ox = 0;
+ oy += rc.top;
+ if (oy < 0)
+ oy = 0;
+
+ /* do some corrections to fit into screen */
+ int sizex = rc.right - rc.left;
+ int sizey = rc.bottom - rc.top;
+ int screenWidth = gdk_screen_width();
+ int screenHeight = gdk_screen_height();
+ if (sizex > screenWidth)
+ ox = 0; /* the best we can do */
+ else if (ox + sizex > screenWidth)
+ ox = screenWidth - sizex;
+ if (oy + sizey > screenHeight)
+ oy = screenHeight - sizey;
+
+ gtk_window_move(GTK_WINDOW(PWidget(wid)), ox, oy);
+
+ gtk_widget_set_usize(PWidget(wid), sizex, sizey);
+}
+
+PRectangle Window::GetClientPosition() {
+ // On GTK+, the client position is the window position
+ return GetPosition();
+}
+
+void Window::Show(bool show) {
+ if (show)
+ gtk_widget_show(PWidget(wid));
+}
+
+void Window::InvalidateAll() {
+ if (wid) {
+ gtk_widget_queue_draw(PWidget(wid));
+ }
+}
+
+void Window::InvalidateRectangle(PRectangle rc) {
+ if (wid) {
+ gtk_widget_queue_draw_area(PWidget(wid),
+ rc.left, rc.top,
+ rc.right - rc.left, rc.bottom - rc.top);
+ }
+}
+
+void Window::SetFont(Font &) {
+ // Can not be done generically but only needed for ListBox
+}
+
+void Window::SetCursor(Cursor curs) {
+ // We don't set the cursor to same value numerous times under gtk because
+ // it stores the cursor in the window once it's set
+ if (curs == cursorLast)
+ return;
+
+ cursorLast = curs;
+ GdkCursor *gdkCurs;
+ switch (curs) {
+ case cursorText:
+ gdkCurs = gdk_cursor_new(GDK_XTERM);
+ break;
+ case cursorArrow:
+ gdkCurs = gdk_cursor_new(GDK_LEFT_PTR);
+ break;
+ case cursorUp:
+ gdkCurs = gdk_cursor_new(GDK_CENTER_PTR);
+ break;
+ case cursorWait:
+ gdkCurs = gdk_cursor_new(GDK_WATCH);
+ break;
+ case cursorHand:
+ gdkCurs = gdk_cursor_new(GDK_HAND2);
+ break;
+ case cursorReverseArrow:
+ gdkCurs = gdk_cursor_new(GDK_RIGHT_PTR);
+ break;
+ default:
+ gdkCurs = gdk_cursor_new(GDK_LEFT_PTR);
+ cursorLast = cursorArrow;
+ break;
+ }
+
+ if (PWidget(wid)->window)
+ gdk_window_set_cursor(PWidget(wid)->window, gdkCurs);
+ gdk_cursor_destroy(gdkCurs);
+}
+
+void Window::SetTitle(const char *s) {
+ gtk_window_set_title(GTK_WINDOW(wid), s);
+}
+
+/* Returns rectangle of monitor pt is on, both rect and pt are in Window's
+ gdk window coordinates */
+PRectangle Window::GetMonitorRect(Point pt) {
+ gint x_offset, y_offset;
+ pt = pt;
+
+ gdk_window_get_origin(PWidget(wid)->window, &x_offset, &y_offset);
+
+#if GTK_CHECK_VERSION(2,2,0)
+ // GTK+ 2.2+
+ {
+ GdkScreen* screen;
+ gint monitor_num;
+ GdkRectangle rect;
+
+ screen = gtk_widget_get_screen(PWidget(wid));
+ monitor_num = gdk_screen_get_monitor_at_point(screen, pt.x + x_offset, pt.y + y_offset);
+ gdk_screen_get_monitor_geometry(screen, monitor_num, &rect);
+ rect.x -= x_offset;
+ rect.y -= y_offset;
+ return PRectangle(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height);
+ }
+#else
+ return PRectangle(-x_offset, -y_offset, (-x_offset) + gdk_screen_width(),
+ (-y_offset) + gdk_screen_height());
+#endif
+}
+
+struct ListImage {
+ const char *xpm_data;
+ GdkPixbuf *pixbuf;
+};
+
+static void list_image_free(gpointer, gpointer value, gpointer) {
+ ListImage *list_image = (ListImage *) value;
+ if (list_image->pixbuf)
+ gdk_pixbuf_unref (list_image->pixbuf);
+ g_free(list_image);
+}
+
+ListBox::ListBox() {
+}
+
+ListBox::~ListBox() {
+}
+
+enum {
+ PIXBUF_COLUMN,
+ TEXT_COLUMN,
+ N_COLUMNS
+};
+
+class ListBoxX : public ListBox {
+ WindowID list;
+ WindowID scroller;
+ void *pixhash;
+ GtkCellRenderer* pixbuf_renderer;
+ XPMSet xset;
+ int desiredVisibleRows;
+ unsigned int maxItemCharacters;
+ unsigned int aveCharWidth;
+public:
+ CallBackAction doubleClickAction;
+ void *doubleClickActionData;
+
+ ListBoxX() : list(0), pixhash(NULL), pixbuf_renderer(0),
+ desiredVisibleRows(5), maxItemCharacters(0),
+ aveCharWidth(1), doubleClickAction(NULL), doubleClickActionData(NULL) {
+ }
+ virtual ~ListBoxX() {
+ if (pixhash) {
+ g_hash_table_foreach((GHashTable *) pixhash, list_image_free, NULL);
+ g_hash_table_destroy((GHashTable *) pixhash);
+ }
+ }
+ virtual void SetFont(Font &font);
+ virtual void Create(Window &parent, int ctrlID, Point location_, int lineHeight_, bool unicodeMode_);
+ virtual void SetAverageCharWidth(int width);
+ virtual void SetVisibleRows(int rows);
+ virtual int GetVisibleRows() const;
+ virtual PRectangle GetDesiredRect();
+ virtual int CaretFromEdge();
+ virtual void Clear();
+ virtual void Append(char *s, int type = -1);
+ virtual int Length();
+ virtual void Select(int n);
+ virtual int GetSelection();
+ virtual int Find(const char *prefix);
+ virtual void GetValue(int n, char *value, int len);
+ virtual void RegisterImage(int type, const char *xpm_data);
+ virtual void ClearRegisteredImages();
+ virtual void SetDoubleClickAction(CallBackAction action, void *data) {
+ doubleClickAction = action;
+ doubleClickActionData = data;
+ }
+ virtual void SetList(const char *listText, char separator, char typesep);
+};
+
+ListBox *ListBox::Allocate() {
+ ListBoxX *lb = new ListBoxX();
+ return lb;
+}
+
+static gboolean ButtonPress(GtkWidget *, GdkEventButton* ev, gpointer p) {
+ try {
+ ListBoxX* lb = reinterpret_cast<ListBoxX*>(p);
+ if (ev->type == GDK_2BUTTON_PRESS && lb->doubleClickAction != NULL) {
+ lb->doubleClickAction(lb->doubleClickActionData);
+ return TRUE;
+ }
+
+ } catch (...) {
+ // No pointer back to Scintilla to save status
+ }
+ return FALSE;
+}
+
+/* Change the active color to the selected color so the listbox uses the color
+scheme that it would use if it had the focus. */
+static void StyleSet(GtkWidget *w, GtkStyle*, void*) {
+ GtkStyle* style;
+
+ g_return_if_fail(w != NULL);
+
+ /* Copy the selected color to active. Note that the modify calls will cause
+ recursive calls to this function after the value is updated and w->style to
+ be set to a new object */
+ style = gtk_widget_get_style(w);
+ if (style == NULL)
+ return;
+ if (!gdk_color_equal(&style->base[GTK_STATE_SELECTED], &style->base[GTK_STATE_ACTIVE]))
+ gtk_widget_modify_base(w, GTK_STATE_ACTIVE, &style->base[GTK_STATE_SELECTED]);
+
+ style = gtk_widget_get_style(w);
+ if (style == NULL)
+ return;
+ if (!gdk_color_equal(&style->text[GTK_STATE_SELECTED], &style->text[GTK_STATE_ACTIVE]))
+ gtk_widget_modify_text(w, GTK_STATE_ACTIVE, &style->text[GTK_STATE_SELECTED]);
+}
+
+void ListBoxX::Create(Window &, int, Point, int, bool) {
+ wid = gtk_window_new(GTK_WINDOW_POPUP);
+
+ GtkWidget *frame = gtk_frame_new(NULL);
+ gtk_widget_show(frame);
+ gtk_container_add(GTK_CONTAINER(GetID()), frame);
+ gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
+ gtk_container_set_border_width(GTK_CONTAINER(frame), 0);
+
+ scroller = gtk_scrolled_window_new(NULL, NULL);
+ gtk_container_set_border_width(GTK_CONTAINER(scroller), 0);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ gtk_container_add(GTK_CONTAINER(frame), PWidget(scroller));
+ gtk_widget_show(PWidget(scroller));
+
+ /* Tree and its model */
+ GtkListStore *store =
+ gtk_list_store_new(N_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING);
+
+ list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
+ g_signal_connect(G_OBJECT(list), "style-set", G_CALLBACK(StyleSet), NULL);
+
+ GtkTreeSelection *selection =
+ gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
+ gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
+ gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), FALSE);
+ gtk_tree_view_set_reorderable(GTK_TREE_VIEW(list), FALSE);
+
+ /* Columns */
+ GtkTreeViewColumn *column = gtk_tree_view_column_new();
+ gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
+ gtk_tree_view_column_set_title(column, "Autocomplete");
+
+ pixbuf_renderer = gtk_cell_renderer_pixbuf_new();
+ gtk_cell_renderer_set_fixed_size(pixbuf_renderer, 0, -1);
+ gtk_tree_view_column_pack_start(column, pixbuf_renderer, FALSE);
+ gtk_tree_view_column_add_attribute(column, pixbuf_renderer,
+ "pixbuf", PIXBUF_COLUMN);
+
+ GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
+ gtk_cell_renderer_text_set_fixed_height_from_font(GTK_CELL_RENDERER_TEXT(renderer), 1);
+ gtk_tree_view_column_pack_start(column, renderer, TRUE);
+ gtk_tree_view_column_add_attribute(column, renderer,
+ "text", TEXT_COLUMN);
+
+ gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
+ if (g_object_class_find_property(G_OBJECT_GET_CLASS(list), "fixed-height-mode"))
+ g_object_set(G_OBJECT(list), "fixed-height-mode", TRUE, NULL);
+
+ GtkWidget *wid = PWidget(list); // No code inside the G_OBJECT macro
+ gtk_container_add(GTK_CONTAINER(PWidget(scroller)), wid);
+ gtk_widget_show(wid);
+ g_signal_connect(G_OBJECT(wid), "button_press_event",
+ G_CALLBACK(ButtonPress), this);
+ gtk_widget_realize(PWidget(wid));
+}
+
+void ListBoxX::SetFont(Font &scint_font) {
+ // Only do for Pango font as there have been crashes for GDK fonts
+ if (Created() && PFont(scint_font)->pfd) {
+ // Current font is Pango font
+ gtk_widget_modify_font(PWidget(list), PFont(scint_font)->pfd);
+ }
+}
+
+void ListBoxX::SetAverageCharWidth(int width) {
+ aveCharWidth = width;
+}
+
+void ListBoxX::SetVisibleRows(int rows) {
+ desiredVisibleRows = rows;
+}
+
+int ListBoxX::GetVisibleRows() const {
+ return desiredVisibleRows;
+}
+
+PRectangle ListBoxX::GetDesiredRect() {
+ // Before any size allocated pretend its 100 wide so not scrolled
+ PRectangle rc(0, 0, 100, 100);
+ if (wid) {
+ int rows = Length();
+ if ((rows == 0) || (rows > desiredVisibleRows))
+ rows = desiredVisibleRows;
+
+ GtkRequisition req;
+ int height;
+
+ // First calculate height of the clist for our desired visible
+ // row count otherwise it tries to expand to the total # of rows
+ // Get cell height
+ int row_width=0;
+ int row_height=0;
+ GtkTreeViewColumn * column =
+ gtk_tree_view_get_column(GTK_TREE_VIEW(list), 0);
+ gtk_tree_view_column_cell_get_size(column, NULL,
+ NULL, NULL, &row_width, &row_height);
+ int ythickness = PWidget(list)->style->ythickness;
+ height = (rows * row_height
+ + 2 * (ythickness
+ + GTK_CONTAINER(PWidget(list))->border_width + 1));
+ gtk_widget_set_usize(GTK_WIDGET(PWidget(list)), -1, height);
+
+ // Get the size of the scroller because we set usize on the window
+ gtk_widget_size_request(GTK_WIDGET(scroller), &req);
+ rc.right = req.width;
+ rc.bottom = req.height;
+
+ gtk_widget_set_usize(GTK_WIDGET(list), -1, -1);
+ int width = maxItemCharacters;
+ if (width < 12)
+ width = 12;
+ rc.right = width * (aveCharWidth + aveCharWidth / 3);
+ if (Length() > rows)
+ rc.right = rc.right + 16;
+ }
+ return rc;
+}
+
+int ListBoxX::CaretFromEdge() {
+ gint renderer_width, renderer_height;
+ gtk_cell_renderer_get_fixed_size(pixbuf_renderer, &renderer_width,
+ &renderer_height);
+ return 4 + renderer_width;
+}
+
+void ListBoxX::Clear() {
+ GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list));
+ gtk_list_store_clear(GTK_LIST_STORE(model));
+ maxItemCharacters = 0;
+}
+
+static void init_pixmap(ListImage *list_image) {
+ const char *textForm = list_image->xpm_data;
+ const char * const * xpm_lineform = reinterpret_cast<const char * const *>(textForm);
+ const char **xpm_lineformfromtext = 0;
+ // The XPM data can be either in atext form as will be read from a file
+ // or in a line form (array of char *) as will be used for images defined in code.
+ // Test for text form and convert to line form
+ if ((0 == memcmp(textForm, "/* X", 4)) && (0 == memcmp(textForm, "/* XPM */", 9))) {
+ // Test done is two parts to avoid possibility of overstepping the memory
+ // if memcmp implemented strangely. Must be 4 bytes at least at destination.
+ xpm_lineformfromtext = XPM::LinesFormFromTextForm(textForm);
+ xpm_lineform = xpm_lineformfromtext;
+ }
+
+ // Drop any existing pixmap/bitmap as data may have changed
+ if (list_image->pixbuf)
+ gdk_pixbuf_unref(list_image->pixbuf);
+ list_image->pixbuf =
+ gdk_pixbuf_new_from_xpm_data((const gchar**)xpm_lineform);
+ delete []xpm_lineformfromtext;
+}
+
+#define SPACING 5
+
+void ListBoxX::Append(char *s, int type) {
+ ListImage *list_image = NULL;
+ if ((type >= 0) && pixhash) {
+ list_image = (ListImage *) g_hash_table_lookup((GHashTable *) pixhash
+ , (gconstpointer) GINT_TO_POINTER(type));
+ }
+ GtkTreeIter iter;
+ GtkListStore *store =
+ GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
+ gtk_list_store_append(GTK_LIST_STORE(store), &iter);
+ if (list_image) {
+ if (NULL == list_image->pixbuf)
+ init_pixmap(list_image);
+ if (list_image->pixbuf) {
+ gtk_list_store_set(GTK_LIST_STORE(store), &iter,
+ PIXBUF_COLUMN, list_image->pixbuf,
+ TEXT_COLUMN, s, -1);
+
+ gint pixbuf_width = gdk_pixbuf_get_width(list_image->pixbuf);
+ gint renderer_height, renderer_width;
+ gtk_cell_renderer_get_fixed_size(pixbuf_renderer,
+ &renderer_width, &renderer_height);
+ if (pixbuf_width > renderer_width)
+ gtk_cell_renderer_set_fixed_size(pixbuf_renderer,
+ pixbuf_width, -1);
+ } else {
+ gtk_list_store_set(GTK_LIST_STORE(store), &iter,
+ TEXT_COLUMN, s, -1);
+ }
+ } else {
+ gtk_list_store_set(GTK_LIST_STORE(store), &iter,
+ TEXT_COLUMN, s, -1);
+ }
+ size_t len = strlen(s);
+ if (maxItemCharacters < len)
+ maxItemCharacters = len;
+}
+
+int ListBoxX::Length() {
+ if (wid)
+ return gtk_tree_model_iter_n_children(gtk_tree_view_get_model
+ (GTK_TREE_VIEW(list)), NULL);
+ return 0;
+}
+
+void ListBoxX::Select(int n) {
+ GtkTreeIter iter;
+ GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list));
+ GtkTreeSelection *selection =
+ gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
+
+ if (n < 0) {
+ gtk_tree_selection_unselect_all(selection);
+ return;
+ }
+
+ bool valid = gtk_tree_model_iter_nth_child(model, &iter, NULL, n) != FALSE;
+ if (valid) {
+ gtk_tree_selection_select_iter(selection, &iter);
+
+ // Move the scrollbar to show the selection.
+ int total = Length();
+ GtkAdjustment *adj =
+ gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(list));
+ gfloat value = ((gfloat)n / total) * (adj->upper - adj->lower)
+ + adj->lower - adj->page_size / 2;
+
+ // Get cell height
+ int row_width;
+ int row_height;
+ GtkTreeViewColumn * column =
+ gtk_tree_view_get_column(GTK_TREE_VIEW(list), 0);
+ gtk_tree_view_column_cell_get_size(column, NULL, NULL,
+ NULL, &row_width, &row_height);
+
+ int rows = Length();
+ if ((rows == 0) || (rows > desiredVisibleRows))
+ rows = desiredVisibleRows;
+ if (rows & 0x1) {
+ // Odd rows to display -- We are now in the middle.
+ // Align it so that we don't chop off rows.
+ value += (gfloat)row_height / 2.0;
+ }
+ // Clamp it.
+ value = (value < 0)? 0 : value;
+ value = (value > (adj->upper - adj->page_size))?
+ (adj->upper - adj->page_size) : value;
+
+ // Set it.
+ gtk_adjustment_set_value(adj, value);
+ } else {
+ gtk_tree_selection_unselect_all(selection);
+ }
+}
+
+int ListBoxX::GetSelection() {
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
+ if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
+ GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
+ int *indices = gtk_tree_path_get_indices(path);
+ // Don't free indices.
+ if (indices)
+ return indices[0];
+ }
+ return -1;
+}
+
+int ListBoxX::Find(const char *prefix) {
+ GtkTreeIter iter;
+ GtkTreeModel *model =
+ gtk_tree_view_get_model(GTK_TREE_VIEW(list));
+ bool valid = gtk_tree_model_get_iter_first(model, &iter) != FALSE;
+ int i = 0;
+ while(valid) {
+ gchar *s;
+ gtk_tree_model_get(model, &iter, TEXT_COLUMN, &s, -1);
+ if (s && (0 == strncmp(prefix, s, strlen(prefix)))) {
+ return i;
+ }
+ valid = gtk_tree_model_iter_next(model, &iter) != FALSE;
+ i++;
+ }
+ return -1;
+}
+
+void ListBoxX::GetValue(int n, char *value, int len) {
+ char *text = NULL;
+ GtkTreeIter iter;
+ GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list));
+ bool valid = gtk_tree_model_iter_nth_child(model, &iter, NULL, n) != FALSE;
+ if (valid) {
+ gtk_tree_model_get(model, &iter, TEXT_COLUMN, &text, -1);
+ }
+ if (text && len > 0) {
+ strncpy(value, text, len);
+ value[len - 1] = '\0';
+ } else {
+ value[0] = '\0';
+ }
+}
+
+// g_return_if_fail causes unnecessary compiler warning in release compile.
+#ifdef _MSC_VER
+#pragma warning(disable: 4127)
+#endif
+
+void ListBoxX::RegisterImage(int type, const char *xpm_data) {
+ g_return_if_fail(xpm_data);
+
+ // Saved and use the saved copy so caller's copy can disappear.
+ xset.Add(type, xpm_data);
+ XPM *pxpm = xset.Get(type);
+ xpm_data = reinterpret_cast<const char *>(pxpm->InLinesForm());
+
+ if (!pixhash) {
+ pixhash = g_hash_table_new(g_direct_hash, g_direct_equal);
+ }
+ ListImage *list_image = (ListImage *) g_hash_table_lookup((GHashTable *) pixhash,
+ (gconstpointer) GINT_TO_POINTER(type));
+ if (list_image) {
+ // Drop icon already registered
+ if (list_image->pixbuf)
+ gdk_pixbuf_unref(list_image->pixbuf);
+ list_image->pixbuf = NULL;
+ list_image->xpm_data = xpm_data;
+ } else {
+ list_image = g_new0(ListImage, 1);
+ list_image->xpm_data = xpm_data;
+ g_hash_table_insert((GHashTable *) pixhash, GINT_TO_POINTER(type),
+ (gpointer) list_image);
+ }
+}
+
+void ListBoxX::ClearRegisteredImages() {
+ xset.Clear();
+}
+
+void ListBoxX::SetList(const char *listText, char separator, char typesep) {
+ Clear();
+ int count = strlen(listText) + 1;
+ char *words = new char[count];
+ if (words) {
+ memcpy(words, listText, count);
+ char *startword = words;
+ char *numword = NULL;
+ int i = 0;
+ for (; words[i]; i++) {
+ if (words[i] == separator) {
+ words[i] = '\0';
+ if (numword)
+ *numword = '\0';
+ Append(startword, numword?atoi(numword + 1):-1);
+ startword = words + i + 1;
+ numword = NULL;
+ } else if (words[i] == typesep) {
+ numword = words + i;
+ }
+ }
+ if (startword) {
+ if (numword)
+ *numword = '\0';
+ Append(startword, numword?atoi(numword + 1):-1);
+ }
+ delete []words;
+ }
+}
+
+Menu::Menu() : mid(0) {}
+
+void Menu::CreatePopUp() {
+ Destroy();
+ mid = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
+}
+
+void Menu::Destroy() {
+ if (mid)
+ g_object_unref(G_OBJECT(mid));
+ mid = 0;
+}
+
+void Menu::Show(Point pt, Window &) {
+ int screenHeight = gdk_screen_height();
+ int screenWidth = gdk_screen_width();
+ GtkItemFactory *factory = reinterpret_cast<GtkItemFactory *>(mid);
+ GtkWidget *widget = gtk_item_factory_get_widget(factory, "<main>");
+ gtk_widget_show_all(widget);
+ GtkRequisition requisition;
+ gtk_widget_size_request(widget, &requisition);
+ if ((pt.x + requisition.width) > screenWidth) {
+ pt.x = screenWidth - requisition.width;
+ }
+ if ((pt.y + requisition.height) > screenHeight) {
+ pt.y = screenHeight - requisition.height;
+ }
+ gtk_item_factory_popup(factory, pt.x - 4, pt.y - 4, 3,
+ gtk_get_current_event_time());
+}
+
+ElapsedTime::ElapsedTime() {
+ GTimeVal curTime;
+ g_get_current_time(&curTime);
+ bigBit = curTime.tv_sec;
+ littleBit = curTime.tv_usec;
+}
+
+class DynamicLibraryImpl : public DynamicLibrary {
+protected:
+ GModule* m;
+public:
+ DynamicLibraryImpl(const char *modulePath) {
+ m = g_module_open(modulePath, G_MODULE_BIND_LAZY);
+ }
+
+ virtual ~DynamicLibraryImpl() {
+ if (m != NULL)
+ g_module_close(m);
+ }
+
+ // Use g_module_symbol to get a pointer to the relevant function.
+ virtual Function FindFunction(const char *name) {
+ if (m != NULL) {
+ gpointer fn_address = NULL;
+ gboolean status = g_module_symbol(m, name, &fn_address);
+ if (status)
+ return static_cast<Function>(fn_address);
+ else
+ return NULL;
+ } else
+ return NULL;
+ }
+
+ virtual bool IsValid() {
+ return m != NULL;
+ }
+};
+
+DynamicLibrary *DynamicLibrary::Load(const char *modulePath) {
+ return static_cast<DynamicLibrary *>( new DynamicLibraryImpl(modulePath) );
+}
+
+double ElapsedTime::Duration(bool reset) {
+ GTimeVal curTime;
+ g_get_current_time(&curTime);
+ long endBigBit = curTime.tv_sec;
+ long endLittleBit = curTime.tv_usec;
+ double result = 1000000.0 * (endBigBit - bigBit);
+ result += endLittleBit - littleBit;
+ result /= 1000000.0;
+ if (reset) {
+ bigBit = endBigBit;
+ littleBit = endLittleBit;
+ }
+ return result;
+}
+
+ColourDesired Platform::Chrome() {
+ return ColourDesired(0xe0, 0xe0, 0xe0);
+}
+
+ColourDesired Platform::ChromeHighlight() {
+ return ColourDesired(0xff, 0xff, 0xff);
+}
+
+const char *Platform::DefaultFont() {
+#ifdef G_OS_WIN32
+ return "Lucida Console";
+#else
+ return "!Sans";
+#endif
+}
+
+int Platform::DefaultFontSize() {
+#ifdef G_OS_WIN32
+ return 10;
+#else
+ return 12;
+#endif
+}
+
+unsigned int Platform::DoubleClickTime() {
+ return 500; // Half a second
+}
+
+bool Platform::MouseButtonBounce() {
+ return true;
+}
+
+void Platform::DebugDisplay(const char *s) {
+ fprintf(stderr, "%s", s);
+}
+
+bool Platform::IsKeyDown(int) {
+ // TODO: discover state of keys in GTK+/X
+ return false;
+}
+
+long Platform::SendScintilla(
+ WindowID w, unsigned int msg, unsigned long wParam, long lParam) {
+ return scintilla_send_message(SCINTILLA(w), msg, wParam, lParam);
+}
+
+long Platform::SendScintillaPointer(
+ WindowID w, unsigned int msg, unsigned long wParam, void *lParam) {
+ return scintilla_send_message(SCINTILLA(w), msg, wParam,
+ reinterpret_cast<sptr_t>(lParam));
+}
+
+bool Platform::IsDBCSLeadByte(int codePage, char ch) {
+ // Byte ranges found in Wikipedia articles with relevant search strings in each case
+ unsigned char uch = static_cast<unsigned char>(ch);
+ switch (codePage) {
+ case 932:
+ // Shift_jis
+ return ((uch >= 0x81) && (uch <= 0x9F)) ||
+ ((uch >= 0xE0) && (uch <= 0xEF));
+ case 936:
+ // GBK
+ return (uch >= 0x81) && (uch <= 0xFE);
+ case 950:
+ // Big5
+ return (uch >= 0x81) && (uch <= 0xFE);
+ // Korean EUC-KR may be code page 949.
+ }
+ return false;
+}
+
+int Platform::DBCSCharLength(int codePage, const char *s) {
+ if (codePage == 932 || codePage == 936 || codePage == 950) {
+ return IsDBCSLeadByte(codePage, s[0]) ? 2 : 1;
+ } else {
+ int bytes = mblen(s, MB_CUR_MAX);
+ if (bytes >= 1)
+ return bytes;
+ else
+ return 1;
+ }
+}
+
+int Platform::DBCSCharMaxLength() {
+ return MB_CUR_MAX;
+ //return 2;
+}
+
+// These are utility functions not really tied to a platform
+
+int Platform::Minimum(int a, int b) {
+ if (a < b)
+ return a;
+ else
+ return b;
+}
+
+int Platform::Maximum(int a, int b) {
+ if (a > b)
+ return a;
+ else
+ return b;
+}
+
+//#define TRACE
+
+#ifdef TRACE
+void Platform::DebugPrintf(const char *format, ...) {
+ char buffer[2000];
+ va_list pArguments;
+ va_start(pArguments, format);
+ vsprintf(buffer, format, pArguments);
+ va_end(pArguments);
+ Platform::DebugDisplay(buffer);
+}
+#else
+void Platform::DebugPrintf(const char *, ...) {}
+
+#endif
+
+// Not supported for GTK+
+static bool assertionPopUps = true;
+
+bool Platform::ShowAssertionPopUps(bool assertionPopUps_) {
+ bool ret = assertionPopUps;
+ assertionPopUps = assertionPopUps_;
+ return ret;
+}
+
+void Platform::Assert(const char *c, const char *file, int line) {
+ char buffer[2000];
+ sprintf(buffer, "Assertion [%s] failed at %s %d", c, file, line);
+ strcat(buffer, "\r\n");
+ Platform::DebugDisplay(buffer);
+ abort();
+}
+
+int Platform::Clamp(int val, int minVal, int maxVal) {
+ if (val > maxVal)
+ val = maxVal;
+ if (val < minVal)
+ val = minVal;
+ return val;
+}
+
+void Platform_Initialise() {
+ FontMutexAllocate();
+}
+
+void Platform_Finalise() {
+ FontMutexFree();
+}
diff --git a/scintilla/gtk/ScintillaGTK.cxx b/scintilla/gtk/ScintillaGTK.cxx
new file mode 100644
index 0000000..3865a6e
--- /dev/null
+++ b/scintilla/gtk/ScintillaGTK.cxx
@@ -0,0 +1,2536 @@
+// Scintilla source code edit control
+// ScintillaGTK.cxx - GTK+ specific subclass of ScintillaBase
+// Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org>
+// The License.txt file describes the conditions under which this software may be distributed.
+
+#include <new>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <time.h>
+
+#include <string>
+#include <vector>
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "Platform.h"
+
+#if PLAT_GTK_WIN32
+#include "windows.h"
+#endif
+
+#include "Scintilla.h"
+#include "ScintillaWidget.h"
+#ifdef SCI_LEXER
+#include "SciLexer.h"
+#include "PropSet.h"
+#include "PropSetSimple.h"
+#include "Accessor.h"
+#include "KeyWords.h"
+#endif
+#include "SVector.h"
+#include "SplitVector.h"
+#include "Partitioning.h"
+#include "RunStyles.h"
+#include "ContractionState.h"
+#include "CellBuffer.h"
+#include "CallTip.h"
+#include "KeyMap.h"
+#include "Indicator.h"
+#include "XPM.h"
+#include "LineMarker.h"
+#include "Style.h"
+#include "AutoComplete.h"
+#include "ViewStyle.h"
+#include "Decoration.h"
+#include "CharClassify.h"
+#include "Document.h"
+#include "Selection.h"
+#include "PositionCache.h"
+#include "Editor.h"
+#include "ScintillaBase.h"
+#include "UniConversion.h"
+
+#include "gtk/gtksignal.h"
+#include "gtk/gtkmarshal.h"
+#include "scintilla-marshal.h"
+
+#ifdef SCI_LEXER
+#include <glib.h>
+#include <gmodule.h>
+#include "ExternalLexer.h"
+#endif
+
+#include "Converter.h"
+
+#ifdef _MSC_VER
+// Constant conditional expressions are because of GTK+ headers
+#pragma warning(disable: 4127)
+// Ignore unreferenced local functions in GTK+ headers
+#pragma warning(disable: 4505)
+#endif
+
+#if GTK_CHECK_VERSION(2,6,0)
+#define USE_GTK_CLIPBOARD
+#endif
+
+#define OBJECT_CLASS GObjectClass
+
+#ifdef SCI_NAMESPACE
+using namespace Scintilla;
+#endif
+
+extern char *UTF8FromLatin1(const char *s, int &len);
+
+class ScintillaGTK : public ScintillaBase {
+ _ScintillaObject *sci;
+ Window wText;
+ Window scrollbarv;
+ Window scrollbarh;
+ GtkObject *adjustmentv;
+ GtkObject *adjustmenth;
+ int scrollBarWidth;
+ int scrollBarHeight;
+
+ // Because clipboard access is asynchronous, copyText is created by Copy
+#ifndef USE_GTK_CLIPBOARD
+ SelectionText copyText;
+#endif
+
+ SelectionText primary;
+
+ GdkEventButton evbtn;
+ bool capturedMouse;
+ bool dragWasDropped;
+ int lastKey;
+ int rectangularSelectionModifier;
+
+ GtkWidgetClass *parentClass;
+
+ static GdkAtom atomClipboard;
+ static GdkAtom atomUTF8;
+ static GdkAtom atomString;
+ static GdkAtom atomUriList;
+ static GdkAtom atomDROPFILES_DND;
+ GdkAtom atomSought;
+
+#if PLAT_GTK_WIN32
+ CLIPFORMAT cfColumnSelect;
+#endif
+
+ Window wPreedit;
+ Window wPreeditDraw;
+ GtkIMContext *im_context;
+
+ // Wheel mouse support
+ unsigned int linesPerScroll;
+ GTimeVal lastWheelMouseTime;
+ gint lastWheelMouseDirection;
+ gint wheelMouseIntensity;
+
+ GdkRegion *rgnUpdate;
+
+ // Private so ScintillaGTK objects can not be copied
+ ScintillaGTK(const ScintillaGTK &);
+ ScintillaGTK &operator=(const ScintillaGTK &);
+
+public:
+ ScintillaGTK(_ScintillaObject *sci_);
+ virtual ~ScintillaGTK();
+ static void ClassInit(OBJECT_CLASS* object_class, GtkWidgetClass *widget_class, GtkContainerClass *container_class);
+private:
+ virtual void Initialise();
+ virtual void Finalise();
+ virtual void DisplayCursor(Window::Cursor c);
+ virtual bool DragThreshold(Point ptStart, Point ptNow);
+ virtual void StartDrag();
+ int TargetAsUTF8(char *text);
+ int EncodedFromUTF8(char *utf8, char *encoded);
+ virtual bool ValidCodePage(int codePage) const;
+public: // Public for scintilla_send_message
+ virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
+private:
+ virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
+ virtual void SetTicking(bool on);
+ virtual bool SetIdle(bool on);
+ virtual void SetMouseCapture(bool on);
+ virtual bool HaveMouseCapture();
+ virtual bool PaintContains(PRectangle rc);
+ void FullPaint();
+ virtual PRectangle GetClientRectangle();
+ void SyncPaint(PRectangle rc);
+ virtual void ScrollText(int linesToMove);
+ virtual void SetVerticalScrollPos();
+ virtual void SetHorizontalScrollPos();
+ virtual bool ModifyScrollBars(int nMax, int nPage);
+ void ReconfigureScrollBars();
+ virtual void NotifyChange();
+ virtual void NotifyFocus(bool focus);
+ virtual void NotifyParent(SCNotification scn);
+ void NotifyKey(int key, int modifiers);
+ void NotifyURIDropped(const char *list);
+ const char *CharacterSetID() const;
+ virtual CaseFolder *CaseFolderForEncoding();
+ virtual std::string CaseMapString(const std::string &s, int caseMapping);
+ virtual int KeyDefault(int key, int modifiers);
+ virtual void CopyToClipboard(const SelectionText &selectedText);
+ virtual void Copy();
+ virtual void Paste();
+ virtual void CreateCallTipWindow(PRectangle rc);
+ virtual void AddToPopUp(const char *label, int cmd = 0, bool enabled = true);
+ bool OwnPrimarySelection();
+ virtual void ClaimSelection();
+ void GetGtkSelectionText(GtkSelectionData *selectionData, SelectionText &selText);
+ void ReceivedSelection(GtkSelectionData *selection_data);
+ void ReceivedDrop(GtkSelectionData *selection_data);
+ static void GetSelection(GtkSelectionData *selection_data, guint info, SelectionText *selected);
+#ifdef USE_GTK_CLIPBOARD
+ void StoreOnClipboard(SelectionText *clipText);
+ static void ClipboardGetSelection(GtkClipboard* clip, GtkSelectionData *selection_data, guint info, void *data);
+ static void ClipboardClearSelection(GtkClipboard* clip, void *data);
+#endif
+
+ void UnclaimSelection(GdkEventSelection *selection_event);
+ void Resize(int width, int height);
+
+ // Callback functions
+ void RealizeThis(GtkWidget *widget);
+ static void Realize(GtkWidget *widget);
+ void UnRealizeThis(GtkWidget *widget);
+ static void UnRealize(GtkWidget *widget);
+ void MapThis();
+ static void Map(GtkWidget *widget);
+ void UnMapThis();
+ static void UnMap(GtkWidget *widget);
+ static gint CursorMoved(GtkWidget *widget, int xoffset, int yoffset, ScintillaGTK *sciThis);
+ gint FocusInThis(GtkWidget *widget);
+ static gint FocusIn(GtkWidget *widget, GdkEventFocus *event);
+ gint FocusOutThis(GtkWidget *widget);
+ static gint FocusOut(GtkWidget *widget, GdkEventFocus *event);
+ static void SizeRequest(GtkWidget *widget, GtkRequisition *requisition);
+ static void SizeAllocate(GtkWidget *widget, GtkAllocation *allocation);
+ gint Expose(GtkWidget *widget, GdkEventExpose *ose);
+ static gint ExposeMain(GtkWidget *widget, GdkEventExpose *ose);
+ static void Draw(GtkWidget *widget, GdkRectangle *area);
+ void ForAll(GtkCallback callback, gpointer callback_data);
+ static void MainForAll(GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data);
+
+ static void ScrollSignal(GtkAdjustment *adj, ScintillaGTK *sciThis);
+ static void ScrollHSignal(GtkAdjustment *adj, ScintillaGTK *sciThis);
+ gint PressThis(GdkEventButton *event);
+ static gint Press(GtkWidget *widget, GdkEventButton *event);
+ static gint MouseRelease(GtkWidget *widget, GdkEventButton *event);
+ static gint ScrollEvent(GtkWidget *widget, GdkEventScroll *event);
+ static gint Motion(GtkWidget *widget, GdkEventMotion *event);
+ gboolean KeyThis(GdkEventKey *event);
+ static gboolean KeyPress(GtkWidget *widget, GdkEventKey *event);
+ static gboolean KeyRelease(GtkWidget *widget, GdkEventKey *event);
+ gboolean ExposePreeditThis(GtkWidget *widget, GdkEventExpose *ose);
+ static gboolean ExposePreedit(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis);
+ void CommitThis(char *str);
+ static void Commit(GtkIMContext *context, char *str, ScintillaGTK *sciThis);
+ void PreeditChangedThis();
+ static void PreeditChanged(GtkIMContext *context, ScintillaGTK *sciThis);
+ static gint StyleSetText(GtkWidget *widget, GtkStyle *previous, void*);
+ static gint RealizeText(GtkWidget *widget, void*);
+ static void Destroy(GObject *object);
+ static void SelectionReceived(GtkWidget *widget, GtkSelectionData *selection_data,
+ guint time);
+ static void SelectionGet(GtkWidget *widget, GtkSelectionData *selection_data,
+ guint info, guint time);
+ static gint SelectionClear(GtkWidget *widget, GdkEventSelection *selection_event);
+ static void DragBegin(GtkWidget *widget, GdkDragContext *context);
+ gboolean DragMotionThis(GdkDragContext *context, gint x, gint y, guint dragtime);
+ static gboolean DragMotion(GtkWidget *widget, GdkDragContext *context,
+ gint x, gint y, guint dragtime);
+ static void DragLeave(GtkWidget *widget, GdkDragContext *context,
+ guint time);
+ static void DragEnd(GtkWidget *widget, GdkDragContext *context);
+ static gboolean Drop(GtkWidget *widget, GdkDragContext *context,
+ gint x, gint y, guint time);
+ static void DragDataReceived(GtkWidget *widget, GdkDragContext *context,
+ gint x, gint y, GtkSelectionData *selection_data, guint info, guint time);
+ static void DragDataGet(GtkWidget *widget, GdkDragContext *context,
+ GtkSelectionData *selection_data, guint info, guint time);
+ static gint TimeOut(ScintillaGTK *sciThis);
+ static gboolean IdleCallback(ScintillaGTK *sciThis);
+ static gboolean StyleIdle(ScintillaGTK *sciThis);
+ virtual void QueueStyling(int upTo);
+ static void PopUpCB(ScintillaGTK *sciThis, guint action, GtkWidget *widget);
+
+ gint ExposeTextThis(GtkWidget *widget, GdkEventExpose *ose);
+ static gint ExposeText(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis);
+
+ static gint ExposeCT(GtkWidget *widget, GdkEventExpose *ose, CallTip *ct);
+ static gint PressCT(GtkWidget *widget, GdkEventButton *event, ScintillaGTK *sciThis);
+
+ static sptr_t DirectFunction(ScintillaGTK *sciThis,
+ unsigned int iMessage, uptr_t wParam, sptr_t lParam);
+};
+
+enum {
+ COMMAND_SIGNAL,
+ NOTIFY_SIGNAL,
+ LAST_SIGNAL
+};
+
+static gint scintilla_signals[LAST_SIGNAL] = { 0 };
+
+enum {
+ TARGET_STRING,
+ TARGET_TEXT,
+ TARGET_COMPOUND_TEXT,
+ TARGET_UTF8_STRING,
+ TARGET_URI
+};
+
+GdkAtom ScintillaGTK::atomClipboard = 0;
+GdkAtom ScintillaGTK::atomUTF8 = 0;
+GdkAtom ScintillaGTK::atomString = 0;
+GdkAtom ScintillaGTK::atomUriList = 0;
+GdkAtom ScintillaGTK::atomDROPFILES_DND = 0;
+
+static const GtkTargetEntry clipboardCopyTargets[] = {
+ { (gchar *) "UTF8_STRING", 0, TARGET_UTF8_STRING },
+ { (gchar *) "STRING", 0, TARGET_STRING },
+};
+static const gint nClipboardCopyTargets = sizeof(clipboardCopyTargets) / sizeof(clipboardCopyTargets[0]);
+
+static const GtkTargetEntry clipboardPasteTargets[] = {
+ { (gchar *) "text/uri-list", 0, TARGET_URI },
+ { (gchar *) "UTF8_STRING", 0, TARGET_UTF8_STRING },
+ { (gchar *) "STRING", 0, TARGET_STRING },
+};
+static const gint nClipboardPasteTargets = sizeof(clipboardPasteTargets) / sizeof(clipboardPasteTargets[0]);
+
+static GtkWidget *PWidget(Window &w) {
+ return reinterpret_cast<GtkWidget *>(w.GetID());
+}
+
+static ScintillaGTK *ScintillaFromWidget(GtkWidget *widget) {
+ ScintillaObject *scio = reinterpret_cast<ScintillaObject *>(widget);
+ return reinterpret_cast<ScintillaGTK *>(scio->pscin);
+}
+
+ScintillaGTK::ScintillaGTK(_ScintillaObject *sci_) :
+ adjustmentv(0), adjustmenth(0),
+ scrollBarWidth(30), scrollBarHeight(30),
+ capturedMouse(false), dragWasDropped(false),
+ lastKey(0), rectangularSelectionModifier(SCMOD_CTRL), parentClass(0),
+ im_context(NULL),
+ lastWheelMouseDirection(0),
+ wheelMouseIntensity(0),
+ rgnUpdate(0) {
+ sci = sci_;
+ wMain = GTK_WIDGET(sci);
+
+#if PLAT_GTK_WIN32
+ rectangularSelectionModifier = SCMOD_ALT;
+#else
+ rectangularSelectionModifier = SCMOD_CTRL;
+#endif
+
+#if PLAT_GTK_WIN32
+ // There does not seem to be a real standard for indicating that the clipboard
+ // contains a rectangular selection, so copy Developer Studio.
+ cfColumnSelect = static_cast<CLIPFORMAT>(
+ ::RegisterClipboardFormat("MSDEVColumnSelect"));
+
+ // Get intellimouse parameters when running on win32; otherwise use
+ // reasonable default
+#ifndef SPI_GETWHEELSCROLLLINES
+#define SPI_GETWHEELSCROLLLINES 104
+#endif
+ ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &linesPerScroll, 0);
+#else
+ linesPerScroll = 4;
+#endif
+ lastWheelMouseTime.tv_sec = 0;
+ lastWheelMouseTime.tv_usec = 0;
+
+ Initialise();
+}
+
+ScintillaGTK::~ScintillaGTK() {
+}
+
+void ScintillaGTK::RealizeThis(GtkWidget *widget) {
+ //Platform::DebugPrintf("ScintillaGTK::realize this\n");
+ GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
+ GdkWindowAttr attrs;
+ attrs.window_type = GDK_WINDOW_CHILD;
+ attrs.x = widget->allocation.x;
+ attrs.y = widget->allocation.y;
+ attrs.width = widget->allocation.width;
+ attrs.height = widget->allocation.height;
+ attrs.wclass = GDK_INPUT_OUTPUT;
+ attrs.visual = gtk_widget_get_visual(widget);
+ attrs.colormap = gtk_widget_get_colormap(widget);
+ attrs.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK;
+ GdkCursor *cursor = gdk_cursor_new(GDK_XTERM);
+ attrs.cursor = cursor;
+ 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);
+ gdk_window_set_background(widget->window, &widget->style->bg[GTK_STATE_NORMAL]);
+ gdk_window_show(widget->window);
+ gdk_cursor_destroy(cursor);
+ widget->style = gtk_style_attach(widget->style, widget->window);
+ wPreedit = gtk_window_new(GTK_WINDOW_POPUP);
+ wPreeditDraw = gtk_drawing_area_new();
+ GtkWidget *predrw = PWidget(wPreeditDraw); // No code inside the G_OBJECT macro
+ g_signal_connect(G_OBJECT(predrw), "expose_event",
+ G_CALLBACK(ExposePreedit), this);
+ gtk_container_add(GTK_CONTAINER(PWidget(wPreedit)), predrw);
+ gtk_widget_realize(PWidget(wPreedit));
+ gtk_widget_realize(predrw);
+ gtk_widget_show(predrw);
+
+ im_context = gtk_im_multicontext_new();
+ g_signal_connect(G_OBJECT(im_context), "commit",
+ G_CALLBACK(Commit), this);
+ g_signal_connect(G_OBJECT(im_context), "preedit_changed",
+ G_CALLBACK(PreeditChanged), this);
+ gtk_im_context_set_client_window(im_context, widget->window);
+ GtkWidget *widtxt = PWidget(wText); // // No code inside the G_OBJECT macro
+ g_signal_connect_after(G_OBJECT(widtxt), "style_set",
+ G_CALLBACK(ScintillaGTK::StyleSetText), NULL);
+ g_signal_connect_after(G_OBJECT(widtxt), "realize",
+ G_CALLBACK(ScintillaGTK::RealizeText), NULL);
+ gtk_widget_realize(widtxt);
+ gtk_widget_realize(PWidget(scrollbarv));
+ gtk_widget_realize(PWidget(scrollbarh));
+}
+
+void ScintillaGTK::Realize(GtkWidget *widget) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ sciThis->RealizeThis(widget);
+}
+
+void ScintillaGTK::UnRealizeThis(GtkWidget *widget) {
+ try {
+ if (GTK_WIDGET_MAPPED(widget)) {
+ gtk_widget_unmap(widget);
+ }
+ GTK_WIDGET_UNSET_FLAGS(widget, GTK_REALIZED);
+ gtk_widget_unrealize(PWidget(wText));
+ gtk_widget_unrealize(PWidget(scrollbarv));
+ gtk_widget_unrealize(PWidget(scrollbarh));
+ gtk_widget_unrealize(PWidget(wPreedit));
+ gtk_widget_unrealize(PWidget(wPreeditDraw));
+ g_object_unref(im_context);
+ im_context = NULL;
+ if (GTK_WIDGET_CLASS(parentClass)->unrealize)
+ GTK_WIDGET_CLASS(parentClass)->unrealize(widget);
+
+ Finalise();
+ } catch (...) {
+ errorStatus = SC_STATUS_FAILURE;
+ }
+}
+
+void ScintillaGTK::UnRealize(GtkWidget *widget) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ sciThis->UnRealizeThis(widget);
+}
+
+static void MapWidget(GtkWidget *widget) {
+ if (widget &&
+ GTK_WIDGET_VISIBLE(widget) &&
+ !GTK_WIDGET_MAPPED(widget)) {
+ gtk_widget_map(widget);
+ }
+}
+
+void ScintillaGTK::MapThis() {
+ try {
+ //Platform::DebugPrintf("ScintillaGTK::map this\n");
+ GTK_WIDGET_SET_FLAGS(PWidget(wMain), GTK_MAPPED);
+ MapWidget(PWidget(wText));
+ MapWidget(PWidget(scrollbarh));
+ MapWidget(PWidget(scrollbarv));
+ wMain.SetCursor(Window::cursorArrow);
+ scrollbarv.SetCursor(Window::cursorArrow);
+ scrollbarh.SetCursor(Window::cursorArrow);
+ ChangeSize();
+ gdk_window_show(PWidget(wMain)->window);
+ } catch (...) {
+ errorStatus = SC_STATUS_FAILURE;
+ }
+}
+
+void ScintillaGTK::Map(GtkWidget *widget) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ sciThis->MapThis();
+}
+
+void ScintillaGTK::UnMapThis() {
+ try {
+ //Platform::DebugPrintf("ScintillaGTK::unmap this\n");
+ GTK_WIDGET_UNSET_FLAGS(PWidget(wMain), GTK_MAPPED);
+ DropGraphics();
+ gdk_window_hide(PWidget(wMain)->window);
+ gtk_widget_unmap(PWidget(wText));
+ gtk_widget_unmap(PWidget(scrollbarh));
+ gtk_widget_unmap(PWidget(scrollbarv));
+ } catch (...) {
+ errorStatus = SC_STATUS_FAILURE;
+ }
+}
+
+void ScintillaGTK::UnMap(GtkWidget *widget) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ sciThis->UnMapThis();
+}
+
+void ScintillaGTK::ForAll(GtkCallback callback, gpointer callback_data) {
+ try {
+ (*callback) (PWidget(wText), callback_data);
+ (*callback) (PWidget(scrollbarv), callback_data);
+ (*callback) (PWidget(scrollbarh), callback_data);
+ } catch (...) {
+ errorStatus = SC_STATUS_FAILURE;
+ }
+}
+
+void ScintillaGTK::MainForAll(GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data) {
+ ScintillaGTK *sciThis = ScintillaFromWidget((GtkWidget *)container);
+
+ if (callback != NULL && include_internals) {
+ sciThis->ForAll(callback, callback_data);
+ }
+}
+
+gint ScintillaGTK::CursorMoved(GtkWidget *, int xoffset, int yoffset, ScintillaGTK *sciThis) {
+ GdkRectangle area;
+ area.x = xoffset;
+ area.y = yoffset;
+ area.width = 1;
+ area.height = 1;
+ gtk_im_context_set_cursor_location(sciThis->im_context, &area);
+ return FALSE;
+}
+
+gint ScintillaGTK::FocusInThis(GtkWidget *widget) {
+ try {
+ GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
+ SetFocusState(true);
+ if (im_context != NULL) {
+ gchar *str = NULL;
+ gint cursor_pos;
+
+ gtk_im_context_get_preedit_string(im_context, &str, NULL, &cursor_pos);
+ if (PWidget(wPreedit) != NULL) {
+ if (strlen(str) > 0) {
+ gtk_widget_show(PWidget(wPreedit));
+ } else {
+ gtk_widget_hide(PWidget(wPreedit));
+ }
+ }
+ g_free(str);
+ gtk_im_context_focus_in(im_context);
+ }
+
+ } catch (...) {
+ errorStatus = SC_STATUS_FAILURE;
+ }
+ return FALSE;
+}
+
+gint ScintillaGTK::FocusIn(GtkWidget *widget, GdkEventFocus * /*event*/) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ return sciThis->FocusInThis(widget);
+}
+
+gint ScintillaGTK::FocusOutThis(GtkWidget *widget) {
+ try {
+ GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
+ SetFocusState(false);
+
+ if (PWidget(wPreedit) != NULL)
+ gtk_widget_hide(PWidget(wPreedit));
+ if (im_context != NULL)
+ gtk_im_context_focus_out(im_context);
+
+ } catch (...) {
+ errorStatus = SC_STATUS_FAILURE;
+ }
+ return FALSE;
+}
+
+gint ScintillaGTK::FocusOut(GtkWidget *widget, GdkEventFocus * /*event*/) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ return sciThis->FocusOutThis(widget);
+}
+
+void ScintillaGTK::SizeRequest(GtkWidget *widget, GtkRequisition *requisition) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ requisition->width = 600;
+ requisition->height = gdk_screen_height();
+ GtkRequisition child_requisition;
+ gtk_widget_size_request(PWidget(sciThis->scrollbarh), &child_requisition);
+ gtk_widget_size_request(PWidget(sciThis->scrollbarv), &child_requisition);
+}
+
+void ScintillaGTK::SizeAllocate(GtkWidget *widget, GtkAllocation *allocation) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ try {
+ widget->allocation = *allocation;
+ if (GTK_WIDGET_REALIZED(widget))
+ gdk_window_move_resize(widget->window,
+ widget->allocation.x,
+ widget->allocation.y,
+ widget->allocation.width,
+ widget->allocation.height);
+
+ sciThis->Resize(allocation->width, allocation->height);
+
+ } catch (...) {
+ sciThis->errorStatus = SC_STATUS_FAILURE;
+ }
+}
+
+void ScintillaGTK::Initialise() {
+ //Platform::DebugPrintf("ScintillaGTK::Initialise\n");
+ parentClass = reinterpret_cast<GtkWidgetClass *>(
+ gtk_type_class(gtk_container_get_type()));
+
+ GTK_WIDGET_SET_FLAGS(PWidget(wMain), GTK_CAN_FOCUS);
+ GTK_WIDGET_SET_FLAGS(GTK_WIDGET(PWidget(wMain)), GTK_SENSITIVE);
+ gtk_widget_set_events(PWidget(wMain),
+ GDK_EXPOSURE_MASK
+ | GDK_STRUCTURE_MASK
+ | GDK_KEY_PRESS_MASK
+ | GDK_KEY_RELEASE_MASK
+ | GDK_FOCUS_CHANGE_MASK
+ | GDK_LEAVE_NOTIFY_MASK
+ | GDK_BUTTON_PRESS_MASK
+ | GDK_BUTTON_RELEASE_MASK
+ | GDK_POINTER_MOTION_MASK
+ | GDK_POINTER_MOTION_HINT_MASK);
+
+ wText = gtk_drawing_area_new();
+ gtk_widget_set_parent(PWidget(wText), PWidget(wMain));
+ GtkWidget *widtxt = PWidget(wText); // No code inside the G_OBJECT macro
+ gtk_widget_show(widtxt);
+ g_signal_connect(G_OBJECT(widtxt), "expose_event",
+ G_CALLBACK(ScintillaGTK::ExposeText), this);
+ gtk_widget_set_events(widtxt, GDK_EXPOSURE_MASK);
+ // Avoid background drawing flash
+ gtk_widget_set_double_buffered(widtxt, FALSE);
+ gtk_drawing_area_size(GTK_DRAWING_AREA(widtxt),
+ 100,100);
+ adjustmentv = gtk_adjustment_new(0.0, 0.0, 201.0, 1.0, 20.0, 20.0);
+ scrollbarv = gtk_vscrollbar_new(GTK_ADJUSTMENT(adjustmentv));
+ GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarv), GTK_CAN_FOCUS);
+ g_signal_connect(G_OBJECT(adjustmentv), "value_changed",
+ G_CALLBACK(ScrollSignal), this);
+ gtk_widget_set_parent(PWidget(scrollbarv), PWidget(wMain));
+ gtk_widget_show(PWidget(scrollbarv));
+
+ adjustmenth = gtk_adjustment_new(0.0, 0.0, 101.0, 1.0, 20.0, 20.0);
+ scrollbarh = gtk_hscrollbar_new(GTK_ADJUSTMENT(adjustmenth));
+ GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarh), GTK_CAN_FOCUS);
+ g_signal_connect(G_OBJECT(adjustmenth), "value_changed",
+ G_CALLBACK(ScrollHSignal), this);
+ gtk_widget_set_parent(PWidget(scrollbarh), PWidget(wMain));
+ gtk_widget_show(PWidget(scrollbarh));
+
+ gtk_widget_grab_focus(PWidget(wMain));
+
+ gtk_selection_add_targets(GTK_WIDGET(PWidget(wMain)), GDK_SELECTION_PRIMARY,
+ clipboardCopyTargets, nClipboardCopyTargets);
+
+#ifndef USE_GTK_CLIPBOARD
+ gtk_selection_add_targets(GTK_WIDGET(PWidget(wMain)), atomClipboard,
+ clipboardPasteTargets, nClipboardPasteTargets);
+#endif
+
+ gtk_drag_dest_set(GTK_WIDGET(PWidget(wMain)),
+ GTK_DEST_DEFAULT_ALL, clipboardPasteTargets, nClipboardPasteTargets,
+ static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE));
+
+ // Set caret period based on GTK settings
+ gboolean blinkOn = false;
+ if (g_object_class_find_property(G_OBJECT_GET_CLASS(
+ G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink")) {
+ g_object_get(G_OBJECT(
+ gtk_settings_get_default()), "gtk-cursor-blink", &blinkOn, NULL);
+ }
+ if (blinkOn &&
+ g_object_class_find_property(G_OBJECT_GET_CLASS(
+ G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink-time")) {
+ gint value;
+ g_object_get(G_OBJECT(
+ gtk_settings_get_default()), "gtk-cursor-blink-time", &value, NULL);
+ caret.period = gint(value / 1.75);
+ } else {
+ caret.period = 0;
+ }
+
+ SetTicking(true);
+}
+
+void ScintillaGTK::Finalise() {
+ SetTicking(false);
+ ScintillaBase::Finalise();
+}
+
+void ScintillaGTK::DisplayCursor(Window::Cursor c) {
+ if (cursorMode == SC_CURSORNORMAL)
+ wText.SetCursor(c);
+ else
+ wText.SetCursor(static_cast<Window::Cursor>(cursorMode));
+}
+
+bool ScintillaGTK::DragThreshold(Point ptStart, Point ptNow) {
+ return gtk_drag_check_threshold(GTK_WIDGET(PWidget(wMain)),
+ ptStart.x, ptStart.y, ptNow.x, ptNow.y);
+}
+
+void ScintillaGTK::StartDrag() {
+ dragWasDropped = false;
+ inDragDrop = ddDragging;
+ GtkTargetList *tl = gtk_target_list_new(clipboardCopyTargets, nClipboardCopyTargets);
+ gtk_drag_begin(GTK_WIDGET(PWidget(wMain)),
+ tl,
+ static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE),
+ evbtn.button,
+ reinterpret_cast<GdkEvent *>(&evbtn));
+}
+
+static char *ConvertText(int *lenResult, char *s, size_t len, const char *charSetDest,
+ const char *charSetSource, bool transliterations, bool silent=false) {
+ // s is not const because of different versions of iconv disagreeing about const
+ *lenResult = 0;
+ char *destForm = 0;
+ Converter conv(charSetDest, charSetSource, transliterations);
+ if (conv) {
+ destForm = new char[len*3+1];
+ char *pin = s;
+ size_t inLeft = len;
+ char *pout = destForm;
+ size_t outLeft = len*3+1;
+ size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
+ if (conversions == ((size_t)(-1))) {
+ if (!silent)
+ fprintf(stderr, "iconv %s->%s failed for %s\n",
+ charSetSource, charSetDest, static_cast<char *>(s));
+ delete []destForm;
+ destForm = 0;
+ } else {
+//fprintf(stderr, "iconv OK %s %d\n", destForm, pout - destForm);
+ *pout = '\0';
+ *lenResult = pout - destForm;
+ }
+ } else {
+fprintf(stderr, "Can not iconv %s %s\n", charSetDest, charSetSource);
+ }
+ if (!destForm) {
+ destForm = new char[1];
+ destForm[0] = '\0';
+ *lenResult = 0;
+ }
+ return destForm;
+}
+
+// Returns the target converted to UTF8.
+// Return the length in bytes.
+int ScintillaGTK::TargetAsUTF8(char *text) {
+ int targetLength = targetEnd - targetStart;
+ if (IsUnicodeMode()) {
+ if (text) {
+ pdoc->GetCharRange(text, targetStart, targetLength);
+ }
+ } else {
+ // Need to convert
+ const char *charSetBuffer = CharacterSetID();
+ if (*charSetBuffer) {
+//~ fprintf(stderr, "AsUTF8 %s %d %0d-%0d\n", charSetBuffer, targetLength, targetStart, targetEnd);
+ char *s = new char[targetLength];
+ if (s) {
+ pdoc->GetCharRange(s, targetStart, targetLength);
+//~ fprintf(stderr, " \"%s\"\n", s);
+ if (text) {
+ char *tmputf = ConvertText(&targetLength, s, targetLength, "UTF-8", charSetBuffer, false);
+ memcpy(text, tmputf, targetLength);
+ delete []tmputf;
+//~ fprintf(stderr, " \"%s\"\n", text);
+ }
+ delete []s;
+ }
+ } else {
+ if (text) {
+ pdoc->GetCharRange(text, targetStart, targetLength);
+ }
+ }
+ }
+//~ fprintf(stderr, "Length = %d bytes\n", targetLength);
+ return targetLength;
+}
+
+// Translates a nul terminated UTF8 string into the document encoding.
+// Return the length of the result in bytes.
+int ScintillaGTK::EncodedFromUTF8(char *utf8, char *encoded) {
+ int inputLength = (lengthForEncode >= 0) ? lengthForEncode : strlen(utf8);
+ if (IsUnicodeMode()) {
+ if (encoded) {
+ memcpy(encoded, utf8, inputLength);
+ }
+ return inputLength;
+ } else {
+ // Need to convert
+ const char *charSetBuffer = CharacterSetID();
+ if (*charSetBuffer) {
+ int outLength = 0;
+ char *tmpEncoded = ConvertText(&outLength, utf8, inputLength, charSetBuffer, "UTF-8", true);
+ if (tmpEncoded) {
+ if (encoded) {
+ memcpy(encoded, tmpEncoded, outLength);
+ }
+ delete []tmpEncoded;
+ }
+ return outLength;
+ } else {
+ if (encoded) {
+ memcpy(encoded, utf8, inputLength);
+ }
+ return inputLength;
+ }
+ }
+ // Fail
+ return 0;
+}
+
+bool ScintillaGTK::ValidCodePage(int codePage) const {
+ return codePage == 0
+ || codePage == SC_CP_UTF8
+ || codePage == 932
+ || codePage == 936
+ || codePage == 950
+ || codePage == SC_CP_DBCS;
+}
+
+sptr_t ScintillaGTK::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
+ try {
+ switch (iMessage) {
+
+ case SCI_GRABFOCUS:
+ gtk_widget_grab_focus(PWidget(wMain));
+ break;
+
+ case SCI_GETDIRECTFUNCTION:
+ return reinterpret_cast<sptr_t>(DirectFunction);
+
+ case SCI_GETDIRECTPOINTER:
+ return reinterpret_cast<sptr_t>(this);
+
+#ifdef SCI_LEXER
+ case SCI_LOADLEXERLIBRARY:
+ LexerManager::GetInstance()->Load(reinterpret_cast<const char*>(lParam));
+ break;
+#endif
+ case SCI_TARGETASUTF8:
+ return TargetAsUTF8(reinterpret_cast<char*>(lParam));
+
+ case SCI_ENCODEDFROMUTF8:
+ return EncodedFromUTF8(reinterpret_cast<char*>(wParam),
+ reinterpret_cast<char*>(lParam));
+
+ case SCI_SETRECTANGULARSELECTIONMODIFIER:
+ rectangularSelectionModifier = wParam;
+ break;
+
+ case SCI_GETRECTANGULARSELECTIONMODIFIER:
+ return rectangularSelectionModifier;
+
+ default:
+ return ScintillaBase::WndProc(iMessage, wParam, lParam);
+ }
+ } catch (std::bad_alloc&) {
+ errorStatus = SC_STATUS_BADALLOC;
+ } catch (...) {
+ errorStatus = SC_STATUS_FAILURE;
+ }
+ return 0l;
+}
+
+sptr_t ScintillaGTK::DefWndProc(unsigned int, uptr_t, sptr_t) {
+ return 0;
+}
+
+void ScintillaGTK::SetTicking(bool on) {
+ if (timer.ticking != on) {
+ timer.ticking = on;
+ if (timer.ticking) {
+ timer.tickerID = reinterpret_cast<TickerID>(gtk_timeout_add(timer.tickSize, (GtkFunction)TimeOut, this));
+ } else {
+ gtk_timeout_remove(GPOINTER_TO_UINT(timer.tickerID));
+ }
+ }
+ timer.ticksToWait = caret.period;
+}
+
+bool ScintillaGTK::SetIdle(bool on) {
+ if (on) {
+ // Start idler, if it's not running.
+ if (!idler.state) {
+ idler.state = true;
+ idler.idlerID = reinterpret_cast<IdlerID>(
+ g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
+ reinterpret_cast<GSourceFunc>(IdleCallback), this, NULL));
+ }
+ } else {
+ // Stop idler, if it's running
+ if (idler.state) {
+ idler.state = false;
+ g_source_remove(GPOINTER_TO_UINT(idler.idlerID));
+ }
+ }
+ return true;
+}
+
+void ScintillaGTK::SetMouseCapture(bool on) {
+ if (mouseDownCaptures) {
+ if (on) {
+ gtk_grab_add(GTK_WIDGET(PWidget(wMain)));
+ } else {
+ gtk_grab_remove(GTK_WIDGET(PWidget(wMain)));
+ }
+ }
+ capturedMouse = on;
+}
+
+bool ScintillaGTK::HaveMouseCapture() {
+ return capturedMouse;
+}
+
+bool ScintillaGTK::PaintContains(PRectangle rc) {
+ bool contains = true;
+ if (paintState == painting) {
+ if (!rcPaint.Contains(rc)) {
+ contains = false;
+ } else if (rgnUpdate) {
+ GdkRectangle grc = {rc.left, rc.top,
+ rc.right - rc.left, rc.bottom - rc.top};
+ if (gdk_region_rect_in(rgnUpdate, &grc) != GDK_OVERLAP_RECTANGLE_IN) {
+ contains = false;
+ }
+ }
+ }
+ return contains;
+}
+
+// Redraw all of text area. This paint will not be abandoned.
+void ScintillaGTK::FullPaint() {
+ wText.InvalidateAll();
+}
+
+PRectangle ScintillaGTK::GetClientRectangle() {
+ PRectangle rc = wMain.GetClientPosition();
+ if (verticalScrollBarVisible)
+ rc.right -= scrollBarWidth;
+ if (horizontalScrollBarVisible && (wrapState == eWrapNone))
+ rc.bottom -= scrollBarHeight;
+ // Move to origin
+ rc.right -= rc.left;
+ rc.bottom -= rc.top;
+ rc.left = 0;
+ rc.top = 0;
+ return rc;
+}
+
+// Synchronously paint a rectangle of the window.
+void ScintillaGTK::SyncPaint(PRectangle rc) {
+ paintState = painting;
+ rcPaint = rc;
+ PRectangle rcClient = GetClientRectangle();
+ paintingAllText = rcPaint.Contains(rcClient);
+ if ((PWidget(wText))->window) {
+ Surface *sw = Surface::Allocate();
+ if (sw) {
+ sw->Init(PWidget(wText)->window, PWidget(wText));
+ Paint(sw, rc);
+ sw->Release();
+ delete sw;
+ }
+ }
+ if (paintState == paintAbandoned) {
+ // Painting area was insufficient to cover new styling or brace highlight positions
+ FullPaint();
+ }
+ paintState = notPainting;
+}
+
+void ScintillaGTK::ScrollText(int linesToMove) {
+ int diff = vs.lineHeight * -linesToMove;
+ //Platform::DebugPrintf("ScintillaGTK::ScrollText %d %d %0d,%0d %0d,%0d\n", linesToMove, diff,
+ // rc.left, rc.top, rc.right, rc.bottom);
+ GtkWidget *wi = PWidget(wText);
+
+ gdk_window_scroll(wi->window, 0, -diff);
+ gdk_window_process_updates(wi->window, FALSE);
+}
+
+void ScintillaGTK::SetVerticalScrollPos() {
+ DwellEnd(true);
+ gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmentv), topLine);
+}
+
+void ScintillaGTK::SetHorizontalScrollPos() {
+ DwellEnd(true);
+ gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmenth), xOffset / 2);
+}
+
+bool ScintillaGTK::ModifyScrollBars(int nMax, int nPage) {
+ bool modified = false;
+ int pageScroll = LinesToScroll();
+
+ if (GTK_ADJUSTMENT(adjustmentv)->upper != (nMax + 1) ||
+ GTK_ADJUSTMENT(adjustmentv)->page_size != nPage ||
+ GTK_ADJUSTMENT(adjustmentv)->page_increment != pageScroll) {
+ GTK_ADJUSTMENT(adjustmentv)->upper = nMax + 1;
+ GTK_ADJUSTMENT(adjustmentv)->page_size = nPage;
+ GTK_ADJUSTMENT(adjustmentv)->page_increment = pageScroll;
+ gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmentv));
+ modified = true;
+ }
+
+ PRectangle rcText = GetTextRectangle();
+ int horizEndPreferred = scrollWidth;
+ if (horizEndPreferred < 0)
+ horizEndPreferred = 0;
+ unsigned int pageWidth = rcText.Width();
+ unsigned int pageIncrement = pageWidth / 3;
+ unsigned int charWidth = vs.styles[STYLE_DEFAULT].aveCharWidth;
+ if (GTK_ADJUSTMENT(adjustmenth)->upper != horizEndPreferred ||
+ GTK_ADJUSTMENT(adjustmenth)->page_size != pageWidth ||
+ GTK_ADJUSTMENT(adjustmenth)->page_increment != pageIncrement ||
+ GTK_ADJUSTMENT(adjustmenth)->step_increment != charWidth) {
+ GTK_ADJUSTMENT(adjustmenth)->upper = horizEndPreferred;
+ GTK_ADJUSTMENT(adjustmenth)->step_increment = charWidth;
+ GTK_ADJUSTMENT(adjustmenth)->page_size = pageWidth;
+ GTK_ADJUSTMENT(adjustmenth)->page_increment = pageIncrement;
+ gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmenth));
+ modified = true;
+ }
+ return modified;
+}
+
+void ScintillaGTK::ReconfigureScrollBars() {
+ PRectangle rc = wMain.GetClientPosition();
+ Resize(rc.Width(), rc.Height());
+}
+
+void ScintillaGTK::NotifyChange() {
+ g_signal_emit(G_OBJECT(sci), scintilla_signals[COMMAND_SIGNAL], 0,
+ Platform::LongFromTwoShorts(GetCtrlID(), SCEN_CHANGE), PWidget(wMain));
+}
+
+void ScintillaGTK::NotifyFocus(bool focus) {
+ g_signal_emit(G_OBJECT(sci), scintilla_signals[COMMAND_SIGNAL], 0,
+ Platform::LongFromTwoShorts
+ (GetCtrlID(), focus ? SCEN_SETFOCUS : SCEN_KILLFOCUS), PWidget(wMain));
+}
+
+void ScintillaGTK::NotifyParent(SCNotification scn) {
+ scn.nmhdr.hwndFrom = PWidget(wMain);
+ scn.nmhdr.idFrom = GetCtrlID();
+ g_signal_emit(G_OBJECT(sci), scintilla_signals[NOTIFY_SIGNAL], 0,
+ GetCtrlID(), &scn);
+}
+
+void ScintillaGTK::NotifyKey(int key, int modifiers) {
+ SCNotification scn = {0};
+ scn.nmhdr.code = SCN_KEY;
+ scn.ch = key;
+ scn.modifiers = modifiers;
+
+ NotifyParent(scn);
+}
+
+void ScintillaGTK::NotifyURIDropped(const char *list) {
+ SCNotification scn = {0};
+ scn.nmhdr.code = SCN_URIDROPPED;
+ scn.text = list;
+
+ NotifyParent(scn);
+}
+
+const char *CharacterSetID(int characterSet);
+
+const char *ScintillaGTK::CharacterSetID() const {
+ return ::CharacterSetID(vs.styles[STYLE_DEFAULT].characterSet);
+}
+
+class CaseFolderUTF8 : public CaseFolderTable {
+public:
+ CaseFolderUTF8() {
+ StandardASCII();
+ }
+ virtual size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) {
+ if ((lenMixed == 1) && (sizeFolded > 0)) {
+ folded[0] = mapping[static_cast<unsigned char>(mixed[0])];
+ return 1;
+ } else {
+ gchar *mapped = g_utf8_casefold(mixed, lenMixed);
+ size_t lenMapped = strlen(mapped);
+ if (lenMapped < sizeFolded) {
+ memcpy(folded, mapped, lenMapped);
+ } else {
+ lenMapped = 0;
+ }
+ g_free(mapped);
+ return lenMapped;
+ }
+ }
+};
+
+CaseFolder *ScintillaGTK::CaseFolderForEncoding() {
+ if (pdoc->dbcsCodePage == SC_CP_UTF8) {
+ return new CaseFolderUTF8();
+ } else {
+ CaseFolderTable *pcf = new CaseFolderTable();
+ const char *charSetBuffer = CharacterSetID();
+ if ((pdoc->dbcsCodePage == 0) && charSetBuffer) {
+ pcf->StandardASCII();
+ // Only for single byte encodings
+ for (int i=0x80; i<0x100; i++) {
+ char sCharacter[2] = "A";
+ sCharacter[0] = i;
+ int convertedLength = 1;
+ const char *sUTF8 = ConvertText(&convertedLength, sCharacter, 1,
+ "UTF-8", charSetBuffer, false);
+ if (sUTF8) {
+ gchar *mapped = g_utf8_casefold(sUTF8, strlen(sUTF8));
+ if (mapped) {
+ int mappedLength = strlen(mapped);
+ const char *mappedBack = ConvertText(&mappedLength, mapped,
+ mappedLength, charSetBuffer, "UTF-8", false, true);
+ if (mappedBack && (strlen(mappedBack) == 1) && (mappedBack[0] != sCharacter[0])) {
+ pcf->SetTranslation(sCharacter[0], mappedBack[0]);
+ }
+ delete []mappedBack;
+ g_free(mapped);
+ }
+ }
+ delete []sUTF8;
+ }
+ }
+ return pcf;
+ }
+}
+
+std::string ScintillaGTK::CaseMapString(const std::string &s, int caseMapping) {
+ if (s.size() == 0)
+ return std::string();
+
+ if (caseMapping == cmSame)
+ return s;
+
+ const char *needsFree1 = 0; // Must be freed with delete []
+ const char *charSetBuffer = CharacterSetID();
+ const char *sUTF8 = s.c_str();
+ int rangeBytes = s.size();
+
+ int convertedLength = rangeBytes;
+ // Change text to UTF-8
+ if (!IsUnicodeMode()) {
+ // Need to convert
+ if (*charSetBuffer) {
+ sUTF8 = ConvertText(&convertedLength, const_cast<char *>(s.c_str()), rangeBytes,
+ "UTF-8", charSetBuffer, false);
+ needsFree1 = sUTF8;
+ }
+ }
+ gchar *mapped; // Must be freed with g_free
+ if (caseMapping == cmUpper) {
+ mapped = g_utf8_strup(sUTF8, convertedLength);
+ } else {
+ mapped = g_utf8_strdown(sUTF8, convertedLength);
+ }
+ int mappedLength = strlen(mapped);
+ char *mappedBack = mapped;
+
+ char *needsFree2 = 0; // Must be freed with delete []
+ if (!IsUnicodeMode()) {
+ if (*charSetBuffer) {
+ mappedBack = ConvertText(&mappedLength, mapped, mappedLength, charSetBuffer, "UTF-8", false);
+ needsFree2 = mappedBack;
+ }
+ }
+
+ std::string ret(mappedBack, mappedLength);
+ g_free(mapped);
+ delete []needsFree1;
+ delete []needsFree2;
+ return ret;
+}
+
+int ScintillaGTK::KeyDefault(int key, int modifiers) {
+ if (!(modifiers & SCI_CTRL) && !(modifiers & SCI_ALT)) {
+ if (key < 256) {
+ NotifyKey(key, modifiers);
+ return 0;
+ } else {
+ // Pass up to container in case it is an accelerator
+ NotifyKey(key, modifiers);
+ return 0;
+ }
+ } else {
+ // Pass up to container in case it is an accelerator
+ NotifyKey(key, modifiers);
+ return 0;
+ }
+ //Platform::DebugPrintf("SK-key: %d %x %x\n",key, modifiers);
+}
+
+void ScintillaGTK::CopyToClipboard(const SelectionText &selectedText) {
+#ifndef USE_GTK_CLIPBOARD
+ copyText.Copy(selectedText);
+ gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain)),
+ atomClipboard,
+ GDK_CURRENT_TIME);
+#else
+ SelectionText *clipText = new SelectionText();
+ clipText->Copy(selectedText);
+ StoreOnClipboard(clipText);
+#endif
+}
+
+void ScintillaGTK::Copy() {
+ if (!sel.Empty()) {
+#ifndef USE_GTK_CLIPBOARD
+ CopySelectionRange(&copyText);
+ gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain)),
+ atomClipboard,
+ GDK_CURRENT_TIME);
+#else
+ SelectionText *clipText = new SelectionText();
+ CopySelectionRange(clipText);
+ StoreOnClipboard(clipText);
+#endif
+#if PLAT_GTK_WIN32
+ if (sel.IsRectangular()) {
+ ::OpenClipboard(NULL);
+ ::SetClipboardData(cfColumnSelect, 0);
+ ::CloseClipboard();
+ }
+#endif
+ }
+}
+
+void ScintillaGTK::Paste() {
+ atomSought = atomUTF8;
+ gtk_selection_convert(GTK_WIDGET(PWidget(wMain)),
+ atomClipboard, atomSought, GDK_CURRENT_TIME);
+}
+
+void ScintillaGTK::CreateCallTipWindow(PRectangle rc) {
+ if (!ct.wCallTip.Created()) {
+ ct.wCallTip = gtk_window_new(GTK_WINDOW_POPUP);
+ 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);
+ g_signal_connect(G_OBJECT(widcdrw), "expose_event",
+ G_CALLBACK(ScintillaGTK::ExposeCT), &ct);
+ g_signal_connect(G_OBJECT(widcdrw), "button_press_event",
+ G_CALLBACK(ScintillaGTK::PressCT), static_cast<void *>(this));
+ gtk_widget_set_events(widcdrw,
+ GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK);
+ }
+ gtk_drawing_area_size(GTK_DRAWING_AREA(PWidget(ct.wDraw)),
+ rc.Width(), rc.Height());
+ ct.wDraw.Show();
+ if (PWidget(ct.wCallTip)->window) {
+ gdk_window_resize(PWidget(ct.wCallTip)->window, rc.Width(), rc.Height());
+ }
+}
+
+void ScintillaGTK::AddToPopUp(const char *label, int cmd, bool enabled) {
+ char fulllabel[200];
+ strcpy(fulllabel, "/");
+ strcat(fulllabel, label);
+ GtkItemFactoryCallback menuSig = GtkItemFactoryCallback(PopUpCB);
+ GtkItemFactoryEntry itemEntry = {
+ fulllabel, NULL,
+ menuSig,
+ cmd,
+ const_cast<gchar *>(label[0] ? "<Item>" : "<Separator>"),
+ NULL
+ };
+ gtk_item_factory_create_item(GTK_ITEM_FACTORY(popup.GetID()),
+ &itemEntry, this, 1);
+ if (cmd) {
+ GtkWidget *item = gtk_item_factory_get_widget_by_action(
+ reinterpret_cast<GtkItemFactory *>(popup.GetID()), cmd);
+ if (item)
+ gtk_widget_set_sensitive(item, enabled);
+ }
+}
+
+bool ScintillaGTK::OwnPrimarySelection() {
+ return ((gdk_selection_owner_get(GDK_SELECTION_PRIMARY)
+ == GTK_WIDGET(PWidget(wMain))->window) &&
+ (GTK_WIDGET(PWidget(wMain))->window != NULL));
+}
+
+void ScintillaGTK::ClaimSelection() {
+ // X Windows has a 'primary selection' as well as the clipboard.
+ // Whenever the user selects some text, we become the primary selection
+ if (!sel.Empty() && GTK_WIDGET_REALIZED(GTK_WIDGET(PWidget(wMain)))) {
+ primarySelection = true;
+ gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain)),
+ GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
+ primary.Free();
+ } else if (OwnPrimarySelection()) {
+ primarySelection = true;
+ if (primary.s == NULL)
+ gtk_selection_owner_set(NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
+ } else {
+ primarySelection = false;
+ primary.Free();
+ }
+}
+
+// Detect rectangular text, convert line ends to current mode, convert from or to UTF-8
+void ScintillaGTK::GetGtkSelectionText(GtkSelectionData *selectionData, SelectionText &selText) {
+ char *data = reinterpret_cast<char *>(selectionData->data);
+ int len = selectionData->length;
+ GdkAtom selectionTypeData = selectionData->type;
+
+ // Return empty string if selection is not a string
+ if ((selectionTypeData != GDK_TARGET_STRING) && (selectionTypeData != atomUTF8)) {
+ char *empty = new char[1];
+ empty[0] = '\0';
+ selText.Set(empty, 0, SC_CP_UTF8, 0, false, false);
+ return;
+ }
+
+ // Check for "\n\0" ending to string indicating that selection is rectangular
+ bool isRectangular;
+#if PLAT_GTK_WIN32
+ isRectangular = ::IsClipboardFormatAvailable(cfColumnSelect) != 0;
+#else
+ isRectangular = ((len > 2) && (data[len - 1] == 0 && data[len - 2] == '\n'));
+ if (isRectangular)
+ len--; // Forget the extra '\0'
+#endif
+
+ char *dest;
+ if (selectionTypeData == GDK_TARGET_STRING) {
+ dest = Document::TransformLineEnds(&len, data, len, pdoc->eolMode);
+ if (IsUnicodeMode()) {
+ // Unknown encoding so assume in Latin1
+ char *destPrevious = dest;
+ dest = UTF8FromLatin1(dest, len);
+ selText.Set(dest, len, SC_CP_UTF8, 0, selText.rectangular, false);
+ delete []destPrevious;
+ } else {
+ // Assume buffer is in same encoding as selection
+ selText.Set(dest, len, pdoc->dbcsCodePage,
+ vs.styles[STYLE_DEFAULT].characterSet, isRectangular, false);
+ }
+ } else { // UTF-8
+ dest = Document::TransformLineEnds(&len, data, len, pdoc->eolMode);
+ selText.Set(dest, len, SC_CP_UTF8, 0, isRectangular, false);
+ const char *charSetBuffer = CharacterSetID();
+ if (!IsUnicodeMode() && *charSetBuffer) {
+ // Convert to locale
+ dest = ConvertText(&len, selText.s, selText.len, charSetBuffer, "UTF-8", true);
+ selText.Set(dest, len, pdoc->dbcsCodePage,
+ vs.styles[STYLE_DEFAULT].characterSet, selText.rectangular, false);
+ }
+ }
+}
+
+void ScintillaGTK::ReceivedSelection(GtkSelectionData *selection_data) {
+ try {
+ if ((selection_data->selection == atomClipboard) ||
+ (selection_data->selection == GDK_SELECTION_PRIMARY)) {
+ if ((atomSought == atomUTF8) && (selection_data->length <= 0)) {
+ atomSought = atomString;
+ gtk_selection_convert(GTK_WIDGET(PWidget(wMain)),
+ selection_data->selection, atomSought, GDK_CURRENT_TIME);
+ } else if ((selection_data->length > 0) &&
+ ((selection_data->type == GDK_TARGET_STRING) || (selection_data->type == atomUTF8))) {
+ SelectionText selText;
+ GetGtkSelectionText(selection_data, selText);
+
+ UndoGroup ug(pdoc);
+ if (selection_data->selection != GDK_SELECTION_PRIMARY) {
+ ClearSelection();
+ }
+ SelectionPosition selStart = sel.IsRectangular() ?
+ sel.Rectangular().Start() :
+ sel.Range(sel.Main()).Start();
+
+ if (selText.rectangular) {
+ PasteRectangular(selStart, selText.s, selText.len);
+ } else {
+ InsertPaste(selStart, selText.s, selText.len);
+ }
+ EnsureCaretVisible();
+ }
+ }
+// else fprintf(stderr, "Target non string %d %d\n", (int)(selection_data->type),
+// (int)(atomUTF8));
+ Redraw();
+ } catch (...) {
+ errorStatus = SC_STATUS_FAILURE;
+ }
+}
+
+void ScintillaGTK::ReceivedDrop(GtkSelectionData *selection_data) {
+ dragWasDropped = true;
+ if (selection_data->type == atomUriList || selection_data->type == atomDROPFILES_DND) {
+ char *ptr = new char[selection_data->length + 1];
+ ptr[selection_data->length] = '\0';
+ memcpy(ptr, selection_data->data, selection_data->length);
+ NotifyURIDropped(ptr);
+ delete []ptr;
+ } else if ((selection_data->type == GDK_TARGET_STRING) || (selection_data->type == atomUTF8)) {
+ if (selection_data->length > 0) {
+ SelectionText selText;
+ GetGtkSelectionText(selection_data, selText);
+ DropAt(posDrop, selText.s, false, selText.rectangular);
+ }
+ } else if (selection_data->length > 0) {
+ //~ fprintf(stderr, "ReceivedDrop other %p\n", static_cast<void *>(selection_data->type));
+ }
+ Redraw();
+}
+
+
+
+void ScintillaGTK::GetSelection(GtkSelectionData *selection_data, guint info, SelectionText *text) {
+#if PLAT_GTK_WIN32
+ // GDK on Win32 expands any \n into \r\n, so make a copy of
+ // the clip text now with newlines converted to \n. Use { } to hide symbols
+ // from code below
+ SelectionText *newline_normalized = NULL;
+ {
+ int tmpstr_len;
+ char *tmpstr = Document::TransformLineEnds(&tmpstr_len, text->s, text->len, SC_EOL_LF);
+ newline_normalized = new SelectionText();
+ newline_normalized->Set(tmpstr, tmpstr_len, SC_CP_UTF8, 0, text->rectangular, false);
+ text = newline_normalized;
+ }
+#endif
+
+ // Convert text to utf8 if it isn't already
+ SelectionText *converted = 0;
+ if ((text->codePage != SC_CP_UTF8) && (info == TARGET_UTF8_STRING)) {
+ const char *charSet = ::CharacterSetID(text->characterSet);
+ if (*charSet) {
+ int new_len;
+ char* tmputf = ConvertText(&new_len, text->s, text->len, "UTF-8", charSet, false);
+ converted = new SelectionText();
+ converted->Set(tmputf, new_len, SC_CP_UTF8, 0, text->rectangular, false);
+ text = converted;
+ }
+ }
+
+ // Here is a somewhat evil kludge.
+ // As I can not work out how to store data on the clipboard in multiple formats
+ // and need some way to mark the clipping as being stream or rectangular,
+ // the terminating \0 is included in the length for rectangular clippings.
+ // All other tested aplications behave benignly by ignoring the \0.
+ // The #if is here because on Windows cfColumnSelect clip entry is used
+ // instead as standard indicator of rectangularness (so no need to kludge)
+ const char *textData = text->s ? text->s : "";
+ int len = strlen(textData);
+#if PLAT_GTK_WIN32 == 0
+ if (text->rectangular)
+ len++;
+#endif
+
+ if (info == TARGET_UTF8_STRING) {
+ gtk_selection_data_set_text(selection_data, textData, len);
+ } else {
+ gtk_selection_data_set(selection_data,
+ static_cast<GdkAtom>(GDK_SELECTION_TYPE_STRING),
+ 8, reinterpret_cast<const unsigned char *>(textData), len);
+ }
+ delete converted;
+
+#if PLAT_GTK_WIN32
+ delete newline_normalized;
+#endif
+}
+
+#ifdef USE_GTK_CLIPBOARD
+void ScintillaGTK::StoreOnClipboard(SelectionText *clipText) {
+ GtkClipboard *clipBoard =
+ gtk_widget_get_clipboard(GTK_WIDGET(PWidget(wMain)), atomClipboard);
+ if (clipBoard == NULL) // Occurs if widget isn't in a toplevel
+ return;
+
+ if (gtk_clipboard_set_with_data(clipBoard, clipboardCopyTargets, nClipboardCopyTargets,
+ ClipboardGetSelection, ClipboardClearSelection, clipText)) {
+ gtk_clipboard_set_can_store(clipBoard, clipboardCopyTargets, nClipboardCopyTargets);
+ }
+}
+
+void ScintillaGTK::ClipboardGetSelection(GtkClipboard *, GtkSelectionData *selection_data, guint info, void *data) {
+ GetSelection(selection_data, info, static_cast<SelectionText*>(data));
+}
+
+void ScintillaGTK::ClipboardClearSelection(GtkClipboard *, void *data) {
+ SelectionText *obj = static_cast<SelectionText*>(data);
+ delete obj;
+}
+#endif
+
+void ScintillaGTK::UnclaimSelection(GdkEventSelection *selection_event) {
+ try {
+ //Platform::DebugPrintf("UnclaimSelection\n");
+ if (selection_event->selection == GDK_SELECTION_PRIMARY) {
+ //Platform::DebugPrintf("UnclaimPrimarySelection\n");
+ if (!OwnPrimarySelection()) {
+ primary.Free();
+ primarySelection = false;
+ FullPaint();
+ }
+ }
+ } catch (...) {
+ errorStatus = SC_STATUS_FAILURE;
+ }
+}
+
+void ScintillaGTK::Resize(int width, int height) {
+ //Platform::DebugPrintf("Resize %d %d\n", width, height);
+ //printf("Resize %d %d\n", width, height);
+
+ // Not always needed, but some themes can have different sizes of scrollbars
+ scrollBarWidth = GTK_WIDGET(PWidget(scrollbarv))->requisition.width;
+ scrollBarHeight = GTK_WIDGET(PWidget(scrollbarh))->requisition.height;
+
+ // These allocations should never produce negative sizes as they would wrap around to huge
+ // unsigned numbers inside GTK+ causing warnings.
+ bool showSBHorizontal = horizontalScrollBarVisible && (wrapState == eWrapNone);
+ int horizontalScrollBarHeight = scrollBarHeight;
+ if (!showSBHorizontal)
+ horizontalScrollBarHeight = 0;
+
+ GtkAllocation alloc;
+ if (showSBHorizontal) {
+ gtk_widget_show(GTK_WIDGET(PWidget(scrollbarh)));
+ alloc.x = 0;
+ alloc.y = height - scrollBarHeight;
+ alloc.width = Platform::Maximum(1, width - scrollBarWidth) + 1;
+ alloc.height = horizontalScrollBarHeight;
+ gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarh)), &alloc);
+ } else {
+ gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarh)));
+ }
+
+ if (verticalScrollBarVisible) {
+ gtk_widget_show(GTK_WIDGET(PWidget(scrollbarv)));
+ alloc.x = width - scrollBarWidth;
+ alloc.y = 0;
+ alloc.width = scrollBarWidth;
+ alloc.height = Platform::Maximum(1, height - scrollBarHeight) + 1;
+ if (!showSBHorizontal)
+ alloc.height += scrollBarWidth-1;
+ gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarv)), &alloc);
+ } else {
+ gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarv)));
+ }
+ if (GTK_WIDGET_MAPPED(PWidget(wMain))) {
+ ChangeSize();
+ }
+
+ alloc.x = 0;
+ alloc.y = 0;
+ alloc.width = Platform::Maximum(1, width - scrollBarWidth);
+ alloc.height = Platform::Maximum(1, height - scrollBarHeight);
+ if (!showSBHorizontal)
+ alloc.height += scrollBarHeight;
+ if (!verticalScrollBarVisible)
+ alloc.width += scrollBarWidth;
+ gtk_widget_size_allocate(GTK_WIDGET(PWidget(wText)), &alloc);
+}
+
+static void SetAdjustmentValue(GtkObject *object, int value) {
+ GtkAdjustment *adjustment = GTK_ADJUSTMENT(object);
+ int maxValue = static_cast<int>(
+ adjustment->upper - adjustment->page_size);
+ if (value > maxValue)
+ value = maxValue;
+ if (value < 0)
+ value = 0;
+ gtk_adjustment_set_value(adjustment, value);
+}
+
+static int modifierTranslated(int sciModifier) {
+ switch (sciModifier) {
+ case SCMOD_SHIFT:
+ return GDK_SHIFT_MASK;
+ case SCMOD_CTRL:
+ return GDK_CONTROL_MASK;
+ case SCMOD_ALT:
+ return GDK_MOD1_MASK;
+ case SCMOD_SUPER:
+ return GDK_MOD4_MASK;
+ default:
+ return 0;
+ }
+}
+
+gint ScintillaGTK::PressThis(GdkEventButton *event) {
+ try {
+ //Platform::DebugPrintf("Press %x time=%d state = %x button = %x\n",this,event->time, event->state, event->button);
+ // Do not use GTK+ double click events as Scintilla has its own double click detection
+ if (event->type != GDK_BUTTON_PRESS)
+ return FALSE;
+
+ evbtn = *event;
+ Point pt;
+ pt.x = int(event->x);
+ pt.y = int(event->y);
+ PRectangle rcClient = GetClientRectangle();
+ //Platform::DebugPrintf("Press %0d,%0d in %0d,%0d %0d,%0d\n",
+ // pt.x, pt.y, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
+ if ((pt.x > rcClient.right) || (pt.y > rcClient.bottom)) {
+ Platform::DebugPrintf("Bad location\n");
+ return FALSE;
+ }
+
+ bool ctrl = (event->state & GDK_CONTROL_MASK) != 0;
+
+ gtk_widget_grab_focus(PWidget(wMain));
+ if (event->button == 1) {
+ // On X, instead of sending literal modifiers use the user specified
+ // modifier, defaulting to control instead of alt.
+ // This is because most X window managers grab alt + click for moving
+ ButtonDown(pt, event->time,
+ (event->state & GDK_SHIFT_MASK) != 0,
+ (event->state & GDK_CONTROL_MASK) != 0,
+ (event->state & modifierTranslated(rectangularSelectionModifier)) != 0);
+ } else if (event->button == 2) {
+ // Grab the primary selection if it exists
+ SelectionPosition pos = SPositionFromLocation(pt, false, false, UserVirtualSpace());
+ if (OwnPrimarySelection() && primary.s == NULL)
+ CopySelectionRange(&primary);
+
+ sel.Clear();
+ SetSelection(pos, pos);
+ atomSought = atomUTF8;
+ gtk_selection_convert(GTK_WIDGET(PWidget(wMain)), GDK_SELECTION_PRIMARY,
+ atomSought, event->time);
+ } else if (event->button == 3) {
+ if (displayPopupMenu) {
+ // PopUp menu
+ // Convert to screen
+ int ox = 0;
+ int oy = 0;
+ gdk_window_get_origin(PWidget(wMain)->window, &ox, &oy);
+ ContextMenu(Point(pt.x + ox, pt.y + oy));
+ } else {
+ return FALSE;
+ }
+ } else if (event->button == 4) {
+ // Wheel scrolling up (only GTK 1.x does it this way)
+ if (ctrl)
+ SetAdjustmentValue(adjustmenth, (xOffset / 2) - 6);
+ else
+ SetAdjustmentValue(adjustmentv, topLine - 3);
+ } else if (event->button == 5) {
+ // Wheel scrolling down (only GTK 1.x does it this way)
+ if (ctrl)
+ SetAdjustmentValue(adjustmenth, (xOffset / 2) + 6);
+ else
+ SetAdjustmentValue(adjustmentv, topLine + 3);
+ }
+ } catch (...) {
+ errorStatus = SC_STATUS_FAILURE;
+ }
+ return TRUE;
+}
+
+gint ScintillaGTK::Press(GtkWidget *widget, GdkEventButton *event) {
+ if (event->window != widget->window)
+ return FALSE;
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ return sciThis->PressThis(event);
+}
+
+gint ScintillaGTK::MouseRelease(GtkWidget *widget, GdkEventButton *event) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ try {
+ //Platform::DebugPrintf("Release %x %d %d\n",sciThis,event->time,event->state);
+ if (!sciThis->HaveMouseCapture())
+ return FALSE;
+ if (event->button == 1) {
+ Point pt;
+ pt.x = int(event->x);
+ pt.y = int(event->y);
+ //Platform::DebugPrintf("Up %x %x %d %d %d\n",
+ // sciThis,event->window,event->time, pt.x, pt.y);
+ if (event->window != PWidget(sciThis->wMain)->window)
+ // If mouse released on scroll bar then the position is relative to the
+ // scrollbar, not the drawing window so just repeat the most recent point.
+ pt = sciThis->ptMouseLast;
+ sciThis->ButtonUp(pt, event->time, (event->state & 4) != 0);
+ }
+ } catch (...) {
+ sciThis->errorStatus = SC_STATUS_FAILURE;
+ }
+ return FALSE;
+}
+
+// win32gtk and GTK >= 2 use SCROLL_* events instead of passing the
+// button4/5/6/7 events to the GTK app
+gint ScintillaGTK::ScrollEvent(GtkWidget *widget,
+ GdkEventScroll *event) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ try {
+
+ if (widget == NULL || event == NULL)
+ return FALSE;
+
+ // 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) where the X11 server already has
+ // and adaptive scrolling algorithm that fights with this one
+ int cLineScroll;
+#if defined(__MWERKS__) || defined(__APPLE_CPP__) || defined(__APPLE_CC__)
+ cLineScroll = sciThis->linesPerScroll;
+ if (cLineScroll == 0)
+ cLineScroll = 4;
+ sciThis->wheelMouseIntensity = cLineScroll;
+#else
+ int timeDelta = 1000000;
+ GTimeVal curTime;
+ g_get_current_time(&curTime);
+ if (curTime.tv_sec == sciThis->lastWheelMouseTime.tv_sec)
+ timeDelta = curTime.tv_usec - sciThis->lastWheelMouseTime.tv_usec;
+ else if (curTime.tv_sec == sciThis->lastWheelMouseTime.tv_sec + 1)
+ timeDelta = 1000000 + (curTime.tv_usec - sciThis->lastWheelMouseTime.tv_usec);
+ if ((event->direction == sciThis->lastWheelMouseDirection) && (timeDelta < 250000)) {
+ if (sciThis->wheelMouseIntensity < 12)
+ sciThis->wheelMouseIntensity++;
+ cLineScroll = sciThis->wheelMouseIntensity;
+ } else {
+ cLineScroll = sciThis->linesPerScroll;
+ if (cLineScroll == 0)
+ cLineScroll = 4;
+ sciThis->wheelMouseIntensity = cLineScroll;
+ }
+#endif
+ if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_LEFT) {
+ cLineScroll *= -1;
+ }
+ g_get_current_time(&sciThis->lastWheelMouseTime);
+ sciThis->lastWheelMouseDirection = event->direction;
+
+ // Note: Unpatched versions of win32gtk don't set the 'state' value so
+ // only regular scrolling is supported there. Also, unpatched win32gtk
+ // 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;
+ }
+
+ // Horizontal scrolling
+ if (event->direction == GDK_SCROLL_LEFT || event->direction == GDK_SCROLL_RIGHT) {
+ sciThis->HorizontalScrollTo(sciThis->xOffset + cLineScroll);
+
+ // Text font size zoom
+ } else if (event->state & GDK_CONTROL_MASK) {
+ if (cLineScroll < 0) {
+ sciThis->KeyCommand(SCI_ZOOMIN);
+ } else {
+ sciThis->KeyCommand(SCI_ZOOMOUT);
+ }
+
+ // Regular scrolling
+ } else {
+ sciThis->ScrollTo(sciThis->topLine + cLineScroll);
+ }
+ return TRUE;
+ } catch (...) {
+ sciThis->errorStatus = SC_STATUS_FAILURE;
+ }
+ return FALSE;
+}
+
+gint ScintillaGTK::Motion(GtkWidget *widget, GdkEventMotion *event) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ try {
+ //Platform::DebugPrintf("Motion %x %d\n",sciThis,event->time);
+ if (event->window != widget->window)
+ return FALSE;
+ int x = 0;
+ int y = 0;
+ GdkModifierType state;
+ if (event->is_hint) {
+ gdk_window_get_pointer(event->window, &x, &y, &state);
+ } else {
+ x = static_cast<int>(event->x);
+ y = static_cast<int>(event->y);
+ state = static_cast<GdkModifierType>(event->state);
+ }
+ //Platform::DebugPrintf("Move %x %x %d %c %d %d\n",
+ // sciThis,event->window,event->time,event->is_hint? 'h' :'.', x, y);
+ Point pt(x, y);
+ sciThis->ButtonMove(pt);
+ } catch (...) {
+ sciThis->errorStatus = SC_STATUS_FAILURE;
+ }
+ return FALSE;
+}
+
+// Map the keypad keys to their equivalent functions
+static int KeyTranslate(int keyIn) {
+ switch (keyIn) {
+ case GDK_ISO_Left_Tab:
+ return SCK_TAB;
+ case GDK_KP_Down:
+ return SCK_DOWN;
+ case GDK_KP_Up:
+ return SCK_UP;
+ case GDK_KP_Left:
+ return SCK_LEFT;
+ case GDK_KP_Right:
+ return SCK_RIGHT;
+ case GDK_KP_Home:
+ return SCK_HOME;
+ case GDK_KP_End:
+ return SCK_END;
+ case GDK_KP_Page_Up:
+ return SCK_PRIOR;
+ case GDK_KP_Page_Down:
+ return SCK_NEXT;
+ case GDK_KP_Delete:
+ return SCK_DELETE;
+ case GDK_KP_Insert:
+ return SCK_INSERT;
+ case GDK_KP_Enter:
+ return SCK_RETURN;
+
+ case GDK_Down:
+ return SCK_DOWN;
+ case GDK_Up:
+ return SCK_UP;
+ case GDK_Left:
+ return SCK_LEFT;
+ case GDK_Right:
+ return SCK_RIGHT;
+ case GDK_Home:
+ return SCK_HOME;
+ case GDK_End:
+ return SCK_END;
+ case GDK_Page_Up:
+ return SCK_PRIOR;
+ case GDK_Page_Down:
+ return SCK_NEXT;
+ case GDK_Delete:
+ return SCK_DELETE;
+ case GDK_Insert:
+ return SCK_INSERT;
+ case GDK_Escape:
+ return SCK_ESCAPE;
+ case GDK_BackSpace:
+ return SCK_BACK;
+ case GDK_Tab:
+ return SCK_TAB;
+ case GDK_Return:
+ return SCK_RETURN;
+ case GDK_KP_Add:
+ return SCK_ADD;
+ case GDK_KP_Subtract:
+ return SCK_SUBTRACT;
+ case GDK_KP_Divide:
+ return SCK_DIVIDE;
+ case GDK_Super_L:
+ return SCK_WIN;
+ case GDK_Super_R:
+ return SCK_RWIN;
+ case GDK_Menu:
+ return SCK_MENU;
+ default:
+ return keyIn;
+ }
+}
+
+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)) {
+ return 1;
+ }
+ if (!event->keyval) {
+ return true;
+ }
+
+ bool shift = (event->state & GDK_SHIFT_MASK) != 0;
+ bool ctrl = (event->state & GDK_CONTROL_MASK) != 0;
+ bool alt = (event->state & GDK_MOD1_MASK) != 0;
+ guint key = event->keyval;
+ if (ctrl && (key < 128))
+ key = toupper(key);
+ else if (!ctrl && (key >= GDK_KP_Multiply && key <= GDK_KP_9))
+ key &= 0x7F;
+ // Hack for keys over 256 and below command keys but makes Hungarian work.
+ // This will have to change for Unicode
+ else if (key >= 0xFE00)
+ key = KeyTranslate(key);
+
+ bool consumed = false;
+ bool added = KeyDown(key, shift, ctrl, alt, &consumed) != 0;
+ if (!consumed)
+ consumed = added;
+ //fprintf(stderr, "SK-key: %d %x %x\n",event->keyval, event->state, consumed);
+ if (event->keyval == 0xffffff && event->length > 0) {
+ ClearSelection();
+ if (pdoc->InsertCString(CurrentPosition(), event->string)) {
+ MovePositionTo(CurrentPosition() + event->length);
+ }
+ }
+ return consumed;
+ } catch (...) {
+ errorStatus = SC_STATUS_FAILURE;
+ }
+ return FALSE;
+}
+
+gboolean ScintillaGTK::KeyPress(GtkWidget *widget, GdkEventKey *event) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ return sciThis->KeyThis(event);
+}
+
+gboolean ScintillaGTK::KeyRelease(GtkWidget *, GdkEventKey * /*event*/) {
+ //Platform::DebugPrintf("SC-keyrel: %d %x %3s\n",event->keyval, event->state, event->string);
+ return FALSE;
+}
+
+gboolean ScintillaGTK::ExposePreeditThis(GtkWidget *widget, GdkEventExpose *ose) {
+ try {
+ gchar *str;
+ gint cursor_pos;
+ PangoAttrList *attrs;
+
+ gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos);
+ PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str);
+ pango_layout_set_attributes(layout, attrs);
+
+ GdkGC *gc = gdk_gc_new(widget->window);
+ GdkColor color[2] = { {0, 0x0000, 0x0000, 0x0000},
+ {0, 0xffff, 0xffff, 0xffff}
+ };
+ gdk_color_alloc(gdk_colormap_get_system(), color);
+ gdk_color_alloc(gdk_colormap_get_system(), color + 1);
+
+ gdk_gc_set_foreground(gc, color + 1);
+ gdk_draw_rectangle(widget->window, gc, TRUE, ose->area.x, ose->area.y,
+ ose->area.width, ose->area.height);
+
+ gdk_gc_set_foreground(gc, color);
+ gdk_gc_set_background(gc, color + 1);
+ gdk_draw_layout(widget->window, gc, 0, 0, layout);
+
+ gdk_gc_unref(gc);
+ g_free(str);
+ pango_attr_list_unref(attrs);
+ g_object_unref(layout);
+ } catch (...) {
+ errorStatus = SC_STATUS_FAILURE;
+ }
+ return TRUE;
+}
+
+gboolean ScintillaGTK::ExposePreedit(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis) {
+ return sciThis->ExposePreeditThis(widget, ose);
+}
+
+void ScintillaGTK::CommitThis(char *utfVal) {
+ try {
+ //~ fprintf(stderr, "Commit '%s'\n", utfVal);
+ if (IsUnicodeMode()) {
+ AddCharUTF(utfVal, strlen(utfVal));
+ } else {
+ const char *source = CharacterSetID();
+ if (*source) {
+ Converter conv(source, "UTF-8", true);
+ if (conv) {
+ char localeVal[4] = "\0\0\0";
+ char *pin = utfVal;
+ size_t inLeft = strlen(utfVal);
+ char *pout = localeVal;
+ size_t outLeft = sizeof(localeVal);
+ size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
+ if (conversions != ((size_t)(-1))) {
+ *pout = '\0';
+ for (int i = 0; localeVal[i]; i++) {
+ AddChar(localeVal[i]);
+ }
+ } else {
+ fprintf(stderr, "Conversion failed '%s'\n", utfVal);
+ }
+ }
+ }
+ }
+ } catch (...) {
+ errorStatus = SC_STATUS_FAILURE;
+ }
+}
+
+void ScintillaGTK::Commit(GtkIMContext *, char *str, ScintillaGTK *sciThis) {
+ sciThis->CommitThis(str);
+}
+
+void ScintillaGTK::PreeditChangedThis() {
+ try {
+ gchar *str;
+ PangoAttrList *attrs;
+ gint cursor_pos;
+ gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos);
+ if (strlen(str) > 0) {
+ PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str);
+ pango_layout_set_attributes(layout, attrs);
+
+ gint w, h;
+ pango_layout_get_pixel_size(layout, &w, &h);
+ g_object_unref(layout);
+
+ gint x, y;
+ gdk_window_get_origin((PWidget(wText))->window, &x, &y);
+
+ Point pt = PointMainCaret();
+ if (pt.x < 0)
+ pt.x = 0;
+ if (pt.y < 0)
+ pt.y = 0;
+
+ gtk_window_move(GTK_WINDOW(PWidget(wPreedit)), x + pt.x, y + pt.y);
+ gtk_window_resize(GTK_WINDOW(PWidget(wPreedit)), w, h);
+ gtk_widget_show(PWidget(wPreedit));
+ gtk_widget_queue_draw_area(PWidget(wPreeditDraw), 0, 0, w, h);
+ } else {
+ gtk_widget_hide(PWidget(wPreedit));
+ }
+ g_free(str);
+ pango_attr_list_unref(attrs);
+ } catch (...) {
+ errorStatus = SC_STATUS_FAILURE;
+ }
+}
+
+void ScintillaGTK::PreeditChanged(GtkIMContext *, ScintillaGTK *sciThis) {
+ sciThis->PreeditChangedThis();
+}
+
+gint ScintillaGTK::StyleSetText(GtkWidget *widget, GtkStyle *, void*) {
+ if (widget->window != NULL)
+ gdk_window_set_back_pixmap(widget->window, NULL, FALSE);
+ return FALSE;
+}
+
+gint ScintillaGTK::RealizeText(GtkWidget *widget, void*) {
+ if (widget->window != NULL)
+ gdk_window_set_back_pixmap(widget->window, NULL, FALSE);
+ return FALSE;
+}
+
+void ScintillaGTK::Destroy(GObject *object) {
+ try {
+ ScintillaObject *scio = reinterpret_cast<ScintillaObject *>(object);
+ // This avoids a double destruction
+ if (!scio->pscin)
+ return;
+ ScintillaGTK *sciThis = reinterpret_cast<ScintillaGTK *>(scio->pscin);
+ //Platform::DebugPrintf("Destroying %x %x\n", sciThis, object);
+ sciThis->Finalise();
+
+ delete sciThis;
+ scio->pscin = 0;
+ } catch (...) {
+ // Its dead so nowhere to save the status
+ }
+}
+
+static void DrawChild(GtkWidget *widget, GdkRectangle *area) {
+ GdkRectangle areaIntersect;
+ if (widget &&
+ GTK_WIDGET_DRAWABLE(widget) &&
+ gtk_widget_intersect(widget, area, &areaIntersect)) {
+ gtk_widget_draw(widget, &areaIntersect);
+ }
+}
+
+void ScintillaGTK::Draw(GtkWidget *widget, GdkRectangle *area) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ try {
+ //Platform::DebugPrintf("Draw %p %0d,%0d %0d,%0d\n", widget, area->x, area->y, area->width, area->height);
+ PRectangle rcPaint(area->x, area->y, area->x + area->width, area->y + area->height);
+ sciThis->SyncPaint(rcPaint);
+ if (GTK_WIDGET_DRAWABLE(PWidget(sciThis->wMain))) {
+ DrawChild(PWidget(sciThis->scrollbarh), area);
+ DrawChild(PWidget(sciThis->scrollbarv), area);
+ }
+
+ Point pt = sciThis->PointMainCaret();
+ pt.y += sciThis->vs.lineHeight - 2;
+ if (pt.x < 0) pt.x = 0;
+ if (pt.y < 0) pt.y = 0;
+ CursorMoved(widget, pt.x, pt.y, sciThis);
+ } catch (...) {
+ sciThis->errorStatus = SC_STATUS_FAILURE;
+ }
+}
+
+gint ScintillaGTK::ExposeTextThis(GtkWidget * /*widget*/, GdkEventExpose *ose) {
+ try {
+ paintState = painting;
+
+ rcPaint.left = ose->area.x;
+ rcPaint.top = ose->area.y;
+ rcPaint.right = ose->area.x + ose->area.width;
+ rcPaint.bottom = ose->area.y + ose->area.height;
+
+ PLATFORM_ASSERT(rgnUpdate == NULL);
+ rgnUpdate = gdk_region_copy(ose->region);
+ PRectangle rcClient = GetClientRectangle();
+ paintingAllText = rcPaint.Contains(rcClient);
+ Surface *surfaceWindow = Surface::Allocate();
+ if (surfaceWindow) {
+ surfaceWindow->Init(PWidget(wText)->window, PWidget(wText));
+ Paint(surfaceWindow, rcPaint);
+ surfaceWindow->Release();
+ delete surfaceWindow;
+ }
+ if (paintState == paintAbandoned) {
+ // Painting area was insufficient to cover new styling or brace highlight positions
+ FullPaint();
+ }
+ paintState = notPainting;
+
+ if (rgnUpdate) {
+ gdk_region_destroy(rgnUpdate);
+ }
+ rgnUpdate = 0;
+ } catch (...) {
+ errorStatus = SC_STATUS_FAILURE;
+ }
+
+ return FALSE;
+}
+
+gint ScintillaGTK::ExposeText(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis) {
+ return sciThis->ExposeTextThis(widget, ose);
+}
+
+gint ScintillaGTK::ExposeMain(GtkWidget *widget, GdkEventExpose *ose) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ //Platform::DebugPrintf("Expose Main %0d,%0d %0d,%0d\n",
+ //ose->area.x, ose->area.y, ose->area.width, ose->area.height);
+ return sciThis->Expose(widget, ose);
+}
+
+gint ScintillaGTK::Expose(GtkWidget *, GdkEventExpose *ose) {
+ try {
+ //fprintf(stderr, "Expose %0d,%0d %0d,%0d\n",
+ //ose->area.x, ose->area.y, ose->area.width, ose->area.height);
+
+ // The text is painted in ExposeText
+ gtk_container_propagate_expose(
+ GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarh), ose);
+ gtk_container_propagate_expose(
+ GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarv), ose);
+
+ } catch (...) {
+ errorStatus = SC_STATUS_FAILURE;
+ }
+ return FALSE;
+}
+
+void ScintillaGTK::ScrollSignal(GtkAdjustment *adj, ScintillaGTK *sciThis) {
+ try {
+ sciThis->ScrollTo(static_cast<int>(adj->value), false);
+ } catch (...) {
+ sciThis->errorStatus = SC_STATUS_FAILURE;
+ }
+}
+
+void ScintillaGTK::ScrollHSignal(GtkAdjustment *adj, ScintillaGTK *sciThis) {
+ try {
+ sciThis->HorizontalScrollTo(static_cast<int>(adj->value * 2));
+ } catch (...) {
+ sciThis->errorStatus = SC_STATUS_FAILURE;
+ }
+}
+
+void ScintillaGTK::SelectionReceived(GtkWidget *widget,
+ GtkSelectionData *selection_data, guint) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ //Platform::DebugPrintf("Selection received\n");
+ sciThis->ReceivedSelection(selection_data);
+}
+
+void ScintillaGTK::SelectionGet(GtkWidget *widget,
+ GtkSelectionData *selection_data, guint info, guint) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ try {
+ //Platform::DebugPrintf("Selection get\n");
+ if (selection_data->selection == GDK_SELECTION_PRIMARY) {
+ if (sciThis->primary.s == NULL) {
+ sciThis->CopySelectionRange(&sciThis->primary);
+ }
+ sciThis->GetSelection(selection_data, info, &sciThis->primary);
+ }
+#ifndef USE_GTK_CLIPBOARD
+ else {
+ sciThis->GetSelection(selection_data, info, &sciThis->copyText);
+ }
+#endif
+ } catch (...) {
+ sciThis->errorStatus = SC_STATUS_FAILURE;
+ }
+}
+
+gint ScintillaGTK::SelectionClear(GtkWidget *widget, GdkEventSelection *selection_event) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ //Platform::DebugPrintf("Selection clear\n");
+ sciThis->UnclaimSelection(selection_event);
+ return gtk_selection_clear(widget, selection_event);
+}
+
+void ScintillaGTK::DragBegin(GtkWidget *, GdkDragContext *) {
+ //Platform::DebugPrintf("DragBegin\n");
+}
+
+gboolean ScintillaGTK::DragMotionThis(GdkDragContext *context,
+ gint x, gint y, guint dragtime) {
+ try {
+ Point npt(x, y);
+ SetDragPosition(SPositionFromLocation(npt, false, false, UserVirtualSpace()));
+ GdkDragAction preferredAction = context->suggested_action;
+ SelectionPosition pos = SPositionFromLocation(npt);
+ if ((inDragDrop == ddDragging) && (PositionInSelection(pos.Position()))) {
+ // Avoid dragging selection onto itself as that produces a move
+ // with no real effect but which creates undo actions.
+ preferredAction = static_cast<GdkDragAction>(0);
+ } else if (context->actions == static_cast<GdkDragAction>
+ (GDK_ACTION_COPY | GDK_ACTION_MOVE)) {
+ preferredAction = GDK_ACTION_MOVE;
+ }
+ gdk_drag_status(context, preferredAction, dragtime);
+ } catch (...) {
+ errorStatus = SC_STATUS_FAILURE;
+ }
+ return FALSE;
+}
+
+gboolean ScintillaGTK::DragMotion(GtkWidget *widget, GdkDragContext *context,
+ gint x, gint y, guint dragtime) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ return sciThis->DragMotionThis(context, x, y, dragtime);
+}
+
+void ScintillaGTK::DragLeave(GtkWidget *widget, GdkDragContext * /*context*/, guint) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ try {
+ sciThis->SetDragPosition(SelectionPosition(invalidPosition));
+ //Platform::DebugPrintf("DragLeave %x\n", sciThis);
+ } catch (...) {
+ sciThis->errorStatus = SC_STATUS_FAILURE;
+ }
+}
+
+void ScintillaGTK::DragEnd(GtkWidget *widget, GdkDragContext * /*context*/) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ try {
+ // If drag did not result in drop here or elsewhere
+ if (!sciThis->dragWasDropped)
+ sciThis->SetEmptySelection(sciThis->posDrag);
+ sciThis->SetDragPosition(SelectionPosition(invalidPosition));
+ //Platform::DebugPrintf("DragEnd %x %d\n", sciThis, sciThis->dragWasDropped);
+ sciThis->inDragDrop = ddNone;
+ } catch (...) {
+ sciThis->errorStatus = SC_STATUS_FAILURE;
+ }
+}
+
+gboolean ScintillaGTK::Drop(GtkWidget *widget, GdkDragContext * /*context*/,
+ gint, gint, guint) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ try {
+ //Platform::DebugPrintf("Drop %x\n", sciThis);
+ sciThis->SetDragPosition(SelectionPosition(invalidPosition));
+ } catch (...) {
+ sciThis->errorStatus = SC_STATUS_FAILURE;
+ }
+ return FALSE;
+}
+
+void ScintillaGTK::DragDataReceived(GtkWidget *widget, GdkDragContext * /*context*/,
+ gint, gint, GtkSelectionData *selection_data, guint /*info*/, guint) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ try {
+ sciThis->ReceivedDrop(selection_data);
+ sciThis->SetDragPosition(SelectionPosition(invalidPosition));
+ } catch (...) {
+ sciThis->errorStatus = SC_STATUS_FAILURE;
+ }
+}
+
+void ScintillaGTK::DragDataGet(GtkWidget *widget, GdkDragContext *context,
+ GtkSelectionData *selection_data, guint info, guint) {
+ ScintillaGTK *sciThis = ScintillaFromWidget(widget);
+ try {
+ sciThis->dragWasDropped = true;
+ if (!sciThis->sel.Empty()) {
+ sciThis->GetSelection(selection_data, info, &sciThis->drag);
+ }
+ if (context->action == GDK_ACTION_MOVE) {
+ for (size_t r=0; r<sciThis->sel.Count(); r++) {
+ if (sciThis->posDrop >= sciThis->sel.Range(r).Start()) {
+ if (sciThis->posDrop > sciThis->sel.Range(r).End()) {
+ sciThis->posDrop.Add(-sciThis->sel.Range(r).Length());
+ } else {
+ sciThis->posDrop.Add(-SelectionRange(sciThis->posDrop, sciThis->sel.Range(r).Start()).Length());
+ }
+ }
+ }
+ sciThis->ClearSelection();
+ }
+ sciThis->SetDragPosition(SelectionPosition(invalidPosition));
+ } catch (...) {
+ sciThis->errorStatus = SC_STATUS_FAILURE;
+ }
+}
+
+int ScintillaGTK::TimeOut(ScintillaGTK *sciThis) {
+ sciThis->Tick();
+ return 1;
+}
+
+gboolean ScintillaGTK::IdleCallback(ScintillaGTK *sciThis) {
+ // Idler will be automatically stopped, if there is nothing
+ // to do while idle.
+ bool ret = sciThis->Idle();
+ if (ret == false) {
+ // FIXME: This will remove the idler from GTK, we don't want to
+ // remove it as it is removed automatically when this function
+ // returns false (although, it should be harmless).
+ sciThis->SetIdle(false);
+ }
+ return ret;
+}
+
+gboolean ScintillaGTK::StyleIdle(ScintillaGTK *sciThis) {
+ sciThis->IdleStyling();
+ // Idler will be automatically stopped
+ return FALSE;
+}
+
+void ScintillaGTK::QueueStyling(int upTo) {
+ Editor::QueueStyling(upTo);
+ if (!styleNeeded.active) {
+ // Only allow one style needed to be queued
+ styleNeeded.active = true;
+ g_idle_add_full(G_PRIORITY_HIGH_IDLE,
+ reinterpret_cast<GSourceFunc>(StyleIdle), this, NULL);
+ }
+}
+
+void ScintillaGTK::PopUpCB(ScintillaGTK *sciThis, guint action, GtkWidget *) {
+ if (action) {
+ sciThis->Command(action);
+ }
+}
+
+gint ScintillaGTK::PressCT(GtkWidget *widget, GdkEventButton *event, ScintillaGTK *sciThis) {
+ try {
+ if (event->window != widget->window)
+ return FALSE;
+ if (event->type != GDK_BUTTON_PRESS)
+ return FALSE;
+ Point pt;
+ pt.x = int(event->x);
+ pt.y = int(event->y);
+ sciThis->ct.MouseClick(pt);
+ sciThis->CallTipClick();
+ } catch (...) {
+ }
+ return TRUE;
+}
+
+gint ScintillaGTK::ExposeCT(GtkWidget *widget, GdkEventExpose * /*ose*/, CallTip *ctip) {
+ try {
+ Surface *surfaceWindow = Surface::Allocate();
+ if (surfaceWindow) {
+ surfaceWindow->Init(widget->window, widget);
+ surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == ctip->codePage);
+ surfaceWindow->SetDBCSMode(ctip->codePage);
+ ctip->PaintCT(surfaceWindow);
+ surfaceWindow->Release();
+ delete surfaceWindow;
+ }
+ } catch (...) {
+ // No pointer back to Scintilla to save status
+ }
+ return TRUE;
+}
+
+sptr_t ScintillaGTK::DirectFunction(
+ ScintillaGTK *sciThis, unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
+ return sciThis->WndProc(iMessage, wParam, lParam);
+}
+
+sptr_t scintilla_send_message(ScintillaObject *sci, unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
+ ScintillaGTK *psci = reinterpret_cast<ScintillaGTK *>(sci->pscin);
+ return psci->WndProc(iMessage, wParam, lParam);
+}
+
+static void scintilla_class_init(ScintillaClass *klass);
+static void scintilla_init(ScintillaObject *sci);
+
+extern void Platform_Initialise();
+extern void Platform_Finalise();
+
+GType scintilla_get_type() {
+ static GType scintilla_type = 0;
+ try {
+
+ if (!scintilla_type) {
+ scintilla_type = g_type_from_name("Scintilla");
+ if (!scintilla_type) {
+ static GTypeInfo scintilla_info = {
+ (guint16) sizeof (ScintillaClass),
+ NULL, //(GBaseInitFunc)
+ NULL, //(GBaseFinalizeFunc)
+ (GClassInitFunc) scintilla_class_init,
+ NULL, //(GClassFinalizeFunc)
+ NULL, //gconstpointer data
+ (guint16) sizeof (ScintillaObject),
+ 0, //n_preallocs
+ (GInstanceInitFunc) scintilla_init,
+ NULL //(GTypeValueTable*)
+ };
+
+ scintilla_type = g_type_register_static(
+ GTK_TYPE_CONTAINER, "Scintilla", &scintilla_info, (GTypeFlags) 0);
+ }
+ }
+
+ } catch (...) {
+ }
+ return scintilla_type;
+}
+
+void ScintillaGTK::ClassInit(OBJECT_CLASS* object_class, GtkWidgetClass *widget_class, GtkContainerClass *container_class) {
+ Platform_Initialise();
+ atomClipboard = gdk_atom_intern("CLIPBOARD", FALSE);
+ atomUTF8 = gdk_atom_intern("UTF8_STRING", FALSE);
+ atomString = GDK_SELECTION_TYPE_STRING;
+ atomUriList = gdk_atom_intern("text/uri-list", FALSE);
+ atomDROPFILES_DND = gdk_atom_intern("DROPFILES_DND", FALSE);
+
+ // Define default signal handlers for the class: Could move more
+ // of the signal handlers here (those that currently attached to wDraw
+ // in Initialise() may require coordinate translation?)
+
+ object_class->finalize = Destroy;
+ widget_class->size_request = SizeRequest;
+ widget_class->size_allocate = SizeAllocate;
+ widget_class->expose_event = ExposeMain;
+ widget_class->motion_notify_event = Motion;
+ widget_class->button_press_event = Press;
+ widget_class->button_release_event = MouseRelease;
+ widget_class->scroll_event = ScrollEvent;
+ widget_class->key_press_event = KeyPress;
+ widget_class->key_release_event = KeyRelease;
+ widget_class->focus_in_event = FocusIn;
+ widget_class->focus_out_event = FocusOut;
+ widget_class->selection_received = SelectionReceived;
+ widget_class->selection_get = SelectionGet;
+ widget_class->selection_clear_event = SelectionClear;
+
+ widget_class->drag_data_received = DragDataReceived;
+ widget_class->drag_motion = DragMotion;
+ widget_class->drag_leave = DragLeave;
+ widget_class->drag_end = DragEnd;
+ widget_class->drag_drop = Drop;
+ widget_class->drag_data_get = DragDataGet;
+
+ widget_class->realize = Realize;
+ widget_class->unrealize = UnRealize;
+ widget_class->map = Map;
+ widget_class->unmap = UnMap;
+
+ container_class->forall = MainForAll;
+}
+
+#define SIG_MARSHAL scintilla_marshal_NONE__INT_POINTER
+#define MARSHAL_ARGUMENTS G_TYPE_INT, G_TYPE_POINTER
+
+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;
+
+ GSignalFlags sigflags = GSignalFlags(G_SIGNAL_ACTION | G_SIGNAL_RUN_LAST);
+ scintilla_signals[COMMAND_SIGNAL] = g_signal_new(
+ "command",
+ G_TYPE_FROM_CLASS(object_class),
+ sigflags,
+ G_STRUCT_OFFSET(ScintillaClass, command),
+ NULL, //(GSignalAccumulator)
+ NULL, //(gpointer)
+ SIG_MARSHAL,
+ G_TYPE_NONE,
+ 2, MARSHAL_ARGUMENTS);
+
+ scintilla_signals[NOTIFY_SIGNAL] = g_signal_new(
+ SCINTILLA_NOTIFY,
+ G_TYPE_FROM_CLASS(object_class),
+ sigflags,
+ G_STRUCT_OFFSET(ScintillaClass, notify),
+ NULL,
+ NULL,
+ SIG_MARSHAL,
+ G_TYPE_NONE,
+ 2, MARSHAL_ARGUMENTS);
+
+ klass->command = NULL;
+ klass->notify = NULL;
+
+ ScintillaGTK::ClassInit(object_class, widget_class, container_class);
+ } catch (...) {
+ }
+}
+
+static void scintilla_init(ScintillaObject *sci) {
+ try {
+ GTK_WIDGET_SET_FLAGS(sci, GTK_CAN_FOCUS);
+ sci->pscin = new ScintillaGTK(sci);
+ } catch (...) {
+ }
+}
+
+GtkWidget* scintilla_new() {
+ return GTK_WIDGET(g_object_new(scintilla_get_type(), NULL));
+}
+
+void scintilla_set_id(ScintillaObject *sci, uptr_t id) {
+ ScintillaGTK *psci = reinterpret_cast<ScintillaGTK *>(sci->pscin);
+ psci->ctrlID = id;
+}
+
+void scintilla_release_resources(void) {
+ try {
+ Platform_Finalise();
+ } catch (...) {
+ }
+}
diff --git a/scintilla/gtk/deps.mak b/scintilla/gtk/deps.mak
new file mode 100644
index 0000000..226705b
--- /dev/null
+++ b/scintilla/gtk/deps.mak
@@ -0,0 +1,337 @@
+PlatGTK.o: PlatGTK.cxx \
+ ../include/Scintilla.h ../include/ScintillaWidget.h \
+ ../src/UniConversion.h ../src/XPM.h Converter.h
+ScintillaGTK.o: ScintillaGTK.cxx \
+ ../include/Scintilla.h ../include/ScintillaWidget.h \
+ ../include/SciLexer.h ../include/PropSet.h ../src/PropSetSimple.h \
+ ../include/Accessor.h ../include/KeyWords.h ../src/SVector.h \
+ ../src/SplitVector.h ../src/Partitioning.h ../src/RunStyles.h \
+ ../src/ContractionState.h ../src/CellBuffer.h ../src/CallTip.h \
+ ../src/KeyMap.h ../src/Indicator.h ../src/XPM.h ../src/LineMarker.h \
+ ../src/Style.h ../src/AutoComplete.h ../src/ViewStyle.h \
+ ../src/Decoration.h ../src/CharClassify.h ../src/Document.h \
+ ../src/Selection.h ../src/PositionCache.h ../src/Editor.h \
+ ../src/ScintillaBase.h ../src/UniConversion.h scintilla-marshal.h \
+ ../src/ExternalLexer.h Converter.h
+AutoComplete.o: ../src/AutoComplete.cxx ../include/Platform.h \
+ ../src/CharClassify.h ../src/AutoComplete.h
+CallTip.o: ../src/CallTip.cxx ../include/Platform.h \
+ ../include/Scintilla.h ../src/CallTip.h
+CellBuffer.o: ../src/CellBuffer.cxx ../include/Platform.h \
+ ../include/Scintilla.h ../src/SplitVector.h ../src/Partitioning.h \
+ ../src/CellBuffer.h
+CharClassify.o: ../src/CharClassify.cxx ../src/CharClassify.h
+ContractionState.o: ../src/ContractionState.cxx ../include/Platform.h \
+ ../src/SplitVector.h ../src/Partitioning.h ../src/RunStyles.h \
+ ../src/ContractionState.h
+Decoration.o: ../src/Decoration.cxx ../include/Platform.h \
+ ../include/Scintilla.h ../src/SplitVector.h ../src/Partitioning.h \
+ ../src/RunStyles.h ../src/Decoration.h
+DocumentAccessor.o: ../src/DocumentAccessor.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/DocumentAccessor.h \
+ ../src/SplitVector.h ../src/Partitioning.h ../src/RunStyles.h \
+ ../src/CellBuffer.h ../include/Scintilla.h ../src/CharClassify.h \
+ ../src/Decoration.h ../src/Document.h
+Document.o: ../src/Document.cxx ../include/Platform.h \
+ ../include/Scintilla.h ../src/SplitVector.h ../src/Partitioning.h \
+ ../src/RunStyles.h ../src/CellBuffer.h ../src/PerLine.h \
+ ../src/CharClassify.h ../src/Decoration.h ../src/Document.h \
+ ../src/RESearch.h
+Editor.o: ../src/Editor.cxx ../include/Platform.h ../include/Scintilla.h \
+ ../src/SplitVector.h ../src/Partitioning.h ../src/RunStyles.h \
+ ../src/ContractionState.h ../src/CellBuffer.h ../src/KeyMap.h \
+ ../src/Indicator.h ../src/XPM.h ../src/LineMarker.h ../src/Style.h \
+ ../src/ViewStyle.h ../src/CharClassify.h ../src/Decoration.h \
+ ../src/Document.h ../src/Selection.h ../src/PositionCache.h \
+ ../src/Editor.h
+ExternalLexer.o: ../src/ExternalLexer.cxx ../include/Platform.h \
+ ../include/Scintilla.h ../include/SciLexer.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/DocumentAccessor.h ../include/KeyWords.h \
+ ../src/ExternalLexer.h
+Indicator.o: ../src/Indicator.cxx ../include/Platform.h \
+ ../include/Scintilla.h ../src/Indicator.h
+KeyMap.o: ../src/KeyMap.cxx ../include/Platform.h ../include/Scintilla.h \
+ ../src/KeyMap.h
+KeyWords.o: ../src/KeyWords.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexAbaqus.o: ../src/LexAbaqus.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexAda.o: ../src/LexAda.cxx ../include/Platform.h ../include/Accessor.h \
+ ../src/StyleContext.h ../include/PropSet.h ../include/KeyWords.h \
+ ../include/SciLexer.h
+LexAPDL.o: ../src/LexAPDL.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexAsm.o: ../src/LexAsm.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexAsn1.o: ../src/LexAsn1.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexASY.o: ../src/LexASY.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h ../src/CharacterSet.h
+LexAU3.o: ../src/LexAU3.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexAVE.o: ../src/LexAVE.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexBaan.o: ../src/LexBaan.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexBash.o: ../src/LexBash.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h ../src/CharacterSet.h
+LexBasic.o: ../src/LexBasic.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexBullant.o: ../src/LexBullant.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexCaml.o: ../src/LexCaml.cxx ../include/Platform.h ../include/PropSet.h \
+ ../src/PropSetSimple.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexCLW.o: ../src/LexCLW.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexCmake.o: ../src/LexCmake.cxx ../include/Platform.h \
+ ../src/CharClassify.h ../include/PropSet.h ../include/Accessor.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexCOBOL.o: ../src/LexCOBOL.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h ../src/StyleContext.h
+LexConf.o: ../src/LexConf.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../include/KeyWords.h ../include/Scintilla.h \
+ ../include/SciLexer.h
+LexCPP.o: ../src/LexCPP.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h ../src/CharacterSet.h
+LexCrontab.o: ../src/LexCrontab.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexCsound.o: ../src/LexCsound.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexCSS.o: ../src/LexCSS.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexD.o: ../src/LexD.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexEiffel.o: ../src/LexEiffel.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexErlang.o: ../src/LexErlang.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexEScript.o: ../src/LexEScript.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexFlagship.o: ../src/LexFlagship.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexForth.o: ../src/LexForth.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexFortran.o: ../src/LexFortran.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexGAP.o: ../src/LexGAP.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexGui4Cli.o: ../src/LexGui4Cli.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexHaskell.o: ../src/LexHaskell.cxx ../include/Platform.h \
+ ../include/PropSet.h ../src/PropSetSimple.h ../include/Accessor.h \
+ ../src/StyleContext.h ../include/KeyWords.h ../include/Scintilla.h \
+ ../include/SciLexer.h
+LexHTML.o: ../src/LexHTML.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h ../src/CharacterSet.h
+LexInno.o: ../src/LexInno.cxx ../include/Platform.h ../src/CharClassify.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexKix.o: ../src/LexKix.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexLisp.o: ../src/LexLisp.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../include/KeyWords.h ../include/Scintilla.h \
+ ../include/SciLexer.h ../src/StyleContext.h
+LexLout.o: ../src/LexLout.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexLua.o: ../src/LexLua.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h ../src/CharacterSet.h
+LexMagik.o: ../src/LexMagik.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexMarkdown.o: ../src/LexMarkdown.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexMatlab.o: ../src/LexMatlab.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexMetapost.o: ../src/LexMetapost.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h ../src/StyleContext.h
+LexMMIXAL.o: ../src/LexMMIXAL.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexMPT.o: ../src/LexMPT.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../include/KeyWords.h ../include/Scintilla.h \
+ ../include/SciLexer.h
+LexMSSQL.o: ../src/LexMSSQL.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexMySQL.o: ../src/LexMySQL.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexNimrod.o: ../src/LexNimrod.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexNsis.o: ../src/LexNsis.cxx ../include/Platform.h ../src/CharClassify.h \
+ ../include/PropSet.h ../include/Accessor.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexOpal.o: ../src/LexOpal.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../include/KeyWords.h ../include/Scintilla.h \
+ ../include/SciLexer.h ../src/StyleContext.h
+LexOthers.o: ../src/LexOthers.cxx ../include/Platform.h \
+ ../src/CharClassify.h ../include/PropSet.h ../include/Accessor.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexPascal.o: ../src/LexPascal.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h ../src/StyleContext.h \
+ ../src/CharacterSet.h
+LexPB.o: ../src/LexPB.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexPerl.o: ../src/LexPerl.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h ../src/CharacterSet.h
+LexPLM.o: ../src/LexPLM.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../include/KeyWords.h ../include/Scintilla.h \
+ ../include/SciLexer.h ../src/StyleContext.h
+LexPOV.o: ../src/LexPOV.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexPowerPro.o: ../src/LexPowerPro.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h \
+ ../src/CharacterSet.h
+LexPowerShell.o: ../src/LexPowerShell.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexProgress.o: ../src/LexProgress.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexPS.o: ../src/LexPS.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexPython.o: ../src/LexPython.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexR.o: ../src/LexR.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexRebol.o: ../src/LexRebol.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h ../src/StyleContext.h
+LexRuby.o: ../src/LexRuby.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../include/KeyWords.h ../include/Scintilla.h \
+ ../include/SciLexer.h
+LexScriptol.o: ../src/LexScriptol.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexSmalltalk.o: ../src/LexSmalltalk.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexSML.o: ../src/LexSML.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexSorcus.o: ../src/LexSorcus.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexSpecman.o: ../src/LexSpecman.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexSpice.o: ../src/LexSpice.cxx ../include/Platform.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/PropSet.h \
+ ../include/KeyWords.h ../include/SciLexer.h
+LexSQL.o: ../src/LexSQL.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexTACL.o: ../src/LexTACL.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../include/KeyWords.h ../include/Scintilla.h \
+ ../include/SciLexer.h ../src/StyleContext.h
+LexTADS3.o: ../src/LexTADS3.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexTAL.o: ../src/LexTAL.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../include/KeyWords.h ../include/Scintilla.h \
+ ../include/SciLexer.h ../src/StyleContext.h
+LexTCL.o: ../src/LexTCL.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexTeX.o: ../src/LexTeX.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../include/KeyWords.h ../include/Scintilla.h \
+ ../include/SciLexer.h ../src/StyleContext.h
+LexVB.o: ../src/LexVB.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexVerilog.o: ../src/LexVerilog.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h \
+ ../include/KeyWords.h ../include/Scintilla.h ../include/SciLexer.h
+LexVHDL.o: ../src/LexVHDL.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LexYAML.o: ../src/LexYAML.cxx ../include/Platform.h ../include/PropSet.h \
+ ../include/Accessor.h ../src/StyleContext.h ../include/KeyWords.h \
+ ../include/Scintilla.h ../include/SciLexer.h
+LineMarker.o: ../src/LineMarker.cxx ../include/Platform.h \
+ ../include/Scintilla.h ../src/XPM.h ../src/LineMarker.h
+PerLine.o: ../src/PerLine.cxx ../include/Platform.h \
+ ../include/Scintilla.h ../src/SplitVector.h ../src/Partitioning.h \
+ ../src/CellBuffer.h ../src/PerLine.h
+PositionCache.o: ../src/PositionCache.cxx ../include/Platform.h \
+ ../include/Scintilla.h ../src/SplitVector.h ../src/Partitioning.h \
+ ../src/RunStyles.h ../src/ContractionState.h ../src/CellBuffer.h \
+ ../src/KeyMap.h ../src/Indicator.h ../src/XPM.h ../src/LineMarker.h \
+ ../src/Style.h ../src/ViewStyle.h ../src/CharClassify.h \
+ ../src/Decoration.h ../src/Document.h ../src/Selection.h \
+ ../src/PositionCache.h
+PropSet.o: ../src/PropSet.cxx ../include/Platform.h ../include/PropSet.h \
+ ../src/PropSetSimple.h
+RESearch.o: ../src/RESearch.cxx ../src/CharClassify.h ../src/RESearch.h
+RunStyles.o: ../src/RunStyles.cxx ../include/Platform.h \
+ ../include/Scintilla.h ../src/SplitVector.h ../src/Partitioning.h \
+ ../src/RunStyles.h
+ScintillaBase.o: ../src/ScintillaBase.cxx ../include/Platform.h \
+ ../include/Scintilla.h ../include/PropSet.h ../src/PropSetSimple.h \
+ ../include/SciLexer.h ../include/Accessor.h ../src/DocumentAccessor.h \
+ ../include/KeyWords.h ../src/SplitVector.h ../src/Partitioning.h \
+ ../src/RunStyles.h ../src/ContractionState.h ../src/CellBuffer.h \
+ ../src/CallTip.h ../src/KeyMap.h ../src/Indicator.h ../src/XPM.h \
+ ../src/LineMarker.h ../src/Style.h ../src/ViewStyle.h \
+ ../src/AutoComplete.h ../src/CharClassify.h ../src/Decoration.h \
+ ../src/Document.h ../src/Selection.h ../src/PositionCache.h \
+ ../src/Editor.h ../src/ScintillaBase.h
+Selection.o: ../src/Selection.cxx ../include/Platform.h \
+ ../include/Scintilla.h ../src/Selection.h
+StyleContext.o: ../src/StyleContext.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../src/StyleContext.h
+Style.o: ../src/Style.cxx ../include/Platform.h ../include/Scintilla.h \
+ ../src/Style.h
+UniConversion.o: ../src/UniConversion.cxx ../src/UniConversion.h
+ViewStyle.o: ../src/ViewStyle.cxx ../include/Platform.h \
+ ../include/Scintilla.h ../src/SplitVector.h ../src/Partitioning.h \
+ ../src/RunStyles.h ../src/Indicator.h ../src/XPM.h ../src/LineMarker.h \
+ ../src/Style.h ../src/ViewStyle.h
+WindowAccessor.o: ../src/WindowAccessor.cxx ../include/Platform.h \
+ ../include/PropSet.h ../include/Accessor.h ../include/WindowAccessor.h \
+ ../include/Scintilla.h
+XPM.o: ../src/XPM.cxx ../include/Platform.h ../src/XPM.h
diff --git a/scintilla/gtk/makefile b/scintilla/gtk/makefile
new file mode 100644
index 0000000..d62c8f3
--- /dev/null
+++ b/scintilla/gtk/makefile
@@ -0,0 +1,89 @@
+# Make file for Scintilla on Linux or compatible OS
+# Copyright 1998-2010 by Neil Hodgson <neilh@scintilla.org>
+# The License.txt file describes the conditions under which this software may be distributed.
+# This makefile assumes GCC 4.3 is used and changes will be needed to use other compilers.
+# GNU make does not like \r\n line endings so should be saved to CVS in binary form.
+# Builds for GTK+ 2 and no longer supports GTK+ 1.
+# Also works with ming32-make on Windows.
+
+.SUFFIXES: .cxx .c .o .h .a
+ifdef CLANG
+CC = clang
+CCOMP = clang
+else
+CC = g++
+CCOMP = gcc
+endif
+AR = ar
+RANLIB = touch
+
+ifndef windir
+ifeq ($(shell uname),Darwin)
+RANLIB = ranlib
+endif
+endif
+
+COMPLIB=../bin/scintilla.a
+
+vpath %.h ../src ../include
+vpath %.cxx ../src
+
+INCLUDEDIRS=-I ../include -I ../src
+CXXBASEFLAGS=-Wall -Wno-missing-braces -Wno-char-subscripts -pedantic -DGTK -DSCI_LEXER $(INCLUDEDIRS)
+
+ifdef NOTHREADS
+THREADFLAGS=-DG_THREADS_IMPL_NONE
+else
+THREADFLAGS=
+endif
+
+ifdef DEBUG
+CXXFLAGS=-DDEBUG -g $(CXXBASEFLAGS) $(THREADFLAGS)
+else
+CXXFLAGS=-DNDEBUG -Os $(CXXBASEFLAGS) $(THREADFLAGS)
+endif
+
+CONFIGFLAGS:=$(shell pkg-config --cflags gtk+-2.0)
+MARSHALLER=scintilla-marshal.o
+
+.cxx.o:
+ $(CC) $(CONFIGFLAGS) $(CXXFLAGS) -c $<
+.c.o:
+ $(CCOMP) $(CONFIGFLAGS) $(CXXFLAGS) -w -c $<
+
+#++Autogenerated -- run src/LexGen.py to regenerate
+#**LEXOBJS=\\\n\(\*.o \)
+LEXOBJS=\
+LexAbaqus.o LexAda.o LexAPDL.o LexAsm.o LexAsn1.o LexASY.o LexAU3.o LexAVE.o \
+LexBaan.o LexBash.o LexBasic.o LexBullant.o LexCaml.o LexCLW.o LexCmake.o \
+LexCOBOL.o LexConf.o LexCPP.o LexCrontab.o LexCsound.o LexCSS.o LexD.o \
+LexEiffel.o LexErlang.o LexEScript.o LexFlagship.o LexForth.o LexFortran.o \
+LexGAP.o LexGui4Cli.o LexHaskell.o LexHTML.o LexInno.o LexKix.o LexLisp.o \
+LexLout.o LexLua.o LexMagik.o LexMarkdown.o LexMatlab.o LexMetapost.o \
+LexMMIXAL.o LexMPT.o LexMSSQL.o LexMySQL.o LexNimrod.o LexNsis.o LexOpal.o \
+LexOthers.o LexPascal.o LexPB.o LexPerl.o LexPLM.o LexPOV.o LexPowerPro.o \
+LexPowerShell.o LexProgress.o LexPS.o LexPython.o LexR.o LexRebol.o LexRuby.o \
+LexScriptol.o LexSmalltalk.o LexSML.o LexSorcus.o LexSpecman.o LexSpice.o \
+LexSQL.o LexTACL.o LexTADS3.o LexTAL.o LexTCL.o LexTeX.o LexVB.o LexVerilog.o \
+LexVHDL.o LexYAML.o
+#--Autogenerated -- end of automatically generated section
+
+all: $(COMPLIB)
+
+clean:
+ rm -f *.o $(COMPLIB)
+
+deps:
+ $(CC) -MM $(CONFIGFLAGS) $(CXXFLAGS) *.cxx ../src/*.cxx | sed -e 's/\/usr.* //' | grep [a-zA-Z] >deps.mak
+
+$(COMPLIB): DocumentAccessor.o WindowAccessor.o KeyWords.o StyleContext.o \
+ CharClassify.o Decoration.o Document.o PerLine.o CallTip.o \
+ ScintillaBase.o ContractionState.o Editor.o ExternalLexer.o PropSet.o PlatGTK.o \
+ KeyMap.o LineMarker.o PositionCache.o ScintillaGTK.o CellBuffer.o ViewStyle.o \
+ RESearch.o RunStyles.o Selection.o Style.o Indicator.o AutoComplete.o UniConversion.o XPM.o \
+ $(MARSHALLER) $(LEXOBJS)
+ $(AR) rc $@ $^
+ $(RANLIB) $@
+
+# Automatically generate header dependencies with "make deps"
+include deps.mak
diff --git a/scintilla/gtk/scintilla-marshal.c b/scintilla/gtk/scintilla-marshal.c
new file mode 100644
index 0000000..02da184
--- /dev/null
+++ b/scintilla/gtk/scintilla-marshal.c
@@ -0,0 +1,86 @@
+
+#include <glib-object.h>
+
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v) g_value_get_char (v)
+#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v) g_value_get_int (v)
+#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
+#define g_marshal_value_peek_long(v) g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
+#define g_marshal_value_peek_float(v) g_value_get_float (v)
+#define g_marshal_value_peek_double(v) g_value_get_double (v)
+#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v) g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v) g_value_get_object (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ * Do not access GValues directly in your code. Instead, use the
+ * g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
+#define g_marshal_value_peek_char(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v) (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v) (v)->data[0].v_int
+#define g_marshal_value_peek_flags(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_float(v) (v)->data[0].v_float
+#define g_marshal_value_peek_double(v) (v)->data[0].v_double
+#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+/* NONE:INT,POINTER (scintilla-marshal.list:1) */
+void
+scintilla_marshal_VOID__INT_POINTER (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__INT_POINTER) (gpointer data1,
+ gint arg_1,
+ gpointer arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__INT_POINTER callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__INT_POINTER) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_int (param_values + 1),
+ g_marshal_value_peek_pointer (param_values + 2),
+ data2);
+}
+
diff --git a/scintilla/gtk/scintilla-marshal.h b/scintilla/gtk/scintilla-marshal.h
new file mode 100644
index 0000000..28e94cc
--- /dev/null
+++ b/scintilla/gtk/scintilla-marshal.h
@@ -0,0 +1,21 @@
+
+#ifndef __scintilla_marshal_MARSHAL_H__
+#define __scintilla_marshal_MARSHAL_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/* NONE:INT,POINTER (scintilla-marshal.list:1) */
+extern void scintilla_marshal_VOID__INT_POINTER (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+#define scintilla_marshal_NONE__INT_POINTER scintilla_marshal_VOID__INT_POINTER
+
+G_END_DECLS
+
+#endif /* __scintilla_marshal_MARSHAL_H__ */
+
diff --git a/scintilla/gtk/scintilla-marshal.list b/scintilla/gtk/scintilla-marshal.list
new file mode 100644
index 0000000..b3cd2aa
--- /dev/null
+++ b/scintilla/gtk/scintilla-marshal.list
@@ -0,0 +1 @@
+NONE:INT,POINTER