changeset 21371:a41ac7fd19ab

propagate from branch 'im.pidgin.pidgin.next.minor' (head a6e1d13e8af0e00ac47c87b5e118bb3c7ed5064f) to branch 'im.pidgin.cpw.resiak.disconnectreason' (head 1c4a76a16cd4f8e8ae374ea786d9c7001acf7918)
author Will Thompson <will.thompson@collabora.co.uk>
date Sat, 27 Oct 2007 17:46:04 +0000
parents 318b3f5d1516 (current diff) 1f59065c606a (diff)
children b6b69faafbe3
files ChangeLog.API
diffstat 8 files changed, 179 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sat Oct 27 17:45:05 2007 +0000
+++ b/ChangeLog	Sat Oct 27 17:46:04 2007 +0000
@@ -22,6 +22,9 @@
 	  could lead to crashes.
 	* It's possible to bind key-strokes to specific menuitems in the windows.
 	  Read the 'Menus' section in the man-page for details.
+	* 'transpose-chars' operation for the entry boxes. The default key-binding
+	  is ctrl+t.
+	* 'yank' operation for the entry boxes. The default binding is ctrl+y.
 
 version 2.2.2:
 	http://developer.pidgin.im/query?status=closed&milestone=2.2.2
--- a/ChangeLog.API	Sat Oct 27 17:45:05 2007 +0000
+++ b/ChangeLog.API	Sat Oct 27 17:46:04 2007 +0000
@@ -4,7 +4,7 @@
 	libpurple:
 		Added:
 		* purple_request_field_blist_nodes_new and its accessory functions.
-		* a PurpleConversation field in PurpleConvMessage
+		* a PurpleConversation field and an alias field in PurpleConvMessage
 		* account-authorization signals (see account-signals.dox for
 		  details) (Stefan Ott)
 		* libpurple/purple.h, which includes #define's and #include's
@@ -133,6 +133,7 @@
 		  given id from a menu.
 		* Added gnt_menuitem_activate, which triggers the 'activate' signal on
 		  the menuitem and calls the callback function, if available.
+		* Added GntEntryKillRing in GntEntry.
 
 version 2.2.2 (??/??/????):
 	libpurple:
--- a/finch/libgnt/gntentry.c	Sat Oct 27 17:45:05 2007 +0000
+++ b/finch/libgnt/gntentry.c	Sat Oct 27 17:46:04 2007 +0000
@@ -36,6 +36,24 @@
 	SIG_COMPLETION,
 	SIGS,
 };
+
+typedef enum
+{
+	ENTRY_JAIL = -1,    /* Suspend the kill ring. */
+	ENTRY_DEL_BWD_WORD = 1,
+	ENTRY_DEL_BWD_CHAR,
+	ENTRY_DEL_FWD_WORD,
+	ENTRY_DEL_FWD_CHAR,
+	ENTRY_DEL_EOL,
+	ENTRY_DEL_BOL,
+} GntEntryAction;
+
+struct _GntEntryKillRing
+{
+	GString *buffer;
+	GntEntryAction last;
+};
+
 static guint signals[SIGS] = { 0 };
 
 static GntWidgetClass *parent_class = NULL;
@@ -43,6 +61,58 @@
 static gboolean gnt_entry_key_pressed(GntWidget *widget, const char *text);
 static void gnt_entry_set_text_internal(GntEntry *entry, const char *text);
 
