changeset 15794:15ed2cc560ce

merge of '781d0a4beb5fa7b8916127b6e322aa96419230ce' and 'cf9ae5cee9d8608b76627c90ea401cc5347486ca'
author Nathan Walp <nwalp@pidgin.im>
date Fri, 16 Mar 2007 00:02:55 +0000
parents 7ea06c408a0d (current diff) 9de8f4e810cb (diff)
children a26ffc69f81c
files
diffstat 37 files changed, 396 insertions(+), 121 deletions(-) [+]
line wrap: on
line diff
--- a/configure.ac	Fri Mar 16 00:02:19 2007 +0000
+++ b/configure.ac	Fri Mar 16 00:02:55 2007 +0000
@@ -1943,6 +1943,7 @@
 		   pidgin/pixmaps/toolbar/16/Makefile
 		   pidgin/pixmaps/toolbar/16/scalable/Makefile
 		   pidgin/pixmaps/tray/Makefile
+		   pidgin/pixmaps/tray/16/Makefile
 		   pidgin/pixmaps/tray/22/Makefile
 		   pidgin/plugins/Makefile
 		   pidgin/plugins/cap/Makefile
--- a/console/gntconv.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/console/gntconv.c	Fri Mar 16 00:02:55 2007 +0000
@@ -333,7 +333,6 @@
 	gnt_entry_set_always_suggest(GNT_ENTRY(ggc->entry), FALSE);
 
 	g_signal_connect_after(G_OBJECT(ggc->entry), "key_pressed", G_CALLBACK(entry_key_pressed), ggc);
-	g_signal_connect(G_OBJECT(ggc->entry), "text_changed", G_CALLBACK(send_typing_notification), ggc);
 	g_signal_connect(G_OBJECT(ggc->window), "destroy", G_CALLBACK(closing_window), ggc);
 
 	gnt_widget_set_position(ggc->window, gaim_prefs_get_int(PREF_ROOT "/position/x"),
@@ -343,10 +342,13 @@
 	g_signal_connect(G_OBJECT(ggc->tv), "size_changed", G_CALLBACK(size_changed_cb), NULL);
 	g_signal_connect(G_OBJECT(ggc->window), "position_set", G_CALLBACK(save_position_cb), NULL);
 
-	gaim_signal_connect(gaim_conversations_get_handle(), "buddy-typing", gg_conv_get_handle(),
-	                GAIM_CALLBACK(update_buddy_typing), NULL);
-	gaim_signal_connect(gaim_conversations_get_handle(), "buddy-typing-stopped", gg_conv_get_handle(),
-	                GAIM_CALLBACK(update_buddy_typing), NULL);
+	if (type == GAIM_CONV_TYPE_IM) {
+		g_signal_connect(G_OBJECT(ggc->entry), "text_changed", G_CALLBACK(send_typing_notification), ggc);
+		gaim_signal_connect(gaim_conversations_get_handle(), "buddy-typing", gg_conv_get_handle(),
+						GAIM_CALLBACK(update_buddy_typing), NULL);
+		gaim_signal_connect(gaim_conversations_get_handle(), "buddy-typing-stopped", gg_conv_get_handle(),
+						GAIM_CALLBACK(update_buddy_typing), NULL);
+	}
 
 	g_free(title);
 }
--- a/console/libgnt/gntbindable.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/console/libgnt/gntbindable.c	Fri Mar 16 00:02:55 2007 +0000
@@ -155,6 +155,7 @@
 
 	if (name == NULL || *name == '\0') {
 		g_hash_table_remove(klass->bindings, (char*)trigger);
+		gnt_keys_del_combination(trigger);
 		return;
 	}
 
@@ -171,6 +172,7 @@
 	param->action = action;
 	param->list = list;
 	g_hash_table_replace(klass->bindings, g_strdup(trigger), param);
+	gnt_keys_add_combination(trigger);
 }
 
 void gnt_bindable_register_binding(GntBindableClass *klass, const char *name,
--- a/console/libgnt/gntentry.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/console/libgnt/gntentry.c	Fri Mar 16 00:02:55 2007 +0000
@@ -302,15 +302,15 @@
 clipboard_paste(GntBindable *bind, GList *n)
 {
 	GntEntry *entry = GNT_ENTRY(bind);
-	gchar *i;
-	gchar *text = i = gnt_get_clipboard_string();
+	gchar *i, *text, *a, *all;
+	text = i = gnt_get_clipboard_string();
 	while (*i != '\0') {
 		i = g_utf8_next_char(i);
 		if (*i == '\r' || *i == '\n')
 			*i = ' ';
 	}
-	char *a = g_strndup(entry->start, entry->cursor - entry->start);
-	char *all = g_strconcat(a, text, entry->cursor, NULL);
+	a = g_strndup(entry->start, entry->cursor - entry->start);
+	all = g_strconcat(a, text, entry->cursor, NULL);
 	gnt_entry_set_text_internal(entry, all);
 	g_free(a);
 	g_free(text);
@@ -563,7 +563,7 @@
 				if (entry->end + len - entry->start >= entry->buffer)
 				{
 					/* This will cause the buffer to grow */
-					char *tmp = g_strdup_printf("%s%*s", entry->start, len, "");
+					char *tmp = g_strdup(entry->start);
 					gnt_entry_set_text_internal(entry, tmp);
 					g_free(tmp);
 				}
@@ -693,7 +693,7 @@
 				GNT_KEY_CTRL_DOWN, NULL);
 	gnt_bindable_class_register_action(bindable, "history-next", history_next,
 				GNT_KEY_CTRL_UP, NULL);
-	gnt_bindable_class_register_action(bindable, "clipboard-past", clipboard_paste,
+	gnt_bindable_class_register_action(bindable, "clipboard-paste", clipboard_paste,
 				GNT_KEY_CTRL_V, NULL);
 
 	gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass));
