summary refs log tree commit diff stats
path: root/src/fe-gtk
diff options
context:
space:
mode:
Diffstat (limited to 'src/fe-gtk')
-rw-r--r--src/fe-gtk/Makefile.am26
-rw-r--r--src/fe-gtk/banlist.c25
-rw-r--r--src/fe-gtk/chanlist.c14
-rw-r--r--src/fe-gtk/chanview-tabs.c7
-rw-r--r--src/fe-gtk/chanview.c19
-rw-r--r--src/fe-gtk/custom-list.c11
-rw-r--r--src/fe-gtk/custom-list.h8
-rw-r--r--src/fe-gtk/dccgui.c49
-rw-r--r--src/fe-gtk/editlist.c2
-rw-r--r--src/fe-gtk/fe-gtk.c70
-rw-r--r--src/fe-gtk/fe-gtk.h25
-rw-r--r--src/fe-gtk/fe-gtk.vcxproj89
-rw-r--r--src/fe-gtk/fe-gtk.vcxproj.filters15
-rw-r--r--src/fe-gtk/fkeys.c153
-rw-r--r--src/fe-gtk/gtkutil.c4
-rw-r--r--src/fe-gtk/gtkutil.h8
-rw-r--r--src/fe-gtk/hexchat.exe.manifest22
-rw-r--r--src/fe-gtk/hexchat.rc.tt5
-rw-r--r--src/fe-gtk/joind.c12
-rw-r--r--src/fe-gtk/maingui.c166
-rw-r--r--src/fe-gtk/menu.c92
-rw-r--r--src/fe-gtk/notifications/notification-backend.h27
-rw-r--r--src/fe-gtk/notifications/notification-dummy.c39
-rw-r--r--src/fe-gtk/notifications/notification-libnotify.c72
-rw-r--r--src/fe-gtk/notifications/notification-osx.m54
-rw-r--r--src/fe-gtk/notifications/notification-windows.c87
-rw-r--r--src/fe-gtk/notifications/notification-winrt.cpp100
-rw-r--r--src/fe-gtk/notifications/notifications-winrt.vcxproj62
-rw-r--r--src/fe-gtk/notifications/notifications-winrt.vcxproj.filters22
-rw-r--r--src/fe-gtk/notifygui.c10
-rw-r--r--src/fe-gtk/palette.c56
-rw-r--r--src/fe-gtk/pixmaps.c3
-rw-r--r--src/fe-gtk/plugin-notification.c215
-rw-r--r--src/fe-gtk/plugin-notification.h25
-rw-r--r--src/fe-gtk/plugin-tray.c124
-rw-r--r--src/fe-gtk/plugingui.c33
-rw-r--r--src/fe-gtk/rawlog.c6
-rw-r--r--src/fe-gtk/servlistgui.c39
-rw-r--r--src/fe-gtk/setup.c118
-rw-r--r--src/fe-gtk/sexy-iso-codes.c3
-rw-r--r--src/fe-gtk/sexy-spell-entry.c34
-rw-r--r--src/fe-gtk/textgui.c36
-rw-r--r--src/fe-gtk/userlistgui.c116
-rw-r--r--src/fe-gtk/userlistgui.h2
-rw-r--r--src/fe-gtk/xtext.c249
-rw-r--r--src/fe-gtk/xtext.h2
46 files changed, 1514 insertions, 842 deletions
diff --git a/src/fe-gtk/Makefile.am b/src/fe-gtk/Makefile.am
index a8f43ac5..71179853 100644
--- a/src/fe-gtk/Makefile.am
+++ b/src/fe-gtk/Makefile.am
@@ -1,3 +1,6 @@
+
+include $(top_srcdir)/m4/clang-analyze.am
+
 localedir = $(datadir)/locale
 
 bin_PROGRAMS = hexchat
@@ -9,7 +12,7 @@ hexchat_LDADD = ../common/libhexchatcommon.a $(GUI_LIBS)
 EXTRA_DIST = \
 	ascii.h banlist.h chanlist.h chanview.h chanview-tabs.c \
 	chanview-tree.c custom-list.h editlist.h fe-gtk.h fkeys.h gtkutil.h joind.h \
-	maingui.h menu.h notifygui.h palette.h pixmaps.h \
+	maingui.h menu.h notifygui.h  notifications palette.h pixmaps.h plugin-notification.h \
 	plugin-tray.h plugingui.c plugingui.h rawlog.h sexy-iso-codes.h \
 	sexy-spell-entry.h textgui.h urlgrab.h userlistgui.h xtext.h \
 	../../data/hexchat.gresource.xml
@@ -26,12 +29,29 @@ if HAVE_ISO_CODES
 iso_codes_c = sexy-iso-codes.c
 endif
 
+if USE_LIBNOTIFY
+notify_c = notifications/notification-libnotify.c
+else
+if HAVE_GTK_MAC
+notify_c = notifications/notification-osx.m
+hexchat_LDFLAGS = -framework Foundation
+else
+notify_c = notifications/notification-dummy.c
+endif
+endif
+
 hexchat_SOURCES = ascii.c banlist.c chanlist.c chanview.c custom-list.c \
 	dccgui.c editlist.c fe-gtk.c fkeys.c gtkutil.c ignoregui.c joind.c menu.c \
-	maingui.c notifygui.c palette.c pixmaps.c plugin-tray.c $(plugingui_c) \
-	rawlog.c resources.c servlistgui.c setup.c $(iso_codes_c) \
+	maingui.c notifygui.c $(notify_c) palette.c pixmaps.c plugin-tray.c $(plugingui_c) \
+	plugin-notification.c rawlog.c resources.c servlistgui.c setup.c $(iso_codes_c) \
 	sexy-spell-entry.c textgui.c urlgrab.c userlistgui.c xtext.c
 hexchat_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_builddir)/src/common
 
 resources.c: $(top_srcdir)/data/hexchat.gresource.xml $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(top_srcdir)/data --generate-dependencies $(top_srcdir)/data/hexchat.gresource.xml)
 	$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(top_srcdir)/data --generate-source $<
+
+if DO_STATIC_ANALYSIS
+analyze_plists = $(hexchat_SOURCES:%.c=%.plist)
+all-local: $(analyze_plists)
+MOSTLYCLEANFILES = $(analyze_plists)
+endif
diff --git a/src/fe-gtk/banlist.c b/src/fe-gtk/banlist.c
index d6f44811..e10aaa67 100644
--- a/src/fe-gtk/banlist.c
+++ b/src/fe-gtk/banlist.c
@@ -491,7 +491,7 @@ banlist_unban_inner (gpointer none, banlist_info *banl, int mode_num)
 	if (!gtk_tree_model_get_iter_first (model, &iter))
 		return 0;
 
-	masks = g_malloc (sizeof (char *) * banl->line_ct);
+	masks = g_new (char *, banl->line_ct);
 	num_sel = 0;
 	do
 	{
@@ -577,17 +577,17 @@ static void
 banlist_add_selected_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
 {
 	GSList **lp = data;
-	GSList *list = NULL;
 	GtkTreeIter *copy;
 
-	if (!lp) return;
-	list = *lp;
-	copy = g_malloc (sizeof (GtkTreeIter));
-	g_return_if_fail (copy != NULL);
+	if (lp == NULL)
+	{
+		return;
+	}
+
+	copy = g_new (GtkTreeIter, 1);
 	*copy = *iter;
 
-	list = g_slist_append (list, copy);
-	*(GSList **)data = list;
+	*lp = g_slist_append (*lp, copy);
 }
 
 static void
@@ -786,14 +786,9 @@ banlist_opengui (struct session *sess)
 		return;
 	}
 
-	if (!sess->res->banlist)
+	if (sess->res->banlist == NULL)
 	{
-		sess->res->banlist = g_malloc0 (sizeof (banlist_info));
-		if (!sess->res->banlist)
-		{
-			fe_message (_("Banlist initialization failed."), FE_MSG_ERROR);
-			return;
-		}
+		sess->res->banlist = g_new0 (banlist_info, 1);
 	}
 	banl = sess->res->banlist;
 	if (banl->window)