+static gboolean
+update_kill_ring(GntEntry *entry, GntEntryAction action, const char *text, int len)
+{
+	if (action < 0) {
+		entry->killring->last = action;
+		return FALSE;
+	}
+
+	if (len == 0)
+		len = strlen(text);
+	else if (len < 0) {
+		text += len;
+		len = -len;
+	}
+
+	if (action != entry->killring->last) {
+		struct {
+			GntEntryAction one;
+			GntEntryAction two;
+		} merges[] = {
+			{ENTRY_DEL_BWD_WORD, ENTRY_DEL_FWD_WORD},
+			{ENTRY_DEL_BWD_CHAR, ENTRY_DEL_FWD_CHAR},
+			{ENTRY_DEL_BOL, ENTRY_DEL_EOL},
+			{ENTRY_JAIL, ENTRY_JAIL},
+		};
+		int i;
+
+		for (i = 0; merges[i].one != ENTRY_JAIL; i++) {
+			if (merges[i].one == entry->killring->last &&
+					merges[i].two == action) {
+				g_string_append_len(entry->killring->buffer, text, len);
+				break;
+			} else if (merges[i].one == action &&
+					merges[i].two == entry->killring->last) {
+				g_string_prepend_len(entry->killring->buffer, text, len);
+				break;
+			}
+		}
+		if (merges[i].one == ENTRY_JAIL) {
+			g_string_assign(entry->killring->buffer, text);
+			g_string_truncate(entry->killring->buffer, len);
+		}
+		entry->killring->last = action;
+	} else {
+		if (action == ENTRY_DEL_BWD_CHAR || action == ENTRY_DEL_BWD_WORD)
+			g_string_prepend_len(entry->killring->buffer, text, len);
+		else
+			g_string_append_len(entry->killring->buffer, text, len);
+	}
+	return TRUE;
+}
+
 static void
 destroy_suggest(GntEntry *entry)
 {
@@ -97,6 +167,7 @@
 	if (changed)
 		g_signal_emit(G_OBJECT(entry), signals[SIG_COMPLETION], 0,
 				entry->start + offstart, entry->start + offend);
+	update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 	return changed;
 }
 
@@ -264,6 +335,7 @@
 	entry->cursor = g_utf8_find_prev_char(entry->start, entry->cursor);
 	if (entry->cursor < entry->scroll)
 		entry->scroll = entry->cursor;
+	update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 	entry_redraw(GNT_WIDGET(entry));
 	return TRUE;
 }
@@ -277,6 +349,7 @@
 	entry->cursor = g_utf8_find_next_char(entry->cursor, NULL);
 	while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= GNT_WIDGET(entry)->priv.width)
 		entry->scroll = g_utf8_find_next_char(entry->scroll, NULL);
+	update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 	entry_redraw(GNT_WIDGET(entry));
 	return TRUE;
 }
@@ -289,9 +362,11 @@
 
 	if (entry->cursor <= entry->start)
 		return TRUE;
-	
+
 	len = entry->cursor - g_utf8_find_prev_char(entry->start, entry->cursor);
+	update_kill_ring(entry, ENTRY_DEL_BWD_CHAR, entry->cursor, -len);
 	entry->cursor -= len;
+
 	memmove(entry->cursor, entry->cursor + len, entry->end - entry->cursor);
 	entry->end -= len;
 
@@ -313,8 +388,9 @@
 
 	if (entry->cursor >= entry->end)
 		return FALSE;
-	
+
 	len = g_utf8_find_next_char(entry->cursor, NULL) - entry->cursor;
+	update_kill_ring(entry, ENTRY_DEL_FWD_CHAR, entry->cursor, len);
 	memmove(entry->cursor, entry->cursor + len, entry->end - entry->cursor - len + 1);
 	entry->end -= len;
 	entry_redraw(GNT_WIDGET(entry));
@@ -331,6 +407,7 @@
 	GntEntry *entry = GNT_ENTRY(bind);
 	entry->scroll = entry->cursor = entry->start;
 	entry_redraw(GNT_WIDGET(entry));
+	update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 	return TRUE;
 }
 
@@ -343,6 +420,7 @@
 	while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= GNT_WIDGET(entry)->priv.width)
 		entry->scroll = g_utf8_find_next_char(entry->scroll, NULL);
 	entry_redraw(GNT_WIDGET(entry));
+	update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 	return TRUE;
 }
 
@@ -357,6 +435,7 @@
 		destroy_suggest(entry);
 		entry_text_changed(entry);
 
+		update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 		return TRUE;
 	}
 	return FALSE;
@@ -381,6 +460,7 @@
 		destroy_suggest(entry);
 		entry_text_changed(entry);
 
+		update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 		return TRUE;
 	}
 	return FALSE;
@@ -400,6 +480,7 @@
 	a = g_strndup(entry->start, entry->cursor - entry->start);
 	all = g_strconcat(a, text, entry->cursor, NULL);
 	gnt_entry_set_text_internal(entry, all);
+	update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 	g_free(a);
 	g_free(text);
 	g_free(all);
@@ -445,6 +526,7 @@
 	GntEntry *entry = GNT_ENTRY(bind);
 	if (entry->cursor <= entry->start)
 		return TRUE;