--- a/console/libgnt/gntkeys.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/console/libgnt/gntkeys.c	Fri Mar 16 00:02:55 2007 +0000
@@ -1,5 +1,6 @@
 #include "gntkeys.h"
 
+#include <glib.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -8,7 +9,6 @@
 char *gnt_key_cleft;
 char *gnt_key_cright;
 
-
 static const char *term;
 
 void gnt_init_keys()
@@ -34,7 +34,7 @@
 
 void gnt_keys_refine(char *text)
 {
-	if (*text == 27 && *(text + 1) == '[' && *(text + 3) == '\0' &&
+	if (*text == 27 && *(text + 1) == '[' &&
 			(*(text + 2) >= 'A' && *(text + 2) <= 'D')) {
 		/* Apparently this is necessary for urxvt and screen and xterm */
 		if (strcmp(term, "screen") == 0 || strcmp(term, "rxvt-unicode") == 0 ||
@@ -48,3 +48,108 @@
 	}
 }
 
+/**
+ * The key-bindings will be saved in a tree. When a keystroke happens, GNT will
+ * find the sequence that matches a binding and return the length.
+ * A sequence should not be a prefix of another sequence. If it is, then only
+ * the shortest one will be processed. If we want to change that, we will need
+ * to allow getting the k-th prefix that matches the input, and pay attention
+ * to the return value of gnt_wm_process_input in gntmain.c.
+ */
+#define SIZE 256
+
+#define IS_END         1 << 0
+struct _node
+{
+	struct _node *next[SIZE];
+	int ref;
+	int flags;
+};
+
+static struct _node root = {.ref = 1, .flags = 0};
+
+static void add_path(struct _node *node, const char *path)
+{
+	struct _node *n = NULL;
+	if (!path || !*path) {
+		node->flags |= IS_END;
+		return;
+	}
+	while (*path && node->next[*path]) {
+		node = node->next[*path];
+		node->ref++;
+		path++;
+	}
+	if (!*path)
+		return;
+	n = g_new0(struct _node, 1);
+	n->ref = 1;
+	node->next[*path++] = n;
+	add_path(n, path);
+}
+
+void gnt_keys_add_combination(const char *path)
+{
+	add_path(&root, path);
+}
+
+static void del_path(struct _node *node, const char *path)
+{
+	struct _node *next = NULL;
+
+	if (!*path)
+		return;
+	next = node->next[*path];
+	if (!next)
+		return;
+	del_path(next, path + 1);
+	next->ref--;
+	if (next->ref == 0) {
+		node->next[*path] = NULL;
+		g_free(next);
+	}
+}
+
+void gnt_keys_del_combination(const char *path)
+{
+	del_path(&root, path);
+}
+
+int gnt_keys_find_combination(const char *path)
+{
+	int depth = 0;
+	struct _node *n = &root;
+
+	while (*path && n->next[*path] && !(n->flags & IS_END)) {
+		if (g_utf8_find_next_char(path, NULL) - path > 1)
+			return 0;
+		n = n->next[*path++];
+		depth++;
+	}
+
+	if (!(n->flags & IS_END))
+		depth = 0;
+	return depth;
+}
+
+static void
+print_path(struct _node *node, int depth)
+{
+	int i;
+	for (i = 0; i < SIZE; i++) {
+		if (node->next[i]) {
+			g_printerr("%*c (%d:%d)\n", depth, i, node->next[i]->ref,
+						node->next[i]->flags);
+			print_path(node->next[i], depth + 1);
+		}
+	}
+}
+
+/* this is purely for debugging purposes. */
+void gnt_keys_print_combinations()
+{
+	g_printerr("--------\n");
+	print_path(&root, 1);
+	g_printerr("--------\n");
+}
+
--- a/console/libgnt/gntkeys.h	Fri Mar 16 00:02:19 2007 +0000
+++ b/console/libgnt/gntkeys.h	Fri Mar 16 00:02:55 2007 +0000
@@ -82,6 +82,10 @@
 void gnt_init_keys();
 void gnt_keys_refine(char *text);
 
+void gnt_keys_add_combination(const char *path);
+void gnt_keys_del_combination(const char *path);
+int gnt_keys_find_combination(const char *path);
+
 
 /* A lot of commonly used variable names are defined in <term.h>. 
  * #undef them to make life easier for everyone. */
--- a/console/libgnt/gntmain.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/console/libgnt/gntmain.c	Fri Mar 16 00:02:55 2007 +0000
@@ -51,6 +51,20 @@
 GntWM *wm;
 static GntClipboard *clipboard;
 
+#define HOLDING_ESCAPE  (escape_stuff.timer != 0)
+
+static struct {
+	int timer;
+} escape_stuff;
+
+static gboolean
+escape_timeout(gpointer data)
+{
+	gnt_wm_process_input(wm, "\033");
+	escape_stuff.timer = 0;
+	return FALSE;
+}
+
 /**
  * Mouse support:
  *  - bring a window on top if you click on its taskbar
@@ -180,7 +194,8 @@
 io_invoke(GIOChannel *source, GIOCondition cond, gpointer null)
 {
 	char keys[256];
-	int rd = read(STDIN_FILENO, keys, sizeof(keys) - 1);
+	int rd = read(STDIN_FILENO, keys + HOLDING_ESCAPE, sizeof(keys) - 1 - HOLDING_ESCAPE);
+	char *k;
 	if (rd < 0)
 	{
 		int ch = getch(); /* This should return ERR, but let's see what it really returns */
@@ -196,13 +211,38 @@
 		raise(SIGABRT);
 	}
 
+	rd += HOLDING_ESCAPE;
 	keys[rd] = 0;
-	gnt_keys_refine(keys);
-
 	if (mouse_enabled && detect_mouse_action(keys))
 		return TRUE;
-	
-	gnt_wm_process_input(wm, keys);
+
+	if (HOLDING_ESCAPE)
+		keys[0] = '\033';
+	k = keys;
+	while (rd) {
+		char back;
+		int p;
+
+		if (k[0] == '\033' && rd == 1) {
+			if (escape_stuff.timer) {
+				gnt_wm_process_input(wm, "\033\033");
+				g_source_remove(escape_stuff.timer);
+				escape_stuff.timer = 0;
+				break;
+			}
+			escape_stuff.timer = g_timeout_add(250, escape_timeout, NULL);
+			break;
+		}
+
+		gnt_keys_refine(k);
+		p = MAX(1, gnt_keys_find_combination(k));
+		back = k[p];
+		k[p] = '\0';
+		gnt_wm_process_input(wm, k);     /* XXX: */
+		k[p] = back;
+		rd -= p;
+		k += p;
+	}
 
 	return TRUE;
 }