diff --git a/src/fe-gtk/chanlist.c b/src/fe-gtk/chanlist.c
index f3a2259d..f6ef46f3 100644
--- a/src/fe-gtk/chanlist.c
+++ b/src/fe-gtk/chanlist.c
@@ -94,7 +94,7 @@ chanlist_update_caption (server *serv)
 {
 	gchar tbuf[256];
 
-	snprintf (tbuf, sizeof tbuf,
+	g_snprintf (tbuf, sizeof tbuf,
 				 _("Displaying %d/%d users on %d/%d channels."),
 				 serv->gui->chanlist_users_shown_count,
 				 serv->gui->chanlist_users_found_count,
@@ -148,7 +148,7 @@ chanlist_data_free (server *serv)
 			data = rows->data;
 			g_free (data->topic);
 			g_free (data->collation_key);
-			free (data);
+			g_free (data);
 		}
 
 		g_slist_free (serv->gui->chanlist_data_stored_rows);
@@ -370,7 +370,7 @@ fe_add_chan_list (server *serv, char *chan, char *users, char *topic)
 	int len = strlen (chan) + 1;
 
 	/* we allocate the struct and channel string in one go */
-	next_row = malloc (sizeof (chanlistrow) + len);
+	next_row = g_malloc (sizeof (chanlistrow) + len);
 	memcpy (((char *)next_row) + sizeof (chanlistrow), chan, len);
 	next_row->topic = strip_color (topic, -1, STRIP_ALL);
 	next_row->collation_key = g_utf8_collate_key (chan, len-1);
@@ -456,7 +456,7 @@ chanlist_join (GtkWidget * wid, server *serv)
 	{
 		if (serv->connected && (strcmp (chan, "*") != 0))
 		{
-			snprintf (tbuf, sizeof (tbuf), "join %s", chan);
+			g_snprintf (tbuf, sizeof (tbuf), "join %s", chan);
 			handle_command (serv->server_session, tbuf, FALSE);
 		} else
 			gdk_beep ();
@@ -482,7 +482,7 @@ chanlist_filereq_done (server *serv, char *file)
 	if (fh == -1)
 		return;
 
-	snprintf (buf, sizeof buf, "HexChat Channel List: %s - %s\n",
+	g_snprintf (buf, sizeof buf, "HexChat Channel List: %s - %s\n",
 				 serv->servername, ctime (&t));
 	write (fh, buf, strlen (buf));
 
@@ -494,7 +494,7 @@ chanlist_filereq_done (server *serv, char *file)
 									  COL_CHANNEL, &chan,
 									  COL_USERS, &users,
 									  COL_TOPIC, &topic, -1);
-			snprintf (buf, sizeof buf, "%-16s %-5d%s\n", chan, users, topic);
+			g_snprintf (buf, sizeof buf, "%-16s %-5d%s\n", chan, users, topic);
 			g_free (chan);
 			g_free (topic);
 			write (fh, buf, strlen (buf));
@@ -717,7 +717,7 @@ chanlist_opengui (server *serv, int do_refresh)
 		return;
 	}
 
-	snprintf (tbuf, sizeof tbuf, _(DISPLAY_NAME": Channel List (%s)"),
+	g_snprintf (tbuf, sizeof tbuf, _(DISPLAY_NAME": Channel List (%s)"),
 				 server_get_network (serv, TRUE));
 
 	serv->gui->chanlist_pending_rows = NULL;
diff --git a/src/fe-gtk/chanview-tabs.c b/src/fe-gtk/chanview-tabs.c
index 8f940c24..5681f9d6 100644
--- a/src/fe-gtk/chanview-tabs.c
+++ b/src/fe-gtk/chanview-tabs.c
@@ -62,12 +62,13 @@ cv_tabs_sizerequest (GtkWidget *viewport, GtkRequisition *requisition, chanview
 static void
 cv_tabs_sizealloc (GtkWidget *widget, GtkAllocation *allocation, chanview *cv)
 {
+	GdkWindow *parent_win;
 	GtkAdjustment *adj;
 	GtkWidget *inner;
 	gint viewport_size;
 
 	inner = ((tabview *)cv)->inner;
-	GdkWindow *parent_win = gtk_widget_get_window (gtk_widget_get_parent (inner));
+	parent_win = gtk_widget_get_window (gtk_widget_get_parent (inner));
 
 	if (cv->vertical)
 	{
@@ -141,7 +142,7 @@ tab_scroll_left_up_clicked (GtkWidget *widget, chanview *cv)
 	gfloat new_value;
 	GtkWidget *inner;
 	GdkWindow *parent_win;
-	gfloat i;
+	gdouble i;
 
 	inner = ((tabview *)cv)->inner;
 	parent_win = gtk_widget_get_window (gtk_widget_get_parent (inner));
@@ -190,7 +191,7 @@ tab_scroll_right_down_clicked (GtkWidget *widget, chanview *cv)
 	gfloat new_value;
 	GtkWidget *inner;
 	GdkWindow *parent_win;
-	gfloat i;
+	gdouble i;
 
 	inner = ((tabview *)cv)->inner;
 	parent_win = gtk_widget_get_window (gtk_widget_get_parent (inner));
diff --git a/src/fe-gtk/chanview.c b/src/fe-gtk/chanview.c
index 4c50d922..e5556d9f 100644
--- a/src/fe-gtk/chanview.c
+++ b/src/fe-gtk/chanview.c
@@ -111,9 +111,8 @@ truncate_tab_name (char *name, int max)
 	if (max > 2 && g_utf8_strlen (name, -1) > max)
 	{
 		/* truncate long channel names */
-		buf = malloc (strlen (name) + 4);
-		strcpy (buf, name);
-		g_utf8_offset_to_pointer (buf, max)[0] = 0;
+		buf = g_malloc (strlen (name) + 4);
+		g_utf8_strncpy (buf, name, max);
 		strcat (buf, "..");
 		return buf;
 	}
@@ -231,7 +230,7 @@ chanview_free_ch (chanview *cv, GtkTreeIter *iter)
 	chan *ch;
 
 	gtk_tree_model_get (GTK_TREE_MODEL (cv->store), iter, COL_CHAN, &ch, -1);
-	free (ch);
+	g_free (ch);
 }
 
 static void
@@ -251,7 +250,7 @@ chanview_destroy (chanview *cv)
 		gtk_widget_destroy (cv->box);
 
 	chanview_destroy_store (cv);
-	free (cv);
+	g_free (cv);
 }
 
 static void
@@ -267,7 +266,7 @@ chanview_new (int type, int trunc_len, gboolean sort, gboolean use_icons,
 {
 	chanview *cv;
 
-	cv = calloc (1, sizeof (chanview));
+	cv = g_new0 (chanview, 1);
 	cv->store = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER,
 											  PANGO_TYPE_ATTR_LIST, GDK_TYPE_PIXBUF);
 	cv->style = style;
@@ -368,7 +367,7 @@ chanview_add_real (chanview *cv, char *name, void *family, void *userdata,
 
 	if (!ch)
 	{
-		ch = calloc (1, sizeof (chan));
+		ch = g_new0 (chan, 1);
 		ch->userdata = userdata;
 		ch->family = family;
 		ch->cv = cv;
@@ -401,7 +400,7 @@ chanview_add (chanview *cv, char *name, void *family, void *userdata, gboolean a
 	ret = chanview_add_real (cv, new_name, family, userdata, allow_closure, tag, icon, NULL, NULL);
 
 	if (new_name != name)
-		free (new_name);
+		g_free (new_name);
 
 	return ret;
 }
@@ -492,7 +491,7 @@ chan_rename (chan *ch, char *name, int trunc_len)
 	ch->cv->trunc_len = trunc_len;
 
 	if (new_name != name)
-		free (new_name);
+		g_free (new_name);
 }
 
 /* this thing is overly complicated */
@@ -645,7 +644,7 @@ chan_remove (chan *ch, gboolean force)
 
 	ch->cv->size--;
 	gtk_tree_store_remove (ch->cv->store, &ch->iter);
-	free (ch);
+	g_free (ch);
 	return TRUE;
 }
 
diff --git a/src/fe-gtk/custom-list.c b/src/fe-gtk/custom-list.c
index a954b4a0..f1241947 100644
--- a/src/fe-gtk/custom-list.c
+++ b/src/fe-gtk/custom-list.c
@@ -134,7 +134,6 @@ custom_list_get_type (void)
 		return custom_list_type;
 
 	/* Some boilerplate type registration stuff */
-	if (1)
 	{
 		static const GTypeInfo custom_list_info = {
 			sizeof (CustomListClass),
@@ -154,7 +153,6 @@ custom_list_get_type (void)
 	}
 
 	/* Here we register our GtkTreeModel interface with the type system */
-	if (1)
 	{
 		static const GInterfaceInfo tree_model_info = {
 			(GInterfaceInitFunc) custom_list_tree_model_init,
@@ -167,7 +165,6 @@ custom_list_get_type (void)
 	}
 
 	/* Add GtkTreeSortable interface */
-	if (1)
 	{
 		static const GInterfaceInfo tree_sortable_info = {
 			(GInterfaceInitFunc) custom_list_sortable_init,
@@ -336,7 +333,7 @@ custom_list_get_iter (GtkTreeModel * tree_model,
 	gint n;
 
 	n = gtk_tree_path_get_indices (path)[0];
-	if (n >= custom_list->num_rows || n < 0)
+	if (n < 0 || (guint) n >= custom_list->num_rows)
 		return FALSE;
 
 	record = custom_list->rows[n];
@@ -533,7 +530,7 @@ custom_list_iter_nth_child (GtkTreeModel * tree_model,
 		return FALSE;
 
 	/* special case: if parent == NULL, set iter to n-th top-level row */
-	if (n >= custom_list->num_rows)
+	if (n < 0 || (guint) n >= custom_list->num_rows)
 		return FALSE;
 
 	iter->user_data = custom_list->rows[n];
@@ -730,7 +727,7 @@ custom_list_resort (CustomList * custom_list)
 							 custom_list);
 
 	/* let other objects know about the new order */
-	neworder = malloc (sizeof (gint) * custom_list->num_rows);
+	neworder = g_new (gint, custom_list->num_rows);
 
 	for (i = custom_list->num_rows - 1; i >= 0; i--)
 	{
@@ -747,7 +744,7 @@ custom_list_resort (CustomList * custom_list)
 	gtk_tree_model_rows_reordered (GTK_TREE_MODEL (custom_list), path, NULL,
 											 neworder);
 	gtk_tree_path_free (path);
-	free (neworder);
+	g_free (neworder);
 }
 
 void
diff --git a/src/fe-gtk/custom-list.h b/src/fe-gtk/custom-list.h
index 64f0535f..30a73919 100644
--- a/src/fe-gtk/custom-list.h
+++ b/src/fe-gtk/custom-list.h
@@ -77,10 +77,10 @@ struct _CustomList
 {
 	GObject parent;
 
-	guint num_rows;				  /* number of rows that we have used */
-	guint num_alloc;					/* number of rows allocated */
-	chanlistrow **rows;			  /* a dynamically allocated array of pointers to the
-										   *  CustomRecord structure for each row */
+	guint num_rows;     /* number of rows that we have used */
+	guint num_alloc;    /* number of rows allocated */
+	chanlistrow **rows; /* a dynamically allocated array of pointers to the
+	                     * CustomRecord structure for each row */
 
 	gint n_columns;
 	GType column_types[CUSTOM_LIST_N_COLUMNS];
diff --git a/src/fe-gtk/dccgui.c b/src/fe-gtk/dccgui.c
index 10ec8388..8c9dc8b4 100644
--- a/src/fe-gtk/dccgui.c
+++ b/src/fe-gtk/dccgui.c
@@ -88,7 +88,7 @@ struct my_dcc_send
 {
 	struct session *sess;
 	char *nick;
-	int maxcps;
+	gint64 maxcps;
 	int passive;
 };
 
@@ -105,7 +105,7 @@ static short view_mode;	/* 1=download 2=upload 3=both */
 
 
 static void
-proper_unit (DCC_SIZE size, char *buf, int buf_len)
+proper_unit (guint64 size, char *buf, size_t buf_len)
 {
 	gchar *formatted_str;
 	GFormatSizeFlags format_flags = G_FORMAT_SIZE_DEFAULT;
@@ -117,7 +117,7 @@ proper_unit (DCC_SIZE size, char *buf, int buf_len)
 		format_flags = G_FORMAT_SIZE_IEC_UNITS;
 #endif
 
-	formatted_str = g_format_size_full ((guint64)size, format_flags);
+	formatted_str = g_format_size_full (size, format_flags);
 	g_strlcpy (buf, formatted_str, buf_len);
 
 	g_free (formatted_str);
@@ -130,45 +130,45 @@ dcc_send_filereq_file (struct my_dcc_send *mdc, char *file)
 		dcc_send (mdc->sess, mdc->nick, file, mdc->maxcps, mdc->passive);
 	else
 	{
-		free (mdc->nick);
-		free (mdc);
+		g_free (mdc->nick);
+		g_free (mdc);
 	}
 }
 
 void
 fe_dcc_send_filereq (struct session *sess, char *nick, int maxcps, int passive)
 {
-	char tbuf[128];
-	struct my_dcc_send *mdc;
-	
-	mdc = malloc (sizeof (*mdc));
+	char* tbuf = g_strdup_printf (_("Send file to %s"), nick);
+
+	struct my_dcc_send *mdc = g_new (struct my_dcc_send, 1);
 	mdc->sess = sess;
-	mdc->nick = strdup (nick);
+	mdc->nick = g_strdup (nick);
 	mdc->maxcps = maxcps;
 	mdc->passive = passive;
 
-	snprintf (tbuf, sizeof tbuf, _("Send file to %s"), nick);
 	gtkutil_file_req (tbuf, dcc_send_filereq_file, mdc, prefs.hex_dcc_dir, NULL, FRF_MULTIPLE|FRF_FILTERISINITIAL);
+
+	g_free (tbuf);
 }
 
 static void
 dcc_prepare_row_chat (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter,
 							 gboolean update_only)
 {
-	static char pos[16], siz[16];
+	static char pos[16], size[16];
 	char *date;
 
 	date = ctime (&dcc->starttime);
 	date[strlen (date) - 1] = 0;	/* remove the \n */
 
 	proper_unit (dcc->pos, pos, sizeof (pos));
-	proper_unit (dcc->size, siz, sizeof (siz));
+	proper_unit (dcc->size, size, sizeof (size));
 
 	gtk_list_store_set (store, iter,
 							  CCOL_STATUS, _(dccstat[dcc->dccstat].name),
 							  CCOL_NICK, dcc->nick,
 							  CCOL_RECV, pos,
-							  CCOL_SENT, siz,
+							  CCOL_SENT, size,
 							  CCOL_START, date,
 							  CCOL_DCC, dcc,
 							  CCOL_COLOR,
@@ -194,13 +194,12 @@ dcc_prepare_row_send (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter,
 	per = (float) ((dcc->ack * 100.00) / dcc->size);
 	proper_unit (dcc->size, size, sizeof (size));
 	proper_unit (dcc->pos, pos, sizeof (pos));
-	snprintf (kbs, sizeof (kbs), "%.1f", ((float)dcc->cps) / 1024);
-/*	proper_unit (dcc->ack, ack, sizeof (ack));*/
-	snprintf (perc, sizeof (perc), "%.0f%%", per);
+	g_snprintf (kbs, sizeof (kbs), "%.1f", ((float)dcc->cps) / 1024);
+	g_snprintf (perc, sizeof (perc), "%.0f%%", per);
 	if (dcc->cps != 0)
 	{
 		to_go = (dcc->size - dcc->ack) / dcc->cps;
-		snprintf (eta, sizeof (eta), "%.2d:%.2d:%.2d",
+		g_snprintf (eta, sizeof (eta), "%.2d:%.2d:%.2d",
 					 to_go / 3600, (to_go / 60) % 60, to_go % 60);
 	} else
 		strcpy (eta, "--:--:--");
@@ -253,14 +252,14 @@ dcc_prepare_row_recv (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter,
 		proper_unit (dcc->resumable, pos, sizeof (pos));
 	else
 		proper_unit (dcc->pos, pos, sizeof (pos));
-	snprintf (kbs, sizeof (kbs), "%.1f", ((float)dcc->cps) / 1024);
+	g_snprintf (kbs, sizeof (kbs), "%.1f", ((float)dcc->cps) / 1024);
 	/* percentage recv'ed */
 	per = (float) ((dcc->pos * 100.00) / dcc->size);
-	snprintf (perc, sizeof (perc), "%.0f%%", per);
+	g_snprintf (perc, sizeof (perc), "%.0f%%", per);
 	if (dcc->cps != 0)
 	{
 		to_go = (dcc->size - dcc->pos) / dcc->cps;
-		snprintf (eta, sizeof (eta), "%.2d:%.2d:%.2d",
+		g_snprintf (eta, sizeof (eta), "%.2d:%.2d:%.2d",
 					 to_go / 3600, (to_go / 60) % 60, to_go % 60);
 	} else
 		strcpy (eta, "--:--:--");
@@ -526,7 +525,7 @@ resume_clicked (GtkWidget * wid, gpointer none)
 			fe_message (_("That file is not resumable."), FE_MSG_ERROR);
 			break;
 		case 1:
-			snprintf (buf, sizeof (buf),
+			g_snprintf (buf, sizeof (buf),
 						_(	"Cannot access file: %s\n"
 							"%s.\n"
 							"Resuming not possible."), dcc->destfile,	
@@ -607,7 +606,7 @@ browse_folder (char *dir)
 #else
 	char buf[512];
 
-	snprintf (buf, sizeof (buf), "file://%s", dir);
+	g_snprintf (buf, sizeof (buf), "file://%s", dir);
 	fe_open_url (buf);
 #endif
 }
@@ -640,7 +639,7 @@ dcc_details_populate (struct DCC *dcc)
 		gtk_label_set_text (GTK_LABEL (dccfwin.file_label), dcc->file);
 
 	/* address and port */
-	snprintf (buf, sizeof (buf), "%s : %d", net_ip (dcc->addr), dcc->port);
+	g_snprintf (buf, sizeof (buf), "%s : %d", net_ip (dcc->addr), dcc->port);
 	gtk_label_set_text (GTK_LABEL (dccfwin.address_label), buf);
 }
 
@@ -738,7 +737,7 @@ dcc_detail_label (char *text, GtkWidget *box, int num)
 	char buf[64];
 
 	label = gtk_label_new (NULL);
-	snprintf (buf, sizeof (buf), "<b>%s</b>", text);
+	g_snprintf (buf, sizeof (buf), "<b>%s</b>", text);
 	gtk_label_set_markup (GTK_LABEL (label), buf);
 	gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
 	gtk_table_attach (GTK_TABLE (box), label, 0, 1, 0 + num, 1 + num, GTK_FILL, GTK_FILL, 0, 0);
diff --git a/src/fe-gtk/editlist.c b/src/fe-gtk/editlist.c
index f7e22d52..4b236dc1 100644
--- a/src/fe-gtk/editlist.c
+++ b/src/fe-gtk/editlist.c
@@ -283,6 +283,7 @@ editlist_treeview_new (GtkWidget *box, char *title1, char *title2)
 	view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
 	gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (view), TRUE);
 	gtk_tree_view_set_enable_search (GTK_TREE_VIEW (view), FALSE);
+	gtk_tree_view_set_reorderable (GTK_TREE_VIEW (view), TRUE);
 	
 	g_signal_connect (G_OBJECT (view), "key_press_event",
 						G_CALLBACK (editlist_keypress), NULL);
@@ -313,7 +314,6 @@ editlist_treeview_new (GtkWidget *box, char *title1, char *title2)
 	gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
 	gtk_tree_view_column_set_resizable (col, TRUE);
 	gtk_tree_view_column_set_min_width (col, 100);
-	col = gtk_tree_view_get_column (GTK_TREE_VIEW (view), CMD_COLUMN);
 
 	gtk_container_add (GTK_CONTAINER (scroll), view);
 	gtk_container_add (GTK_CONTAINER (box), scroll);
diff --git a/src/fe-gtk/fe-gtk.c b/src/fe-gtk/fe-gtk.c
index 4b7d916f..8c163eb7 100644
--- a/src/fe-gtk/fe-gtk.c
+++ b/src/fe-gtk/fe-gtk.c
@@ -52,6 +52,7 @@
 #include "plugin-tray.h"
 #include "urlgrab.h"
 #include "setup.h"
+#include "plugin-notification.h"
 
 #ifdef USE_LIBCANBERRA
 #include <canberra.h>
@@ -224,7 +225,7 @@ fe_args (int argc, char *argv[])
 	/* cuts can. So we have to set the current dir manually, to the path  */
 	/* of the exe. */
 	{
-		char *tmp = strdup (argv[0]);
+		char *tmp = g_strdup (argv[0]);
 		char *sl;
 
 		sl = strrchr (tmp, G_DIR_SEPARATOR);
@@ -233,7 +234,7 @@ fe_args (int argc, char *argv[])
 			*sl = 0;
 			chdir (tmp);
 		}
-		free (tmp);
+		g_free (tmp);
 	}
 #endif
 
@@ -265,7 +266,7 @@ create_input_style (GtkStyle *style)
 	/* fall back */
 	if (pango_font_description_get_size (style->font_desc) == 0)
 	{
-		snprintf (buf, sizeof (buf), _("Failed to open font:\n\n%s"), prefs.hex_text_font);
+		g_snprintf (buf, sizeof (buf), _("Failed to open font:\n\n%s"), prefs.hex_text_font);
 		fe_message (buf, FE_MSG_ERROR);
 		pango_font_description_free (style->font_desc);
 		style->font_desc = pango_font_description_from_string ("sans 11");
@@ -381,6 +382,8 @@ fe_idle (gpointer data)
 {
 	session *sess = sess_list->data;
 
+	plugin_add (sess, NULL, NULL, notification_plugin_init, notification_plugin_deinit, NULL, FALSE);
+
 	plugin_add (sess, NULL, NULL, tray_plugin_init, tray_plugin_deinit, NULL, FALSE);
 
 	if (arg_minimize == 1)
@@ -424,8 +427,7 @@ fe_new_window (session *sess, int focus)
 void
 fe_new_server (struct server *serv)
 {
-	serv->gui = malloc (sizeof (struct server_gui));
-	memset (serv->gui, 0, sizeof (struct server_gui));
+	serv->gui = g_new0 (struct server_gui, 1);
 }
 
 void
@@ -510,18 +512,15 @@ fe_set_topic (session *sess, char *topic, char *stripped_topic)
 	}
 	else
 	{
-		if (sess->res->topic_text)
-		{
-			free (sess->res->topic_text);
-		}
+		g_free (sess->res->topic_text);
 
 		if (prefs.hex_text_stripcolor_topic)
 		{
-			sess->res->topic_text = strdup (stripped_topic);
+			sess->res->topic_text = g_strdup (stripped_topic);
 		}
 		else
 		{
-			sess->res->topic_text = strdup (topic);
+			sess->res->topic_text = g_strdup (topic);
 		}
 	}
 }
@@ -547,9 +546,8 @@ fe_update_mode_entry (session *sess, GtkWidget *entry, char **text, char *new_te
 	{
 		if (sess->gui->is_tab)
 		{
-			if (*text)
-				free (*text);
-			*text = strdup (new_text);
+			g_free (*text);
+			*text = g_strdup (new_text);
 		}
 	}
 }
@@ -721,7 +719,7 @@ fe_lastlog (session *sess, session *lastlog_sess, char *sstr, gtk_xtext_search_f
 		lbuf->search_lnee = strlen (lbuf->search_nee);
 	}
 	lbuf->search_flags = flags;
-	lbuf->search_text = strdup (sstr);
+	lbuf->search_text = g_strdup (sstr);
 	gtk_xtext_lastlog (lbuf, buf);
 }
 
@@ -751,9 +749,9 @@ fe_set_lag (server *serv, long lag)
 	if (per > 1.0)
 		per = 1.0;
 
-	snprintf (lagtext, sizeof (lagtext) - 1, "%s%ld.%lds",
+	g_snprintf (lagtext, sizeof (lagtext) - 1, "%s%ld.%lds",
 			  serv->lag_sent ? "+" : "", lag / 1000, (lag/100) % 10);
-	snprintf (lagtip, sizeof (lagtip) - 1, "Lag: %s%ld.%ld seconds",
+	g_snprintf (lagtip, sizeof (lagtip) - 1, "Lag: %s%ld.%ld seconds",
 				 serv->lag_sent ? "+" : "", lag / 1000, (lag/100) % 10);
 
 	while (list)
@@ -761,9 +759,8 @@ fe_set_lag (server *serv, long lag)
 		sess = list->data;
 		if (sess->server == serv)
 		{
-			if (sess->res->lag_tip)
-				free (sess->res->lag_tip);
-			sess->res->lag_tip = strdup (lagtip);
+			g_free (sess->res->lag_tip);
+			sess->res->lag_tip = g_strdup (lagtip);
 
 			if (!sess->gui->is_tab || current_tab == sess)
 			{
@@ -777,9 +774,8 @@ fe_set_lag (server *serv, long lag)
 			} else
 			{
 				sess->res->lag_value = per;
-				if (sess->res->lag_text)
-					free (sess->res->lag_text);
-				sess->res->lag_text = strdup (lagtext);
+				g_free (sess->res->lag_text);
+				sess->res->lag_text = g_strdup (lagtext);
 			}
 		}
 		list = list->next;
@@ -804,12 +800,11 @@ fe_set_throttle (server *serv)
 		sess = list->data;
 		if (sess->server == serv)
 		{
-			snprintf (tbuf, sizeof (tbuf) - 1, _("%d bytes"), serv->sendq_len);
-			snprintf (tip, sizeof (tip) - 1, _("Network send queue: %d bytes"), serv->sendq_len);
+			g_snprintf (tbuf, sizeof (tbuf) - 1, _("%d bytes"), serv->sendq_len);
+			g_snprintf (tip, sizeof (tip) - 1, _("Network send queue: %d bytes"), serv->sendq_len);
 
-			if (sess->res->queue_tip)
-				free (sess->res->queue_tip);
-			sess->res->queue_tip = strdup (tip);
+			g_free (sess->res->queue_tip);
+			sess->res->queue_tip = g_strdup (tip);
 
 			if (!sess->gui->is_tab || current_tab == sess)
 			{
@@ -823,9 +818,8 @@ fe_set_throttle (server *serv)
 			} else
 			{
 				sess->res->queue_value = per;
-				if (sess->res->queue_text)
-					free (sess->res->queue_text);
-				sess->res->queue_text = strdup (tbuf);
+				g_free (sess->res->queue_text);
+				sess->res->queue_text = g_strdup (tbuf);
 			}
 		}
 		list = list->next;
@@ -882,11 +876,10 @@ fe_confirm (const char *message, void (*yesproc)(void *), void (*noproc)(void *)
 {
 	/* warning, assuming fe_confirm is used by DCC only! */
 	struct DCC *dcc = ud;
-	char *filepath;
 
 	if (dcc->file)
 	{
-		filepath = g_build_filename (prefs.hex_dcc_dir, dcc->file, NULL);
+		char *filepath = g_build_filename (prefs.hex_dcc_dir, dcc->file, NULL);
 		gtkutil_file_req (message, dcc_saveas_cb, ud, filepath, NULL,
 								FRF_WRITE|FRF_NOASKOVERWRITE|FRF_FILTERISINITIAL);
 		g_free (filepath);
@@ -978,9 +971,8 @@ fe_set_inputbox_contents (session *sess, char *text)
 		SPELL_ENTRY_SET_TEXT (sess->gui->input_box, text);
 	} else
 	{
-		if (sess->res->input_text)
-			free (sess->res->input_text);
-		sess->res->input_text = strdup (text);
+		g_free (sess->res->input_text);
+		sess->res->input_text = g_strdup (text);
 	}
 }
 
@@ -1092,9 +1084,9 @@ fe_open_url (const char *url)
 	/* the http:// part's missing, prepend it, otherwise it won't always work */
 	else if (strchr (url, ':') == NULL)
 	{
-		url = g_strdup_printf ("http://%s", url);
-		fe_open_url_inner (url);
-		g_free ((char *)url);
+		uri = g_strdup_printf ("http://%s", url);
+		fe_open_url_inner (uri);
+		g_free (uri);
 	}
 	/* we have a sane URL, send it to the browser untouched */
 	else
diff --git a/src/fe-gtk/fe-gtk.h b/src/fe-gtk/fe-gtk.h
index 17d1ab4d..ab776f63 100644
--- a/src/fe-gtk/fe-gtk.h
+++ b/src/fe-gtk/fe-gtk.h
@@ -20,7 +20,7 @@
 #ifndef HEXCHAT_FE_GTK_H
 #define HEXCHAT_FE_GTK_H
 
-#include "../../config.h"
+#include "config.h"
 
 #define DISPLAY_NAME "HexChat"
 
@@ -39,14 +39,13 @@
 
 #define flag_c flag_wid[0]
 #define flag_n flag_wid[1]
-#define flag_r flag_wid[2]
-#define flag_t flag_wid[3]
-#define flag_i flag_wid[4]
-#define flag_m flag_wid[5]
-#define flag_l flag_wid[6]
-#define flag_k flag_wid[7]
-#define flag_b flag_wid[8]
-#define NUM_FLAG_WIDS 9
+#define flag_t flag_wid[2]
+#define flag_i flag_wid[3]
+#define flag_m flag_wid[4]
+#define flag_l flag_wid[5]
+#define flag_k flag_wid[6]
+#define flag_b flag_wid[7]
+#define NUM_FLAG_WIDS 8
 
 #ifdef HAVE_GTK_MAC
 extern GtkosxApplication *osx_app;
@@ -92,9 +91,9 @@ struct server_gui
 	guint chanlist_channels_shown_count;	/* total number of displayed 
 														   channels */
 
-	int chanlist_maxusers;
-	int chanlist_minusers;
-	int chanlist_minusers_downloaded;	/* used by LIST IRC command */
+	guint32 chanlist_maxusers;
+	guint32 chanlist_minusers;
+	guint32 chanlist_minusers_downloaded;	/* used by LIST IRC command */
 	int chanlist_search_type;		/* 0=simple 1=pattern/wildcard 2=regexp */
 	gboolean chanlist_caption_is_stale;
 };
@@ -108,7 +107,7 @@ typedef struct restore_gui
 	void *tab;			/* (chan *) */
 
 	/* information stored when this tab isn't front-most */
-	void *user_model;	/* for filling the GtkTreeView */
+	GtkListStore *user_model;	/* for filling the GtkTreeView */
 	void *buffer;		/* xtext_Buffer */
 	char *input_text;	/* input text buffer (while not-front tab) */
 	char *topic_text;	/* topic GtkEntry buffer */
diff --git a/src/fe-gtk/fe-gtk.vcxproj b/src/fe-gtk/fe-gtk.vcxproj
index 59ab17c6..401518b4 100644
--- a/src/fe-gtk/fe-gtk.vcxproj
+++ b/src/fe-gtk/fe-gtk.vcxproj
@@ -2,6 +2,7 @@
 <Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <PropertyGroup Label="Configuration">

     <PlatformToolset>v120</PlatformToolset>

+    <ConfigurationType>Application</ConfigurationType>

   </PropertyGroup>

   <ItemGroup Label="ProjectConfigurations">

     <ProjectConfiguration Include="Release|Win32">

@@ -19,79 +20,38 @@
     <RootNamespace>fegtk</RootNamespace>

   </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

-    <ConfigurationType>Application</ConfigurationType>

-    <UseDebugLibraries>false</UseDebugLibraries>

-    <CharacterSet>MultiByte</CharacterSet>

-  </PropertyGroup>

-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

-    <ConfigurationType>Application</ConfigurationType>

-    <UseDebugLibraries>false</UseDebugLibraries>

-    <CharacterSet>MultiByte</CharacterSet>

-  </PropertyGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

-  <ImportGroup Label="ExtensionSettings">

-  </ImportGroup>

-  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

-    <Import Project="..\..\win32\hexchat.props" />

-  </ImportGroup>

-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

-    <Import Project="..\..\win32\hexchat.props" />

-  </ImportGroup>

-  <PropertyGroup Label="UserMacros" />

-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

-    <LinkIncremental>false</LinkIncremental>

-    <TargetName>hexchat</TargetName>

-    <OutDir>$(HexChatBin)</OutDir>

-    <IntDir>$(HexChatObj)$(ProjectName)\</IntDir>

-  </PropertyGroup>

-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

-    <LinkIncremental>false</LinkIncremental>

+  <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  <Import Project="..\..\win32\hexchat.props" />

+  <PropertyGroup>

     <TargetName>hexchat</TargetName>

-    <OutDir>$(HexChatBin)</OutDir>

-    <IntDir>$(HexChatObj)$(ProjectName)\</IntDir>

+    <OutDir>$(HexChatRel)</OutDir>

   </PropertyGroup>

   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

     <ClCompile>

-      <PrecompiledHeader>

-      </PrecompiledHeader>

-      <FunctionLevelLinking>true</FunctionLevelLinking>

-      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <!-- WholeProgramOptimization must be turned off for gresource constructors to work, otherwise the .CRT$XCU section is not emitted. -->

+      <WholeProgramOptimization>false</WholeProgramOptimization>

       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>

-      <AdditionalIncludeDirectories>$(SolutionDir)..;$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

-      <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <AdditionalIncludeDirectories>..\common;$(HexChatLib);$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <DisableSpecificWarnings>4244;%(DisableSpecificWarnings)</DisableSpecificWarnings>

     </ClCompile>

     <Link>

-      <SubSystem>Windows</SubSystem>

-      <GenerateDebugInformation>true</GenerateDebugInformation>

-      <EnableCOMDATFolding>true</EnableCOMDATFolding>

-      <OptimizeReferences>true</OptimizeReferences>

-      <AdditionalLibraryDirectories>$(DepsRoot)\lib;$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>

-      <AdditionalDependencies>$(DepLibs);common.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <AdditionalLibraryDirectories>$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>

+      <AdditionalDependencies>$(DepLibs);$(HexChatLib)common.lib;%(AdditionalDependencies)</AdditionalDependencies>

       <EntryPointSymbol>mainCRTStartup</EntryPointSymbol>

     </Link>

   </ItemDefinitionGroup>

   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

     <ClCompile>

-      <PrecompiledHeader>

-      </PrecompiledHeader>

-      <FunctionLevelLinking>true</FunctionLevelLinking>

-      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <!-- WholeProgramOptimization must be turned off for gresource constructors to work, otherwise the .CRT$XCU section is not emitted. -->

+      <WholeProgramOptimization>false</WholeProgramOptimization>

       <PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>

-      <AdditionalIncludeDirectories>$(SolutionDir)..;$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

-      <MultiProcessorCompilation>true</MultiProcessorCompilation>

+      <AdditionalIncludeDirectories>..\common;$(HexChatLib);$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <DisableSpecificWarnings>4244;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>

     </ClCompile>

     <Link>

-      <SubSystem>Windows</SubSystem>

-      <GenerateDebugInformation>true</GenerateDebugInformation>

-      <EnableCOMDATFolding>true</EnableCOMDATFolding>

-      <OptimizeReferences>true</OptimizeReferences>

-      <AdditionalLibraryDirectories>$(DepsRoot)\lib;$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>

-      <AdditionalDependencies>$(DepLibs);common.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <AdditionalLibraryDirectories>$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>

+      <AdditionalDependencies>$(DepLibs);$(HexChatLib)common.lib;%(AdditionalDependencies)</AdditionalDependencies>

       <EntryPointSymbol>mainCRTStartup</EntryPointSymbol>

     </Link>

   </ItemDefinitionGroup>

@@ -99,10 +59,10 @@
     <PreBuildEvent>

       <Command><![CDATA[

 SET SOLUTIONDIR=$(SolutionDir)..\

-powershell -File "$(SolutionDir)..\win32\version-template.ps1" "$(SolutionDir)..\src\fe-gtk\hexchat.rc.tt" "$(SolutionDir)..\src\fe-gtk\hexchat.rc.utf8"

+powershell -File "$(SolutionDir)..\win32\version-template.ps1" "$(SolutionDir)..\src\fe-gtk\hexchat.rc.tt" "$(HexChatLib)hexchat.rc.utf8"

 REM hexchat.rc needs to be in UCS-2 or Resource Compiler will complain

-powershell "Get-Content -Encoding UTF8 '$(SolutionDir)..\src\fe-gtk\hexchat.rc.utf8' | Out-File '$(SolutionDir)..\src\fe-gtk\hexchat.rc'; Remove-Item '$(SolutionDir)..\src\fe-gtk\hexchat.rc.utf8'"

-"$(DepsRoot)\bin\glib-compile-resources.exe" --generate-source --sourcedir "$(DataDir)" --target "$(ProjectDir)resources.c" "$(DataDir)hexchat.gresource.xml"

+powershell "Get-Content -Encoding UTF8 '$(HexChatLib)hexchat.rc.utf8' | Out-File '$(HexChatLib)hexchat.rc'; Remove-Item '$(HexChatLib)hexchat.rc.utf8'"

+"$(DepsRoot)\bin\glib-compile-resources.exe" --generate-source --sourcedir "$(DataDir)" --target "$(HexChatLib)resources.c" "$(DataDir)hexchat.gresource.xml"

       ]]></Command>

       <Message>Build hexchat.rc and gresource file</Message>

     </PreBuildEvent>

@@ -120,6 +80,7 @@ powershell "Get-Content -Encoding UTF8 '$(SolutionDir)..\src\fe-gtk\hexchat.rc.u
     <ClInclude Include="joind.h" />

     <ClInclude Include="maingui.h" />

     <ClInclude Include="menu.h" />

+    <ClInclude Include="notifications\notification-backend.h" />

     <ClInclude Include="notifygui.h" />

     <ClInclude Include="palette.h" />

     <ClInclude Include="pixmaps.h" />

@@ -150,13 +111,15 @@ powershell "Get-Content -Encoding UTF8 '$(SolutionDir)..\src\fe-gtk\hexchat.rc.u
     <ClCompile Include="joind.c" />

     <ClCompile Include="maingui.c" />

     <ClCompile Include="menu.c" />

+    <ClCompile Include="notifications\notification-windows.c" />

     <ClCompile Include="notifygui.c" />

     <ClCompile Include="palette.c" />

     <ClCompile Include="pixmaps.c" />

+    <ClCompile Include="plugin-notification.c" />

     <ClCompile Include="plugin-tray.c" />

     <ClCompile Include="plugingui.c" />

     <ClCompile Include="rawlog.c" />

-    <ClCompile Include="resources.c" />

+    <ClCompile Include="$(HexChatLib)resources.c" />

     <ClCompile Include="servlistgui.c" />

     <ClCompile Include="setup.c" />

     <ClCompile Include="sexy-iso-codes.c" />

@@ -167,11 +130,11 @@ powershell "Get-Content -Encoding UTF8 '$(SolutionDir)..\src\fe-gtk\hexchat.rc.u
     <ClCompile Include="xtext.c" />

   </ItemGroup>

   <ItemGroup>

-    <Manifest Include="hexchat.exe.manifest" />

+    <Manifest Include="..\..\win32\hexchat.exe.manifest" />

   </ItemGroup>

   <ItemGroup>

     <None Include="hexchat.rc.tt" />

-    <ResourceCompile Include="hexchat.rc" />

+    <ResourceCompile Include="$(HexChatLib)hexchat.rc" />

   </ItemGroup>

   <ItemGroup>

     <None Include="..\..\data\icons\hexchat.ico" />

@@ -180,6 +143,4 @@ powershell "Get-Content -Encoding UTF8 '$(SolutionDir)..\src\fe-gtk\hexchat.rc.u
     <Xml Include="..\..\data\hexchat.gresource.xml" />

   </ItemGroup>

   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

-  <ImportGroup Label="ExtensionTargets">

-  </ImportGroup>

-</Project>
\ No newline at end of file
+</Project>

diff --git a/src/fe-gtk/fe-gtk.vcxproj.filters b/src/fe-gtk/fe-gtk.vcxproj.filters
index 4598b1f2..fe211a2d 100644
--- a/src/fe-gtk/fe-gtk.vcxproj.filters
+++ b/src/fe-gtk/fe-gtk.vcxproj.filters
@@ -93,6 +93,9 @@
     <ClInclude Include="setup.h">

       <Filter>Header Files</Filter>

     </ClInclude>

+    <ClInclude Include="notifications\notification-backend.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

   </ItemGroup>

   <ItemGroup>

     <ClCompile Include="ascii.c">

@@ -179,17 +182,23 @@
     <ClCompile Include="xtext.c">

       <Filter>Source Files</Filter>

     </ClCompile>

-    <ClCompile Include="resources.c">

+    <ClCompile Include="$(HexChatLib)resources.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="plugin-notification.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="notifications\notification-windows.c">

       <Filter>Source Files</Filter>

     </ClCompile>

   </ItemGroup>

   <ItemGroup>

-    <Manifest Include="hexchat.exe.manifest">

+    <Manifest Include="..\..\win32\hexchat.exe.manifest">

       <Filter>Resource Files</Filter>

     </Manifest>

   </ItemGroup>

   <ItemGroup>

-    <ResourceCompile Include="hexchat.rc">

+    <ResourceCompile Include="$(HexChatLib)hexchat.rc">

       <Filter>Resource Files</Filter>

     </ResourceCompile>

   </ItemGroup>

diff --git a/src/fe-gtk/fkeys.c b/src/fe-gtk/fkeys.c
index 59086a5e..e762d208 100644
--- a/src/fe-gtk/fkeys.c
+++ b/src/fe-gtk/fkeys.c
@@ -198,6 +198,7 @@ static const struct key_action key_actions[KEY_MAX_ACTIONS + 1] = {
 	"ACCEL=Down\nNext Command\nD1!\nD2!\n\n"\
 	"ACCEL=Up\nLast Command\nD1!\nD2!\n\n"\
 	"ACCEL=Tab\nComplete nick/command\nD1!\nD2!\n\n"\
+	"ACCEL=<Shift>ISO_Left_Tab\nComplete nick/command\nD1:Previous\nD2!\n\n"\
 	"ACCEL=space\nCheck For Replace\nD1!\nD2!\n\n"\
 	"ACCEL=Return\nCheck For Replace\nD1!\nD2!\n\n"\
 	"ACCEL=KP_Enter\nCheck For Replace\nD1!\nD2!\n\n"\
@@ -241,10 +242,8 @@ key_free (gpointer data)
 
 	g_return_if_fail (kb != NULL);
 
-	if (kb->data1)
-		g_free (kb->data1);
-	if (kb->data2)
-		g_free (kb->data2);
+	g_free (kb->data1);
+	g_free (kb->data2);
 	g_free (kb);
 }
 
@@ -323,7 +322,7 @@ key_handle_key_press (GtkWidget *wid, GdkEventKey *evt, session *sess)
 		return FALSE;
 	current_sess = sess;
 
-	if (plugin_emit_keypress (sess, evt->state, evt->keyval, evt->length, evt->string))
+	if (plugin_emit_keypress (sess, evt->state, evt->keyval, gdk_keyval_to_unicode (evt->keyval)))
 		return 1;
 
 	/* maybe the plugin closed this tab? */
@@ -567,7 +566,7 @@ key_dialog_save (GtkWidget *wid, gpointer userdata)
 	{
 		do
 		{
-			kb = (struct key_binding *) g_malloc0 (sizeof (struct key_binding));
+			kb = g_new0 (struct key_binding, 1);
 
 			gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, ACCEL_COLUMN, &accel,
 															ACTION_COLUMN, &actiontext,
@@ -598,7 +597,8 @@ key_dialog_save (GtkWidget *wid, gpointer userdata)
 			else
 				keybind_list = g_slist_append (keybind_list, kb);
 
-		} while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));
+		}
+		while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));
 	}
 
 	if (key_save_kbs () == 0)
@@ -666,6 +666,7 @@ key_dialog_treeview_new (GtkWidget *box)
 	view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
 	gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (view), TRUE);
 	gtk_tree_view_set_enable_search (GTK_TREE_VIEW (view), FALSE);
+	gtk_tree_view_set_reorderable (GTK_TREE_VIEW (view), TRUE);
 
 	g_signal_connect (G_OBJECT (view), "key-press-event",
 					G_CALLBACK (key_dialog_keypress), NULL);
@@ -850,7 +851,7 @@ key_save_kbs (void)
 									 0x180, XOF_DOMODE);
 	if (fd < 0)
 		return 1;
-	write (fd, buf, snprintf (buf, 510, "# HexChat key bindings config file\n\n"));
+	write (fd, buf, g_snprintf (buf, 510, "# HexChat key bindings config file\n\n"));
 
 	while (list)
 	{
@@ -858,17 +859,17 @@ key_save_kbs (void)
 
 		accel_text = gtk_accelerator_name (kb->keyval, kb->mod);
 
-		snprintf (buf, 510, "ACCEL=%s\n%s\n", accel_text, key_actions[kb->action].name);
+		g_snprintf (buf, 510, "ACCEL=%s\n%s\n", accel_text, key_actions[kb->action].name);
 		write (fd, buf, strlen (buf));
 		g_free (accel_text);
 
 		if (kb->data1 && kb->data1[0])
-			write (fd, buf, snprintf (buf, 510, "D1:%s\n", kb->data1));
+			write (fd, buf, g_snprintf (buf, 510, "D1:%s\n", kb->data1));
 		else
 			write (fd, "D1!\n", 4);
 
 		if (kb->data2 && kb->data2[0])
-			write (fd, buf, snprintf (buf, 510, "D2:%s\n", kb->data2));
+			write (fd, buf, g_snprintf (buf, 510, "D2:%s\n", kb->data2));
 		else
 			write (fd, "D2!\n", 4);
 
@@ -946,7 +947,7 @@ key_load_kbs (void)
 	fd = hexchat_open_file ("keybindings.conf", O_RDONLY, 0, 0);
 	if (fd < 0)
 	{
-		ibuf = strdup (default_kb_cfg);
+		ibuf = g_strdup (default_kb_cfg);
 		size = strlen (default_kb_cfg);
 	}
 	else
@@ -957,7 +958,7 @@ key_load_kbs (void)
 			return 1;
 		}
 
-		ibuf = malloc (st.st_size);
+		ibuf = g_malloc(st.st_size);
 		read (fd, ibuf, st.st_size);
 		size = st.st_size;
 		close (fd);
@@ -979,7 +980,7 @@ key_load_kbs (void)
 		switch (state)
 		{
 		case KBSTATE_MOD:
-			kb = (struct key_binding *) g_malloc0 (sizeof (struct key_binding));
+			kb = g_new0 (struct key_binding, 1);
 
 			/* New format */
 			if (strncmp (buf, "ACCEL=", 6) == 0)
@@ -1010,7 +1011,7 @@ key_load_kbs (void)
 			keyval = gdk_keyval_from_name (buf);
 			if (keyval == 0)
 			{
-				free (ibuf);
+				g_free (ibuf);
 				return 2;
 			}
 
@@ -1026,7 +1027,7 @@ key_load_kbs (void)
 
 			if (kb->action == KEY_MAX_ACTIONS + 1)
 			{
-				free (ibuf);
+				g_free (ibuf);
 				return 3;
 			}
 
@@ -1043,7 +1044,7 @@ key_load_kbs (void)
 
 			if (buf[0] != 'D')
 			{
-				free (ibuf);
+				g_free (ibuf);
 				return 4;
 			}
 
@@ -1069,12 +1070,10 @@ key_load_kbs (void)
 				len -= 3;
 				if (state == KBSTATE_DT1)
 				{
-					kb->data1 = g_malloc (len);
-					memcpy (kb->data1, &buf[3], len);
+					kb->data1 = g_strndup (&buf[3], len);
 				} else
 				{
-					kb->data2 = g_malloc (len);
-					memcpy (kb->data2, &buf[3], len);
+					kb->data2 = g_strndup (&buf[3], len);
 				}
 			} else if (buf[2] == '!')
 			{
@@ -1097,12 +1096,12 @@ key_load_kbs (void)
 			continue;
 		}
 	}
-	free (ibuf);
+	g_free (ibuf);
 	return 0;
 
 corrupt_file:
-	free (ibuf);
-	free (kb);
+	g_free (ibuf);
+	g_free (kb);
 	return 5;
 }
 
@@ -1410,9 +1409,6 @@ key_action_tab_clean(void)
 	}
 }
 
-/* Used in the followig completers */
-#define COMP_BUF 2048
-
 /* For use in sorting the user list for completion */
 static int
 talked_recent_cmp (struct User *a, struct User *b)
@@ -1426,16 +1422,31 @@ talked_recent_cmp (struct User *a, struct User *b)
 	return 0;
 }
 
+#define COMP_BUF 2048
+
+static inline glong
+len_to_offset (const char *str, glong len)
+{
+	return g_utf8_pointer_to_offset (str, str + len);
+}
+
+static inline glong
+offset_to_len (const char *str, glong offset)
+{
+	return g_utf8_offset_to_pointer (str, offset) - str;
+}
+
 static int
 key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2,
 							struct session *sess)
 {
-	int len = 0, elen = 0, i = 0, cursor_pos, ent_start = 0, comp = 0, found = 0,
-	    prefix_len, skip_len = 0, is_nick, is_cmd = 0;
-	char buf[COMP_BUF], ent[CHANLEN], *postfix = NULL, *result, *ch;
+	int len = 0, elen = 0, i = 0, cursor_pos, ent_start = 0, comp = 0, prefix_len, skip_len = 0;
+	gboolean is_nick = FALSE, is_cmd = FALSE, found = FALSE, has_nick_prefix = FALSE;
+	char ent[CHANLEN], *postfix = NULL, *result, *ch;
 	GList *list = NULL, *tmp_list = NULL;
 	const char *text;
 	GCompletion *gcomp = NULL;
+	GString *buf;
 
 	/* force the IM Context to reset */
 	SPELL_ENTRY_SET_EDITABLE (t, FALSE);
@@ -1449,8 +1460,6 @@ key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2,
 
 	cursor_pos = SPELL_ENTRY_GET_POS (t);
 
-	buf[0] = 0; /* make sure we don't get garbage in the buffer */
-
 	/* handle "nick: " or "nick " or "#channel "*/
 	ch = g_utf8_find_prev_char(text, g_utf8_offset_to_pointer(text,cursor_pos));
 	if (ch && ch[0] == ' ')
@@ -1489,15 +1498,23 @@ key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2,
 	if (ent_start == 0 && text[0] == prefs.hex_input_command_char[0])
 	{
 		ent_start++;
-		is_cmd = 1;
+		is_cmd = TRUE;
 	}
-	
+	else if (strchr (sess->server->chantypes, text[ent_start]) == NULL)
+	{
+		is_nick = TRUE;
+		if (strchr (sess->server->nick_prefixes, text[ent_start]) != NULL)
+		{
+			if (ent_start == 0)
+				has_nick_prefix = TRUE;
+			ent_start++;
+		}
+	}
+
 	prefix_len = ent_start;
 	elen = cursor_pos - ent_start;
 
 	g_utf8_strncpy (ent, g_utf8_offset_to_pointer (text, prefix_len), elen);
-
-	is_nick = (ent[0] == '#' || ent[0] == '&' || is_cmd) ? 0 : 1;
 	
 	if (sess->type == SESS_DIALOG && is_nick)
 	{
@@ -1505,7 +1522,7 @@ key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2,
 		if (rfc_ncasecmp (sess->channel, ent, elen) == 0)
 		{
 			result =  sess->channel;
-			is_nick = 0;
+			is_nick = FALSE;
 		}
 		else
 			return 2;
@@ -1562,7 +1579,7 @@ key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2,
 			{
 				if(rfc_ncasecmp(list->data, ent, elen) == 0)
 				{
-					found = 1;
+					found = TRUE;
 					break;
 				}
 				list = list->next;
@@ -1600,7 +1617,7 @@ key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2,
 			old_gcomp.elen = elen;
 
 			/* Get the first nick and put out the data for future nickcompletes */
-			if (prefs.hex_completion_amount && g_list_length (list) <= prefs.hex_completion_amount)
+			if (prefs.hex_completion_amount > 0 && g_list_length (list) <= (guint) prefs.hex_completion_amount)
 			{
 				g_free(result);
 				result = (char*)list->data;
@@ -1610,40 +1627,42 @@ key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2,
 				/* bash style completion */
 				if (g_list_next(list) != NULL)
 				{
+					buf = g_string_sized_new (MAX(COMP_BUF, len + NICKLEN));
 					if (strlen (result) > elen) /* the largest common prefix is larger than nick, change the data */
 					{
 						if (prefix_len)
-							g_utf8_strncpy (buf, text, prefix_len);
-						strncat (buf, result, COMP_BUF - prefix_len);
-						cursor_pos = strlen (buf);
+							g_string_append_len (buf, text, offset_to_len (text, prefix_len));
+						g_string_append (buf, result);
+						cursor_pos = buf->len;
 						g_free(result);
 						if (postfix)
 						{
-							strcat (buf, " ");
-							strncat (buf, postfix, COMP_BUF - cursor_pos -1);
+							g_string_append_c (buf, ' ');
+							g_string_append (buf, postfix);
 						}
-						SPELL_ENTRY_SET_TEXT (t, buf);
-						SPELL_ENTRY_SET_POS (t, g_utf8_pointer_to_offset(buf, buf + cursor_pos));
-						buf[0] = 0;
+						SPELL_ENTRY_SET_TEXT (t, buf->str);
+						SPELL_ENTRY_SET_POS (t, len_to_offset (buf->str, cursor_pos));
+						g_string_erase (buf, 0, -1);
 					}
 					else
 						g_free(result);
+
 					while (list)
 					{
-						len = strlen (buf);	/* current buffer */
+						len = buf->len;
 						elen = strlen (list->data);	/* next item to add */
 						if (len + elen + 2 >= COMP_BUF) /* +2 is space + null */
 						{
-							PrintText (sess, buf);
-							buf[0] = 0;
-							len = 0;
+							PrintText (sess, buf->str);
+							g_string_erase (buf, 0, -1);
 						}
-						strcpy (buf + len, (char *) list->data);
-						strcpy (buf + len + elen, " ");
+						g_string_append (buf, (char*)list->data);
+						g_string_append_c (buf, ' ');
 						list = list->next;
 					}
-					PrintText (sess, buf);
+					PrintText (sess, buf->str);
 					g_completion_free(gcomp);
+					g_string_free (buf, TRUE);
 					return 2;
 				}
 				/* Only one matching entry */
@@ -1655,17 +1674,19 @@ key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2,
 	
 	if(result)
 	{
+		buf = g_string_sized_new (len + NICKLEN);
 		if (prefix_len)
-			g_utf8_strncpy(buf, text, prefix_len);
-		strncat (buf, result, COMP_BUF - (prefix_len + 3)); /* make sure nicksuffix and space fits */
-		if(!prefix_len && is_nick)
-			strcat (buf, &prefs.hex_completion_suffix[0]);
-		strcat (buf, " ");
-		cursor_pos = strlen (buf);
+			g_string_append_len (buf, text, offset_to_len (text, prefix_len));
+		g_string_append (buf, result);
+		if((!prefix_len || has_nick_prefix) && is_nick && prefs.hex_completion_suffix[0] != '\0')
+			g_string_append_unichar (buf, g_utf8_get_char_validated (prefs.hex_completion_suffix, -1));
+		g_string_append_c (buf, ' ');
+		cursor_pos = buf->len;
 		if (postfix)
-			strncat (buf, postfix, COMP_BUF - cursor_pos - 2);
-		SPELL_ENTRY_SET_TEXT (t, buf);
-		SPELL_ENTRY_SET_POS (t, g_utf8_pointer_to_offset(buf, buf + cursor_pos));
+			g_string_append (buf, postfix);
+		SPELL_ENTRY_SET_TEXT (t, buf->str);
+		SPELL_ENTRY_SET_POS (t, len_to_offset (buf->str, cursor_pos));
+		g_string_free (buf, TRUE);
 	}
 	if (gcomp)
 		g_completion_free(gcomp);
@@ -1794,10 +1815,10 @@ replace_handle (GtkWidget *t)
 			memcpy (outbuf, text, xlen);
 			outbuf[xlen] = 0;
 			if (postfix_pnt == NULL)
-				snprintf (word, sizeof (word), "%s", pop->cmd);
+				g_snprintf (word, sizeof (word), "%s", pop->cmd);
 			else
-				snprintf (word, sizeof (word), "%s%s", pop->cmd, postfix);
-			strcat (outbuf, word);
+				g_snprintf (word, sizeof (word), "%s%s", pop->cmd, postfix);
+			g_strlcat (outbuf, word, sizeof(outbuf));
 			SPELL_ENTRY_SET_TEXT (t, outbuf);
 			SPELL_ENTRY_SET_POS (t, -1);
 			return;
diff --git a/src/fe-gtk/gtkutil.c b/src/fe-gtk/gtkutil.c
index eabe9c75..e2ca1192 100644
--- a/src/fe-gtk/gtkutil.c
+++ b/src/fe-gtk/gtkutil.c
@@ -62,7 +62,7 @@ static void
 gtkutil_file_req_destroy (GtkWidget * wid, struct file_req *freq)
 {
 	freq->callback (freq->userdata, NULL);
-	free (freq);
+	g_free (freq);
 }
 
 static void
@@ -255,7 +255,7 @@ gtkutil_file_req (const char *title, void *callback, void *userdata, char *filte
 
 	gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (dialog), get_xdir (), NULL);
 
-	freq = malloc (sizeof (struct file_req));
+	freq = g_new (struct file_req, 1);
 	freq->dialog = dialog;
 	freq->flags = flags;
 	freq->callback = callback;
diff --git a/src/fe-gtk/gtkutil.h b/src/fe-gtk/gtkutil.h
index 87beed08..9547cb3b 100644
--- a/src/fe-gtk/gtkutil.h
+++ b/src/fe-gtk/gtkutil.h
@@ -33,14 +33,6 @@ GtkWidget *gtkutil_button (GtkWidget *box, char *stock, char *tip, void *callbac
 void gtkutil_label_new (char *text, GtkWidget * box);
 GtkWidget *gtkutil_entry_new (int max, GtkWidget * box, void *callback,
 										gpointer userdata);
-GtkWidget *gtkutil_clist_new (int columns, char *titles[], GtkWidget * box,
-										int policy, void *select_callback,
-										gpointer select_userdata,
-										void *unselect_callback,
-										gpointer unselect_userdata, int selection_mode);
-int gtkutil_clist_selection (GtkWidget * clist);
-int gtkutil_clist_multiple_selection (GtkWidget * clist,
-													int ** rows, const int max_rows);
 void show_and_unfocus (GtkWidget * wid);
 void gtkutil_set_icon (GtkWidget *win);
 GtkWidget *gtkutil_window_new (char *title, char *role, int width, int height, int flags);
diff --git a/src/fe-gtk/hexchat.exe.manifest b/src/fe-gtk/hexchat.exe.manifest
deleted file mode 100644
index 39c4eb4c..00000000
--- a/src/fe-gtk/hexchat.exe.manifest
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
-  <assemblyIdentity
-    name="HexChat"
-    processorArchitecture="*"
-    version="1.0.0.0"
-    type="win32"
-  />
-  <description>HexChat IRC Client</description>
-  <dependency>
-    <dependentAssembly>
-      <assemblyIdentity
-        type="win32"
-        name="Microsoft.Windows.Common-Controls"
-        version="6.0.0.0"
-        processorArchitecture="*"
-        publicKeyToken="6595b64144ccf1df"
-        language="*"
-      />
-    </dependentAssembly>
-  </dependency>
-</assembly>
diff --git a/src/fe-gtk/hexchat.rc.tt b/src/fe-gtk/hexchat.rc.tt
index 684ddfdb..35b0e6aa 100644
--- a/src/fe-gtk/hexchat.rc.tt
+++ b/src/fe-gtk/hexchat.rc.tt
@@ -1,9 +1,9 @@
 #include <winver.h>

-#include "../../config.h"

+#include "config.h"

 

 #define COMMA_VERSION <#= [string]::Join(',', $versionParts) #>,0

 

-XC_ICON ICON "../../data/icons/hexchat.ico"

+XC_ICON ICON "<#= $env:SOLUTIONDIR -replace '\\', '/' #>data/icons/hexchat.ico"

 

 VS_VERSION_INFO VERSIONINFO

 	FILEVERSION    COMMA_VERSION

@@ -15,6 +15,7 @@ VS_VERSION_INFO VERSIONINFO
 			BEGIN

 				

 				VALUE "FileDescription", "HexChat IRC Client"

+				VALUE "CompanyName", "HexChat"

 				VALUE "ProductName", "HexChat"

 				VALUE "ProductVersion", PACKAGE_VERSION

 				VALUE "FileVersion", PACKAGE_VERSION

diff --git a/src/fe-gtk/joind.c b/src/fe-gtk/joind.c
index 61ce8828..2fdbeb32 100644
--- a/src/fe-gtk/joind.c
+++ b/src/fe-gtk/joind.c
@@ -151,16 +151,16 @@ joind_show_dialog (server *serv)
 	image1 = gtk_image_new_from_stock (GTK_STOCK_NETWORK, GTK_ICON_SIZE_LARGE_TOOLBAR);
 	gtk_widget_show (image1);
 	gtk_box_pack_start (GTK_BOX (hbox1), image1, FALSE, TRUE, 24);
-	gtk_misc_set_alignment (GTK_MISC (image1), 0.5, 0.06);
+	gtk_misc_set_alignment (GTK_MISC (image1), 0.5f, 0.06f);
 
 	vbox2 = gtk_vbox_new (FALSE, 10);
 	gtk_container_set_border_width (GTK_CONTAINER (vbox2), 6);
 	gtk_widget_show (vbox2);
 	gtk_box_pack_start (GTK_BOX (hbox1), vbox2, TRUE, TRUE, 0);
 
-	snprintf (buf2, sizeof (buf2), _("Connection to %s complete."),
+	g_snprintf (buf2, sizeof (buf2), _("Connection to %s complete."),
 				 server_get_network (serv, TRUE));
-	snprintf (buf, sizeof (buf), "\n<b>%s</b>", buf2);
+	g_snprintf (buf, sizeof (buf), "\n<b>%s</b>", buf2);
 	label = gtk_label_new (buf);
 	gtk_widget_show (label);
 	gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0);
@@ -198,7 +198,7 @@ joind_show_dialog (server *serv)
 	gtk_widget_show (entry1);
 	gtk_box_pack_start (GTK_BOX (hbox2), entry1, TRUE, TRUE, 8);
 
-	snprintf (buf, sizeof (buf), "<small>     %s</small>",
+	g_snprintf (buf, sizeof (buf), "<small>     %s</small>",
 				 _("If you know the name of the channel you want to join, enter it here."));
 	label = gtk_label_new (buf);
 	gtk_widget_show (label);
@@ -210,9 +210,8 @@ joind_show_dialog (server *serv)
 	gtk_widget_show (radiobutton3);
 	gtk_box_pack_start (GTK_BOX (vbox2), radiobutton3, FALSE, FALSE, 0);
 	gtk_radio_button_set_group (GTK_RADIO_BUTTON (radiobutton3), radiobutton1_group);
-	radiobutton1_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton3));
 
-	snprintf (buf, sizeof (buf), "<small>     %s</small>",
+	g_snprintf (buf, sizeof (buf), "<small>     %s</small>",
 				 _("Retrieving the Channel-List may take a minute or two."));
 	label = gtk_label_new (buf);
 	gtk_widget_show (label);
@@ -250,7 +249,6 @@ joind_show_dialog (server *serv)
 		if (g_ascii_strcasecmp(((ircnet*)serv->network)->name, "freenode") == 0)
 		{
 			gtk_entry_set_text (GTK_ENTRY (entry1), "#hexchat");
-			gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(radiobutton2), TRUE);
 		}
 
 	gtk_widget_grab_focus (okbutton1);
diff --git a/src/fe-gtk/maingui.c b/src/fe-gtk/maingui.c
index 2d50a98c..d718dba0 100644
--- a/src/fe-gtk/maingui.c
+++ b/src/fe-gtk/maingui.c
@@ -78,7 +78,7 @@ static void mg_link_irctab (session *sess, int focus);
 static session_gui static_mg_gui;
 static session_gui *mg_gui = NULL;	/* the shared irc tab */
 static int ignore_chanmode = FALSE;
-static const char chan_flags[] = { 'c', 'n', 'r', 't', 'i', 'm', 'l', 'k' };
+static const char chan_flags[] = { 'c', 'n', 't', 'i', 'm', 'l', 'k' };
 
 static chan *active_tab = NULL;	/* active tab */
 GtkWidget *parent_window = NULL;			/* the master window */
@@ -312,7 +312,7 @@ mg_inputbox_cb (GtkWidget *igad, session_gui *gui)
 	if (cmd[0] == 0)
 		return;
 
-	cmd = strdup (cmd);
+	cmd = g_strdup (cmd);
 
 	/* avoid recursive loop */
 	ignore = TRUE;
@@ -340,7 +340,7 @@ mg_inputbox_cb (GtkWidget *igad, session_gui *gui)
 	if (sess)
 		handle_multiline (sess, cmd, TRUE, FALSE);
 
-	free (cmd);
+	g_free (cmd);
 }
 
 static gboolean
@@ -393,42 +393,42 @@ fe_set_title (session *sess)
 	switch (type)
 	{
 	case SESS_DIALOG:
-		snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME": %s %s @ %s",
+		g_snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME": %s %s @ %s",
 					 _("Dialog with"), sess->channel, server_get_network (sess->server, TRUE));
 		break;
 	case SESS_SERVER:
-		snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME": %s @ %s",
+		g_snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME": %s @ %s",
 					 sess->server->nick, server_get_network (sess->server, TRUE));
 		break;
 	case SESS_CHANNEL:
 		/* don't display keys in the titlebar */
 		if (prefs.hex_gui_win_modes)
 		{
-			snprintf (tbuf, sizeof (tbuf),
+			g_snprintf (tbuf, sizeof (tbuf),
 						 DISPLAY_NAME": %s @ %s / %s (%s)",
 						 sess->server->nick, server_get_network (sess->server, TRUE),
 						 sess->channel, sess->current_modes ? sess->current_modes : "");
 		}
 		else
 		{
-			snprintf (tbuf, sizeof (tbuf),
+			g_snprintf (tbuf, sizeof (tbuf),
 						 DISPLAY_NAME": %s @ %s / %s",
 						 sess->server->nick, server_get_network (sess->server, TRUE),
 						 sess->channel);
 		}
 		if (prefs.hex_gui_win_ucount)
 		{
-			snprintf (tbuf + strlen (tbuf), 9, " (%d)", sess->total);
+			g_snprintf (tbuf + strlen (tbuf), 9, " (%d)", sess->total);
 		}
 		break;
 	case SESS_NOTICES:
 	case SESS_SNOTICES:
-		snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME": %s @ %s (notices)",
+		g_snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME": %s @ %s (notices)",
 					 sess->server->nick, server_get_network (sess->server, TRUE));
 		break;
 	default:
 	def:
-		snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME);
+		g_snprintf (tbuf, sizeof (tbuf), DISPLAY_NAME);
 		gtk_window_set_title (GTK_WINDOW (sess->gui->window), tbuf);
 		return;
 	}
@@ -557,7 +557,7 @@ static int
 mg_progressbar_update (GtkWidget *bar)
 {
 	static int type = 0;
-	static float pos = 0;
+	static gdouble pos = 0;
 
 	pos += 0.05;
 	if (pos >= 0.99)
@@ -609,14 +609,14 @@ mg_unpopulate (session *sess)
 	gui = sess->gui;
 	res = sess->res;
 
-	res->input_text = strdup (SPELL_ENTRY_GET_TEXT (gui->input_box));
-	res->topic_text = strdup (gtk_entry_get_text (GTK_ENTRY (gui->topic_entry)));
-	res->limit_text = strdup (gtk_entry_get_text (GTK_ENTRY (gui->limit_entry)));
-	res->key_text = strdup (gtk_entry_get_text (GTK_ENTRY (gui->key_entry)));
+	res->input_text = g_strdup (SPELL_ENTRY_GET_TEXT (gui->input_box));
+	res->topic_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (gui->topic_entry)));
+	res->limit_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (gui->limit_entry)));
+	res->key_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (gui->key_entry)));
 	if (gui->laginfo)
