Hi,
I've working on a lightweight IDE, making it scroll a certain line to
1/3 of the view of the editor widget. We used to just send SCI_GOTOLINE
in response to a GtkTreeView click - now we are using SCI_LINESCROLL to
get the line in exactly the right place. My problem is we have code
that may cause an initial scroll in reponse to SCI_GOTOLINE, but also
code after a SCN_PAINTED notification that calls SCI_LINESCROLL. On the
attempt to scroll the ScintillaObject the second time, Scintilla aborts
with an assert failure in ScintillaGTK::ExposeTextThis.
I'm using Scintilla 1.72 with GTK 2.8.20 (also tested on GTK 2.6.9) on
Fedora Core 5 Linux.
I've attached a small demo of this in scrollview.c (based on the GTK
bait sample). Just click the Test button and it should abort.
I've patched scintilla (gtk-expose-event-scroll-safe.patch) to prevent
the assert failure and it seems to be working fine. The patch assumes
that the assert was just to prevent a memory leak, I'm not too familiar
with widget internals. Is this a good idea?
Regards,
Nick
Index: ScintillaGTK.cxx
===================================================================
--- ScintillaGTK.cxx (revision 1236)
+++ ScintillaGTK.cxx (revision 1237)
@@ -2198,7 +2198,13 @@
rcPaint.right = ose->area.x + ose->area.width;
rcPaint.bottom = ose->area.y + ose->area.height;
- PLATFORM_ASSERT(rgnUpdate == NULL);
+ /* We can receive an expose-event during an expose-event.
+ * This can happen when two different scroll messages are sent at different times. */
+ if (rgnUpdate != NULL)
+ {
+ gdk_region_destroy(rgnUpdate);
+ rgnUpdate = NULL;
+ }
#if GTK_MAJOR_VERSION >= 2
rgnUpdate = gdk_region_copy(ose->region);
#endif
#include <gtk/gtk.h>
#include <Scintilla.h>
#include <SciLexer.h>
#define PLAT_GTK 1
#include <ScintillaWidget.h>
ScintillaObject *sci;
gboolean scroll_in_view = TRUE;
#define SSM(m, w, l) scintilla_send_message(sci, m, w, l)
static void scroll_to_line(ScintillaObject *sci, gint line, gfloat percent_of_view);
static void on_editor_notification(GtkWidget *editor, gint scn, gpointer lscn,
gpointer user_data)
{
struct SCNotification *nt = lscn;
switch (nt->nmhdr.code)
{
case SCN_PAINTED:
{
if (scroll_in_view)
scroll_to_line(sci, -1, 0.5F);
scroll_in_view = FALSE;
break;
}
}
}
static void on_button_clicked()
{
SSM(SCI_GOTOLINE, 5, 0); // also scrolls
scroll_in_view = TRUE;
/* because of the last scroll, the SCN_PAINTED scrolling will now cause
* Scintilla to abort. */
}
int main(int argc, char **argv)
{
GtkWidget *app;
GtkWidget *editor;
GtkWidget *box;
GtkWidget *button;
gint i;
gtk_init(&argc, &argv);
app = gtk_window_new(GTK_WINDOW_TOPLEVEL);
editor = scintilla_new();
sci = SCINTILLA(editor);
button = gtk_button_new_with_label("Test");
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(on_button_clicked), NULL);
box = gtk_vbox_new(FALSE, 6);
gtk_container_add(GTK_CONTAINER(box), button);
gtk_container_add(GTK_CONTAINER(box), editor);
gtk_container_add(GTK_CONTAINER(app), box);
g_signal_connect(G_OBJECT(app), "delete_event", G_CALLBACK(gtk_main_quit), NULL);
scintilla_set_id(sci, 0);
gtk_widget_set_usize(editor, 500, 300);
for (i = 0; i < 100; i++)
SSM(SCI_INSERTTEXT, 0, (sptr_t) "\n");
SSM(SCI_INSERTTEXT, 0, (sptr_t)
"int main(int argc, char **argv) {\n"
" // Start up the gnome\n"
" gnome_init(\"stest\", \"1.0\", argc, argv);\n}"
);
for (i = 0; i < 100; i++)
SSM(SCI_INSERTTEXT, 0, (sptr_t) "\n");
SSM(SCI_GOTOLINE, 100, 0);
gtk_widget_show_all(app);
//gtk_widget_grab_focus(GTK_WIDGET(editor));
g_signal_connect((GtkWidget*) sci, "sci-notify",
G_CALLBACK(on_editor_notification), NULL);
//scroll_to_line(sci, -1, 0.5F);
gtk_main();
return 0;
}
gint sci_get_current_line(ScintillaObject *sci, gint pos)
{
if (pos >= 0)
{
return SSM(SCI_LINEFROMPOSITION, pos, 0);
}
else
{
return SSM(SCI_LINEFROMPOSITION, SSM(SCI_GETCURRENTPOS, 0, 0), 0);
}
}
/* Scroll the view to make line appear at percent_of_view.
* line can be -1 to use the current position. */
static void scroll_to_line(ScintillaObject *sci, gint line, gfloat percent_of_view)
{
gint vis1, los, delta;
if (line == -1)
line = sci_get_current_line(sci, -1);
line = SSM(SCI_VISIBLEFROMDOCLINE, line, 0);
vis1 = SSM(SCI_GETFIRSTVISIBLELINE, 0, 0);
los = SSM(SCI_LINESONSCREEN, 0, 0);
delta = (line - vis1) - los * percent_of_view;
SSM(SCI_LINESCROLL, 0, delta);
}
_______________________________________________
Scintilla-interest mailing list
[email protected]
http://mailman.lyra.org/mailman/listinfo/scintilla-interest