@@ -212,6 +252,7 @@
 {
 	int result;
 	channel = g_io_channel_unix_new(STDIN_FILENO);
+	g_io_channel_set_close_on_unref(channel, TRUE);
 
 #if 0
 	g_io_channel_set_encoding(channel, NULL, NULL);
--- a/console/libgnt/gnttextview.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/console/libgnt/gnttextview.c	Fri Mar 16 00:02:55 2007 +0000
@@ -69,13 +69,17 @@
 				(select_end <= view->string->str + seg->end && select_start <= view->string->str + seg->start))) {
 				char *cur = view->string->str + seg->start;
 				while (*cur != '\0') {
+					gchar *last = g_utf8_next_char(cur);
+					gchar *str;
 					if (cur >= select_start && cur <= select_end)
 						fl |= A_REVERSE;
 					else
 						fl = seg->flags;
+					str = g_strndup(cur, last - cur);
 					wattrset(widget->window, fl);
-					waddch(widget->window, *cur);
-					cur++;
+					waddstr(widget->window, str);
+					g_free(str);
+					cur = g_utf8_next_char(cur);
 				}
 			} else {
 				wattrset(widget->window, fl);
@@ -187,31 +191,43 @@
 static char *
 gnt_text_view_get_p(GntTextView *view, int x, int y)
 {
-	int i;
+	int i = 0;
 	GntWidget *wid = GNT_WIDGET(view);
 	GntTextLine *line;
 	GList *lines;
 	GList *segs;
 	GntTextSegment *seg;
+	gchar *pos;
 
 	y = wid->priv.height - y;
 	if (g_list_length(view->list) < y) {
 		x = 0;
-		y = g_list_length(view->list);
+		y = g_list_length(view->list) - 1;
 	}
 
 	lines = g_list_nth(view->list, y - 1);
+	if (!lines)
+		return NULL;
 	do {
 		line = lines->data;
 		lines = lines->next;
-	} while (line && !line->segments);
+	} while (line && !line->segments && lines);
 
-	if (!line) /* no valid line */
+	if (!line || !line->segments) /* no valid line */
 		return NULL;
 	segs = line->segments;
 	seg = (GntTextSegment *)segs->data;
-	i = 0;
-	return view->string->str + seg->start + MIN(x, line->length);
+	pos = view->string->str + seg->start;
+	x = MIN(x, line->length);
+	while (++i <= x) {
+		gunichar *u;
+		pos = g_utf8_next_char(pos);
+		u = g_utf8_to_ucs4(pos, -1, NULL, NULL, NULL);
+		if (u && g_unichar_iswide_cjk(*u))
+			i++;
+		g_free(u);
+	}
+	return pos;
 }
 
 static GString *
@@ -219,7 +235,7 @@
 {
 	gchar *start = c;
 	gchar *end = c;
-	gchar *t;
+	gchar *t, *endsize;
 	while (t = g_utf8_prev_char(start)) {
 		if (!g_ascii_isspace(*t)) {
 			if (start == view->string->str)
@@ -236,7 +252,8 @@
 	}
 	select_start = start;
 	select_end = end;
-	return g_string_new_len(start, end - start + 1);
+	endsize = g_utf8_next_char(select_end); /* End at the correct byte */
+	return g_string_new_len(start, endsize - start);
 }
 
 static gboolean too_slow(gpointer n)
@@ -276,7 +293,8 @@
 					return;
 				}
 			} else {
-				clip = g_string_new_len(select_start, select_end - select_start + 1);
+				gchar *endsize = g_utf8_next_char(select_end); /* End at the correct byte */
+				clip = g_string_new_len(select_start, endsize - select_start);
 			}
 			gnt_widget_draw(widget);
 			gnt_set_clipboard_string(clip->str);
--- a/console/libgnt/gntwidget.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/console/libgnt/gntwidget.c	Fri Mar 16 00:02:55 2007 +0000
@@ -357,7 +357,7 @@
 			g_signal_emit(widget, signals[SIG_SIZE_CHANGED], 0, oldw, oldh);
 		}
 #else
-		widget->window = newpad(150, 350);  /* XXX: */
+		widget->window = newpad(widget->priv.height + 20, widget->priv.width + 20);  /* XXX: */
 #endif
 		init_widget(widget);
 	}