-		res->lag_text = strdup (gtk_label_get_text (GTK_LABEL (gui->laginfo)));
+		res->lag_text = g_strdup (gtk_label_get_text (GTK_LABEL (gui->laginfo)));
 	if (gui->throttleinfo)
-		res->queue_text = strdup (gtk_label_get_text (GTK_LABEL (gui->throttleinfo)));
+		res->queue_text = g_strdup (gtk_label_get_text (GTK_LABEL (gui->throttleinfo)));
 
 	for (i = 0; i < NUM_FLAG_WIDS - 1; i++)
 		res->flag_wid_state[i] = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gui->flag_wid[i]));
@@ -645,7 +645,7 @@ mg_restore_label (GtkWidget *label, char **text)
 	if (*text)
 	{
 		gtk_label_set_text (GTK_LABEL (label), *text);
-		free (*text);
+		g_free (*text);
 		*text = NULL;
 	} else
 	{
@@ -659,7 +659,7 @@ mg_restore_entry (GtkWidget *entry, char **text)
 	if (*text)
 	{
 		gtk_entry_set_text (GTK_ENTRY (entry), *text);
-		free (*text);
+		g_free (*text);
 		*text = NULL;
 	} else
 	{
@@ -674,7 +674,7 @@ mg_restore_speller (GtkWidget *entry, char **text)
 	if (*text)
 	{
 		SPELL_ENTRY_SET_TEXT (entry, *text);
-		free (*text);
+		g_free (*text);
 		*text = NULL;
 	} else
 	{
@@ -1096,8 +1096,11 @@ mg_tab_close (session *sess)
 	else
 	{
 		for (i = 0, list = sess_list; list; list = list->next)
-			if (((session *)list->data)->server == sess->server)
+		{
+			session *s = (session*)list->data;
+			if (s->server == sess->server && (s->type == SESS_CHANNEL || s->type == SESS_DIALOG))
 				i++;
+		}
 		dialog = gtk_message_dialog_new (GTK_WINDOW (parent_window), 0,
 						GTK_MESSAGE_WARNING, GTK_BUTTONS_OK_CANCEL,
 						_("This server still has %d channels or dialogs associated with it. "
@@ -1331,8 +1334,7 @@ mg_close_gen (chan *ch, GtkWidget *box)
 {
 	char *title = g_object_get_data (G_OBJECT (box), "title");
 
-	if (title)
-		free (title);
+	g_free (title);
 	if (!ch)
 		ch = g_object_get_data (G_OBJECT (box), "ch");
 	if (ch)
@@ -1568,7 +1570,7 @@ mg_create_tabmenu (session *sess, GdkEventButton *event, chan *ch)
 	if (sess)
 	{
 		char *name = g_markup_escape_text (sess->channel[0] ? sess->channel : _("<none>"), -1);
-		snprintf (buf, sizeof (buf), "<span foreground=\"#3344cc\"><b>%s</b></span>", name);
+		g_snprintf (buf, sizeof (buf), "<span foreground=\"#3344cc\"><b>%s</b></span>", name);
 		g_free (name);
 
 		item = gtk_menu_item_new_with_label ("");
@@ -1617,7 +1619,7 @@ static gboolean
 mg_tab_contextmenu_cb (chanview *cv, chan *ch, int tag, gpointer ud, GdkEventButton *event)
 {
 	/* middle-click or shift-click to close a tab */
-	if ((event->button == 2 || (event->button == 1 && event->state & STATE_SHIFT))
+	if (((prefs.hex_gui_tab_middleclose && event->button == 2) || (event->button == 1 && event->state & STATE_SHIFT))
 		&& event->type == GDK_BUTTON_PRESS)
 	{
 		mg_xbutton_cb (cv, ch, tag, ud);
@@ -1640,7 +1642,7 @@ mg_dnd_drop_file (session *sess, char *target, char *uri)
 {
 	char *p, *data, *next, *fname;
 
-	p = data = strdup (uri);
+	p = data = g_strdup (uri);
 	while (*p)
 	{
 		next = strchr (p, '\r');
@@ -1652,7 +1654,7 @@ mg_dnd_drop_file (session *sess, char *target, char *uri)
 			if (fname)
 			{
 				/* dcc_send() expects utf-8 */
-				p = hexchat_filename_to_utf8 (fname, -1, 0, 0, 0);
+				p = g_filename_from_utf8 (fname, -1, 0, 0, 0);
 				if (p)
 				{
 					dcc_send (sess, target, p, prefs.hex_dcc_max_send_cps, 0);
@@ -1667,7 +1669,7 @@ mg_dnd_drop_file (session *sess, char *target, char *uri)
 		if (*p == '\n')
 			p++;
 	}
-	free (data);
+	g_free (data);
 
 }
 
@@ -1716,7 +1718,7 @@ mg_add_chan (session *sess)
 	{
 		sess->res->buffer = gtk_xtext_buffer_new (GTK_XTEXT (sess->gui->xtext));
 		gtk_xtext_set_time_stamp (sess->res->buffer, prefs.hex_stamp_text);
-		sess->res->user_model = userlist_create_model ();
+		sess->res->user_model = userlist_create_model (sess);
 	}
 }
 
@@ -1837,7 +1839,7 @@ mg_changui_destroy (session *sess)
 		/* it fixes: Gdk-CRITICAL **: gdk_colormap_get_screen: */
 		/*           assertion `GDK_IS_COLORMAP (cmap)' failed */
 		ret = sess->gui->window;
-		free (sess->gui);
+		g_free (sess->gui);
 		sess->gui = NULL;
 	}
 	return ret;
@@ -1941,7 +1943,7 @@ flagl_hit (GtkWidget * wid, struct session *sess)
 				gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid), FALSE);
 				return;
 			}
-			snprintf (modes, sizeof (modes), "+l %d", atoi (limit_str));
+			g_snprintf (modes, sizeof (modes), "+l %d", atoi (limit_str));
 			serv->p_mode (serv, sess->channel, modes);
 			serv->p_join_info (serv, sess->channel);
 		}
@@ -1957,7 +1959,7 @@ flagk_hit (GtkWidget * wid, struct session *sess)
 
 	if (serv->connected && sess->channel[0])
 	{
-		snprintf (modes, sizeof (modes), "-k %s", 
+		g_snprintf (modes, sizeof (modes), "-k %s", 
 			  gtk_entry_get_text (GTK_ENTRY (sess->gui->key_entry)));
 
 		if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (wid)))
@@ -2001,17 +2003,24 @@ mg_flagbutton_cb (GtkWidget *but, char *flag)
 static GtkWidget *
 mg_create_flagbutton (char *tip, GtkWidget *box, char *face)
 {
-	GtkWidget *wid;
+	GtkWidget *btn, *lbl;
+	char label_markup[16];
+
+	g_snprintf (label_markup, sizeof(label_markup), "<tt>%s</tt>", face);
+	lbl = gtk_label_new (NULL);
+	gtk_label_set_markup (GTK_LABEL(lbl), label_markup);
 
-	wid = gtk_toggle_button_new_with_label (face);
-	gtk_widget_set_size_request (wid, 18, 0);
-	gtk_widget_set_tooltip_text (wid, tip);
-	gtk_box_pack_start (GTK_BOX (box), wid, 0, 0, 0);
-	g_signal_connect (G_OBJECT (wid), "toggled",
+	btn = gtk_toggle_button_new ();
+	gtk_widget_set_size_request (btn, -1, 0);
+	gtk_widget_set_tooltip_text (btn, tip);
+	gtk_container_add (GTK_CONTAINER(btn), lbl);
+
+	gtk_box_pack_start (GTK_BOX (box), btn, 0, 0, 0);
+	g_signal_connect (G_OBJECT (btn), "toggled",
 							G_CALLBACK (mg_flagbutton_cb), face);
-	show_and_unfocus (wid);
+	show_and_unfocus (btn);
 
-	return wid;
+	return btn;
 }
 
 static void
@@ -2023,7 +2032,7 @@ mg_key_entry_cb (GtkWidget * igad, gpointer userdata)
 
 	if (serv->connected && sess->channel[0])
 	{
-		snprintf (modes, sizeof (modes), "+k %s",
+		g_snprintf (modes, sizeof (modes), "+k %s",
 				gtk_entry_get_text (GTK_ENTRY (igad)));
 		serv->p_mode (serv, sess->channel, modes);
 		serv->p_join_info (serv, sess->channel);
@@ -2046,7 +2055,7 @@ mg_limit_entry_cb (GtkWidget * igad, gpointer userdata)
 			gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sess->gui->flag_l), FALSE);
 			return;
 		}
-		snprintf (modes, sizeof(modes), "+l %d", 
+		g_snprintf (modes, sizeof(modes), "+l %d", 
 				atoi (gtk_entry_get_text (GTK_ENTRY (igad))));
 		serv->p_mode (serv, sess->channel, modes);
 		serv->p_join_info (serv, sess->channel);
@@ -2066,7 +2075,6 @@ mg_create_chanmodebuttons (session_gui *gui, GtkWidget *box)
 {
 	gui->flag_c = mg_create_flagbutton (_("Filter Colors"), box, "c");
 	gui->flag_n = mg_create_flagbutton (_("No outside messages"), box, "n");
-	gui->flag_r = mg_create_flagbutton (_("Registered Only"), box, "r");
 	gui->flag_t = mg_create_flagbutton (_("Topic Protection"), box, "t");
 	gui->flag_i = mg_create_flagbutton (_("Invite Only"), box, "i");
 	gui->flag_m = mg_create_flagbutton (_("Moderated"), box, "m");
@@ -2287,7 +2295,7 @@ mg_word_clicked (GtkWidget *xtext, char *word, GdkEventButton *even)
 	case WORD_EMAIL:
 		word[end] = 0;
 		word += start;
-		tmp = g_strdup_printf("mailto:%s", word + (ispunct (*word)? 1: 0));
+		tmp = g_strdup_printf ("mailto:%s", word + (ispunct (*word) ? 1 : 0));
 		menu_urlmenu (even, tmp);
 		g_free (tmp);
 		break;
@@ -2597,7 +2605,7 @@ mg_change_nick (int cancel, char *text, gpointer userdata)
 
 	if (!cancel)
 	{
-		snprintf (buf, sizeof (buf), "nick %s", text);
+		g_snprintf (buf, sizeof (buf), "nick %s", text);
 		handle_command (current_sess, buf, FALSE);
 	}
 }
@@ -2940,7 +2948,7 @@ mg_create_search(session *sess, GtkWidget *box)
 	gtk_box_pack_start(GTK_BOX(gui->shbox), next, FALSE, FALSE, 0);
 	g_signal_connect(G_OBJECT(next), "clicked", G_CALLBACK(mg_search_handle_next), sess);
 
-	highlight = gtk_check_button_new_with_mnemonic (_("Highlight _all"));
+	highlight = gtk_check_button_new_with_mnemonic (_("_Highlight all"));
 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(highlight), prefs.hex_text_search_highlight_all);
 	gtk_widget_set_can_focus (highlight, FALSE);
 	g_signal_connect (G_OBJECT (highlight), "toggled", G_CALLBACK (search_set_option), &prefs.hex_text_search_highlight_all);
@@ -3165,7 +3173,7 @@ mg_create_topwindow (session *sess)
 		sess->res->buffer = gtk_xtext_buffer_new (GTK_XTEXT (sess->gui->xtext));
 		gtk_xtext_buffer_show (GTK_XTEXT (sess->gui->xtext), sess->res->buffer, TRUE);
 		gtk_xtext_set_time_stamp (sess->res->buffer, prefs.hex_stamp_text);
-		sess->res->user_model = userlist_create_model ();
+		sess->res->user_model = userlist_create_model (sess);
 	}
 
 	userlist_show (sess);
@@ -3332,7 +3340,7 @@ mg_add_generic_tab (char *name, char *title, void *family, GtkWidget *box)
 	ch = chanview_add (mg_gui->chanview, name, NULL, box, TRUE, TAG_UTIL, pix_tree_util);
 	chan_set_color (ch, plain_list);
 	/* FIXME: memory leak */
-	g_object_set_data (G_OBJECT (box), "title", strdup (title));
+	g_object_set_data (G_OBJECT (box), "title", g_strdup (title));
 	g_object_set_data (G_OBJECT (box), "ch", ch);
 
 	if (prefs.hex_gui_tab_newtofront)
@@ -3395,7 +3403,7 @@ fe_clear_channel (session *sess)
 	{
 		if (sess->res->topic_text)
 		{
-			free (sess->res->topic_text);
+			g_free (sess->res->topic_text);
 			sess->res->topic_text = NULL;
 		}
 	}
@@ -3506,32 +3514,26 @@ mg_changui_new (session *sess, restore_gui *res, int tab, int focus)
 {
 	int first_run = FALSE;
 	session_gui *gui;
-	struct User *user = NULL;
 
-	if (!res)
+	if (res == NULL)
 	{
-		res = malloc (sizeof (restore_gui));
-		memset (res, 0, sizeof (restore_gui));
+		res = g_new0 (restore_gui, 1);
 	}
 
 	sess->res = res;
 
-	if (!sess->server->front_session)
+	if (sess->server->front_session == NULL)
+	{
 		sess->server->front_session = sess;
-
-	if (!is_channel (sess->server, sess->channel))
-		user = userlist_find_global (sess->server, sess->channel);
+	}
 
 	if (!tab)
 	{
-		gui = malloc (sizeof (session_gui));
-		memset (gui, 0, sizeof (session_gui));
+		gui = g_new0 (session_gui, 1);
 		gui->is_tab = FALSE;
 		sess->gui = gui;
 		mg_create_topwindow (sess);
 		fe_set_title (sess);
-		if (user && user->hostname)
-			set_topic (sess, user->hostname, user->hostname);
 		return;
 	}
 
@@ -3551,9 +3553,6 @@ mg_changui_new (session *sess, restore_gui *res, int tab, int focus)
 		gui->is_tab = TRUE;
 	}
 
-	if (user && user->hostname)
-		set_topic (sess, user->hostname, user->hostname);
-
 	mg_add_chan (sess);
 
 	if (first_run || (prefs.hex_gui_tab_newtofront == FOCUS_NEW_ONLY_ASKED && focus)
@@ -3631,8 +3630,8 @@ mg_set_title (GtkWidget *vbox, char *title) /* for non-irc tab/window only */
 	old = g_object_get_data (G_OBJECT (vbox), "title");
 	if (old)
 	{
-		g_object_set_data (G_OBJECT (vbox), "title", strdup (title));
-		free (old);
+		g_object_set_data (G_OBJECT (vbox), "title", g_strdup (title));
+		g_free (old);
 	} else
 	{
 		gtk_window_set_title (GTK_WINDOW (vbox), title);
@@ -3650,7 +3649,7 @@ fe_server_callback (server *serv)
 	if (serv->gui->rawlog_window)
 		mg_close_gen (NULL, serv->gui->rawlog_window);
 
-	free (serv->gui);
+	g_free (serv->gui);
 }
 
 /* called when a session is being killed */
@@ -3661,34 +3660,21 @@ fe_session_callback (session *sess)
 	if (sess->res->banlist && sess->res->banlist->window)
 		mg_close_gen (NULL, sess->res->banlist->window);
 
-	if (sess->res->input_text)
-		free (sess->res->input_text);
-
-	if (sess->res->topic_text)
-		free (sess->res->topic_text);
-
-	if (sess->res->limit_text)
-		free (sess->res->limit_text);
-
-	if (sess->res->key_text)
-		free (sess->res->key_text);
-
-	if (sess->res->queue_text)
-		free (sess->res->queue_text);
-	if (sess->res->queue_tip)
-		free (sess->res->queue_tip);
-
-	if (sess->res->lag_text)
-		free (sess->res->lag_text);
-	if (sess->res->lag_tip)
-		free (sess->res->lag_tip);
+	g_free (sess->res->input_text);
+	g_free (sess->res->topic_text);
+	g_free (sess->res->limit_text);
+	g_free (sess->res->key_text);
+	g_free (sess->res->queue_text);
+	g_free (sess->res->queue_tip);
+	g_free (sess->res->lag_text);
+	g_free (sess->res->lag_tip);
 
 	if (sess->gui->bartag)
 		fe_timeout_remove (sess->gui->bartag);
 
 	if (sess->gui != &static_mg_gui)
-		free (sess->gui);
-	free (sess->res);
+		g_free (sess->gui);
+	g_free (sess->res);
 }
 
 /* ===== DRAG AND DROP STUFF ===== */
diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c
index 945f6360..902af92e 100644
--- a/src/fe-gtk/menu.c
+++ b/src/fe-gtk/menu.c
@@ -137,7 +137,7 @@ nick_command_parse (session *sess, char *cmd, char *nick, char *allnick)
 
 	/* this can't overflow, since popup->cmd is only 256 */
 	len = strlen (cmd) + strlen (nick) + strlen (allnick) + 512;
-	buf = malloc (len);
+	buf = g_malloc (len);
 
 	auto_insert (buf, len, cmd, 0, 0, allnick, sess->channel, "",
 					 server_get_network (sess->server, TRUE), host,
@@ -145,7 +145,7 @@ nick_command_parse (session *sess, char *cmd, char *nick, char *allnick)
 
 	nick_command (sess, buf);
 
-	free (buf);
+	g_free (buf);
 }
 
 /* userlist button has been clicked */
@@ -166,11 +166,12 @@ userlist_button_cb (GtkWidget * button, char *cmd)
 	if (sess->type == SESS_DIALOG)
 	{
 		/* fake a selection */
-		nicks = malloc (sizeof (char *) * 2);
+		nicks = g_new (char *, 2);
 		nicks[0] = g_strdup (sess->channel);
 		nicks[1] = NULL;
 		num_sel = 1;
-	} else
+	}
+	else
 	{
 		/* find number of selected rows */
 		nicks = userlist_selection_list (sess->gui->user_tree, &num_sel);
@@ -178,14 +179,13 @@ userlist_button_cb (GtkWidget * button, char *cmd)
 		{
 			nick_command_parse (sess, cmd, "", "");
 
-			if (nicks)
-				free (nicks);
+			g_free (nicks);
 			return;
 		}
 	}
 
 	/* create "allnicks" string */
-	allnicks = malloc (((NICKLEN + 1) * num_sel) + 1);
+	allnicks = g_malloc (((NICKLEN + 1) * num_sel) + 1);
 	*allnicks = 0;
 
 	i = 0;
@@ -218,8 +218,8 @@ userlist_button_cb (GtkWidget * button, char *cmd)
 		g_free (nicks[num_sel]);
 	}
 
-	free (nicks);
-	free (allnicks);
+	g_free (nicks);
+	g_free (allnicks);
 }
 
 /* a popup-menu-item has been selected */
@@ -393,9 +393,9 @@ toggle_cb (GtkWidget *item, char *pref_name)
 	char buf[256];
 
 	if (GTK_CHECK_MENU_ITEM (item)->active)
-		snprintf (buf, sizeof (buf), "set %s 1", pref_name);
+		g_snprintf (buf, sizeof (buf), "set %s 1", pref_name);
 	else
-		snprintf (buf, sizeof (buf), "set %s 0", pref_name);
+		g_snprintf (buf, sizeof (buf), "set %s 0", pref_name);
 
 	handle_command (current_sess, buf, FALSE);
 }
@@ -403,12 +403,11 @@ toggle_cb (GtkWidget *item, char *pref_name)
 static int
 is_in_path (char *cmd)
 {
-	char *prog = g_strdup (cmd + 1);	/* 1st char is "!" */
-	char *path, *orig;
+	char *orig = g_strdup (cmd + 1);	/* 1st char is "!" */
+	char *prog = orig;
 	char **argv;
 	int argc;
 
-	orig = prog; /* save for free()ing */
 	/* special-case these default entries. */
 	/*                  123456789012345678 */
 	if (strncmp (prog, "gnome-terminal -x ", 18) == 0)
@@ -417,15 +416,14 @@ is_in_path (char *cmd)
 
 	if (g_shell_parse_argv (prog, &argc, &argv, NULL))
 	{
-		path = g_find_program_in_path (argv[0]);
+		char *path = g_find_program_in_path (argv[0]);
+		g_strfreev (argv);
 		if (path)
 		{
 			g_free (path);
 			g_free (orig);
-			g_strfreev (argv);
 			return 1;
 		}
-		g_strfreev (argv);
 	}
 
 	g_free (orig);
@@ -588,7 +586,7 @@ menu_nickinfo_cb (GtkWidget *menu, session *sess)
 		return;
 
 	/* issue a /WHOIS */
-	snprintf (buf, sizeof (buf), "WHOIS %s %s", str_copy, str_copy);
+	g_snprintf (buf, sizeof (buf), "WHOIS %s %s", str_copy, str_copy);
 	handle_command (sess, buf, FALSE);
 	/* and hide the output */
 	sess->server->skip_next_whois = 1;
@@ -614,30 +612,30 @@ menu_create_nickinfo_menu (struct User *user, GtkWidget *submenu)
 
 	/* let the translators tweak this if need be */
 	fmt = _("<tt><b>%-11s</b></tt> %s");
-	snprintf (unknown, sizeof (unknown), "<i>%s</i>", _("Unknown"));
+	g_snprintf (unknown, sizeof (unknown), "<i>%s</i>", _("Unknown"));
 
 	if (user->realname)
 	{
 		real = strip_color (user->realname, -1, STRIP_ALL|STRIP_ESCMARKUP);
-		snprintf (buf, sizeof (buf), fmt, _("Real Name:"), real);
+		g_snprintf (buf, sizeof (buf), fmt, _("Real Name:"), real);
 		g_free (real);
 	} else
 	{
-		snprintf (buf, sizeof (buf), fmt, _("Real Name:"), unknown);
+		g_snprintf (buf, sizeof (buf), fmt, _("Real Name:"), unknown);
 	}
 	item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0);
 	g_signal_connect (G_OBJECT (item), "activate",
 							G_CALLBACK (copy_to_clipboard_cb), 
 							user->realname ? user->realname : unknown);
 
-	snprintf (buf, sizeof (buf), fmt, _("User:"),
+	g_snprintf (buf, sizeof (buf), fmt, _("User:"),
 				 user->hostname ? user->hostname : unknown);
 	item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0);
 	g_signal_connect (G_OBJECT (item), "activate",
 							G_CALLBACK (copy_to_clipboard_cb), 
 							user->hostname ? user->hostname : unknown);
 	
-	snprintf (buf, sizeof (buf), fmt, _("Account:"),
+	g_snprintf (buf, sizeof (buf), fmt, _("Account:"),
 				 user->account ? user->account : unknown);
 	item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0);
 	g_signal_connect (G_OBJECT (item), "activate",
@@ -647,13 +645,13 @@ menu_create_nickinfo_menu (struct User *user, GtkWidget *submenu)
 	users_country = country (user->hostname);
 	if (users_country)
 	{
-		snprintf (buf, sizeof (buf), fmt, _ ("Country:"), users_country);
+		g_snprintf (buf, sizeof (buf), fmt, _ ("Country:"), users_country);
 		item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0);
 		g_signal_connect (G_OBJECT (item), "activate",
 			G_CALLBACK (copy_to_clipboard_cb), users_country);
 	}
 
-	snprintf (buf, sizeof (buf), fmt, _("Server:"),
+	g_snprintf (buf, sizeof (buf), fmt, _("Server:"),
 				 user->servername ? user->servername : unknown);
 	item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0);
 	g_signal_connect (G_OBJECT (item), "activate",
@@ -664,12 +662,12 @@ menu_create_nickinfo_menu (struct User *user, GtkWidget *submenu)
 	{
 		char min[96];
 
-		snprintf (min, sizeof (min), _("%u minutes ago"),
+		g_snprintf (min, sizeof (min), _("%u minutes ago"),
 					(unsigned int) ((time (0) - user->lasttalk) / 60));
-		snprintf (buf, sizeof (buf), fmt, _("Last Msg:"), min);
+		g_snprintf (buf, sizeof (buf), fmt, _("Last Msg:"), min);
 	} else
 	{
-		snprintf (buf, sizeof (buf), fmt, _("Last Msg:"), unknown);
+		g_snprintf (buf, sizeof (buf), fmt, _("Last Msg:"), unknown);
 	}
 	menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0);
 
@@ -679,7 +677,7 @@ menu_create_nickinfo_menu (struct User *user, GtkWidget *submenu)
 		if (away)
 		{
 			char *msg = strip_color (away->message ? away->message : unknown, -1, STRIP_ALL|STRIP_ESCMARKUP);
-			snprintf (buf, sizeof (buf), fmt, _("Away Msg:"), msg);
+			g_snprintf (buf, sizeof (buf), fmt, _("Away Msg:"), msg);
 			g_free (msg);
 			item = menu_quick_item (0, buf, submenu, XCMENU_MARKUP, 0, 0);
 			g_signal_connect (G_OBJECT (item), "activate",
@@ -728,16 +726,15 @@ menu_nickmenu (session *sess, GdkEventButton *event, char *nick, int num_sel)
 	struct User *user;
 	GtkWidget *submenu, *menu = gtk_menu_new ();
 
-	if (str_copy)
-		free (str_copy);
-	str_copy = strdup (nick);
+	g_free (str_copy);
+	str_copy = g_strdup (nick);
 
 	submenu_list = 0;	/* first time through, might not be 0 */
 
 	/* more than 1 nick selected? */
 	if (num_sel > 1)
 	{
-		snprintf (buf, sizeof (buf), _("%d nicks selected."), num_sel);
+		g_snprintf (buf, sizeof (buf), _("%d nicks selected."), num_sel);
 		menu_quick_item (0, buf, menu, 0, 0, 0);
 		menu_quick_item (0, 0, menu, XCMENU_SHADED, 0, 0);
 	} else
@@ -938,7 +935,7 @@ open_url_cb (GtkWidget *item, char *url)
 	char buf[512];
 
 	/* pass this to /URL so it can handle irc:// */
-	snprintf (buf, sizeof (buf), "URL %s", url);
+	g_snprintf (buf, sizeof (buf), "URL %s", url);
 	handle_command (current_sess, buf, FALSE);
 }
 
@@ -948,20 +945,19 @@ menu_urlmenu (GdkEventButton *event, char *url)
 	GtkWidget *menu;
 	char *tmp, *chop;
 
-	if (str_copy)
-		free (str_copy);
-	str_copy = strdup (url);
+	g_free (str_copy);
+	str_copy = g_strdup (url);
 
 	menu = gtk_menu_new ();
 	/* more than 51 chars? Chop it */
 	if (g_utf8_strlen (str_copy, -1) >= 52)
 	{
-		tmp = strdup (str_copy);
+		tmp = g_strdup (str_copy);
 		chop = g_utf8_offset_to_pointer (tmp, 48);
 		chop[0] = chop[1] = chop[2] = '.';
 		chop[3] = 0;
 		menu_quick_item (0, tmp, menu, XCMENU_SHADED, 0, 0);
-		free (tmp);
+		g_free (tmp);
 	} else
 	{
 		menu_quick_item (0, str_copy, menu, XCMENU_SHADED, 0, 0);
@@ -988,7 +984,7 @@ menu_chan_cycle (GtkWidget * menu, char *chan)
 
 	if (current_sess)
 	{
-		snprintf (tbuf, sizeof tbuf, "CYCLE %s", chan);
+		g_snprintf (tbuf, sizeof tbuf, "CYCLE %s", chan);
 		handle_command (current_sess, tbuf, FALSE);
 	}
 }
@@ -1000,7 +996,7 @@ menu_chan_part (GtkWidget * menu, char *chan)
 
 	if (current_sess)
 	{
-		snprintf (tbuf, sizeof tbuf, "part %s", chan);
+		g_snprintf (tbuf, sizeof tbuf, "part %s", chan);
 		handle_command (current_sess, tbuf, FALSE);
 	}
 }
@@ -1012,7 +1008,7 @@ menu_chan_join (GtkWidget * menu, char *chan)
 
 	if (current_sess)
 	{
-		snprintf (tbuf, sizeof tbuf, "join %s", chan);
+		g_snprintf (tbuf, sizeof tbuf, "join %s", chan);
 		handle_command (current_sess, tbuf, FALSE);
 	}
 }
@@ -1026,9 +1022,8 @@ menu_chanmenu (struct session *sess, GdkEventButton * event, char *chan)
 	if (find_channel (sess->server, chan))
 		is_joined = TRUE;
 
-	if (str_copy)
-		free (str_copy);
-	str_copy = strdup (chan);
+	g_free (str_copy);
+	str_copy = g_strdup (chan);
 
 	menu = gtk_menu_new ();
 
@@ -1074,9 +1069,8 @@ menu_addfavoritemenu (server *serv, GtkWidget *menu, char *channel, gboolean ist
 
 	if (channel != str_copy)
 	{
-		if (str_copy)
-			free (str_copy);
-		str_copy = strdup (channel);
+		g_free (str_copy);
+		str_copy = g_strdup (channel);
 	}
 	
 	if (istree)
@@ -1717,7 +1711,7 @@ menu_about (GtkWidget *wid, gpointer sess)
 					"You should have received a copy of the GNU General Public License\n" \
 					"along with this program. If not, see <http://www.gnu.org/licenses/>";
 
-	g_snprintf  (comment, sizeof(comment), "Compiled: "__DATE__"\n"
+	g_snprintf  (comment, sizeof(comment), ""
 #ifdef WIN32
 				"Portable Mode: %s\n"
 				"Build Type: x%d\n"
diff --git a/src/fe-gtk/notifications/notification-backend.h b/src/fe-gtk/notifications/notification-backend.h
new file mode 100644
index 00000000..b60ced4e
--- /dev/null
+++ b/src/fe-gtk/notifications/notification-backend.h
@@ -0,0 +1,27 @@
+/* HexChat
+ * Copyright (C) 2015 Patrick Griffis.
+ *
+ * This program 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef HEXCHAT_PLUGIN_NOTIFICATION_BACKEND_H
+#define HEXCHAT_PLUGIN_NOTIFICATION_BACKEND_H
+
+int notification_backend_supported (void);
+void notification_backend_show (const char *title, const char *text);
+int notification_backend_init (void);
+void notification_backend_deinit (void);
+
+#endif
diff --git a/src/fe-gtk/notifications/notification-dummy.c b/src/fe-gtk/notifications/notification-dummy.c
new file mode 100644
index 00000000..022443bf
--- /dev/null
+++ b/src/fe-gtk/notifications/notification-dummy.c
@@ -0,0 +1,39 @@
+/* HexChat
+ * Copyright (C) 2015 Patrick Griffis.
+ *
+ * This program 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+void
+notification_backend_show (const char *title, const char *text)
+{
+}
+
+int
+notification_backend_init (void)
+{
+	return 0;
+}
+
+void
+notification_backend_deinit (void)
+{
+}
+
+int
+notification_backend_supported (void)
+{
+	return 0;
+}
diff --git a/src/fe-gtk/notifications/notification-libnotify.c b/src/fe-gtk/notifications/notification-libnotify.c
new file mode 100644
index 00000000..94f9679d
--- /dev/null
+++ b/src/fe-gtk/notifications/notification-libnotify.c
@@ -0,0 +1,72 @@
+/* HexChat
+ * Copyright (C) 2015 Patrick Griffis.
+ *
+ * This program 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+#include <glib.h>
+#include <libnotify/notify.h>
+
+static gboolean strip_markup = FALSE;
+
+void
+notification_backend_show (const char *title, const char *text)
+{
+	NotifyNotification *notification;
+
+	if (strip_markup)
+		text = g_markup_escape_text (text, -1);
+
+	notification = notify_notification_new (title, text, "hexchat");
+	notify_notification_set_hint (notification, "desktop-entry", g_variant_new_string ("hexchat"));
+
+	notify_notification_show (notification, NULL);
+
+	g_object_unref (notification);
+	if (strip_markup)
+		g_free ((char*)text);
+}
+
+int
+notification_backend_init (void)
+{
+	GList* server_caps;
+
+	if (!NOTIFY_CHECK_VERSION (0, 7, 0))
+		return 0;
+
+	if (!notify_init (PACKAGE_NAME))
+		return 0;
+
+	server_caps = notify_get_server_caps ();
+	if (g_list_find_custom (server_caps, "body-markup", (GCompareFunc)g_strcmp0))
+		strip_markup = TRUE;
+	g_list_free_full (server_caps, g_free);
+
+	return 1;
+}
+
+void
+notification_backend_deinit (void)
+{
+	notify_uninit ();
+}
+
+int
+notification_backend_supported (void)
+{
+	return notify_is_initted ();
+}
diff --git a/src/fe-gtk/notifications/notification-osx.m b/src/fe-gtk/notifications/notification-osx.m
new file mode 100644
index 00000000..c9ad72d0
--- /dev/null
+++ b/src/fe-gtk/notifications/notification-osx.m
@@ -0,0 +1,54 @@
+/* HexChat
+ * Copyright (C) 2015 Patrick Griffis.
+ *
+ * This program 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#import <Cocoa/Cocoa.h>
+#include <gtkosxapplication.h>
+
+void
+notification_backend_show (const char *title, const char *text)
+{
+	NSString *str_title = [[NSString alloc] initWithUTF8String:title];
+	NSString *str_text = [[NSString alloc] initWithUTF8String:text];
+
+	NSUserNotification *userNotification = [NSUserNotification new];
+	userNotification.title = str_title;
+	userNotification.informativeText = str_text;
+
+	NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
+	[center scheduleNotification:userNotification];
+
+	[str_title release];
+	[str_text release];
+}
+
+int
+notification_backend_init (void)
+{
+	return 1;
+}
+
+void
+notification_backend_deinit (void)
+{
+}
+
+int
+notification_backend_supported (void)
+{
+	return gtkosx_application_get_bundle_id () != NULL;
+}
diff --git a/src/fe-gtk/notifications/notification-windows.c b/src/fe-gtk/notifications/notification-windows.c
new file mode 100644
index 00000000..3fade306
--- /dev/null
+++ b/src/fe-gtk/notifications/notification-windows.c
@@ -0,0 +1,87 @@
+/* HexChat
+ * Copyright (C) 2015 Arnav Singh.
+ *
+ * This program 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <gmodule.h>
+
+#include "hexchat.h"
+#include "plugin.h"
+
+#include <Windows.h>
+
+void (*winrt_notification_backend_show) (const char *title, const char *text) = NULL;
+int (*winrt_notification_backend_init) (void) = NULL;
+void (*winrt_notification_backend_deinit) (void) = NULL;
+int (*winrt_notification_backend_supported) (void) = NULL;
+
+void
+notification_backend_show (const char *title, const char *text)
+{
+	if (winrt_notification_backend_show == NULL)
+	{
+		return;
+	}
+
+	winrt_notification_backend_show (title, text);
+}
+
+int
+notification_backend_init (void)
+{
+	UINT original_error_mode;
+	GModule *module;
+
+	/* Temporarily suppress the "DLL could not be loaded" dialog box before trying to load hcnotifications-winrt.dll */
+	original_error_mode = GetErrorMode ();
+	SetErrorMode(SEM_FAILCRITICALERRORS);
+	module = module_load (HEXCHATLIBDIR "\\hcnotifications-winrt.dll");
+	SetErrorMode (original_error_mode);
+
+	if (module == NULL)
+	{
+		return 0;
+	}
+
+	g_module_symbol (module, "notification_backend_show", (gpointer *) &winrt_notification_backend_show);
+	g_module_symbol (module, "notification_backend_init", (gpointer *) &winrt_notification_backend_init);
+	g_module_symbol (module, "notification_backend_deinit", (gpointer *) &winrt_notification_backend_deinit);
+	g_module_symbol (module, "notification_backend_supported", (gpointer *) &winrt_notification_backend_supported);
+
+	return winrt_notification_backend_init ();
+}
+
+void
+notification_backend_deinit (void)
+{
+	if (winrt_notification_backend_deinit == NULL)
+	{
+		return;
+	}
+
+	winrt_notification_backend_deinit ();
+}
+
+int
+notification_backend_supported (void)
+{
+	if (winrt_notification_backend_supported == NULL)
+	{
+		return 0;
+	}
+
+	return winrt_notification_backend_supported ();
+}
diff --git a/src/fe-gtk/notifications/notification-winrt.cpp b/src/fe-gtk/notifications/notification-winrt.cpp
new file mode 100644
index 00000000..663f9c08
--- /dev/null
+++ b/src/fe-gtk/notifications/notification-winrt.cpp
@@ -0,0 +1,100 @@
+/* HexChat
+ * Copyright (c) 2014 Leetsoftwerx
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string>
+#include <codecvt>
+
+#include <roapi.h>
+#include <windows.ui.notifications.h>
+
+using namespace Windows::UI::Notifications;
+using namespace Windows::Data::Xml::Dom;
+
+static ToastNotifier ^ notifier = nullptr;
+
+static std::wstring
+widen(const std::string & to_widen)
+{
+	std::wstring_convert<std::codecvt_utf8_utf16<wchar_t> > converter;
+	return converter.from_bytes(to_widen);
+}
+
+extern "C"
+{
+	__declspec (dllexport) void
+	notification_backend_show (const char *title, const char *text)
+	{
+		try
+		{
+			auto toastTemplate = ToastNotificationManager::GetTemplateContent (ToastTemplateType::ToastText02);
+			auto node_list = toastTemplate->GetElementsByTagName ("text");
+			UINT node_count = node_list->Length;
+
+			auto wtitle = widen (title);
+			node_list->GetAt (0)->AppendChild (
+				toastTemplate->CreateTextNode (Platform::StringReference (wtitle.c_str (), wtitle.size ())));
+
+			auto wtext = widen (text);
+			node_list->GetAt (1)->AppendChild (
+				toastTemplate->CreateTextNode (Platform::StringReference (wtext.c_str (), wtext.size ())));
+
+			// Mute sound, we already play our own
+			auto node = toastTemplate->SelectSingleNode ("/toast");
+			auto audio_elem = toastTemplate->CreateElement ("audio");
+			audio_elem->SetAttribute ("silent", "true");
+			static_cast<XmlElement^>(node)->AppendChild (audio_elem);
+
+			notifier->Show (ref new ToastNotification (toastTemplate));
+		}
+		catch (Platform::Exception ^ ex)
+		{
+		}
+		catch (...)
+		{
+		}
+	}
+
+	__declspec (dllexport) int
+	notification_backend_init (void)
+	{
+		if (!notifier)
+			notifier = ToastNotificationManager::CreateToastNotifier ("HexChat.Desktop.Notify");
+
+		if (FAILED (Windows::Foundation::Initialize (RO_INIT_SINGLETHREADED)))
+			return 0;
+
+		return 1;
+	}
+
+	__declspec (dllexport) 	void
+	notification_backend_deinit (void)
+	{
+		notifier = nullptr;
+		Windows::Foundation::Uninitialize ();
+	}
+
+	__declspec (dllexport) int
+	notification_backend_supported (void)
+	{
+		return 1;
+	}
+}
diff --git a/src/fe-gtk/notifications/notifications-winrt.vcxproj b/src/fe-gtk/notifications/notifications-winrt.vcxproj
new file mode 100644
index 00000000..dcd2a2b7
--- /dev/null
+++ b/src/fe-gtk/notifications/notifications-winrt.vcxproj
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="notification-winrt.cpp">

+      <CompileAsWinRT>true</CompileAsWinRT>

+    </ClCompile>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{C53145CC-D021-40C9-B97C-0249AB9A43C9}</ProjectGuid>

+    <Keyword>Win32Proj</Keyword>

+    <RootNamespace>notifications-winrt</RootNamespace>

+    <ProjectName>notifications-winrt</ProjectName>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Label="Configuration">

+    <PlatformToolset>v120</PlatformToolset>

+    <ConfigurationType>DynamicLibrary</ConfigurationType>

+    <CharacterSet>Unicode</CharacterSet>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  <Import Project="..\..\..\win32\hexchat.props" />

+  <PropertyGroup>

+    <TargetName>hcnotifications-winrt</TargetName>

+    <OutDir>$(HexChatRel)plugins\</OutDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <PreprocessorDefinitions>WIN32;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_MEMORY;_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES_MEMORY;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT;NDEBUG;_WINDOWS;_USRDLL;NOTIFICATIONS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <SDLCheck>true</SDLCheck>

+      <AdditionalUsingDirectories>$(VCInstallDir)vcpackages;$(FrameworkSdkDir)References\CommonConfiguration\Neutral;%(AdditionalUsingDirectories)</AdditionalUsingDirectories>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(DepLibs);mincore.lib;runtimeobject.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <MinimumRequiredVersion>6.03</MinimumRequiredVersion>

+      <AdditionalLibraryDirectories>$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <PreprocessorDefinitions>WIN32;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_MEMORY;_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES_MEMORY;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT;NDEBUG;_WINDOWS;_USRDLL;NOTIFICATIONS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <SDLCheck>true</SDLCheck>

+      <AdditionalUsingDirectories>$(VCInstallDir)vcpackages;$(FrameworkSdkDir)References\CommonConfiguration\Neutral;%(AdditionalUsingDirectories)</AdditionalUsingDirectories>

+    </ClCompile>

+    <Link>

+      <AdditionalDependencies>$(DepLibs);mincore.lib;runtimeobject.lib;%(AdditionalDependencies)</AdditionalDependencies>

+      <MinimumRequiredVersion>6.03</MinimumRequiredVersion>

+      <AdditionalLibraryDirectories>$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>

+    </Link>

+  </ItemDefinitionGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+</Project>

diff --git a/src/fe-gtk/notifications/notifications-winrt.vcxproj.filters b/src/fe-gtk/notifications/notifications-winrt.vcxproj.filters
new file mode 100644
index 00000000..06f4e558
--- /dev/null
+++ b/src/fe-gtk/notifications/notifications-winrt.vcxproj.filters
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="notification-winrt.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/src/fe-gtk/notifygui.c b/src/fe-gtk/notifygui.c
index 5aa60d0a..ed16f44f 100644
--- a/src/fe-gtk/notifygui.c
+++ b/src/fe-gtk/notifygui.c
@@ -190,11 +190,11 @@ notify_gui_update (void)
 			{
 				lastseenminutes = (int)(time (0) - lastseen) / 60;
 				if (lastseenminutes < 60) 
-					snprintf (agobuf, sizeof (agobuf), _("%d minutes ago"), lastseenminutes);
+					g_snprintf (agobuf, sizeof (agobuf), _("%d minutes ago"), lastseenminutes);
 				else if (lastseenminutes < 120)
-					snprintf (agobuf, sizeof (agobuf), _("An hour ago"));
+					g_snprintf (agobuf, sizeof (agobuf), _("An hour ago"));
 				else
-					snprintf (agobuf, sizeof (agobuf), _("%d hours ago"), lastseenminutes / 60);
+					g_snprintf (agobuf, sizeof (agobuf), _("%d hours ago"), lastseenminutes / 60);
 				seen = agobuf;
 			}
 			if (!valid)	/* create new tree row if required */
@@ -219,7 +219,7 @@ notify_gui_update (void)
 						name = "";
 					server = server_get_network (servnot->server, TRUE);
 
-					snprintf (agobuf, sizeof (agobuf), _("%d minutes ago"), (int)(time (0) - lastseen) / 60);
+					g_snprintf (agobuf, sizeof (agobuf), _("%d minutes ago"), (int)(time (0) - lastseen) / 60);
 					seen = agobuf;
 
 					if (!valid)	/* create new tree row if required */
@@ -380,7 +380,7 @@ fe_notify_ask (char *nick, char *networks)
 	gtk_table_attach_defaults (GTK_TABLE (table), wid, 1, 2, 2, 3);
 
 	label = gtk_label_new (NULL);
-	snprintf (buf, sizeof (buf), "<i><span size=\"smaller\">%s</span></i>", _("Comma separated list of networks is accepted."));
+	g_snprintf (buf, sizeof (buf), "<i><span size=\"smaller\">%s</span></i>", _("Comma separated list of networks is accepted."));
 	gtk_label_set_markup (GTK_LABEL (label), buf);
 	gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, 3, 4);
 
diff --git a/src/fe-gtk/palette.c b/src/fe-gtk/palette.c
index 435ba84b..17689756 100644
--- a/src/fe-gtk/palette.c
+++ b/src/fe-gtk/palette.c
@@ -106,45 +106,39 @@ palette_alloc (GtkWidget * widget)
 void
 palette_load (void)
 {
-	int i, j, l, fh;
+	int i, j, fh;
 	char prefname[256];
 	struct stat st;
 	char *cfg;
-	int red, green, blue;
+	guint16 red, green, blue;
 
 	fh = hexchat_open_file ("colors.conf", O_RDONLY, 0, 0);
 	if (fh != -1)
 	{
 		fstat (fh, &st);
-		cfg = malloc (st.st_size + 1);
-		if (cfg)
+		cfg = g_malloc0 (st.st_size + 1);
+		read (fh, cfg, st.st_size);
+
+		/* mIRC colors 0-31 are here */
+		for (i = 0; i < 32; i++)
+		{
+			g_snprintf (prefname, sizeof prefname, "color_%d", i);
+			cfg_get_color (cfg, prefname, &red, &green, &blue);
+			colors[i].red = red;
+			colors[i].green = green;
+			colors[i].blue = blue;
+		}
+
+		/* our special colors are mapped at 256+ */
+		for (i = 256, j = 32; j < MAX_COL+1; i++, j++)
 		{
-			cfg[0] = '\0';
-			l = read (fh, cfg, st.st_size);
-			if (l >= 0)
-				cfg[l] = '\0';
-
-			/* mIRC colors 0-31 are here */
-			for (i = 0; i < 32; i++)
-			{
-				snprintf (prefname, sizeof prefname, "color_%d", i);
-				cfg_get_color (cfg, prefname, &red, &green, &blue);
-				colors[i].red = red;
-				colors[i].green = green;
-				colors[i].blue = blue;
-			}
-
-			/* our special colors are mapped at 256+ */
-			for (i = 256, j = 32; j < MAX_COL+1; i++, j++)
-			{
-				snprintf (prefname, sizeof prefname, "color_%d", i);
-				cfg_get_color (cfg, prefname, &red, &green, &blue);
-				colors[j].red = red;
-				colors[j].green = green;
-				colors[j].blue = blue;
-			}
-			free (cfg);
+			g_snprintf (prefname, sizeof prefname, "color_%d", i);
+			cfg_get_color (cfg, prefname, &red, &green, &blue);
+			colors[j].red = red;
+			colors[j].green = green;
+			colors[j].blue = blue;
 		}
+		g_free (cfg);
 		close (fh);
 	}
 }
@@ -161,14 +155,14 @@ palette_save (void)
 		/* mIRC colors 0-31 are here */
 		for (i = 0; i < 32; i++)
 		{
-			snprintf (prefname, sizeof prefname, "color_%d", i);
+			g_snprintf (prefname, sizeof prefname, "color_%d", i);
 			cfg_put_color (fh, colors[i].red, colors[i].green, colors[i].blue, prefname);
 		}
 
 		/* our special colors are mapped at 256+ */
 		for (i = 256, j = 32; j < MAX_COL+1; i++, j++)
 		{
-			snprintf (prefname, sizeof prefname, "color_%d", i);
+			g_snprintf (prefname, sizeof prefname, "color_%d", i);
 			cfg_put_color (fh, colors[j].red, colors[j].green, colors[j].blue, prefname);
 		}
 
diff --git a/src/fe-gtk/pixmaps.c b/src/fe-gtk/pixmaps.c
index cbec6f71..053afaaf 100644
--- a/src/fe-gtk/pixmaps.c
+++ b/src/fe-gtk/pixmaps.c
@@ -87,10 +87,9 @@ pixmap_load_from_file (char *filename)
 static GdkPixbuf *
 load_pixmap (const char *filename)
 {
-	gchar *path;
 	GdkPixbuf *pixbuf;
 
-	path = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "icons" G_DIR_SEPARATOR_S "%s.png", get_xdir (), filename);
+	gchar *path = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "icons" G_DIR_SEPARATOR_S "%s.png", get_xdir (), filename);
 	pixbuf = gdk_pixbuf_new_from_file (path, 0);
 	g_free (path);
 
diff --git a/src/fe-gtk/plugin-notification.c b/src/fe-gtk/plugin-notification.c
new file mode 100644
index 00000000..04a64213
--- /dev/null
+++ b/src/fe-gtk/plugin-notification.c
@@ -0,0 +1,215 @@
+/* HexChat
+ * Copyright (C) 2015 Patrick Griffis.
+ *
+ * This program 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+#include <glib.h>
+
+#include "../common/hexchat-plugin.h"
+#include "../common/inbound.h" /* For alert_match_word() */
+#include "notifications/notification-backend.h"
+
+static hexchat_plugin *ph;
+
+static gboolean
+should_alert (void)
+{
+	int omit_away, omit_focused, omit_tray;
+
+	if (hexchat_get_prefs (ph, "gui_focus_omitalerts", NULL, &omit_focused) == 3 && omit_focused)
+	{
+		const char *status = hexchat_get_info (ph, "win_status");
+
+		if (status && !g_strcmp0 (status, "active"))
+			return FALSE;
+	}
+
+	if (hexchat_get_prefs (ph, "away_omit_alerts", NULL, &omit_away) == 3 && omit_away)
+	{
+		if (hexchat_get_info (ph, "away"))
+			return FALSE;
+	}
+
+	if (hexchat_get_prefs (ph, "gui_tray_quiet", NULL, &omit_tray) == 3 && omit_tray)
+	{
+		int tray_enabled;
+
+		if (hexchat_get_prefs (ph, "gui_tray", NULL, &tray_enabled) == 3 && tray_enabled)
+		{
+			const char *status = hexchat_get_info (ph, "win_status");
+
+			if (status && g_strcmp0 (status, "hidden") != 0)
+				return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+static gboolean
+is_ignored (char *nick)
+{
+	const char *no_hilight;
+
+	if (hexchat_get_prefs (ph, "irc_no_hilight", &no_hilight, NULL) == 1 && no_hilight)
+	{
+		return alert_match_word (nick, (char*)no_hilight);
+	}
+	return FALSE;
+}
+
+static void
+show_notification (const char *title, const char *text)
+{
+	char *stripped_title, *stripped_text;
+
+	/* Strip all colors */
+	stripped_title = hexchat_strip (ph, title, -1, 7);
+	stripped_text = hexchat_strip (ph, text, -1, 7);
+	
+	notification_backend_show (stripped_title, stripped_text);
+
+	hexchat_free (ph, stripped_title);
+	hexchat_free (ph, stripped_text);
+}
+
+static void
+show_notificationf (const char *text, const char *format, ...)
+{
+	va_list args;
+	char *buf;
+
+	va_start (args, format);
+	buf = g_strdup_vprintf (format, args);
+	va_end (args);
+
+	show_notification (buf, text);
+	g_free (buf);
+}
+
+static int
+incoming_hilight_cb (char *word[], gpointer userdata)
+{
+	int hilight;
+
+	if (hexchat_get_prefs (ph, "input_balloon_hilight", NULL, &hilight) == 3 && hilight && should_alert())
+	{
+		show_notificationf (word[2], _("Highlighted message from: %s (%s)"), word[1], hexchat_get_info (ph, "channel"));
+	}
+	return HEXCHAT_EAT_NONE;
+}
+
+static int
+incoming_message_cb (char *word[], gpointer userdata)
+{
+	int message;
+
+	if (hexchat_get_prefs (ph, "input_balloon_chans", NULL, &message) == 3 && message && should_alert ())
+	{
+		show_notificationf (word[2], _("Channel message from: %s (%s)"), word[1], hexchat_get_info (ph, "channel"));
+	}
+	return HEXCHAT_EAT_NONE;
+}
+
+static int
+incoming_priv_cb (char *word[], gpointer userdata)
+{
+	int priv;
+
+	if (hexchat_get_prefs (ph, "input_balloon_priv", NULL, &priv) == 3 && priv && should_alert ())
+	{
+		const char *network = hexchat_get_info (ph, "network");
+		if (!network)
+			network = hexchat_get_info (ph, "server");
+
+		if (userdata != NULL) /* Special event */
+		{
+			if (GPOINTER_TO_INT (userdata) == 3)
+			{
+				if (!is_ignored (word[2]))
+					show_notificationf (word[1], _("File offer from: %s (%s)"), word[2], network);
+			}
+			else if (GPOINTER_TO_INT (userdata) == 2)
+			{
+				if (!is_ignored (word[2]))
+					show_notificationf (word[1], _("Invited to channel by: %s (%s)"), word[2], network);
+			}
+			else
+			{
+				if (!is_ignored (word[1]))
+					show_notificationf (word[2], _("Notice from: %s (%s)"), word[1], network);
+			}
+		}
+		else
+			show_notificationf (word[2], _("Private message from: %s (%s)"), word[1], network);
+	}
+	return HEXCHAT_EAT_NONE;
+}
+
+static int
+tray_cmd_cb (char *word[], char *word_eol[], gpointer userdata)
+{
+	if (word[2] && !g_ascii_strcasecmp (word[2], "-b") && word[3] && word[4])
+	{
+		if (should_alert ())
+			show_notification (word[3], word_eol[4]);
+		return HEXCHAT_EAT_ALL;
+	}
+
+	return HEXCHAT_EAT_NONE;
+}
+
+int
+notification_plugin_init (hexchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg)
+{
+	if (!notification_backend_init ())
+		return 0;
+
+	ph = plugin_handle;
+	*plugin_name = "";
+	*plugin_desc = "";
+	*plugin_version = "";
+
+	hexchat_hook_print (ph, "Channel Msg Hilight", HEXCHAT_PRI_LOWEST, incoming_hilight_cb, NULL);
+	hexchat_hook_print (ph, "Channel Action Hilight", HEXCHAT_PRI_LOWEST, incoming_hilight_cb, NULL);
+
+	hexchat_hook_print (ph, "Channel Message", HEXCHAT_PRI_LOWEST, incoming_message_cb, NULL);
+	hexchat_hook_print (ph, "Channel Action", HEXCHAT_PRI_LOWEST, incoming_message_cb, NULL);
+	hexchat_hook_print (ph, "Channel Notice", HEXCHAT_PRI_LOWEST, incoming_message_cb, NULL);
+
+	hexchat_hook_print (ph, "Private Message", HEXCHAT_PRI_LOWEST, incoming_priv_cb, NULL);
+	hexchat_hook_print (ph, "Private Message to Dialog", HEXCHAT_PRI_LOWEST, incoming_priv_cb, NULL);
+	hexchat_hook_print (ph, "Private Action", HEXCHAT_PRI_LOWEST, incoming_priv_cb, NULL);
+	hexchat_hook_print (ph, "Private Action to Dialog", HEXCHAT_PRI_LOWEST, incoming_priv_cb, NULL);
+
+	/* Special events treated as priv */
+	hexchat_hook_print (ph, "Notice", HEXCHAT_PRI_LOWEST, incoming_priv_cb, GINT_TO_POINTER (1));
+	hexchat_hook_print (ph, "Invited", HEXCHAT_PRI_LOWEST, incoming_priv_cb, GINT_TO_POINTER (2));
+	hexchat_hook_print (ph, "DCC Offer", HEXCHAT_PRI_LOWEST, incoming_priv_cb, GINT_TO_POINTER (3));
+
+	hexchat_hook_command (ph, "TRAY", HEXCHAT_PRI_HIGH, tray_cmd_cb, NULL, NULL);
+	
+	return 1;
+}
+
+
+int
+notification_plugin_deinit (void)
+{
+	notification_backend_deinit ();
+	return 1;
+}
diff --git a/src/fe-gtk/plugin-notification.h b/src/fe-gtk/plugin-notification.h
new file mode 100644
index 00000000..07ad1609
--- /dev/null
+++ b/src/fe-gtk/plugin-notification.h
@@ -0,0 +1,25 @@
+/* HexChat
+ * Copyright (C) 2015 Patrick Griffis.
+ *
+ * This program 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef HEXCHAT_PLUGIN_NOTIFICATION_H
+#define HEXCHAT_PLUGIN_NOTIFICATION_H
+
+int notification_plugin_init (void *, char **, char **, char **, char *);
+int notification_plugin_deinit (void *);
+
+#endif
diff --git a/src/fe-gtk/plugin-tray.c b/src/fe-gtk/plugin-tray.c
index b3e34c0a..077a7c63 100644
--- a/src/fe-gtk/plugin-tray.c
+++ b/src/fe-gtk/plugin-tray.c
@@ -34,18 +34,6 @@
 #include <unistd.h>
 #endif
 
-#ifdef USE_LIBNOTIFY
-#include <libnotify/notify.h>
-#ifndef NOTIFY_CHECK_VERSION
-#define NOTIFY_CHECK_VERSION(x,y,z) 0
-#endif
-#if NOTIFY_CHECK_VERSION(0,7,0)
-#define XC_NOTIFY_NEW(a,b,c,d) notify_notification_new(a,b,c)
-#else
-#define XC_NOTIFY_NEW(a,b,c,d) notify_notification_new(a,b,c,d)
-#endif
-#endif
-
 typedef enum	/* current icon status */
 {
 	TS_NONE,
@@ -154,82 +142,6 @@ fe_tray_set_tooltip (const char *text)
 		gtk_status_icon_set_tooltip_text (sticon, text);
 }
 
-void
-fe_tray_set_balloon (const char *title, const char *text)
-{
-#ifndef WIN32
-#if 0
-	const char *argv[8];
-	const char *path;
-	char time[16];
-#endif
-	WinStatus ws;
-
-	/* no balloons if the window is focused */
-	ws = tray_get_window_status ();
-	if ((prefs.hex_away_omit_alerts && hexchat_get_info(ph, "away")) ||
-		(prefs.hex_gui_focus_omitalerts && ws == WS_FOCUSED))
-		return;
-
-	/* bit 1 of flags means "no balloons unless hidden/iconified" */
-	if (ws != WS_HIDDEN && prefs.hex_gui_tray_quiet)
-		return;
-
-	/* FIXME: this should close the current balloon */
-	if (!text)
-		return;
-
-#ifdef USE_LIBNOTIFY
-	static int notify_text_strip_flags = STRIP_ALL;
-	NotifyNotification *notification;
-	char *notify_text, *notify_title;
-
-	if (!notify_is_initted())
-	{
-		notify_init(PACKAGE_NAME);
-
-		GList* server_caps = notify_get_server_caps ();
-		if (g_list_find_custom (server_caps, "body-markup", (GCompareFunc)strcmp))
-		{
-			notify_text_strip_flags |= STRIP_ESCMARKUP;
-		}
-		g_list_free_full (server_caps, g_free);
-	}
-
-	notify_text = strip_color (text, -1, notify_text_strip_flags);
-	notify_title = strip_color (title, -1, STRIP_ALL);
-
-	notification = XC_NOTIFY_NEW (notify_title, notify_text, HEXCHATSHAREDIR "/icons/hicolor/scalable/apps/hexchat.svg", NULL);
-
-#if NOTIFY_CHECK_VERSION(0,7,0)
-	notify_notification_set_hint (notification, "desktop-entry", g_variant_new_string ("hexchat"));
-#endif
-
-	g_free ((char *)notify_title);
-	g_free ((char *)notify_text);
-
-	notify_notification_set_timeout (notification, prefs.hex_input_balloon_time*1000);
-	notify_notification_show (notification, NULL);
-
-	g_object_unref (notification);
-#endif
-#endif
-}
-
-static void
-tray_set_balloonf (const char *text, const char *format, ...)
-{
-	va_list args;
-	char *buf;
-
-	va_start (args, format);
-	buf = g_strdup_vprintf (format, args);
-	va_end (args);
-
-	fe_tray_set_balloon (buf, text);
-	g_free (buf);
-}
-
 static void
 tray_set_tipf (const char *format, ...)
 {
@@ -575,26 +487,32 @@ tray_menu_destroy (GtkWidget *menu, gpointer userdata)
 }
 
 #ifdef WIN32
-static void
+static gboolean
 tray_menu_enter_cb (GtkWidget *menu)
 {
 	tray_menu_inactivetime = 0;
+	return FALSE;
 }
 
-static void
+static gboolean
 tray_menu_left_cb (GtkWidget *menu)
 {
 	tray_menu_inactivetime = g_get_real_time ();
+	return FALSE;
 }
 
-static void
+static gboolean
 tray_check_hide (GtkWidget *menu)
 {
 	if (tray_menu_inactivetime && g_get_real_time () - tray_menu_inactivetime  >= 2000000)
 	{
 		tray_menu_destroy (menu, NULL);
+		return G_SOURCE_REMOVE;
 	}
+
+	return G_SOURCE_CONTINUE;
 }
+#endif
 
 static void
 tray_menu_settings (GtkWidget * wid, gpointer none)
@@ -602,7 +520,6 @@ tray_menu_settings (GtkWidget * wid, gpointer none)
 	extern void setup_open (void);
 	setup_open ();
 }
-#endif
 
 static void
 tray_menu_cb (GtkWidget *widget, guint button, guint time, gpointer userdata)
@@ -651,10 +568,9 @@ tray_menu_cb (GtkWidget *widget, guint button, guint time, gpointer userdata)
 		gtk_widget_set_sensitive (item, FALSE);
 
 	menu_add_plugin_items (menu, "\x5$TRAY", NULL);
-#ifdef WIN32
+
 	tray_make_item (menu, NULL, tray_menu_quit_cb, NULL);
 	mg_create_icon_item (_("_Preferences"), GTK_STOCK_PREFERENCES, menu, tray_menu_settings, NULL);
-#endif
 	tray_make_item (menu, NULL, tray_menu_quit_cb, NULL);
 	mg_create_icon_item (_("_Quit"), GTK_STOCK_QUIT, menu, tray_menu_quit_cb, NULL);
 
@@ -669,7 +585,7 @@ tray_menu_cb (GtkWidget *widget, guint button, guint time, gpointer userdata)
 	g_signal_connect (G_OBJECT (menu), "enter-notify-event",
 							G_CALLBACK (tray_menu_enter_cb), NULL);
 
-	tray_menu_timer = g_timeout_add(500, (GSourceFunc) tray_check_hide, menu);
+	tray_menu_timer = g_timeout_add (500, tray_check_hide, menu);
 #endif
 
 	gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL,
@@ -718,10 +634,6 @@ tray_hilight_cb (char *word[], void *userdata)
 								tray_hilight_count, word[1], hexchat_get_info (ph, "channel"));
 	}
 
-	if (prefs.hex_input_balloon_hilight)
-		tray_set_balloonf (word[2], _("Highlighted message from: %s (%s)"),
-								 word[1], hexchat_get_info (ph, "channel"));
-
 	return HEXCHAT_EAT_NONE;
 }
 
@@ -743,10 +655,6 @@ tray_message_cb (char *word[], void *userdata)
 			tray_set_tipf (_(DISPLAY_NAME": %u channel messages."), tray_pub_count);
 	}
 
