changeset 18339:b4f5a2c0f00a

merge of '4622b2fa3f28dfda1d13eac1a7db52752dd45635' and '7bf90628ea82588a24a5c2e11b62e1128d8c90f0'
author Richard Laager <rlaager@wiktel.com>
date Thu, 28 Jun 2007 14:53:47 +0000
parents 6f5e6efd2241 (current diff) 466f933f4a6b (diff)
children e356256cb8a6 7f2c22c705a5 2aad33bb021d 27e54692b2b4
files
diffstat 46 files changed, 542 insertions(+), 214 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Thu Jun 28 14:12:35 2007 +0000
+++ b/COPYRIGHT	Thu Jun 28 14:53:47 2007 +0000
@@ -356,6 +356,7 @@
 Cestonaro Thilo
 Will Thompson
 Douglas Thrift (douglaswth)
+Mark Tiefenbruck
 Andrew Tinney
 Jeffery To
 Warren Togami
--- a/Doxyfile.in	Thu Jun 28 14:12:35 2007 +0000
+++ b/Doxyfile.in	Thu Jun 28 14:53:47 2007 +0000
@@ -432,8 +432,9 @@
 # with spaces.
 
 INPUT                  = libpurple \
-						 finch \
-						 pidgin \
+	                     finch \
+	                     finch/libgnt \
+	                     pidgin \
                          doc
 
 # If the value of the INPUT tag contains directories, you can use the 
--- a/finch/finch.c	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/finch.c	Thu Jun 28 14:53:47 2007 +0000
@@ -381,10 +381,12 @@
 {
 	signal(SIGPIPE, SIG_IGN);
 
+	g_set_application_name(_("Finch"));
+
 	/* Initialize the libpurple stuff */
 	if (!init_libpurple(argc, argv))
 		return 0;
-
+ 
 	purple_blist_show();
 	gnt_main();
 
--- a/finch/gntblist.c	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/gntblist.c	Thu Jun 28 14:53:47 2007 +0000
@@ -1260,7 +1260,7 @@
 }
 
 static void
-tooltip_for_buddy(PurpleBuddy *buddy, GString *str)
+tooltip_for_buddy(PurpleBuddy *buddy, GString *str, gboolean full)
 {
 	PurplePlugin *prpl;
 	PurplePluginProtocolInfo *prpl_info;
@@ -1273,7 +1273,7 @@
 
 	account = purple_buddy_get_account(buddy);
 
-	if (g_utf8_collate(purple_buddy_get_name(buddy), alias))
+	if (!full || g_utf8_collate(purple_buddy_get_name(buddy), alias))
 		purple_notify_user_info_add_pair(user_info, _("Nickname"), alias);
 
 	tmp = g_strdup_printf("%s (%s)",
@@ -1285,7 +1285,7 @@
 	prpl = purple_find_prpl(purple_account_get_protocol_id(account));
 	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 	if (prpl_info && prpl_info->tooltip_text) {
-		prpl_info->tooltip_text(buddy, user_info, TRUE);
+		prpl_info->tooltip_text(buddy, user_info, full);
 	}
 
 	if (purple_prefs_get_bool("/finch/blist/idletime")) {
@@ -1357,7 +1357,7 @@
 		const char *name = purple_buddy_get_name(pr);
 
 		title = g_strdup(name);
-		tooltip_for_buddy(pr, str);
+		tooltip_for_buddy(pr, str, TRUE);
 		for (node = node->child; node; node = node->next) {
 			PurpleBuddy *buddy = (PurpleBuddy*)node;
 			if (offline) {
@@ -1372,11 +1372,11 @@
 			if (!showoffline && !PURPLE_BUDDY_IS_ONLINE(buddy))
 				continue;
 			str = g_string_append(str, "\n----------\n");
-			tooltip_for_buddy(buddy, str);
+			tooltip_for_buddy(buddy, str, FALSE);
 		}
 	} else if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
 		PurpleBuddy *buddy = (PurpleBuddy *)node;
-		tooltip_for_buddy(buddy, str);
+		tooltip_for_buddy(buddy, str, TRUE);
 		title = g_strdup(purple_buddy_get_name(buddy));
 		if (!PURPLE_BUDDY_IS_ONLINE((PurpleBuddy*)node))
 			lastseen = purple_blist_node_get_int(node, "last_seen");
@@ -1422,9 +1422,10 @@
 
 	str = make_sure_text_fits(str);
 	gnt_util_get_text_bound(str->str, &w, &h);
-	h = MAX(2, h);
+	h = MAX(1, h);
 	tv = gnt_text_view_new();
 	gnt_widget_set_size(tv, w + 1, h);
+	gnt_text_view_set_flag(GNT_TEXT_VIEW(tv), GNT_TEXT_VIEW_NO_SCROLL);
 	gnt_box_add_widget(GNT_BOX(box), tv);
 
 	gnt_widget_set_position(box, x, y);
--- a/finch/libgnt/gnt-skel.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gnt-skel.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gnt-skel.h -skel API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
--- a/finch/libgnt/gnt.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gnt.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,14 @@
 /**
+ * @defgroup gnt GNT (GLib Ncurses Toolkit)
+ *
+ * GNT is an ncurses toolkit for creating text-mode graphical user interfaces
+ * in a fast and easy way.
+ */
+/**
+ * @file gnt.h GNT API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
--- a/finch/libgnt/gntbindable.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntbindable.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gntbindable.h Bindable API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
--- a/finch/libgnt/gntbox.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntbox.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gntbox.h Box API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
@@ -84,9 +88,8 @@
 G_BEGIN_DECLS
 
 /**
- * 
- *
- * @return
+ * The GType for GntBox.
+ * @return The GType.
  */
 GType gnt_box_get_gtype(void);
 
@@ -94,98 +97,110 @@
 #define gnt_hbox_new(homo) gnt_box_new(homo, FALSE)
 
 /**
- * 
- * @param homo
- * @param vert
+ * Create a new GntBox.
  *
- * @return
+ * @param homo  If @c TRUE, all the widgets in it will have the same width (or height)
+ * @param vert  Whether the widgets in it should be stacked vertically (if @c TRUE)
+ *              or horizontally (if @c FALSE).
+ *
+ * @return The new GntBox.
  */
 GntWidget * gnt_box_new(gboolean homo, gboolean vert);
 
 /**
- * 
- * @param box
- * @param widget
+ * Add a widget in the box.
+ *
+ * @param box     The box
+ * @param widget  The widget to add
  */
 void gnt_box_add_widget(GntBox *box, GntWidget *widget);
 
 /**
- * 
- * @param box
- * @param title
+ * Set a title for the box.
+ *
+ * @param box    The box
+ * @param title	 The title to set
  */
 void gnt_box_set_title(GntBox *box, const char *title);
 
 /**
- * 
- * @param box
- * @param pad
+ * Set the padding to use between the widgets in the box.
+ *
+ * @param box The box
+ * @param pad The padding to use
  */
 void gnt_box_set_pad(GntBox *box, int pad);
 
 /**
- * 
- * @param box
- * @param set
+ * Set whether it's a toplevel box (ie, a window) or not. If a box is toplevel,
+ * then it will show borders, the title (if set) and shadow (if enabled in
+ * @e .gntrc)
+ *
+ * @param box The box
+ * @param set @c TRUE if it's a toplevel box, @c FALSE otherwise.
  */
 void gnt_box_set_toplevel(GntBox *box, gboolean set);
 
 /**
- * 
- * @param box
+ * Reposition and refresh the widgets in the box.
+ *
+ * @param box The box
  */
 void gnt_box_sync_children(GntBox *box);
 
 /**
- * 
- * @param box
- * @param alignment
+ * Set the alignment for the widgets in the box.
+ *
+ * @param box       The box
+ * @param alignment The alignment to use
  */
 void gnt_box_set_alignment(GntBox *box, GntAlignment alignment);
 
 /**
- * 
- * @param box
- * @param widget
+ * Remove a widget from the box. Calling this does NOT destroy the removed widget.
+ *
+ * @param box       The box
+ * @param widget    The widget to remove
  */
 void gnt_box_remove(GntBox *box, GntWidget *widget);
 
- /* XXX: does NOT destroy widget */
-
 /**
- * 
- * @param box
+ * Remove all widgets from the box. This DOES destroy all widgets in the box.
+ *
+ * @param box The box
  */
 void gnt_box_remove_all(GntBox *box);
 
-      /* Removes AND destroys all the widgets in it */
-
 /**
- * 
- * @param box
+ * Readjust the size of each child widget, reposition the child widgets and
+ * recalculate the size of the box.
+ *
+ * @param box  The box
  */
 void gnt_box_readjust(GntBox *box);
 
 /**
- * 
- * @param box
- * @param fill
+ * Set whether the widgets in the box should fill the empty spaces.
+ *
+ * @param box   The box
+ * @param fill  Whether the child widgets should fill the empty space
  */
 void gnt_box_set_fill(GntBox *box, gboolean fill);
 
 /**
- * 
- * @param box
- * @param dir
+ * Move the focus from one widget to the other.
+ *
+ * @param box The box
+ * @param dir The direction. If it's 1, then the focus is moved forwards, if it's
+ *            -1, the focus is moved backwards.
  */
 void gnt_box_move_focus(GntBox *box, int dir);
 
-  /* +1 to move forward, -1 for backward */
-
 /**
- * 
- * @param box
- * @param widget
+ * Give focus to a specific child widget.
+ *
+ * @param box       The box
+ * @param widget    The child widget to give focus
  */
 void gnt_box_give_focus_to_child(GntBox *box, GntWidget *widget);
 
--- a/finch/libgnt/gntbutton.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntbutton.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gntbutton.h Button API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
--- a/finch/libgnt/gntcheckbox.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntcheckbox.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gntcheckbox.h Checkbox API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
--- a/finch/libgnt/gntclipboard.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntclipboard.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gntclipboard.h Clipboard API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
--- a/finch/libgnt/gntcolors.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntcolors.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gntcolors.h Colors API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
--- a/finch/libgnt/gntcombobox.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntcombobox.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gntcombobox.h Combobox API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
--- a/finch/libgnt/gntentry.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntentry.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gntentry.h Entry API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
--- a/finch/libgnt/gntfilesel.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntfilesel.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gntfilesel.h File selector API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
--- a/finch/libgnt/gntkeys.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntkeys.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gntkeys.h Keys API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
--- a/finch/libgnt/gntlabel.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntlabel.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gntlabel.h Label API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
--- a/finch/libgnt/gntline.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntline.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gntline.h Line API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
--- a/finch/libgnt/gntmenu.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntmenu.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gntmenu.h Menu API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
--- a/finch/libgnt/gntmenuitem.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntmenuitem.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gntmenuitem.h Menuitem API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
--- a/finch/libgnt/gntmenuitemcheck.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntmenuitemcheck.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gntmenuitemcheck.h Check Menuitem API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
--- a/finch/libgnt/gntstyle.c	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntstyle.c	Thu Jun 28 14:53:47 2007 +0000
@@ -36,7 +36,6 @@
 static GKeyFile *gkfile;
 #endif
 
-static GHashTable *unknowns;
 static char * str_styles[GNT_STYLES];
 static int int_styles[GNT_STYLES];
 static int bool_styles[GNT_STYLES];
@@ -46,9 +45,11 @@
 	return str_styles[style];
 }
 
-const char *gnt_style_get_from_name(const char *name)
+char *gnt_style_get_from_name(const char *group, const char *key)
 {
-	return g_hash_table_lookup(unknowns, name);
+#if GLIB_CHECK_VERSION(2,6,0)
+	return g_key_file_get_value(gkfile, group, key, NULL);
+#endif
 }
 
 gboolean gnt_style_get_bool(GntStyle style, gboolean def)
@@ -293,10 +294,6 @@
 			str_styles[styles[i].en] =
 					g_key_file_get_string(kfile, "general", styles[i].style, NULL);
 		}
-
-		for (i = 0; i < nkeys; i++)
-			g_hash_table_replace(unknowns, g_strdup(keys[i]),
-					g_strdup(g_key_file_get_string(kfile, "general", keys[i], NULL)));
 	}
 	g_strfreev(keys);
 }
