Fix replies targeting the wrong message

This commit is contained in:
deepend committed 2026-10-28 03:08:56 -06:00
1 parent 25bbfe21c4
commit 995ed49861
14 files changed
+291 -54

No files matched your search

+4
View File
@@ -23,6 +23,8 @@
#ifndef ZOITECHAT_FE_H
#define ZOITECHAT_FE_H
struct reply_item;
/* for storage of /menu entries */
typedef struct
{
@@ -110,6 +112,8 @@ void fe_progressbar_start (struct session *sess);
void fe_progressbar_end (struct server *serv);
void fe_print_text (struct session *sess, char *text, time_t stamp,
gboolean no_activity);
void fe_print_text_with_message (struct session *sess, char *text, time_t stamp,
gboolean no_activity, const struct reply_item *message);
void fe_userlist_insert (struct session *sess, struct User *newuser, gboolean sel);
int fe_userlist_remove (struct session *sess, struct User *user);
void fe_userlist_rehash (struct session *sess, struct User *user);
+27 -22
View File
@@ -313,6 +313,20 @@ inbound_make_idtext (server *serv, char *idtext, int max, int id)
}
}
/* Pass message identity alongside the formatted event, outside plugin output.
* Private messages displayed in another channel have no reply destination here. */
static void
inbound_emit_message (int event, session *sess, char *from, char *text,
char *c, char *d, const message_tags_data *tags_data)
{
reply_item message = {tags_data->msgid, from, text, tags_data->timestamp};
gboolean can_reply = reply_msgid_valid (message.msgid) &&
event != XP_TE_PRIVMSG && event != XP_TE_PRIVACTION;
text_emit_with_message (event, sess, from, text, c, d, tags_data->timestamp,
can_reply ? &message : NULL);
}
void
inbound_privmsg (server *serv, char *from, char *ip, char *text, int id,
const message_tags_data *tags_data)
@@ -362,11 +376,9 @@ inbound_privmsg (server *serv, char *from, char *ip, char *text, int id,
inbound_make_idtext (serv, idtext, sizeof (idtext), id);
if (sess->type == SESS_DIALOG && !nodiag)
EMIT_SIGNAL_TIMESTAMP (XP_TE_DPRIVMSG, sess, from, text, idtext, NULL, 0,
tags_data->timestamp);
inbound_emit_message (XP_TE_DPRIVMSG, sess, from, text, idtext, NULL, tags_data);
else
EMIT_SIGNAL_TIMESTAMP (XP_TE_PRIVMSG, sess, from, text, idtext, NULL, 0,
tags_data->timestamp);
inbound_emit_message (XP_TE_PRIVMSG, sess, from, text, idtext, NULL, tags_data);
}
/* used for Alerts section. Masks can be separated by commas and spaces. */
@@ -608,24 +620,21 @@ inbound_action (session *sess, char *chan, char *from, char *ip, char *text,
{
if (is_hilight (from, text, sess, serv))
{
EMIT_SIGNAL_TIMESTAMP (XP_TE_HCHANACTION, sess, from, text, nickchar,
idtext, 0, tags_data->timestamp);
inbound_emit_message (XP_TE_HCHANACTION, sess, from, text, nickchar,
idtext, tags_data);
return;
}
}
if (fromme)
EMIT_SIGNAL_TIMESTAMP (XP_TE_UACTION, sess, from, text, nickchar, idtext,
0, tags_data->timestamp);
inbound_emit_message (XP_TE_UACTION, sess, from, text, nickchar, idtext, tags_data);
else if (!privaction)
EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANACTION, sess, from, text, nickchar,
idtext, 0, tags_data->timestamp);
inbound_emit_message (XP_TE_CHANACTION, sess, from, text, nickchar,
idtext, tags_data);
else if (sess->type == SESS_DIALOG)
EMIT_SIGNAL_TIMESTAMP (XP_TE_DPRIVACTION, sess, from, text, idtext, NULL,
0, tags_data->timestamp);
inbound_emit_message (XP_TE_DPRIVACTION, sess, from, text, idtext, NULL, tags_data);
else
EMIT_SIGNAL_TIMESTAMP (XP_TE_PRIVACTION, sess, from, text, idtext, NULL, 0,
tags_data->timestamp);
inbound_emit_message (XP_TE_PRIVACTION, sess, from, text, idtext, NULL, tags_data);
}
void
@@ -679,8 +688,7 @@ inbound_chanmsg (server *serv, session *sess, char *chan, char *from,
(!tags_data->timestamp || serv->have_echo_message))
sess->server->p_set_back (sess->server);
reply_context_print (sess, tags_data);
EMIT_SIGNAL_TIMESTAMP (XP_TE_UCHANMSG, sess, from, text, nickchar, NULL,
0, tags_data->timestamp);
inbound_emit_message (XP_TE_UCHANMSG, sess, from, text, nickchar, NULL, tags_data);
reply_cache_add (sess, tags_data->msgid, from, text, tags_data->timestamp);
return;
}
@@ -693,14 +701,11 @@ inbound_chanmsg (server *serv, session *sess, char *chan, char *from,
reply_context_print (sess, tags_data);
if (sess->type == SESS_DIALOG)
EMIT_SIGNAL_TIMESTAMP (XP_TE_DPRIVMSG, sess, from, text, idtext, NULL, 0,
tags_data->timestamp);
inbound_emit_message (XP_TE_DPRIVMSG, sess, from, text, idtext, NULL, tags_data);
else if (hilight)
EMIT_SIGNAL_TIMESTAMP (XP_TE_HCHANMSG, sess, from, text, nickchar, idtext,
0, tags_data->timestamp);
inbound_emit_message (XP_TE_HCHANMSG, sess, from, text, nickchar, idtext, tags_data);
else
EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANMSG, sess, from, text, nickchar, idtext,
0, tags_data->timestamp);
inbound_emit_message (XP_TE_CHANMSG, sess, from, text, nickchar, idtext, tags_data);
reply_cache_add (sess, tags_data->msgid, from, text, tags_data->timestamp);
}
+20 -6
View File
@@ -834,8 +834,9 @@ G_GNUC_END_IGNORE_DEPRECATIONS
#endif
}
void
PrintTextTimeStamp (session *sess, char *text, time_t timestamp)
static void
PrintTextTimeStampWithMessage (session *sess, char *text, time_t timestamp,
const reply_item *message)
{
if (!sess)
{
@@ -856,10 +857,16 @@ PrintTextTimeStamp (session *sess, char *text, time_t timestamp)
log_write (sess, text, timestamp);
scrollback_save (sess, text, timestamp);
fe_print_text (sess, text, timestamp, FALSE);
fe_print_text_with_message (sess, text, timestamp, FALSE, message);
g_free (text);
}
void
PrintTextTimeStamp (session *sess, char *text, time_t timestamp)
{
PrintTextTimeStampWithMessage (sess, text, timestamp, NULL);
}
void
PrintText (session *sess, char *text)
{
@@ -1962,7 +1969,7 @@ display_event_string (session *sess, int event, char **args, char *format,
static void
display_event (session *sess, int event, char **args,
unsigned int stripcolor_args, time_t timestamp)
unsigned int stripcolor_args, time_t timestamp, const reply_item *message)
{
char o[4096];
char *format;
@@ -1992,7 +1999,7 @@ display_event (session *sess, int event, char **args,
}
if (o[0])
PrintTextTimeStamp (sess, o, timestamp);
PrintTextTimeStampWithMessage (sess, o, timestamp, message);
}
int
@@ -2210,6 +2217,13 @@ text_color_of (char *name)
void
text_emit (int index, session *sess, char *a, char *b, char *c, char *d,
time_t timestamp)
{
text_emit_with_message (index, sess, a, b, c, d, timestamp, NULL);
}
void
text_emit_with_message (int index, session *sess, char *a, char *b, char *c, char *d,
time_t timestamp, const reply_item *message)
{
char *word[PDIWORDS];
int i;
@@ -2305,7 +2319,7 @@ text_emit (int index, session *sess, char *a, char *b, char *c, char *d,
if (!prefs.hex_away_omit_alerts || !sess->server->is_away)
sound_play_event (index);
display_event (sess, index, word, stripcolor_args, timestamp);
display_event (sess, index, word, stripcolor_args, timestamp, message);
}
char *
+2
View File
@@ -56,6 +56,8 @@ int text_color_of (char *name);
char **text_color_event_names (int color, int *count);
void text_emit (int index, session *sess, char *a, char *b, char *c, char *d,
time_t timestamp);
void text_emit_with_message (int index, session *sess, char *a, char *b, char *c, char *d,
time_t timestamp, const reply_item *message);
int text_emit_by_name (char *name, session *sess, time_t timestamp,
char *a, char *b, char *c, char *d);
gchar *text_convert_invalid (const gchar* text, gssize len, GIConv converter, const gchar *fallback, gsize *len_out);
+9 -2
View File
@@ -994,13 +994,20 @@ fe_progressbar_end (server *serv)
void
fe_print_text (struct session *sess, char *text, time_t stamp,
gboolean no_activity)
{
fe_print_text_with_message (sess, text, stamp, no_activity, NULL);
}
void
fe_print_text_with_message (struct session *sess, char *text, time_t stamp,
gboolean no_activity, const reply_item *message)
{
/* image links become a "[view image]" placeholder with a hidden URL */
char *filtered = inline_image_filter_text (text);
PrintTextRaw (sess->res->buffer,
PrintTextRawWithMessage (sess->res->buffer,
(unsigned char *)(filtered ? filtered : text),
prefs.hex_text_indent, stamp);
prefs.hex_text_indent, stamp, message);
g_free (filtered);
if (no_activity || !sess->gui->is_tab)
+23 -4
View File
@@ -3865,10 +3865,25 @@ mg_update_topicbar_layout (session_gui *gui)
/* check if a word is clickable */
static session *
mg_xtext_session (GtkWidget *widget)
{
GSList *list;
for (list = sess_list; list; list = list->next)
{
session *sess = list->data;
if (sess->res && sess->res->buffer == GTK_XTEXT (widget)->buffer)
return sess;
}
return current_sess;
}
static int
mg_word_check (GtkWidget * xtext, char *word)
{
session *sess = current_sess;
session *sess = mg_xtext_session (xtext);
int ret;
ret = url_check_word (word);
@@ -3883,7 +3898,7 @@ mg_word_check (GtkWidget * xtext, char *word)
static void
mg_word_clicked (GtkWidget *xtext, char *word, GdkEventButton *even)
{
session *sess = current_sess;
session *sess = mg_xtext_session (xtext);
int word_type = 0, start, end;
char *tmp;
@@ -3963,7 +3978,9 @@ mg_word_clicked (GtkWidget *xtext, char *word, GdkEventButton *even)
case WORD_NICK:
word[end] = 0;
word += start;
menu_nickmenu (sess, even, word, FALSE);
menu_nickmenu_with_message (sess, even, word, FALSE,
gtk_xtext_entry_get_message (GTK_XTEXT (xtext),
gtk_xtext_get_clicked_entry (GTK_XTEXT (xtext))));
break;
case WORD_CHANNEL:
word[end] = 0;
@@ -3978,7 +3995,9 @@ mg_word_clicked (GtkWidget *xtext, char *word, GdkEventButton *even)
g_free (tmp);
break;
case WORD_DIALOG:
menu_nickmenu (sess, even, sess->channel, FALSE);
menu_nickmenu_with_message (sess, even, sess->channel, FALSE,
gtk_xtext_entry_get_message (GTK_XTEXT (xtext),
gtk_xtext_get_clicked_entry (GTK_XTEXT (xtext))));
break;
}
}
+76 -12
View File
@@ -790,26 +790,73 @@ fe_userlist_update (session *sess, struct User *user)
}
static void
menu_reply_to_latest_cb (GtkWidget *wid, gpointer data)
typedef struct
{
reply_item *item;
session *sess;
char *target;
char *msgid;
char *nick;
char *text;
gboolean latest;
} reply_menu_data;
item = reply_cache_latest_from (current_sess, str_copy);
if (!item)
static void
menu_reply_data_free (gpointer data)
{
reply_menu_data *reply = data;
g_free (reply->target);
g_free (reply->msgid);
g_free (reply->nick);
g_free (reply->text);
g_free (reply);
}
static void
menu_reply_cb (GtkWidget *wid, gpointer data)
{
reply_menu_data *reply = data;
session *sess = reply->sess;
reply_item selected = {reply->msgid, reply->nick, reply->text, 0};
const reply_item *item = &selected;
GtkWidget *menu = g_object_ref (gtk_widget_get_parent (wid));
/* The menu may outlive a closed or retargeted tab. Never reply in whatever
* session happens to be current when the menu item is activated. */
if (!is_session (sess) ||
sess->server->p_cmp (sess->channel, reply->target))
goto done;
if (sess != current_sess)
{
PrintText (current_sess, _("No recent message to reply to.\n"));
return;
fe_ctrl_gui (sess, FE_GUI_FOCUS, 0);
if (!is_session (sess) || sess != current_sess ||
sess->server->p_cmp (sess->channel, reply->target))
goto done;
}
if (reply->latest)
item = reply_cache_latest_from (sess, reply->nick);
if (!item || !item->msgid)
{
PrintText (sess, _("No recent message to reply to.\n"));
goto done;
}
reply_state_set (current_sess, item->msgid, current_sess->channel, item->nick, item->text);
mg_reply_update (current_sess);
if (current_sess->gui && current_sess->gui->input_box)
gtk_widget_grab_focus (current_sess->gui->input_box);
reply_state_set (sess, item->msgid, reply->target, item->nick, item->text);
mg_reply_update (sess);
if (sess->gui && sess->gui->input_box)
gtk_widget_grab_focus (sess->gui->input_box);
done:
g_object_unref (menu);
}
void
menu_nickmenu (session *sess, GdkEventButton *event, char *nick, int num_sel)
{
menu_nickmenu_with_message (sess, event, nick, num_sel, NULL);
}
void
menu_nickmenu_with_message (session *sess, GdkEventButton *event, char *nick,
int num_sel, const reply_item *message)
{
char buf[512];
struct User *user;
@@ -853,7 +900,24 @@ menu_nickmenu (session *sess, GdkEventButton *event, char *nick, int num_sel)
if (num_sel <= 1)
{
menu_quick_item_with_callback (menu_reply_to_latest_cb, _("Reply"), menu, 0);
/* A transcript click must identify that exact message. A user-list
* click has no message row and retains the reply-to-latest behaviour.
* Copy row data now: messages may arrive or be trimmed while open. */
reply_menu_data *reply = g_new0 (reply_menu_data, 1);
reply->sess = sess;
reply->target = g_strdup (sess->channel);
reply->latest = num_sel != 0;
if (reply->latest)
reply->nick = g_strdup (nick);
else if (message)
{
reply->msgid = g_strdup (message->msgid);
reply->nick = g_strdup (message->nick);
reply->text = g_strdup (message->text);
}
g_object_set_data_full (G_OBJECT (menu), "reply-message", reply, menu_reply_data_free);
menu_quick_item_with_callback (menu_reply_cb, _("Reply"), menu, reply);
menu_quick_item (0, 0, menu, XCMENU_SHADED, 0, 0);
}
+2
View File
@@ -29,6 +29,8 @@ void menu_chanmenu (session *sess, GdkEventButton * event, char *chan);
void menu_addfavoritemenu (server *serv, GtkWidget *menu, char *channel, gboolean istree);
void menu_addconnectmenu (server *serv, GtkWidget *menu);
void menu_nickmenu (session *sess, GdkEventButton * event, char *nick, int num_sel);
void menu_nickmenu_with_message (session *sess, GdkEventButton *event, char *nick,
int num_sel, const reply_item *message);
void menu_middlemenu (session *sess, GdkEventButton *event);
void userlist_button_cb (GtkWidget * button, char *cmd);
void nick_command_parse (session *sess, char *cmd, char *nick, char *allnick);
+44
View File
@@ -137,6 +137,49 @@ static void test_null_empty_prefix (Fixture *f, gconstpointer data)
cairo_surface_destroy (snapshot (f, FALSE));
}
static void test_message_identity (Fixture *f, gconstpointer data)
{
xtext_buffer *buf = f->xtext->buffer;
xtext_buffer *other;
textentry *first, *second;
char msgid[] = "message-one";
char nick[] = "same-nick";
char text[] = "identical text";
reply_item message = {msgid, nick, text, 1234};
const reply_item *saved;
/* ZNC playback can repeat the same sender, text and server timestamp. */
gtk_xtext_append_wrap_with_message (buf, (guchar *)text, -1, 1234, 0, &message);
first = buf->text_last;
message.msgid = "message-two";
gtk_xtext_append_indent_with_message (buf, (guchar *)nick, -1,
(guchar *)text, -1, 1234, &message);
second = buf->text_last;
msgid[0] = nick[0] = text[0] = 'X';
saved = gtk_xtext_entry_get_message (f->xtext, first);
g_assert_cmpstr (saved->msgid, ==, "message-one");
g_assert_cmpstr (saved->nick, ==, "same-nick");
g_assert_cmpstr (saved->text, ==, "identical text");
g_assert_cmpint (saved->timestamp, ==, 1234);
g_assert_cmpstr (gtk_xtext_entry_get_message (f->xtext, second)->msgid, ==, "message-two");
/* Other output must not inherit a message ID, including after reflow. */
append (f, "a plugin or status message");
g_assert_null (gtk_xtext_entry_get_message (f->xtext, buf->text_last));
g_assert_true (gtk_xtext_set_font (f->xtext, "monospace 18"));
g_assert_cmpstr (gtk_xtext_entry_get_message (f->xtext, first)->msgid, ==, "message-one");
g_assert_null (gtk_xtext_entry_get_message (f->xtext, NULL));
/* Entries from another tab, and removed entries, are never dereferenced. */
other = gtk_xtext_buffer_new (f->xtext);
gtk_xtext_buffer_show (f->xtext, other, TRUE);
g_assert_null (gtk_xtext_entry_get_message (f->xtext, first));
gtk_xtext_buffer_show (f->xtext, buf, TRUE);
gtk_xtext_buffer_free (other);
gtk_xtext_clear (buf, 0);
g_assert_null (gtk_xtext_entry_get_message (f->xtext, first));
}
static void test_wrapping (Fixture *f, gconstpointer data)
{
xtext_buffer *buf = f->xtext->buffer;
@@ -1138,6 +1181,7 @@ int main (int argc, char **argv)
ADD ("append/empty-bounded", test_empty_and_bounded_append);
ADD ("append/utf8-limits", test_utf8_limits);
ADD ("append/null-empty-prefix", test_null_empty_prefix);
ADD ("reply/message-identity", test_message_identity);
ADD ("layout/wrapping", test_wrapping);
ADD ("layout/font-isolation", test_font_isolation);
ADD ("layout/wide-metrics", test_wide_metrics);
+17 -8
View File
@@ -69,7 +69,8 @@ xtext_get_stamp_str (time_t tim, char **ret)
}
static void
PrintTextLine (xtext_buffer *xtbuf, unsigned char *text, int len, int indent, time_t timet)
PrintTextLine (xtext_buffer *xtbuf, unsigned char *text, int len, int indent, time_t timet,
const reply_item *message)
{
unsigned char *tab, *new_text;
int leftlen;
@@ -92,10 +93,11 @@ PrintTextLine (xtext_buffer *xtbuf, unsigned char *text, int len, int indent, ti
memcpy (new_text, stamp, stamp_size);
g_free (stamp);
memcpy (new_text + stamp_size, text, len);
gtk_xtext_append_wrap (xtbuf, new_text, len + stamp_size, timet, stamp_size);
gtk_xtext_append_wrap_with_message (xtbuf, new_text, len + stamp_size,
timet, stamp_size, message);
g_free (new_text);
} else
gtk_xtext_append (xtbuf, text, len, timet);
gtk_xtext_append_wrap_with_message (xtbuf, text, len, timet, 0, message);
return;
}
@@ -103,14 +105,21 @@ PrintTextLine (xtext_buffer *xtbuf, unsigned char *text, int len, int indent, ti
if (tab && tab < (text + len))
{
leftlen = tab - text;
gtk_xtext_append_indent (xtbuf,
text, leftlen, tab + 1, len - (leftlen + 1), timet);
gtk_xtext_append_indent_with_message (xtbuf, text, leftlen,
tab + 1, len - (leftlen + 1), timet, message);
} else
gtk_xtext_append_indent (xtbuf, 0, 0, text, len, timet);
gtk_xtext_append_indent_with_message (xtbuf, 0, 0, text, len, timet, message);
}
void
PrintTextRaw (void *xtbuf, unsigned char *text, int indent, time_t stamp)
{
PrintTextRawWithMessage (xtbuf, text, indent, stamp, NULL);
}
void
PrintTextRawWithMessage (void *xtbuf, unsigned char *text, int indent, time_t stamp,
const reply_item *message)
{
char *last_text = text;
int len = 0;
@@ -122,10 +131,10 @@ PrintTextRaw (void *xtbuf, unsigned char *text, int indent, time_t stamp)
switch (*text)
{
case 0:
PrintTextLine (xtbuf, last_text, len, indent, stamp);
PrintTextLine (xtbuf, last_text, len, indent, stamp, message);
return;
case '\n':
PrintTextLine (xtbuf, last_text, len, indent, stamp);
PrintTextLine (xtbuf, last_text, len, indent, stamp, message);
text++;
if (*text == 0)
return;
+4
View File
@@ -20,7 +20,11 @@
#ifndef ZOITECHAT_TEXTGUI_H
#define ZOITECHAT_TEXTGUI_H
struct reply_item;
void PrintTextRaw (void *xtbuf, unsigned char *text, int indent, time_t stamp);
void PrintTextRawWithMessage (void *xtbuf, unsigned char *text, int indent, time_t stamp,
const struct reply_item *message);
void pevent_dialog_show (void);
#endif
+49
View File
@@ -90,6 +90,7 @@ struct textentry
GdkPixbuf *image; /* inline image shown below the text, or NULL */
GdkPixbuf *image_full; /* larger version for the image viewer */
char *image_url; /* the URL the image was loaded from */
reply_item *message; /* original IRC message, independent of the reply cache */
};
/* inline image display */
@@ -287,6 +288,7 @@ static char *gtk_xtext_selection_get_text (GtkXText *xtext, int *len_ret);
static void gtk_xtext_clipboard_get (GtkClipboard *, GtkSelectionData *, guint, gpointer);
static void gtk_xtext_clipboard_clear (GtkClipboard *, gpointer);
static textentry *gtk_xtext_nth (GtkXText *xtext, int line, int *subline);
static void gtk_xtext_entry_set_message (textentry *ent, const reply_item *message);
static void gtk_xtext_adjustment_changed (GtkAdjustment * adj,
GtkXText * xtext);
static void gtk_xtext_scroll_adjustments (GtkXText *xtext, GtkAdjustment *hadj,
@@ -362,6 +364,13 @@ gtk_xtext_entry_free (GtkXText *xtext, textentry *ent)
g_clear_pointer (&ent->sublines, g_array_unref);
g_list_free (ent->marks);
gtk_xtext_ent_free_image (ent);
if (ent->message)
{
g_free (ent->message->msgid);
g_free (ent->message->nick);
g_free (ent->message->text);
g_free (ent->message);
}
g_free (ent);
}
@@ -5413,6 +5422,15 @@ gtk_xtext_append_indent (xtext_buffer *buf,
unsigned char *left_text, int left_len,
unsigned char *right_text, int right_len,
time_t stamp)
{
gtk_xtext_append_indent_with_message (buf, left_text, left_len,
right_text, right_len, stamp, NULL);
}
void
gtk_xtext_append_indent_with_message (xtext_buffer *buf,
unsigned char *left_text, int left_len, unsigned char *right_text, int right_len,
time_t stamp, const reply_item *message)
{
textentry *ent;
unsigned char *str;
@@ -5489,6 +5507,7 @@ gtk_xtext_append_indent (xtext_buffer *buf,
}
}
gtk_xtext_entry_set_message (ent, message);
gtk_xtext_append_entry (buf, ent, stamp);
}
@@ -5502,6 +5521,13 @@ gtk_xtext_append (xtext_buffer *buf, unsigned char *text, int len, time_t stamp)
void
gtk_xtext_append_wrap (xtext_buffer *buf, unsigned char *text, int len, time_t stamp, int stamp_len)
{
gtk_xtext_append_wrap_with_message (buf, text, len, stamp, stamp_len, NULL);
}
void
gtk_xtext_append_wrap_with_message (xtext_buffer *buf, unsigned char *text,
int len, time_t stamp, int stamp_len, const reply_item *message)
{
textentry *ent;
@@ -5521,6 +5547,7 @@ gtk_xtext_append_wrap (xtext_buffer *buf, unsigned char *text, int len, time_t s
ent->left_len = -1;
ent->stamp_len = (stamp_len > 0 && stamp_len < ent->str_len) ? stamp_len : 0;
gtk_xtext_entry_set_message (ent, message);
gtk_xtext_append_entry (buf, ent, stamp);
}
@@ -5854,6 +5881,28 @@ gtk_xtext_buffer_free (xtext_buffer *buf)
/* ========== INLINE IMAGE API ============= */
/* ========================================= */
/* Each rendered line owns its message identity, including continuation lines.
* Do not infer identity from nick, text or timestamp: ZNC playback and repeated
* messages can have identical values for all three. */
static void
gtk_xtext_entry_set_message (textentry *ent, const reply_item *message)
{
if (!message || !message->msgid || !*message->msgid)
return;
ent->message = g_new0 (reply_item, 1);
ent->message->msgid = g_strdup (message->msgid);
ent->message->nick = g_strdup (message->nick);
ent->message->text = g_strdup (message->text);
ent->message->timestamp = message->timestamp;
}
const reply_item *
gtk_xtext_entry_get_message (GtkXText *xtext, textentry *ent)
{
return gtk_xtext_buffer_contains (xtext, ent) ? ent->message : NULL;
}
/* the entry the last word_click signal was emitted for; only valid while
handling that signal */
+7
View File
@@ -26,6 +26,7 @@
typedef struct _GtkXText GtkXText;
typedef struct _GtkXTextClass GtkXTextClass;
struct reply_item;
#define GTK_TYPE_XTEXT (gtk_xtext_get_type ())
#define GTK_XTEXT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GTK_TYPE_XTEXT, GtkXText))
@@ -286,6 +287,11 @@ void gtk_xtext_append_indent (xtext_buffer *buf,
unsigned char *left_text, int left_len,
unsigned char *right_text, int right_len,
time_t stamp);
void gtk_xtext_append_wrap_with_message (xtext_buffer *buf, unsigned char *text,
int len, time_t stamp, int stamp_len, const struct reply_item *message);
void gtk_xtext_append_indent_with_message (xtext_buffer *buf,
unsigned char *left_text, int left_len, unsigned char *right_text, int right_len,
time_t stamp, const struct reply_item *message);
int gtk_xtext_set_font (GtkXText *xtext, char *name);
void gtk_xtext_set_background (GtkXText * xtext, cairo_surface_t *surface);
void gtk_xtext_set_palette (GtkXText * xtext, const XTextColor *palette);
@@ -318,6 +324,7 @@ xtext_buffer *gtk_xtext_buffer_new (GtkXText *xtext);
void gtk_xtext_buffer_free (xtext_buffer *buf);
void gtk_xtext_buffer_show (GtkXText *xtext, xtext_buffer *buf, int render);
void gtk_xtext_copy_selection (GtkXText *xtext);
const struct reply_item *gtk_xtext_entry_get_message (GtkXText *xtext, textentry *ent);
/* inline image support. A textentry can have one image attached, which is
* rendered below its text. Loading is asynchronous: begin() registers the
+7
View File
@@ -406,6 +406,13 @@ fe_print_text (struct session *sess, char *text, time_t stamp,
}
#endif
void
fe_print_text_with_message (struct session *sess, char *text, time_t stamp,
gboolean no_activity, const reply_item *message)
{
fe_print_text (sess, text, stamp, no_activity);
}
void
fe_timeout_remove (int tag)
{