2009-04-24 23:35:41 +00:00
|
|
|
// 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.
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
#include <cstddef>
|
|
|
|
#include <cstdlib>
|
2022-01-04 23:07:50 +00:00
|
|
|
#include <cstdint>
|
2019-05-04 18:14:48 +00:00
|
|
|
#include <cassert>
|
|
|
|
#include <cstring>
|
|
|
|
#include <cstdio>
|
|
|
|
#include <ctime>
|
|
|
|
#include <cmath>
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2015-06-07 21:19:26 +00:00
|
|
|
#include <stdexcept>
|
|
|
|
#include <new>
|
2009-08-23 02:24:48 +00:00
|
|
|
#include <string>
|
2019-05-04 18:14:48 +00:00
|
|
|
#include <string_view>
|
2009-08-23 02:24:48 +00:00
|
|
|
#include <vector>
|
2013-08-28 00:44:27 +00:00
|
|
|
#include <map>
|
2022-01-04 23:07:50 +00:00
|
|
|
#include <set>
|
|
|
|
#include <optional>
|
2013-08-28 00:44:27 +00:00
|
|
|
#include <algorithm>
|
2019-05-04 18:14:48 +00:00
|
|
|
#include <memory>
|
2009-08-23 02:24:48 +00:00
|
|
|
|
2015-06-07 21:19:26 +00:00
|
|
|
#include <glib.h>
|
|
|
|
#include <gmodule.h>
|
2019-05-04 18:14:48 +00:00
|
|
|
#include <gdk/gdk.h>
|
2009-04-24 23:35:41 +00:00
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <gdk/gdkkeysyms.h>
|
2019-05-04 18:14:48 +00:00
|
|
|
#if defined(GDK_WINDOWING_WAYLAND)
|
|
|
|
#include <gdk/gdkwayland.h>
|
|
|
|
#endif
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
#if defined(_WIN32)
|
|
|
|
// On Win32 use windows.h to access clipboard (rectangular format) and systems parameters
|
|
|
|
#undef NOMINMAX
|
|
|
|
#define NOMINMAX
|
2011-07-17 22:30:49 +00:00
|
|
|
#include <windows.h>
|
2009-04-24 23:35:41 +00:00
|
|
|
#endif
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
#include "ScintillaTypes.h"
|
|
|
|
#include "ScintillaMessages.h"
|
|
|
|
#include "ScintillaStructures.h"
|
2019-05-04 18:14:48 +00:00
|
|
|
#include "ILoader.h"
|
2010-08-21 23:59:56 +00:00
|
|
|
#include "ILexer.h"
|
2022-01-04 23:07:50 +00:00
|
|
|
|
|
|
|
#include "Debugging.h"
|
|
|
|
#include "Geometry.h"
|
|
|
|
#include "Platform.h"
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
#include "Scintilla.h"
|
|
|
|
#include "ScintillaWidget.h"
|
2022-01-04 23:07:50 +00:00
|
|
|
#include "CharacterCategoryMap.h"
|
2019-05-04 18:14:48 +00:00
|
|
|
#include "Position.h"
|
|
|
|
#include "UniqueString.h"
|
2009-04-24 23:35:41 +00:00
|
|
|
#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 "LineMarker.h"
|
|
|
|
#include "Style.h"
|
|
|
|
#include "ViewStyle.h"
|
|
|
|
#include "CharClassify.h"
|
2015-06-07 21:19:26 +00:00
|
|
|
#include "Decoration.h"
|
2013-08-28 00:44:27 +00:00
|
|
|
#include "CaseFolder.h"
|
2009-04-24 23:35:41 +00:00
|
|
|
#include "Document.h"
|
2015-06-07 21:19:26 +00:00
|
|
|
#include "CaseConvert.h"
|
|
|
|
#include "UniConversion.h"
|
2009-08-23 02:24:48 +00:00
|
|
|
#include "Selection.h"
|
2009-04-24 23:35:41 +00:00
|
|
|
#include "PositionCache.h"
|
2015-06-07 21:19:26 +00:00
|
|
|
#include "EditModel.h"
|
|
|
|
#include "MarginView.h"
|
|
|
|
#include "EditView.h"
|
2009-04-24 23:35:41 +00:00
|
|
|
#include "Editor.h"
|
2015-06-07 21:19:26 +00:00
|
|
|
#include "AutoComplete.h"
|
2009-04-24 23:35:41 +00:00
|
|
|
#include "ScintillaBase.h"
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
#include "Wrappers.h"
|
2019-05-04 18:14:48 +00:00
|
|
|
#include "ScintillaGTK.h"
|
2015-06-07 21:19:26 +00:00
|
|
|
#include "scintilla-marshal.h"
|
2019-05-04 18:14:48 +00:00
|
|
|
#include "ScintillaGTKAccessible.h"
|
2009-04-24 23:35:41 +00:00
|
|
|
#include "Converter.h"
|
|
|
|
|
2010-09-05 22:56:27 +00:00
|
|
|
#define IS_WIDGET_REALIZED(w) (gtk_widget_get_realized(GTK_WIDGET(w)))
|
|
|
|
#define IS_WIDGET_MAPPED(w) (gtk_widget_get_mapped(GTK_WIDGET(w)))
|
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
#define SC_INDICATOR_INPUT INDICATOR_IME
|
|
|
|
#define SC_INDICATOR_TARGET INDICATOR_IME+1
|
|
|
|
#define SC_INDICATOR_CONVERTED INDICATOR_IME+2
|
|
|
|
#define SC_INDICATOR_UNKNOWN INDICATOR_IME_MAX
|
2015-06-07 21:19:26 +00:00
|
|
|
|
2009-06-24 19:09:31 +00:00
|
|
|
using namespace Scintilla;
|
2022-01-04 23:07:50 +00:00
|
|
|
using namespace Scintilla::Internal;
|
2009-06-24 19:09:31 +00:00
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
// From PlatGTK.cxx
|
2019-05-04 18:14:48 +00:00
|
|
|
extern std::string UTF8FromLatin1(std::string_view text);
|
2022-01-04 23:07:50 +00:00
|
|
|
extern void Platform_Initialise();
|
|
|
|
extern void Platform_Finalise();
|
|
|
|
|
|
|
|
namespace {
|
2009-04-24 23:35:41 +00:00
|
|
|
|
|
|
|
enum {
|
2019-07-21 13:26:02 +00:00
|
|
|
COMMAND_SIGNAL,
|
|
|
|
NOTIFY_SIGNAL,
|
|
|
|
LAST_SIGNAL
|
2009-04-24 23:35:41 +00:00
|
|
|
};
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
gint scintilla_signals[LAST_SIGNAL] = { 0 };
|
2009-04-24 23:35:41 +00:00
|
|
|
|
|
|
|
enum {
|
2019-07-21 13:26:02 +00:00
|
|
|
TARGET_STRING,
|
|
|
|
TARGET_TEXT,
|
|
|
|
TARGET_COMPOUND_TEXT,
|
|
|
|
TARGET_UTF8_STRING,
|
|
|
|
TARGET_URI
|
2009-04-24 23:35:41 +00:00
|
|
|
};
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
const GtkTargetEntry clipboardCopyTargets[] = {
|
2009-04-25 23:38:15 +00:00
|
|
|
{ (gchar *) "UTF8_STRING", 0, TARGET_UTF8_STRING },
|
|
|
|
{ (gchar *) "STRING", 0, TARGET_STRING },
|
2009-04-24 23:35:41 +00:00
|
|
|
};
|
2022-01-04 23:07:50 +00:00
|
|
|
constexpr gint nClipboardCopyTargets = static_cast<gint>(std::size(clipboardCopyTargets));
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
const GtkTargetEntry clipboardPasteTargets[] = {
|
2009-04-25 23:38:15 +00:00
|
|
|
{ (gchar *) "text/uri-list", 0, TARGET_URI },
|
|
|
|
{ (gchar *) "UTF8_STRING", 0, TARGET_UTF8_STRING },
|
|
|
|
{ (gchar *) "STRING", 0, TARGET_STRING },
|
2009-04-24 23:35:41 +00:00
|
|
|
};
|
2022-01-04 23:07:50 +00:00
|
|
|
constexpr gint nClipboardPasteTargets = static_cast<gint>(std::size(clipboardPasteTargets));
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
const GdkDragAction actionCopyOrMove = static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE);
|
2019-05-04 18:14:48 +00:00
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
GtkWidget *PWidget(const Window &w) noexcept {
|
2019-05-04 18:14:48 +00:00
|
|
|
return static_cast<GtkWidget *>(w.GetID());
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
GdkWindow *PWindow(const Window &w) noexcept {
|
|
|
|
GtkWidget *widget = static_cast<GtkWidget *>(w.GetID());
|
|
|
|
return gtk_widget_get_window(widget);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapWidget(GtkWidget *widget) noexcept {
|
|
|
|
if (widget &&
|
|
|
|
gtk_widget_get_visible(GTK_WIDGET(widget)) &&
|
|
|
|
!IS_WIDGET_MAPPED(widget)) {
|
|
|
|
gtk_widget_map(widget);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const guchar *DataOfGSD(GtkSelectionData *sd) noexcept {
|
|
|
|
return gtk_selection_data_get_data(sd);
|
|
|
|
}
|
|
|
|
|
|
|
|
gint LengthOfGSD(GtkSelectionData *sd) noexcept {
|
|
|
|
return gtk_selection_data_get_length(sd);
|
|
|
|
}
|
|
|
|
|
|
|
|
GdkAtom TypeOfGSD(GtkSelectionData *sd) noexcept {
|
|
|
|
return gtk_selection_data_get_data_type(sd);
|
|
|
|
}
|
|
|
|
|
|
|
|
GdkAtom SelectionOfGSD(GtkSelectionData *sd) noexcept {
|
|
|
|
return gtk_selection_data_get_selection(sd);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SettingGet(GtkSettings *settings, const gchar *name, gpointer value) noexcept {
|
|
|
|
if (!settings) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!g_object_class_find_property(G_OBJECT_GET_CLASS(
|
|
|
|
G_OBJECT(settings)), name)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
g_object_get(G_OBJECT(settings), name, value, nullptr);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
FontOptions::FontOptions(GtkWidget *widget) noexcept {
|
|
|
|
UniquePangoContext pcontext(gtk_widget_create_pango_context(widget));
|
|
|
|
PLATFORM_ASSERT(pcontext);
|
|
|
|
const cairo_font_options_t *options = pango_cairo_context_get_font_options(pcontext.get());
|
|
|
|
// options is owned by the PangoContext so must not be freed.
|
|
|
|
if (options) {
|
|
|
|
// options is NULL on Win32
|
|
|
|
antialias = cairo_font_options_get_antialias(options);
|
|
|
|
order = cairo_font_options_get_subpixel_order(options);
|
|
|
|
hint = cairo_font_options_get_hint_style(options);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FontOptions::operator==(const FontOptions &other) const noexcept {
|
|
|
|
return antialias == other.antialias &&
|
|
|
|
order == other.order &&
|
|
|
|
hint == other.hint;
|
|
|
|
}
|
|
|
|
|
2021-02-21 04:53:09 +00:00
|
|
|
ScintillaGTK *ScintillaGTK::FromWidget(GtkWidget *widget) noexcept {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaObject *scio = SCINTILLA(widget);
|
|
|
|
return static_cast<ScintillaGTK *>(scio->pscin);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ScintillaGTK::ScintillaGTK(_ScintillaObject *sci_) :
|
2019-07-21 13:26:02 +00:00
|
|
|
adjustmentv(nullptr), adjustmenth(nullptr),
|
|
|
|
verticalScrollBarWidth(30), horizontalScrollBarHeight(30),
|
|
|
|
buttonMouse(0),
|
|
|
|
capturedMouse(false), dragWasDropped(false),
|
|
|
|
lastKey(0), rectangularSelectionModifier(SCMOD_CTRL),
|
|
|
|
parentClass(nullptr),
|
|
|
|
atomSought(nullptr),
|
2021-02-21 04:53:09 +00:00
|
|
|
preeditInitialized(false),
|
2019-07-21 13:26:02 +00:00
|
|
|
im_context(nullptr),
|
2021-02-21 04:53:09 +00:00
|
|
|
lastNonCommonScript(G_UNICODE_SCRIPT_INVALID_CODE),
|
2022-01-04 23:07:50 +00:00
|
|
|
settings(nullptr),
|
|
|
|
settingsHandlerId(0),
|
2021-02-21 04:53:09 +00:00
|
|
|
lastWheelMouseTime(0),
|
2019-07-21 13:26:02 +00:00
|
|
|
lastWheelMouseDirection(0),
|
|
|
|
wheelMouseIntensity(0),
|
|
|
|
smoothScrollY(0),
|
|
|
|
smoothScrollX(0),
|
|
|
|
rgnUpdate(nullptr),
|
|
|
|
repaintFullWindow(false),
|
|
|
|
styleIdleID(0),
|
|
|
|
accessibilityEnabled(SC_ACCESSIBILITY_ENABLED),
|
|
|
|
accessible(nullptr) {
|
2009-04-24 23:35:41 +00:00
|
|
|
sci = sci_;
|
|
|
|
wMain = GTK_WIDGET(sci);
|
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
rectangularSelectionModifier = SCMOD_ALT;
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
#if PLAT_GTK_WIN32
|
2013-08-28 00:44:27 +00:00
|
|
|
// There does not seem to be a real standard for indicating that the clipboard
|
2009-04-24 23:35:41 +00:00
|
|
|
// contains a rectangular selection, so copy Developer Studio.
|
|
|
|
cfColumnSelect = static_cast<CLIPFORMAT>(
|
2022-01-04 23:07:50 +00:00
|
|
|
::RegisterClipboardFormatW(L"MSDEVColumnSelect"));
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2013-08-28 00:44:27 +00:00
|
|
|
// Get intellimouse parameters when running on win32; otherwise use
|
2009-04-24 23:35:41 +00:00
|
|
|
// reasonable default
|
|
|
|
#ifndef SPI_GETWHEELSCROLLLINES
|
|
|
|
#define SPI_GETWHEELSCROLLLINES 104
|
|
|
|
#endif
|
|
|
|
::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &linesPerScroll, 0);
|
|
|
|
#else
|
|
|
|
linesPerScroll = 4;
|
|
|
|
#endif
|
2022-01-04 23:07:50 +00:00
|
|
|
primarySelection = false;
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
Init();
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ScintillaGTK::~ScintillaGTK() {
|
2019-05-04 18:14:48 +00:00
|
|
|
if (styleIdleID) {
|
|
|
|
g_source_remove(styleIdleID);
|
|
|
|
styleIdleID = 0;
|
|
|
|
}
|
2022-05-25 20:16:39 +00:00
|
|
|
if (scrollBarIdleID) {
|
|
|
|
g_source_remove(scrollBarIdleID);
|
|
|
|
scrollBarIdleID = 0;
|
|
|
|
}
|
2022-01-04 23:07:50 +00:00
|
|
|
ClearPrimarySelection();
|
2015-06-07 21:19:26 +00:00
|
|
|
wPreedit.Destroy();
|
2022-01-04 23:07:50 +00:00
|
|
|
if (settingsHandlerId) {
|
|
|
|
g_signal_handler_disconnect(settings, settingsHandlerId);
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::RealizeThis(GtkWidget *widget) {
|
|
|
|
//Platform::DebugPrintf("ScintillaGTK::realize this\n");
|
2011-03-22 00:16:49 +00:00
|
|
|
gtk_widget_set_realized(widget, TRUE);
|
2022-01-04 23:07:50 +00:00
|
|
|
GdkWindowAttr attrs {};
|
2009-04-24 23:35:41 +00:00
|
|
|
attrs.window_type = GDK_WINDOW_CHILD;
|
2011-07-17 22:30:49 +00:00
|
|
|
GtkAllocation allocation;
|
|
|
|
gtk_widget_get_allocation(widget, &allocation);
|
|
|
|
attrs.x = allocation.x;
|
|
|
|
attrs.y = allocation.y;
|
|
|
|
attrs.width = allocation.width;
|
|
|
|
attrs.height = allocation.height;
|
2009-04-24 23:35:41 +00:00
|
|
|
attrs.wclass = GDK_INPUT_OUTPUT;
|
|
|
|
attrs.visual = gtk_widget_get_visual(widget);
|
2011-07-17 22:30:49 +00:00
|
|
|
#if !GTK_CHECK_VERSION(3,0,0)
|
2009-04-24 23:35:41 +00:00
|
|
|
attrs.colormap = gtk_widget_get_colormap(widget);
|
2011-07-17 22:30:49 +00:00
|
|
|
#endif
|
2009-04-24 23:35:41 +00:00
|
|
|
attrs.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK;
|
2019-05-04 18:14:48 +00:00
|
|
|
GdkDisplay *pdisplay = gtk_widget_get_display(widget);
|
|
|
|
GdkCursor *cursor = gdk_cursor_new_for_display(pdisplay, GDK_XTERM);
|
2009-04-24 23:35:41 +00:00
|
|
|
attrs.cursor = cursor;
|
2011-07-17 22:30:49 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
gtk_widget_set_window(widget, gdk_window_new(gtk_widget_get_parent_window(widget), &attrs,
|
2019-07-21 13:26:02 +00:00
|
|
|
GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_CURSOR));
|
2019-05-04 18:14:48 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,8,0)
|
|
|
|
gtk_widget_register_window(widget, gtk_widget_get_window(widget));
|
|
|
|
#else
|
2011-07-17 22:30:49 +00:00
|
|
|
gdk_window_set_user_data(gtk_widget_get_window(widget), widget);
|
2019-05-04 18:14:48 +00:00
|
|
|
#endif
|
|
|
|
#if !GTK_CHECK_VERSION(3,18,0)
|
|
|
|
gtk_style_context_set_background(gtk_widget_get_style_context(widget),
|
2019-07-21 13:26:02 +00:00
|
|
|
gtk_widget_get_window(widget));
|
2019-05-04 18:14:48 +00:00
|
|
|
#endif
|
2011-07-17 22:30:49 +00:00
|
|
|
gdk_window_show(gtk_widget_get_window(widget));
|
|
|
|
#else
|
2009-04-24 23:35:41 +00:00
|
|
|
widget->window = gdk_window_new(gtk_widget_get_parent_window(widget), &attrs,
|
2019-07-21 13:26:02 +00:00
|
|
|
GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_CURSOR);
|
2009-04-24 23:35:41 +00:00
|
|
|
gdk_window_set_user_data(widget->window, widget);
|
2011-07-17 22:30:49 +00:00
|
|
|
widget->style = gtk_style_attach(widget->style, widget->window);
|
2009-04-24 23:35:41 +00:00
|
|
|
gdk_window_set_background(widget->window, &widget->style->bg[GTK_STATE_NORMAL]);
|
|
|
|
gdk_window_show(widget->window);
|
2011-07-17 22:30:49 +00:00
|
|
|
#endif
|
2022-01-04 23:07:50 +00:00
|
|
|
UnRefCursor(cursor);
|
2021-02-21 04:53:09 +00:00
|
|
|
|
|
|
|
preeditInitialized = false;
|
2009-04-24 23:35:41 +00:00
|
|
|
gtk_widget_realize(PWidget(wPreedit));
|
2015-06-07 21:19:26 +00:00
|
|
|
gtk_widget_realize(PWidget(wPreeditDraw));
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
im_context.reset(gtk_im_multicontext_new());
|
|
|
|
g_signal_connect(G_OBJECT(im_context.get()), "commit",
|
2019-07-21 13:26:02 +00:00
|
|
|
G_CALLBACK(Commit), this);
|
2022-01-04 23:07:50 +00:00
|
|
|
g_signal_connect(G_OBJECT(im_context.get()), "preedit_changed",
|
2019-07-21 13:26:02 +00:00
|
|
|
G_CALLBACK(PreeditChanged), this);
|
2023-02-09 16:57:24 +00:00
|
|
|
g_signal_connect(G_OBJECT(im_context.get()), "retrieve-surrounding",
|
|
|
|
G_CALLBACK(RetrieveSurrounding), this);
|
|
|
|
g_signal_connect(G_OBJECT(im_context.get()), "delete-surrounding",
|
|
|
|
G_CALLBACK(DeleteSurrounding), this);
|
2022-01-04 23:07:50 +00:00
|
|
|
gtk_im_context_set_client_window(im_context.get(), WindowFromWidget(widget));
|
2021-02-21 04:53:09 +00:00
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
GtkWidget *widtxt = PWidget(wText); // // No code inside the G_OBJECT macro
|
|
|
|
g_signal_connect_after(G_OBJECT(widtxt), "style_set",
|
2019-07-21 13:26:02 +00:00
|
|
|
G_CALLBACK(ScintillaGTK::StyleSetText), nullptr);
|
2009-04-24 23:35:41 +00:00
|
|
|
g_signal_connect_after(G_OBJECT(widtxt), "realize",
|
2019-07-21 13:26:02 +00:00
|
|
|
G_CALLBACK(ScintillaGTK::RealizeText), nullptr);
|
2009-04-24 23:35:41 +00:00
|
|
|
gtk_widget_realize(widtxt);
|
|
|
|
gtk_widget_realize(PWidget(scrollbarv));
|
|
|
|
gtk_widget_realize(PWidget(scrollbarh));
|
2011-07-17 22:30:49 +00:00
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
cursor = gdk_cursor_new_for_display(pdisplay, GDK_XTERM);
|
2011-07-17 22:30:49 +00:00
|
|
|
gdk_window_set_cursor(PWindow(wText), cursor);
|
2013-08-28 00:44:27 +00:00
|
|
|
UnRefCursor(cursor);
|
2011-07-17 22:30:49 +00:00
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
cursor = gdk_cursor_new_for_display(pdisplay, GDK_LEFT_PTR);
|
2011-07-17 22:30:49 +00:00
|
|
|
gdk_window_set_cursor(PWindow(scrollbarv), cursor);
|
2013-08-28 00:44:27 +00:00
|
|
|
UnRefCursor(cursor);
|
2011-07-17 22:30:49 +00:00
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
cursor = gdk_cursor_new_for_display(pdisplay, GDK_LEFT_PTR);
|
2011-07-17 22:30:49 +00:00
|
|
|
gdk_window_set_cursor(PWindow(scrollbarh), cursor);
|
2013-08-28 00:44:27 +00:00
|
|
|
UnRefCursor(cursor);
|
2011-07-17 22:30:49 +00:00
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
using NotifyLambda = void (*)(GObject *, GParamSpec *, ScintillaGTK *);
|
|
|
|
if (settings) {
|
|
|
|
settingsHandlerId = g_signal_connect(settings, "notify::gtk-xft-dpi",
|
|
|
|
G_CALLBACK(static_cast<NotifyLambda>([](GObject *, GParamSpec *, ScintillaGTK *sciThis) {
|
|
|
|
sciThis->InvalidateStyleRedraw();
|
|
|
|
})),
|
|
|
|
this);
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::Realize(GtkWidget *widget) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-04-24 23:35:41 +00:00
|
|
|
sciThis->RealizeThis(widget);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::UnRealizeThis(GtkWidget *widget) {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
2010-09-05 22:56:27 +00:00
|
|
|
if (IS_WIDGET_MAPPED(widget)) {
|
2009-08-23 02:24:48 +00:00
|
|
|
gtk_widget_unmap(widget);
|
|
|
|
}
|
2011-03-22 00:16:49 +00:00
|
|
|
gtk_widget_set_realized(widget, FALSE);
|
2009-08-23 02:24:48 +00:00
|
|
|
gtk_widget_unrealize(PWidget(wText));
|
2019-05-04 18:14:48 +00:00
|
|
|
if (PWidget(scrollbarv))
|
|
|
|
gtk_widget_unrealize(PWidget(scrollbarv));
|
|
|
|
if (PWidget(scrollbarh))
|
|
|
|
gtk_widget_unrealize(PWidget(scrollbarh));
|
2009-08-23 02:24:48 +00:00
|
|
|
gtk_widget_unrealize(PWidget(wPreedit));
|
|
|
|
gtk_widget_unrealize(PWidget(wPreeditDraw));
|
2022-01-04 23:07:50 +00:00
|
|
|
im_context.reset();
|
2009-08-23 02:24:48 +00:00
|
|
|
if (GTK_WIDGET_CLASS(parentClass)->unrealize)
|
|
|
|
GTK_WIDGET_CLASS(parentClass)->unrealize(widget);
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
Finalise();
|
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::UnRealize(GtkWidget *widget) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-04-24 23:35:41 +00:00
|
|
|
sciThis->UnRealizeThis(widget);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::MapThis() {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
|
|
|
//Platform::DebugPrintf("ScintillaGTK::map this\n");
|
2011-03-22 00:16:49 +00:00
|
|
|
gtk_widget_set_mapped(PWidget(wMain), TRUE);
|
2009-08-23 02:24:48 +00:00
|
|
|
MapWidget(PWidget(wText));
|
|
|
|
MapWidget(PWidget(scrollbarh));
|
|
|
|
MapWidget(PWidget(scrollbarv));
|
2022-01-04 23:07:50 +00:00
|
|
|
wMain.SetCursor(Window::Cursor::arrow);
|
|
|
|
scrollbarv.SetCursor(Window::Cursor::arrow);
|
|
|
|
scrollbarh.SetCursor(Window::Cursor::arrow);
|
Update scintilla 5.3.4 and lexilla 5.2.4 with:
https://www.scintilla.org/scintilla534.zip
Released 8 March 2023.
Add multithreaded wrap to significantly improve performance of wrapping large files.
More typesafe bindings of *Full APIs in ScintillaCall. Feature #1477.
Fix overlapping of text with line end wrap marker. Bug #2378.
Fix clipping of line end wrap symbol for SC_WRAPVISUALFLAGLOC_END_BY_TEXT.
Where a multi-byte character contains multiple styles, display each byte as a representation. This makes it easier to see and fix lexers that change styles mid-character, commonly because they use fixed size buffers.
Fix a potential crash with autocompletion list fill-ups where a SCN_CHARADDED handler retriggered an autocompletion list, but with no items that match the typed character.
lexilla523
Released 8 March 2023.
Add scripts/PromoteNew.bat script to promote .new files after checking.
Makefile: Remove 1024-byte line length limit..
Ruby: Add new lexical classes for % literals SCE_RB_STRING_W (%w non-interpolable string array), SCE_RB_STRING_I (%i non-interpolable symbol array), SCE_RB_STRING_QI (%I interpolable symbol array), and SCE_RB_STRING_QS (%s symbol). Issue #124.
Ruby: Disambiguate %= which may be a quote or modulo assignment. Issue #124, Bug #1255, Bug #2182.
Ruby: Fix additional fold level for single character in SCE_RB_STRING_QW. Issue #132.
Ruby: Set SCE_RB_HERE_QQ for unquoted and double-quoted heredocs and SCE_RB_HERE_QX for backticks-quoted heredocs. Issue #134.
Ruby: Recognise #{} inside SCE_RB_HERE_QQ and SCE_RB_HERE_QX. Issue #134.
Ruby: Improve regex and heredoc recognition. Issue #136.
Ruby: Highlight #@, #@@ and #$ style interpolation. Issue #140.
Ruby: Fix folding for multiple heredocs started on one line. Fix folding when there is a space after heredoc opening delimiter. Issue #135.
YAML: Remove 1024-byte line length limit.
https://www.scintilla.org/lexilla524.zip
Released 13 March 2023.
C++: Fix failure to recognize keywords containing upper case. Issue #149.
GDScript: Support % and $ node paths. Issue #145, Pull request #146.
Close #13338
2023-03-10 02:37:21 +00:00
|
|
|
SetClientRectangle();
|
2009-08-23 02:24:48 +00:00
|
|
|
ChangeSize();
|
2011-07-17 22:30:49 +00:00
|
|
|
gdk_window_show(PWindow(wMain));
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::Map(GtkWidget *widget) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-04-24 23:35:41 +00:00
|
|
|
sciThis->MapThis();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::UnMapThis() {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
|
|
|
//Platform::DebugPrintf("ScintillaGTK::unmap this\n");
|
2011-03-22 00:16:49 +00:00
|
|
|
gtk_widget_set_mapped(PWidget(wMain), FALSE);
|
2022-01-04 23:07:50 +00:00
|
|
|
DropGraphics();
|
2011-07-17 22:30:49 +00:00
|
|
|
gdk_window_hide(PWindow(wMain));
|
2009-08-23 02:24:48 +00:00
|
|
|
gtk_widget_unmap(PWidget(wText));
|
2019-05-04 18:14:48 +00:00
|
|
|
if (PWidget(scrollbarh))
|
|
|
|
gtk_widget_unmap(PWidget(scrollbarh));
|
|
|
|
if (PWidget(scrollbarv))
|
|
|
|
gtk_widget_unmap(PWidget(scrollbarv));
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::UnMap(GtkWidget *widget) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-04-24 23:35:41 +00:00
|
|
|
sciThis->UnMapThis();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::ForAll(GtkCallback callback, gpointer callback_data) {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
2019-07-21 13:26:02 +00:00
|
|
|
(*callback)(PWidget(wText), callback_data);
|
2019-05-04 18:14:48 +00:00
|
|
|
if (PWidget(scrollbarv))
|
2019-07-21 13:26:02 +00:00
|
|
|
(*callback)(PWidget(scrollbarv), callback_data);
|
2019-05-04 18:14:48 +00:00
|
|
|
if (PWidget(scrollbarh))
|
2019-07-21 13:26:02 +00:00
|
|
|
(*callback)(PWidget(scrollbarh), callback_data);
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::MainForAll(GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data) {
|
2022-01-04 23:07:50 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(GTK_WIDGET(container));
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
if (callback && include_internals) {
|
2009-04-24 23:35:41 +00:00
|
|
|
sciThis->ForAll(callback, callback_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-07 21:19:26 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
class PreEditString {
|
|
|
|
public:
|
|
|
|
gchar *str;
|
|
|
|
gint cursor_pos;
|
|
|
|
PangoAttrList *attrs;
|
|
|
|
gboolean validUTF8;
|
|
|
|
glong uniStrLen;
|
|
|
|
gunichar *uniStr;
|
2021-02-21 04:53:09 +00:00
|
|
|
GUnicodeScript pscript;
|
2015-06-07 21:19:26 +00:00
|
|
|
|
2021-02-21 04:53:09 +00:00
|
|
|
explicit PreEditString(GtkIMContext *im_context) noexcept {
|
2015-06-07 21:19:26 +00:00
|
|
|
gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos);
|
2019-07-21 13:26:02 +00:00
|
|
|
validUTF8 = g_utf8_validate(str, strlen(str), nullptr);
|
2022-01-04 23:07:50 +00:00
|
|
|
uniStr = g_utf8_to_ucs4_fast(str, static_cast<glong>(strlen(str)), &uniStrLen);
|
2021-02-21 04:53:09 +00:00
|
|
|
pscript = g_unichar_get_script(uniStr[0]);
|
2015-06-07 21:19:26 +00:00
|
|
|
}
|
2021-02-21 04:53:09 +00:00
|
|
|
// Deleted so PreEditString objects can not be copied.
|
|
|
|
PreEditString(const PreEditString&) = delete;
|
|
|
|
PreEditString(PreEditString&&) = delete;
|
|
|
|
PreEditString&operator=(const PreEditString&) = delete;
|
|
|
|
PreEditString&operator=(PreEditString&&) = delete;
|
2015-06-07 21:19:26 +00:00
|
|
|
~PreEditString() {
|
|
|
|
g_free(str);
|
|
|
|
g_free(uniStr);
|
|
|
|
pango_attr_list_unref(attrs);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
gint ScintillaGTK::FocusInThis(GtkWidget *) {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
|
|
|
SetFocusState(true);
|
2021-02-21 04:53:09 +00:00
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
if (im_context) {
|
2022-01-04 23:07:50 +00:00
|
|
|
gtk_im_context_focus_in(im_context.get());
|
|
|
|
PreEditString pes(im_context.get());
|
2019-07-21 13:26:02 +00:00
|
|
|
if (PWidget(wPreedit)) {
|
2021-02-21 04:53:09 +00:00
|
|
|
if (!preeditInitialized) {
|
|
|
|
GtkWidget *top = gtk_widget_get_toplevel(PWidget(wMain));
|
|
|
|
gtk_window_set_transient_for(GTK_WINDOW(PWidget(wPreedit)), GTK_WINDOW(top));
|
|
|
|
preeditInitialized = true;
|
|
|
|
}
|
|
|
|
|
2015-06-07 21:19:26 +00:00
|
|
|
if (strlen(pes.str) > 0) {
|
2009-08-23 02:24:48 +00:00
|
|
|
gtk_widget_show(PWidget(wPreedit));
|
|
|
|
} else {
|
|
|
|
gtk_widget_hide(PWidget(wPreedit));
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
gint ScintillaGTK::FocusIn(GtkWidget *widget, GdkEventFocus * /*event*/) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-08-23 02:24:48 +00:00
|
|
|
return sciThis->FocusInThis(widget);
|
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
gint ScintillaGTK::FocusOutThis(GtkWidget *) {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
|
|
|
SetFocusState(false);
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
if (PWidget(wPreedit))
|
2009-08-23 02:24:48 +00:00
|
|
|
gtk_widget_hide(PWidget(wPreedit));
|
2019-07-21 13:26:02 +00:00
|
|
|
if (im_context)
|
2022-01-04 23:07:50 +00:00
|
|
|
gtk_im_context_focus_out(im_context.get());
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
gint ScintillaGTK::FocusOut(GtkWidget *widget, GdkEventFocus * /*event*/) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-08-23 02:24:48 +00:00
|
|
|
return sciThis->FocusOutThis(widget);
|
|
|
|
}
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
void ScintillaGTK::SizeRequest(GtkWidget *widget, GtkRequisition *requisition) {
|
Update: Scintilla 5.3.6 and Lexilla 5.2.6
update to Scinitlla Release 5.3.6 (https://www.scintilla.org/scintilla536.zip)
Released 26 July 2023.
Redraw calltip after showing as didn't update when size of new text exactly same as previous. Feature #1486.
On Win32 fix reverse arrow cursor when scaled. Bug #2382.
On Win32 hide cursor when typing if that system preference has been chosen. Bug #2333.
On Win32 and Qt, stop aligning IME candidate window to target. It is now always aligned to start of composition string. This undoes part of feature #1300. Feature #1488, Bug #2391, Feature #1300.
On Qt, for IMEs, update micro focus when selection changes. This may move the location of IME popups to align with the caret.
On Qt, implement replacement for IMEs which may help with actions like reconversion. This is similar to delete-surrounding on GTK.
and Lexilla Release 5.2.6 (https://www.scintilla.org/lexilla526.zip)
Released 26 July 2023.
Include empty word list names in value returned by DescribeWordListSets and SCI_DESCRIBEKEYWORDSETS. Issue #175, Pull request #176.
Bash: style here-doc end delimiters as SCE_SH_HERE_DELIM instead of SCE_SH_HERE_Q. Issue #177.
Bash: allow '$' as last character in string. Issue #180, Pull request #181.
Bash: fix state after expansion. Highlight all numeric and file test operators. Don't highlight dash in long option as operator. Issue #182, Pull request #183.
Bash: strict checking of special parameters ($*, $@, $$, ...) with property lexer.bash.special.parameter to specify valid parameters. Issue #184, Pull request #186.
Bash: recognize keyword before redirection operators (< and >). Issue #188, Pull request #189.
Errorlist: recognize Bash diagnostic messages.
HTML: allow ASP block to terminate inside line comment. Issue #185.
HTML: fix folding with JSP/ASP.NET <%-- comment. Issue #191.
HTML: fix incremental styling of multi-line ASP.NET directive. Issue #191.
Matlab: improve arguments blocks. Add support for multiple arguments blocks. Prevent "arguments" from being keyword in function declaration line. Fix semicolon handling. Pull request #179.
Visual Prolog: add support for embedded syntax with SCE_VISUALPROLOG_EMBEDDED and SCE_VISUALPROLOG_PLACEHOLDER.
Styling of string literals changed with no differentiation between literals with quotes and those that are prefixed with "@". Quote characters are in a separate style (SCE_VISUALPROLOG_STRING_QUOTE) to contents (SCE_VISUALPROLOG_STRING).
SCE_VISUALPROLOG_CHARACTER, SCE_VISUALPROLOG_CHARACTER_TOO_MANY, SCE_VISUALPROLOG_CHARACTER_ESCAPE_ERROR, SCE_VISUALPROLOG_STRING_EOL_OPEN, and SCE_VISUALPROLOG_STRING_VERBATIM_SPECIAL were removed (replaced with SCE_VISUALPROLOG_UNUSED[1-5]). Pull request #178.
Fix #13901, fix #13911, fix #13943, close #13940
2023-07-27 17:57:12 +00:00
|
|
|
const ScintillaGTK *sciThis = FromWidget(widget);
|
2011-07-17 22:30:49 +00:00
|
|
|
requisition->width = 1;
|
|
|
|
requisition->height = 1;
|
2009-04-24 23:35:41 +00:00
|
|
|
GtkRequisition child_requisition;
|
2011-07-17 22:30:49 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
2019-07-21 13:26:02 +00:00
|
|
|
gtk_widget_get_preferred_size(PWidget(sciThis->scrollbarh), nullptr, &child_requisition);
|
|
|
|
gtk_widget_get_preferred_size(PWidget(sciThis->scrollbarv), nullptr, &child_requisition);
|
2011-07-17 22:30:49 +00:00
|
|
|
#else
|
2009-04-24 23:35:41 +00:00
|
|
|
gtk_widget_size_request(PWidget(sciThis->scrollbarh), &child_requisition);
|
|
|
|
gtk_widget_size_request(PWidget(sciThis->scrollbarv), &child_requisition);
|
2011-07-17 22:30:49 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-08-28 00:44:27 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
|
2011-07-17 22:30:49 +00:00
|
|
|
void ScintillaGTK::GetPreferredWidth(GtkWidget *widget, gint *minimalWidth, gint *naturalWidth) {
|
|
|
|
GtkRequisition requisition;
|
|
|
|
SizeRequest(widget, &requisition);
|
|
|
|
*minimalWidth = *naturalWidth = requisition.width;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::GetPreferredHeight(GtkWidget *widget, gint *minimalHeight, gint *naturalHeight) {
|
|
|
|
GtkRequisition requisition;
|
|
|
|
SizeRequest(widget, &requisition);
|
|
|
|
*minimalHeight = *naturalHeight = requisition.height;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2013-08-28 00:44:27 +00:00
|
|
|
#endif
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
void ScintillaGTK::SizeAllocate(GtkWidget *widget, GtkAllocation *allocation) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
2011-07-17 22:30:49 +00:00
|
|
|
gtk_widget_set_allocation(widget, allocation);
|
2010-09-05 22:56:27 +00:00
|
|
|
if (IS_WIDGET_REALIZED(widget))
|
2011-07-17 22:30:49 +00:00
|
|
|
gdk_window_move_resize(WindowFromWidget(widget),
|
2019-07-21 13:26:02 +00:00
|
|
|
allocation->x,
|
|
|
|
allocation->y,
|
|
|
|
allocation->width,
|
|
|
|
allocation->height);
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
sciThis->Resize(allocation->width, allocation->height);
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
sciThis->errorStatus = Status::Failure;
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
void ScintillaGTK::Init() {
|
2021-02-21 04:53:09 +00:00
|
|
|
parentClass = static_cast<GtkWidgetClass *>(
|
2019-07-21 13:26:02 +00:00
|
|
|
g_type_class_ref(gtk_container_get_type()));
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
gint maskSmooth = 0;
|
|
|
|
#if defined(GDK_WINDOWING_WAYLAND)
|
|
|
|
GdkDisplay *pdisplay = gdk_display_get_default();
|
|
|
|
if (GDK_IS_WAYLAND_DISPLAY(pdisplay)) {
|
|
|
|
// On Wayland, touch pads only produce smooth scroll events
|
|
|
|
maskSmooth = GDK_SMOOTH_SCROLL_MASK;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-03-22 00:16:49 +00:00
|
|
|
gtk_widget_set_can_focus(PWidget(wMain), TRUE);
|
|
|
|
gtk_widget_set_sensitive(PWidget(wMain), TRUE);
|
2009-04-24 23:35:41 +00:00
|
|
|
gtk_widget_set_events(PWidget(wMain),
|
2019-07-21 13:26:02 +00:00
|
|
|
GDK_EXPOSURE_MASK
|
|
|
|
| GDK_SCROLL_MASK
|
|
|
|
| maskSmooth
|
|
|
|
| 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);
|
2009-04-24 23:35:41 +00:00
|
|
|
|
|
|
|
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);
|
2011-07-17 22:30:49 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
g_signal_connect(G_OBJECT(widtxt), "draw",
|
2019-07-21 13:26:02 +00:00
|
|
|
G_CALLBACK(ScintillaGTK::DrawText), this);
|
2011-07-17 22:30:49 +00:00
|
|
|
#else
|
2009-04-24 23:35:41 +00:00
|
|
|
g_signal_connect(G_OBJECT(widtxt), "expose_event",
|
2019-07-21 13:26:02 +00:00
|
|
|
G_CALLBACK(ScintillaGTK::ExposeText), this);
|
2011-07-17 22:30:49 +00:00
|
|
|
#endif
|
2015-06-07 21:19:26 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
// we need a runtime check because we don't want double buffering when
|
|
|
|
// running on >= 3.9.2
|
2019-07-21 13:26:02 +00:00
|
|
|
if (gtk_check_version(3, 9, 2) != nullptr /* on < 3.9.2 */)
|
2015-06-07 21:19:26 +00:00
|
|
|
#endif
|
|
|
|
{
|
|
|
|
#if !GTK_CHECK_VERSION(3,14,0)
|
|
|
|
// Avoid background drawing flash/missing redraws
|
|
|
|
gtk_widget_set_double_buffered(widtxt, FALSE);
|
|
|
|
#endif
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
gtk_widget_set_events(widtxt, GDK_EXPOSURE_MASK);
|
2010-09-05 22:56:27 +00:00
|
|
|
gtk_widget_set_size_request(widtxt, 100, 100);
|
2011-07-17 22:30:49 +00:00
|
|
|
adjustmentv = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 201.0, 1.0, 20.0, 20.0));
|
2013-08-28 00:44:27 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
scrollbarv = gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, GTK_ADJUSTMENT(adjustmentv));
|
|
|
|
#else
|
2009-04-24 23:35:41 +00:00
|
|
|
scrollbarv = gtk_vscrollbar_new(GTK_ADJUSTMENT(adjustmentv));
|
2013-08-28 00:44:27 +00:00
|
|
|
#endif
|
2011-03-22 00:16:49 +00:00
|
|
|
gtk_widget_set_can_focus(PWidget(scrollbarv), FALSE);
|
2009-04-24 23:35:41 +00:00
|
|
|
g_signal_connect(G_OBJECT(adjustmentv), "value_changed",
|
2019-07-21 13:26:02 +00:00
|
|
|
G_CALLBACK(ScrollSignal), this);
|
2009-04-24 23:35:41 +00:00
|
|
|
gtk_widget_set_parent(PWidget(scrollbarv), PWidget(wMain));
|
|
|
|
gtk_widget_show(PWidget(scrollbarv));
|
|
|
|
|
2011-07-17 22:30:49 +00:00
|
|
|
adjustmenth = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 101.0, 1.0, 20.0, 20.0));
|
2013-08-28 00:44:27 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
scrollbarh = gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, GTK_ADJUSTMENT(adjustmenth));
|
|
|
|
#else
|
2009-04-24 23:35:41 +00:00
|
|
|
scrollbarh = gtk_hscrollbar_new(GTK_ADJUSTMENT(adjustmenth));
|
2013-08-28 00:44:27 +00:00
|
|
|
#endif
|
2011-03-22 00:16:49 +00:00
|
|
|
gtk_widget_set_can_focus(PWidget(scrollbarh), FALSE);
|
2009-04-24 23:35:41 +00:00
|
|
|
g_signal_connect(G_OBJECT(adjustmenth), "value_changed",
|
2019-07-21 13:26:02 +00:00
|
|
|
G_CALLBACK(ScrollHSignal), this);
|
2009-04-24 23:35:41 +00:00
|
|
|
gtk_widget_set_parent(PWidget(scrollbarh), PWidget(wMain));
|
|
|
|
gtk_widget_show(PWidget(scrollbarh));
|
|
|
|
|
|
|
|
gtk_widget_grab_focus(PWidget(wMain));
|
|
|
|
|
|
|
|
gtk_drag_dest_set(GTK_WIDGET(PWidget(wMain)),
|
2019-07-21 13:26:02 +00:00
|
|
|
GTK_DEST_DEFAULT_ALL, clipboardPasteTargets, nClipboardPasteTargets,
|
|
|
|
actionCopyOrMove);
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2015-06-07 21:19:26 +00:00
|
|
|
/* create pre-edit window */
|
|
|
|
wPreedit = gtk_window_new(GTK_WINDOW_POPUP);
|
2023-09-22 09:32:35 +00:00
|
|
|
gtk_window_set_type_hint(GTK_WINDOW(PWidget(wPreedit)), GDK_WINDOW_TYPE_HINT_POPUP_MENU);
|
2015-06-07 21:19:26 +00:00
|
|
|
wPreeditDraw = gtk_drawing_area_new();
|
|
|
|
GtkWidget *predrw = PWidget(wPreeditDraw); // No code inside the G_OBJECT macro
|
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
g_signal_connect(G_OBJECT(predrw), "draw",
|
2019-07-21 13:26:02 +00:00
|
|
|
G_CALLBACK(DrawPreedit), this);
|
2015-06-07 21:19:26 +00:00
|
|
|
#else
|
|
|
|
g_signal_connect(G_OBJECT(predrw), "expose_event",
|
2019-07-21 13:26:02 +00:00
|
|
|
G_CALLBACK(ExposePreedit), this);
|
2015-06-07 21:19:26 +00:00
|
|
|
#endif
|
|
|
|
gtk_container_add(GTK_CONTAINER(PWidget(wPreedit)), predrw);
|
|
|
|
gtk_widget_show(predrw);
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
settings = gtk_settings_get_default();
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
// Set caret period based on GTK settings
|
|
|
|
gboolean blinkOn = false;
|
2022-01-04 23:07:50 +00:00
|
|
|
SettingGet(settings, "gtk-cursor-blink", &blinkOn);
|
|
|
|
if (blinkOn) {
|
|
|
|
gint value = 500;
|
|
|
|
if (SettingGet(settings, "gtk-cursor-blink-time", &value)) {
|
|
|
|
caret.period = static_cast<int>(value / 1.75);
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
} else {
|
|
|
|
caret.period = 0;
|
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
for (size_t tr = static_cast<size_t>(TickReason::caret); tr <= static_cast<size_t>(TickReason::dwell); tr++) {
|
|
|
|
timers[tr].reason = static_cast<TickReason>(tr);
|
2015-06-07 21:19:26 +00:00
|
|
|
timers[tr].scintilla = this;
|
|
|
|
}
|
2023-11-05 17:24:41 +00:00
|
|
|
|
|
|
|
vs.indicators[SC_INDICATOR_UNKNOWN] = Indicator(IndicatorStyle::Hidden, colourIME);
|
|
|
|
vs.indicators[SC_INDICATOR_INPUT] = Indicator(IndicatorStyle::Dots, colourIME);
|
|
|
|
vs.indicators[SC_INDICATOR_CONVERTED] = Indicator(IndicatorStyle::CompositionThick, colourIME);
|
|
|
|
vs.indicators[SC_INDICATOR_TARGET] = Indicator(IndicatorStyle::StraightBox, colourIME);
|
2022-01-04 23:07:50 +00:00
|
|
|
|
|
|
|
fontOptionsPrevious = FontOptions(PWidget(wText));
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::Finalise() {
|
2022-01-04 23:07:50 +00:00
|
|
|
for (size_t tr = static_cast<size_t>(TickReason::caret); tr <= static_cast<size_t>(TickReason::dwell); tr++) {
|
|
|
|
FineTickerCancel(static_cast<TickReason>(tr));
|
2015-06-07 21:19:26 +00:00
|
|
|
}
|
2019-05-04 18:14:48 +00:00
|
|
|
if (accessible) {
|
2019-07-21 13:26:02 +00:00
|
|
|
gtk_accessible_set_widget(GTK_ACCESSIBLE(accessible), nullptr);
|
2019-05-04 18:14:48 +00:00
|
|
|
g_object_unref(accessible);
|
2019-07-21 13:26:02 +00:00
|
|
|
accessible = nullptr;
|
2019-05-04 18:14:48 +00:00
|
|
|
}
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
ScintillaBase::Finalise();
|
|
|
|
}
|
|
|
|
|
2015-06-07 21:19:26 +00:00
|
|
|
bool ScintillaGTK::AbandonPaint() {
|
2022-01-04 23:07:50 +00:00
|
|
|
if ((paintState == PaintState::painting) && !paintingAllText) {
|
2015-06-07 21:19:26 +00:00
|
|
|
repaintFullWindow = true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
void ScintillaGTK::DisplayCursor(Window::Cursor c) {
|
2022-01-04 23:07:50 +00:00
|
|
|
if (cursorMode == CursorShape::Normal)
|
2009-04-24 23:35:41 +00:00
|
|
|
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)),
|
2022-01-04 23:07:50 +00:00
|
|
|
static_cast<gint>(ptStart.x), static_cast<gint>(ptStart.y),
|
|
|
|
static_cast<gint>(ptNow.x), static_cast<gint>(ptNow.y));
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::StartDrag() {
|
2019-05-04 18:14:48 +00:00
|
|
|
PLATFORM_ASSERT(evbtn);
|
2009-04-24 23:35:41 +00:00
|
|
|
dragWasDropped = false;
|
2022-01-04 23:07:50 +00:00
|
|
|
inDragDrop = DragDrop::dragging;
|
2009-04-24 23:35:41 +00:00
|
|
|
GtkTargetList *tl = gtk_target_list_new(clipboardCopyTargets, nClipboardCopyTargets);
|
2015-06-07 21:19:26 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,10,0)
|
|
|
|
gtk_drag_begin_with_coordinates(GTK_WIDGET(PWidget(wMain)),
|
2019-07-21 13:26:02 +00:00
|
|
|
tl,
|
|
|
|
actionCopyOrMove,
|
|
|
|
buttonMouse,
|
2022-01-04 23:07:50 +00:00
|
|
|
evbtn.get(),
|
2019-07-21 13:26:02 +00:00
|
|
|
-1, -1);
|
2015-06-07 21:19:26 +00:00
|
|
|
#else
|
2009-04-24 23:35:41 +00:00
|
|
|
gtk_drag_begin(GTK_WIDGET(PWidget(wMain)),
|
2019-07-21 13:26:02 +00:00
|
|
|
tl,
|
|
|
|
actionCopyOrMove,
|
|
|
|
buttonMouse,
|
2022-01-04 23:07:50 +00:00
|
|
|
evbtn.get());
|
2015-06-07 21:19:26 +00:00
|
|
|
#endif
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
namespace Scintilla::Internal {
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
std::string ConvertText(const char *s, size_t len, const char *charSetDest,
|
2019-07-21 13:26:02 +00:00
|
|
|
const char *charSetSource, bool transliterations, bool silent) {
|
2010-07-12 22:19:51 +00:00
|
|
|
// s is not const because of different versions of iconv disagreeing about const
|
2013-08-28 00:44:27 +00:00
|
|
|
std::string destForm;
|
2009-04-24 23:35:41 +00:00
|
|
|
Converter conv(charSetDest, charSetSource, transliterations);
|
|
|
|
if (conv) {
|
2019-05-04 18:14:48 +00:00
|
|
|
gsize outLeft = len*3+1;
|
2013-08-28 00:44:27 +00:00
|
|
|
destForm = std::string(outLeft, '\0');
|
|
|
|
// g_iconv does not actually write to its input argument so safe to cast away const
|
|
|
|
char *pin = const_cast<char *>(s);
|
2019-05-04 18:14:48 +00:00
|
|
|
gsize inLeft = len;
|
2013-08-28 00:44:27 +00:00
|
|
|
char *putf = &destForm[0];
|
|
|
|
char *pout = putf;
|
2019-07-21 13:26:02 +00:00
|
|
|
const gsize conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
|
2019-05-04 18:14:48 +00:00
|
|
|
if (conversions == sizeFailure) {
|
2013-08-28 00:44:27 +00:00
|
|
|
if (!silent) {
|
|
|
|
if (len == 1)
|
|
|
|
fprintf(stderr, "iconv %s->%s failed for %0x '%s'\n",
|
2022-01-04 23:07:50 +00:00
|
|
|
charSetSource, charSetDest, static_cast<unsigned char>(*s), s);
|
2013-08-28 00:44:27 +00:00
|
|
|
else
|
|
|
|
fprintf(stderr, "iconv %s->%s failed for %s\n",
|
|
|
|
charSetSource, charSetDest, s);
|
|
|
|
}
|
|
|
|
destForm = std::string();
|
2009-04-24 23:35:41 +00:00
|
|
|
} else {
|
2013-08-28 00:44:27 +00:00
|
|
|
destForm.resize(pout - putf);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
} else {
|
2013-08-28 00:44:27 +00:00
|
|
|
fprintf(stderr, "Can not iconv %s %s\n", charSetDest, charSetSource);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
return destForm;
|
|
|
|
}
|
2019-05-04 18:14:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
|
|
|
|
// Returns the target converted to UTF8.
|
|
|
|
// Return the length in bytes.
|
2019-05-04 18:14:48 +00:00
|
|
|
Sci::Position ScintillaGTK::TargetAsUTF8(char *text) const {
|
2021-02-21 04:53:09 +00:00
|
|
|
const Sci::Position targetLength = targetRange.Length();
|
2009-04-24 23:35:41 +00:00
|
|
|
if (IsUnicodeMode()) {
|
|
|
|
if (text) {
|
2021-02-21 04:53:09 +00:00
|
|
|
pdoc->GetCharRange(text, targetRange.start.Position(), targetLength);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Need to convert
|
|
|
|
const char *charSetBuffer = CharacterSetID();
|
|
|
|
if (*charSetBuffer) {
|
2021-02-21 04:53:09 +00:00
|
|
|
std::string s = RangeText(targetRange.start.Position(), targetRange.end.Position());
|
2013-08-28 00:44:27 +00:00
|
|
|
std::string tmputf = ConvertText(&s[0], targetLength, "UTF-8", charSetBuffer, false);
|
|
|
|
if (text) {
|
|
|
|
memcpy(text, tmputf.c_str(), tmputf.length());
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
2013-08-28 00:44:27 +00:00
|
|
|
return tmputf.length();
|
2009-04-24 23:35:41 +00:00
|
|
|
} else {
|
|
|
|
if (text) {
|
2021-02-21 04:53:09 +00:00
|
|
|
pdoc->GetCharRange(text, targetRange.start.Position(), targetLength);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return targetLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Translates a nul terminated UTF8 string into the document encoding.
|
|
|
|
// Return the length of the result in bytes.
|
2019-05-04 18:14:48 +00:00
|
|
|
Sci::Position ScintillaGTK::EncodedFromUTF8(const char *utf8, char *encoded) const {
|
2019-07-21 13:26:02 +00:00
|
|
|
const Sci::Position inputLength = (lengthForEncode >= 0) ? lengthForEncode : strlen(utf8);
|
2009-04-24 23:35:41 +00:00
|
|
|
if (IsUnicodeMode()) {
|
|
|
|
if (encoded) {
|
|
|
|
memcpy(encoded, utf8, inputLength);
|
|
|
|
}
|
|
|
|
return inputLength;
|
|
|
|
} else {
|
|
|
|
// Need to convert
|
|
|
|
const char *charSetBuffer = CharacterSetID();
|
|
|
|
if (*charSetBuffer) {
|
2013-08-28 00:44:27 +00:00
|
|
|
std::string tmpEncoded = ConvertText(utf8, inputLength, charSetBuffer, "UTF-8", true);
|
|
|
|
if (encoded) {
|
|
|
|
memcpy(encoded, tmpEncoded.c_str(), tmpEncoded.length());
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
2013-08-28 00:44:27 +00:00
|
|
|
return tmpEncoded.length();
|
2009-04-24 23:35:41 +00:00
|
|
|
} else {
|
|
|
|
if (encoded) {
|
|
|
|
memcpy(encoded, utf8, inputLength);
|
|
|
|
}
|
|
|
|
return inputLength;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Fail
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScintillaGTK::ValidCodePage(int codePage) const {
|
2010-07-12 22:19:51 +00:00
|
|
|
return codePage == 0
|
2019-07-21 13:26:02 +00:00
|
|
|
|| codePage == SC_CP_UTF8
|
|
|
|
|| codePage == 932
|
|
|
|
|| codePage == 936
|
|
|
|
|| codePage == 949
|
|
|
|
|| codePage == 950
|
|
|
|
|| codePage == 1361;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
std::string ScintillaGTK::UTF8FromEncoded(std::string_view encoded) const {
|
|
|
|
if (IsUnicodeMode()) {
|
|
|
|
return std::string(encoded);
|
|
|
|
} else {
|
|
|
|
const char *charSetBuffer = CharacterSetID();
|
|
|
|
return ConvertText(encoded.data(), encoded.length(), "UTF-8", charSetBuffer, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string ScintillaGTK::EncodedFromUTF8(std::string_view utf8) const {
|
|
|
|
if (IsUnicodeMode()) {
|
|
|
|
return std::string(utf8);
|
|
|
|
} else {
|
|
|
|
const char *charSetBuffer = CharacterSetID();
|
|
|
|
return ConvertText(utf8.data(), utf8.length(), charSetBuffer, "UTF-8", true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sptr_t ScintillaGTK::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
|
|
|
switch (iMessage) {
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
case Message::GrabFocus:
|
2009-08-23 02:24:48 +00:00
|
|
|
gtk_widget_grab_focus(PWidget(wMain));
|
|
|
|
break;
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
case Message::GetDirectFunction:
|
2009-08-23 02:24:48 +00:00
|
|
|
return reinterpret_cast<sptr_t>(DirectFunction);
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
case Message::GetDirectStatusFunction:
|
|
|
|
return reinterpret_cast<sptr_t>(DirectStatusFunction);
|
|
|
|
|
|
|
|
case Message::GetDirectPointer:
|
2009-08-23 02:24:48 +00:00
|
|
|
return reinterpret_cast<sptr_t>(this);
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
case Message::TargetAsUTF8:
|
2019-05-04 18:14:48 +00:00
|
|
|
return TargetAsUTF8(CharPtrFromSPtr(lParam));
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
case Message::EncodedFromUTF8:
|
2019-05-04 18:14:48 +00:00
|
|
|
return EncodedFromUTF8(ConstCharPtrFromUPtr(wParam),
|
2019-07-21 13:26:02 +00:00
|
|
|
CharPtrFromSPtr(lParam));
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
case Message::SetRectangularSelectionModifier:
|
|
|
|
rectangularSelectionModifier = static_cast<int>(wParam);
|
2009-08-23 02:24:48 +00:00
|
|
|
break;
|
2010-07-12 22:19:51 +00:00
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
case Message::GetRectangularSelectionModifier:
|
2009-08-23 02:24:48 +00:00
|
|
|
return rectangularSelectionModifier;
|
2010-07-12 22:19:51 +00:00
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
case Message::SetReadOnly: {
|
2019-07-21 13:26:02 +00:00
|
|
|
const sptr_t ret = ScintillaBase::WndProc(iMessage, wParam, lParam);
|
|
|
|
if (accessible) {
|
|
|
|
ScintillaGTKAccessible *sciAccessible = ScintillaGTKAccessible::FromAccessible(accessible);
|
|
|
|
if (sciAccessible) {
|
|
|
|
sciAccessible->NotifyReadOnly();
|
|
|
|
}
|
2019-05-04 18:14:48 +00:00
|
|
|
}
|
2019-07-21 13:26:02 +00:00
|
|
|
return ret;
|
2019-05-04 18:14:48 +00:00
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
case Message::GetAccessibility:
|
2019-05-04 18:14:48 +00:00
|
|
|
return accessibilityEnabled;
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
case Message::SetAccessibility:
|
|
|
|
accessibilityEnabled = static_cast<int>(wParam);
|
2019-05-04 18:14:48 +00:00
|
|
|
if (accessible) {
|
|
|
|
ScintillaGTKAccessible *sciAccessible = ScintillaGTKAccessible::FromAccessible(accessible);
|
|
|
|
if (sciAccessible) {
|
2019-07-21 13:26:02 +00:00
|
|
|
sciAccessible->SetAccessibility(accessibilityEnabled);
|
2019-05-04 18:14:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
default:
|
|
|
|
return ScintillaBase::WndProc(iMessage, wParam, lParam);
|
|
|
|
}
|
2019-07-21 13:26:02 +00:00
|
|
|
} catch (std::bad_alloc &) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::BadAlloc;
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
2019-05-04 18:14:48 +00:00
|
|
|
return 0;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
sptr_t ScintillaGTK::DefWndProc(Message, uptr_t, sptr_t) {
|
2009-04-24 23:35:41 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-07 21:19:26 +00:00
|
|
|
bool ScintillaGTK::FineTickerRunning(TickReason reason) {
|
2022-01-04 23:07:50 +00:00
|
|
|
return timers[static_cast<size_t>(reason)].timer != 0;
|
2015-06-07 21:19:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::FineTickerStart(TickReason reason, int millis, int /* tolerance */) {
|
|
|
|
FineTickerCancel(reason);
|
2022-01-04 23:07:50 +00:00
|
|
|
const size_t reasonIndex = static_cast<size_t>(reason);
|
|
|
|
timers[reasonIndex].timer = gdk_threads_add_timeout(millis, TimeOut, &timers[reasonIndex]);
|
2015-06-07 21:19:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::FineTickerCancel(TickReason reason) {
|
2022-01-04 23:07:50 +00:00
|
|
|
const size_t reasonIndex = static_cast<size_t>(reason);
|
|
|
|
if (timers[reasonIndex].timer) {
|
|
|
|
g_source_remove(timers[reasonIndex].timer);
|
|
|
|
timers[reasonIndex].timer = 0;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScintillaGTK::SetIdle(bool on) {
|
|
|
|
if (on) {
|
|
|
|
// Start idler, if it's not running.
|
2010-07-12 22:19:51 +00:00
|
|
|
if (!idler.state) {
|
2009-04-24 23:35:41 +00:00
|
|
|
idler.state = true;
|
2019-05-04 18:14:48 +00:00
|
|
|
idler.idlerID = GUINT_TO_POINTER(
|
2019-07-21 13:26:02 +00:00
|
|
|
gdk_threads_add_idle_full(G_PRIORITY_DEFAULT_IDLE, IdleCallback, this, nullptr));
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Stop idler, if it's running
|
2010-07-12 22:19:51 +00:00
|
|
|
if (idler.state) {
|
2009-04-24 23:35:41 +00:00
|
|
|
idler.state = false;
|
2010-07-12 22:19:51 +00:00
|
|
|
g_source_remove(GPOINTER_TO_UINT(idler.idlerID));
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2011-07-17 22:30:49 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
namespace {
|
|
|
|
|
2011-07-17 22:30:49 +00:00
|
|
|
// Is crcTest completely in crcContainer?
|
2022-01-04 23:07:50 +00:00
|
|
|
bool CRectContains(const cairo_rectangle_t &crcContainer, const cairo_rectangle_t &crcTest) {
|
2011-07-17 22:30:49 +00:00
|
|
|
return
|
|
|
|
(crcTest.x >= crcContainer.x) && ((crcTest.x + crcTest.width) <= (crcContainer.x + crcContainer.width)) &&
|
|
|
|
(crcTest.y >= crcContainer.y) && ((crcTest.y + crcTest.height) <= (crcContainer.y + crcContainer.height));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Is crcTest completely in crcListContainer?
|
|
|
|
// May incorrectly return false if complex shape
|
2022-01-04 23:07:50 +00:00
|
|
|
bool CRectListContains(const cairo_rectangle_list_t *crcListContainer, const cairo_rectangle_t &crcTest) {
|
2011-07-17 22:30:49 +00:00
|
|
|
for (int r=0; r<crcListContainer->num_rectangles; r++) {
|
|
|
|
if (CRectContains(crcListContainer->rectangles[r], crcTest))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
}
|
|
|
|
|
2011-07-17 22:30:49 +00:00
|
|
|
#endif
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
bool ScintillaGTK::PaintContains(PRectangle rc) {
|
2011-07-17 22:30:49 +00:00
|
|
|
// This allows optimization when a rectangle is completely in the update region.
|
|
|
|
// It is OK to return false when too difficult to determine as that just performs extra drawing
|
2009-04-24 23:35:41 +00:00
|
|
|
bool contains = true;
|
2022-01-04 23:07:50 +00:00
|
|
|
if (paintState == PaintState::painting) {
|
2009-04-24 23:35:41 +00:00
|
|
|
if (!rcPaint.Contains(rc)) {
|
|
|
|
contains = false;
|
|
|
|
} else if (rgnUpdate) {
|
2011-07-17 22:30:49 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
cairo_rectangle_t grc = {rc.left, rc.top,
|
2019-07-21 13:26:02 +00:00
|
|
|
rc.right - rc.left, rc.bottom - rc.top
|
|
|
|
};
|
2011-07-17 22:30:49 +00:00
|
|
|
contains = CRectListContains(rgnUpdate, grc);
|
|
|
|
#else
|
2013-08-28 00:44:27 +00:00
|
|
|
GdkRectangle grc = {static_cast<gint>(rc.left), static_cast<gint>(rc.top),
|
2019-07-21 13:26:02 +00:00
|
|
|
static_cast<gint>(rc.right - rc.left), static_cast<gint>(rc.bottom - rc.top)
|
|
|
|
};
|
2009-04-24 23:35:41 +00:00
|
|
|
if (gdk_region_rect_in(rgnUpdate, &grc) != GDK_OVERLAP_RECTANGLE_IN) {
|
|
|
|
contains = false;
|
|
|
|
}
|
2011-07-17 22:30:49 +00:00
|
|
|
#endif
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return contains;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Redraw all of text area. This paint will not be abandoned.
|
|
|
|
void ScintillaGTK::FullPaint() {
|
|
|
|
wText.InvalidateAll();
|
|
|
|
}
|
|
|
|
|
Update scintilla 5.3.4 and lexilla 5.2.4 with:
https://www.scintilla.org/scintilla534.zip
Released 8 March 2023.
Add multithreaded wrap to significantly improve performance of wrapping large files.
More typesafe bindings of *Full APIs in ScintillaCall. Feature #1477.
Fix overlapping of text with line end wrap marker. Bug #2378.
Fix clipping of line end wrap symbol for SC_WRAPVISUALFLAGLOC_END_BY_TEXT.
Where a multi-byte character contains multiple styles, display each byte as a representation. This makes it easier to see and fix lexers that change styles mid-character, commonly because they use fixed size buffers.
Fix a potential crash with autocompletion list fill-ups where a SCN_CHARADDED handler retriggered an autocompletion list, but with no items that match the typed character.
lexilla523
Released 8 March 2023.
Add scripts/PromoteNew.bat script to promote .new files after checking.
Makefile: Remove 1024-byte line length limit..
Ruby: Add new lexical classes for % literals SCE_RB_STRING_W (%w non-interpolable string array), SCE_RB_STRING_I (%i non-interpolable symbol array), SCE_RB_STRING_QI (%I interpolable symbol array), and SCE_RB_STRING_QS (%s symbol). Issue #124.
Ruby: Disambiguate %= which may be a quote or modulo assignment. Issue #124, Bug #1255, Bug #2182.
Ruby: Fix additional fold level for single character in SCE_RB_STRING_QW. Issue #132.
Ruby: Set SCE_RB_HERE_QQ for unquoted and double-quoted heredocs and SCE_RB_HERE_QX for backticks-quoted heredocs. Issue #134.
Ruby: Recognise #{} inside SCE_RB_HERE_QQ and SCE_RB_HERE_QX. Issue #134.
Ruby: Improve regex and heredoc recognition. Issue #136.
Ruby: Highlight #@, #@@ and #$ style interpolation. Issue #140.
Ruby: Fix folding for multiple heredocs started on one line. Fix folding when there is a space after heredoc opening delimiter. Issue #135.
YAML: Remove 1024-byte line length limit.
https://www.scintilla.org/lexilla524.zip
Released 13 March 2023.
C++: Fix failure to recognize keywords containing upper case. Issue #149.
GDScript: Support % and $ node paths. Issue #145, Pull request #146.
Close #13338
2023-03-10 02:37:21 +00:00
|
|
|
void ScintillaGTK::SetClientRectangle() {
|
|
|
|
rectangleClient = wMain.GetClientPosition();
|
|
|
|
}
|
|
|
|
|
2015-06-07 21:19:26 +00:00
|
|
|
PRectangle ScintillaGTK::GetClientRectangle() const {
|
Update scintilla 5.3.4 and lexilla 5.2.4 with:
https://www.scintilla.org/scintilla534.zip
Released 8 March 2023.
Add multithreaded wrap to significantly improve performance of wrapping large files.
More typesafe bindings of *Full APIs in ScintillaCall. Feature #1477.
Fix overlapping of text with line end wrap marker. Bug #2378.
Fix clipping of line end wrap symbol for SC_WRAPVISUALFLAGLOC_END_BY_TEXT.
Where a multi-byte character contains multiple styles, display each byte as a representation. This makes it easier to see and fix lexers that change styles mid-character, commonly because they use fixed size buffers.
Fix a potential crash with autocompletion list fill-ups where a SCN_CHARADDED handler retriggered an autocompletion list, but with no items that match the typed character.
lexilla523
Released 8 March 2023.
Add scripts/PromoteNew.bat script to promote .new files after checking.
Makefile: Remove 1024-byte line length limit..
Ruby: Add new lexical classes for % literals SCE_RB_STRING_W (%w non-interpolable string array), SCE_RB_STRING_I (%i non-interpolable symbol array), SCE_RB_STRING_QI (%I interpolable symbol array), and SCE_RB_STRING_QS (%s symbol). Issue #124.
Ruby: Disambiguate %= which may be a quote or modulo assignment. Issue #124, Bug #1255, Bug #2182.
Ruby: Fix additional fold level for single character in SCE_RB_STRING_QW. Issue #132.
Ruby: Set SCE_RB_HERE_QQ for unquoted and double-quoted heredocs and SCE_RB_HERE_QX for backticks-quoted heredocs. Issue #134.
Ruby: Recognise #{} inside SCE_RB_HERE_QQ and SCE_RB_HERE_QX. Issue #134.
Ruby: Improve regex and heredoc recognition. Issue #136.
Ruby: Highlight #@, #@@ and #$ style interpolation. Issue #140.
Ruby: Fix folding for multiple heredocs started on one line. Fix folding when there is a space after heredoc opening delimiter. Issue #135.
YAML: Remove 1024-byte line length limit.
https://www.scintilla.org/lexilla524.zip
Released 13 March 2023.
C++: Fix failure to recognize keywords containing upper case. Issue #149.
GDScript: Support % and $ node paths. Issue #145, Pull request #146.
Close #13338
2023-03-10 02:37:21 +00:00
|
|
|
PRectangle rc = rectangleClient;
|
2009-04-24 23:35:41 +00:00
|
|
|
if (verticalScrollBarVisible)
|
2013-08-28 00:44:27 +00:00
|
|
|
rc.right -= verticalScrollBarWidth;
|
2015-06-07 21:19:26 +00:00
|
|
|
if (horizontalScrollBarVisible && !Wrapping())
|
2013-08-28 00:44:27 +00:00
|
|
|
rc.bottom -= horizontalScrollBarHeight;
|
2009-04-24 23:35:41 +00:00
|
|
|
// Move to origin
|
|
|
|
rc.right -= rc.left;
|
|
|
|
rc.bottom -= rc.top;
|
2019-05-04 18:14:48 +00:00
|
|
|
if (rc.bottom < 0)
|
|
|
|
rc.bottom = 0;
|
|
|
|
if (rc.right < 0)
|
|
|
|
rc.right = 0;
|
2009-04-24 23:35:41 +00:00
|
|
|
rc.left = 0;
|
|
|
|
rc.top = 0;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
void ScintillaGTK::ScrollText(Sci::Line linesToMove) {
|
2013-08-28 00:44:27 +00:00
|
|
|
NotifyUpdateUI();
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,22,0)
|
|
|
|
Redraw();
|
|
|
|
#else
|
|
|
|
GtkWidget *wi = PWidget(wText);
|
2013-08-28 00:44:27 +00:00
|
|
|
if (IS_WIDGET_REALIZED(wi)) {
|
2022-01-04 23:07:50 +00:00
|
|
|
const Sci::Line diff = vs.lineHeight * -linesToMove;
|
|
|
|
gdk_window_scroll(WindowFromWidget(wi), 0, static_cast<gint>(-diff));
|
2013-08-28 00:44:27 +00:00
|
|
|
gdk_window_process_updates(WindowFromWidget(wi), FALSE);
|
|
|
|
}
|
2019-05-04 18:14:48 +00:00
|
|
|
#endif
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::SetVerticalScrollPos() {
|
|
|
|
DwellEnd(true);
|
2022-01-04 23:07:50 +00:00
|
|
|
gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmentv), static_cast<gdouble>(topLine));
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::SetHorizontalScrollPos() {
|
|
|
|
DwellEnd(true);
|
2015-06-07 21:19:26 +00:00
|
|
|
gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmenth), xOffset);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
bool ScintillaGTK::ModifyScrollBars(Sci::Line nMax, Sci::Line nPage) {
|
2009-04-24 23:35:41 +00:00
|
|
|
bool modified = false;
|
2022-01-04 23:07:50 +00:00
|
|
|
const int pageScroll = static_cast<int>(LinesToScroll());
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2011-07-17 22:30:49 +00:00
|
|
|
if (gtk_adjustment_get_upper(adjustmentv) != (nMax + 1) ||
|
2019-07-21 13:26:02 +00:00
|
|
|
gtk_adjustment_get_page_size(adjustmentv) != nPage ||
|
|
|
|
gtk_adjustment_get_page_increment(adjustmentv) != pageScroll) {
|
2022-01-04 23:07:50 +00:00
|
|
|
gtk_adjustment_set_upper(adjustmentv, nMax + 1.0);
|
|
|
|
gtk_adjustment_set_page_size(adjustmentv, static_cast<gdouble>(nPage));
|
2019-07-21 13:26:02 +00:00
|
|
|
gtk_adjustment_set_page_increment(adjustmentv, pageScroll);
|
2019-05-04 18:14:48 +00:00
|
|
|
#if !GTK_CHECK_VERSION(3,18,0)
|
2011-07-17 22:30:49 +00:00
|
|
|
gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmentv));
|
2019-05-04 18:14:48 +00:00
|
|
|
#endif
|
2022-05-25 20:16:39 +00:00
|
|
|
gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmentv), static_cast<gdouble>(topLine));
|
2011-07-17 22:30:49 +00:00
|
|
|
modified = true;
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
const PRectangle rcText = GetTextRectangle();
|
2009-04-24 23:35:41 +00:00
|
|
|
int horizEndPreferred = scrollWidth;
|
|
|
|
if (horizEndPreferred < 0)
|
|
|
|
horizEndPreferred = 0;
|
2019-07-21 13:26:02 +00:00
|
|
|
const unsigned int pageWidth = static_cast<unsigned int>(rcText.Width());
|
|
|
|
const unsigned int pageIncrement = pageWidth / 3;
|
2022-01-04 23:07:50 +00:00
|
|
|
const unsigned int charWidth = static_cast<unsigned int>(vs.styles[STYLE_DEFAULT].aveCharWidth);
|
2011-07-17 22:30:49 +00:00
|
|
|
if (gtk_adjustment_get_upper(adjustmenth) != horizEndPreferred ||
|
2019-07-21 13:26:02 +00:00
|
|
|
gtk_adjustment_get_page_size(adjustmenth) != pageWidth ||
|
|
|
|
gtk_adjustment_get_page_increment(adjustmenth) != pageIncrement ||
|
|
|
|
gtk_adjustment_get_step_increment(adjustmenth) != charWidth) {
|
2011-07-17 22:30:49 +00:00
|
|
|
gtk_adjustment_set_upper(adjustmenth, horizEndPreferred);
|
2019-07-21 13:26:02 +00:00
|
|
|
gtk_adjustment_set_page_size(adjustmenth, pageWidth);
|
|
|
|
gtk_adjustment_set_page_increment(adjustmenth, pageIncrement);
|
|
|
|
gtk_adjustment_set_step_increment(adjustmenth, charWidth);
|
2019-05-04 18:14:48 +00:00
|
|
|
#if !GTK_CHECK_VERSION(3,18,0)
|
2011-07-17 22:30:49 +00:00
|
|
|
gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmenth));
|
2019-05-04 18:14:48 +00:00
|
|
|
#endif
|
2022-05-25 20:16:39 +00:00
|
|
|
gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmenth), xOffset);
|
2011-07-17 22:30:49 +00:00
|
|
|
modified = true;
|
|
|
|
}
|
2022-01-04 23:07:50 +00:00
|
|
|
if (modified && (paintState == PaintState::painting)) {
|
2015-06-07 21:19:26 +00:00
|
|
|
repaintFullWindow = true;
|
2013-08-28 00:44:27 +00:00
|
|
|
}
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
return modified;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::ReconfigureScrollBars() {
|
2019-07-21 13:26:02 +00:00
|
|
|
const PRectangle rc = wMain.GetClientPosition();
|
|
|
|
Resize(static_cast<int>(rc.Width()), static_cast<int>(rc.Height()));
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2022-05-25 20:16:39 +00:00
|
|
|
void ScintillaGTK::SetScrollBars() {
|
|
|
|
if (scrollBarIdleID) {
|
|
|
|
// Only allow one scroll bar change to be queued
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
constexpr gint priorityScrollBar = GDK_PRIORITY_REDRAW + 5;
|
|
|
|
// On GTK, unlike other platforms, modifying scrollbars inside some events including
|
|
|
|
// resizes causes problems. Deferring the modification to a lower priority (125) idle
|
|
|
|
// event avoids the problems. This code did not always work when the priority was
|
Update: Scintilla 5.3.6 and Lexilla 5.2.6
update to Scinitlla Release 5.3.6 (https://www.scintilla.org/scintilla536.zip)
Released 26 July 2023.
Redraw calltip after showing as didn't update when size of new text exactly same as previous. Feature #1486.
On Win32 fix reverse arrow cursor when scaled. Bug #2382.
On Win32 hide cursor when typing if that system preference has been chosen. Bug #2333.
On Win32 and Qt, stop aligning IME candidate window to target. It is now always aligned to start of composition string. This undoes part of feature #1300. Feature #1488, Bug #2391, Feature #1300.
On Qt, for IMEs, update micro focus when selection changes. This may move the location of IME popups to align with the caret.
On Qt, implement replacement for IMEs which may help with actions like reconversion. This is similar to delete-surrounding on GTK.
and Lexilla Release 5.2.6 (https://www.scintilla.org/lexilla526.zip)
Released 26 July 2023.
Include empty word list names in value returned by DescribeWordListSets and SCI_DESCRIBEKEYWORDSETS. Issue #175, Pull request #176.
Bash: style here-doc end delimiters as SCE_SH_HERE_DELIM instead of SCE_SH_HERE_Q. Issue #177.
Bash: allow '$' as last character in string. Issue #180, Pull request #181.
Bash: fix state after expansion. Highlight all numeric and file test operators. Don't highlight dash in long option as operator. Issue #182, Pull request #183.
Bash: strict checking of special parameters ($*, $@, $$, ...) with property lexer.bash.special.parameter to specify valid parameters. Issue #184, Pull request #186.
Bash: recognize keyword before redirection operators (< and >). Issue #188, Pull request #189.
Errorlist: recognize Bash diagnostic messages.
HTML: allow ASP block to terminate inside line comment. Issue #185.
HTML: fix folding with JSP/ASP.NET <%-- comment. Issue #191.
HTML: fix incremental styling of multi-line ASP.NET directive. Issue #191.
Matlab: improve arguments blocks. Add support for multiple arguments blocks. Prevent "arguments" from being keyword in function declaration line. Fix semicolon handling. Pull request #179.
Visual Prolog: add support for embedded syntax with SCE_VISUALPROLOG_EMBEDDED and SCE_VISUALPROLOG_PLACEHOLDER.
Styling of string literals changed with no differentiation between literals with quotes and those that are prefixed with "@". Quote characters are in a separate style (SCE_VISUALPROLOG_STRING_QUOTE) to contents (SCE_VISUALPROLOG_STRING).
SCE_VISUALPROLOG_CHARACTER, SCE_VISUALPROLOG_CHARACTER_TOO_MANY, SCE_VISUALPROLOG_CHARACTER_ESCAPE_ERROR, SCE_VISUALPROLOG_STRING_EOL_OPEN, and SCE_VISUALPROLOG_STRING_VERBATIM_SPECIAL were removed (replaced with SCE_VISUALPROLOG_UNUSED[1-5]). Pull request #178.
Fix #13901, fix #13911, fix #13943, close #13940
2023-07-27 17:57:12 +00:00
|
|
|
// higher than GTK's resize (GTK_PRIORITY_RESIZE=110) or redraw
|
2022-05-25 20:16:39 +00:00
|
|
|
// (GDK_PRIORITY_REDRAW=120) idle tasks.
|
|
|
|
scrollBarIdleID = gdk_threads_add_idle_full(priorityScrollBar,
|
|
|
|
[](gpointer pSci) -> gboolean {
|
|
|
|
ScintillaGTK *sciThis = static_cast<ScintillaGTK *>(pSci);
|
|
|
|
sciThis->ChangeScrollBars();
|
|
|
|
sciThis->scrollBarIdleID = 0;
|
|
|
|
return FALSE;
|
|
|
|
},
|
|
|
|
this, nullptr);
|
|
|
|
}
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
void ScintillaGTK::NotifyChange() {
|
|
|
|
g_signal_emit(G_OBJECT(sci), scintilla_signals[COMMAND_SIGNAL], 0,
|
2019-07-21 13:26:02 +00:00
|
|
|
Platform::LongFromTwoShorts(GetCtrlID(), SCEN_CHANGE), PWidget(wMain));
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::NotifyFocus(bool focus) {
|
2019-05-04 18:14:48 +00:00
|
|
|
if (commandEvents)
|
|
|
|
g_signal_emit(G_OBJECT(sci), scintilla_signals[COMMAND_SIGNAL], 0,
|
2019-07-21 13:26:02 +00:00
|
|
|
Platform::LongFromTwoShorts
|
|
|
|
(GetCtrlID(), focus ? SCEN_SETFOCUS : SCEN_KILLFOCUS), PWidget(wMain));
|
2015-06-07 21:19:26 +00:00
|
|
|
Editor::NotifyFocus(focus);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
void ScintillaGTK::NotifyParent(NotificationData scn) {
|
2009-04-24 23:35:41 +00:00
|
|
|
scn.nmhdr.hwndFrom = PWidget(wMain);
|
|
|
|
scn.nmhdr.idFrom = GetCtrlID();
|
|
|
|
g_signal_emit(G_OBJECT(sci), scintilla_signals[NOTIFY_SIGNAL], 0,
|
2019-07-21 13:26:02 +00:00
|
|
|
GetCtrlID(), &scn);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
void ScintillaGTK::NotifyKey(Keys key, KeyMod modifiers) {
|
|
|
|
NotificationData scn = {};
|
|
|
|
scn.nmhdr.code = Notification::Key;
|
|
|
|
scn.ch = static_cast<int>(key);
|
2009-04-24 23:35:41 +00:00
|
|
|
scn.modifiers = modifiers;
|
|
|
|
|
|
|
|
NotifyParent(scn);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::NotifyURIDropped(const char *list) {
|
2022-01-04 23:07:50 +00:00
|
|
|
NotificationData scn = {};
|
|
|
|
scn.nmhdr.code = Notification::URIDropped;
|
2009-04-24 23:35:41 +00:00
|
|
|
scn.text = list;
|
|
|
|
|
|
|
|
NotifyParent(scn);
|
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
const char *CharacterSetID(CharacterSet characterSet);
|
2009-04-24 23:35:41 +00:00
|
|
|
|
|
|
|
const char *ScintillaGTK::CharacterSetID() const {
|
|
|
|
return ::CharacterSetID(vs.styles[STYLE_DEFAULT].characterSet);
|
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
namespace {
|
|
|
|
|
2010-09-05 22:56:27 +00:00
|
|
|
class CaseFolderDBCS : public CaseFolderTable {
|
|
|
|
const char *charSet;
|
|
|
|
public:
|
2022-01-04 23:07:50 +00:00
|
|
|
explicit CaseFolderDBCS(const char *charSet_) noexcept : charSet(charSet_) {
|
2010-09-05 22:56:27 +00:00
|
|
|
}
|
2019-05-04 18:14:48 +00:00
|
|
|
size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) override {
|
2010-09-05 22:56:27 +00:00
|
|
|
if ((lenMixed == 1) && (sizeFolded > 0)) {
|
|
|
|
folded[0] = mapping[static_cast<unsigned char>(mixed[0])];
|
|
|
|
return 1;
|
|
|
|
} else if (*charSet) {
|
2013-08-28 00:44:27 +00:00
|
|
|
std::string sUTF8 = ConvertText(mixed, lenMixed,
|
2019-07-21 13:26:02 +00:00
|
|
|
"UTF-8", charSet, false);
|
2013-08-28 00:44:27 +00:00
|
|
|
if (!sUTF8.empty()) {
|
2022-01-04 23:07:50 +00:00
|
|
|
UniqueStr mapped(g_utf8_casefold(sUTF8.c_str(), sUTF8.length()));
|
|
|
|
size_t lenMapped = strlen(mapped.get());
|
2010-09-05 22:56:27 +00:00
|
|
|
if (lenMapped < sizeFolded) {
|
2022-01-04 23:07:50 +00:00
|
|
|
memcpy(folded, mapped.get(), lenMapped);
|
2010-09-05 22:56:27 +00:00
|
|
|
} else {
|
|
|
|
folded[0] = '\0';
|
|
|
|
lenMapped = 1;
|
|
|
|
}
|
|
|
|
return lenMapped;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Something failed so return a single NUL byte
|
|
|
|
folded[0] = '\0';
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<CaseFolder> ScintillaGTK::CaseFolderForEncoding() {
|
2010-07-12 22:19:51 +00:00
|
|
|
if (pdoc->dbcsCodePage == SC_CP_UTF8) {
|
2022-01-04 23:07:50 +00:00
|
|
|
return std::make_unique<CaseFolderUnicode>();
|
2010-07-12 22:19:51 +00:00
|
|
|
} else {
|
|
|
|
const char *charSetBuffer = CharacterSetID();
|
2010-09-05 22:56:27 +00:00
|
|
|
if (charSetBuffer) {
|
|
|
|
if (pdoc->dbcsCodePage == 0) {
|
2022-01-04 23:07:50 +00:00
|
|
|
std::unique_ptr<CaseFolderTable> pcf = std::make_unique<CaseFolderTable>();
|
2010-09-05 22:56:27 +00:00
|
|
|
// Only for single byte encodings
|
|
|
|
for (int i=0x80; i<0x100; i++) {
|
|
|
|
char sCharacter[2] = "A";
|
|
|
|
sCharacter[0] = i;
|
2013-08-28 00:44:27 +00:00
|
|
|
// Silent as some bytes have no assigned character
|
|
|
|
std::string sUTF8 = ConvertText(sCharacter, 1,
|
2019-07-21 13:26:02 +00:00
|
|
|
"UTF-8", charSetBuffer, false, true);
|
2013-08-28 00:44:27 +00:00
|
|
|
if (!sUTF8.empty()) {
|
2022-01-04 23:07:50 +00:00
|
|
|
UniqueStr mapped(g_utf8_casefold(sUTF8.c_str(), sUTF8.length()));
|
2010-09-05 22:56:27 +00:00
|
|
|
if (mapped) {
|
2022-01-04 23:07:50 +00:00
|
|
|
std::string mappedBack = ConvertText(mapped.get(), strlen(mapped.get()),
|
2019-07-21 13:26:02 +00:00
|
|
|
charSetBuffer, "UTF-8", false, true);
|
2013-08-28 00:44:27 +00:00
|
|
|
if ((mappedBack.length() == 1) && (mappedBack[0] != sCharacter[0])) {
|
2010-09-05 22:56:27 +00:00
|
|
|
pcf->SetTranslation(sCharacter[0], mappedBack[0]);
|
|
|
|
}
|
2010-07-12 22:19:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-09-05 22:56:27 +00:00
|
|
|
return pcf;
|
|
|
|
} else {
|
2022-01-04 23:07:50 +00:00
|
|
|
return std::make_unique<CaseFolderDBCS>(charSetBuffer);
|
2010-07-12 22:19:51 +00:00
|
|
|
}
|
|
|
|
}
|
2019-07-21 13:26:02 +00:00
|
|
|
return nullptr;
|
2010-07-12 22:19:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-28 00:44:27 +00:00
|
|
|
namespace {
|
2010-07-12 22:19:51 +00:00
|
|
|
|
2013-08-28 00:44:27 +00:00
|
|
|
struct CaseMapper {
|
2022-01-04 23:07:50 +00:00
|
|
|
UniqueStr mapped;
|
|
|
|
CaseMapper(const std::string &sUTF8, bool toUpperCase) noexcept {
|
2013-08-28 00:44:27 +00:00
|
|
|
if (toUpperCase) {
|
2022-01-04 23:07:50 +00:00
|
|
|
mapped.reset(g_utf8_strup(sUTF8.c_str(), sUTF8.length()));
|
2013-08-28 00:44:27 +00:00
|
|
|
} else {
|
2022-01-04 23:07:50 +00:00
|
|
|
mapped.reset(g_utf8_strdown(sUTF8.c_str(), sUTF8.length()));
|
2010-07-12 22:19:51 +00:00
|
|
|
}
|
|
|
|
}
|
2013-08-28 00:44:27 +00:00
|
|
|
};
|
2010-07-12 22:19:51 +00:00
|
|
|
|
2013-08-28 00:44:27 +00:00
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
std::string ScintillaGTK::CaseMapString(const std::string &s, CaseMapping caseMapping) {
|
|
|
|
if (s.empty() || (caseMapping == CaseMapping::same))
|
2013-08-28 00:44:27 +00:00
|
|
|
return s;
|
|
|
|
|
|
|
|
if (IsUnicodeMode()) {
|
|
|
|
std::string retMapped(s.length() * maxExpansionCaseConversion, 0);
|
2019-07-21 13:26:02 +00:00
|
|
|
const size_t lenMapped = CaseConvertString(&retMapped[0], retMapped.length(), s.c_str(), s.length(),
|
2022-01-04 23:07:50 +00:00
|
|
|
(caseMapping == CaseMapping::upper) ? CaseConversion::upper : CaseConversion::lower);
|
2013-08-28 00:44:27 +00:00
|
|
|
retMapped.resize(lenMapped);
|
|
|
|
return retMapped;
|
2010-07-12 22:19:51 +00:00
|
|
|
}
|
|
|
|
|
2013-08-28 00:44:27 +00:00
|
|
|
const char *charSetBuffer = CharacterSetID();
|
2010-07-12 22:19:51 +00:00
|
|
|
|
2013-08-28 00:44:27 +00:00
|
|
|
if (!*charSetBuffer) {
|
2022-01-04 23:07:50 +00:00
|
|
|
CaseMapper mapper(s, caseMapping == CaseMapping::upper);
|
|
|
|
return std::string(mapper.mapped.get());
|
2009-04-24 23:35:41 +00:00
|
|
|
} else {
|
2013-08-28 00:44:27 +00:00
|
|
|
// Change text to UTF-8
|
|
|
|
std::string sUTF8 = ConvertText(s.c_str(), s.length(),
|
2019-07-21 13:26:02 +00:00
|
|
|
"UTF-8", charSetBuffer, false);
|
2022-01-04 23:07:50 +00:00
|
|
|
CaseMapper mapper(sUTF8, caseMapping == CaseMapping::upper);
|
|
|
|
return ConvertText(mapper.mapped.get(), strlen(mapper.mapped.get()), charSetBuffer, "UTF-8", false);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
2013-08-28 00:44:27 +00:00
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
int ScintillaGTK::KeyDefault(Keys key, KeyMod modifiers) {
|
2013-08-28 00:44:27 +00:00
|
|
|
// Pass up to container in case it is an accelerator
|
|
|
|
NotifyKey(key, modifiers);
|
|
|
|
return 0;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::CopyToClipboard(const SelectionText &selectedText) {
|
|
|
|
SelectionText *clipText = new SelectionText();
|
|
|
|
clipText->Copy(selectedText);
|
|
|
|
StoreOnClipboard(clipText);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::Copy() {
|
2009-08-23 02:24:48 +00:00
|
|
|
if (!sel.Empty()) {
|
2009-04-24 23:35:41 +00:00
|
|
|
SelectionText *clipText = new SelectionText();
|
|
|
|
CopySelectionRange(clipText);
|
|
|
|
StoreOnClipboard(clipText);
|
|
|
|
#if PLAT_GTK_WIN32
|
2009-08-23 02:24:48 +00:00
|
|
|
if (sel.IsRectangular()) {
|
2009-04-24 23:35:41 +00:00
|
|
|
::OpenClipboard(NULL);
|
|
|
|
::SetClipboardData(cfColumnSelect, 0);
|
|
|
|
::CloseClipboard();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
namespace {
|
2019-05-04 18:14:48 +00:00
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
// Helper class for the asynchronous paste not to risk calling in a destroyed ScintillaGTK
|
2019-05-04 18:14:48 +00:00
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
class SelectionReceiver : GObjectWatcher {
|
|
|
|
ScintillaGTK *sci;
|
2019-05-04 18:14:48 +00:00
|
|
|
|
2021-02-21 04:53:09 +00:00
|
|
|
void Destroyed() noexcept override {
|
2019-07-21 13:26:02 +00:00
|
|
|
sci = nullptr;
|
|
|
|
}
|
2019-05-04 18:14:48 +00:00
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
public:
|
|
|
|
SelectionReceiver(ScintillaGTK *sci_) :
|
|
|
|
GObjectWatcher(G_OBJECT(sci_->MainObject())),
|
|
|
|
sci(sci_) {
|
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
static void ClipboardReceived(GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer data) noexcept {
|
2019-07-21 13:26:02 +00:00
|
|
|
SelectionReceiver *self = static_cast<SelectionReceiver *>(data);
|
|
|
|
if (self->sci) {
|
2021-02-21 04:53:09 +00:00
|
|
|
self->sci->ReceivedClipboard(clipboard, selection_data);
|
2019-05-04 18:14:48 +00:00
|
|
|
}
|
2019-07-21 13:26:02 +00:00
|
|
|
delete self;
|
|
|
|
}
|
|
|
|
};
|
2019-05-04 18:14:48 +00:00
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::RequestSelection(GdkAtom atomSelection) {
|
|
|
|
atomSought = atomUTF8;
|
|
|
|
GtkClipboard *clipBoard =
|
|
|
|
gtk_widget_get_clipboard(GTK_WIDGET(PWidget(wMain)), atomSelection);
|
|
|
|
if (clipBoard) {
|
|
|
|
gtk_clipboard_request_contents(clipBoard, atomSought,
|
|
|
|
SelectionReceiver::ClipboardReceived,
|
|
|
|
new SelectionReceiver(this));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::Paste() {
|
|
|
|
RequestSelection(GDK_SELECTION_CLIPBOARD);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::CreateCallTipWindow(PRectangle rc) {
|
|
|
|
if (!ct.wCallTip.Created()) {
|
|
|
|
ct.wCallTip = gtk_window_new(GTK_WINDOW_POPUP);
|
2023-09-22 09:32:35 +00:00
|
|
|
gtk_window_set_type_hint(GTK_WINDOW(PWidget(ct.wCallTip)), GDK_WINDOW_TYPE_HINT_TOOLTIP);
|
2009-04-24 23:35:41 +00:00
|
|
|
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);
|
2011-07-17 22:30:49 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
g_signal_connect(G_OBJECT(widcdrw), "draw",
|
2019-07-21 13:26:02 +00:00
|
|
|
G_CALLBACK(ScintillaGTK::DrawCT), &ct);
|
2011-07-17 22:30:49 +00:00
|
|
|
#else
|
2009-04-24 23:35:41 +00:00
|
|
|
g_signal_connect(G_OBJECT(widcdrw), "expose_event",
|
2019-07-21 13:26:02 +00:00
|
|
|
G_CALLBACK(ScintillaGTK::ExposeCT), &ct);
|
2011-07-17 22:30:49 +00:00
|
|
|
#endif
|
2009-04-24 23:35:41 +00:00
|
|
|
g_signal_connect(G_OBJECT(widcdrw), "button_press_event",
|
2019-07-21 13:26:02 +00:00
|
|
|
G_CALLBACK(ScintillaGTK::PressCT), this);
|
2009-04-24 23:35:41 +00:00
|
|
|
gtk_widget_set_events(widcdrw,
|
2019-07-21 13:26:02 +00:00
|
|
|
GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK);
|
2021-02-21 04:53:09 +00:00
|
|
|
GtkWidget *top = gtk_widget_get_toplevel(PWidget(wMain));
|
|
|
|
gtk_window_set_transient_for(GTK_WINDOW(PWidget(ct.wCallTip)), GTK_WINDOW(top));
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
2019-07-21 13:26:02 +00:00
|
|
|
const int width = static_cast<int>(rc.Width());
|
|
|
|
const int height = static_cast<int>(rc.Height());
|
|
|
|
gtk_widget_set_size_request(PWidget(ct.wDraw), width, height);
|
2009-04-24 23:35:41 +00:00
|
|
|
ct.wDraw.Show();
|
2011-07-17 22:30:49 +00:00
|
|
|
if (PWindow(ct.wCallTip)) {
|
2019-07-21 13:26:02 +00:00
|
|
|
gdk_window_resize(PWindow(ct.wCallTip), width, height);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::AddToPopUp(const char *label, int cmd, bool enabled) {
|
2010-09-05 22:56:27 +00:00
|
|
|
GtkWidget *menuItem;
|
|
|
|
if (label[0])
|
|
|
|
menuItem = gtk_menu_item_new_with_label(label);
|
|
|
|
else
|
|
|
|
menuItem = gtk_separator_menu_item_new();
|
|
|
|
gtk_menu_shell_append(GTK_MENU_SHELL(popup.GetID()), menuItem);
|
2019-05-04 18:14:48 +00:00
|
|
|
g_object_set_data(G_OBJECT(menuItem), "CmdNum", GINT_TO_POINTER(cmd));
|
2019-07-21 13:26:02 +00:00
|
|
|
g_signal_connect(G_OBJECT(menuItem), "activate", G_CALLBACK(PopUpCB), this);
|
2010-09-05 22:56:27 +00:00
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
if (cmd) {
|
2010-09-05 22:56:27 +00:00
|
|
|
if (menuItem)
|
|
|
|
gtk_widget_set_sensitive(menuItem, enabled);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScintillaGTK::OwnPrimarySelection() {
|
2022-01-04 23:07:50 +00:00
|
|
|
return primarySelection;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::ClearPrimarySelection() {
|
|
|
|
if (primarySelection) {
|
|
|
|
inClearSelection++;
|
|
|
|
// Calls PrimaryClearSelection: primarySelection -> false
|
|
|
|
gtk_clipboard_clear(gtk_clipboard_get(GDK_SELECTION_PRIMARY));
|
|
|
|
inClearSelection--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::PrimaryGetSelectionThis(GtkClipboard *clip, GtkSelectionData *selection_data, guint info) {
|
|
|
|
try {
|
|
|
|
if (SelectionOfGSD(selection_data) == GDK_SELECTION_PRIMARY) {
|
|
|
|
if (primary.Empty()) {
|
|
|
|
CopySelectionRange(&primary);
|
|
|
|
}
|
|
|
|
GetSelection(selection_data, info, &primary);
|
|
|
|
}
|
|
|
|
} catch (...) {
|
|
|
|
errorStatus = Status::Failure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::PrimaryGetSelection(GtkClipboard *clip, GtkSelectionData *selection_data, guint info, gpointer pSci) {
|
|
|
|
static_cast<ScintillaGTK *>(pSci)->PrimaryGetSelectionThis(clip, selection_data, info);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::PrimaryClearSelectionThis(GtkClipboard *clip) {
|
|
|
|
try {
|
|
|
|
primarySelection = false;
|
|
|
|
primary.Clear();
|
|
|
|
if (!inClearSelection) {
|
|
|
|
// Called because of another application or window claiming primary selection
|
|
|
|
// so redraw to show selection in secondary colour.
|
|
|
|
Redraw();
|
|
|
|
}
|
|
|
|
} catch (...) {
|
|
|
|
errorStatus = Status::Failure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::PrimaryClearSelection(GtkClipboard *clip, gpointer pSci) {
|
|
|
|
static_cast<ScintillaGTK *>(pSci)->PrimaryClearSelectionThis(clip);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2022-01-04 23:07:50 +00:00
|
|
|
ClearPrimarySelection();
|
|
|
|
if (!sel.Empty()) {
|
|
|
|
if (gtk_clipboard_set_with_data(
|
|
|
|
gtk_clipboard_get(GDK_SELECTION_PRIMARY),
|
|
|
|
clipboardCopyTargets, nClipboardCopyTargets,
|
|
|
|
PrimaryGetSelection,
|
|
|
|
PrimaryClearSelection,
|
|
|
|
this)) {
|
|
|
|
primarySelection = true;
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-21 04:53:09 +00:00
|
|
|
bool ScintillaGTK::IsStringAtom(GdkAtom type) {
|
|
|
|
return (type == GDK_TARGET_STRING) || (type == atomUTF8) || (type == atomUTF8Mime);
|
|
|
|
}
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
// Detect rectangular text, convert line ends to current mode, convert from or to UTF-8
|
|
|
|
void ScintillaGTK::GetGtkSelectionText(GtkSelectionData *selectionData, SelectionText &selText) {
|
2011-07-17 22:30:49 +00:00
|
|
|
const char *data = reinterpret_cast<const char *>(DataOfGSD(selectionData));
|
|
|
|
int len = LengthOfGSD(selectionData);
|
|
|
|
GdkAtom selectionTypeData = TypeOfGSD(selectionData);
|
2009-04-24 23:35:41 +00:00
|
|
|
|
|
|
|
// Return empty string if selection is not a string
|
2021-02-21 04:53:09 +00:00
|
|
|
if (!IsStringAtom(selectionTypeData)) {
|
2013-08-28 00:44:27 +00:00
|
|
|
selText.Clear();
|
2009-04-24 23:35:41 +00:00
|
|
|
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'));
|
2010-07-12 22:19:51 +00:00
|
|
|
if (isRectangular)
|
|
|
|
len--; // Forget the extra '\0'
|
2009-04-24 23:35:41 +00:00
|
|
|
#endif
|
|
|
|
|
2015-06-07 21:19:26 +00:00
|
|
|
#if PLAT_GTK_WIN32
|
|
|
|
// Win32 includes an ending '\0' byte in 'len' for clipboard text from
|
|
|
|
// external applications; ignore it.
|
|
|
|
if ((len > 0) && (data[len - 1] == '\0'))
|
|
|
|
len--;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
std::string dest(data, len);
|
2009-04-25 23:38:15 +00:00
|
|
|
if (selectionTypeData == GDK_TARGET_STRING) {
|
2009-04-24 23:35:41 +00:00
|
|
|
if (IsUnicodeMode()) {
|
|
|
|
// Unknown encoding so assume in Latin1
|
2019-05-04 18:14:48 +00:00
|
|
|
dest = UTF8FromLatin1(dest);
|
2022-01-04 23:07:50 +00:00
|
|
|
selText.Copy(dest, CpUtf8, CharacterSet::Ansi, isRectangular, false);
|
2009-04-24 23:35:41 +00:00
|
|
|
} else {
|
|
|
|
// Assume buffer is in same encoding as selection
|
2013-08-28 00:44:27 +00:00
|
|
|
selText.Copy(dest, pdoc->dbcsCodePage,
|
2019-07-21 13:26:02 +00:00
|
|
|
vs.styles[STYLE_DEFAULT].characterSet, isRectangular, false);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
} else { // UTF-8
|
|
|
|
const char *charSetBuffer = CharacterSetID();
|
|
|
|
if (!IsUnicodeMode() && *charSetBuffer) {
|
2010-07-12 22:19:51 +00:00
|
|
|
// Convert to locale
|
2013-08-28 00:44:27 +00:00
|
|
|
dest = ConvertText(dest.c_str(), dest.length(), charSetBuffer, "UTF-8", true);
|
|
|
|
selText.Copy(dest, pdoc->dbcsCodePage,
|
2019-07-21 13:26:02 +00:00
|
|
|
vs.styles[STYLE_DEFAULT].characterSet, isRectangular, false);
|
2013-08-28 00:44:27 +00:00
|
|
|
} else {
|
2022-01-04 23:07:50 +00:00
|
|
|
selText.Copy(dest, CpUtf8, CharacterSet::Ansi, isRectangular, false);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-21 04:53:09 +00:00
|
|
|
void ScintillaGTK::InsertSelection(GtkClipboard *clipBoard, GtkSelectionData *selectionData) {
|
2019-07-21 13:26:02 +00:00
|
|
|
const gint length = gtk_selection_data_get_length(selectionData);
|
2022-01-04 23:07:50 +00:00
|
|
|
const GdkAtom selection = gtk_selection_data_get_selection(selectionData);
|
2019-07-21 13:26:02 +00:00
|
|
|
if (length >= 0) {
|
|
|
|
SelectionText selText;
|
|
|
|
GetGtkSelectionText(selectionData, selText);
|
|
|
|
|
|
|
|
UndoGroup ug(pdoc);
|
|
|
|
if (selection == GDK_SELECTION_CLIPBOARD) {
|
2022-01-04 23:07:50 +00:00
|
|
|
ClearSelection(multiPasteMode == MultiPaste::Each);
|
|
|
|
}
|
|
|
|
if (selection == GDK_SELECTION_PRIMARY) {
|
|
|
|
SetSelection(posPrimary, posPrimary);
|
2019-07-21 13:26:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
InsertPasteShape(selText.Data(), selText.Length(),
|
2022-01-04 23:07:50 +00:00
|
|
|
selText.rectangular ? PasteShape::rectangular : PasteShape::stream);
|
2019-07-21 13:26:02 +00:00
|
|
|
EnsureCaretVisible();
|
2021-02-21 04:53:09 +00:00
|
|
|
} else {
|
2022-01-04 23:07:50 +00:00
|
|
|
if (selection == GDK_SELECTION_PRIMARY) {
|
|
|
|
SetSelection(posPrimary, posPrimary);
|
|
|
|
}
|
2021-02-21 04:53:09 +00:00
|
|
|
GdkAtom target = gtk_selection_data_get_target(selectionData);
|
|
|
|
if (target == atomUTF8) {
|
|
|
|
// In case data is actually only stored as text/plain;charset=utf-8 not UTF8_STRING
|
|
|
|
gtk_clipboard_request_contents(clipBoard, atomUTF8Mime,
|
|
|
|
SelectionReceiver::ClipboardReceived,
|
|
|
|
new SelectionReceiver(this)
|
|
|
|
);
|
|
|
|
}
|
2019-07-21 13:26:02 +00:00
|
|
|
}
|
|
|
|
Redraw();
|
|
|
|
}
|
|
|
|
|
|
|
|
GObject *ScintillaGTK::MainObject() const noexcept {
|
|
|
|
return G_OBJECT(PWidget(wMain));
|
|
|
|
}
|
|
|
|
|
2021-02-21 04:53:09 +00:00
|
|
|
void ScintillaGTK::ReceivedClipboard(GtkClipboard *clipBoard, GtkSelectionData *selection_data) noexcept {
|
2019-07-21 13:26:02 +00:00
|
|
|
try {
|
2021-02-21 04:53:09 +00:00
|
|
|
InsertSelection(clipBoard, selection_data);
|
2019-07-21 13:26:02 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2019-07-21 13:26:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
void ScintillaGTK::ReceivedSelection(GtkSelectionData *selection_data) {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
2019-07-21 13:26:02 +00:00
|
|
|
if ((SelectionOfGSD(selection_data) == GDK_SELECTION_CLIPBOARD) ||
|
|
|
|
(SelectionOfGSD(selection_data) == GDK_SELECTION_PRIMARY)) {
|
2011-07-17 22:30:49 +00:00
|
|
|
if ((atomSought == atomUTF8) && (LengthOfGSD(selection_data) <= 0)) {
|
2009-08-23 02:24:48 +00:00
|
|
|
atomSought = atomString;
|
|
|
|
gtk_selection_convert(GTK_WIDGET(PWidget(wMain)),
|
2019-07-21 13:26:02 +00:00
|
|
|
SelectionOfGSD(selection_data), atomSought, GDK_CURRENT_TIME);
|
2021-02-21 04:53:09 +00:00
|
|
|
} else if ((LengthOfGSD(selection_data) > 0) && IsStringAtom(TypeOfGSD(selection_data))) {
|
|
|
|
GtkClipboard *clipBoard = gtk_widget_get_clipboard(GTK_WIDGET(PWidget(wMain)), SelectionOfGSD(selection_data));
|
|
|
|
InsertSelection(clipBoard, selection_data);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// else fprintf(stderr, "Target non string %d %d\n", (int)(selection_data->type),
|
|
|
|
// (int)(atomUTF8));
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::ReceivedDrop(GtkSelectionData *selection_data) {
|
|
|
|
dragWasDropped = true;
|
2011-07-17 22:30:49 +00:00
|
|
|
if (TypeOfGSD(selection_data) == atomUriList || TypeOfGSD(selection_data) == atomDROPFILES_DND) {
|
2013-08-28 00:44:27 +00:00
|
|
|
const char *data = reinterpret_cast<const char *>(DataOfGSD(selection_data));
|
|
|
|
std::vector<char> drop(data, data + LengthOfGSD(selection_data));
|
|
|
|
drop.push_back('\0');
|
|
|
|
NotifyURIDropped(&drop[0]);
|
2021-02-21 04:53:09 +00:00
|
|
|
} else if (IsStringAtom(TypeOfGSD(selection_data))) {
|
2015-06-07 21:19:26 +00:00
|
|
|
if (LengthOfGSD(selection_data) > 0) {
|
2009-04-24 23:35:41 +00:00
|
|
|
SelectionText selText;
|
|
|
|
GetGtkSelectionText(selection_data, selText);
|
2013-08-28 00:44:27 +00:00
|
|
|
DropAt(posDrop, selText.Data(), selText.Length(), false, selText.rectangular);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
2011-07-17 22:30:49 +00:00
|
|
|
} else if (LengthOfGSD(selection_data) > 0) {
|
2009-08-23 02:24:48 +00:00
|
|
|
//~ fprintf(stderr, "ReceivedDrop other %p\n", static_cast<void *>(selection_data->type));
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
Redraw();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ScintillaGTK::GetSelection(GtkSelectionData *selection_data, guint info, SelectionText *text) {
|
|
|
|
#if PLAT_GTK_WIN32
|
2009-04-25 23:38:15 +00:00
|
|
|
// 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
|
2009-04-24 23:35:41 +00:00
|
|
|
// from code below
|
2019-05-04 18:14:48 +00:00
|
|
|
std::unique_ptr<SelectionText> newline_normalized;
|
2009-04-24 23:35:41 +00:00
|
|
|
{
|
2022-01-04 23:07:50 +00:00
|
|
|
std::string tmpstr = Document::TransformLineEnds(text->Data(), text->Length(), EndOfLine::Lf);
|
|
|
|
newline_normalized = std::make_unique<SelectionText>();
|
|
|
|
newline_normalized->Copy(tmpstr, CpUtf8, CharacterSet::Ansi, text->rectangular, false);
|
2019-05-04 18:14:48 +00:00
|
|
|
text = newline_normalized.get();
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Convert text to utf8 if it isn't already
|
2019-05-04 18:14:48 +00:00
|
|
|
std::unique_ptr<SelectionText> converted;
|
2009-04-24 23:35:41 +00:00
|
|
|
if ((text->codePage != SC_CP_UTF8) && (info == TARGET_UTF8_STRING)) {
|
|
|
|
const char *charSet = ::CharacterSetID(text->characterSet);
|
|
|
|
if (*charSet) {
|
2013-08-28 00:44:27 +00:00
|
|
|
std::string tmputf = ConvertText(text->Data(), text->Length(), "UTF-8", charSet, false);
|
2019-07-21 13:26:02 +00:00
|
|
|
converted = std::make_unique<SelectionText>();
|
2022-01-04 23:07:50 +00:00
|
|
|
converted->Copy(tmputf, CpUtf8, CharacterSet::Ansi, text->rectangular, false);
|
2019-05-04 18:14:48 +00:00
|
|
|
text = converted.get();
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
2021-02-21 04:53:09 +00:00
|
|
|
// All other tested applications behave benignly by ignoring the \0.
|
2009-04-24 23:35:41 +00:00
|
|
|
// The #if is here because on Windows cfColumnSelect clip entry is used
|
|
|
|
// instead as standard indicator of rectangularness (so no need to kludge)
|
2013-08-28 00:44:27 +00:00
|
|
|
const char *textData = text->Data();
|
2022-01-04 23:07:50 +00:00
|
|
|
gint len = static_cast<gint>(text->Length());
|
2009-04-24 23:35:41 +00:00
|
|
|
#if PLAT_GTK_WIN32 == 0
|
|
|
|
if (text->rectangular)
|
|
|
|
len++;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (info == TARGET_UTF8_STRING) {
|
2009-08-23 02:24:48 +00:00
|
|
|
gtk_selection_data_set_text(selection_data, textData, len);
|
2009-04-24 23:35:41 +00:00
|
|
|
} else {
|
|
|
|
gtk_selection_data_set(selection_data,
|
2019-07-21 13:26:02 +00:00
|
|
|
static_cast<GdkAtom>(GDK_SELECTION_TYPE_STRING),
|
|
|
|
8, reinterpret_cast<const guchar *>(textData), len);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::StoreOnClipboard(SelectionText *clipText) {
|
|
|
|
GtkClipboard *clipBoard =
|
2019-07-21 13:26:02 +00:00
|
|
|
gtk_widget_get_clipboard(GTK_WIDGET(PWidget(wMain)), GDK_SELECTION_CLIPBOARD);
|
|
|
|
if (clipBoard == nullptr) // Occurs if widget isn't in a toplevel
|
2009-04-24 23:35:41 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (gtk_clipboard_set_with_data(clipBoard, clipboardCopyTargets, nClipboardCopyTargets,
|
2019-07-21 13:26:02 +00:00
|
|
|
ClipboardGetSelection, ClipboardClearSelection, clipText)) {
|
2009-04-24 23:35:41 +00:00
|
|
|
gtk_clipboard_set_can_store(clipBoard, clipboardCopyTargets, nClipboardCopyTargets);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::ClipboardGetSelection(GtkClipboard *, GtkSelectionData *selection_data, guint info, void *data) {
|
2019-07-21 13:26:02 +00:00
|
|
|
GetSelection(selection_data, info, static_cast<SelectionText *>(data));
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::ClipboardClearSelection(GtkClipboard *, void *data) {
|
2019-07-21 13:26:02 +00:00
|
|
|
SelectionText *obj = static_cast<SelectionText *>(data);
|
2009-04-24 23:35:41 +00:00
|
|
|
delete obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::UnclaimSelection(GdkEventSelection *selection_event) {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
|
|
|
//Platform::DebugPrintf("UnclaimSelection\n");
|
|
|
|
if (selection_event->selection == GDK_SELECTION_PRIMARY) {
|
|
|
|
//Platform::DebugPrintf("UnclaimPrimarySelection\n");
|
|
|
|
if (!OwnPrimarySelection()) {
|
2013-08-28 00:44:27 +00:00
|
|
|
primary.Clear();
|
2009-08-23 02:24:48 +00:00
|
|
|
primarySelection = false;
|
|
|
|
FullPaint();
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::Resize(int width, int height) {
|
|
|
|
//Platform::DebugPrintf("Resize %d %d\n", width, height);
|
|
|
|
//printf("Resize %d %d\n", width, height);
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
// GTK+ 3 warns when we allocate smaller than the minimum allocation,
|
|
|
|
// so we use these variables to store the minimum scrollbar lengths.
|
|
|
|
int minVScrollBarHeight, minHScrollBarWidth;
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
// Not always needed, but some themes can have different sizes of scrollbars
|
2011-07-17 22:30:49 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
2019-05-04 18:14:48 +00:00
|
|
|
GtkRequisition minimum, requisition;
|
|
|
|
gtk_widget_get_preferred_size(PWidget(scrollbarv), &minimum, &requisition);
|
|
|
|
minVScrollBarHeight = minimum.height;
|
2013-08-28 00:44:27 +00:00
|
|
|
verticalScrollBarWidth = requisition.width;
|
2019-05-04 18:14:48 +00:00
|
|
|
gtk_widget_get_preferred_size(PWidget(scrollbarh), &minimum, &requisition);
|
|
|
|
minHScrollBarWidth = minimum.width;
|
2013-08-28 00:44:27 +00:00
|
|
|
horizontalScrollBarHeight = requisition.height;
|
2011-07-17 22:30:49 +00:00
|
|
|
#else
|
2019-05-04 18:14:48 +00:00
|
|
|
minVScrollBarHeight = minHScrollBarWidth = 1;
|
2013-08-28 00:44:27 +00:00
|
|
|
verticalScrollBarWidth = GTK_WIDGET(PWidget(scrollbarv))->requisition.width;
|
|
|
|
horizontalScrollBarHeight = GTK_WIDGET(PWidget(scrollbarh))->requisition.height;
|
2011-07-17 22:30:49 +00:00
|
|
|
#endif
|
2009-04-24 23:35:41 +00:00
|
|
|
|
|
|
|
// These allocations should never produce negative sizes as they would wrap around to huge
|
|
|
|
// unsigned numbers inside GTK+ causing warnings.
|
2019-07-21 13:26:02 +00:00
|
|
|
const bool showSBHorizontal = horizontalScrollBarVisible && !Wrapping();
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
GtkAllocation alloc = {};
|
2009-04-24 23:35:41 +00:00
|
|
|
if (showSBHorizontal) {
|
|
|
|
gtk_widget_show(GTK_WIDGET(PWidget(scrollbarh)));
|
|
|
|
alloc.x = 0;
|
2013-08-28 00:44:27 +00:00
|
|
|
alloc.y = height - horizontalScrollBarHeight;
|
2019-05-04 18:14:48 +00:00
|
|
|
alloc.width = std::max(minHScrollBarWidth, width - verticalScrollBarWidth);
|
2009-04-24 23:35:41 +00:00
|
|
|
alloc.height = horizontalScrollBarHeight;
|
|
|
|
gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarh)), &alloc);
|
|
|
|
} else {
|
|
|
|
gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarh)));
|
2013-08-28 00:44:27 +00:00
|
|
|
horizontalScrollBarHeight = 0; // in case horizontalScrollBarVisible is true.
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (verticalScrollBarVisible) {
|
|
|
|
gtk_widget_show(GTK_WIDGET(PWidget(scrollbarv)));
|
2013-08-28 00:44:27 +00:00
|
|
|
alloc.x = width - verticalScrollBarWidth;
|
2009-04-24 23:35:41 +00:00
|
|
|
alloc.y = 0;
|
2013-08-28 00:44:27 +00:00
|
|
|
alloc.width = verticalScrollBarWidth;
|
2019-05-04 18:14:48 +00:00
|
|
|
alloc.height = std::max(minVScrollBarHeight, height - horizontalScrollBarHeight);
|
2009-04-24 23:35:41 +00:00
|
|
|
gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarv)), &alloc);
|
|
|
|
} else {
|
|
|
|
gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarv)));
|
2013-08-28 00:44:27 +00:00
|
|
|
verticalScrollBarWidth = 0;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
Update scintilla 5.3.4 and lexilla 5.2.4 with:
https://www.scintilla.org/scintilla534.zip
Released 8 March 2023.
Add multithreaded wrap to significantly improve performance of wrapping large files.
More typesafe bindings of *Full APIs in ScintillaCall. Feature #1477.
Fix overlapping of text with line end wrap marker. Bug #2378.
Fix clipping of line end wrap symbol for SC_WRAPVISUALFLAGLOC_END_BY_TEXT.
Where a multi-byte character contains multiple styles, display each byte as a representation. This makes it easier to see and fix lexers that change styles mid-character, commonly because they use fixed size buffers.
Fix a potential crash with autocompletion list fill-ups where a SCN_CHARADDED handler retriggered an autocompletion list, but with no items that match the typed character.
lexilla523
Released 8 March 2023.
Add scripts/PromoteNew.bat script to promote .new files after checking.
Makefile: Remove 1024-byte line length limit..
Ruby: Add new lexical classes for % literals SCE_RB_STRING_W (%w non-interpolable string array), SCE_RB_STRING_I (%i non-interpolable symbol array), SCE_RB_STRING_QI (%I interpolable symbol array), and SCE_RB_STRING_QS (%s symbol). Issue #124.
Ruby: Disambiguate %= which may be a quote or modulo assignment. Issue #124, Bug #1255, Bug #2182.
Ruby: Fix additional fold level for single character in SCE_RB_STRING_QW. Issue #132.
Ruby: Set SCE_RB_HERE_QQ for unquoted and double-quoted heredocs and SCE_RB_HERE_QX for backticks-quoted heredocs. Issue #134.
Ruby: Recognise #{} inside SCE_RB_HERE_QQ and SCE_RB_HERE_QX. Issue #134.
Ruby: Improve regex and heredoc recognition. Issue #136.
Ruby: Highlight #@, #@@ and #$ style interpolation. Issue #140.
Ruby: Fix folding for multiple heredocs started on one line. Fix folding when there is a space after heredoc opening delimiter. Issue #135.
YAML: Remove 1024-byte line length limit.
https://www.scintilla.org/lexilla524.zip
Released 13 March 2023.
C++: Fix failure to recognize keywords containing upper case. Issue #149.
GDScript: Support % and $ node paths. Issue #145, Pull request #146.
Close #13338
2023-03-10 02:37:21 +00:00
|
|
|
SetClientRectangle();
|
2010-09-05 22:56:27 +00:00
|
|
|
if (IS_WIDGET_MAPPED(PWidget(wMain))) {
|
2009-04-24 23:35:41 +00:00
|
|
|
ChangeSize();
|
2022-10-12 18:45:40 +00:00
|
|
|
} else {
|
|
|
|
const PRectangle rcTextArea = GetTextRectangle();
|
|
|
|
if (wrapWidth != rcTextArea.Width()) {
|
|
|
|
wrapWidth = rcTextArea.Width();
|
|
|
|
NeedWrapping();
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
alloc.x = 0;
|
|
|
|
alloc.y = 0;
|
2019-05-04 18:14:48 +00:00
|
|
|
alloc.width = 1;
|
|
|
|
alloc.height = 1;
|
|
|
|
#if GTK_CHECK_VERSION(3, 0, 0)
|
|
|
|
// please GTK 3.20 and ask wText what size it wants, although we know it doesn't really need
|
|
|
|
// anything special as it's ours.
|
2019-07-21 13:26:02 +00:00
|
|
|
gtk_widget_get_preferred_size(PWidget(wText), &requisition, nullptr);
|
2019-05-04 18:14:48 +00:00
|
|
|
alloc.width = requisition.width;
|
|
|
|
alloc.height = requisition.height;
|
|
|
|
#endif
|
|
|
|
alloc.width = std::max(alloc.width, width - verticalScrollBarWidth);
|
|
|
|
alloc.height = std::max(alloc.height, height - horizontalScrollBarHeight);
|
2009-04-24 23:35:41 +00:00
|
|
|
gtk_widget_size_allocate(GTK_WIDGET(PWidget(wText)), &alloc);
|
|
|
|
}
|
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
namespace {
|
|
|
|
|
2021-02-21 04:53:09 +00:00
|
|
|
void SetAdjustmentValue(GtkAdjustment *object, int value) noexcept {
|
2009-04-24 23:35:41 +00:00
|
|
|
GtkAdjustment *adjustment = GTK_ADJUSTMENT(object);
|
2019-07-21 13:26:02 +00:00
|
|
|
const int maxValue = static_cast<int>(
|
|
|
|
gtk_adjustment_get_upper(adjustment) - gtk_adjustment_get_page_size(adjustment));
|
2011-07-17 22:30:49 +00:00
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
if (value > maxValue)
|
|
|
|
value = maxValue;
|
|
|
|
if (value < 0)
|
|
|
|
value = 0;
|
|
|
|
gtk_adjustment_set_value(adjustment, value);
|
|
|
|
}
|
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
int modifierTranslated(int sciModifier) noexcept {
|
2009-08-23 02:24:48 +00:00
|
|
|
switch (sciModifier) {
|
2019-07-21 13:26:02 +00:00
|
|
|
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;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
Point PointOfEvent(const GdkEventButton *event) noexcept {
|
|
|
|
// Use floor as want to round in the same direction (-infinity) so
|
|
|
|
// there is no stickiness crossing 0.0.
|
|
|
|
return Point(static_cast<XYPOSITION>(std::floor(event->x)), static_cast<XYPOSITION>(std::floor(event->y)));
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
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;
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
evbtn.reset(gdk_event_copy(reinterpret_cast<GdkEvent *>(event)));
|
2019-05-04 18:14:48 +00:00
|
|
|
buttonMouse = event->button;
|
2019-07-21 13:26:02 +00:00
|
|
|
const Point pt = PointOfEvent(event);
|
|
|
|
const PRectangle rcClient = GetClientRectangle();
|
2009-08-23 02:24:48 +00:00
|
|
|
//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");
|
2009-04-24 23:35:41 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2009-08-23 02:24:48 +00:00
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
const bool shift = (event->state & GDK_SHIFT_MASK) != 0;
|
2009-08-23 02:24:48 +00:00
|
|
|
bool ctrl = (event->state & GDK_CONTROL_MASK) != 0;
|
2015-06-07 21:19:26 +00:00
|
|
|
// 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
|
2019-07-21 13:26:02 +00:00
|
|
|
const bool alt = (event->state & modifierTranslated(rectangularSelectionModifier)) != 0;
|
2009-08-23 02:24:48 +00:00
|
|
|
|
|
|
|
gtk_widget_grab_focus(PWidget(wMain));
|
|
|
|
if (event->button == 1) {
|
2015-06-07 21:19:26 +00:00
|
|
|
#if PLAT_GTK_MACOSX
|
2019-07-21 13:26:02 +00:00
|
|
|
const bool meta = ctrl;
|
2021-02-21 04:53:09 +00:00
|
|
|
// GDK reports the Command modifier key as GDK_MOD2_MASK for button events,
|
2015-06-07 21:19:26 +00:00
|
|
|
// not GDK_META_MASK like in key events.
|
|
|
|
ctrl = (event->state & GDK_MOD2_MASK) != 0;
|
|
|
|
#else
|
2019-07-21 13:26:02 +00:00
|
|
|
const bool meta = false;
|
2015-06-07 21:19:26 +00:00
|
|
|
#endif
|
|
|
|
ButtonDownWithModifiers(pt, event->time, ModifierFlags(shift, ctrl, alt, meta));
|
2009-08-23 02:24:48 +00:00
|
|
|
} else if (event->button == 2) {
|
|
|
|
// Grab the primary selection if it exists
|
2022-01-04 23:07:50 +00:00
|
|
|
posPrimary = SPositionFromLocation(pt, false, false, UserVirtualSpace());
|
2013-08-28 00:44:27 +00:00
|
|
|
if (OwnPrimarySelection() && primary.Empty())
|
2009-08-23 02:24:48 +00:00
|
|
|
CopySelectionRange(&primary);
|
|
|
|
|
2010-07-12 22:19:51 +00:00
|
|
|
sel.Clear();
|
2019-07-21 13:26:02 +00:00
|
|
|
RequestSelection(GDK_SELECTION_PRIMARY);
|
2009-08-23 02:24:48 +00:00
|
|
|
} else if (event->button == 3) {
|
2011-07-17 22:30:49 +00:00
|
|
|
if (!PointInSelection(pt))
|
|
|
|
SetEmptySelection(PositionFromLocation(pt));
|
2019-05-04 18:14:48 +00:00
|
|
|
if (ShouldDisplayPopup(pt)) {
|
2009-08-23 02:24:48 +00:00
|
|
|
// PopUp menu
|
|
|
|
// Convert to screen
|
|
|
|
int ox = 0;
|
|
|
|
int oy = 0;
|
2011-07-17 22:30:49 +00:00
|
|
|
gdk_window_get_origin(PWindow(wMain), &ox, &oy);
|
2009-08-23 02:24:48 +00:00
|
|
|
ContextMenu(Point(pt.x + ox, pt.y + oy));
|
|
|
|
} else {
|
2019-05-04 18:14:48 +00:00
|
|
|
#if PLAT_GTK_MACOSX
|
2019-07-21 13:26:02 +00:00
|
|
|
const bool meta = ctrl;
|
2021-02-21 04:53:09 +00:00
|
|
|
// GDK reports the Command modifier key as GDK_MOD2_MASK for button events,
|
2019-05-04 18:14:48 +00:00
|
|
|
// not GDK_META_MASK like in key events.
|
|
|
|
ctrl = (event->state & GDK_MOD2_MASK) != 0;
|
|
|
|
#else
|
2019-07-21 13:26:02 +00:00
|
|
|
const bool meta = false;
|
2019-05-04 18:14:48 +00:00
|
|
|
#endif
|
|
|
|
RightButtonDownWithModifiers(pt, event->time, ModifierFlags(shift, ctrl, alt, meta));
|
2009-08-23 02:24:48 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
} else if (event->button == 4) {
|
|
|
|
// Wheel scrolling up (only GTK 1.x does it this way)
|
|
|
|
if (ctrl)
|
2015-06-07 21:19:26 +00:00
|
|
|
SetAdjustmentValue(adjustmenth, xOffset - 6);
|
2009-08-23 02:24:48 +00:00
|
|
|
else
|
2022-01-04 23:07:50 +00:00
|
|
|
SetAdjustmentValue(adjustmentv, static_cast<int>(topLine) - 3);
|
2009-08-23 02:24:48 +00:00
|
|
|
} else if (event->button == 5) {
|
|
|
|
// Wheel scrolling down (only GTK 1.x does it this way)
|
|
|
|
if (ctrl)
|
2015-06-07 21:19:26 +00:00
|
|
|
SetAdjustmentValue(adjustmenth, xOffset + 6);
|
2009-08-23 02:24:48 +00:00
|
|
|
else
|
2022-01-04 23:07:50 +00:00
|
|
|
SetAdjustmentValue(adjustmentv, static_cast<int>(topLine) + 3);
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gint ScintillaGTK::Press(GtkWidget *widget, GdkEventButton *event) {
|
2011-07-17 22:30:49 +00:00
|
|
|
if (event->window != WindowFromWidget(widget))
|
2009-04-24 23:35:41 +00:00
|
|
|
return FALSE;
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-04-24 23:35:41 +00:00
|
|
|
return sciThis->PressThis(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
gint ScintillaGTK::MouseRelease(GtkWidget *widget, GdkEventButton *event) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
|
|
|
//Platform::DebugPrintf("Release %x %d %d\n",sciThis,event->time,event->state);
|
|
|
|
if (!sciThis->HaveMouseCapture())
|
|
|
|
return FALSE;
|
|
|
|
if (event->button == 1) {
|
2019-07-21 13:26:02 +00:00
|
|
|
Point pt = PointOfEvent(event);
|
2009-08-23 02:24:48 +00:00
|
|
|
//Platform::DebugPrintf("Up %x %x %d %d %d\n",
|
|
|
|
// sciThis,event->window,event->time, pt.x, pt.y);
|
2011-07-17 22:30:49 +00:00
|
|
|
if (event->window != PWindow(sciThis->wMain))
|
2009-08-23 02:24:48 +00:00
|
|
|
// 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;
|
2022-01-04 23:07:50 +00:00
|
|
|
const KeyMod modifiers = ModifierFlags(
|
2019-07-21 13:26:02 +00:00
|
|
|
(event->state & GDK_SHIFT_MASK) != 0,
|
|
|
|
(event->state & GDK_CONTROL_MASK) != 0,
|
|
|
|
(event->state & modifierTranslated(sciThis->rectangularSelectionModifier)) != 0);
|
2019-05-04 18:14:48 +00:00
|
|
|
sciThis->ButtonUpWithModifiers(pt, event->time, modifiers);
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
sciThis->errorStatus = Status::Failure;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// win32gtk and GTK >= 2 use SCROLL_* events instead of passing the
|
|
|
|
// button4/5/6/7 events to the GTK app
|
2013-08-28 00:44:27 +00:00
|
|
|
gint ScintillaGTK::ScrollEvent(GtkWidget *widget, GdkEventScroll *event) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
if (widget == nullptr || event == nullptr)
|
2009-08-23 02:24:48 +00:00
|
|
|
return FALSE;
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
#if defined(GDK_WINDOWING_WAYLAND)
|
|
|
|
if (event->direction == GDK_SCROLL_SMOOTH && GDK_IS_WAYLAND_WINDOW(event->window)) {
|
|
|
|
const int smoothScrollFactor = 4;
|
|
|
|
sciThis->smoothScrollY += event->delta_y * smoothScrollFactor;
|
|
|
|
sciThis->smoothScrollX += event->delta_x * smoothScrollFactor;;
|
|
|
|
if (ABS(sciThis->smoothScrollY) >= 1.0) {
|
2019-07-21 13:26:02 +00:00
|
|
|
const int scrollLines = std::trunc(sciThis->smoothScrollY);
|
2019-05-04 18:14:48 +00:00
|
|
|
sciThis->ScrollTo(sciThis->topLine + scrollLines);
|
|
|
|
sciThis->smoothScrollY -= scrollLines;
|
|
|
|
}
|
|
|
|
if (ABS(sciThis->smoothScrollX) >= 1.0) {
|
2019-07-21 13:26:02 +00:00
|
|
|
const int scrollPixels = std::trunc(sciThis->smoothScrollX);
|
2019-05-04 18:14:48 +00:00
|
|
|
sciThis->HorizontalScrollTo(sciThis->xOffset + scrollPixels);
|
|
|
|
sciThis->smoothScrollX -= scrollPixels;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
// 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)
|
2022-01-04 23:07:50 +00:00
|
|
|
// Note that this is disabled on macOS (Darwin) with the X11 backend
|
2019-05-04 18:14:48 +00:00
|
|
|
// where the X11 server already has an adaptive scrolling algorithm
|
2015-06-07 21:19:26 +00:00
|
|
|
// that fights with this one
|
2009-08-23 02:24:48 +00:00
|
|
|
int cLineScroll;
|
2023-02-09 16:57:24 +00:00
|
|
|
#if (defined(__APPLE__) || defined(PLAT_GTK_WIN32)) && !defined(GDK_WINDOWING_QUARTZ)
|
2009-04-24 23:35:41 +00:00
|
|
|
cLineScroll = sciThis->linesPerScroll;
|
|
|
|
if (cLineScroll == 0)
|
|
|
|
cLineScroll = 4;
|
|
|
|
sciThis->wheelMouseIntensity = cLineScroll;
|
2009-08-23 02:24:48 +00:00
|
|
|
#else
|
2021-02-21 04:53:09 +00:00
|
|
|
const gint64 curTime = g_get_monotonic_time();
|
|
|
|
const gint64 timeDelta = curTime - sciThis->lastWheelMouseTime;
|
2009-08-23 02:24:48 +00:00
|
|
|
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;
|
|
|
|
}
|
2021-02-21 04:53:09 +00:00
|
|
|
sciThis->lastWheelMouseTime = curTime;
|
2009-04-24 23:35:41 +00:00
|
|
|
#endif
|
2009-08-23 02:24:48 +00:00
|
|
|
if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_LEFT) {
|
|
|
|
cLineScroll *= -1;
|
|
|
|
}
|
|
|
|
sciThis->lastWheelMouseDirection = event->direction;
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
// 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)
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2013-08-28 00:44:27 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,4,0)
|
|
|
|
// Smooth scrolling not supported
|
|
|
|
if (event->direction == GDK_SCROLL_SMOOTH) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
// Horizontal scrolling
|
2022-04-13 11:10:12 +00:00
|
|
|
if (event->direction == GDK_SCROLL_LEFT || event->direction == GDK_SCROLL_RIGHT || event->state & GDK_SHIFT_MASK) {
|
|
|
|
int hScroll = gtk_adjustment_get_step_increment(sciThis->adjustmenth);
|
|
|
|
hScroll *= cLineScroll; // scroll by this many characters
|
|
|
|
sciThis->HorizontalScrollTo(sciThis->xOffset + hScroll);
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
// Text font size zoom
|
|
|
|
} else if (event->state & GDK_CONTROL_MASK) {
|
|
|
|
if (cLineScroll < 0) {
|
2022-01-04 23:07:50 +00:00
|
|
|
sciThis->KeyCommand(Message::ZoomIn);
|
2009-08-23 02:24:48 +00:00
|
|
|
} else {
|
2022-01-04 23:07:50 +00:00
|
|
|
sciThis->KeyCommand(Message::ZoomOut);
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
// Regular scrolling
|
2009-04-24 23:35:41 +00:00
|
|
|
} else {
|
2009-08-23 02:24:48 +00:00
|
|
|
sciThis->ScrollTo(sciThis->topLine + cLineScroll);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
2009-08-23 02:24:48 +00:00
|
|
|
return TRUE;
|
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
sciThis->errorStatus = Status::Failure;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
2009-08-23 02:24:48 +00:00
|
|
|
return FALSE;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gint ScintillaGTK::Motion(GtkWidget *widget, GdkEventMotion *event) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
|
|
|
//Platform::DebugPrintf("Motion %x %d\n",sciThis,event->time);
|
2011-07-17 22:30:49 +00:00
|
|
|
if (event->window != WindowFromWidget(widget))
|
2009-08-23 02:24:48 +00:00
|
|
|
return FALSE;
|
|
|
|
int x = 0;
|
|
|
|
int y = 0;
|
2021-02-21 04:53:09 +00:00
|
|
|
GdkModifierType state {};
|
2009-08-23 02:24:48 +00:00
|
|
|
if (event->is_hint) {
|
2013-08-28 00:44:27 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
2015-06-07 21:19:26 +00:00
|
|
|
gdk_window_get_device_position(event->window,
|
2019-07-21 13:26:02 +00:00
|
|
|
event->device, &x, &y, &state);
|
2013-08-28 00:44:27 +00:00
|
|
|
#else
|
2009-08-23 02:24:48 +00:00
|
|
|
gdk_window_get_pointer(event->window, &x, &y, &state);
|
2013-08-28 00:44:27 +00:00
|
|
|
#endif
|
2009-08-23 02:24:48 +00:00
|
|
|
} 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);
|
2019-07-21 13:26:02 +00:00
|
|
|
const Point pt(static_cast<XYPOSITION>(x), static_cast<XYPOSITION>(y));
|
2022-01-04 23:07:50 +00:00
|
|
|
const KeyMod modifiers = ModifierFlags(
|
2019-07-21 13:26:02 +00:00
|
|
|
(event->state & GDK_SHIFT_MASK) != 0,
|
|
|
|
(event->state & GDK_CONTROL_MASK) != 0,
|
|
|
|
(event->state & modifierTranslated(sciThis->rectangularSelectionModifier)) != 0);
|
2019-05-04 18:14:48 +00:00
|
|
|
sciThis->ButtonMoveWithModifiers(pt, event->time, modifiers);
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
sciThis->errorStatus = Status::Failure;
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
namespace {
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
// Map the keypad keys to their equivalent functions
|
2022-01-04 23:07:50 +00:00
|
|
|
int KeyTranslate(int keyIn) noexcept {
|
2009-04-24 23:35:41 +00:00
|
|
|
switch (keyIn) {
|
2011-07-17 22:30:49 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
case GDK_KEY_ISO_Left_Tab:
|
|
|
|
return SCK_TAB;
|
|
|
|
case GDK_KEY_KP_Down:
|
|
|
|
return SCK_DOWN;
|
|
|
|
case GDK_KEY_KP_Up:
|
|
|
|
return SCK_UP;
|
|
|
|
case GDK_KEY_KP_Left:
|
|
|
|
return SCK_LEFT;
|
|
|
|
case GDK_KEY_KP_Right:
|
|
|
|
return SCK_RIGHT;
|
|
|
|
case GDK_KEY_KP_Home:
|
|
|
|
return SCK_HOME;
|
|
|
|
case GDK_KEY_KP_End:
|
|
|
|
return SCK_END;
|
|
|
|
case GDK_KEY_KP_Page_Up:
|
|
|
|
return SCK_PRIOR;
|
|
|
|
case GDK_KEY_KP_Page_Down:
|
|
|
|
return SCK_NEXT;
|
|
|
|
case GDK_KEY_KP_Delete:
|
|
|
|
return SCK_DELETE;
|
|
|
|
case GDK_KEY_KP_Insert:
|
|
|
|
return SCK_INSERT;
|
|
|
|
case GDK_KEY_KP_Enter:
|
|
|
|
return SCK_RETURN;
|
|
|
|
|
|
|
|
case GDK_KEY_Down:
|
|
|
|
return SCK_DOWN;
|
|
|
|
case GDK_KEY_Up:
|
|
|
|
return SCK_UP;
|
|
|
|
case GDK_KEY_Left:
|
|
|
|
return SCK_LEFT;
|
|
|
|
case GDK_KEY_Right:
|
|
|
|
return SCK_RIGHT;
|
|
|
|
case GDK_KEY_Home:
|
|
|
|
return SCK_HOME;
|
|
|
|
case GDK_KEY_End:
|
|
|
|
return SCK_END;
|
|
|
|
case GDK_KEY_Page_Up:
|
|
|
|
return SCK_PRIOR;
|
|
|
|
case GDK_KEY_Page_Down:
|
|
|
|
return SCK_NEXT;
|
|
|
|
case GDK_KEY_Delete:
|
|
|
|
return SCK_DELETE;
|
|
|
|
case GDK_KEY_Insert:
|
|
|
|
return SCK_INSERT;
|
|
|
|
case GDK_KEY_Escape:
|
|
|
|
return SCK_ESCAPE;
|
|
|
|
case GDK_KEY_BackSpace:
|
|
|
|
return SCK_BACK;
|
|
|
|
case GDK_KEY_Tab:
|
|
|
|
return SCK_TAB;
|
|
|
|
case GDK_KEY_Return:
|
|
|
|
return SCK_RETURN;
|
|
|
|
case GDK_KEY_KP_Add:
|
|
|
|
return SCK_ADD;
|
|
|
|
case GDK_KEY_KP_Subtract:
|
|
|
|
return SCK_SUBTRACT;
|
|
|
|
case GDK_KEY_KP_Divide:
|
|
|
|
return SCK_DIVIDE;
|
|
|
|
case GDK_KEY_Super_L:
|
|
|
|
return SCK_WIN;
|
|
|
|
case GDK_KEY_Super_R:
|
|
|
|
return SCK_RWIN;
|
|
|
|
case GDK_KEY_Menu:
|
|
|
|
return SCK_MENU;
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
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;
|
2011-07-17 22:30:49 +00:00
|
|
|
#endif
|
2009-04-24 23:35:41 +00:00
|
|
|
default:
|
|
|
|
return keyIn;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
}
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
gboolean ScintillaGTK::KeyThis(GdkEventKey *event) {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
|
|
|
//fprintf(stderr, "SC-key: %d %x [%s]\n",
|
|
|
|
// event->keyval, event->state, (event->length > 0) ? event->string : "empty");
|
2022-01-04 23:07:50 +00:00
|
|
|
if (gtk_im_context_filter_keypress(im_context.get(), event)) {
|
2009-08-23 02:24:48 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (!event->keyval) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
const bool shift = (event->state & GDK_SHIFT_MASK) != 0;
|
2009-08-23 02:24:48 +00:00
|
|
|
bool ctrl = (event->state & GDK_CONTROL_MASK) != 0;
|
2019-07-21 13:26:02 +00:00
|
|
|
const bool alt = (event->state & GDK_MOD1_MASK) != 0;
|
|
|
|
const bool super = (event->state & GDK_MOD4_MASK) != 0;
|
2009-08-23 02:24:48 +00:00
|
|
|
guint key = event->keyval;
|
2013-08-28 00:44:27 +00:00
|
|
|
if ((ctrl || alt) && (key < 128))
|
2009-08-23 02:24:48 +00:00
|
|
|
key = toupper(key);
|
2011-07-17 22:30:49 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
else if (!ctrl && (key >= GDK_KEY_KP_Multiply && key <= GDK_KEY_KP_9))
|
|
|
|
#else
|
2009-08-23 02:24:48 +00:00
|
|
|
else if (!ctrl && (key >= GDK_KP_Multiply && key <= GDK_KP_9))
|
2011-07-17 22:30:49 +00:00
|
|
|
#endif
|
2009-08-23 02:24:48 +00:00
|
|
|
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;
|
2013-08-28 00:44:27 +00:00
|
|
|
#if !(PLAT_GTK_MACOSX)
|
2019-07-21 13:26:02 +00:00
|
|
|
const bool meta = false;
|
2013-08-28 00:44:27 +00:00
|
|
|
#else
|
2019-07-21 13:26:02 +00:00
|
|
|
const bool meta = ctrl;
|
2013-08-28 00:44:27 +00:00
|
|
|
ctrl = (event->state & GDK_META_MASK) != 0;
|
|
|
|
#endif
|
2022-01-04 23:07:50 +00:00
|
|
|
const bool added = KeyDownWithModifiers(static_cast<Keys>(key), ModifierFlags(shift, ctrl, alt, meta, super), &consumed) != 0;
|
2009-08-23 02:24:48 +00:00
|
|
|
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();
|
2022-01-04 23:07:50 +00:00
|
|
|
const Sci::Position lengthInserted = pdoc->InsertString(CurrentPosition(), event->string, strlen(event->string));
|
2015-06-07 21:19:26 +00:00
|
|
|
if (lengthInserted > 0) {
|
|
|
|
MovePositionTo(CurrentPosition() + lengthInserted);
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
2009-08-23 02:24:48 +00:00
|
|
|
return consumed;
|
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
2009-08-23 02:24:48 +00:00
|
|
|
return FALSE;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gboolean ScintillaGTK::KeyPress(GtkWidget *widget, GdkEventKey *event) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-04-24 23:35:41 +00:00
|
|
|
return sciThis->KeyThis(event);
|
|
|
|
}
|
|
|
|
|
2013-08-28 00:44:27 +00:00
|
|
|
gboolean ScintillaGTK::KeyRelease(GtkWidget *widget, GdkEventKey *event) {
|
2009-04-24 23:35:41 +00:00
|
|
|
//Platform::DebugPrintf("SC-keyrel: %d %x %3s\n",event->keyval, event->state, event->string);
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2022-01-04 23:07:50 +00:00
|
|
|
if (gtk_im_context_filter_keypress(sciThis->im_context.get(), event)) {
|
2013-08-28 00:44:27 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2013-08-28 00:44:27 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
gboolean ScintillaGTK::DrawPreeditThis(GtkWidget *, cairo_t *cr) {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
2022-01-04 23:07:50 +00:00
|
|
|
PreEditString pes(im_context.get());
|
|
|
|
UniquePangoLayout layout(gtk_widget_create_pango_layout(PWidget(wText), pes.str));
|
|
|
|
pango_layout_set_attributes(layout.get(), pes.attrs);
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2013-08-28 00:44:27 +00:00
|
|
|
cairo_move_to(cr, 0, 0);
|
2022-01-04 23:07:50 +00:00
|
|
|
pango_cairo_show_layout(cr, layout.get());
|
2013-08-28 00:44:27 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2013-08-28 00:44:27 +00:00
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean ScintillaGTK::DrawPreedit(GtkWidget *widget, cairo_t *cr, ScintillaGTK *sciThis) {
|
|
|
|
return sciThis->DrawPreeditThis(widget, cr);
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2013-08-28 00:44:27 +00:00
|
|
|
#else
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
gboolean ScintillaGTK::ExposePreeditThis(GtkWidget *widget, GdkEventExpose *) {
|
2013-08-28 00:44:27 +00:00
|
|
|
try {
|
2022-01-04 23:07:50 +00:00
|
|
|
PreEditString pes(im_context.get());
|
|
|
|
UniquePangoLayout layout(gtk_widget_create_pango_layout(PWidget(wText), pes.str));
|
|
|
|
pango_layout_set_attributes(layout.get(), pes.attrs);
|
|
|
|
|
|
|
|
UniqueCairo context(gdk_cairo_create(WindowFromWidget(widget)));
|
|
|
|
cairo_move_to(context.get(), 0, 0);
|
|
|
|
pango_cairo_show_layout(context.get(), layout.get());
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
gboolean ScintillaGTK::ExposePreedit(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis) {
|
|
|
|
return sciThis->ExposePreeditThis(widget, ose);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2013-08-28 00:44:27 +00:00
|
|
|
#endif
|
|
|
|
|
2015-06-07 21:19:26 +00:00
|
|
|
bool ScintillaGTK::KoreanIME() {
|
2022-01-04 23:07:50 +00:00
|
|
|
PreEditString pes(im_context.get());
|
2021-02-21 04:53:09 +00:00
|
|
|
if (pes.pscript != G_UNICODE_SCRIPT_COMMON)
|
2015-06-07 21:19:26 +00:00
|
|
|
lastNonCommonScript = pes.pscript;
|
2021-02-21 04:53:09 +00:00
|
|
|
return lastNonCommonScript == G_UNICODE_SCRIPT_HANGUL;
|
2015-06-07 21:19:26 +00:00
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
void ScintillaGTK::MoveImeCarets(Sci::Position pos) {
|
2015-06-07 21:19:26 +00:00
|
|
|
// Move carets relatively by bytes
|
|
|
|
for (size_t r=0; r<sel.Count(); r++) {
|
2019-07-21 13:26:02 +00:00
|
|
|
const Sci::Position positionInsert = sel.Range(r).Start().Position();
|
2015-06-07 21:19:26 +00:00
|
|
|
sel.Range(r).caret.SetPosition(positionInsert + pos);
|
|
|
|
sel.Range(r).anchor.SetPosition(positionInsert + pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
void ScintillaGTK::DrawImeIndicator(int indicator, Sci::Position len) {
|
2015-06-07 21:19:26 +00:00
|
|
|
// Emulate the visual style of IME characters with indicators.
|
|
|
|
// Draw an indicator on the character before caret by the character bytes of len
|
2019-07-21 13:26:02 +00:00
|
|
|
// so it should be called after InsertCharacter().
|
2015-06-07 21:19:26 +00:00
|
|
|
// It does not affect caret positions.
|
2019-07-21 13:26:02 +00:00
|
|
|
if (indicator < 8 || indicator > INDICATOR_MAX) {
|
2015-06-07 21:19:26 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-05-04 18:14:48 +00:00
|
|
|
pdoc->DecorationSetCurrentIndicator(indicator);
|
2015-06-07 21:19:26 +00:00
|
|
|
for (size_t r=0; r<sel.Count(); r++) {
|
2019-07-21 13:26:02 +00:00
|
|
|
const Sci::Position positionInsert = sel.Range(r).Start().Position();
|
2015-06-07 21:19:26 +00:00
|
|
|
pdoc->DecorationFillRange(positionInsert - len, 1, len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
std::vector<int> MapImeIndicators(PangoAttrList *attrs, const char *u8Str) {
|
2019-05-04 18:14:48 +00:00
|
|
|
// Map input style to scintilla ime indicator.
|
|
|
|
// Attrs position points between UTF-8 bytes.
|
|
|
|
// Indicator index to be returned is character based though.
|
2019-07-21 13:26:02 +00:00
|
|
|
const glong charactersLen = g_utf8_strlen(u8Str, strlen(u8Str));
|
2019-05-04 18:14:48 +00:00
|
|
|
std::vector<int> indicator(charactersLen, SC_INDICATOR_UNKNOWN);
|
|
|
|
|
2015-06-07 21:19:26 +00:00
|
|
|
PangoAttrIterator *iterunderline = pango_attr_list_get_iterator(attrs);
|
|
|
|
if (iterunderline) {
|
|
|
|
do {
|
2022-01-04 23:07:50 +00:00
|
|
|
const PangoAttribute *attrunderline = pango_attr_iterator_get(iterunderline, PANGO_ATTR_UNDERLINE);
|
2015-06-07 21:19:26 +00:00
|
|
|
if (attrunderline) {
|
2019-07-21 13:26:02 +00:00
|
|
|
const glong start = g_utf8_strlen(u8Str, attrunderline->start_index);
|
|
|
|
const glong end = g_utf8_strlen(u8Str, attrunderline->end_index);
|
2022-01-04 23:07:50 +00:00
|
|
|
const int ulinevalue = reinterpret_cast<const PangoAttrInt *>(attrunderline)->value;
|
|
|
|
const PangoUnderline uline = static_cast<PangoUnderline>(ulinevalue);
|
2015-06-07 21:19:26 +00:00
|
|
|
for (glong i=start; i < end; ++i) {
|
|
|
|
switch (uline) {
|
|
|
|
case PANGO_UNDERLINE_NONE:
|
2019-05-04 18:14:48 +00:00
|
|
|
indicator[i] = SC_INDICATOR_UNKNOWN;
|
2015-06-07 21:19:26 +00:00
|
|
|
break;
|
|
|
|
case PANGO_UNDERLINE_SINGLE: // normal input
|
2019-05-04 18:14:48 +00:00
|
|
|
indicator[i] = SC_INDICATOR_INPUT;
|
2015-06-07 21:19:26 +00:00
|
|
|
break;
|
|
|
|
case PANGO_UNDERLINE_DOUBLE:
|
|
|
|
case PANGO_UNDERLINE_LOW:
|
|
|
|
case PANGO_UNDERLINE_ERROR:
|
2022-01-04 23:07:50 +00:00
|
|
|
default:
|
2015-06-07 21:19:26 +00:00
|
|
|
break;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-06-07 21:19:26 +00:00
|
|
|
} while (pango_attr_iterator_next(iterunderline));
|
|
|
|
pango_attr_iterator_destroy(iterunderline);
|
|
|
|
}
|
|
|
|
|
|
|
|
PangoAttrIterator *itercolor = pango_attr_list_get_iterator(attrs);
|
|
|
|
if (itercolor) {
|
|
|
|
do {
|
2019-07-21 13:26:02 +00:00
|
|
|
const PangoAttribute *backcolor = pango_attr_iterator_get(itercolor, PANGO_ATTR_BACKGROUND);
|
2015-06-07 21:19:26 +00:00
|
|
|
if (backcolor) {
|
2019-07-21 13:26:02 +00:00
|
|
|
const glong start = g_utf8_strlen(u8Str, backcolor->start_index);
|
|
|
|
const glong end = g_utf8_strlen(u8Str, backcolor->end_index);
|
2015-06-07 21:19:26 +00:00
|
|
|
for (glong i=start; i < end; ++i) {
|
2019-05-04 18:14:48 +00:00
|
|
|
indicator[i] = SC_INDICATOR_TARGET; // target converted
|
2015-06-07 21:19:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (pango_attr_iterator_next(itercolor));
|
|
|
|
pango_attr_iterator_destroy(itercolor);
|
|
|
|
}
|
2019-05-04 18:14:48 +00:00
|
|
|
return indicator;
|
2015-06-07 21:19:26 +00:00
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
}
|
|
|
|
|
2015-06-07 21:19:26 +00:00
|
|
|
void ScintillaGTK::SetCandidateWindowPos() {
|
|
|
|
// Composition box accompanies candidate box.
|
2019-07-21 13:26:02 +00:00
|
|
|
const Point pt = PointMainCaret();
|
2022-01-04 23:07:50 +00:00
|
|
|
GdkRectangle imeBox {};
|
2021-02-21 04:53:09 +00:00
|
|
|
imeBox.x = static_cast<gint>(pt.x);
|
|
|
|
imeBox.y = static_cast<gint>(pt.y + std::max(4, vs.lineHeight/4));
|
|
|
|
// prevent overlapping with current line
|
|
|
|
imeBox.height = vs.lineHeight;
|
2022-01-04 23:07:50 +00:00
|
|
|
gtk_im_context_set_cursor_location(im_context.get(), &imeBox);
|
2015-06-07 21:19:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::CommitThis(char *commitStr) {
|
|
|
|
try {
|
|
|
|
//~ fprintf(stderr, "Commit '%s'\n", commitStr);
|
|
|
|
view.imeCaretBlockOverride = false;
|
|
|
|
|
|
|
|
if (pdoc->TentativeActive()) {
|
|
|
|
pdoc->TentativeUndo();
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
2015-06-07 21:19:26 +00:00
|
|
|
|
|
|
|
const char *charSetSource = CharacterSetID();
|
|
|
|
|
|
|
|
glong uniStrLen = 0;
|
2022-01-04 23:07:50 +00:00
|
|
|
gunichar *uniStr = g_utf8_to_ucs4_fast(commitStr, static_cast<glong>(strlen(commitStr)), &uniStrLen);
|
2015-06-07 21:19:26 +00:00
|
|
|
for (glong i = 0; i < uniStrLen; i++) {
|
2019-05-04 18:14:48 +00:00
|
|
|
gchar u8Char[UTF8MaxBytes+2] = {0};
|
2019-07-21 13:26:02 +00:00
|
|
|
const gint u8CharLen = g_unichar_to_utf8(uniStr[i], u8Char);
|
2019-05-04 18:14:48 +00:00
|
|
|
std::string docChar = u8Char;
|
|
|
|
if (!IsUnicodeMode())
|
|
|
|
docChar = ConvertText(u8Char, u8CharLen, charSetSource, "UTF-8", true);
|
2015-06-07 21:19:26 +00:00
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
InsertCharacter(docChar, CharacterSource::DirectInput);
|
2015-06-07 21:19:26 +00:00
|
|
|
}
|
|
|
|
g_free(uniStr);
|
|
|
|
ShowCaretAtCurrentPosition();
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
void ScintillaGTK::Commit(GtkIMContext *, char *str, ScintillaGTK *sciThis) {
|
|
|
|
sciThis->CommitThis(str);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2015-06-07 21:19:26 +00:00
|
|
|
void ScintillaGTK::PreeditChangedInlineThis() {
|
|
|
|
// Copy & paste by johnsonj with a lot of helps of Neil
|
|
|
|
// Great thanks for my foreruners, jiniya and BLUEnLIVE
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
2019-05-04 18:14:48 +00:00
|
|
|
if (pdoc->IsReadOnly() || SelectionContainsProtected()) {
|
2022-01-04 23:07:50 +00:00
|
|
|
gtk_im_context_reset(im_context.get());
|
2019-05-04 18:14:48 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-06-07 21:19:26 +00:00
|
|
|
view.imeCaretBlockOverride = false; // If backspace.
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
bool initialCompose = false;
|
2015-06-07 21:19:26 +00:00
|
|
|
if (pdoc->TentativeActive()) {
|
|
|
|
pdoc->TentativeUndo();
|
|
|
|
} else {
|
|
|
|
// No tentative undo means start of this composition so
|
|
|
|
// fill in any virtual spaces.
|
2019-05-04 18:14:48 +00:00
|
|
|
initialCompose = true;
|
2015-06-07 21:19:26 +00:00
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
PreEditString preeditStr(im_context.get());
|
2015-06-07 21:19:26 +00:00
|
|
|
const char *charSetSource = CharacterSetID();
|
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
if (!preeditStr.validUTF8 || (charSetSource == nullptr)) {
|
2015-06-07 21:19:26 +00:00
|
|
|
ShowCaretAtCurrentPosition();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
if (preeditStr.uniStrLen == 0) {
|
2015-06-07 21:19:26 +00:00
|
|
|
ShowCaretAtCurrentPosition();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-02-21 04:53:09 +00:00
|
|
|
if (initialCompose) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ClearBeforeTentativeStart();
|
2021-02-21 04:53:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SetCandidateWindowPos();
|
2015-06-07 21:19:26 +00:00
|
|
|
pdoc->TentativeStart(); // TentativeActive() from now on
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
std::vector<int> indicator = MapImeIndicators(preeditStr.attrs, preeditStr.str);
|
2015-06-07 21:19:26 +00:00
|
|
|
|
|
|
|
for (glong i = 0; i < preeditStr.uniStrLen; i++) {
|
2019-05-04 18:14:48 +00:00
|
|
|
gchar u8Char[UTF8MaxBytes+2] = {0};
|
2019-07-21 13:26:02 +00:00
|
|
|
const gint u8CharLen = g_unichar_to_utf8(preeditStr.uniStr[i], u8Char);
|
2019-05-04 18:14:48 +00:00
|
|
|
std::string docChar = u8Char;
|
|
|
|
if (!IsUnicodeMode())
|
|
|
|
docChar = ConvertText(u8Char, u8CharLen, charSetSource, "UTF-8", true);
|
2015-06-07 21:19:26 +00:00
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
InsertCharacter(docChar, CharacterSource::TentativeInput);
|
2015-06-07 21:19:26 +00:00
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
DrawImeIndicator(indicator[i], docChar.size());
|
2015-06-07 21:19:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Move caret to ime cursor position.
|
2019-07-21 13:26:02 +00:00
|
|
|
const int imeEndToImeCaretU32 = preeditStr.cursor_pos - preeditStr.uniStrLen;
|
2022-01-04 23:07:50 +00:00
|
|
|
const Sci::Position imeCaretPosDoc = pdoc->GetRelativePosition(CurrentPosition(), imeEndToImeCaretU32);
|
2019-05-04 18:14:48 +00:00
|
|
|
|
|
|
|
MoveImeCarets(- CurrentPosition() + imeCaretPosDoc);
|
|
|
|
|
2015-06-07 21:19:26 +00:00
|
|
|
if (KoreanIME()) {
|
2019-05-04 18:14:48 +00:00
|
|
|
#if !PLAT_GTK_WIN32
|
|
|
|
if (preeditStr.cursor_pos > 0) {
|
|
|
|
int oneCharBefore = pdoc->GetRelativePosition(CurrentPosition(), -1);
|
|
|
|
MoveImeCarets(- CurrentPosition() + oneCharBefore);
|
|
|
|
}
|
|
|
|
#endif
|
2015-06-07 21:19:26 +00:00
|
|
|
view.imeCaretBlockOverride = true;
|
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
EnsureCaretVisible();
|
2015-06-07 21:19:26 +00:00
|
|
|
ShowCaretAtCurrentPosition();
|
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2015-06-07 21:19:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::PreeditChangedWindowedThis() {
|
|
|
|
try {
|
2022-01-04 23:07:50 +00:00
|
|
|
PreEditString pes(im_context.get());
|
2015-06-07 21:19:26 +00:00
|
|
|
if (strlen(pes.str) > 0) {
|
2021-02-21 04:53:09 +00:00
|
|
|
SetCandidateWindowPos();
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
UniquePangoLayout layout(gtk_widget_create_pango_layout(PWidget(wText), pes.str));
|
|
|
|
pango_layout_set_attributes(layout.get(), pes.attrs);
|
2009-08-23 02:24:48 +00:00
|
|
|
|
|
|
|
gint w, h;
|
2022-01-04 23:07:50 +00:00
|
|
|
pango_layout_get_pixel_size(layout.get(), &w, &h);
|
2009-08-23 02:24:48 +00:00
|
|
|
|
|
|
|
gint x, y;
|
2011-07-17 22:30:49 +00:00
|
|
|
gdk_window_get_origin(PWindow(wText), &x, &y);
|
2009-08-23 02:24:48 +00:00
|
|
|
|
|
|
|
Point pt = PointMainCaret();
|
|
|
|
if (pt.x < 0)
|
|
|
|
pt.x = 0;
|
|
|
|
if (pt.y < 0)
|
|
|
|
pt.y = 0;
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
gtk_window_move(GTK_WINDOW(PWidget(wPreedit)), x + static_cast<gint>(pt.x), y + static_cast<gint>(pt.y));
|
2009-08-23 02:24:48 +00:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::PreeditChanged(GtkIMContext *, ScintillaGTK *sciThis) {
|
2022-01-04 23:07:50 +00:00
|
|
|
if ((sciThis->imeInteraction == IMEInteraction::Inline) || (sciThis->KoreanIME())) {
|
2015-06-07 21:19:26 +00:00
|
|
|
sciThis->PreeditChangedInlineThis();
|
|
|
|
} else {
|
|
|
|
sciThis->PreeditChangedWindowedThis();
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2023-02-09 16:57:24 +00:00
|
|
|
bool ScintillaGTK::RetrieveSurroundingThis(GtkIMContext *context) {
|
|
|
|
try {
|
|
|
|
const Sci::Position pos = CurrentPosition();
|
|
|
|
const int line = pdoc->LineFromPosition(pos);
|
|
|
|
const Sci::Position startByte = pdoc->LineStart(line);
|
|
|
|
const Sci::Position endByte = pdoc->LineEnd(line);
|
|
|
|
|
|
|
|
std::string utf8Text;
|
|
|
|
gint cursorIndex; // index of the cursor inside utf8Text, in bytes
|
|
|
|
const char *charSetBuffer;
|
|
|
|
|
|
|
|
if (IsUnicodeMode() || ! *(charSetBuffer = CharacterSetID())) {
|
|
|
|
utf8Text = RangeText(startByte, endByte);
|
|
|
|
cursorIndex = pos - startByte;
|
|
|
|
} else {
|
|
|
|
// Need to convert
|
|
|
|
std::string tmpbuf = RangeText(startByte, pos);
|
|
|
|
utf8Text = ConvertText(&tmpbuf[0], tmpbuf.length(), "UTF-8", charSetBuffer, false);
|
|
|
|
cursorIndex = utf8Text.length();
|
|
|
|
if (endByte > pos) {
|
|
|
|
tmpbuf = RangeText(pos, endByte);
|
|
|
|
utf8Text += ConvertText(&tmpbuf[0], tmpbuf.length(), "UTF-8", charSetBuffer, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_im_context_set_surrounding(context, &utf8Text[0], utf8Text.length(), cursorIndex);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
} catch (...) {
|
|
|
|
errorStatus = Status::Failure;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean ScintillaGTK::RetrieveSurrounding(GtkIMContext *context, ScintillaGTK *sciThis) {
|
|
|
|
return sciThis->RetrieveSurroundingThis(context);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScintillaGTK::DeleteSurroundingThis(GtkIMContext *, gint characterOffset, gint characterCount) {
|
|
|
|
try {
|
|
|
|
const Sci::Position startByte = pdoc->GetRelativePosition(CurrentPosition(), characterOffset);
|
|
|
|
if (startByte == INVALID_POSITION)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const Sci::Position endByte = pdoc->GetRelativePosition(startByte, characterCount);
|
|
|
|
if (endByte == INVALID_POSITION)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return pdoc->DeleteChars(startByte, endByte - startByte);
|
|
|
|
} catch (...) {
|
|
|
|
errorStatus = Status::Failure;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean ScintillaGTK::DeleteSurrounding(GtkIMContext *context, gint characterOffset, gint characterCount, ScintillaGTK *sciThis) {
|
|
|
|
return sciThis->DeleteSurroundingThis(context, characterOffset, characterCount);
|
|
|
|
}
|
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
void ScintillaGTK::StyleSetText(GtkWidget *widget, GtkStyle *, void *) {
|
|
|
|
RealizeText(widget, nullptr);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
void ScintillaGTK::RealizeText(GtkWidget *widget, void *) {
|
2011-07-17 22:30:49 +00:00
|
|
|
// Set NULL background to avoid automatic clearing so Scintilla responsible for all drawing
|
|
|
|
if (WindowFromWidget(widget)) {
|
2019-05-04 18:14:48 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,22,0)
|
|
|
|
// Appears unnecessary
|
|
|
|
#elif GTK_CHECK_VERSION(3,0,0)
|
2019-07-21 13:26:02 +00:00
|
|
|
gdk_window_set_background_pattern(WindowFromWidget(widget), nullptr);
|
2011-07-17 22:30:49 +00:00
|
|
|
#else
|
2019-07-21 13:26:02 +00:00
|
|
|
gdk_window_set_back_pixmap(WindowFromWidget(widget), nullptr, FALSE);
|
2011-07-17 22:30:49 +00:00
|
|
|
#endif
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2015-06-07 21:19:26 +00:00
|
|
|
static GObjectClass *scintilla_class_parent_class;
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
void ScintillaGTK::Dispose(GObject *object) {
|
|
|
|
try {
|
|
|
|
ScintillaObject *scio = SCINTILLA(object);
|
|
|
|
ScintillaGTK *sciThis = static_cast<ScintillaGTK *>(scio->pscin);
|
|
|
|
|
|
|
|
if (PWidget(sciThis->scrollbarv)) {
|
|
|
|
gtk_widget_unparent(PWidget(sciThis->scrollbarv));
|
2019-07-21 13:26:02 +00:00
|
|
|
sciThis->scrollbarv = nullptr;
|
2019-05-04 18:14:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (PWidget(sciThis->scrollbarh)) {
|
|
|
|
gtk_widget_unparent(PWidget(sciThis->scrollbarh));
|
2019-07-21 13:26:02 +00:00
|
|
|
sciThis->scrollbarh = nullptr;
|
2019-05-04 18:14:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
scintilla_class_parent_class->dispose(object);
|
|
|
|
} catch (...) {
|
|
|
|
// Its dying so nowhere to save the status
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-12 22:19:51 +00:00
|
|
|
void ScintillaGTK::Destroy(GObject *object) {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaObject *scio = SCINTILLA(object);
|
2015-06-07 21:19:26 +00:00
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
// This avoids a double destruction
|
|
|
|
if (!scio->pscin)
|
|
|
|
return;
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = static_cast<ScintillaGTK *>(scio->pscin);
|
2009-08-23 02:24:48 +00:00
|
|
|
//Platform::DebugPrintf("Destroying %x %x\n", sciThis, object);
|
|
|
|
sciThis->Finalise();
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
delete sciThis;
|
2019-07-21 13:26:02 +00:00
|
|
|
scio->pscin = nullptr;
|
2015-06-07 21:19:26 +00:00
|
|
|
scintilla_class_parent_class->finalize(object);
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
|
|
|
// Its dead so nowhere to save the status
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
void ScintillaGTK::CheckForFontOptionChange() {
|
|
|
|
const FontOptions fontOptionsNow(PWidget(wText));
|
|
|
|
if (!(fontOptionsNow == fontOptionsPrevious)) {
|
|
|
|
// Clear position caches
|
|
|
|
InvalidateStyleData();
|
|
|
|
}
|
|
|
|
fontOptionsPrevious = fontOptionsNow;
|
|
|
|
}
|
|
|
|
|
2011-07-17 22:30:49 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
|
|
|
|
gboolean ScintillaGTK::DrawTextThis(cairo_t *cr) {
|
|
|
|
try {
|
2022-01-04 23:07:50 +00:00
|
|
|
CheckForFontOptionChange();
|
|
|
|
|
|
|
|
paintState = PaintState::painting;
|
2015-06-07 21:19:26 +00:00
|
|
|
repaintFullWindow = false;
|
2011-07-17 22:30:49 +00:00
|
|
|
|
|
|
|
rcPaint = GetClientRectangle();
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
cairo_rectangle_list_t *oldRgnUpdate = rgnUpdate;
|
2011-07-17 22:30:49 +00:00
|
|
|
rgnUpdate = cairo_copy_clip_rectangle_list(cr);
|
|
|
|
if (rgnUpdate && rgnUpdate->status != CAIRO_STATUS_SUCCESS) {
|
|
|
|
// If not successful then ignore
|
|
|
|
fprintf(stderr, "DrawTextThis failed to copy update region %d [%d]\n", rgnUpdate->status, rgnUpdate->num_rectangles);
|
|
|
|
cairo_rectangle_list_destroy(rgnUpdate);
|
2022-01-04 23:07:50 +00:00
|
|
|
rgnUpdate = nullptr;
|
2011-07-17 22:30:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double x1, y1, x2, y2;
|
|
|
|
cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
|
|
|
|
rcPaint.left = x1;
|
|
|
|
rcPaint.top = y1;
|
|
|
|
rcPaint.right = x2;
|
|
|
|
rcPaint.bottom = y2;
|
|
|
|
PRectangle rcClient = GetClientRectangle();
|
|
|
|
paintingAllText = rcPaint.Contains(rcClient);
|
2022-01-04 23:07:50 +00:00
|
|
|
std::unique_ptr<Surface> surfaceWindow(Surface::Allocate(Technology::Default));
|
2019-05-04 18:14:48 +00:00
|
|
|
surfaceWindow->Init(cr, PWidget(wText));
|
|
|
|
Paint(surfaceWindow.get(), rcPaint);
|
|
|
|
surfaceWindow->Release();
|
2022-01-04 23:07:50 +00:00
|
|
|
if ((paintState == PaintState::abandoned) || repaintFullWindow) {
|
2011-07-17 22:30:49 +00:00
|
|
|
// Painting area was insufficient to cover new styling or brace highlight positions
|
|
|
|
FullPaint();
|
|
|
|
}
|
2022-01-04 23:07:50 +00:00
|
|
|
paintState = PaintState::notPainting;
|
2015-06-07 21:19:26 +00:00
|
|
|
repaintFullWindow = false;
|
2011-07-17 22:30:49 +00:00
|
|
|
|
|
|
|
if (rgnUpdate) {
|
|
|
|
cairo_rectangle_list_destroy(rgnUpdate);
|
|
|
|
}
|
2022-01-04 23:07:50 +00:00
|
|
|
rgnUpdate = oldRgnUpdate;
|
|
|
|
paintState = PaintState::notPainting;
|
2011-07-17 22:30:49 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2011-07-17 22:30:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean ScintillaGTK::DrawText(GtkWidget *, cairo_t *cr, ScintillaGTK *sciThis) {
|
|
|
|
return sciThis->DrawTextThis(cr);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean ScintillaGTK::DrawThis(cairo_t *cr) {
|
|
|
|
try {
|
2019-05-04 18:14:48 +00:00
|
|
|
#ifdef GTK_STYLE_CLASS_SCROLLBARS_JUNCTION /* GTK >= 3.4 */
|
|
|
|
// if both scrollbars are visible, paint the little square on the bottom right corner
|
|
|
|
if (verticalScrollBarVisible && horizontalScrollBarVisible && !Wrapping()) {
|
|
|
|
GtkStyleContext *styleContext = gtk_widget_get_style_context(PWidget(wMain));
|
|
|
|
PRectangle rc = GetClientRectangle();
|
|
|
|
|
|
|
|
gtk_style_context_save(styleContext);
|
|
|
|
gtk_style_context_add_class(styleContext, GTK_STYLE_CLASS_SCROLLBARS_JUNCTION);
|
|
|
|
|
|
|
|
gtk_render_background(styleContext, cr, rc.right, rc.bottom,
|
2019-07-21 13:26:02 +00:00
|
|
|
verticalScrollBarWidth, horizontalScrollBarHeight);
|
2019-05-04 18:14:48 +00:00
|
|
|
gtk_render_frame(styleContext, cr, rc.right, rc.bottom,
|
2019-07-21 13:26:02 +00:00
|
|
|
verticalScrollBarWidth, horizontalScrollBarHeight);
|
2019-05-04 18:14:48 +00:00
|
|
|
|
|
|
|
gtk_style_context_restore(styleContext);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-07-17 22:30:49 +00:00
|
|
|
gtk_container_propagate_draw(
|
2019-07-21 13:26:02 +00:00
|
|
|
GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarh), cr);
|
2011-07-17 22:30:49 +00:00
|
|
|
gtk_container_propagate_draw(
|
2019-07-21 13:26:02 +00:00
|
|
|
GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarv), cr);
|
2015-06-07 21:19:26 +00:00
|
|
|
// Starting from the following version, the expose event are not propagated
|
|
|
|
// for double buffered non native windows, so we need to call it ourselves
|
|
|
|
// or keep the default handler
|
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
// we want to forward on any >= 3.9.2 runtime
|
2019-07-21 13:26:02 +00:00
|
|
|
if (gtk_check_version(3, 9, 2) == nullptr) {
|
2015-06-07 21:19:26 +00:00
|
|
|
gtk_container_propagate_draw(
|
2019-07-21 13:26:02 +00:00
|
|
|
GTK_CONTAINER(PWidget(wMain)), PWidget(wText), cr);
|
2015-06-07 21:19:26 +00:00
|
|
|
}
|
|
|
|
#endif
|
2011-07-17 22:30:49 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2011-07-17 22:30:49 +00:00
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean ScintillaGTK::DrawMain(GtkWidget *widget, cairo_t *cr) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2011-07-17 22:30:49 +00:00
|
|
|
return sciThis->DrawThis(cr);
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
gboolean ScintillaGTK::ExposeTextThis(GtkWidget * /*widget*/, GdkEventExpose *ose) {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
2022-01-04 23:07:50 +00:00
|
|
|
CheckForFontOptionChange();
|
|
|
|
|
|
|
|
paintState = PaintState::painting;
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
rcPaint = PRectangle::FromInts(
|
|
|
|
ose->area.x,
|
|
|
|
ose->area.y,
|
|
|
|
ose->area.x + ose->area.width,
|
|
|
|
ose->area.y + ose->area.height);
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
GdkRegion *oldRgnUpdate = rgnUpdate;
|
2009-08-23 02:24:48 +00:00
|
|
|
rgnUpdate = gdk_region_copy(ose->region);
|
2019-07-21 13:26:02 +00:00
|
|
|
const PRectangle rcClient = GetClientRectangle();
|
2009-08-23 02:24:48 +00:00
|
|
|
paintingAllText = rcPaint.Contains(rcClient);
|
2022-01-04 23:07:50 +00:00
|
|
|
{
|
|
|
|
std::unique_ptr<Surface> surfaceWindow(Surface::Allocate(Technology::Default));
|
|
|
|
UniqueCairo cr(gdk_cairo_create(PWindow(wText)));
|
|
|
|
surfaceWindow->Init(cr.get(), PWidget(wText));
|
|
|
|
Paint(surfaceWindow.get(), rcPaint);
|
|
|
|
}
|
|
|
|
if ((paintState == PaintState::abandoned) || repaintFullWindow) {
|
2009-08-23 02:24:48 +00:00
|
|
|
// Painting area was insufficient to cover new styling or brace highlight positions
|
|
|
|
FullPaint();
|
|
|
|
}
|
2022-01-04 23:07:50 +00:00
|
|
|
paintState = PaintState::notPainting;
|
2019-05-04 18:14:48 +00:00
|
|
|
repaintFullWindow = false;
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
if (rgnUpdate) {
|
|
|
|
gdk_region_destroy(rgnUpdate);
|
|
|
|
}
|
2022-01-04 23:07:50 +00:00
|
|
|
rgnUpdate = oldRgnUpdate;
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2011-07-17 22:30:49 +00:00
|
|
|
gboolean ScintillaGTK::ExposeText(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis) {
|
2009-04-24 23:35:41 +00:00
|
|
|
return sciThis->ExposeTextThis(widget, ose);
|
|
|
|
}
|
|
|
|
|
2011-07-17 22:30:49 +00:00
|
|
|
gboolean ScintillaGTK::ExposeMain(GtkWidget *widget, GdkEventExpose *ose) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-04-24 23:35:41 +00:00
|
|
|
//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);
|
|
|
|
}
|
|
|
|
|
2011-07-17 22:30:49 +00:00
|
|
|
gboolean ScintillaGTK::Expose(GtkWidget *, GdkEventExpose *ose) {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
|
|
|
//fprintf(stderr, "Expose %0d,%0d %0d,%0d\n",
|
|
|
|
//ose->area.x, ose->area.y, ose->area.width, ose->area.height);
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2010-07-12 22:19:51 +00:00
|
|
|
// The text is painted in ExposeText
|
2009-08-23 02:24:48 +00:00
|
|
|
gtk_container_propagate_expose(
|
2019-07-21 13:26:02 +00:00
|
|
|
GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarh), ose);
|
2009-08-23 02:24:48 +00:00
|
|
|
gtk_container_propagate_expose(
|
2019-07-21 13:26:02 +00:00
|
|
|
GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarv), ose);
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2011-07-17 22:30:49 +00:00
|
|
|
#endif
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
void ScintillaGTK::ScrollSignal(GtkAdjustment *adj, ScintillaGTK *sciThis) {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
2011-07-17 22:30:49 +00:00
|
|
|
sciThis->ScrollTo(static_cast<int>(gtk_adjustment_get_value(adj)), false);
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
sciThis->errorStatus = Status::Failure;
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::ScrollHSignal(GtkAdjustment *adj, ScintillaGTK *sciThis) {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
2015-06-07 21:19:26 +00:00
|
|
|
sciThis->HorizontalScrollTo(static_cast<int>(gtk_adjustment_get_value(adj)));
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
sciThis->errorStatus = Status::Failure;
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::SelectionReceived(GtkWidget *widget,
|
2019-07-21 13:26:02 +00:00
|
|
|
GtkSelectionData *selection_data, guint) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-04-24 23:35:41 +00:00
|
|
|
//Platform::DebugPrintf("Selection received\n");
|
|
|
|
sciThis->ReceivedSelection(selection_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::SelectionGet(GtkWidget *widget,
|
2019-07-21 13:26:02 +00:00
|
|
|
GtkSelectionData *selection_data, guint info, guint) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
|
|
|
//Platform::DebugPrintf("Selection get\n");
|
2011-07-17 22:30:49 +00:00
|
|
|
if (SelectionOfGSD(selection_data) == GDK_SELECTION_PRIMARY) {
|
2013-08-28 00:44:27 +00:00
|
|
|
if (sciThis->primary.Empty()) {
|
2009-08-23 02:24:48 +00:00
|
|
|
sciThis->CopySelectionRange(&sciThis->primary);
|
|
|
|
}
|
|
|
|
sciThis->GetSelection(selection_data, info, &sciThis->primary);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
sciThis->errorStatus = Status::Failure;
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gint ScintillaGTK::SelectionClear(GtkWidget *widget, GdkEventSelection *selection_event) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-04-24 23:35:41 +00:00
|
|
|
//Platform::DebugPrintf("Selection clear\n");
|
|
|
|
sciThis->UnclaimSelection(selection_event);
|
2010-09-05 22:56:27 +00:00
|
|
|
if (GTK_WIDGET_CLASS(sciThis->parentClass)->selection_clear_event) {
|
|
|
|
return GTK_WIDGET_CLASS(sciThis->parentClass)->selection_clear_event(widget, selection_event);
|
|
|
|
}
|
|
|
|
return TRUE;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gboolean ScintillaGTK::DragMotionThis(GdkDragContext *context,
|
2019-07-21 13:26:02 +00:00
|
|
|
gint x, gint y, guint dragtime) {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
2019-07-21 13:26:02 +00:00
|
|
|
const Point npt = Point::FromInts(x, y);
|
2009-08-23 02:24:48 +00:00
|
|
|
SetDragPosition(SPositionFromLocation(npt, false, false, UserVirtualSpace()));
|
2011-07-17 22:30:49 +00:00
|
|
|
GdkDragAction preferredAction = gdk_drag_context_get_suggested_action(context);
|
2019-07-21 13:26:02 +00:00
|
|
|
const GdkDragAction actions = gdk_drag_context_get_actions(context);
|
|
|
|
const SelectionPosition pos = SPositionFromLocation(npt);
|
2022-01-04 23:07:50 +00:00
|
|
|
if ((inDragDrop == DragDrop::dragging) && (PositionInSelection(pos.Position()))) {
|
2009-08-23 02:24:48 +00:00
|
|
|
// Avoid dragging selection onto itself as that produces a move
|
|
|
|
// with no real effect but which creates undo actions.
|
|
|
|
preferredAction = static_cast<GdkDragAction>(0);
|
2019-05-04 18:14:48 +00:00
|
|
|
} else if (actions == actionCopyOrMove) {
|
2009-08-23 02:24:48 +00:00
|
|
|
preferredAction = GDK_ACTION_MOVE;
|
|
|
|
}
|
|
|
|
gdk_drag_status(context, preferredAction, dragtime);
|
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
errorStatus = Status::Failure;
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean ScintillaGTK::DragMotion(GtkWidget *widget, GdkDragContext *context,
|
2019-07-21 13:26:02 +00:00
|
|
|
gint x, gint y, guint dragtime) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-04-24 23:35:41 +00:00
|
|
|
return sciThis->DragMotionThis(context, x, y, dragtime);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::DragLeave(GtkWidget *widget, GdkDragContext * /*context*/, guint) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
2019-05-04 18:14:48 +00:00
|
|
|
sciThis->SetDragPosition(SelectionPosition(Sci::invalidPosition));
|
2009-08-23 02:24:48 +00:00
|
|
|
//Platform::DebugPrintf("DragLeave %x\n", sciThis);
|
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
sciThis->errorStatus = Status::Failure;
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::DragEnd(GtkWidget *widget, GdkDragContext * /*context*/) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
|
|
|
// If drag did not result in drop here or elsewhere
|
|
|
|
if (!sciThis->dragWasDropped)
|
|
|
|
sciThis->SetEmptySelection(sciThis->posDrag);
|
2019-05-04 18:14:48 +00:00
|
|
|
sciThis->SetDragPosition(SelectionPosition(Sci::invalidPosition));
|
2009-08-23 02:24:48 +00:00
|
|
|
//Platform::DebugPrintf("DragEnd %x %d\n", sciThis, sciThis->dragWasDropped);
|
2022-01-04 23:07:50 +00:00
|
|
|
sciThis->inDragDrop = DragDrop::none;
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
sciThis->errorStatus = Status::Failure;
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gboolean ScintillaGTK::Drop(GtkWidget *widget, GdkDragContext * /*context*/,
|
2019-07-21 13:26:02 +00:00
|
|
|
gint, gint, guint) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
|
|
|
//Platform::DebugPrintf("Drop %x\n", sciThis);
|
2019-05-04 18:14:48 +00:00
|
|
|
sciThis->SetDragPosition(SelectionPosition(Sci::invalidPosition));
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
sciThis->errorStatus = Status::Failure;
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::DragDataReceived(GtkWidget *widget, GdkDragContext * /*context*/,
|
2019-07-21 13:26:02 +00:00
|
|
|
gint, gint, GtkSelectionData *selection_data, guint /*info*/, guint) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
|
|
|
sciThis->ReceivedDrop(selection_data);
|
2019-05-04 18:14:48 +00:00
|
|
|
sciThis->SetDragPosition(SelectionPosition(Sci::invalidPosition));
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
sciThis->errorStatus = Status::Failure;
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::DragDataGet(GtkWidget *widget, GdkDragContext *context,
|
2019-07-21 13:26:02 +00:00
|
|
|
GtkSelectionData *selection_data, guint info, guint) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *sciThis = FromWidget(widget);
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
|
|
|
sciThis->dragWasDropped = true;
|
|
|
|
if (!sciThis->sel.Empty()) {
|
|
|
|
sciThis->GetSelection(selection_data, info, &sciThis->drag);
|
|
|
|
}
|
2019-07-21 13:26:02 +00:00
|
|
|
const GdkDragAction action = gdk_drag_context_get_selected_action(context);
|
2011-07-17 22:30:49 +00:00
|
|
|
if (action == GDK_ACTION_MOVE) {
|
2009-08-23 02:24:48 +00:00
|
|
|
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();
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
2019-05-04 18:14:48 +00:00
|
|
|
sciThis->SetDragPosition(SelectionPosition(Sci::invalidPosition));
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
2022-01-04 23:07:50 +00:00
|
|
|
sciThis->errorStatus = Status::Failure;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
int ScintillaGTK::TimeOut(gpointer ptt) {
|
|
|
|
TimeThunk *tt = static_cast<TimeThunk *>(ptt);
|
2015-06-07 21:19:26 +00:00
|
|
|
tt->scintilla->TickFor(tt->reason);
|
2009-04-24 23:35:41 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
gboolean ScintillaGTK::IdleCallback(gpointer pSci) {
|
|
|
|
ScintillaGTK *sciThis = static_cast<ScintillaGTK *>(pSci);
|
2010-07-12 22:19:51 +00:00
|
|
|
// Idler will be automatically stopped, if there is nothing
|
2009-04-24 23:35:41 +00:00
|
|
|
// to do while idle.
|
2019-07-21 13:26:02 +00:00
|
|
|
const bool ret = sciThis->Idle();
|
2022-01-04 23:07:50 +00:00
|
|
|
if (!ret) {
|
2009-04-24 23:35:41 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
gboolean ScintillaGTK::StyleIdle(gpointer pSci) {
|
|
|
|
ScintillaGTK *sciThis = static_cast<ScintillaGTK *>(pSci);
|
2013-08-28 00:44:27 +00:00
|
|
|
sciThis->IdleWork();
|
2010-07-12 22:19:51 +00:00
|
|
|
// Idler will be automatically stopped
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
void ScintillaGTK::IdleWork() {
|
|
|
|
Editor::IdleWork();
|
|
|
|
styleIdleID = 0;
|
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
void ScintillaGTK::QueueIdleWork(WorkItems items, Sci::Position upTo) {
|
2013-08-28 00:44:27 +00:00
|
|
|
Editor::QueueIdleWork(items, upTo);
|
2019-05-04 18:14:48 +00:00
|
|
|
if (!styleIdleID) {
|
2010-07-12 22:19:51 +00:00
|
|
|
// Only allow one style needed to be queued
|
2019-07-21 13:26:02 +00:00
|
|
|
styleIdleID = gdk_threads_add_idle_full(G_PRIORITY_HIGH_IDLE, StyleIdle, this, nullptr);
|
2019-05-04 18:14:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScintillaGTK::SetDocPointer(Document *document) {
|
2019-07-21 13:26:02 +00:00
|
|
|
Document *oldDoc = nullptr;
|
|
|
|
ScintillaGTKAccessible *sciAccessible = nullptr;
|
2019-05-04 18:14:48 +00:00
|
|
|
if (accessible) {
|
|
|
|
sciAccessible = ScintillaGTKAccessible::FromAccessible(accessible);
|
|
|
|
if (sciAccessible && pdoc) {
|
|
|
|
oldDoc = pdoc;
|
|
|
|
oldDoc->AddRef();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Editor::SetDocPointer(document);
|
|
|
|
|
|
|
|
if (sciAccessible) {
|
|
|
|
// the accessible needs have the old Document, but also the new one active
|
|
|
|
sciAccessible->ChangeDocument(oldDoc, pdoc);
|
|
|
|
}
|
|
|
|
if (oldDoc) {
|
|
|
|
oldDoc->Release();
|
2010-07-12 22:19:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-05 22:56:27 +00:00
|
|
|
void ScintillaGTK::PopUpCB(GtkMenuItem *menuItem, ScintillaGTK *sciThis) {
|
2019-07-21 13:26:02 +00:00
|
|
|
guint const action = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(menuItem), "CmdNum"));
|
2009-04-24 23:35:41 +00:00
|
|
|
if (action) {
|
|
|
|
sciThis->Command(action);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-17 22:30:49 +00:00
|
|
|
gboolean ScintillaGTK::PressCT(GtkWidget *widget, GdkEventButton *event, ScintillaGTK *sciThis) {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
2011-07-17 22:30:49 +00:00
|
|
|
if (event->window != WindowFromWidget(widget))
|
2009-08-23 02:24:48 +00:00
|
|
|
return FALSE;
|
|
|
|
if (event->type != GDK_BUTTON_PRESS)
|
|
|
|
return FALSE;
|
2019-07-21 13:26:02 +00:00
|
|
|
const Point pt = PointOfEvent(event);
|
2009-08-23 02:24:48 +00:00
|
|
|
sciThis->ct.MouseClick(pt);
|
|
|
|
sciThis->CallTipClick();
|
|
|
|
} catch (...) {
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2011-07-17 22:30:49 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
|
|
|
|
gboolean ScintillaGTK::DrawCT(GtkWidget *widget, cairo_t *cr, CallTip *ctip) {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
2022-01-04 23:07:50 +00:00
|
|
|
std::unique_ptr<Surface> surfaceWindow(Surface::Allocate(Technology::Default));
|
2019-05-04 18:14:48 +00:00
|
|
|
surfaceWindow->Init(cr, widget);
|
2022-01-04 23:07:50 +00:00
|
|
|
surfaceWindow->SetMode(SurfaceMode(ctip->codePage, false));
|
2019-05-04 18:14:48 +00:00
|
|
|
ctip->PaintCT(surfaceWindow.get());
|
|
|
|
surfaceWindow->Release();
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
|
|
|
// No pointer back to Scintilla to save status
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2011-07-17 22:30:49 +00:00
|
|
|
#else
|
|
|
|
|
|
|
|
gboolean ScintillaGTK::ExposeCT(GtkWidget *widget, GdkEventExpose * /*ose*/, CallTip *ctip) {
|
|
|
|
try {
|
2022-01-04 23:07:50 +00:00
|
|
|
std::unique_ptr<Surface> surfaceWindow(Surface::Allocate(Technology::Default));
|
|
|
|
UniqueCairo cr(gdk_cairo_create(WindowFromWidget(widget)));
|
|
|
|
surfaceWindow->Init(cr.get(), widget);
|
|
|
|
surfaceWindow->SetMode(SurfaceMode(ctip->codePage, false));
|
2019-05-04 18:14:48 +00:00
|
|
|
ctip->PaintCT(surfaceWindow.get());
|
2011-07-17 22:30:49 +00:00
|
|
|
} catch (...) {
|
|
|
|
// No pointer back to Scintilla to save status
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
AtkObject *ScintillaGTK::GetAccessibleThis(GtkWidget *widget) {
|
2019-05-04 18:14:48 +00:00
|
|
|
return ScintillaGTKAccessible::WidgetGetAccessibleImpl(widget, &accessible, scintilla_class_parent_class);
|
|
|
|
}
|
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
AtkObject *ScintillaGTK::GetAccessible(GtkWidget *widget) {
|
2019-05-04 18:14:48 +00:00
|
|
|
return FromWidget(widget)->GetAccessibleThis(widget);
|
|
|
|
}
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
sptr_t ScintillaGTK::DirectFunction(
|
2019-07-21 13:26:02 +00:00
|
|
|
sptr_t ptr, unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
|
2022-01-04 23:07:50 +00:00
|
|
|
ScintillaGTK *sci = reinterpret_cast<ScintillaGTK *>(ptr);
|
|
|
|
return sci->WndProc(static_cast<Message>(iMessage), wParam, lParam);
|
|
|
|
}
|
|
|
|
|
|
|
|
sptr_t ScintillaGTK::DirectStatusFunction(
|
|
|
|
sptr_t ptr, unsigned int iMessage, uptr_t wParam, sptr_t lParam, int *pStatus) {
|
|
|
|
ScintillaGTK *sci = reinterpret_cast<ScintillaGTK *>(ptr);
|
|
|
|
const sptr_t returnValue = sci->WndProc(static_cast<Message>(iMessage), wParam, lParam);
|
|
|
|
*pStatus = static_cast<int>(sci->errorStatus);
|
|
|
|
return returnValue;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
/* legacy name for scintilla_object_send_message */
|
2009-04-24 23:35:41 +00:00
|
|
|
sptr_t scintilla_send_message(ScintillaObject *sci, unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *psci = static_cast<ScintillaGTK *>(sci->pscin);
|
2022-01-04 23:07:50 +00:00
|
|
|
return psci->WndProc(static_cast<Message>(iMessage), wParam, lParam);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
gintptr scintilla_object_send_message(ScintillaObject *sci, unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
|
|
|
|
return scintilla_send_message(sci, iMessage, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
static void scintilla_class_init(ScintillaClass *klass);
|
|
|
|
static void scintilla_init(ScintillaObject *sci);
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
/* legacy name for scintilla_object_get_type */
|
2009-04-24 23:35:41 +00:00
|
|
|
GType scintilla_get_type() {
|
|
|
|
static GType scintilla_type = 0;
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
2009-04-24 23:35:41 +00:00
|
|
|
|
|
|
|
if (!scintilla_type) {
|
2019-05-04 18:14:48 +00:00
|
|
|
scintilla_type = g_type_from_name("ScintillaObject");
|
2009-08-23 02:24:48 +00:00
|
|
|
if (!scintilla_type) {
|
|
|
|
static GTypeInfo scintilla_info = {
|
2019-07-21 13:26:02 +00:00
|
|
|
(guint16) sizeof(ScintillaObjectClass),
|
|
|
|
nullptr, //(GBaseInitFunc)
|
|
|
|
nullptr, //(GBaseFinalizeFunc)
|
2009-08-23 02:24:48 +00:00
|
|
|
(GClassInitFunc) scintilla_class_init,
|
2019-07-21 13:26:02 +00:00
|
|
|
nullptr, //(GClassFinalizeFunc)
|
|
|
|
nullptr, //gconstpointer data
|
|
|
|
(guint16) sizeof(ScintillaObject),
|
2009-08-23 02:24:48 +00:00
|
|
|
0, //n_preallocs
|
|
|
|
(GInstanceInitFunc) scintilla_init,
|
2019-07-21 13:26:02 +00:00
|
|
|
nullptr //(GTypeValueTable*)
|
2009-08-23 02:24:48 +00:00
|
|
|
};
|
|
|
|
scintilla_type = g_type_register_static(
|
2019-07-21 13:26:02 +00:00
|
|
|
GTK_TYPE_CONTAINER, "ScintillaObject", &scintilla_info, (GTypeFlags) 0);
|
2009-08-23 02:24:48 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2009-08-23 02:24:48 +00:00
|
|
|
} catch (...) {
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
return scintilla_type;
|
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
GType scintilla_object_get_type() {
|
|
|
|
return scintilla_get_type();
|
|
|
|
}
|
|
|
|
|
2019-07-21 13:26:02 +00:00
|
|
|
void ScintillaGTK::ClassInit(OBJECT_CLASS *object_class, GtkWidgetClass *widget_class, GtkContainerClass *container_class) {
|
2009-04-24 23:35:41 +00:00
|
|
|
Platform_Initialise();
|
|
|
|
atomUTF8 = gdk_atom_intern("UTF8_STRING", FALSE);
|
2021-02-21 04:53:09 +00:00
|
|
|
atomUTF8Mime = gdk_atom_intern("text/plain;charset=utf-8", FALSE);
|
2009-04-24 23:35:41 +00:00
|
|
|
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
|
2019-05-04 18:14:48 +00:00
|
|
|
// in Init() may require coordinate translation?)
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
object_class->dispose = Dispose;
|
2009-04-24 23:35:41 +00:00
|
|
|
object_class->finalize = Destroy;
|
2011-07-17 22:30:49 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
widget_class->get_preferred_width = GetPreferredWidth;
|
|
|
|
widget_class->get_preferred_height = GetPreferredHeight;
|
|
|
|
#else
|
2009-04-24 23:35:41 +00:00
|
|
|
widget_class->size_request = SizeRequest;
|
2011-07-17 22:30:49 +00:00
|
|
|
#endif
|
2009-04-24 23:35:41 +00:00
|
|
|
widget_class->size_allocate = SizeAllocate;
|
2011-07-17 22:30:49 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
widget_class->draw = DrawMain;
|
|
|
|
#else
|
2009-04-24 23:35:41 +00:00
|
|
|
widget_class->expose_event = ExposeMain;
|
2011-07-17 22:30:49 +00:00
|
|
|
#endif
|
2009-04-24 23:35:41 +00:00
|
|
|
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;
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
widget_class->get_accessible = GetAccessible;
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
container_class->forall = MainForAll;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void scintilla_class_init(ScintillaClass *klass) {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
2022-08-14 10:23:34 +00:00
|
|
|
OBJECT_CLASS *object_class = reinterpret_cast<OBJECT_CLASS *>(klass);
|
|
|
|
GtkWidgetClass *widget_class = reinterpret_cast<GtkWidgetClass *>(klass);
|
|
|
|
GtkContainerClass *container_class = reinterpret_cast<GtkContainerClass *>(klass);
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
const GSignalFlags sigflags = static_cast<GSignalFlags>(G_SIGNAL_ACTION | G_SIGNAL_RUN_LAST);
|
2009-08-23 02:24:48 +00:00
|
|
|
scintilla_signals[COMMAND_SIGNAL] = g_signal_new(
|
2019-07-21 13:26:02 +00:00
|
|
|
"command",
|
|
|
|
G_TYPE_FROM_CLASS(object_class),
|
|
|
|
sigflags,
|
|
|
|
G_STRUCT_OFFSET(ScintillaClass, command),
|
|
|
|
nullptr, //(GSignalAccumulator)
|
|
|
|
nullptr, //(gpointer)
|
|
|
|
scintilla_marshal_VOID__INT_OBJECT,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
2, G_TYPE_INT, GTK_TYPE_WIDGET);
|
2009-08-23 02:24:48 +00:00
|
|
|
|
|
|
|
scintilla_signals[NOTIFY_SIGNAL] = g_signal_new(
|
2019-07-21 13:26:02 +00:00
|
|
|
SCINTILLA_NOTIFY,
|
|
|
|
G_TYPE_FROM_CLASS(object_class),
|
|
|
|
sigflags,
|
|
|
|
G_STRUCT_OFFSET(ScintillaClass, notify),
|
|
|
|
nullptr, //(GSignalAccumulator)
|
|
|
|
nullptr, //(gpointer)
|
|
|
|
scintilla_marshal_VOID__INT_BOXED,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
2, G_TYPE_INT, SCINTILLA_TYPE_NOTIFICATION);
|
|
|
|
|
|
|
|
klass->command = nullptr;
|
|
|
|
klass->notify = nullptr;
|
2015-06-07 21:19:26 +00:00
|
|
|
scintilla_class_parent_class = G_OBJECT_CLASS(g_type_class_peek_parent(klass));
|
2009-08-23 02:24:48 +00:00
|
|
|
ScintillaGTK::ClassInit(object_class, widget_class, container_class);
|
|
|
|
} catch (...) {
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void scintilla_init(ScintillaObject *sci) {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
2011-03-22 00:16:49 +00:00
|
|
|
gtk_widget_set_can_focus(GTK_WIDGET(sci), TRUE);
|
2009-08-23 02:24:48 +00:00
|
|
|
sci->pscin = new ScintillaGTK(sci);
|
|
|
|
} catch (...) {
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
/* legacy name for scintilla_object_new */
|
2019-07-21 13:26:02 +00:00
|
|
|
GtkWidget *scintilla_new() {
|
|
|
|
GtkWidget *widget = GTK_WIDGET(g_object_new(scintilla_get_type(), nullptr));
|
2013-08-28 00:44:27 +00:00
|
|
|
gtk_widget_set_direction(widget, GTK_TEXT_DIR_LTR);
|
|
|
|
|
|
|
|
return widget;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
GtkWidget *scintilla_object_new() {
|
|
|
|
return scintilla_new();
|
|
|
|
}
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
void scintilla_set_id(ScintillaObject *sci, uptr_t id) {
|
2019-05-04 18:14:48 +00:00
|
|
|
ScintillaGTK *psci = static_cast<ScintillaGTK *>(sci->pscin);
|
2022-01-04 23:07:50 +00:00
|
|
|
psci->ctrlID = static_cast<int>(id);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void scintilla_release_resources(void) {
|
2009-08-23 02:24:48 +00:00
|
|
|
try {
|
|
|
|
Platform_Finalise();
|
|
|
|
} catch (...) {
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
2019-05-04 18:14:48 +00:00
|
|
|
|
|
|
|
/* Define a dummy boxed type because g-ir-scanner is unable to
|
|
|
|
* recognize gpointer-derived types. Note that SCNotificaiton
|
|
|
|
* is always allocated on stack so copying is not appropriate. */
|
|
|
|
static void *copy_(void *src) { return src; }
|
|
|
|
static void free_(void *) { }
|
|
|
|
|
|
|
|
GType scnotification_get_type(void) {
|
|
|
|
static gsize type_id = 0;
|
|
|
|
if (g_once_init_enter(&type_id)) {
|
2019-07-21 13:26:02 +00:00
|
|
|
const gsize id = (gsize) g_boxed_type_register_static(
|
|
|
|
g_intern_static_string("SCNotification"),
|
|
|
|
(GBoxedCopyFunc) copy_,
|
|
|
|
(GBoxedFreeFunc) free_);
|
2019-05-04 18:14:48 +00:00
|
|
|
g_once_init_leave(&type_id, id);
|
|
|
|
}
|
|
|
|
return (GType) type_id;
|
|
|
|
}
|