aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2023-06-18 18:50:39 +0300
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2023-06-18 18:50:39 +0300
commit493504f12f79990dae7791efa27366b560151f2c (patch)
tree263ff3fefd2746ceae8a21e28dcc6fea6397b4eb
parent517ae85027f088615026fad6b880647dac5abf0a (diff)
downloadsciteco-493504f12f79990dae7791efa27366b560151f2c.tar.gz
fixed caret scrolling on startup
* Since Scintilla no longer automatically scrolls the caret (see 941f48da6dde691a7800290cc729aaaacd051392), the caret wouldn't always end up in the view on startup. * Added teco_interface_refresh() which includes SCI_SCROLLCARET and is invoked on startup. This helps with the Curses backend. It also reduces code redundancies. * On Gtk, the caret cannot be easily scrolled on startup as long as no size is allocated to the window, so we also added a size-allocate callback to the window's event box. Sizes are less often allocated to the event box than to the window itself for some strange reason.
-rw-r--r--src/interface-curses/interface.c59
-rw-r--r--src/interface-gtk/interface.c125
2 files changed, 93 insertions, 91 deletions
diff --git a/src/interface-curses/interface.c b/src/interface-curses/interface.c
index e056333..ef3f0c7 100644
--- a/src/interface-curses/interface.c
+++ b/src/interface-curses/interface.c
@@ -1507,6 +1507,31 @@ teco_interface_is_interrupted(void)
#endif
+static void
+teco_interface_refresh(void)
+{
+ /*
+ * Scintilla has been patched to avoid any automatic scrolling since that
+ * has been benchmarked to be a very costly operation.
+ * Instead we do it only once after every keypress.
+ */
+ teco_interface_ssm(SCI_SCROLLCARET, 0, 0);
+
+ /*
+ * Info window is updated very often which is very
+ * costly, especially when using PDC_set_title(),
+ * so we redraw it here, where the overhead does
+ * not matter much.
+ */
+ teco_interface_draw_info();
+ wnoutrefresh(teco_interface.info_window);
+ teco_view_noutrefresh(teco_interface_current_view);
+ wnoutrefresh(teco_interface.msg_window);
+ wnoutrefresh(teco_interface.cmdline_window);
+ teco_curses_info_popup_noutrefresh(&teco_interface.popup);
+ doupdate();
+}
+
static gint
teco_interface_blocking_getch(void)
{
@@ -1640,48 +1665,22 @@ teco_interface_event_loop_iter(void)
return;
}
- /*
- * Scintilla has been patched to avoid any automatic scrolling since that
- * has been benchmarked to be a very costly operation.
- * Instead we do it only once after every keypress.
- */
- teco_interface_ssm(SCI_SCROLLCARET, 0, 0);
-
- /*
- * Info window is updated very often which is very
- * costly, especially when using PDC_set_title(),
- * so we redraw it here, where the overhead does
- * not matter much.
- */
- teco_interface_draw_info();
- wnoutrefresh(teco_interface.info_window);
- teco_view_noutrefresh(teco_interface_current_view);
- wnoutrefresh(teco_interface.msg_window);
- wnoutrefresh(teco_interface.cmdline_window);
- teco_curses_info_popup_noutrefresh(&teco_interface.popup);
- doupdate();
+ teco_interface_refresh();
}
gboolean
teco_interface_event_loop(GError **error)
{
- static const teco_cmdline_t empty_cmdline; // FIXME
-
/*
* Initialize Curses for interactive mode
*/
if (!teco_interface_init_interactive(error))
return FALSE;
- /* initial refresh */
- teco_interface_draw_info();
- wnoutrefresh(teco_interface.info_window);
- teco_view_noutrefresh(teco_interface_current_view);
- teco_interface_msg_clear();
- wnoutrefresh(teco_interface.msg_window);
+ static const teco_cmdline_t empty_cmdline; // FIXME
teco_interface_cmdline_update(&empty_cmdline);
- wnoutrefresh(teco_interface.cmdline_window);
- doupdate();
+ teco_interface_msg_clear();
+ teco_interface_refresh();
#ifdef EMCURSES
PDC_emscripten_set_handler(teco_interface_event_loop_iter, TRUE);
diff --git a/src/interface-gtk/interface.c b/src/interface-gtk/interface.c
index 6301a71..253600a 100644
--- a/src/interface-gtk/interface.c
+++ b/src/interface-gtk/interface.c
@@ -64,6 +64,9 @@ static void teco_interface_cmdline_size_allocate_cb(GtkWidget *widget,
gpointer user_data);
static void teco_interface_cmdline_commit_cb(GtkIMContext *context, gchar *str,
gpointer user_data);
+static void teco_interface_size_allocate_cb(GtkWidget *widget,
+ GdkRectangle *allocation,
+ gpointer user_data);
static gboolean teco_interface_key_pressed_cb(GtkWidget *widget, GdkEventKey *event,
gpointer user_data);
static gboolean teco_interface_window_delete_cb(GtkWidget *widget, GdkEventAny *event,
@@ -308,6 +311,9 @@ teco_interface_init(void)
gtk_box_pack_start(GTK_BOX(overlay_vbox), teco_interface.event_box_widget,
TRUE, TRUE, 0);
+ g_signal_connect(teco_interface.event_box_widget, "size-allocate",
+ G_CALLBACK(teco_interface_size_allocate_cb), NULL);
+
teco_interface.message_bar_widget = gtk_info_bar_new();
gtk_widget_set_name(teco_interface.message_bar_widget, "sciteco-message-bar");
GtkWidget *message_bar_content =
@@ -825,6 +831,52 @@ teco_interface_set_css_variables(teco_view_t *view)
}
static void
+teco_interface_refresh(gboolean current_view_changed)
+{
+ /*
+ * The styles configured via Scintilla might change
+ * with every keypress.
+ */
+ if (teco_interface_current_view)
+ teco_interface_set_css_variables(teco_interface_current_view);
+
+ /*
+ * The info area is updated very often and setting the
+ * window title each time it is updated is VERY costly.
+ * So we set it here once after every keypress even if the
+ * info line did not change.
+ * View changes are also only applied here to the GTK
+ * window even though GDK updates have been frozen since
+ * the size reallocations are very costly.
+ */
+ teco_interface_refresh_info();
+
+ if (current_view_changed) {
+ /*
+ * The last view's object is not guaranteed to
+ * still exist.
+ * However its widget is, due to reference counting.
+ */
+ if (teco_interface.current_view_widget)
+ gtk_container_remove(GTK_CONTAINER(teco_interface.event_box_widget),
+ teco_interface.current_view_widget);
+
+ teco_interface.current_view_widget = teco_view_get_widget(teco_interface_current_view);
+
+ gtk_container_add(GTK_CONTAINER(teco_interface.event_box_widget),
+ teco_interface.current_view_widget);
+ gtk_widget_show(teco_interface.current_view_widget);
+ }
+
+ /*
+ * Scintilla has been patched to avoid any automatic scrolling since that
+ * has been benchmarked to be a very costly operation.
+ * Instead we do it only once after every keypress.
+ */
+ teco_interface_ssm(SCI_SCROLLCARET, 0, 0);
+}
+
+static void
teco_interface_cmdline_commit_cb(GtkIMContext *context, gchar *str, gpointer user_data)
{
g_autoptr(GError) error = NULL;
@@ -933,46 +985,7 @@ teco_interface_handle_key_press(GdkEventKey *event, GError **error)
}
}
- /*
- * Scintilla has been patched to avoid any automatic scrolling since that
- * has been benchmarked to be a very costly operation.
- * Instead we do it only once after every keypress.
- */
- teco_interface_ssm(SCI_SCROLLCARET, 0, 0);
-
- /*
- * The styles configured via Scintilla might change
- * with every keypress.
- */
- teco_interface_set_css_variables(teco_interface_current_view);
-
- /*
- * The info area is updated very often and setting the
- * window title each time it is updated is VERY costly.
- * So we set it here once after every keypress even if the
- * info line did not change.
- * View changes are also only applied here to the GTK
- * window even though GDK updates have been frozen since
- * the size reallocations are very costly.
- */
- teco_interface_refresh_info();
-
- if (teco_interface_current_view != last_view) {
- /*
- * The last view's object is not guaranteed to
- * still exist.
- * However its widget is, due to reference counting.
- */
- if (teco_interface.current_view_widget)
- gtk_container_remove(GTK_CONTAINER(teco_interface.event_box_widget),
- teco_interface.current_view_widget);
-
- teco_interface.current_view_widget = teco_view_get_widget(teco_interface_current_view);
-
- gtk_container_add(GTK_CONTAINER(teco_interface.event_box_widget),
- teco_interface.current_view_widget);
- gtk_widget_show(teco_interface.current_view_widget);
- }
+ teco_interface_refresh(teco_interface_current_view != last_view);
return TRUE;
}
@@ -1032,16 +1045,11 @@ teco_interface_event_loop(GError **error)
g_list_free_full(icon_list, g_object_unref);
#endif
- teco_interface_refresh_info();
-
/*
* Initialize the CSS variable provider and the CSS provider
* for the included fallback.css.
*/
teco_interface.css_var_provider = gtk_css_provider_new();
- if (teco_interface_current_view)
- /* set CSS variables initially */
- teco_interface_set_css_variables(teco_interface_current_view);
GdkScreen *default_screen = gdk_screen_get_default();
gtk_style_context_add_provider_for_screen(default_screen,
GTK_STYLE_PROVIDER(teco_interface.css_var_provider),
@@ -1073,22 +1081,7 @@ teco_interface_event_loop(GError **error)
GTK_STYLE_PROVIDER(user_css_provider),
GTK_STYLE_PROVIDER_PRIORITY_USER);
- /*
- * When changing views, the new widget is not
- * added immediately to avoid flickering in the GUI.
- * It is only updated once per key press and only
- * if it really changed.
- * Therefore we must add the current view to the
- * window initially.
- * For the same reason, window title updates are
- * deferred to once after every key press, so we must
- * set the window title initially.
- */
- if (teco_interface_current_view) {
- teco_interface.current_view_widget = teco_view_get_widget(teco_interface_current_view);
- gtk_container_add(GTK_CONTAINER(teco_interface.event_box_widget),
- teco_interface.current_view_widget);
- }
+ teco_interface_refresh(TRUE);
gtk_widget_show_all(teco_interface.window);
/* don't show popup by default */
@@ -1157,6 +1150,16 @@ teco_interface_cmdline_size_allocate_cb(GtkWidget *widget,
CARET_SLOP | CARET_EVEN, allocation->width/2);
}
+static void
+teco_interface_size_allocate_cb(GtkWidget *widget,
+ GdkRectangle *allocation, gpointer user_data)
+{
+ /*
+ * This especially ensures that the caret is visible after startup.
+ */
+ teco_interface_ssm(SCI_SCROLLCARET, 0, 0);
+}
+
static gboolean
teco_interface_key_pressed_cb(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{