-	if (prefs.hex_input_balloon_chans)
-		tray_set_balloonf (word[2], _("Channel message from: %s (%s)"),
-								 word[1], hexchat_get_info (ph, "channel"));
-
 	return HEXCHAT_EAT_NONE;
 }
 
@@ -774,10 +682,6 @@ tray_priv (char *from, char *text)
 			tray_set_tipf (_(DISPLAY_NAME": %u private messages, latest from: %s (%s)"),
 								tray_priv_count, from, network);
 	}
-
-	if (prefs.hex_input_balloon_priv)
-		tray_set_balloonf (text, _("Private message from: %s (%s)"),
-								 from, network);
 }
 
 static int
@@ -822,10 +726,6 @@ tray_dcc_cb (char *word[], void *userdata)
 								tray_file_count, word[1], network);
 	}
 
-	if (prefs.hex_input_balloon_priv && (!prefs.hex_away_omit_alerts || tray_find_away_status () != 1))
-		tray_set_balloonf ("", _("File offer from: %s (%s)"),
-								word[1], network);
-
 	return HEXCHAT_EAT_NONE;
 }
 
@@ -904,8 +804,6 @@ tray_plugin_deinit (hexchat_plugin *plugin_handle)
 {
 #ifdef WIN32
 	tray_cleanup ();
-#elif defined(USE_LIBNOTIFY)
-	notify_uninit ();
 #endif
 	return 1;
 }