@@ -307,9 +304,9 @@
 #if GLIB_CHECK_VERSION(2,6,0)
 	GError *error = NULL;
 	gkfile = g_key_file_new();
-	unknowns = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
 
-	if (!g_key_file_load_from_file(gkfile, filename, G_KEY_FILE_NONE, &error))
+	if (!g_key_file_load_from_file(gkfile, filename,
+                G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, &error))
 	{
 		g_printerr("GntStyle: %s\n", error->message);
 		g_error_free(error);
@@ -337,7 +334,6 @@
 	for (i = 0; i < GNT_STYLES; i++)
 		g_free(str_styles[i]);
 
-	g_hash_table_destroy(unknowns);
 #if GLIB_CHECK_VERSION(2,6,0)
 	g_key_file_free(gkfile);
 #endif
--- a/finch/libgnt/gntstyle.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntstyle.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gntstyle.h Style API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
@@ -41,7 +45,7 @@
 
 const char *gnt_style_get(GntStyle style);
 
-const char *gnt_style_get_from_name(const char *key);
+char *gnt_style_get_from_name(const char *group, const char *key);
 
 /**
  * 
--- a/finch/libgnt/gnttextview.c	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gnttextview.c	Thu Jun 28 14:53:47 2007 +0000
@@ -65,6 +65,7 @@
 	int i = 0;
 	GList *lines;
 	int rows, scrcol;
+	gboolean has_scroll = !(view->flags & GNT_TEXT_VIEW_NO_SCROLL);
 
 	wbkgd(widget->window, COLOR_PAIR(GNT_COLOR_NORMAL));
 	werase(widget->window);
@@ -111,12 +112,12 @@
 			*end = back;
 		}
 		wattroff(widget->window, A_UNDERLINE | A_BLINK | A_REVERSE);
-		whline(widget->window, ' ', widget->priv.width - line->length - 1);
+		whline(widget->window, ' ', widget->priv.width - line->length - has_scroll);
 	}
 
 	scrcol = widget->priv.width - 1;
 	rows = widget->priv.height - 2;
-	if (rows > 0)
+	if (has_scroll && rows > 0)
 	{
 		int total = g_list_length(g_list_first(view->list));
 		int showing, position, up, down;
@@ -143,11 +144,13 @@
 				ACS_CKBOARD | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D), showing);
 	}
 
-	mvwaddch(widget->window, 0, scrcol,
-			(lines ? ACS_UARROW : ' ') | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D));
-	mvwaddch(widget->window, widget->priv.height - 1, scrcol,
-			((view->list && view->list->prev) ? ACS_DARROW : ' ') |
-				COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D));
+	if (has_scroll) {
+		mvwaddch(widget->window, 0, scrcol,
+				(lines ? ACS_UARROW : ' ') | COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D));
+		mvwaddch(widget->window, widget->priv.height - 1, scrcol,
+				((view->list && view->list->prev) ? ACS_DARROW : ' ') |
+					COLOR_PAIR(GNT_COLOR_HIGHLIGHT_D));
+	}
 
 	GNTDEBUG;
 }
@@ -483,6 +486,8 @@
 	GList *list = view->list;
 	GntTextLine *line;
 	int len;
+	gboolean has_scroll = !(view->flags & GNT_TEXT_VIEW_NO_SCROLL);
+	gboolean wrap_word = !(view->flags & GNT_TEXT_VIEW_WRAP_CHAR);
 
 	if (text == NULL || *text == '\0')
 		return;
@@ -519,7 +524,7 @@
 		}
 
 		line = view->list->data;
-		if (line->length == widget->priv.width - 1) {
+		if (line->length == widget->priv.width - has_scroll) {
 			/* The last added line was exactly the same width as the widget */
 			line = g_new0(GntTextLine, 1);
 			line->soft = TRUE;
@@ -528,15 +533,15 @@
 
 		if ((end = strchr(start, '\r')) != NULL ||
 			(end = strchr(start, '\n')) != NULL) {
-			len = gnt_util_onscreen_width(start, end - 1);
-			if (len >= widget->priv.width - line->length - 1) {
+			len = gnt_util_onscreen_width(start, end - has_scroll);
+			if (len >= widget->priv.width - line->length - has_scroll) {
 				end = NULL;
 			}
 		}
 
 		if (end == NULL)
 			end = gnt_util_onscreen_width_to_pointer(start,
-					widget->priv.width - line->length - 1, &len);
+					widget->priv.width - line->length - has_scroll, &len);
 
 		/* Try to append to the previous segment if possible */
 		if (line->segments) {
@@ -554,7 +559,7 @@
 		}
 
 		oldl = line;
-		if (*end && *end != '\n' && *end != '\r') {
+		if (wrap_word && *end && *end != '\n' && *end != '\r') {
 			const char *tmp = end;
 			while (end && *end != '\n' && *end != '\r' && !g_ascii_isspace(*end)) {
 				end = g_utf8_find_prev_char(seg->start + view->string->str, end);
@@ -783,3 +788,8 @@
 	g_signal_connect(G_OBJECT(widget), "key_pressed", G_CALLBACK(scroll_tv), view);
 }
 
+void gnt_text_view_set_flag(GntTextView *view, GntTextViewFlag flag)
+{
+	view->flags |= flag;
+}
+
--- a/finch/libgnt/gnttextview.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gnttextview.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gnttextview.h Textview API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
@@ -43,6 +47,11 @@
 typedef struct _GntTextViewPriv		GntTextViewPriv;
 typedef struct _GntTextViewClass		GntTextViewClass;
 
+typedef enum {
+	GNT_TEXT_VIEW_NO_SCROLL     = 1 << 0,
+	GNT_TEXT_VIEW_WRAP_CHAR     = 1 << 1,
+} GntTextViewFlag;
+
 struct _GntTextView
 {
 	GntWidget parent;
@@ -51,6 +60,7 @@
 	GList *list;        /* List of GntTextLine */
 
 	GList *tags;       /* A list of tags */
+	GntTextViewFlag flags;
 };
 
 typedef enum
@@ -173,6 +183,14 @@
  */
 void gnt_text_view_attach_scroll_widget(GntTextView *view, GntWidget *widget);
 
+/**
+ * Set a GntTextViewFlag for the textview widget.
+ *
+ * @param view  The textview widget
+ * @param flag  The flag to set
+ */
+void gnt_text_view_set_flag(GntTextView *view, GntTextViewFlag flag);
+
 G_END_DECLS
 
 #endif /* GNT_TEXT_VIEW_H */
--- a/finch/libgnt/gnttree.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gnttree.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gnttree.h Tree API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
--- a/finch/libgnt/gntutils.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntutils.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gntutils.h Some utility functions
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
@@ -28,87 +32,101 @@
 typedef gpointer (*GDupFunc)(gconstpointer data);
 
 /**
- * 
- * @param text
- * @param width
- * @param height
+ * Compute the width and height required to view the text on the screen.
+ *
+ * @param text     The text to be displayed.
+ * @param width    The width required is set here, if not @c NULL.
+ * @param height   The height required is set here, if not @c NULL.
  */
 void gnt_util_get_text_bound(const char *text, int *width, int *height);
 
-/* excluding *end */
 /**
- * 
- * @param start
- * @param end
+ * Get the onscreen width of a string, or a substring.
  *
- * @return
+ * @param start  The beginning of the string.
+ * @param end    The end of the string. The width returned is the width
+ *               upto (but not including) end. If end is NULL, then start
+ *               is considered as a @c NULL-terminated string.
+ *
+ * @return       The on-screen width of the string.
  */
 int gnt_util_onscreen_width(const char *start, const char *end);
 
+/**
+ * Computes and returns the string after a specific number of onscreen characters.
+ *
+ * @param str  The string.
+ * @param len  The length to consider. If non-positive, the entire screenlength is used.
+ * @param w    The actual width of the string upto the returned offset, if not @c NULL.
+ *
+ * @return     The string after len offset.
+ */
 const char *gnt_util_onscreen_width_to_pointer(const char *str, int len, int *w);
 
-/* Inserts newlines in 'string' where necessary so that its onscreen width is
+/**
+ * Inserts newlines in 'string' where necessary so that its onscreen width is 
  * no more than 'maxw'.
- * 'maxw' can be <= 0, in which case the maximum screen width is considered.
  *
- * Returns a newly allocated string.
- */
-/**
- * 
- * @param string
- * @param maxw
+ * @param string  The string.
+ * @param maxw    The width that the string should fit into. If maxw is <= 0,
+ *                then the available maximum width is used.
  *
- * @return
+ * @return  A newly allocated string that needs to be freed by the caller.
  */
 char * gnt_util_onscreen_fit_string(const char *string, int maxw);
 
 /**
- * 
- * @param src
- * @param hash
- * @param equal
- * @param key_d
- * @param value_d
- * @param key_dup
- * @param value_dup
+ * Duplicate the contents of a hastable.
  *
- * @return
+ * @param src         The source hashtable.
+ * @param hash        The hash-function to use.
+ * @param equal       The hash-equal function to use.
+ * @param key_d       The key-destroy function to use.
+ * @param value_d     The value-destroy function to use.
+ * @param key_dup     The function to use to duplicate the key.
+ * @param value_dup   The function to use to duplicate the value.
+ *
+ * @return    The new hashtable.
  */
 GHashTable * g_hash_table_duplicate(GHashTable *src, GHashFunc hash, GEqualFunc equal, GDestroyNotify key_d, GDestroyNotify value_d, GDupFunc key_dup, GDupFunc value_dup);
 
 /**
  * To be used with g_signal_new. Look in the key_pressed signal-definition in
  * gntwidget.c for usage.
- */
-/**
- * 
- * @param ihint
- * @param return_accu
- * @param handler_return
- * @param dummy
  *
- * @return
+ * @param ihint           NA
+ * @param return_accu     NA
+ * @param handler_return  NA
+ * @param dummy           NA
+ *
+ * @return  NA
  */
 gboolean gnt_boolean_handled_accumulator(GSignalInvocationHint *ihint, GValue *return_accu, const GValue *handler_return, gpointer dummy);
 
 /**
- * Returns a GntTree populated with "key" -> "binding" for the widget.
- */
-/**
+ * Get a helpful display about the bindings of a widget.
  * 
- * @param widget
+ * @param widget The widget to get bindings for.
  *
- * @return
+ * @return Returns a GntTree populated with "key" -> "binding" for the widget.
  */
 GntWidget * gnt_widget_bindings_view(GntWidget *widget);
 
 /**
- * Parse widgets from 'string'.
- */
-/**
+ * Parse widgets from an XML description. For example,
+ *
+ * @code
+ * GntWidget *win, *button;
+ * gnt_util_parse_widgets("\
+ *      <vwindow id='0' fill='0' align='2'>     \
+ *          <label>This is a test</label>       \
+ *          <button id='1'>OK</button>          \
+ *      </vwindow>",
+ *   2, &win, &button);
+ * @endcode
  * 
- * @param string
- * @param num
+ * @param string  The XML string.
+ * @param num     The number of widgets to return, followed by 'num' GntWidget **
  */
 void gnt_util_parse_widgets(const char *string, int num, ...);
 
--- a/finch/libgnt/gntwidget.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntwidget.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gntwidget.h Widget API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
--- a/finch/libgnt/gntwindow.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntwindow.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gntwindow.h Window API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
--- a/finch/libgnt/gntwm.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntwm.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,4 +1,8 @@
 /**
+ * @file gntwm.h Window-manager API
+ * @ingroup gnt
+ */
+/*
  * GNT - The GLib Ncurses Toolkit
  *
  * GNT is the legal property of its developers, whose names are too numerous
--- a/finch/libgnt/gntws.h	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/gntws.h	Thu Jun 28 14:53:47 2007 +0000
@@ -1,3 +1,29 @@
+/**
+ * @file gntws.h Workspace API
+ * @ingroup gnt
+ */
+/*
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
 #ifndef GNTWS_H
 #define GNTWS_H
 
--- a/finch/libgnt/wms/irssi.c	Thu Jun 28 14:12:35 2007 +0000
+++ b/finch/libgnt/wms/irssi.c	Thu Jun 28 14:53:47 2007 +0000
@@ -274,17 +274,19 @@
 
 void gntwm_init(GntWM **wm)
 {
-	const char *style = NULL;
+	char *style = NULL;
 	Irssi *irssi;
 
 	irssi = g_object_new(TYPE_IRSSI, NULL);
 	*wm = GNT_WM(irssi);
 
-	style = gnt_style_get_from_name("irssi-split-v");
+	style = gnt_style_get_from_name("irssi", "split-v");
 	irssi->vert = style ? atoi(style) : 1;
+	g_free(style);
 
-	style = gnt_style_get_from_name("irssi-split-h");
+	style = gnt_style_get_from_name("irssi", "split-h");
 	irssi->horiz = style ? atoi(style) : 1;
+	g_free(style);
 
 	irssi->vert = MAX(irssi->vert, 1);
 	irssi->horiz = MAX(irssi->horiz, 1);
--- a/libpurple/Makefile.am	Thu Jun 28 14:12:35 2007 +0000
+++ b/libpurple/Makefile.am	Thu Jun 28 14:53:47 2007 +0000
@@ -157,10 +157,10 @@
 purple_build_coreheaders = $(addprefix $(srcdir)/, $(purple_coreheaders))
 dbus_build_exported = $(addprefix $(srcdir)/, $(dbus_exported))
 
-dbus-types.c: dbus-analyze-types.py $(purple_coreheaders)
+dbus-types.c: dbus-analyze-types.py $(purple_build_coreheaders)
 	cat $(purple_build_coreheaders) | $(PYTHON) $(srcdir)/dbus-analyze-types.py --pattern=PURPLE_DBUS_DEFINE_TYPE\(%s\) > $@
 
-dbus-types.h: dbus-analyze-types.py $(dbus_coreheaders)
+dbus-types.h: dbus-analyze-types.py $(purple_build_coreheaders)
 	cat $(purple_build_coreheaders) | $(PYTHON) $(srcdir)/dbus-analyze-types.py --pattern=PURPLE_DBUS_DECLARE_TYPE\(%s\) > $@
 
 dbus-bindings.c: dbus-analyze-functions.py $(dbus_exported)
--- a/libpurple/conversation.c	Thu Jun 28 14:12:35 2007 +0000
+++ b/libpurple/conversation.c	Thu Jun 28 14:53:47 2007 +0000
@@ -1563,6 +1563,7 @@
 				purple_conv_chat_is_user_ignored(chat, user);
 
 		cbuddy = purple_conv_chat_cb_new(user, alias, flag);
+		cbuddy->buddy = purple_find_buddy(conv->account, user) != NULL;
 		/* This seems dumb. Why should we set users thousands of times? */
 		purple_conv_chat_set_users(chat,
 				g_list_prepend(chat->in_room, cbuddy));
@@ -1631,11 +1632,6 @@
 	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
 	g_return_if_fail(prpl_info != NULL);
 
-	flags = purple_conv_chat_user_get_flags(chat, old_user);
-	cb = purple_conv_chat_cb_new(new_user, NULL, flags);
-	purple_conv_chat_set_users(chat,
-		g_list_prepend(chat->in_room, cb));
-
 	if (!strcmp(chat->nick, purple_normalize(conv->account, old_user))) {
 		const char *alias;
 
@@ -1659,6 +1655,12 @@
 			new_alias = purple_buddy_get_contact_alias(buddy);
 	}
 
+	flags = purple_conv_chat_user_get_flags(chat, old_user);
+	cb = purple_conv_chat_cb_new(new_user, new_alias, flags);
+	cb->buddy = purple_find_buddy(conv->account, new_user) != NULL;
+	purple_conv_chat_set_users(chat,
+		g_list_prepend(chat->in_room, cb));
+
 	if (ops != NULL && ops->chat_rename_user != NULL)
 		ops->chat_rename_user(conv, old_user, new_user, new_alias);
 
@@ -1949,6 +1951,7 @@
 
 	return chat->left;
 }
+
 PurpleConvChatBuddy *
 purple_conv_chat_cb_new(const char *name, const char *alias, PurpleConvChatBuddyFlags flags)
 {
--- a/libpurple/protocols/jabber/jabber.c	Thu Jun 28 14:12:35 2007 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Thu Jun 28 14:53:47 2007 +0000
@@ -1369,11 +1369,13 @@
 	field = purple_request_field_string_new("password1", _("Password"),
 			"", FALSE);
 	purple_request_field_string_set_masked(field, TRUE);
+	purple_request_field_set_required(field, TRUE);
 	purple_request_field_group_add_field(group, field);
 
 	field = purple_request_field_string_new("password2", _("Password (again)"),
 			"", FALSE);
 	purple_request_field_string_set_masked(field, TRUE);
+	purple_request_field_set_required(field, TRUE);
 	purple_request_field_group_add_field(group, field);
 
 	purple_request_fields(js->gc, _("Change XMPP Password"),
--- a/libpurple/protocols/jabber/presence.c	Thu Jun 28 14:12:35 2007 +0000
+++ b/libpurple/protocols/jabber/presence.c	Thu Jun 28 14:53:47 2007 +0000
@@ -565,7 +565,7 @@
 		}
 
 		if((found_jbr = jabber_buddy_find_resource(jb, NULL))) {
-			purple_prpl_got_user_status(js->gc->account, buddy_name, jabber_buddy_state_get_status_id(state), "priority", found_jbr->priority, found_jbr->status ? "message" : NULL, found_jbr->status, NULL);
+			purple_prpl_got_user_status(js->gc->account, buddy_name, jabber_buddy_state_get_status_id(found_jbr->state), "priority", found_jbr->priority, found_jbr->status ? "message" : NULL, found_jbr->status, NULL);
 		} else {
 			purple_prpl_got_user_status(js->gc->account, buddy_name, "offline", status ? "message" : NULL, status, NULL);
 		}
--- a/libpurple/protocols/oscar/libicq.c	Thu Jun 28 14:12:35 2007 +0000
+++ b/libpurple/protocols/oscar/libicq.c	Thu Jun 28 14:53:47 2007 +0000
@@ -32,7 +32,7 @@
 	OPT_PROTO_MAIL_CHECK | OPT_PROTO_IM_IMAGE,
 	NULL,					/* user_splits */
 	NULL,					/* protocol_options */
-	{"gif,jpeg,bmp,ico", 48, 48, 50, 50, 7168,
+	{"gif,jpeg,bmp,ico", 48, 48, 52, 64, 7168,
 		PURPLE_ICON_SCALE_SEND | PURPLE_ICON_SCALE_DISPLAY},	/* icon_spec */
 	oscar_list_icon_icq,		/* list_icon */
 	oscar_list_emblem,		/* list_emblems */
--- a/libpurple/request.c	Thu Jun 28 14:12:35 2007 +0000
+++ b/libpurple/request.c	Thu Jun 28 14:53:47 2007 +0000
@@ -150,7 +150,8 @@
 		switch (purple_request_field_get_type(field))
 		{
 			case PURPLE_REQUEST_FIELD_STRING:
-				if (purple_request_field_string_get_value(field) == NULL)
+				if (purple_request_field_string_get_value(field) == NULL ||
+				    *(purple_request_field_string_get_value(field)) == '\0')
 					return FALSE;
 
 				break;
--- a/pidgin/eggtrayicon.c	Thu Jun 28 14:12:35 2007 +0000
+++ b/pidgin/eggtrayicon.c	Thu Jun 28 14:53:47 2007 +0000
@@ -152,6 +152,26 @@
     }
 }
 
+static Display *
+egg_tray_icon_get_x_display(EggTrayIcon *icon)
+{
+  Display *xdisplay = NULL;
+
+#if GTK_CHECK_VERSION(2,1,0)
+  {
+    GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (icon));
+    if (!GDK_IS_DISPLAY (display))
+      display = gdk_display_get_default ();
+
+    xdisplay = GDK_DISPLAY_XDISPLAY (display);
+  }
+#else
+  xdisplay = gdk_display;
+#endif
+
+  return xdisplay;
+}
+
 static void
 egg_tray_icon_get_orientation_property (EggTrayIcon *icon)
 {
@@ -168,11 +188,10 @@
 
   g_return_if_fail(icon->manager_window != None);
 
-#if GTK_CHECK_VERSION(2,1,0)
-  xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
-#else
-  xdisplay = gdk_display;
-#endif
+  xdisplay = egg_tray_icon_get_x_display(icon);
+
+  if (xdisplay == NULL)
+    return;
 
   gdk_error_trap_push ();
   type = None;
@@ -321,11 +340,10 @@
   if (icon->manager_window != None)
     return;
 
-#if GTK_CHECK_VERSION(2,1,0)
-  xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
-#else
-  xdisplay = gdk_display;
-#endif
+  xdisplay = egg_tray_icon_get_x_display(icon);
+
+  if (xdisplay == NULL)
+    return;
 
   XGrabServer (xdisplay);
   
@@ -424,12 +442,15 @@
 
   make_transparent (widget, NULL);
 
+  xdisplay = egg_tray_icon_get_x_display(icon);
+
+  if (xdisplay == NULL)
+    return;
+
 #if GTK_CHECK_VERSION(2,1,0)
   screen = gdk_screen_get_number (gtk_widget_get_screen (widget));
-  xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget));
 #else
   screen = XScreenNumberOfScreen (DefaultScreenOfDisplay (gdk_display));
-  xdisplay = gdk_display;
 #endif
 
   /* Now see if there's a manager window around */
@@ -519,11 +540,10 @@
       XClientMessageEvent ev;
       Display *xdisplay;
 
-#if GTK_CHECK_VERSION(2,1,0)
-      xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
-#else
-      xdisplay = gdk_display;
-#endif
+      xdisplay = egg_tray_icon_get_x_display(icon);
+
+      if (xdisplay == NULL)
+        return;
 
       ev.type = ClientMessage;
       ev.window = (Window)gtk_plug_get_id (GTK_PLUG (icon));
--- a/pidgin/gtkblist.c	Thu Jun 28 14:12:35 2007 +0000
+++ b/pidgin/gtkblist.c	Thu Jun 28 14:53:47 2007 +0000
@@ -174,6 +174,7 @@
 
 static gboolean gtk_blist_window_state_cb(GtkWidget *w, GdkEventWindowState *event, gpointer data)
 {
+#if GTK_CHECK_VERSION(2,2,0)
 	if(event->changed_mask & GDK_WINDOW_STATE_WITHDRAWN) {
 		if(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN)
 			purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/list_visible", FALSE);
@@ -195,6 +196,28 @@
 		if (!(event->new_window_state & GDK_WINDOW_STATE_ICONIFIED))
 			pidgin_blist_refresh_timer(purple_get_blist());
 	}
+#else
+	/* At least gtk+ 2.0.6 does not properly set the change_mask when unsetting a
+	 * GdkWindowState flag. To work around, the window state will be explicitly
+	 * queried on these older versions of gtk+. See pidgin ticket #739.
+	 */
+	GdkWindowState new_window_state = gdk_window_get_state(G_OBJECT(gtkblist->window->window));
+
+	if(new_window_state & GDK_WINDOW_STATE_WITHDRAWN) {
+		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/list_visible", FALSE);
+	} else {
+		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/list_visible", TRUE);
+		pidgin_blist_refresh_timer(purple_get_blist());
+	}
+
+	if(new_window_state & GDK_WINDOW_STATE_MAXIMIZED)
+		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/list_maximized", TRUE);
+	else
+		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/list_maximized", FALSE);
+
+	if (!(new_window_state & GDK_WINDOW_STATE_ICONIFIED))
+		pidgin_blist_refresh_timer(purple_get_blist());
+#endif
 
 	return FALSE;
 }
@@ -3093,6 +3116,15 @@
 	} else if(PURPLE_BLIST_NODE_IS_BUDDY(node)) {
 		buddy = (PurpleBuddy*)node;
 		gtkbuddynode = node->ui_data;
+		p = purple_buddy_get_presence(buddy);
+		if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_MOBILE)) {
+			path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", 
+						"16", "mobile.png", NULL);
+			ret = gdk_pixbuf_new_from_file(path, NULL);
+			g_free(path);
+			return ret;
+		}
+
 		if (((struct _pidgin_blist_node*)(node->parent->ui_data))->contact_expanded)
 			return pidgin_create_prpl_icon(((PurpleBuddy*)node)->account, PIDGIN_PRPL_ICON_SMALL);
 	} else if(PURPLE_BLIST_NODE_IS_CHAT(node)) {
@@ -4888,10 +4920,17 @@
 	gboolean selected;
 	char group_count[12] = "";
 	char *mark, *esc;
+	PurpleBlistNode *selected_node = NULL;
+	GtkTreeIter iter;
 
 	group = (PurpleGroup*)gnode;
 	textcolor = gtkblist->treeview->style->fg[GTK_STATE_ACTIVE];
-	selected = gtkblist ? (gtkblist->selected_node == gnode) : FALSE;
+        
+	if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(gtkblist->treeview)), NULL, &iter)) {
+		gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), &iter,
+				NODE_COLUMN, &selected_node, -1);
+	}
+	selected = (gnode == selected_node);
 
 	if (!expanded) {
 		g_snprintf(group_count, sizeof(group_count), " (%d/%d)",
--- a/pidgin/gtkconv.c	Thu Jun 28 14:12:35 2007 +0000
+++ b/pidgin/gtkconv.c	Thu Jun 28 14:53:47 2007 +0000
@@ -256,19 +256,11 @@
 	 * negate it anyway.  --luke */
 	if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM)
 	{
-		if (w == gtkconv->imhtml) {
-			purple_prefs_set_int(PIDGIN_PREFS_ROOT "/conversations/im/default_width", allocation->width);
-			purple_prefs_set_int(PIDGIN_PREFS_ROOT "/conversations/im/default_height", allocation->height);
-		}
 		if (w == gtkconv->lower_hbox)
 			purple_prefs_set_int(PIDGIN_PREFS_ROOT "/conversations/im/entry_height", allocation->height);
 	}
 	else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT)
 	{
-		if (w == gtkconv->imhtml) {
-			purple_prefs_set_int(PIDGIN_PREFS_ROOT "/conversations/chat/default_width", allocation->width);
-			purple_prefs_set_int(PIDGIN_PREFS_ROOT "/conversations/chat/default_height", allocation->height);
-		}
 		if (w == gtkconv->lower_hbox)
 			purple_prefs_set_int(PIDGIN_PREFS_ROOT "/conversations/chat/entry_height", allocation->height);
 	}