@@ -520,6 +520,10 @@
 
 		widget->priv.width = width;
 		widget->priv.height = height;
+		if (width >= getmaxx(widget->window) || height >= getmaxy(widget->window)) {
+			delwin(widget->window);
+			widget->window = newpad(height + 20, width + 20);
+		}
 
 		g_signal_emit(widget, signals[SIG_SIZE_CHANGED], 0, oldw, oldh);
 
@@ -581,7 +585,8 @@
 
 	if (!g_object_get_data(G_OBJECT(widget), "gnt:queue_update"))
 		return FALSE;
-	gnt_screen_update(widget);
+	if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_MAPPED))
+		gnt_screen_update(widget);
 	g_object_set_data(G_OBJECT(widget), "gnt:queue_update", NULL);
 	return FALSE;
 }
--- a/console/libgnt/gntwm.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/console/libgnt/gntwm.c	Fri Mar 16 00:02:55 2007 +0000
@@ -875,6 +875,8 @@
 static void
 gnt_wm_class_init(GntWMClass *klass)
 {
+	int i;
+
 	klass->new_window = gnt_wm_new_window_real;
 	klass->decorate_window = NULL;
 	klass->close_window = NULL;
@@ -1004,6 +1006,14 @@
 				"\033" GNT_KEY_CTRL_K, NULL);
 
 	gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass));
+
+	/* Make sure Alt+x are detected properly. */
+	for (i = '0'; i <= '9'; i++) {
+		char str[] = "\033X";
+		str[1] = i;
+		gnt_keys_add_combination(str);
+	}
+
 	GNTDEBUG;
 }
 
@@ -1209,14 +1219,16 @@
 	return time(NULL) - last_active_time;
 }
 
-void gnt_wm_process_input(GntWM *wm, const char *keys)
+gboolean gnt_wm_process_input(GntWM *wm, const char *keys)
 {
+	gboolean ret = FALSE;
+
 	keys = gnt_bindable_remap_keys(GNT_BINDABLE(wm), keys);
 
 	idle_update = TRUE;
 
 	if (gnt_bindable_perform_action_key(GNT_BINDABLE(wm), keys))
-		return;
+		return TRUE;
 
 	/* Do some manual checking */
 	if (wm->ordered && wm->mode != GNT_KP_MODE_NORMAL) {
@@ -1247,7 +1259,7 @@
 			if (ox != x || oy != y) {
 				gnt_screen_move_widget(widget, x, y);
 				window_reverse(widget, TRUE, wm);
-				return;
+				return TRUE;
 			}
 		} else if (wm->mode == GNT_KP_MODE_RESIZE) {
 			if (strcmp(keys, GNT_KEY_LEFT) == 0) {
@@ -1264,14 +1276,14 @@
 			if (oh != h || ow != w) {
 				gnt_screen_resize_widget(widget, w, h);
 				window_reverse(widget, TRUE, wm);
-				return;
+				return TRUE;
 			}
 		}
 		if (strcmp(keys, "\r") == 0 || strcmp(keys, "\033") == 0) {
 			window_reverse(widget, FALSE, wm);
 			wm->mode = GNT_KP_MODE_NORMAL;
 		}
-		return;
+		return TRUE;
 	}
 
 	wm->event_stack = TRUE;
@@ -1281,7 +1293,7 @@
 		if (wm->_list.window) {
 			gnt_widget_destroy(wm->_list.window);
 			wm->event_stack = FALSE;
-			return;
+			return TRUE;
 		}
 	} else if (keys[0] == '\033' && isdigit(keys[1]) && keys[2] == '\0') {
 		/* Alt+x for quick switch */
@@ -1294,16 +1306,17 @@
 		list = g_list_append(list, GINT_TO_POINTER(n - 1));
 		switch_window_n(GNT_BINDABLE(wm), list);
 		g_list_free(list);
-		return;
+		return TRUE;
 	}
 
 	if (wm->menu)
-		gnt_widget_key_pressed(GNT_WIDGET(wm->menu), keys);
+		ret = gnt_widget_key_pressed(GNT_WIDGET(wm->menu), keys);
 	else if (wm->_list.window)
-		gnt_widget_key_pressed(wm->_list.window, keys);
+		ret = gnt_widget_key_pressed(wm->_list.window, keys);
 	else if (wm->ordered)
-		gnt_widget_key_pressed(GNT_WIDGET(wm->ordered->data), keys);
+		ret = gnt_widget_key_pressed(GNT_WIDGET(wm->ordered->data), keys);
 	wm->event_stack = FALSE;
+	return ret;
 }
 
 static void
@@ -1476,8 +1489,8 @@
 
 gboolean gnt_wm_process_click(GntWM *wm, GntMouseEvent event, int x, int y, GntWidget *widget)
 {
+	gboolean ret = TRUE;
 	idle_update = TRUE;
-	gboolean ret = TRUE;
 	g_signal_emit(wm, signals[SIG_MOUSE_CLICK], 0, event, x, y, widget, &ret);
 	return ret;
 }
--- a/console/libgnt/gntwm.h	Fri Mar 16 00:02:19 2007 +0000
+++ b/console/libgnt/gntwm.h	Fri Mar 16 00:02:55 2007 +0000
@@ -151,7 +151,7 @@
 
 void gnt_wm_window_close(GntWM *wm, GntWidget *widget);
 
-void gnt_wm_process_input(GntWM *wm, const char *string);
+gboolean gnt_wm_process_input(GntWM *wm, const char *string);
 
 gboolean gnt_wm_process_click(GntWM *wm, GntMouseEvent event, int x, int y, GntWidget *widget);
 