diff --git a/src/fe-gtk/plugingui.c b/src/fe-gtk/plugingui.c
index 9b3186a6..83e05727 100644
--- a/src/fe-gtk/plugingui.c
+++ b/src/fe-gtk/plugingui.c
@@ -142,23 +142,21 @@ plugingui_load_cb (session *sess, char *file)
 {
 	if (file)
 	{
-		char *buf = malloc (strlen (file) + 9);
+		char *buf;
 
 		if (strchr (file, ' '))
-			sprintf (buf, "LOAD \"%s\"", file);
+			buf = g_strdup_printf ("LOAD \"%s\"", file);
 		else
-			sprintf (buf, "LOAD %s", file);
+			buf = g_strdup_printf ("LOAD %s", file);
 		handle_command (sess, buf, FALSE);
-		free (buf);
+		g_free (buf);
 	}
 }
 
 void
 plugingui_load (void)
 {
-	char *sub_dir;
-
-	sub_dir = g_build_filename (get_xdir(), "addons", NULL);
+	char *sub_dir = g_build_filename (get_xdir(), "addons", NULL);
 
 	gtkutil_file_req (_("Select a Plugin or Script to load"), plugingui_load_cb, current_sess,
 							sub_dir, "*."G_MODULE_SUFFIX";*.lua;*.pl;*.py;*.tcl;*.js", FRF_FILTERISINITIAL|FRF_EXTENSIONS);
@@ -175,7 +173,7 @@ plugingui_loadbutton_cb (GtkWidget * wid, gpointer unused)
 static void
 plugingui_unload (GtkWidget * wid, gpointer unused)
 {
-	char *modname, *file, *buf;
+	char *modname, *file;
 	GtkTreeView *view;
 	GtkTreeIter iter;
 	
@@ -188,16 +186,17 @@ plugingui_unload (GtkWidget * wid, gpointer unused)
 	{
 		if (plugin_kill (modname, FALSE) == 2)
 			fe_message (_("That plugin is refusing to unload.\n"), FE_MSG_ERROR);
-	} else
+	}
+	else
 	{
+		char *buf;
 		/* let python.so or perl.so handle it */
-		buf = malloc (strlen (file) + 10);
 		if (strchr (file, ' '))
-			sprintf (buf, "UNLOAD \"%s\"", file);
+			buf = g_strdup_printf ("UNLOAD \"%s\"", file);
 		else
-			sprintf (buf, "UNLOAD %s", file);
+			buf = g_strdup_printf ("UNLOAD %s", file);
 		handle_command (current_sess, buf, FALSE);
-		free (buf);
+		g_free (buf);
 	}
 
 	g_free (modname);
@@ -211,14 +210,14 @@ plugingui_reloadbutton_cb (GtkWidget *wid, GtkTreeView *view)
 
 	if (file)
 	{
-		char *buf = malloc (strlen (file) + 9);
+		char *buf;
 
 		if (strchr (file, ' '))
-			sprintf (buf, "RELOAD \"%s\"", file);
+			buf = g_strdup_printf ("RELOAD \"%s\"", file);
 		else
-			sprintf (buf, "RELOAD %s", file);
+			buf = g_strdup_printf ("RELOAD %s", file);
 		handle_command (current_sess, buf, FALSE);
-		free (buf);
+		g_free (buf);
 		g_free (file);
 	}
 }
