1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
/*
* Copyright (C) 2012-2025 Robin Haberkorn
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <Scintilla.h>
#include <ScintillaWidget.h>
#include "view.h"
G_DEFINE_AUTOPTR_CLEANUP_FUNC(ScintillaObject, g_object_unref)
#define TECO_TYPE_VIEW teco_view_get_type()
G_DECLARE_FINAL_TYPE(TecoView, teco_view, TECO, VIEW, ScintillaObject)
struct _TecoView {
ScintillaObject parent_instance;
/** current size allocation */
GdkRectangle allocation;
};
G_DEFINE_TYPE(TecoView, teco_view, SCINTILLA_TYPE_OBJECT)
static void
teco_view_scintilla_notify_cb(ScintillaObject *sci, gint iMessage, SCNotification *notify)
{
teco_view_process_notify((teco_view_t *)TECO_VIEW(sci), notify);
}
/**
* Called when the view is size allocated.
*
* This especially ensures that the caret is visible after startup and when
* opening files on specific lines.
* It's important to scroll the caret only when the size actually changes,
* so we do not interfere with mouse scrolling.
* That callback is invoked even if the size does not change, so that's why
* we have to store the current allocation in teco_view_t.
* Calling it once is unfortunately not sufficient since the window size
* can change during startup.
*/
static void
teco_view_size_allocate_cb(GtkWidget *widget, GdkRectangle *allocation)
{
/* chain to parent class */
GTK_WIDGET_CLASS(teco_view_parent_class)->size_allocate(widget, allocation);
TecoView *view = TECO_VIEW(widget);
if (allocation->width == view->allocation.width && allocation->height == view->allocation.height)
return;
teco_view_ssm((teco_view_t *)view, SCI_SCROLLCARET, 0, 0);
memcpy(&view->allocation, allocation, sizeof(view->allocation));
}
teco_view_t *
teco_view_new(void)
{
TecoView *ctx = TECO_VIEW(g_object_new(TECO_TYPE_VIEW, NULL));
/*
* We don't want the object to be destroyed
* when it is removed from the vbox.
*/
g_object_ref_sink(ctx);
scintilla_set_id(SCINTILLA(ctx), 0);
gtk_widget_set_size_request(GTK_WIDGET(ctx), 500, 300);
/*
* This disables mouse and key events on this view.
* For some strange reason, masking events on
* the event box does NOT work.
*/
gtk_widget_set_can_focus(GTK_WIDGET(ctx), FALSE);
gint events = gtk_widget_get_events(GTK_WIDGET(ctx));
events &= ~(GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK | GDK_TOUCH_MASK |
#ifdef GDK_VERSION_3_18
GDK_TOUCHPAD_GESTURE_MASK |
#endif
#ifdef GDK_VERSION_3_22
GDK_TABLET_PAD_MASK |
#endif
GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
gtk_widget_set_events(GTK_WIDGET(ctx), events);
/*
* Disables drag and drop interaction.
*/
gtk_drag_dest_unset(GTK_WIDGET(ctx));
return (teco_view_t *)ctx;
}
static void
teco_view_class_init(TecoViewClass *klass)
{
SCINTILLA_CLASS(klass)->notify = teco_view_scintilla_notify_cb;
GTK_WIDGET_CLASS(klass)->size_allocate = teco_view_size_allocate_cb;
}
static void teco_view_init(TecoView *self) {}
sptr_t
teco_view_ssm(teco_view_t *ctx, unsigned int iMessage, uptr_t wParam, sptr_t lParam)
{
return scintilla_send_message(SCINTILLA(ctx), iMessage, wParam, lParam);
}
void
teco_view_free(teco_view_t *ctx)
{
g_object_unref(ctx);
}
|