--- a/console/libgnt/test/tv.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/console/libgnt/test/tv.c	Fri Mar 16 00:02:55 2007 +0000
@@ -83,6 +83,7 @@
 	gnt_entry_set_history_length(GNT_ENTRY(entry), -1);
 	g_signal_connect_after(G_OBJECT(entry), "key_pressed", G_CALLBACK(key_pressed), view);
 
+	gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "\n", GNT_TEXT_FLAG_NORMAL);
 	gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "plugins: ", GNT_TEXT_FLAG_BOLD);
 	gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), "this is the 1st line\n", GNT_TEXT_FLAG_NORMAL);
 
--- a/console/libgnt/wms/s.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/console/libgnt/wms/s.c	Fri Mar 16 00:02:55 2007 +0000
@@ -182,7 +182,7 @@
 	text = gnt_get_clipboard_string();
 	clip = gnt_hwindow_new(FALSE);
 	GNT_WIDGET_SET_FLAGS(clip, GNT_WIDGET_TRANSIENT);
-	GNT_WIDGET_UNSET_FLAGS(clip, GNT_WIDGET_NO_BORDER);
+	GNT_WIDGET_SET_FLAGS(clip, GNT_WIDGET_NO_BORDER);
 	gnt_box_set_pad(GNT_BOX(clip), 0);
 	gnt_box_add_widget(GNT_BOX(clip), gnt_label_new(" "));
 	gnt_box_add_widget(GNT_BOX(clip), gnt_label_new(text));
--- a/console/plugins/gntclipboard.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/console/plugins/gntclipboard.c	Fri Mar 16 00:02:55 2007 +0000
@@ -30,6 +30,9 @@
 #include <X11/Xatom.h>
 #endif
 
+#include <sys/types.h>
+#include <signal.h>
+
 #include <glib.h>
 
 #include <plugin.h>
@@ -39,11 +42,11 @@
 
 #include <gntplugin.h>
 
-static gboolean stop = FALSE;
+static pid_t child = 0;
 
 static gulong sig_handle;
 
-static gpointer *
+static void
 set_clip(gchar *string)
 {
 #ifdef HAVE_X11
@@ -54,16 +57,16 @@
 	Display *dpy = XOpenDisplay(NULL);
 
 	if (!dpy)
-		return NULL;
+		return;
 	ids = getenv("WINDOWID");
 	if (ids == NULL)
-		return NULL;
+		return;
 	w = atoi(ids);
 	XSetSelectionOwner(dpy, XA_PRIMARY, w, CurrentTime);
 	XFlush(dpy);
 	XSelectInput(dpy, w, StructureNotifyMask);
-	while (!stop) {
-		XNextEvent(dpy, &e);
+	while (TRUE) {
+		XNextEvent(dpy, &e); /* this blocks. */
 		req = &e.xselectionrequest;
 		if (e.type == SelectionRequest) {
 			XChangeProperty(dpy,
@@ -83,33 +86,38 @@
 			XSendEvent(dpy, req->requestor, 0, 0, &respond);
 			XFlush (dpy);
 		} else if (e.type == SelectionClear) {
-			return NULL;
+			return;
 		}
 	}
 #endif
-	return NULL;
+	return;
 }
 
 static void
 clipboard_changed(GntWM *wm, gchar *string)
 {
 #ifdef HAVE_X11
-	static GThread *thread = NULL;
-	if (thread) {
-		stop = TRUE;
-		thread = g_thread_join(thread);
+	if (child) {
+		kill(child, SIGTERM);
 	}
-	g_thread_create((GThreadFunc)set_clip, string, TRUE, NULL);
+	if ((child = fork() == 0)) {
+		set_clip(string);
+		_exit(0);
+	}
 #endif
 }
 
 static gboolean
 plugin_load(GaimPlugin *plugin)
 {
-	if (!XOpenDisplay(NULL))
+	if (!XOpenDisplay(NULL)) {
 		gaim_debug_warning("gntclipboard", "Couldn't find X display\n");
-	if (!getenv("WINDOWID"))
+		return FALSE;
+	}
+	if (!getenv("WINDOWID")) {
 		gaim_debug_warning("gntclipboard", "Couldn't find window\n");
+		return FALSE;
+	}
 	sig_handle = g_signal_connect(G_OBJECT(gnt_get_clipboard()), "clipboard_changed", G_CALLBACK(clipboard_changed), NULL);
 	return TRUE;
 }
@@ -117,6 +125,10 @@
 static gboolean
 plugin_unload(GaimPlugin *plugin)
 {
+	if (child) {
+		kill(child, SIGTERM);
+		child = 0;
+	}
 	g_signal_handler_disconnect(G_OBJECT(gnt_get_clipboard()), sig_handle);
 	return TRUE;
 }
@@ -151,7 +163,6 @@
 static void
 init_plugin(GaimPlugin *plugin)
 {
-	g_thread_init(NULL);
 }
 
 GAIM_INIT_PLUGIN(PLUGIN_STATIC_NAME, init_plugin, info)
--- a/libpurple/connection.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/libpurple/connection.c	Fri Mar 16 00:02:55 2007 +0000
@@ -434,7 +434,11 @@
 	GaimConnectionUiOps *ops;
 
 	g_return_if_fail(gc   != NULL);
-	g_return_if_fail(text != NULL);
+
+	if (text != NULL) {
+		g_critical("gaim_connection_error: check `text != NULL' failed");
+		text = _("Unknown error");
+	}
 
 	/* If we've already got one error, we don't need any more */
 	if (gc->disconnect_timeout)
--- a/libpurple/plugins/ssl/ssl-gnutls.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/libpurple/plugins/ssl/ssl-gnutls.c	Fri Mar 16 00:02:55 2007 +0000
@@ -83,7 +83,8 @@
 	gnutls_data->handshake_handler = 0;
 
 	if(ret != 0) {
-		gaim_debug_error("gnutls", "Handshake failed. Error %d\n", ret);
+		gaim_debug_error("gnutls", "Handshake failed. Error %s\n",
+			gnutls_strerror(ret));
 
 		if(gsc->error_cb != NULL)
 			gsc->error_cb(gsc, GAIM_SSL_HANDSHAKE_FAILED,
@@ -156,8 +157,16 @@
 		s = -1;
 		errno = EAGAIN;
 	} else if(s < 0) {
-		gaim_debug_error("gnutls", "receive failed: %d\n", s);
-		s = 0;
+		gaim_debug_error("gnutls", "receive failed: %s\n",
+				gnutls_strerror(s));
+		s = -1;
+		/*
+		 * TODO: Set errno to something more appropriate.  Or even
+		 *       better: allow ssl plugins to keep track of their
+		 *       own error message, then add a new ssl_ops function
+		 *       that returns the error message.
+		 */
+		errno = EIO;
 	}
 
 	return s;
@@ -177,8 +186,16 @@
 		s = -1;
 		errno = EAGAIN;
 	} else if(s < 0) {
-		gaim_debug_error("gnutls", "send failed: %d\n", s);
-		s = 0;
+		gaim_debug_error("gnutls", "send failed: %s\n",
+				gnutls_strerror(s));
+		s = -1;
+		/*
+		 * TODO: Set errno to something more appropriate.  Or even
+		 *       better: allow ssl plugins to keep track of their
+		 *       own error message, then add a new ssl_ops function
+		 *       that returns the error message.
+		 */
+		errno = EIO;
 	}
 
 	return s;
--- a/libpurple/protocols/jabber/roster.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/libpurple/protocols/jabber/roster.c	Fri Mar 16 00:02:55 2007 +0000
@@ -380,7 +380,7 @@
 	GSList *groups = NULL;
 
 	buddies = g_slist_remove(buddies, buddy);
-	if(g_slist_length(buddies)) {
+	if(buddies != NULL) {
 		GaimBuddy *tmpbuddy;
 		GaimGroup *tmpgroup;
 
--- a/libpurple/protocols/jabber/si.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/libpurple/protocols/jabber/si.c	Fri Mar 16 00:02:55 2007 +0000
@@ -783,7 +783,7 @@
 			return;
 
 		/* XXX: for now, send to the first resource available */
-		if(g_list_length(jb->resources) >= 1) {
+		if(jb->resources != NULL) {
 			char **who_v = g_strsplit(xfer->who, "/", 2);
 			char *who;
 
--- a/libpurple/protocols/msn/msn-utils.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/libpurple/protocols/msn/msn-utils.c	Fri Mar 16 00:02:55 2007 +0000
@@ -174,6 +174,11 @@
 	char fonteffect[4];
 	char fontcolor[7];
 
+	gboolean has_bold = FALSE;
+	gboolean has_italic = FALSE;
+	gboolean has_underline = FALSE;
+	gboolean has_strikethrough = FALSE;
+
 	g_return_if_fail(html       != NULL);
 	g_return_if_fail(attributes != NULL);
 	g_return_if_fail(message    != NULL);
@@ -197,22 +202,38 @@
 			}
 			else if (!g_ascii_strncasecmp(c + 1, "i>", 2))
 			{
-				strcat(fonteffect, "I");
+				if (!has_italic)
+				{
+					strcat(fonteffect, "I");
+					has_italic = TRUE;
+				}
 				c += 3;
 			}
 			else if (!g_ascii_strncasecmp(c + 1, "b>", 2))
 			{
-				strcat(fonteffect, "B");
+				if (!has_bold)
+				{
+					strcat(fonteffect, "B");
+					has_bold = TRUE;
+				}
 				c += 3;
 			}
 			else if (!g_ascii_strncasecmp(c + 1, "u>", 2))
 			{
-				strcat(fonteffect, "U");
+				if (!has_underline)
+				{
+					strcat(fonteffect, "U");
+					has_underline = TRUE;
+				}
 				c += 3;
 			}
 			else if (!g_ascii_strncasecmp(c + 1, "s>", 2))
 			{
-				strcat(fonteffect, "S");
+				if (!has_strikethrough)
+				{
+					strcat(fonteffect, "S");
+					has_strikethrough = TRUE;
+				}
 				c += 3;
 			}
 			else if (!g_ascii_strncasecmp(c + 1, "a href=\"", 8))
--- a/libpurple/protocols/novell/nmuser.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/libpurple/protocols/novell/nmuser.c	Fri Mar 16 00:02:55 2007 +0000
@@ -1534,13 +1534,12 @@
 		}
 
 		/* Time to callback? */
-		if (g_slist_length(list) == 0) {
+		if (list == NULL) {
 			nm_response_cb cb = nm_request_get_callback(request);
 
 			if (cb) {
 				cb(user, 0, conference, conference);
 			}
-			g_slist_free(list);
 			nm_release_request(request);
 		}
 	}
--- a/libpurple/protocols/oscar/oscar.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Fri Mar 16 00:02:55 2007 +0000
@@ -1357,8 +1357,8 @@
 			gaim_connection_error(gc, _("Authentication failed"));
 			break;
 		}
-		gaim_debug_error("oscar", "Login Error Code 0x%04hx\n", info->errorcode);
-		gaim_debug_error("oscar", "Error URL: %s\n", info->errorurl);
+		gaim_debug_info("oscar", "Login Error Code 0x%04hx\n", info->errorcode);
+		gaim_debug_info("oscar", "Error URL: %s\n", info->errorurl);
 		od->killme = TRUE;
 		return 1;
 	}
--- a/libpurple/util.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/libpurple/util.c	Fri Mar 16 00:02:55 2007 +0000
@@ -3217,7 +3217,7 @@
 		gaim_input_remove(gfud->inpa);
 		gfud->inpa = 0;
 		close(gfud->fd);
-		gfud->fd = 0;
+		gfud->fd = -1;
 
 		g_free(gfud->website.user);
 		g_free(gfud->website.passwd);
--- a/pidgin/gaimstock.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/pidgin/gaimstock.c	Fri Mar 16 00:02:55 2007 +0000
@@ -166,13 +166,13 @@
 	{ PIDGIN_STOCK_TOOLBAR_TYPING, "toolbar", "typing.png", TRUE, FALSE, FALSE, FALSE, FALSE, FALSE },
 	{ PIDGIN_STOCK_TOOLBAR_PENDING, "status", "message-pending.png", TRUE, FALSE, FALSE, FALSE, FALSE, FALSE },
 	
-	{ PIDGIN_STOCK_TRAY_AVAILABLE, "tray", "tray-online.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE },
-	{ PIDGIN_STOCK_TRAY_AWAY, "tray", "tray-away.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE },
-	{ PIDGIN_STOCK_TRAY_BUSY, "tray", "tray-busy.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE },
-	{ PIDGIN_STOCK_TRAY_XA, "tray", "tray-extended-away.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE },
-	{ PIDGIN_STOCK_TRAY_OFFLINE, "tray", "tray-offline.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE },
-	{ PIDGIN_STOCK_TRAY_CONNECT, "tray", "tray-connecting.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE },
-	{ PIDGIN_STOCK_TRAY_PENDING, "tray", "tray-message.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE }
+	{ PIDGIN_STOCK_TRAY_AVAILABLE, "tray", "tray-online.png", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE },
+	{ PIDGIN_STOCK_TRAY_AWAY, "tray", "tray-away.png", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE },
+	{ PIDGIN_STOCK_TRAY_BUSY, "tray", "tray-busy.png", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE },
+	{ PIDGIN_STOCK_TRAY_XA, "tray", "tray-extended-away.png", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE },
+	{ PIDGIN_STOCK_TRAY_OFFLINE, "tray", "tray-offline.png", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE },
+	{ PIDGIN_STOCK_TRAY_CONNECT, "tray", "tray-connecting.png", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE },
+	{ PIDGIN_STOCK_TRAY_PENDING, "tray", "tray-message.png", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE }
 };
 
 static gchar *
--- a/pidgin/gtkdocklet-x11.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/pidgin/gtkdocklet-x11.c	Fri Mar 16 00:02:55 2007 +0000
@@ -40,6 +40,8 @@
 static GtkTooltips *tooltips = NULL;
 static GdkPixbuf *blank_icon = NULL;
 static int embed_timeout = 0;
+static DockletStatus icon_status = 0;
+static int docklet_height = 0;
 
 /* protos */
 static void docklet_x11_create(void);
@@ -115,37 +117,25 @@
 			break;
 	}
 
-	if(icon_name)
-		gtk_image_set_from_stock(GTK_IMAGE(image), icon_name, gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_SMALL));
-
-#if 0
-	GdkPixbuf *p;
-	GdkBitmap *mask = NULL;
-
-	p = gtk_widget_render_icon(GTK_WIDGET(image), icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR, NULL);
-
-	if (p && (gdk_pixbuf_get_colorspace(p) == GDK_COLORSPACE_RGB) && (gdk_pixbuf_get_bits_per_sample(p) == 8)
-	   && (gdk_pixbuf_get_has_alpha(p)) && (gdk_pixbuf_get_n_channels(p) == 4)) {
-		int len = gdk_pixbuf_get_width(p) * gdk_pixbuf_get_height(p);
-		guchar *data = gdk_pixbuf_get_pixels(p);
-		guchar *bitmap = g_malloc((len / 8) + 1);
-		int i;
+	if(icon_name) {
+		int icon_size;
+		if (docklet_height < 22)
+			icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL);
+		else
+			icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_SMALL);
 
-		for (i = 0; i < len; i++)
-			if (data[i*4 + 3] > 55)
-				bitmap[i/8] |= 1 << i % 8;
-			else
-				bitmap[i/8] &= ~(1 << i % 8);
+		gtk_image_set_from_stock(GTK_IMAGE(image), icon_name, icon_size);
+	}
+	icon_status = icon;
+}
 
-		mask = gdk_bitmap_create_from_data(GDK_DRAWABLE(GTK_WIDGET(image)->window), bitmap, gdk_pixbuf_get_width(p), gdk_pixbuf_get_height(p));
-		g_free(bitmap);
-	}
-
-	if (mask)
-		gdk_window_shape_combine_mask(image->window, mask, 0, 0);
-
-	g_object_unref(G_OBJECT(p));
-#endif
+static void
+docklet_x11_resize_icon(GtkWidget *widget)
+{
+	if (docklet_height == widget->allocation.height)
+		return;
+	docklet_height = widget->allocation.height;
+	docklet_x11_update_icon(icon_status);
 }
 
 static void
@@ -263,8 +253,8 @@
 
 	g_signal_connect(G_OBJECT(docklet), "embedded", G_CALLBACK(docklet_x11_embedded_cb), NULL);
 	g_signal_connect(G_OBJECT(docklet), "destroy", G_CALLBACK(docklet_x11_destroyed_cb), NULL);
+	g_signal_connect(G_OBJECT(docklet), "size-allocate", G_CALLBACK(docklet_x11_resize_icon), NULL);
 	g_signal_connect(G_OBJECT(box), "button-release-event", G_CALLBACK(docklet_x11_clicked_cb), NULL);
-
 	gtk_container_add(GTK_CONTAINER(box), image);
 	gtk_container_add(GTK_CONTAINER(docklet), box);
 
--- a/pidgin/gtkimhtmltoolbar.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/pidgin/gtkimhtmltoolbar.c	Fri Mar 16 00:02:55 2007 +0000
@@ -672,7 +672,7 @@
 	gtk_window_set_role(GTK_WINDOW(dialog), "smiley_dialog");
 	gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE);
 
-	if (g_slist_length(unique_smileys)) {
+	if (unique_smileys != NULL) {
 		struct smiley_button_list *ls, *it, *it_tmp;
 		GtkWidget *line;
 		int line_width = 0;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/pixmaps/tray/16/Makefile.am	Fri Mar 16 00:02:55 2007 +0000
@@ -0,0 +1,18 @@
+TRAY_ICONS =	tray-away.png \
+		tray-busy.png \
+		tray-connecting.png \
+		tray-extended-away.png \
+		tray-message.png \
+		tray-offline.png \
+		tray-online.png
+
+EXTRA_DIST = 	tray-away.ico \
+		tray-busy.ico \
+		tray-connecting.ico \
+		tray-extended-away.ico \
+		tray-message.ico \
+		tray-offline.ico \
+		tray-online.ico 
+
+pidgintraypixdir = $(datadir)/pixmaps/pidgin/tray/16
+pidgintraypix_DATA = $(TRAY_ICONS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/pixmaps/tray/16/Makefile.mingw	Fri Mar 16 00:02:55 2007 +0000
@@ -0,0 +1,20 @@
+#
+# Makefile.mingw
+#
+# Description: Makefile for win32 (mingw) version of Pidgin pixmaps
+#
+
+GAIM_TOP := ../../../..
+include $(GAIM_TOP)/libpurple/win32/global.mak
+
+datadir = $(GAIM_INSTALL_DIR)
+include ./Makefile.am
+
+.PHONY: install
+
+install:
+	if test '$(pidgintraypix_DATA)'; then \
+	  mkdir -p $(pidgintraypixdir); \
+	  cp $(pidgintraypix_DATA) $(pidgintraypixdir); \
+	fi;
+
Binary file pidgin/pixmaps/tray/16/tray-away.png has changed
Binary file pidgin/pixmaps/tray/16/tray-busy.png has changed
Binary file pidgin/pixmaps/tray/16/tray-connecting.png has changed
Binary file pidgin/pixmaps/tray/16/tray-extended-away.png has changed
Binary file pidgin/pixmaps/tray/16/tray-message.png has changed
Binary file pidgin/pixmaps/tray/16/tray-offline.png has changed
Binary file pidgin/pixmaps/tray/16/tray-online.png has changed
--- a/pidgin/pixmaps/tray/Makefile.am	Fri Mar 16 00:02:19 2007 +0000
+++ b/pidgin/pixmaps/tray/Makefile.am	Fri Mar 16 00:02:55 2007 +0000
@@ -1,4 +1,4 @@
-SUBDIRS = 22
+SUBDIRS = 16 22
 
 EXTRA_DIST = \
 	Makefile.mingw \
--- a/pidgin/plugins/musicmessaging/musicmessaging.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/pidgin/plugins/musicmessaging/musicmessaging.c	Fri Mar 16 00:02:55 2007 +0000
@@ -235,16 +235,19 @@
 static int
 mmconv_from_conv_loc(GaimConversation *conv)
 {
+	GList *l;
 	MMConversation *mmconv_current = NULL;
 	guint i;
 	
-	for (i = 0; i < g_list_length(conversations); i++)
+	i = 0;
+	for (l = conversations; l != NULL; l = l->next)
 	{
-		mmconv_current = (MMConversation *)g_list_nth_data(conversations, i);
+		mmconv_current = l->data;
 		if (conv == mmconv_current->conv)
 		{
 			return i;
 		}
+		i++;
 	}
 	return -1;
 }
@@ -295,9 +298,9 @@
 plugin_unload(GaimPlugin *plugin) {
 	MMConversation *mmconv = NULL;
 	
-	while (g_list_length(conversations) > 0)
+	while (conversations != NULL)
 	{
-		mmconv = g_list_first(conversations)->data;
+		mmconv = conversations->data;
 		conv_destroyed(mmconv->conv);
 	}
 	return TRUE;
--- a/pidgin/win32/gtkdocklet-win32.c	Fri Mar 16 00:02:19 2007 +0000
+++ b/pidgin/win32/gtkdocklet-win32.c	Fri Mar 16 00:02:55 2007 +0000
@@ -443,7 +443,7 @@
 static HICON load_hicon_from_stock(const char *stock) {
 	HICON hicon = NULL;
 	GdkPixbuf *pixbuf = gtk_widget_render_icon(image, stock,
-		gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_SMALL), NULL);
+		gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL), NULL);
 
 	if (pixbuf) {
 		hicon = pixbuf_to_hicon(pixbuf);