diff --git a/src/fe-gtk/rawlog.c b/src/fe-gtk/rawlog.c
index f2527492..1d4bf9fd 100644
--- a/src/fe-gtk/rawlog.c
+++ b/src/fe-gtk/rawlog.c
@@ -109,7 +109,7 @@ open_rawlog (struct server *serv)
 		return;
 	}
 
-	snprintf (tbuf, sizeof tbuf, _(DISPLAY_NAME": Raw Log (%s)"), serv->servername);
+	g_snprintf (tbuf, sizeof tbuf, _(DISPLAY_NAME": Raw Log (%s)"), serv->servername);
 	serv->gui->rawlog_window =
 		mg_create_generic_tab ("RawLog", tbuf, FALSE, TRUE, close_rawlog, serv,
 							 640, 320, &vbox, serv);
@@ -146,7 +146,7 @@ fe_add_rawlog (server *serv, char *text, int len, int outbound)
 {
 	char **split_text;
 	char *new_text;
-	int i;
+	size_t i;
 
 	if (!serv->gui->rawlog_window)
 		return;
@@ -163,7 +163,7 @@ fe_add_rawlog (server *serv, char *text, int len, int outbound)
 		else
 			new_text = g_strconcat ("\0033>>\017 ", split_text[i], NULL);
 
-		gtk_xtext_append (GTK_XTEXT (serv->gui->rawlog_textlist)->buffer, new_text, strlen (new_text));
+		gtk_xtext_append (GTK_XTEXT (serv->gui->rawlog_textlist)->buffer, new_text, strlen (new_text), 0);
 
 		g_free (new_text);
 	}
diff --git a/src/fe-gtk/servlistgui.c b/src/fe-gtk/servlistgui.c
index f43a225a..f7909f72 100644
--- a/src/fe-gtk/servlistgui.c
+++ b/src/fe-gtk/servlistgui.c
@@ -90,7 +90,7 @@ static GtkWidget *servlist_open_edit (GtkWidget *parent, ircnet *net);
 static const char *pages[]=
 {
 	IRC_DEFAULT_CHARSET,
-	"IRC (Latin/Unicode Hybrid)",
+	"CP1252 (Windows-1252)",
 	"ISO-8859-15 (Western Europe)",
 	"ISO-8859-2 (Central Europe)",
 	"ISO-8859-7 (Greek)",
@@ -497,7 +497,7 @@ servlist_addnet_cb (GtkWidget *item, GtkTreeView *treeview)
 	ircnet *net;
 
 	net = servlist_net_add (_("New Network"), "", TRUE);
-	net->encoding = strdup (IRC_DEFAULT_CHARSET);
+	net->encoding = g_strdup (IRC_DEFAULT_CHARSET);
 	servlist_server_add (net, "newserver/6667");
 
 	store = (GtkListStore *)gtk_tree_view_get_model (treeview);
@@ -668,13 +668,12 @@ servlist_favor (GtkWidget *button, gpointer none)
 static void
 servlist_update_from_entry (char **str, GtkWidget *entry)
 {
-	if (*str)
-		free (*str);
+	g_free (*str);
 
 	if (gtk_entry_get_text (GTK_ENTRY (entry))[0] == 0)
 		*str = NULL;
 	else
-		*str = strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
+		*str = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
 }
 
 static void
@@ -960,10 +959,10 @@ servlist_savegui (void)
 	if (!rfc_casecmp (nick1, nick2))
 		return 2;
 
-	strcpy (prefs.hex_irc_nick1, nick1);
-	strcpy (prefs.hex_irc_nick2, nick2);
-	strcpy (prefs.hex_irc_nick3, gtk_entry_get_text (GTK_ENTRY (entry_nick3)));
-	strcpy (prefs.hex_irc_user_name, gtk_entry_get_text (GTK_ENTRY (entry_guser)));
+	safe_strcpy (prefs.hex_irc_nick1, nick1, sizeof(prefs.hex_irc_nick1));
+	safe_strcpy (prefs.hex_irc_nick2, nick2, sizeof(prefs.hex_irc_nick2));
+	safe_strcpy (prefs.hex_irc_nick3, gtk_entry_get_text (GTK_ENTRY (entry_nick3)), sizeof(prefs.hex_irc_nick3));
+	safe_strcpy (prefs.hex_irc_user_name, gtk_entry_get_text (GTK_ENTRY (entry_guser)), sizeof(prefs.hex_irc_user_name));
 	sp = strchr (prefs.hex_irc_user_name, ' ');
 	if (sp)
 		sp[0] = 0;	/* spaces will break the login */
@@ -1203,9 +1202,9 @@ servlist_celledit_cb (GtkCellRendererText *cell, gchar *arg1, gchar *arg2,
 		}
 
 		netname = net->name;
-		net->name = strdup (arg2);
+		net->name = g_strdup (arg2);
 		gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, net->name, -1);
-		free (netname);
+		g_free (netname);
 	}
 
 	gtk_tree_path_free (path);
@@ -1311,7 +1310,7 @@ servlist_sanitize_hostname (char *host)
 {
 	char *ret, *c, *e;
 
-	ret = strdup (host);
+	ret = g_strdup (host);
 
 	c = strchr  (ret, ':');
 	e = strrchr (ret, ':');
@@ -1371,7 +1370,7 @@ servlist_editserver_cb (GtkCellRendererText *cell, gchar *name, gchar *newval, g
 		servname = serv->hostname;
 		serv->hostname = servlist_sanitize_hostname (newval);
 		gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, serv->hostname, -1);
-		free (servname);
+		g_free (servname);
 	}
 }
 
@@ -1409,7 +1408,7 @@ servlist_editcommand_cb (GtkCellRendererText *cell, gchar *name, gchar *newval,
 		cmd = entry->command;
 		entry->command = servlist_sanitize_command (newval);
 		gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, entry->command, -1);
-		free (cmd);
+		g_free (cmd);
 	}
 }
 
@@ -1508,9 +1507,8 @@ servlist_combo_cb (GtkEntry *entry, gpointer userdata)
 	if (!selected_net)
 		return;
 
-	if (selected_net->encoding)
-		free (selected_net->encoding);
-	selected_net->encoding = strdup (gtk_entry_get_text (entry));
+	g_free (selected_net->encoding);
+	selected_net->encoding = g_strdup (gtk_entry_get_text (entry));
 }
 
 /* Fills up the network's authentication type so that it's guaranteed to be either NULL or a valid value. */
@@ -1594,7 +1592,6 @@ servlist_create_charsetcombo (void)
 	int i;
 
 	cb = gtk_combo_box_text_new_with_entry ();
-	gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (cb), "System default");
 	i = 0;
 	while (pages[i])
 	{
@@ -1602,7 +1599,7 @@ servlist_create_charsetcombo (void)
 		i++;
 	}
 
-	gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN(cb))), selected_net->encoding ? selected_net->encoding : "System default");
+	gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN(cb))), selected_net->encoding ? selected_net->encoding : pages[0]);
 	
 	g_signal_connect (G_OBJECT (gtk_bin_get_child (GTK_BIN (cb))), "changed",
 							G_CALLBACK (servlist_combo_cb), NULL);
@@ -1660,7 +1657,7 @@ bold_label (char *text)
 	char buf[128];
 	GtkWidget *label;
 
-	snprintf (buf, sizeof (buf), "<b>%s</b>", text);
+	g_snprintf (buf, sizeof (buf), "<b>%s</b>", text);
 	label = gtk_label_new (buf);
 	gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
 	gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
@@ -1702,7 +1699,7 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
 
 	editwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 	gtk_container_set_border_width (GTK_CONTAINER (editwindow), 4);
-	snprintf (buf, sizeof (buf), _(DISPLAY_NAME": Edit %s"), net->name);
+	g_snprintf (buf, sizeof (buf), _(DISPLAY_NAME": Edit %s"), net->name);
 	gtk_window_set_title (GTK_WINDOW (editwindow), buf);
 	gtk_window_set_default_size (GTK_WINDOW (editwindow), netedit_win_width, netedit_win_height);
 	gtk_window_set_transient_for (GTK_WINDOW (editwindow), GTK_WINDOW (parent));
diff --git a/src/fe-gtk/setup.c b/src/fe-gtk/setup.c
index e4372dc9..dc469591 100644
--- a/src/fe-gtk/setup.c
+++ b/src/fe-gtk/setup.c
@@ -36,6 +36,7 @@
 #include "pixmaps.h"
 #include "menu.h"
 #include "plugin-tray.h"
+#include "notifications/notification-backend.h"
 
 #ifdef WIN32
 #include "../common/fe.h"
@@ -314,6 +315,7 @@ static const setting tabs_settings[] =
 	{ST_TOGGLE, N_("Show icons in the channel tree"), P_OFFINTNL(hex_gui_tab_icons), 0, 0, 0},
 	{ST_TOGGLE, N_("Show dotted lines in the channel tree"), P_OFFINTNL(hex_gui_tab_dots), 0, 0, 0},
 	{ST_TOGGLE, N_("Scroll mouse-wheel to change tabs"), P_OFFINTNL (hex_gui_tab_scrollchans), 0, 0, 0},
+	{ST_TOGGLE, N_("Middle click to close tab"), P_OFFINTNL(hex_gui_tab_middleclose), 0, 0, 0},
 	{ST_TOGGLE, N_("Smaller text"), P_OFFINTNL(hex_gui_tab_small), 0, 0, 0},
 	{ST_MENU,	N_("Focus new tabs:"), P_OFFINTNL(hex_gui_tab_newtofront), 0, focusnewtabsmenu, 0},
 	{ST_MENU,	N_("Placement of notices:"), P_OFFINTNL(hex_irc_notice_pos), 0, noticeposmenu, 0},
@@ -396,9 +398,47 @@ static const setting alert_settings[] =
 	{ST_HEADER,	N_("Alerts"),0,0,0},
 
 	{ST_ALERTHEAD},
-#if !defined (WIN32) && !defined (__APPLE__)
-	{ST_3OGGLE, N_("Show tray balloons on:"), 0, 0, (void *)balloonlist, 0},
+
+
+	{ST_3OGGLE, N_("Show notifications on:"), 0, 0, (void *)balloonlist, 0},
+	{ST_3OGGLE, N_("Blink tray icon on:"), 0, 0, (void *)trayblinklist, 0},
+	{ST_3OGGLE, N_("Blink task bar on:"), 0, 0, (void *)taskbarlist, 0},
+#ifdef WIN32
+	{ST_3OGGLE, N_("Make a beep sound on:"), 0, N_("Play the \"Instant Message Notification\" system sound upon the selected events"), (void *)beeplist, 0},
+#else
+#ifdef USE_LIBCANBERRA
+	{ST_3OGGLE, N_("Make a beep sound on:"), 0, N_("Play \"message-new-instant\" from the freedesktop.org sound theme upon the selected events"), (void *)beeplist, 0},
+#else
+	{ST_3OGGLE, N_("Make a beep sound on:"), 0, N_("Play a GTK beep upon the selected events"), (void *)beeplist, 0},
 #endif