@@ -347,15 +339,28 @@
 	}
 }
 
-static PurpleCmdRet
-clear_command_cb(PurpleConversation *conv,
-                 const char *cmd, char **args, char **error, void *data)
+static void clear_conversation_scrollback(PurpleConversation *conv)
 {
 	PidginConversation *gtkconv = NULL;
 
 	gtkconv = PIDGIN_CONVERSATION(conv);
 
 	gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml));
+}
+
+static PurpleCmdRet
+clear_command_cb(PurpleConversation *conv,
+                 const char *cmd, char **args, char **error, void *data)
+{
+	clear_conversation_scrollback(conv);
+	return PURPLE_CMD_STATUS_OK;
+}
+
+static PurpleCmdRet
+clearall_command_cb(PurpleConversation *conv,
+                 const char *cmd, char **args, char **error, void *data)
+{
+	purple_conversation_foreach(clear_conversation_scrollback);
 	return PURPLE_CMD_STATUS_OK;
 }
 
@@ -528,13 +533,6 @@
 
 	account = purple_conversation_get_account(conv);
 
-	if (!purple_account_is_connected(account))
-		return;
-
-	if ((purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) &&
-		purple_conv_chat_has_left(PURPLE_CONV_CHAT(conv)))
-		return;
-
 	if (check_for_and_do_command(conv)) {
 		if (gtkconv->entry_growing) {
 			reset_default_size(gtkconv);
@@ -544,6 +542,13 @@
 		return;
 	}
 
+	if ((purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) &&
+		purple_conv_chat_has_left(PURPLE_CONV_CHAT(conv)))
+		return;
+
+	if (!purple_account_is_connected(account))
+		return;
+
 	buf = gtk_imhtml_get_markup(GTK_IMHTML(gtkconv->entry));
 	clean = gtk_imhtml_get_text(GTK_IMHTML(gtkconv->entry), NULL, NULL);
 
@@ -1736,6 +1741,9 @@
 
 	gtk_tree_selection_select_path(GTK_TREE_SELECTION(
 			gtk_tree_view_get_selection(GTK_TREE_VIEW(gtkchat->list))), path);
+	gtk_tree_view_set_cursor(GTK_TREE_VIEW(gtkchat->list),
+							 path, NULL, FALSE); 
+	gtk_widget_grab_focus(GTK_WIDGET(gtkchat->list));
 
 	gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path);
 	gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHAT_USERS_NAME_COLUMN, &who, -1);