+	update_kill_ring(entry, ENTRY_DEL_BOL, entry->start, entry->cursor - entry->start);
 	memmove(entry->start, entry->cursor, entry->end - entry->cursor);
 	entry->end -= (entry->cursor - entry->start);
 	entry->cursor = entry->scroll = entry->start;
@@ -460,6 +542,7 @@
 	GntEntry *entry = GNT_ENTRY(bind);
 	if (entry->end <= entry->cursor)
 		return TRUE;
+	update_kill_ring(entry, ENTRY_DEL_EOL, entry->cursor, entry->end - entry->cursor);
 	entry->end = entry->cursor;
 	memset(entry->end, '\0', entry->buffer - (entry->end - entry->start));
 	entry_redraw(GNT_WIDGET(bind));
@@ -517,6 +600,7 @@
 	entry->cursor = (char*)iter;
 	if (entry->cursor < entry->scroll)
 		entry->scroll = entry->cursor;
+	update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 	entry_redraw(GNT_WIDGET(bind));
 	return TRUE;
 }
@@ -533,6 +617,7 @@
 		return TRUE;
 	iter = (char*)begin_word(iter, entry->start);
 	count = entry->cursor - iter;
+	update_kill_ring(entry, ENTRY_DEL_BWD_WORD, iter, count);
 	memmove(iter, entry->cursor, entry->end - entry->cursor);
 	entry->end -= count;
 	entry->cursor = iter;
@@ -557,6 +642,7 @@
 	while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= widget->priv.width) {
 		entry->scroll = g_utf8_find_next_char(entry->scroll, NULL);
 	}
+	update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 	entry_redraw(widget);
 	return TRUE;
 }
@@ -570,6 +656,7 @@
 	int len = entry->end - iter + 1;
 	if (len <= 0)
 		return TRUE;
+	update_kill_ring(entry, ENTRY_DEL_FWD_WORD, entry->cursor, iter - entry->cursor);
 	memmove(entry->cursor, iter, len);
 	len = iter - entry->cursor;
 	entry->end -= len;
@@ -580,6 +667,42 @@
 }
 
 static gboolean
+transpose_chars(GntBindable *bind, GList *null)
+{
+	GntEntry *entry = GNT_ENTRY(bind);
+	char *current, *prev;
+	char hold[8];  /* that's right */
+
+	if (entry->cursor <= entry->start)
+		return FALSE;
+
+	if (!*entry->cursor)
+		entry->cursor = g_utf8_find_prev_char(entry->start, entry->cursor);
+
+	current = entry->cursor;
+	prev = g_utf8_find_prev_char(entry->start, entry->cursor);
+	move_forward(bind, null);
+
+	/* Let's do this dance! */
+	memcpy(hold, prev, current - prev);
+	memmove(prev, current, entry->cursor - current);
+	memcpy(prev + (entry->cursor - current), hold, current - prev);
+
+	update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
+	entry_redraw(GNT_WIDGET(entry));
+	entry_text_changed(entry);
+	return TRUE;
+}
+
+static gboolean
+entry_yank(GntBindable *bind, GList *null)
+{
+	GntEntry *entry = GNT_ENTRY(bind);
+	gnt_entry_key_pressed(GNT_WIDGET(entry), entry->killring->buffer->str);
+	return TRUE;
+}
+
+static gboolean
 gnt_entry_key_pressed(GntWidget *widget, const char *text)
 {
 	GntEntry *entry = GNT_ENTRY(widget);
@@ -602,6 +725,7 @@
 			destroy_suggest(entry);
 			complete_suggest(entry, text);
 			g_free(text);
+			update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 			entry_text_changed(entry);
 			return TRUE;
 		}
@@ -658,6 +782,7 @@
 				if (entry->ddown)
 					show_suggest_dropdown(entry);
 			}
+			update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 			entry_redraw(widget);
 			entry_text_changed(entry);
 			return TRUE;
@@ -668,6 +793,13 @@
 }
 
 static void
+jail_killring(GntEntryKillRing *kr)
+{
+	g_string_free(kr->buffer, TRUE);
+	g_free(kr);
+}
+
+static void
 gnt_entry_destroy(GntWidget *widget)
 {
 	GntEntry *entry = GNT_ENTRY(widget);
@@ -690,6 +822,8 @@
 	{
 		gnt_widget_destroy(entry->ddown->parent);
 	}
+
+	jail_killring(entry->killring);
 }
 
 static void