+#endif
+
+	{ST_TOGGLE,	N_("Omit alerts when marked as being away"), P_OFFINTNL(hex_away_omit_alerts), 0, 0, 0},
+	{ST_TOGGLE,	N_("Omit alerts while the window is focused"), P_OFFINTNL(hex_gui_focus_omitalerts), 0, 0, 0},
+
+	{ST_HEADER,	N_("Tray Behavior"), 0, 0, 0},
+	{ST_TOGGLE,	N_("Enable system tray icon"), P_OFFINTNL(hex_gui_tray), 0, 0, 4},
+	{ST_TOGGLE,	N_("Minimize to tray"), P_OFFINTNL(hex_gui_tray_minimize), 0, 0, 0},
+	{ST_TOGGLE,	N_("Close to tray"), P_OFFINTNL(hex_gui_tray_close), 0, 0, 0},
+	{ST_TOGGLE,	N_("Automatically mark away/back"), P_OFFINTNL(hex_gui_tray_away), N_("Automatically change status when hiding to tray."), 0, 0},
+	{ST_TOGGLE,	N_("Only show notifications when hidden or iconified"), P_OFFINTNL(hex_gui_tray_quiet), 0, 0, 0},
+
+	{ST_HEADER,	N_("Highlighted Messages"),0,0,0},
+	{ST_LABEL,	N_("Highlighted messages are ones where your nickname is mentioned, but also:"), 0, 0, 0, 1},
+
+	{ST_ENTRY,	N_("Extra words to highlight:"), P_OFFSETNL(hex_irc_extra_hilight), 0, 0, sizeof prefs.hex_irc_extra_hilight},
+	{ST_ENTRY,	N_("Nick names not to highlight:"), P_OFFSETNL(hex_irc_no_hilight), 0, 0, sizeof prefs.hex_irc_no_hilight},
+	{ST_ENTRY,	N_("Nick names to always highlight:"), P_OFFSETNL(hex_irc_nick_hilight), 0, 0, sizeof prefs.hex_irc_nick_hilight},
+	{ST_LABEL,	N_("Separate multiple words with commas.\nWildcards are accepted.")},
+
+	{ST_END, 0, 0, 0, 0, 0}
+};
+
+static const setting alert_settings_nonotifications[] =
+{
+	{ST_HEADER,	N_("Alerts"),0,0,0},
+
+	{ST_ALERTHEAD},
 	{ST_3OGGLE, N_("Blink tray icon on:"), 0, 0, (void *)trayblinklist, 0},
 #ifdef HAVE_GTK_MAC
 	{ST_3OGGLE, N_("Bounce dock icon on:"), 0, 0, (void *)taskbarlist, 0},
@@ -421,17 +461,10 @@ static const setting alert_settings[] =
 	{ST_TOGGLE,	N_("Omit alerts while the window is focused"), P_OFFINTNL(hex_gui_focus_omitalerts), 0, 0, 0},
 
 	{ST_HEADER,	N_("Tray Behavior"), 0, 0, 0},
-#ifdef WIN32
-	{ST_TOGGLE,	N_("Enable system tray icon"), P_OFFINTNL(hex_gui_tray), 0, 0, 3},
-#else
 	{ST_TOGGLE,	N_("Enable system tray icon"), P_OFFINTNL(hex_gui_tray), 0, 0, 4},
-#endif
 	{ST_TOGGLE,	N_("Minimize to tray"), P_OFFINTNL(hex_gui_tray_minimize), 0, 0, 0},
 	{ST_TOGGLE,	N_("Close to tray"), P_OFFINTNL(hex_gui_tray_close), 0, 0, 0},
 	{ST_TOGGLE,	N_("Automatically mark away/back"), P_OFFINTNL(hex_gui_tray_away), N_("Automatically change status when hiding to tray."), 0, 0},
-#ifndef WIN32
-	{ST_TOGGLE,	N_("Only show tray balloons when hidden or iconified"), P_OFFINTNL(hex_gui_tray_quiet), 0, 0, 0},
-#endif
 
 	{ST_HEADER,	N_("Highlighted Messages"),0,0,0},
 	{ST_LABEL,	N_("Highlighted messages are ones where your nickname is mentioned, but also:"), 0, 0, 0, 1},
@@ -449,7 +482,7 @@ static const setting alert_settings_unity[] =
 	{ST_HEADER,	N_("Alerts"),0,0,0},
 
 	{ST_ALERTHEAD},
-	{ST_3OGGLE, N_("Show tray balloons on:"), 0, 0, (void *)balloonlist, 0},
+	{ST_3OGGLE, N_("Show notifications on:"), 0, 0, (void *)balloonlist, 0},
 	{ST_3OGGLE, N_("Blink task bar on:"), 0, 0, (void *)taskbarlist, 0},
 	{ST_3OGGLE, N_("Make a beep sound on:"), 0, 0, (void *)beeplist, 0},
 
@@ -467,6 +500,28 @@ static const setting alert_settings_unity[] =
 	{ST_END, 0, 0, 0, 0, 0}
 };
 
+static const setting alert_settings_unityandnonotifications[] =
+{
+	{ST_HEADER, N_("Alerts"), 0, 0, 0},
+
+	{ST_ALERTHEAD},
+	{ST_3OGGLE, N_("Blink task bar on:"), 0, 0, (void *)taskbarlist, 0},
+	{ST_3OGGLE, N_("Make a beep sound on:"), 0, 0, (void *)beeplist, 0},
+
+	{ST_TOGGLE, N_("Omit alerts when marked as being away"), P_OFFINTNL (hex_away_omit_alerts), 0, 0, 0},
+	{ST_TOGGLE, N_("Omit alerts while the window is focused"), P_OFFINTNL (hex_gui_focus_omitalerts), 0, 0, 0},
+
+	{ST_HEADER, N_("Highlighted Messages"), 0, 0, 0},
+	{ST_LABEL, N_("Highlighted messages are ones where your nickname is mentioned, but also:"), 0, 0, 0, 1},
+
+	{ST_ENTRY, N_("Extra words to highlight:"), P_OFFSETNL (hex_irc_extra_hilight), 0, 0, sizeof prefs.hex_irc_extra_hilight},
+	{ST_ENTRY, N_("Nick names not to highlight:"), P_OFFSETNL (hex_irc_no_hilight), 0, 0, sizeof prefs.hex_irc_no_hilight},
+	{ST_ENTRY, N_("Nick names to always highlight:"), P_OFFSETNL (hex_irc_nick_hilight), 0, 0, sizeof prefs.hex_irc_nick_hilight},
+	{ST_LABEL, N_("Separate multiple words with commas.\nWildcards are accepted.")},
+
+	{ST_END, 0, 0, 0, 0, 0}
+};
+
 static const setting general_settings[] =
 {
 	{ST_HEADER,	N_("Default Messages"),0,0,0},
@@ -559,9 +614,6 @@ static const char *const proxytypes[] =
 	N_("Socks4"),
 	N_("Socks5"),
 	N_("HTTP"),
-#ifdef USE_MSPROXY
-	N_("MS Proxy (ISA)"),
-#endif
 #ifdef USE_LIBPROXY
 	N_("Auto"),
 #endif
@@ -598,11 +650,7 @@ static const setting network_settings[] =
 	{ST_MENU,	N_("Use proxy for:"), P_OFFINTNL(hex_net_proxy_use), 0, proxyuse, 0},
 
 	{ST_HEADER,	N_("Proxy Authentication"), 0, 0, 0, 0},
-#ifdef USE_MSPROXY
-	{ST_TOGGLE,	N_("Use Authentication (MS Proxy, HTTP or Socks5 only)"), P_OFFINTNL(hex_net_proxy_auth), 0, 0, 0},
-#else
 	{ST_TOGGLE,	N_("Use Authentication (HTTP or Socks5 only)"), P_OFFINTNL(hex_net_proxy_auth), 0, 0, 0},
-#endif
 	{ST_ENTRY,	N_("Username:"), P_OFFSETNL(hex_net_proxy_user), 0, 0, sizeof prefs.hex_net_proxy_user},
 	{ST_ENTRY,	N_("Password:"), P_OFFSETNL(hex_net_proxy_pass), 0, GINT_TO_POINTER(1), sizeof prefs.hex_net_proxy_pass},
 
@@ -630,7 +678,7 @@ setup_headlabel (GtkWidget *tab, int row, int col, char *text)
 	char buf[128];
 	char *sp;
 
-	snprintf (buf, sizeof (buf), "<b><span size=\"smaller\">%s</span></b>", text);
+	g_snprintf (buf, sizeof (buf), "<b><span size=\"smaller\">%s</span></b>", text);
 	sp = strchr (buf + 17, ' ');
 	if (sp)
 		*sp = '\n';
@@ -752,7 +800,7 @@ setup_create_italic_label (char *text)
 	char buf[256];
 
 	label = gtk_label_new (NULL);
-	snprintf (buf, sizeof (buf), "<i><span size=\"smaller\">%s</span></i>", text);
+	g_snprintf (buf, sizeof (buf), "<i><span size=\"smaller\">%s</span></i>", text);
 	gtk_label_set_markup (GTK_LABEL (label), buf);
 	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
 
@@ -1121,8 +1169,8 @@ setup_entry_cb (GtkEntry *entry, setting *set)
 {
 	int size;
 	int pos;
-	int len = gtk_entry_get_text_length (entry);
 	unsigned char *p = (unsigned char*)gtk_entry_get_text (entry);
+	int len = strlen (p);
 
 	/* need to truncate? */
 	if (len >= set->extra)
@@ -1220,9 +1268,9 @@ setup_create_header (GtkWidget *table, int row, char *labeltext)
 	char buf[128];
 
 	if (row == 0)
-		snprintf (buf, sizeof (buf), "<b>%s</b>", _(labeltext));
+		g_snprintf (buf, sizeof (buf), "<b>%s</b>", _(labeltext));
 	else
-		snprintf (buf, sizeof (buf), "\n<b>%s</b>", _(labeltext));
+		g_snprintf (buf, sizeof (buf), "\n<b>%s</b>", _(labeltext));
 
 	label = gtk_label_new (NULL);
 	gtk_label_set_markup (GTK_LABEL (label), buf);
@@ -1683,9 +1731,8 @@ setup_snd_changed_cb (GtkEntry *ent, GtkTreeView *tree)
 		return;
 
 	/* get the new sound file */
-	if (sound_files[n])
-		free (sound_files[n]);
-	sound_files[n] = strdup (gtk_entry_get_text (GTK_ENTRY (ent)));
+	g_free (sound_files[n]);
+	sound_files[n] = g_strdup (gtk_entry_get_text (GTK_ENTRY (ent)));
 
 	/* update the TreeView list */
 	store = (GtkListStore *)gtk_tree_view_get_model (tree);
@@ -1790,7 +1837,7 @@ setup_add_page (const char *title, GtkWidget *book, GtkWidget *tab)
 
 	/* label */
 	label = gtk_label_new (NULL);
-	snprintf (buf, sizeof (buf), "<b><big>%s</big></b>", _(title));
+	g_snprintf (buf, sizeof (buf), "<b><big>%s</big></b>", _(title));
 	gtk_label_set_markup (GTK_LABEL (label), buf);
 	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
 	gtk_misc_set_padding (GTK_MISC (label), 2, 1);
@@ -1839,10 +1886,18 @@ setup_create_pages (GtkWidget *box)
 
 	setup_add_page (cata[8], book, setup_create_page (general_settings));
 
-	if (unity_mode ())
+	if (unity_mode () && !notification_backend_supported ())
+	{
+		setup_add_page (cata[9], book, setup_create_page (alert_settings_unityandnonotifications));
+	}
+	else if (unity_mode ())
 	{
 		setup_add_page (cata[9], book, setup_create_page (alert_settings_unity));
 	}
+	else if (!notification_backend_supported ())
+	{
+		setup_add_page (cata[9], book, setup_create_page (alert_settings_nonotifications));
+	}
 	else
 	{
 		setup_add_page (cata[9], book, setup_create_page (alert_settings));
@@ -2121,6 +2176,8 @@ setup_apply (struct hexchatprefs *pr)
 		noapply = TRUE;
 	if (DIFF (hex_gui_ulist_style))
 		noapply = TRUE;
+	if (DIFF (hex_gui_ulist_sort))
+		noapply = TRUE;
 
 	if (DIFF (hex_gui_tab_dots))
 		do_layout = TRUE;
@@ -2137,6 +2194,13 @@ setup_apply (struct hexchatprefs *pr)
 						" menu first."),
 						FE_MSG_WARN | FE_MSG_MARKUP);
 
+	/* format cannot be blank, there is already a setting for this */
+	if (pr->hex_stamp_text_format[0] == 0)
+	{
+		pr->hex_stamp_text = 0;
+		strcpy (pr->hex_stamp_text_format, prefs.hex_stamp_text_format);
+	}
+
 	memcpy (&prefs, pr, sizeof (prefs));
 
 #ifdef WIN32
diff --git a/src/fe-gtk/sexy-iso-codes.c b/src/fe-gtk/sexy-iso-codes.c
index e6acb726..06c8cd07 100644
--- a/src/fe-gtk/sexy-iso-codes.c
+++ b/src/fe-gtk/sexy-iso-codes.c
@@ -19,10 +19,11 @@
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
+#include "config.h"
+
 #include "sexy-iso-codes.h"
 #include <libintl.h>
 #include <string.h>
-#include "../../config.h"
 
 #define ISO_639_DOMAIN	"iso_639"
 #define ISO_3166_DOMAIN	"iso_3166"
diff --git a/src/fe-gtk/sexy-spell-entry.c b/src/fe-gtk/sexy-spell-entry.c
index bac1e2b5..f57c7f41 100644
--- a/src/fe-gtk/sexy-spell-entry.c
+++ b/src/fe-gtk/sexy-spell-entry.c
@@ -31,7 +31,12 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include "sexy-iso-codes.h"
+
+#ifdef WIN32
+#include "marshal.h"
+#else
 #include "../common/marshal.h"
+#endif
 
 #ifdef WIN32
 #include "../common/typedef.h"
@@ -136,6 +141,8 @@ enum
 };
 static guint signals[LAST_SIGNAL] = {0};
 
+static PangoAttrList *empty_attrs_list = NULL;
+
 static gboolean
 spell_accumulator(GSignalInvocationHint *hint, GValue *return_accu, const GValue *handler_return, gpointer data)
 {
@@ -243,6 +250,11 @@ sexy_spell_entry_class_init(SexySpellEntryClass *klass)
 					   _hexchat_marshal_BOOLEAN__STRING,
 					   G_TYPE_BOOLEAN,
 					   1, G_TYPE_STRING);
+
+	if (empty_attrs_list == NULL)
+	{
+		empty_attrs_list = pango_attr_list_new ();
+	}
 }
 
 static void
@@ -292,7 +304,7 @@ insert_hiddenchar (SexySpellEntry *entry, guint start, guint end)
 	 * is 'hidden' */
 #if 0
 	PangoAttribute *hattr;
-	PangoRectangle *rect = g_malloc (sizeof (PangoRectangle));
+	PangoRectangle *rect = g_new (PangoRectangle, 1);
 
 	rect->x = 0;
 	rect->y = 0;
@@ -758,12 +770,9 @@ sexy_spell_entry_finalize(GObject *obj)
 		pango_attr_list_unref(entry->priv->attr_list);
 	if (entry->priv->dict_hash)
 		g_hash_table_destroy(entry->priv->dict_hash);
-	if (entry->priv->words)
-		g_strfreev(entry->priv->words);
-	if (entry->priv->word_starts)
-		g_free(entry->priv->word_starts);
-	if (entry->priv->word_ends)
-		g_free(entry->priv->word_ends);
+	g_strfreev(entry->priv->words);
+	g_free(entry->priv->word_starts);
+	g_free(entry->priv->word_ends);
 
 	if (have_enchant) {
 		if (entry->priv->broker) {
@@ -1038,7 +1047,7 @@ sexy_spell_entry_recheck_all(SexySpellEntry *entry)
 	{
 		/* Check for attributes */
 		text = gtk_entry_get_text (GTK_ENTRY (entry));
-		text_len = gtk_entry_get_text_length (GTK_ENTRY (entry));
+		text_len = strlen (text);
 		check_attributes (entry, text, text_len);
 	}
 
@@ -1078,7 +1087,14 @@ sexy_spell_entry_expose(GtkWidget *widget, GdkEventExpose *event)
 
 	
 	layout = gtk_entry_get_layout(gtk_entry);
-	pango_layout_set_attributes(layout, entry->priv->attr_list);
+	if (gtk_entry->preedit_length == 0)
+	{
+		pango_layout_set_attributes(layout, entry->priv->attr_list);
+	}
+	else
+	{
+		pango_layout_set_attributes(layout, empty_attrs_list);
+	}
 
 	return GTK_WIDGET_CLASS(parent_class)->expose_event (widget, event);
 }
diff --git a/src/fe-gtk/textgui.c b/src/fe-gtk/textgui.c
index 9956e9c6..b0f2f392 100644
--- a/src/fe-gtk/textgui.c
+++ b/src/fe-gtk/textgui.c
@@ -81,14 +81,14 @@ PrintTextLine (xtext_buffer *xtbuf, unsigned char *text, int len, int indent, ti
 				timet = time (0);
 
 			stamp_size = get_stamp_str (prefs.hex_stamp_text_format, timet, &stamp);
-			new_text = malloc (len + stamp_size + 1);
+			new_text = g_malloc (len + stamp_size + 1);
 			memcpy (new_text, stamp, stamp_size);
 			g_free (stamp);
 			memcpy (new_text + stamp_size, text, len);
-			gtk_xtext_append (xtbuf, new_text, len + stamp_size);
-			free (new_text);
+			gtk_xtext_append (xtbuf, new_text, len + stamp_size, timet);
+			g_free (new_text);
 		} else
-			gtk_xtext_append (xtbuf, text, len);
+			gtk_xtext_append (xtbuf, text, len, timet);
 		return;
 	}
 
@@ -173,13 +173,12 @@ pevent_edited (GtkCellRendererText *render, gchar *pathstr, gchar *new_text, gpo
 	}
 	if (m > (te[sig].num_args & 0x7f))
 	{
-		free (out);
-		out = malloc (4096);
-		snprintf (out, 4096,
-					_("This signal is only passed %d args, $%d is invalid"),
-					te[sig].num_args & 0x7f, m);
+		g_free (out);
+		out = g_strdup_printf (
+			_("This signal is only passed %d args, $%d is invalid"),
+			te[sig].num_args & 0x7f, m);
 		fe_message (out, FE_MSG_WARN);
-		free (out);
+		g_free (out);
 		return;
 	}
 
@@ -188,23 +187,20 @@ pevent_edited (GtkCellRendererText *render, gchar *pathstr, gchar *new_text, gpo
 	gtk_list_store_set (GTK_LIST_STORE (model), &iter, TEXT_COLUMN, new_text, -1);
 	gtk_tree_path_free (path);
 
-	if (pntevts_text[sig])
-		free (pntevts_text[sig]);
-	if (pntevts[sig])
-		free (pntevts[sig]);
+	g_free (pntevts_text[sig]);
+	g_free (pntevts[sig]);
 
-	pntevts_text[sig] = malloc (len + 1);
-	memcpy (pntevts_text[sig], text, len + 1);
+	pntevts_text[sig] = g_strdup (text);
 	pntevts[sig] = out;
 
-	out = malloc (len + 2);
+	out = g_malloc (len + 2);
 	memcpy (out, text, len + 1);
 	out[len] = '\n';
 	out[len + 1] = 0;
 	check_special_chars (out, TRUE);
 
 	PrintTextRaw (xtext->buffer, out, 0, 0);
-	free (out);
+	g_free (out);
 
 	/* Scroll to bottom */
 	gtk_adjustment_set_value (xtext->adj, gtk_adjustment_get_upper (xtext->adj));
@@ -328,14 +324,14 @@ pevent_test_cb (GtkWidget * wid, GtkWidget * twid)
 		text = _(pntevts_text[n]);
 		len = strlen (text);
 
-		out = malloc (len + 2);
+		out = g_malloc (len + 2);
 		memcpy (out, text, len + 1);
 		out[len] = '\n';
 		out[len + 1] = 0;
 		check_special_chars (out, TRUE);
 
 		PrintTextRaw (GTK_XTEXT (twid)->buffer, out, 0, 0);
-		free (out);
+		g_free (out);
 	}
 }
 
diff --git a/src/fe-gtk/userlistgui.c b/src/fe-gtk/userlistgui.c
index 19564ece..d06975ca 100644
--- a/src/fe-gtk/userlistgui.c
+++ b/src/fe-gtk/userlistgui.c
@@ -42,11 +42,11 @@
 
 enum
 {
-	COL_PIX=0,		// GdkPixbuf *
-	COL_NICK=1,		// char *
-	COL_HOST=2,		// char *
-	COL_USER=3,		// struct User *
-	COL_GDKCOLOR=4	// GdkColor *
+	COL_PIX=0,		/* GdkPixbuf * */
+	COL_NICK=1,		/* char * */
+	COL_HOST=2,		/* char * */
+	COL_USER=3,		/* struct User * */
+	COL_GDKCOLOR=4	/* GdkColor * */
 };
 
 
@@ -105,7 +105,7 @@ fe_userlist_numbers (session *sess)
 	{
 		if (sess->total)
 		{
-			snprintf (tbuf, sizeof (tbuf), _("%d ops, %d total"), sess->ops, sess->total);
+			g_snprintf (tbuf, sizeof (tbuf), _("%d ops, %d total"), sess->ops, sess->total);
 			tbuf[sizeof (tbuf) - 1] = 0;
 			gtk_label_set_text (GTK_LABEL (sess->gui->namelistinfo), tbuf);
 		} else
@@ -188,7 +188,7 @@ userlist_selection_list (GtkWidget *widget, int *num_ret)
 	if (num_sel < 1)
 		return NULL;
 
-	nicks = malloc (sizeof (char *) * (num_sel + 1));
+	nicks = g_new (char *, num_sel + 1);
 
 	i = 0;
 	gtk_tree_model_get_iter_first (model, &iter);
@@ -286,7 +286,7 @@ fe_userlist_remove (session *sess, struct User *user)
 	int sel;
 
 	iter = find_row (GTK_TREE_VIEW (sess->gui->user_tree),
-						  sess->res->user_model, user, &sel);
+						  GTK_TREE_MODEL(sess->res->user_model), user, &sel);
 	if (!iter)
 		return 0;
 
@@ -316,7 +316,7 @@ fe_userlist_rehash (session *sess, struct User *user)
 	int nick_color = 0;
 
 	iter = find_row (GTK_TREE_VIEW (sess->gui->user_tree),
-						  sess->res->user_model, user, &sel);
+						  GTK_TREE_MODEL(sess->res->user_model), user, &sel);
 	if (!iter)
 		return;
 
@@ -332,9 +332,9 @@ fe_userlist_rehash (session *sess, struct User *user)
 }
 
 void
-fe_userlist_insert (session *sess, struct User *newuser, int row, int sel)
+fe_userlist_insert (session *sess, struct User *newuser, gboolean sel)
 {
-	GtkTreeModel *model = sess->res->user_model;
+	GtkTreeModel *model = GTK_TREE_MODEL(sess->res->user_model);
 	GdkPixbuf *pix = get_user_icon (sess->server, newuser);
 	GtkTreeIter iter;
 	char *nick;
@@ -348,16 +348,16 @@ fe_userlist_insert (session *sess, struct User *newuser, int row, int sel)
 	nick = newuser->nick;
 	if (!prefs.hex_gui_ulist_icons)
 	{
-		nick = malloc (strlen (newuser->nick) + 2);
+		nick = g_malloc (strlen (newuser->nick) + 2);
 		nick[0] = newuser->prefix[0];
-		if (!nick[0] || nick[0] == ' ')
+		if (nick[0] == '\0' || nick[0] == ' ')
 			strcpy (nick, newuser->nick);
 		else
 			strcpy (nick + 1, newuser->nick);
 		pix = NULL;
 	}
 
-	gtk_list_store_insert_with_values (GTK_LIST_STORE (model), &iter, row,
+	gtk_list_store_insert_with_values (GTK_LIST_STORE (model), &iter, 0,
 									COL_PIX, pix,
 									COL_NICK, nick,
 									COL_HOST, newuser->hostname,
@@ -367,7 +367,7 @@ fe_userlist_insert (session *sess, struct User *newuser, int row, int sel)
 
 	if (!prefs.hex_gui_ulist_icons)
 	{
-		free (nick);
+		g_free (nick);
 	}
 
 	/* is it me? */
@@ -377,14 +377,6 @@ fe_userlist_insert (session *sess, struct User *newuser, int row, int sel)
 			mg_set_access_icon (sess->gui, pix, sess->server->is_away);
 	}
 
-#if 0
-	if (prefs.hilitenotify && notify_isnotify (sess, newuser->nick))
-	{
-		gtk_clist_set_foreground ((GtkCList *) sess->gui->user_clist, row,
-										  &colors[prefs.nu_color]);
-	}
-#endif
-
 	/* is it the front-most tab? */
 	if (gtk_tree_view_get_model (GTK_TREE_VIEW (sess->gui->user_tree))
 		 == model)
@@ -396,12 +388,6 @@ fe_userlist_insert (session *sess, struct User *newuser, int row, int sel)
 }
 
 void
-fe_userlist_move (session *sess, struct User *user, int new_row)
-{
-	fe_userlist_insert (sess, user, new_row, fe_userlist_remove (sess, user));
-}
-
-void
 fe_userlist_clear (session *sess)
 {
 	gtk_list_store_clear (sess->res->user_model);
@@ -459,11 +445,67 @@ userlist_dnd_leave (GtkTreeView *widget, GdkDragContext *context, guint ttime)
 	return TRUE;
 }
 
-void *
-userlist_create_model (void)
+static int
+userlist_alpha_cmp (GtkTreeModel *model, GtkTreeIter *iter_a, GtkTreeIter *iter_b, gpointer userdata)
+{
+	struct User *user_a, *user_b;
+
+	gtk_tree_model_get (model, iter_a, COL_USER, &user_a, -1);
+	gtk_tree_model_get (model, iter_b, COL_USER, &user_b, -1);
+
+	return nick_cmp_alpha (user_a, user_b, ((session*)userdata)->server);
+}
+
+static int
+userlist_ops_cmp (GtkTreeModel *model, GtkTreeIter *iter_a, GtkTreeIter *iter_b, gpointer userdata)
 {
-	return gtk_list_store_new (5, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING,
+	struct User *user_a, *user_b;
+
+	gtk_tree_model_get (model, iter_a, COL_USER, &user_a, -1);
+	gtk_tree_model_get (model, iter_b, COL_USER, &user_b, -1);
+
+	return nick_cmp_az_ops (((session*)userdata)->server, user_a, user_b);
+}
+
+GtkListStore *
+userlist_create_model (session *sess)
+{
+	GtkListStore *store;
+	GtkTreeIterCompareFunc cmp_func;
+	GtkSortType sort_type;
+
+	store = gtk_list_store_new (5, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING,
 										G_TYPE_POINTER, GDK_TYPE_COLOR);
+
+	switch (prefs.hex_gui_ulist_sort)
+	{
+	case 0:
+		cmp_func = userlist_ops_cmp;
+		sort_type = GTK_SORT_ASCENDING;
+		break;
+	case 1:
+		cmp_func = userlist_alpha_cmp;
+		sort_type = GTK_SORT_ASCENDING;
+		break;
+	case 2:
+		cmp_func = userlist_ops_cmp;
+		sort_type = GTK_SORT_DESCENDING;
+		break;
+	case 3:
+		cmp_func = userlist_alpha_cmp;
+		sort_type = GTK_SORT_DESCENDING;
+		break;
+	default:
+		/* No sorting */
+		gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE(store), NULL, NULL, NULL);
+		return store;
+	}
+
+	gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE(store), cmp_func, sess, NULL);
+	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(store),
+						GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, sort_type);
+
+	return store;
 }
 
 static void