@@ -3671,7 +3679,7 @@
 	if (!strcmp(chat->nick, purple_normalize(conv->account, old_name != NULL ? old_name : name)))
 		is_me = TRUE;
 
-	is_buddy = (purple_find_buddy(conv->account, name) != NULL);
+	is_buddy = cb->buddy;
 
 	tmp = g_utf8_casefold(alias, -1);
 	alias_key = g_utf8_collate_key(tmp, -1);
@@ -3879,7 +3887,7 @@
 						   CHAT_USERS_ALIAS_COLUMN, &alias,
 						   -1);
 
-				if (strcmp(name, alias))
+				if (name && alias && strcmp(name, alias))
 					tab_complete_process_item(&most_matched, entered, &partial, nick_partial,
 										  &matches, FALSE, alias);
 				g_free(name);
@@ -4464,15 +4472,6 @@
 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(imhtml_sw),
 	                               imhtml_sw_hscroll, GTK_POLICY_ALWAYS);
 
-	gtk_widget_set_size_request(gtkconv->imhtml,
-			chat ? purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/chat/default_width") :
-			purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/im/default_width"),
-			chat ? purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/chat/default_height") :
-			purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/im/default_height"));
-
-	g_signal_connect(G_OBJECT(gtkconv->imhtml), "size-allocate",
-	                 G_CALLBACK(size_allocate_cb), gtkconv);
-
 	g_signal_connect_after(G_OBJECT(gtkconv->imhtml), "button_press_event",
 	                       G_CALLBACK(entry_stop_rclick_cb), NULL);
 	g_signal_connect(G_OBJECT(gtkconv->imhtml), "key_press_event",
@@ -5563,7 +5562,7 @@
 
 	g_return_if_fail(new_alias != NULL);
 
-	cbuddy = purple_conv_chat_cb_new(new_name, new_alias, flags);
+	cbuddy = purple_conv_chat_cb_find(chat, new_name);
 
 	add_chat_buddy_common(conv, cbuddy, old_name);
 }
@@ -6192,10 +6191,12 @@
 				markup = title;
 		} else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) {
 			PurpleConvChat *chat = PURPLE_CONV_CHAT(conv);
-			markup = g_strdup_printf("%s\n<span color='%s' size='smaller'>%s</span>",
+			const char *topic = purple_conv_chat_get_topic(chat);
+			markup = g_strdup_printf("%s%s<span color='%s' size='smaller'>%s</span>",
 						purple_conversation_get_title(conv),
+						topic ? "\n" : "",
 						pidgin_get_dim_grey_string(gtkconv->infopane),
-						purple_conv_chat_get_topic(chat));
+						topic ? topic : "");
 		}
 		gtk_list_store_set(gtkconv->infopane_model, &(gtkconv->infopane_iter),
 				TEXT_COLUMN, markup, -1);
