diff --git a/src/common/hexchat.c b/src/common/hexchat.c index 07f91cfb..8729df33 100644 --- a/src/common/hexchat.c +++ b/src/common/hexchat.c @@ -528,6 +528,8 @@ new_ircwindow (server *serv, char *name, int type, int focus) irc_init (sess); chanopt_load (sess); scrollback_load (sess); + if (sess->scrollwritten && sess->scrollback_replay_marklast) + sess->scrollback_replay_marklast (sess); plugin_emit_dummy_print (sess, "Open Context"); return sess; diff --git a/src/common/hexchat.h b/src/common/hexchat.h index 7143f8ab..5d96fd4b 100644 --- a/src/common/hexchat.h +++ b/src/common/hexchat.h @@ -459,6 +459,7 @@ typedef struct session int doing_who:1; /* /who sent on this channel */ int done_away_check:1; /* done checking for away status changes */ gtk_xtext_search_flags lastlog_flags; + void (*scrollback_replay_marklast) (struct session *sess); } session; struct msproxy_state_t diff --git a/src/common/inbound.c b/src/common/inbound.c index ea7c3c9b..3737e479 100644 --- a/src/common/inbound.c +++ b/src/common/inbound.c @@ -608,6 +608,8 @@ inbound_ujoin (server *serv, char *chan, char *nick, char *ip, { chanopt_load (sess); scrollback_load (sess); + if (sess->scrollwritten && sess->scrollback_replay_marklast) + sess->scrollback_replay_marklast (sess); } fe_set_channel (sess); diff --git a/src/fe-gtk/fe-gtk.c b/src/fe-gtk/fe-gtk.c index c0e7f53f..35aff3b2 100644 --- a/src/fe-gtk/fe-gtk.c +++ b/src/fe-gtk/fe-gtk.c @@ -407,6 +407,8 @@ fe_new_window (session *sess, int focus) if (!sess_list->next) g_idle_add (fe_idle, NULL); + + sess->scrollback_replay_marklast = gtk_xtext_set_marker_last; } void diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index d0c4e95b..658f1c3e 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -42,6 +42,7 @@ #include "../common/servlist.h" #include "../common/notify.h" #include "../common/util.h" +#include "../common/text.h" #include "xtext.h" #include "ascii.h" #include "banlist.h" @@ -1281,6 +1282,36 @@ menu_resetmarker (GtkWidget * wid, gpointer none) gtk_xtext_reset_marker_pos (GTK_XTEXT (current_sess->gui->xtext)); } +static void +menu_movetomarker (GtkWidget *wid, gpointer none) +{ + marker_reset_reason reason; + char *str; + + if (!prefs.hex_text_show_marker) + PrintText (current_sess, _("Marker line disabled.")); + else + { + reason = gtk_xtext_moveto_marker_pos (GTK_XTEXT (current_sess->gui->xtext)); + switch (reason) { + case MARKER_WAS_NEVER_SET: + str = _("Marker line never set."); break; + case MARKER_IS_SET: + str = ""; break; + case MARKER_RESET_MANUALLY: + str = _("Marker line reset manually."); break; + case MARKER_RESET_BY_KILL: + str = _("Marker line reset because exceeded scrollback limit."); break; + case MARKER_RESET_BY_CLEAR: + str = _("Marker line reset by CLEAR command."); break; + default: + str = _("Marker line state unknown."); break; + } + if (str[0]) + PrintText (current_sess, str); + } +} + static void menu_copy_selection (GtkWidget * wid, gpointer none) { @@ -1789,6 +1820,7 @@ static struct mymenu mymenu[] = { {N_("URL Grabber..."), url_opengui, 0, M_MENUITEM, 0, 0, 1}, {0, 0, 0, M_SEP, 0, 0, 0}, {N_("Reset Marker Line"), menu_resetmarker, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_m}, + {N_("Move to Marker Line"), menu_movetomarker, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_M}, {N_("_Copy Selection"), menu_copy_selection, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_C}, {N_("C_lear Text"), menu_flushbuffer, GTK_STOCK_CLEAR, M_MENUSTOCK, 0, 0, 1}, {N_("Save Text..."), menu_savebuffer, GTK_STOCK_SAVE, M_MENUSTOCK, 0, 0, 1}, diff --git a/src/fe-gtk/xtext.c b/src/fe-gtk/xtext.c index d6a2cf7f..88dfb056 100644 --- a/src/fe-gtk/xtext.c +++ b/src/fe-gtk/xtext.c @@ -3862,7 +3862,12 @@ gtk_xtext_kill_ent (xtext_buffer *buffer, textentry *ent) buffer->last_ent_end = NULL; } - if (buffer->marker_pos == ent) buffer->marker_pos = NULL; + if (buffer->marker_pos == ent) + { + /* Allow for "Marker line reset because exceeded scrollback limit. to appear. */ + buffer->marker_pos = ent->next; + buffer->marker_state = MARKER_RESET_BY_KILL; + } if (ent->marks) { @@ -3961,6 +3966,7 @@ void gtk_xtext_clear (xtext_buffer *buf, int lines) { textentry *next; + int marker_reset = FALSE; if (lines != 0) { @@ -3970,6 +3976,8 @@ gtk_xtext_clear (xtext_buffer *buf, int lines) lines *= -1; while (lines) { + if (buf->text_last == buf->marker_pos) + marker_reset = TRUE; gtk_xtext_remove_bottom (buf); lines--; } @@ -3979,6 +3987,8 @@ gtk_xtext_clear (xtext_buffer *buf, int lines) /* delete lines from top */ while (lines) { + if (buf->text_first == buf->marker_pos) + marker_reset = TRUE; gtk_xtext_remove_top (buf); lines--; } @@ -3995,6 +4005,8 @@ gtk_xtext_clear (xtext_buffer *buf, int lines) buf->last_ent_start = NULL; buf->last_ent_end = NULL; buf->marker_pos = NULL; + if (buf->text_first) + marker_reset = TRUE; dontscroll (buf); while (buf->text_first) @@ -4014,6 +4026,9 @@ gtk_xtext_clear (xtext_buffer *buf, int lines) { gtk_xtext_calc_lines (buf, FALSE); } + + if (marker_reset) + buf->marker_state = MARKER_RESET_BY_CLEAR; } static gboolean @@ -4528,14 +4543,13 @@ gtk_xtext_append_entry (xtext_buffer *buf, textentry * ent, time_t stamp) ent->sublines = NULL; buf->num_lines += gtk_xtext_lines_taken (buf, ent); - if (buf->reset_marker_pos || - ((buf->marker_pos == NULL || buf->marker_seen) && (buf->xtext->buffer != buf || - !gtk_window_has_toplevel_focus (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (buf->xtext))))))) + if ((buf->marker_pos == NULL || buf->marker_seen) && (buf->xtext->buffer != buf || + !gtk_window_has_toplevel_focus (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (buf->xtext)))))) { buf->marker_pos = ent; + buf->marker_state = MARKER_IS_SET; dontscroll (buf); /* force scrolling off */ buf->marker_seen = FALSE; - buf->reset_marker_pos = FALSE; } if (buf->xtext->max_lines > 2 && buf->xtext->max_lines < buf->num_lines) @@ -4782,13 +4796,64 @@ gtk_xtext_set_wordwrap (GtkXText *xtext, gboolean wordwrap) xtext->wordwrap = wordwrap; } +void +gtk_xtext_set_marker_last (session *sess) +{ + xtext_buffer *buf = sess->res->buffer; + + buf->marker_pos = buf->text_last; + buf->marker_state = MARKER_IS_SET; +} + void gtk_xtext_reset_marker_pos (GtkXText *xtext) { - xtext->buffer->marker_pos = NULL; - dontscroll (xtext->buffer); /* force scrolling off */ - gtk_xtext_render_page (xtext); - xtext->buffer->reset_marker_pos = TRUE; + if (xtext->buffer->marker_pos) + { + xtext->buffer->marker_pos = NULL; + dontscroll (xtext->buffer); /* force scrolling off */ + gtk_xtext_render_page (xtext); + xtext->buffer->marker_state = MARKER_RESET_MANUALLY; + } +} + +int +gtk_xtext_moveto_marker_pos (GtkXText *xtext) +{ + gdouble value = 0; + xtext_buffer *buf = xtext->buffer; + textentry *ent = buf->text_first; + GtkAdjustment *adj = xtext->adj; + + if (buf->marker_pos == NULL) + return buf->marker_state; + + if (gtk_xtext_check_ent_visibility (xtext, buf->marker_pos, 1) == FALSE) + { + while (ent) + { + if (ent == buf->marker_pos) + break; + value += g_slist_length (ent->sublines); + ent = ent->next; + } + if (value >= adj->value && value < adj->value + adj->page_size) + return MARKER_IS_SET; + value -= adj->page_size / 2; + if (value < 0) + value = 0; + if (value > adj->upper - adj->page_size) + value = adj->upper - adj->page_size; + gtk_adjustment_set_value (adj, value); + gtk_xtext_render_page (xtext); + } + + /* If we previously lost marker position to scrollback limit -- */ + if (buf->marker_pos == buf->text_first && + buf->marker_state == MARKER_RESET_BY_KILL) + return MARKER_RESET_BY_KILL; + else + return MARKER_IS_SET; } void diff --git a/src/fe-gtk/xtext.h b/src/fe-gtk/xtext.h index 2476e15c..0a4215c5 100644 --- a/src/fe-gtk/xtext.h +++ b/src/fe-gtk/xtext.h @@ -68,6 +68,14 @@ typedef union offsets_u { guint32 u; } offsets_t; +typedef enum marker_reset_reason_e { + MARKER_WAS_NEVER_SET, + MARKER_IS_SET, + MARKER_RESET_MANUALLY, + MARKER_RESET_BY_KILL, + MARKER_RESET_BY_CLEAR +} marker_reset_reason; + typedef struct { GtkXText *xtext; /* attached to this widget */ @@ -90,6 +98,7 @@ typedef struct { int indent; /* position of separator (pixels) from left */ textentry *marker_pos; + marker_reset_reason marker_state; int window_width; /* window size when last rendered. */ int window_height; @@ -98,7 +107,6 @@ typedef struct { unsigned int scrollbar_down:1; unsigned int needs_recalc:1; unsigned int marker_seen:1; - unsigned int reset_marker_pos:1; GList *search_found; /* list of textentries where search found strings */ gchar *search_text; /* desired text to search for */ @@ -257,7 +265,9 @@ void gtk_xtext_refresh (GtkXText * xtext); int gtk_xtext_lastlog (xtext_buffer *out, xtext_buffer *search_area); textentry *gtk_xtext_search (GtkXText * xtext, const gchar *text, gtk_xtext_search_flags flags, GError **err); void gtk_xtext_reset_marker_pos (GtkXText *xtext); +int gtk_xtext_moveto_marker_pos (GtkXText *xtext); void gtk_xtext_check_marker_visibility(GtkXText *xtext); +void gtk_xtext_set_marker_last (session *sess); gboolean gtk_xtext_is_empty (xtext_buffer *buf); typedef void (*GtkXTextForeach) (GtkXText *xtext, unsigned char *text, void *data);