@@ -525,7 +567,7 @@ userlist_click_cb (GtkWidget *widget, GdkEventButton *event, gpointer userdata)
 				i--;
 				g_free (nicks[i]);
 			}
-			free (nicks);
+			g_free (nicks);
 		}
 		return TRUE;
 	}
@@ -542,13 +584,13 @@ userlist_click_cb (GtkWidget *widget, GdkEventButton *event, gpointer userdata)
 				i--;
 				g_free (nicks[i]);
 			}
-			free (nicks);
+			g_free (nicks);
 			return TRUE;
 		}
 		if (nicks)
 		{
 			g_free (nicks[0]);
-			free (nicks);
+			g_free (nicks);
 		}
 
 		sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
@@ -567,7 +609,7 @@ userlist_click_cb (GtkWidget *widget, GdkEventButton *event, gpointer userdata)
 					i--;
 					g_free (nicks[i]);
 				}
-				free (nicks);
+				g_free (nicks);
 			}
 		} else
 		{
@@ -668,7 +710,7 @@ void
 userlist_show (session *sess)
 {
 	gtk_tree_view_set_model (GTK_TREE_VIEW (sess->gui->user_tree),
-									 sess->res->user_model);
+									 GTK_TREE_MODEL(sess->res->user_model));
 }
 
 void
diff --git a/src/fe-gtk/userlistgui.h b/src/fe-gtk/userlistgui.h
index 993fe8f0..e24f2ebc 100644
--- a/src/fe-gtk/userlistgui.h
+++ b/src/fe-gtk/userlistgui.h
@@ -23,7 +23,7 @@
 void userlist_set_value (GtkWidget *treeview, gfloat val);
 gfloat userlist_get_value (GtkWidget *treeview);
 GtkWidget *userlist_create (GtkWidget *box);
-void *userlist_create_model (void);
+GtkListStore *userlist_create_model (session *sess);
 void userlist_show (session *sess);
 void userlist_select (session *sess, char *name);
 char **userlist_selection_list (GtkWidget *widget, int *num_ret);
diff --git a/src/fe-gtk/xtext.c b/src/fe-gtk/xtext.c
index 6a499f52..6692b360 100644
--- a/src/fe-gtk/xtext.c
+++ b/src/fe-gtk/xtext.c
@@ -31,13 +31,19 @@
 #include <stdlib.h>
 #include <time.h>
 
-#include "../../config.h"
+#include "config.h"
 #include "../common/hexchat.h"
 #include "../common/fe.h"
 #include "../common/util.h"
 #include "../common/hexchatc.h"
 #include "../common/url.h"
+
+#ifdef WIN32
+#include "marshal.h"
+#else
 #include "../common/marshal.h"
+#endif
+
 #include "fe-gtk.h"
 #include "xtext.h"
 #include "fkeys.h"
@@ -484,7 +490,10 @@ gtk_xtext_adjustment_set (xtext_buffer *buf, int fire_signal)
 		adj->page_increment = adj->page_size;
 
 		if (adj->value > adj->upper - adj->page_size)
+		{
+			buf->scrollbar_down = TRUE;
 			adj->value = adj->upper - adj->page_size;
+		}
 
 		if (adj->value < 0)
 			adj->value = 0;
@@ -829,7 +838,6 @@ find_x (GtkXText *xtext, textentry *ent, int x, int subline, int indent)
 	int off, len, wid, mbl, mbw;
 
 	/* Skip to the first chunk of stuff for the subline */
-	list = ent->slp;
 	if (subline > 0)
 	{
 		suboff = GPOINTER_TO_INT (g_slist_nth_data (ent->sublines, subline - 1));
@@ -846,6 +854,8 @@ find_x (GtkXText *xtext, textentry *ent, int x, int subline, int indent)
 		list = ent->slp;
 	} 
 	/* Step to the first character of the subline */
+	if (list == NULL)
+		return 0;
 	meta = list->data;
 	off = meta->off;
 	len = meta->len;
@@ -934,12 +944,12 @@ gtk_xtext_find_x (GtkXText * xtext, int x, textentry * ent, int subline,
 }
 
 static textentry *
-gtk_xtext_find_char (GtkXText * xtext, int x, int y, int *off,
-							int *out_of_bounds, int *ret_subline)
+gtk_xtext_find_char (GtkXText * xtext, int x, int y, int *off, int *out_of_bounds)
 {
 	textentry *ent;
 	int line;
 	int subline;
+	int outofbounds;
 
 	/* Adjust y value for negative rounding, double to int */
 	if (y < 0)
@@ -948,13 +958,12 @@ gtk_xtext_find_char (GtkXText * xtext, int x, int y, int *off,
 	line = (y + xtext->pixel_offset) / xtext->fontsize;
 	ent = gtk_xtext_nth (xtext, line + (int)xtext->adj->value, &subline);
 	if (!ent)
-		return 0;
+		return NULL;
 
 	if (off)
-		*off = gtk_xtext_find_x (xtext, x, ent, subline, line, out_of_bounds);
-
-	if (ret_subline)
-		*ret_subline = subline;
+		*off = gtk_xtext_find_x (xtext, x, ent, subline, line, &outofbounds);
+	if (out_of_bounds)
+		*out_of_bounds = outofbounds;
 
 	return ent;
 }
@@ -1049,14 +1058,14 @@ gtk_xtext_paint (GtkWidget *widget, GdkRectangle *area)
 		return;
 	}
 
-	ent_start = gtk_xtext_find_char (xtext, area->x, area->y, NULL, NULL, NULL);
+	ent_start = gtk_xtext_find_char (xtext, area->x, area->y, NULL, NULL);
 	if (!ent_start)
 	{
 		xtext_draw_bg (xtext, area->x, area->y, area->width, area->height);
 		goto xit;
 	}
 	ent_end = gtk_xtext_find_char (xtext, area->x + area->width,
-											 area->y + area->height, NULL, NULL, NULL);
+											 area->y + area->height, NULL, NULL);
 	if (!ent_end)
 		ent_end = xtext->buffer->text_last;
 
@@ -1244,13 +1253,14 @@ lamejump:
 		}
 	}
 	/* marking upward? */
-	else if (xtext->buffer->last_ent_end == end_ent &&
+	else if (xtext->buffer->last_ent_start != NULL &&
+				xtext->buffer->last_ent_end == end_ent &&
 				xtext->buffer->last_offset_end == end_offset)
 	{
 		ent = end_ent;
 		while (ent)
 		{
-			if (ent == start_ent)
+			if (ent == start_ent && xtext->buffer->last_ent_start)
 			{
 				gtk_xtext_selection_up (xtext, xtext->buffer->last_ent_start, ent, start_offset);
 				/*gtk_xtext_render_ents (xtext, xtext->buffer->last_ent_start, ent);*/
@@ -1299,99 +1309,104 @@ gtk_xtext_selection_draw (GtkXText * xtext, GdkEventMotion * event, gboolean ren
 	textentry *ent;
 	textentry *ent_end;
 	textentry *ent_start;
-	int offset_start;
-	int offset_end;
-	int subline_start;
-	int subline_end;
-	int oob;
-	int marking_up = FALSE;
-	int len_start;
-	int len_end;
+	int offset_start = 0;
+	int offset_end = 0;
+	textentry *low_ent, *high_ent;
+	int low_x, low_y, low_offs;
+	int high_x, high_y, high_offs, high_len;
 
-	ent_start = gtk_xtext_find_char (xtext, xtext->select_start_x, xtext->select_start_y, &offset_start, &oob, &subline_start);
-	ent_end = gtk_xtext_find_char (xtext, xtext->select_end_x, xtext->select_end_y, &offset_end, &oob, &subline_end);
+	if (xtext->buffer->text_first == NULL)
+		return;
 
-	if ((!ent_start || !ent_end) && !xtext->buffer->text_last && xtext->adj->value != xtext->buffer->old_value)
-	{
-		gtk_xtext_render_page (xtext);
+	ent_start = gtk_xtext_find_char (xtext, xtext->select_start_x, xtext->select_start_y, &offset_start, NULL);
+	ent_end = gtk_xtext_find_char (xtext, xtext->select_end_x, xtext->select_end_y, &offset_end, NULL);
+	if (ent_start == NULL && ent_end == NULL)
 		return;
-	}
 
-	if (!ent_start)
+	if	((ent_start != ent_end && xtext->select_start_y > xtext->select_end_y) || /* different entries */
+		(ent_start == ent_end && offset_start > offset_end))	/* same entry, different character offsets */
 	{
-		ent_start = xtext->buffer->text_last;
-		offset_start = ent_start->str_len;
+		/* marking up */
+		low_ent = ent_end;
+		low_x = xtext->select_end_x;
+		low_y = xtext->select_end_y;
+		low_offs = offset_end;
+		high_ent = ent_start;
+		high_x = xtext->select_start_x;
+		high_y = xtext->select_start_y;
+		high_offs = offset_start;
 	}
-
-	if (!ent_end)
+	else
 	{
-		ent_end = xtext->buffer->text_last;
-		offset_end = ent_end->str_len;
+		/* marking down */
+		low_ent = ent_start;
+		low_x = xtext->select_start_x;
+		low_y = xtext->select_start_y;
+		low_offs = offset_start;
+		high_ent = ent_end;
+		high_x = xtext->select_end_x;
+		high_y = xtext->select_end_y;
+		high_offs = offset_end;
 	}
-
-	if ((ent_start != ent_end && xtext->select_start_y > xtext->select_end_y) || /* different entries */
-		(ent_start == ent_end && subline_start > subline_end) || /* different lines */
-		(ent_start == ent_end && subline_start == subline_end && xtext->select_start_x > xtext->select_end_x)) /* marking to the left */
+	if (low_ent == NULL)
+	{
+		low_ent = xtext->buffer->text_first;
+		low_offs = 0;
+	}
+	if (high_ent == NULL)
 	{
-		marking_up = TRUE;
+		high_ent = xtext->buffer->text_last;
+		high_offs = high_ent->str_len;
 	}
 
 	/* word selection */
 	if (xtext->word_select)
 	{
 		/* a word selection cannot be started if the cursor is out of bounds in gtk_xtext_button_press */
-		gtk_xtext_get_word (xtext, xtext->select_start_x, xtext->select_start_y, NULL, &offset_start, &len_start, NULL);
+		gtk_xtext_get_word (xtext, low_x, low_y, NULL, &low_offs, NULL, NULL);
 
 		/* in case the cursor is out of bounds we keep offset_end from gtk_xtext_find_char and fix the length */
-		if (gtk_xtext_get_word (xtext, xtext->select_end_x, xtext->select_end_y, NULL, &offset_end, &len_end, NULL) == NULL)
-			len_end = offset_end == ent_end->str_len? 0: -1; /* -1 for the space, 0 if at the end */
-
-		if (!marking_up)
-			offset_end += len_end;
-		else
-			offset_start += len_start;
+		if (gtk_xtext_get_word (xtext, high_x, high_y, NULL, &high_offs, &high_len, NULL) == NULL)
+			high_len = high_offs == high_ent->str_len? 0: -1; /* -1 for the space, 0 if at the end */
+		high_offs += high_len;
+		if (low_y < 0)
+			low_offs = xtext->buffer->last_offset_start;
+		if (high_y > xtext->buffer->window_height)
+			high_offs = xtext->buffer->last_offset_end;
 	}
 	/* line/ent selection */
 	else if (xtext->line_select)
 	{
-		offset_start = marking_up? ent_start->str_len: 0;
-		offset_end = marking_up? 0: ent_end->str_len;
+		low_offs = 0;
+		high_offs = high_ent->str_len;
 	}
-
-	if (marking_up)
+	/* character selection */
+	else
 	{
-		int temp;
-
-		/* ensure ent_start is above ent_end */
-		if (ent_start != ent_end)
-		{
-			ent = ent_start;
-			ent_start = ent_end;
-			ent_end = ent;
-		}
-
-		/* switch offsets as well */
-		temp = offset_start;
-		offset_start = offset_end;
-		offset_end = temp;
+		if (low_y < 0)
+			low_offs = xtext->buffer->last_offset_start;
+		if (high_y > xtext->buffer->window_height)
+			high_offs = xtext->buffer->last_offset_end;
 	}
 
 	/* set all the old mark_ fields to -1 */
 	gtk_xtext_selection_clear (xtext->buffer);
 
-	/* set the default values */
-	ent_start->mark_end = ent_start->str_len;
-	ent_end->mark_start = 0;
+	low_ent->mark_start = low_offs;
+	low_ent->mark_end = high_offs;
 
-	/* set the calculated values (this overwrites the default values if we're on the same ent) */
-	ent_start->mark_start = offset_start;
-	ent_end->mark_end = offset_end;
-
-	/* set all the mark_ fields of the ents within the selection */
-	if (ent_start != ent_end)
+	if (low_ent != high_ent)
 	{
-		ent = ent_start->next;
-		while (ent && ent != ent_end)
+		low_ent->mark_end = low_ent->str_len;
+		if (high_offs != 0)
+		{
+			high_ent->mark_start = 0;
+			high_ent->mark_end = high_offs;
+		}
+
+		/* set all the mark_ fields of the ents within the selection */
+		ent = low_ent->next;
+		while (ent && ent != high_ent)
 		{
 			ent->mark_start = 0;
 			ent->mark_end = ent->str_len;
@@ -1400,7 +1415,7 @@ gtk_xtext_selection_draw (GtkXText * xtext, GdkEventMotion * event, gboolean ren
 	}
 
 	if (render)
-		gtk_xtext_selection_render (xtext, ent_start, ent_end);
+		gtk_xtext_selection_render (xtext, low_ent, high_ent);
 }
 
 static int
@@ -1532,7 +1547,7 @@ gtk_xtext_get_word (GtkXText * xtext, int x, int y, textentry ** ret_ent,
 	int out_of_bounds = 0;
 	int len_to_offset = 0;
 
-	ent = gtk_xtext_find_char (xtext, x, y, &offset, &out_of_bounds, NULL);
+	ent = gtk_xtext_find_char (xtext, x, y, &offset, &out_of_bounds);
 	if (ent == NULL || out_of_bounds || offset < 0 || offset >= ent->str_len)
 		return NULL;
 
@@ -1585,11 +1600,11 @@ gtk_xtext_get_word (GtkXText * xtext, int x, int y, textentry ** ret_ent,
 
 		/* make sure we're not before the start of the match */
 		if (len_to_offset < start)
-			return 0;
+			return NULL;
 
 		/* and not after it */
 		if (len_to_offset - start >= end - start)
-			return 0;
+			return NULL;
 	}
 
 	return word;
@@ -1646,7 +1661,8 @@ gtk_xtext_check_mark_stamp (GtkXText *xtext, GdkModifierType mask)
 {
 	gboolean redraw = FALSE;
 
-	if (mask & STATE_SHIFT || prefs.hex_text_autocopy_stamp)
+	if ((mask & STATE_SHIFT || prefs.hex_text_autocopy_stamp)
+	    && (!prefs.hex_stamp_text || prefs.hex_text_indent))
 	{
 		if (!xtext->mark_stamp)
 		{
@@ -1707,7 +1723,7 @@ gtk_xtext_get_word_adjust (GtkXText *xtext, int x, int y, textentry **word_ent,
 			}
 		}
 	}
-	g_slist_free_full (slp, free);
+	g_slist_free_full (slp, g_free);
 
 	return word_type;
 }
@@ -1853,7 +1869,7 @@ gtk_xtext_set_clip_owner (GtkWidget * xtext, GdkEventButton * event)
 			gtk_selection_owner_set (xtext, GDK_SELECTION_SECONDARY, event ? event->time : GDK_CURRENT_TIME);
 		}
 
-		free (str);
+		g_free (str);
 	}
 }
 
@@ -2107,7 +2123,7 @@ gtk_xtext_selection_get_text (GtkXText *xtext, int *len_ret)
 		return NULL;
 
 	/* now allocate mem and copy buffer */
-	pos = txt = malloc (len);
+	pos = txt = g_malloc (len);
 	ent = buf->last_ent_start;
 	while (ent)
 	{
@@ -2147,10 +2163,11 @@ gtk_xtext_selection_get_text (GtkXText *xtext, int *len_ret)
 		/*stripped = gtk_xtext_conv_color (txt, strlen (txt), &len);*/
 		stripped = txt;
 		len = strlen (txt);
-	} else
+	}
+	else
 	{
 		stripped = gtk_xtext_strip_color (txt, strlen (txt), NULL, &len, NULL, FALSE);
-		free (txt);
+		g_free (txt);
 	}
 
 	*len_ret = len;
@@ -2205,7 +2222,7 @@ gtk_xtext_selection_get (GtkWidget * widget,
 		g_free (new_text);
 	}
 
-	free (stripped);
+	g_free (stripped);
 }
 
 static gboolean
@@ -2360,7 +2377,7 @@ xtext_do_chunk(chunk_t *c)
 	if (c->len1 == 0)
 		return;
 
-	meta = malloc (sizeof *meta);
+	meta = g_new (offlen_t, 1);
 	meta->off = c->off1;
 	meta->len = c->len1;
 	meta->emph = c->emph;
@@ -2383,7 +2400,7 @@ gtk_xtext_strip_color (unsigned char *text, int len, unsigned char *outbuf,
 	int mbl;	/* multi-byte length */
 
 	if (outbuf == NULL)
-		new_str = malloc (len + 2);
+		new_str = g_malloc (len + 2);
 	else
 		new_str = outbuf;
 
@@ -2459,7 +2476,7 @@ bad_utf8:		/* Normal ending sequence, and give up if bad utf8 */
 	if (slpp)
 		*slpp = c.slp;
 	else
-		g_slist_free_full (c.slp, free);
+		g_slist_free_full (c.slp, g_free);
 
 	return new_str;
 }
@@ -2475,7 +2492,7 @@ gtk_xtext_text_width_ent (GtkXText *xtext, textentry *ent)
 
 	if (ent->slp)
 	{
-		g_slist_free_full (ent->slp, free);
+		g_slist_free_full (ent->slp, g_free);
 		ent->slp = NULL;
 	}
 
@@ -2507,7 +2524,7 @@ gtk_xtext_text_width (GtkXText *xtext, unsigned char *text, int len)
 												&new_len, &slp, !xtext->ignore_hidden);
 
 	width =  backend_get_text_width_slp (xtext, new_buf, slp);
-	g_slist_free_full (slp, free);
+	g_slist_free_full (slp, g_free);
 
 	return width;
 }
@@ -3254,7 +3271,7 @@ gtk_xtext_render_stamp (GtkXText * xtext, textentry * ent,
 {
 	textentry tmp_ent;
 	int jo, ji, hs;
-	int xsize, y;
+	int xsize, y, emphasis;
 
 	/* trashing ent here, so make a backup first */
 	memcpy (&tmp_ent, ent, sizeof (tmp_ent));
@@ -3264,7 +3281,7 @@ gtk_xtext_render_stamp (GtkXText * xtext, textentry * ent,
 	xtext->jump_out_offset = 0;
 	xtext->jump_in_offset = 0;
 	xtext->hilight_start = 0xffff;	/* temp disable */
-	int emphasis = 0;
+	emphasis = 0;
 
 	if (xtext->mark_stamp)
 	{
@@ -3530,7 +3547,7 @@ gtk_xtext_save (GtkXText * xtext, int fh)
 											  &newlen, NULL, FALSE);
 		write (fh, buf, newlen);
 		write (fh, "\n", 1);
-		free (buf);
+		g_free (buf);
 		ent = ent->next;
 	}
 }
@@ -3641,7 +3658,7 @@ gtk_xtext_nth (GtkXText *xtext, int line, int *subline)
 					break;
 				lines -= g_slist_length (ent->sublines);
 			}
-			return 0;
+			return NULL;
 		}
 	}
 	/* -- end of optimization -- */
@@ -3656,7 +3673,7 @@ gtk_xtext_nth (GtkXText *xtext, int line, int *subline)
 		}
 		ent = ent->next;
 	}
-	return 0;
+	return NULL;
 }
 
 /* render enta (or an inclusive range enta->entb) */
@@ -3895,10 +3912,10 @@ gtk_xtext_kill_ent (xtext_buffer *buffer, textentry *ent)
 		gtk_xtext_search_textentry_del (buffer, ent);
 	}
 
-	g_slist_free_full (ent->slp, free);
+	g_slist_free_full (ent->slp, g_free);
 	g_slist_free (ent->sublines);
 
-	free (ent);
+	g_free (ent);
 	return visible;
 }
 
@@ -4033,7 +4050,7 @@ gtk_xtext_clear (xtext_buffer *buf, int lines)
 		while (buf->text_first)
 		{
 			next = buf->text_first->next;
-			free (buf->text_first);
+			g_free (buf->text_first);
 			buf->text_first = next;
 		}
 		buf->text_last = NULL;
@@ -4191,7 +4208,6 @@ gtk_xtext_search_textentry (xtext_buffer *buf, textentry *ent)
 
 		hay = match? g_strdup (str): g_utf8_casefold (str, lstr);
 		lhay = strlen (hay);
-		off = 0;
 
 		for (pos = hay, len = lhay; len;
 			  off += buf->search_lnee, pos = hay + off, len = lhay - off)
@@ -4210,7 +4226,7 @@ gtk_xtext_search_textentry (xtext_buffer *buf, textentry *ent)
 	}
 
 	/* Common processing --- */
-	g_slist_free_full (slp, free);
+	g_slist_free_full (slp, g_free);
 	return gl;
 }
 
@@ -4639,7 +4655,7 @@ gtk_xtext_append_indent (xtext_buffer *buf,
 	if (right_text[right_len-1] == '\n')
 		right_len--;
 
-	ent = malloc (left_len + right_len + 2 + sizeof (textentry));
+	ent = g_malloc (left_len + right_len + 2 + sizeof (textentry));
 	str = (unsigned char *) ent + sizeof (textentry);
 
 	memcpy (str, left_text, left_len);
@@ -4660,7 +4676,9 @@ gtk_xtext_append_indent (xtext_buffer *buf,
 		space = 0;
 
 	/* do we need to auto adjust the separator position? */
-	if (buf->xtext->auto_indent && ent->indent < MARGIN + space)
+	if (buf->xtext->auto_indent &&
+		 buf->indent < buf->xtext->max_auto_indent &&
+		 ent->indent < MARGIN + space)
 	{
 		tempindent = MARGIN + space + buf->xtext->space_width + left_width;
 
@@ -4681,7 +4699,7 @@ gtk_xtext_append_indent (xtext_buffer *buf,
 }
 
 void
-gtk_xtext_append (xtext_buffer *buf, unsigned char *text, int len)
+gtk_xtext_append (xtext_buffer *buf, unsigned char *text, int len, time_t stamp)
 {
 	textentry *ent;
 
@@ -4694,7 +4712,7 @@ gtk_xtext_append (xtext_buffer *buf, unsigned char *text, int len)
 	if (len >= sizeof (buf->xtext->scratch_buffer))
 		len = sizeof (buf->xtext->scratch_buffer) - 1;
 
-	ent = malloc (len + 1 + sizeof (textentry));
+	ent = g_malloc (len + 1 + sizeof (textentry));
 	ent->str = (unsigned char *) ent + sizeof (textentry);
 	ent->str_len = len;
 	if (len)
@@ -4703,7 +4721,7 @@ gtk_xtext_append (xtext_buffer *buf, unsigned char *text, int len)
 	ent->indent = 0;
 	ent->left_len = -1;
 
-	gtk_xtext_append_entry (buf, ent, 0);
+	gtk_xtext_append_entry (buf, ent, stamp);
 }
 
 gboolean
@@ -4738,11 +4756,14 @@ gtk_xtext_lastlog (xtext_buffer *out, xtext_buffer *search_area)
 			}
 			else
 			{
-				gtk_xtext_append (out, ent->str, ent->str_len);
+				gtk_xtext_append (out, ent->str, ent->str_len, 0);
 			}
 
-			out->text_last->stamp = ent->stamp;
-			gtk_xtext_search_textentry_add (out, out->text_last, gl, TRUE);
+			if (out->text_last)
+			{
+				out->text_last->stamp = ent->stamp;
+				gtk_xtext_search_textentry_add (out, out->text_last, gl, TRUE);
+			}
 		}
 		ent = ent->next;
 	}
@@ -4936,6 +4957,7 @@ gtk_xtext_buffer_show (GtkXText *xtext, xtext_buffer *buf, int render)
 		if (buf->window_width != w)
 		{
 			buf->window_width = w;
+			buf->window_height = h;
 			gtk_xtext_calc_lines (buf, FALSE);
 			if (buf->scrollbar_down)
 				gtk_adjustment_set_value (xtext->adj, xtext->adj->upper -
@@ -4959,8 +4981,7 @@ gtk_xtext_buffer_new (GtkXText *xtext)
 {
 	xtext_buffer *buf;
 
-	buf = malloc (sizeof (xtext_buffer));
-	memset (buf, 0, sizeof (xtext_buffer));
+	buf = g_new0 (xtext_buffer, 1);
 	buf->old_value = -1;
 	buf->xtext = xtext;
 	buf->scrollbar_down = TRUE;
@@ -4990,9 +5011,9 @@ gtk_xtext_buffer_free (xtext_buffer *buf)
 	while (ent)
 	{
 		next = ent->next;
-		free (ent);
+		g_free (ent);
 		ent = next;
 	}
 
-	free (buf);
+	g_free (buf);
 }
diff --git a/src/fe-gtk/xtext.h b/src/fe-gtk/xtext.h
index 73f5b52d..d6853f9f 100644
--- a/src/fe-gtk/xtext.h
+++ b/src/fe-gtk/xtext.h
@@ -252,7 +252,7 @@ struct _GtkXTextClass
 };
 
 GtkWidget *gtk_xtext_new (GdkColor palette[], int separator);
-void gtk_xtext_append (xtext_buffer *buf, unsigned char *text, int len);
+void gtk_xtext_append (xtext_buffer *buf, unsigned char *text, int len, time_t stamp);
 void gtk_xtext_append_indent (xtext_buffer *buf,
 										unsigned char *left_text, int left_len,
 										unsigned char *right_text, int right_len,