@@ -7057,6 +7058,8 @@
 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/tabs", TRUE);
 	purple_prefs_add_int(PIDGIN_PREFS_ROOT "/conversations/tab_side", GTK_POS_TOP);
 	purple_prefs_add_int(PIDGIN_PREFS_ROOT "/conversations/scrollback_lines", 4000);
+	purple_prefs_add_int(PIDGIN_PREFS_ROOT "/conversations/x", 0);
+	purple_prefs_add_int(PIDGIN_PREFS_ROOT "/conversations/y", 0);
 
 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/use_theme_font", TRUE);
 	purple_prefs_add_string(PIDGIN_PREFS_ROOT "/conversations/custom_font", "");
@@ -7202,6 +7205,9 @@
 	purple_cmd_register("clear", "", PURPLE_CMD_P_DEFAULT,
 	                  PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM, NULL,
 	                  clear_command_cb, _("clear: Clears the conversation scrollback."), NULL);
+	purple_cmd_register("clearall", "", PURPLE_CMD_P_DEFAULT,
+	                  PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM, NULL,
+	                  clearall_command_cb, _("clear: Clears all conversation scrollbacks."), NULL);
 	purple_cmd_register("help", "w", PURPLE_CMD_P_DEFAULT,
 	                  PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, NULL,
 	                  help_command_cb, _("help &lt;command&gt;:  Help on a specific command."), NULL);
