# HG changeset patch # User Will Thompson # Date 1193507164 0 # Node ID a41ac7fd19ab7e780d56f799d9d72a9e4f1b5aa2 # Parent 318b3f5d151613e83d60449132b5cf5048d68ce1# Parent 1f59065c606aac4e2c0e174e3e7630699cb2cef4 propagate from branch 'im.pidgin.pidgin.next.minor' (head a6e1d13e8af0e00ac47c87b5e118bb3c7ed5064f) to branch 'im.pidgin.cpw.resiak.disconnectreason' (head 1c4a76a16cd4f8e8ae374ea786d9c7001acf7918) diff -r 318b3f5d1516 -r a41ac7fd19ab ChangeLog --- 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 diff -r 318b3f5d1516 -r a41ac7fd19ab ChangeLog.API --- 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: diff -r 318b3f5d1516 -r a41ac7fd19ab finch/libgnt/gntentry.c --- 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; diff -r 318b3f5d1516 -r a41ac7fd19ab finch/libgnt/gntentry.h --- 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 diff -r 318b3f5d1516 -r a41ac7fd19ab finch/libgnt/gnttree.c --- 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)); diff -r 318b3f5d1516 -r a41ac7fd19ab libpurple/conversation.c --- 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"), diff -r 318b3f5d1516 -r a41ac7fd19ab libpurple/conversation.h --- 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 */ }; /** diff -r 318b3f5d1516 -r a41ac7fd19ab pidgin/gtkconv.c --- 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), "

", 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), "

", 0); g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL);