summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorRichardHitt <rbh00@netcom.com>2014-04-02 16:09:13 -0700
committerRichardHitt <rbh00@netcom.com>2014-04-02 16:14:45 -0700
commit0f828dd74f9ea81fe70c8a101a7aa7c40737437a (patch)
tree2e94607cdf2fc775e8e909f8a750ea513099afdf /src
parent5e8bc980e101f06b452d840569e255b01b220134 (diff)
Add marker-line functionality for scrollback, instant seek.
Fixes #662.
Diffstat (limited to 'src')
-rw-r--r--src/common/hexchat.c2
-rw-r--r--src/common/hexchat.h1
-rw-r--r--src/common/inbound.c2
-rw-r--r--src/fe-gtk/fe-gtk.c2
-rw-r--r--src/fe-gtk/menu.c32
-rw-r--r--src/fe-gtk/xtext.c83
-rw-r--r--src/fe-gtk/xtext.h12
7 files changed, 124 insertions, 10 deletions
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"
@@ -1282,6 +1283,36 @@ menu_resetmarker (GtkWidget * wid, gpointer none)
 }
 
 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)
 {
 	gtk_xtext_copy_selection (GTK_XTEXT (current_sess->gui->xtext));
@@ -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)
@@ -4783,12 +4797,63 @@ gtk_xtext_set_wordwrap (GtkXText *xtext, gboolean 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);