@@ -762,6 +896,10 @@
 				"\033" "f", NULL);
 	gnt_bindable_class_register_action(bindable, "delete-next-word", delete_forward_word,
 				"\033" "d", NULL);
+	gnt_bindable_class_register_action(bindable, "transpose-chars", transpose_chars,
+				GNT_KEY_CTRL_T, NULL);
+	gnt_bindable_class_register_action(bindable, "yank", entry_yank,
+				GNT_KEY_CTRL_Y, NULL);
 	gnt_bindable_class_register_action(bindable, "suggest-show", suggest_show,
 				"\t", NULL);
 	gnt_bindable_class_register_action(bindable, "suggest-next", suggest_next,
@@ -779,6 +917,14 @@
 	GNTDEBUG;
 }
 
+static GntEntryKillRing *
+new_killring()
+{
+	GntEntryKillRing *kr = g_new0(GntEntryKillRing, 1);
+	kr->buffer = g_string_new(NULL);
+	return kr;
+}
+
 static void
 gnt_entry_init(GTypeInstance *instance, gpointer class)
 {
@@ -787,13 +933,14 @@
 
 	entry->flag = GNT_ENTRY_FLAG_ALL;
 	entry->max = 0;
-	
+
 	entry->histlength = 0;
 	entry->history = NULL;
 
 	entry->word = TRUE;
 	entry->always = FALSE;
 	entry->suggests = NULL;
+	entry->killring = new_killring();
 
 	GNT_WIDGET_SET_FLAGS(GNT_WIDGET(entry),
 			GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW | GNT_WIDGET_CAN_TAKE_FOCUS);
@@ -801,7 +948,7 @@
 
 	widget->priv.minw = 3;
 	widget->priv.minh = 1;
-	
+
 	GNTDEBUG;
 }
 
@@ -992,7 +1139,7 @@
 
 	if (!text || !*text)
 		return;
-	
+
 	find = g_list_find_custom(entry->suggests, text, (GCompareFunc)g_utf8_collate);
 	if (find)
 		return;
--- a/finch/libgnt/gntentry.h	Sat Oct 27 17:45:05 2007 +0000
+++ b/finch/libgnt/gntentry.h	Sat Oct 27 17:46:04 2007 +0000
@@ -48,6 +48,7 @@
 typedef struct _GntEntry			GntEntry;
 typedef struct _GntEntryPriv		GntEntryPriv;
 typedef struct _GntEntryClass	GntEntryClass;
+typedef struct _GntEntryKillRing    GntEntryKillRing;
 
 typedef enum
 {
@@ -71,9 +72,9 @@
 	char *scroll;   /* Current scrolling position */
 	char *cursor;   /* Cursor location */
 	                /* 0 <= cursor - scroll < widget-width */
-	
+
 	size_t buffer;  /* Size of the buffer */
-	
+
 	int max;        /* 0 means infinite */
 	gboolean masked;
 
@@ -84,6 +85,7 @@
 	gboolean word;      /* Are the suggestions for only a word, or for the whole thing? */
 	gboolean always;    /* Should the list of suggestions show at all times, or only on tab-press? */
 	GntWidget *ddown;   /* The dropdown with the suggested list */
+	GntEntryKillRing *killring; /**< @since 2.3.0 */
 };
 
 struct _GntEntryClass
--- a/finch/libgnt/gnttree.c	Sat Oct 27 17:45:05 2007 +0000
+++ b/finch/libgnt/gnttree.c	Sat Oct 27 17:46:04 2007 +0000
@@ -455,9 +455,10 @@
 		}
 		if (pos)
 		{
-			tree_mark_columns(tree, pos, 0, ACS_TTEE | gnt_color_pair(GNT_COLOR_NORMAL));
+			tree_mark_columns(tree, pos, 0,
+					(tree->show_separator ? ACS_TTEE : ACS_HLINE) | gnt_color_pair(GNT_COLOR_NORMAL));
 			tree_mark_columns(tree, pos, widget->priv.height - pos,
-					ACS_BTEE | gnt_color_pair(GNT_COLOR_NORMAL));
+					(tree->show_separator ? ACS_BTEE : ACS_HLINE) | gnt_color_pair(GNT_COLOR_NORMAL));
 		}
 		tree_mark_columns(tree, pos, pos + 1,
 			(tree->show_separator ? ACS_PLUS : ACS_HLINE) | gnt_color_pair(GNT_COLOR_NORMAL));