@@ -8203,6 +8209,44 @@
 	regenerate_plugins_items(data);
 }
 
+static gboolean gtk_conv_configure_cb(GtkWidget *w, GdkEventConfigure *event, gpointer data) {
+	int x, y;
+	
+	if (GTK_WIDGET_VISIBLE(w))
+		gtk_window_get_position(GTK_WINDOW(w), &x, &y);
+	else
+		return FALSE; /* carry on normally */
+
+	/* Workaround for GTK+ bug # 169811 - "configure_event" is fired
+	* when the window is being maximized */
+	if (gdk_window_get_state(w->window) & GDK_WINDOW_STATE_MAXIMIZED)
+		return FALSE;
+	
+	/* don't save if nothing changed */
+	if (x == purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/x") &&
+	    y == purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/y") &&
+	    event->width  == purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/im/default_width") &&
+	    event->height == purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/im/default_height"))
+		return FALSE; /* carry on normally */
+		
+	/* don't save off-screen positioning */
+	if (x + event->width < 0 ||
+	    y + event->height < 0 ||
+	    x > gdk_screen_width() ||
+	    y > gdk_screen_height())
+		return FALSE; /* carry on normally */
+
+        /* store the position */
+        purple_prefs_set_int(PIDGIN_PREFS_ROOT "/conversations/x",      x);
+	purple_prefs_set_int(PIDGIN_PREFS_ROOT "/conversations/y",      y);
+	purple_prefs_set_int(PIDGIN_PREFS_ROOT "/conversations/im/width",  event->width);
+	purple_prefs_set_int(PIDGIN_PREFS_ROOT "/conversations/im/height", event->height);
+
+	/* continue to handle event normally */
+	return FALSE;
+						
+}
+
 PidginWindow *
 pidgin_conv_window_new()
 {
@@ -8217,7 +8261,8 @@
 
 	/* Create the window. */
 	win->window = pidgin_create_window(NULL, 0, "conversation", TRUE);
-	GTK_WINDOW(win->window)->allow_shrink = TRUE;
+	gtk_window_set_default_size(GTK_WINDOW(win->window), purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/im/width"),
+							     purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/im/height"));
 
 	if (available_list == NULL) {
 		create_icon_lists(win->window);
@@ -8225,7 +8270,8 @@
 
 	g_signal_connect(G_OBJECT(win->window), "delete_event",
 	                 G_CALLBACK(close_win_cb), win);
-
+	g_signal_connect(G_OBJECT(win->window), "configure_event", 
+			 G_CALLBACK(gtk_conv_configure_cb), NULL);
 	g_signal_connect(G_OBJECT(win->window), "focus_in_event",
 	                 G_CALLBACK(focus_win_cb), win);
 
--- a/pidgin/gtkdialogs.c	Thu Jun 28 14:12:35 2007 +0000
+++ b/pidgin/gtkdialogs.c	Thu Jun 28 14:53:47 2007 +0000
@@ -165,7 +165,7 @@
 	{N_("Japanese"),            "ja", "Takashi Aihana", "aihana@gnome.gr.jp"},
 	{N_("Georgian"),            "ka", N_("Ubuntu Georgian Translators"), "alexander.didebulidze@stusta.mhn.de"},
 	{N_("Kannada"),             "kn", N_("Kannada Translation team"), "translation@sampada.info"},
-	{N_("Korean"),              "ko", "Kyung-uk Son", "vvs740@chol.com"},
+	{N_("Korean"),              "ko", "Sushizang", "sushizang@empal.com"},
 	{N_("Kurdish"),             "ku", "Erdal Ronahi", "erdal.ronahi@gmail.com"},
 	{N_("Kurdish"),             "ku", "Amed Ç. Jiyan", "amedcj@hotmail.com"},
 	{N_("Kurdish"),             "ku", "Rizoyê Xerzî", "rizoxerzi@hotmail.com"},
@@ -230,6 +230,7 @@
 	{N_("Japanese"),            "ja", "Junichi Uekawa", NULL},
 	{N_("Georgian"),            "ka", "Temuri Doghonadze", NULL},
 	{N_("Korean"),              "ko", "Sang-hyun S, A Ho-seok Lee", NULL},
+	{N_("Korean"),              "ko", "Kyeong-uk Son", "hey@gnome.or.kr"},
 	{N_("Lithuanian"),          "lt", "Andrius Štikonas", NULL},
 	{N_("Lithuanian"),          "lt", "Gediminas Čičinskas", NULL},
 	{N_("Macedonian"),          "mk", "Tomislav Markovski", "herrera@users.sf.net"},
--- a/pidgin/gtkimhtml.c	Thu Jun 28 14:12:35 2007 +0000
+++ b/pidgin/gtkimhtml.c	Thu Jun 28 14:53:47 2007 +0000
@@ -1002,11 +1002,12 @@
 		gtk_imhtml_close_tags(imhtml, &iter);
 
 	gtk_imhtml_insert_html_at_iter(imhtml, text, flags, &iter);
-	if (!imhtml->wbfo && !plaintext)
-		gtk_imhtml_close_tags(imhtml, &iter);
 	gtk_text_buffer_move_mark_by_name(imhtml->text_buffer, "insert", &iter);
 	gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(imhtml), gtk_text_buffer_get_insert(imhtml->text_buffer),
 	                             0, FALSE, 0.0, 0.0);
+	if (!imhtml->wbfo && !plaintext)
+		gtk_imhtml_close_tags(imhtml, &iter);
+
 }
 
 static void paste_plaintext_received_cb (GtkClipboard *clipboard, const gchar *text, gpointer data)
@@ -4938,9 +4939,6 @@
 
 	if (imhtml->edit.link)
 		gtk_imhtml_toggle_link(imhtml, NULL);
-
-	gtk_text_buffer_remove_all_tags(imhtml->text_buffer, iter, iter);
-
 }
 
 char *gtk_imhtml_get_markup(GtkIMHtml *imhtml)
--- a/pidgin/gtkutils.c	Thu Jun 28 14:12:35 2007 +0000
+++ b/pidgin/gtkutils.c	Thu Jun 28 14:53:47 2007 +0000
@@ -1147,6 +1147,9 @@
 	acc = gtk_widget_get_accessible (w);
 	label = gtk_widget_get_accessible (l);
 
+	/* Make sure mnemonics work */
+        gtk_label_set_mnemonic_widget(GTK_LABEL(l), w);
+	
 	/* If this object has no name, set it's name with the label text */
 	existing_name = atk_object_get_name (acc);
 	if (!existing_name) {
--- a/po/ChangeLog	Thu Jun 28 14:12:35 2007 +0000
+++ b/po/ChangeLog	Thu Jun 28 14:53:47 2007 +0000
@@ -1,5 +1,8 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
+version 2.1.0
+	* Korean translation updated (Sushizang)
+
 version 2.0.2
 	* Chinese (Traditional) translation updated (Ambrose C. Li)
 	* English (British) translation updated (Luke Ross)
--- a/po/ko.po	Thu Jun 28 14:12:35 2007 +0000
+++ b/po/ko.po	Thu Jun 28 14:53:47 2007 +0000
@@ -11,7 +11,7 @@
 "Project-Id-Version: gaim 2.0\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2005-10-27 16:12-0400\n"
-"PO-Revision-Date: 2007-05-07 09:18+0900\n"
+"PO-Revision-Date: 2007-06-28 10:48+0900\n"
 "Last-Translator: sushizang <sushizang@empal.com>\n"
 "Language-Team: GTP Korean <gnome-kr-translation@gnome.or.kr>\n"
 "MIME-Version: 1.0\n"
@@ -1388,18 +1388,34 @@
 msgid "Login Options"
 msgstr "로그인 설정"
 
-#: ../gtk/gtkaccount.c:492
-msgid "Local alias:"
-msgstr "별칭:"
+#: ../pidgin/gtkaccount.c:430
+msgid "Pro_tocol:"
+msgstr "프로토콜(_t):"
+
+#: ../pidgin/gtkaccount.c:441
+msgid "Screen _name:"
+msgstr "아이디(_n):"
+
+#: ../pidgin/gtkaccount.c:531
+msgid "_Local alias:"
+msgstr "별칭(_L):"
+
+#: ../pidgin/gtkaccount.c:535
+msgid "Remember pass_word"
+msgstr "비밀번호 저장"
 
 #. Build the user options frame.
 #: ../gtk/gtkaccount.c:554
 msgid "User Options"
 msgstr "사용자 설정"
 
+#: ../pidgin/gtkaccount.c:606
+msgid "New _mail notifications"
+msgstr "새 메일 알림"
+
 #. Buddy icon
-#: ../gtk/gtkaccount.c:572
-msgid "Use this buddy icon for this account:"
+#: ../pidgin/gtkaccount.c:611
+msgid "Use this buddy _icon for this account:"
 msgstr "다음 아이콘 사용:"
 
 #. Build the protocol options frame.
@@ -3906,6 +3922,22 @@
 msgid "F_lash window when IMs are received"
 msgstr "메시지를 받으면 창을 깜빡거림(_L)"
 
+#: ../pidgin/gtkprefs.c:943
+msgid "Font"
+msgstr "글꼴"
+
+#: ../pidgin/gtkprefs.c:945
+msgid "Use document font from _theme"
+msgstr "테마로부터 문서 글꼴 사용(_t)"
+
+#: ../pidgin/gtkprefs.c:947
+msgid "Use font from _theme"
+msgstr "테마로부터 글꼴 사용(_t)"
+
+#: ../pidgin/gtkprefs.c:949
+msgid "Conversation _font:"
+msgstr "대화창 글꼴(_f):"
+
 #: ../gtk/gtkprefs.c:925
 msgid "Default Formatting"
 msgstr "기본 서식"
@@ -4710,7 +4742,7 @@
 #. Not used yet.
 #: ../gtk/plugins/contact_priority.c:66
 msgid "Buddy is mobile"
-msgstr "이동 중인 친구"
+msgstr "휴대 기기 친구"
 
 #: ../gtk/plugins/contact_priority.c:68
 msgid "Buddy is offline"
@@ -9352,7 +9384,7 @@
 
 #: ../libgaim/protocols/msn/msn.c:291
 msgid "Set your mobile phone number."
-msgstr "이동 전화번호를 설정해 주십시오."
+msgstr "휴대 전화번호를 설정해 주십시오."
 
 #: ../libgaim/protocols/msn/msn.c:304
 msgid "Allow MSN Mobile pages?"
@@ -9360,7 +9392,7 @@
 
 #: ../libgaim/protocols/msn/msn.c:305
 msgid "Do you want to allow or disallow people on your buddy list to send you MSN Mobile pages to your cell phone or other mobile device?"
-msgstr "친구가 휴대 전화 등의 모바일 기기에 MSN 모바일 호출을 전송하는 것을 허가하시겠습니까?"
+msgstr "친구가 휴대 전화 등의 휴대용 기기에 MSN 모바일 호출을 전송하는 것을 허가하시겠습니까?"
 
 #: ../libgaim/protocols/msn/msn.c:309
 msgid "Allow"
@@ -9434,11 +9466,11 @@
 
 #: ../libgaim/protocols/msn/msn.c:638
 msgid "Enable/Disable Mobile Devices..."
-msgstr "모바일 기기 사용/사용 안 함..."
+msgstr "휴대용 기기 사용/사용 안 함..."
 
 #: ../libgaim/protocols/msn/msn.c:643
 msgid "Allow/Disallow Mobile Pages..."
-msgstr "모바일 호출 허가/허가 안 함..."
+msgstr "무선 호출 허가/허가 안 함..."
 
 #: ../libgaim/protocols/msn/msn.c:653
 msgid "Open Hotmail Inbox"
@@ -9446,7 +9478,7 @@
 
 #: ../libgaim/protocols/msn/msn.c:677
 msgid "Send to Mobile"
-msgstr "모바일 기기에 전송"
+msgstr "휴대용 기기에 전송"
 
 #: ../libgaim/protocols/msn/msn.c:687
 #: ../libgaim/protocols/novell/novell.c:3443
@@ -9563,11 +9595,11 @@
 
 #: ../libgaim/protocols/msn/msn.c:1602
 msgid "Home Phone"
-msgstr "자택 전화1"
+msgstr "자택 전화"
 
 #: ../libgaim/protocols/msn/msn.c:1603
 msgid "Home Phone 2"
-msgstr "자택 전화2"
+msgstr "자택 전화 2"
 
 #: ../libgaim/protocols/msn/msn.c:1604
 #: ../libgaim/protocols/oscar/oscar.c:3768
@@ -9576,7 +9608,7 @@
 
 #: ../libgaim/protocols/msn/msn.c:1605
 msgid "Personal Mobile"
-msgstr "휴대 전화"
+msgstr "개인 휴대 기기"
 
 #: ../libgaim/protocols/msn/msn.c:1606
 msgid "Home Fax"
@@ -9620,11 +9652,11 @@
 
 #: ../libgaim/protocols/msn/msn.c:1632
 msgid "Work Phone"
-msgstr "회사 전화1"
+msgstr "회사 전화"
 
 #: ../libgaim/protocols/msn/msn.c:1633
 msgid "Work Phone 2"
-msgstr "회사 전화2"
+msgstr "회사 전화 2"
 
 #: ../libgaim/protocols/msn/msn.c:1634
 #: ../libgaim/protocols/oscar/oscar.c:3781
@@ -9633,7 +9665,7 @@
 
 #: ../libgaim/protocols/msn/msn.c:1635
 msgid "Work Mobile"
-msgstr "회사 휴대 전화"
+msgstr "업무 휴대 기기"
 
 #: ../libgaim/protocols/msn/msn.c:1636
 msgid "Work Pager"
@@ -14816,7 +14848,7 @@
 
 #: ../libgaim/status.c:160
 msgid "Mobile"
-msgstr "이동 중"
+msgstr "휴대 기기"
 
 #: ../libgaim/status.c:611
 #, c-format