--- a/libpurple/conversation.c	Sat Oct 27 17:45:05 2007 +0000
+++ b/libpurple/conversation.c	Sat Oct 27 17:46:04 2007 +0000
@@ -205,8 +205,8 @@
 /* Functions that deal with PurpleConvMessage */
 
 static void
-add_message_to_history(PurpleConversation *conv, const char *who, const char *message,
-		PurpleMessageFlags flags, time_t when)
+add_message_to_history(PurpleConversation *conv, const char *who, const char *alias,
+		const char *message, PurpleMessageFlags flags, time_t when)
 {
 	PurpleConvMessage *msg;
 
@@ -218,10 +218,11 @@
 			me = conv->account->username;
 		who = me;
 	}
-	
+
 	msg = g_new0(PurpleConvMessage, 1);
 	PURPLE_DBUS_REGISTER_POINTER(msg, PurpleConvMessage);
 	msg->who = g_strdup(who);
+	msg->alias = g_strdup(alias);
 	msg->flags = flags;
 	msg->what = g_strdup(message);
 	msg->when = when;
@@ -234,6 +235,7 @@
 free_conv_message(PurpleConvMessage *msg)
 {
 	g_free(msg->who);
+	g_free(msg->alias);
 	g_free(msg->what);
 	PURPLE_DBUS_UNREGISTER_POINTER(msg);
 	g_free(msg);
@@ -293,14 +295,10 @@
 	/* Check if this conversation already exists. */
 	if ((conv = purple_find_conversation_with_account(type, name, account)) != NULL)
 	{
-		if (purple_conversation_get_type(conv) != PURPLE_CONV_TYPE_CHAT ||
-		    purple_conv_chat_has_left(PURPLE_CONV_CHAT(conv)))
-		{
-			if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT)
-				purple_conversation_chat_cleanup_for_rejoin(conv);
-
-			return conv;
-		}
+		if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT &&
+				purple_conv_chat_has_left(PURPLE_CONV_CHAT(conv)))
+			purple_conversation_chat_cleanup_for_rejoin(conv);
+		return conv;
 	}
 
 	gc = purple_account_get_connection(account);
@@ -934,7 +932,8 @@
 
 	if (ops && ops->write_conv)
 		ops->write_conv(conv, who, alias, displayed, flags, mtime);
-	add_message_to_history(conv, who, message, flags, mtime);
+
+	add_message_to_history(conv, who, alias, message, flags, mtime);
 
 	purple_signal_emit(purple_conversations_get_handle(),
 		(type == PURPLE_CONV_TYPE_IM ? "wrote-im-msg" : "wrote-chat-msg"),
--- a/libpurple/conversation.h	Sat Oct 27 17:45:05 2007 +0000
+++ b/libpurple/conversation.h	Sat Oct 27 17:46:04 2007 +0000
@@ -294,7 +294,8 @@
 	char *what;
 	PurpleMessageFlags flags;
 	time_t when;
-	PurpleConversation *conv;
+	PurpleConversation *conv;  /**< @since 2.3.0 */
+	char *alias;               /**< @since 2.3.0 */
 };
 
 /**
--- a/pidgin/gtkconv.c	Sat Oct 27 17:45:05 2007 +0000
+++ b/pidgin/gtkconv.c	Sat Oct 27 17:46:04 2007 +0000
@@ -7435,7 +7435,7 @@
 			gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR><HR>", 0);
 			g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL);
 		}
-		pidgin_conv_write_conv(msg->conv, msg->who, msg->who, msg->what, msg->flags, msg->when);
+		pidgin_conv_write_conv(msg->conv, msg->who, msg->alias, msg->what, msg->flags, msg->when);
 		if (im) {
 			gtkconv->attach.current = g_list_delete_link(gtkconv->attach.current, gtkconv->attach.current);
 		} else {
@@ -7465,7 +7465,7 @@
 		msgs = g_list_sort(msgs, message_compare);
 		for (; msgs; msgs = g_list_delete_link(msgs, msgs)) {
 			PurpleConvMessage *msg = msgs->data;
-			pidgin_conv_write_conv(msg->conv, msg->who, msg->who, msg->what, msg->flags, msg->when);
+			pidgin_conv_write_conv(msg->conv, msg->who, msg->alias, msg->what, msg->flags, msg->when);
 		}
 		gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR><HR>", 0);
 		g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL);