propagate from branch 'im.pidgin.pidgin' (head 3180b88b4c1b8e73c22589457b99d2c1b6096bf4) next.minor

Thu, 04 Feb 2010 05:30:35 +0000

author
Paul Aurich <darkrain42@pidgin.im>
date
Thu, 04 Feb 2010 05:30:35 +0000
branch
next.minor
changeset 29686
f9dee36112d0
parent 29285
3180b88b4c1b (current diff)
parent 29685
1507ce18860b (diff)
child 29687
7a29e5783510

propagate from branch 'im.pidgin.pidgin' (head 3180b88b4c1b8e73c22589457b99d2c1b6096bf4)
to branch 'im.pidgin.pidgin.next.minor' (head 1507ce18860b4a4481751cda84af9a334bfff934)

ChangeLog file | annotate | diff | comparison | revisions
configure.ac file | annotate | diff | comparison | revisions
libpurple/ft.c file | annotate | diff | comparison | revisions
libpurple/media.c file | annotate | diff | comparison | revisions
libpurple/media/media.c file | annotate | diff | comparison | revisions
libpurple/network.h file | annotate | diff | comparison | revisions
libpurple/protocols/jabber/jabber.c file | annotate | diff | comparison | revisions
libpurple/protocols/jabber/presence.c file | annotate | diff | comparison | revisions
libpurple/protocols/msn/state.c file | annotate | diff | comparison | revisions
libpurple/protocols/myspace/user.c file | annotate | diff | comparison | revisions
libpurple/util.c file | annotate | diff | comparison | revisions
pidgin/gtkaccount.c file | annotate | diff | comparison | revisions
pidgin/gtkblist.c file | annotate | diff | comparison | revisions
pidgin/gtkcelllayout.c file | annotate | diff | comparison | revisions
pidgin/gtkcelllayout.h file | annotate | diff | comparison | revisions
pidgin/gtkcellrendererprogress.c file | annotate | diff | comparison | revisions
pidgin/gtkcellrendererprogress.h file | annotate | diff | comparison | revisions
pidgin/gtkcellview.c file | annotate | diff | comparison | revisions
pidgin/gtkcellview.h file | annotate | diff | comparison | revisions
pidgin/gtkcellviewmenuitem.c file | annotate | diff | comparison | revisions
pidgin/gtkcellviewmenuitem.h file | annotate | diff | comparison | revisions
pidgin/gtkconv.c file | annotate | diff | comparison | revisions
pidgin/gtkdialogs.c file | annotate | diff | comparison | revisions
pidgin/gtkexpander.c file | annotate | diff | comparison | revisions
pidgin/gtkexpander.h file | annotate | diff | comparison | revisions
pidgin/gtkrequest.c file | annotate | diff | comparison | revisions
pidgin/gtkstatusbox.c file | annotate | diff | comparison | revisions
pidgin/gtkutils.c file | annotate | diff | comparison | revisions
pidgin/pidgincombobox.c file | annotate | diff | comparison | revisions
pidgin/pidgincombobox.h file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/16/tray-away.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/16/tray-busy.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/16/tray-connecting.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/16/tray-extended-away.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/16/tray-invisible.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/16/tray-message.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/16/tray-new-im.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/16/tray-offline.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/16/tray-online.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/22/tray-away.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/22/tray-busy.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/22/tray-connecting.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/22/tray-extended-away.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/22/tray-invisible.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/22/tray-message.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/22/tray-new-im.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/22/tray-offline.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/22/tray-online.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/32/tray-away.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/32/tray-busy.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/32/tray-connecting.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/32/tray-extended-away.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/32/tray-invisible.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/32/tray-message.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/32/tray-new-im.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/32/tray-offline.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/32/tray-online.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/48/tray-away.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/48/tray-busy.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/48/tray-connecting.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/48/tray-extended-away.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/48/tray-invisible.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/48/tray-message.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/48/tray-new-im.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/48/tray-offline.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/48/tray-online.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/16x16/status/pidgin-tray-away.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/16x16/status/pidgin-tray-busy.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/16x16/status/pidgin-tray-connecting.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/16x16/status/pidgin-tray-extended-away.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/16x16/status/pidgin-tray-invisible.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/16x16/status/pidgin-tray-message.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/16x16/status/pidgin-tray-new-im.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/16x16/status/pidgin-tray-offline.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/16x16/status/pidgin-tray-online.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/22x22/status/pidgin-tray-away.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/22x22/status/pidgin-tray-busy.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/22x22/status/pidgin-tray-connecting.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/22x22/status/pidgin-tray-extended-away.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/22x22/status/pidgin-tray-invisible.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/22x22/status/pidgin-tray-message.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/22x22/status/pidgin-tray-new-im.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/22x22/status/pidgin-tray-offline.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/22x22/status/pidgin-tray-online.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/32x32/status/pidgin-tray-away.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/32x32/status/pidgin-tray-busy.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/32x32/status/pidgin-tray-connecting.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/32x32/status/pidgin-tray-extended-away.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/32x32/status/pidgin-tray-invisible.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/32x32/status/pidgin-tray-message.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/32x32/status/pidgin-tray-new-im.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/32x32/status/pidgin-tray-offline.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/32x32/status/pidgin-tray-online.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/48x48/status/pidgin-tray-away.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/48x48/status/pidgin-tray-busy.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/48x48/status/pidgin-tray-connecting.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/48x48/status/pidgin-tray-extended-away.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/48x48/status/pidgin-tray-invisible.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/48x48/status/pidgin-tray-message.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/48x48/status/pidgin-tray-new-im.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/48x48/status/pidgin-tray-offline.png file | annotate | diff | comparison | revisions
pidgin/pixmaps/tray/hicolor/48x48/status/pidgin-tray-online.png file | annotate | diff | comparison | revisions
pidgin/win32/nsis/translations/polish.nsh file | annotate | diff | comparison | revisions
po/ChangeLog file | annotate | diff | comparison | revisions
--- a/ChangeLog	Thu Feb 04 02:18:37 2010 +0000
+++ b/ChangeLog	Thu Feb 04 05:30:35 2010 +0000
@@ -1,5 +1,23 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
+version 2.7.0 (??/??/????):
+	General:
+	* Changed GTK+ minimum version requirement to 2.10.0.
+	* Changed GLib minimum version requirement to 2.12.0.
+
+	Pidgin:
+	* Moved the "Debugging Information" section of the About box to a
+	  "Build Information" dialog accessible on the Help menu.
+	* Moved the Developer and Crazy Patch Writer information from the About
+	  box to a "Developer Information" dialog accessible on the Help menu.
+	* Moved the Translator information from the About box to a "Translator
+	  Information" dialog accessible on the Help menu.
+	* Use GtkStatusIcon for the docklet, providing better integration in
+	  notification area.
+	* Added UI for sending attentions (buzz, nudge) on supporting protocols.
+	* Make the search dialog unobtrusive in the conversation window (by making
+	  it look and behave like the search dialog in Firefox)
+
 version 2.6.6 (??/??/20??):
 	libpurple:
 	* Fix 'make check' on OS X. (David Fang)
--- a/ChangeLog.API	Thu Feb 04 02:18:37 2010 +0000
+++ b/ChangeLog.API	Thu Feb 04 05:30:35 2010 +0000
@@ -1,5 +1,32 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
+version 2.7.0 (??/??/????):
+	libpurple:
+		Added:
+		* purple_account_get_name_for_display
+		* purple_buddy_get_media_caps
+		* purple_buddy_set_media_caps
+		* purple_contact_get_group
+		* purple_media_candidate_copy
+		* purple_media_codec_copy
+		* purple_media_manager_get_backend_type
+		* purple_media_manager_set_backend_type
+		* purple_network_get_all_local_system_ips
+		* purple_prpl_got_media_caps
+		* purple_uuid_random
+		* media_caps to the PurpleBuddy struct
+		* buddy-caps-changed blist signal
+		* ui-caps-changed media manager signal
+		* sent-attention conversation signal
+		* got-attention conversation signal
+	
+	Pidgin:
+		Added:
+		* pidgin_dialogs_buildinfo (should not be used by anything but Pidgin)
+		* pidgin_dialogs_developers (should not be used by anything but Pidgin)
+		* pidgin_dialogs_translators (should not be used by anything but Pidgin)
+		* gtk_imhtmltoolbar_switch_active_conversation
+
 version 2.6.6 (??/??/2010):
 	libpurple:
 		Changed:
--- a/ChangeLog.win32	Thu Feb 04 02:18:37 2010 +0000
+++ b/ChangeLog.win32	Thu Feb 04 05:30:35 2010 +0000
@@ -1,5 +1,11 @@
+version 2.7.0 (??/??/????):
+	* Minimum required GTK+ version increased to 2.14.0
+	* Private GTK+ Runtime now used (GTK+ Installer no longer supported)
+	* Win9x no longer supported.
+	* Crash Report files (pidgin.RPT) are now generated in the ~/.purple
+	  directory instead of the installation directory.
 
-version 2.6.6 (??/??/2010):
+version 2.6.6 (??/??/20??):
 	* Installer translations for: Norwegian nynorsk
 
 version 2.6.5 (01/08/2010):
--- a/Makefile.mingw	Thu Feb 04 02:18:37 2010 +0000
+++ b/Makefile.mingw	Thu Feb 04 05:30:35 2010 +0000
@@ -37,6 +37,7 @@
 )
 
 STRIPPED_RELEASE_DIR = $(PIDGIN_TREE_TOP)/pidgin-$(PIDGIN_VERSION)-win32bin
+DEBUG_SYMBOLS_DIR = $(PIDGIN_TREE_TOP)/pidgin-$(PIDGIN_VERSION)-dbgsym
 
 
 # Any *.dll or *.exe files included in win32-install-dir that we don't compile
@@ -71,7 +72,7 @@
 #build an expression for `find` to use to ignore the above files
 EXTERNAL_DLLS_FIND_EXP = $(patsubst %,-o -name %,$(EXTERNAL_DLLS))
 
-.PHONY: all docs install installer installer_nogtk installer_debug installers clean uninstall create_release_install_dir
+.PHONY: all docs install installer installer_offline installer_zip debug_symbols_zip installers clean uninstall create_release_install_dir generate_translations_installer_include $(PIDGIN_REVISION_H) $(PIDGIN_REVISION_RAW_TXT)
 
 all: $(PIDGIN_CONFIG_H) $(PIDGIN_REVISION_H)
 	$(MAKE) -C $(PURPLE_TOP) -f $(MINGW_MAKEFILE)
@@ -89,29 +90,41 @@
 	$(MAKE) -C share/ca-certs -f $(MINGW_MAKEFILE) install
 	$(MAKE) -C share/sounds -f $(MINGW_MAKEFILE) install
 
+generate_translations_installer_include: create_release_install_dir 
+	rm -f pidgin/win32/nsis/pidgin-translations.nsh
+	find $(STRIPPED_RELEASE_DIR)/locale -maxdepth 1 -mindepth 1 \
+	 -exec basename {} ';' \
+	 | sed -e s/^/\!insertmacro\ LANG_SECTION\ \"/ -e s/$$/\"/ \
+	 > pidgin/win32/nsis/pidgin-translations.nsh
+
 create_release_install_dir: install
 	rm -rf $(STRIPPED_RELEASE_DIR)
 	cp -R $(PIDGIN_INSTALL_DIR) $(STRIPPED_RELEASE_DIR)
 	find $(STRIPPED_RELEASE_DIR) \( -name '*.dll' -o -name '*.exe' \) \
-	 -not \( -false $(EXTERNAL_DLLS_FIND_EXP) \) -exec $(STRIP) --strip-unneeded {} ';'
+	 -not \( -false $(EXTERNAL_DLLS_FIND_EXP) \) \
+	 -exec $(STRIP) --strip-unneeded {} ';'
 
-installer: create_release_install_dir
-	$(MAKENSIS) $(MAKENSISOPT)V3 $(MAKENSISOPT)DPIDGIN_VERSION="$(PIDGIN_VERSION)" $(MAKENSISOPT)DPIDGIN_PRODUCT_VERSION="$(PIDGIN_PRODUCT_VERSION)" $(MAKENSISOPT)DWITH_GTK $(MAKENSISOPT)DPIDGIN_INSTALL_DIR="$(STRIPPED_RELEASE_DIR)" $(MAKENSISOPT)DGTK_INSTALL_VERSION="$(GTK_INSTALL_VERSION)" pidgin/win32/nsis/pidgin-installer.nsi
+installer: create_release_install_dir generate_translations_installer_include
+	$(MAKENSIS) $(MAKENSISOPT)V3 $(MAKENSISOPT)DPIDGIN_VERSION="$(PIDGIN_VERSION)" $(MAKENSISOPT)DPIDGIN_PRODUCT_VERSION="$(PIDGIN_PRODUCT_VERSION)" $(MAKENSISOPT)DPIDGIN_INSTALL_DIR="$(STRIPPED_RELEASE_DIR)" $(MAKENSISOPT)DGTK_INSTALL_VERSION="$(GTK_INSTALL_VERSION)" pidgin/win32/nsis/pidgin-installer.nsi
 	mv pidgin/win32/nsis/pidgin-$(PIDGIN_VERSION).exe ./
 
-installer_nogtk: create_release_install_dir
-	$(MAKENSIS) $(MAKENSISOPT)V3 $(MAKENSISOPT)DPIDGIN_VERSION="$(PIDGIN_VERSION)" $(MAKENSISOPT)DPIDGIN_PRODUCT_VERSION="$(PIDGIN_PRODUCT_VERSION)" $(MAKENSISOPT)DPIDGIN_INSTALL_DIR="$(STRIPPED_RELEASE_DIR)" $(MAKENSISOPT)DGTK_INSTALL_VERSION="$(GTK_INSTALL_VERSION)" pidgin/win32/nsis/pidgin-installer.nsi
-	mv pidgin/win32/nsis/pidgin-$(PIDGIN_VERSION)-no-gtk.exe ./
-
-installer_debug: install
-	$(MAKENSIS) $(MAKENSISOPT)V3 $(MAKENSISOPT)DPIDGIN_VERSION="$(PIDGIN_VERSION)" $(MAKENSISOPT)DPIDGIN_PRODUCT_VERSION="$(PIDGIN_PRODUCT_VERSION)" $(MAKENSISOPT)DPIDGIN_INSTALL_DIR="$(PIDGIN_INSTALL_DIR)" $(MAKENSISOPT)DDEBUG $(MAKENSISOPT)DGTK_INSTALL_VERSION="$(GTK_INSTALL_VERSION)" pidgin/win32/nsis/pidgin-installer.nsi
-	mv pidgin/win32/nsis/pidgin-$(PIDGIN_VERSION)-debug.exe ./
+installer_offline: create_release_install_dir generate_translations_installer_include debug_symbols_zip
+	$(MAKENSIS) $(MAKENSISOPT)V3 $(MAKENSISOPT)DPIDGIN_VERSION="$(PIDGIN_VERSION)" $(MAKENSISOPT)DPIDGIN_PRODUCT_VERSION="$(PIDGIN_PRODUCT_VERSION)" $(MAKENSISOPT)DOFFLINE_INSTALLER $(MAKENSISOPT)DPIDGIN_INSTALL_DIR="$(STRIPPED_RELEASE_DIR)" $(MAKENSISOPT)DGTK_INSTALL_VERSION="$(GTK_INSTALL_VERSION)" pidgin/win32/nsis/pidgin-installer.nsi
+	mv pidgin/win32/nsis/pidgin-$(PIDGIN_VERSION)-offline.exe ./
 
 installer_zip: create_release_install_dir
 	rm -f pidgin-$(PIDGIN_VERSION)-win32-bin.zip
 	zip -9 -r pidgin-$(PIDGIN_VERSION)-win32-bin.zip $(STRIPPED_RELEASE_DIR)
 
-installers: installer installer_nogtk installer_debug installer_zip
+debug_symbols_zip: install
+	rm -rf $(DEBUG_SYMBOLS_DIR) $(DEBUG_SYMBOLS_DIR).zip
+	mkdir $(DEBUG_SYMBOLS_DIR)
+	tar -cf - `find $(PIDGIN_INSTALL_DIR) \( -name '*.dll' -o -name '*.exe' \) \
+	 -not \( -false $(EXTERNAL_DLLS_FIND_EXP) \) -print` \
+	 | tar --strip 2 --xform s/$$/.dbgsym/ -xC $(DEBUG_SYMBOLS_DIR) -f -
+	zip -9 -r $(DEBUG_SYMBOLS_DIR).zip $(DEBUG_SYMBOLS_DIR) 
+
+installers: installer installer_offline debug_symbols_zip installer_zip
 
 Doxyfile.mingw: Doxyfile.in
 	sed -e "s/@PACKAGE@/pidgin/" -e "s/@VERSION@/$(PIDGIN_VERSION)/" -e "s/@top_srcdir@/$(PIDGIN_TREE_TOP)/g" -e "s/@enable_dot@/NO/" Doxyfile.in > Doxyfile.mingw
@@ -125,13 +138,12 @@
 	$(MAKE) -C $(PIDGIN_TOP) -f $(MINGW_MAKEFILE) clean
 	$(MAKE) -C $(PURPLE_TOP) -f $(MINGW_MAKEFILE) clean
 	$(MAKE) -C share/ca-certs -f $(MINGW_MAKEFILE) clean
-	rm -f $(PIDGIN_CONFIG_H) $(PIDGIN_REVISION_H) $(PIDGIN_REVISION_RAW_TXT) ./VERSION pidgin-$(PIDGIN_VERSION)*.exe pidgin-$(PIDGIN_VERSION)-win32-bin.zip
+	rm -f $(PIDGIN_CONFIG_H) $(PIDGIN_REVISION_H) $(PIDGIN_REVISION_RAW_TXT) ./VERSION pidgin-$(PIDGIN_VERSION)*.exe pidgin-$(PIDGIN_VERSION)-win32-bin.zip $(DEBUG_SYMBOLS_DIR).zip
 	rm -rf doc/html Doxyfile.mingw
 
 uninstall:
-	rm -rf $(PURPLE_INSTALL_PERL_DIR) $(PIDGIN_INSTALL_PLUGINS_DIR) $(PURPLE_INSTALL_PO_DIR) $(PIDGIN_INSTALL_DIR) $(STRIPPED_RELEASE_DIR)
+	rm -rf $(PURPLE_INSTALL_PERL_DIR) $(PIDGIN_INSTALL_PLUGINS_DIR) $(PURPLE_INSTALL_PO_DIR) $(PIDGIN_INSTALL_DIR) $(STRIPPED_RELEASE_DIR) $(DEBUG_SYMBOLS_DIR)
 	rm -f ./VERSION
 
 include $(PIDGIN_COMMON_TARGETS)
 
-.PHONY: $(PIDGIN_REVISION_H) $(PIDGIN_REVISION_RAW_TXT)
--- a/configure.ac	Thu Feb 04 02:18:37 2010 +0000
+++ b/configure.ac	Thu Feb 04 05:30:35 2010 +0000
@@ -43,19 +43,19 @@
 #
 # Make sure to update finch/libgnt/configure.ac with libgnt version changes.
 #
-m4_define([purple_lt_current], [6])
+m4_define([purple_lt_current], [7])
 m4_define([purple_major_version], [2])
-m4_define([purple_minor_version], [6])
-m4_define([purple_micro_version], [6])
+m4_define([purple_minor_version], [7])
+m4_define([purple_micro_version], [0])
 m4_define([purple_version_suffix], [devel])
 m4_define([purple_version],
           [purple_major_version.purple_minor_version.purple_micro_version])
 m4_define([purple_display_version], purple_version[]m4_ifdef([purple_version_suffix],[purple_version_suffix]))
 
-m4_define([gnt_lt_current], [6])
+m4_define([gnt_lt_current], [7])
 m4_define([gnt_major_version], [2])
-m4_define([gnt_minor_version], [6])
-m4_define([gnt_micro_version], [6])
+m4_define([gnt_minor_version], [7])
+m4_define([gnt_micro_version], [0])
 m4_define([gnt_version_suffix], [devel])
 m4_define([gnt_version],
           [gnt_major_version.gnt_minor_version.gnt_micro_version])
@@ -310,9 +310,9 @@
 )
 
 dnl #######################################################################
-dnl # Check for GLib 2.0 (required)
+dnl # Check for GLib 2.12 (required)
 dnl #######################################################################
-PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.4.0 gobject-2.0 gmodule-2.0 gthread-2.0], , [
+PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.12.0 gobject-2.0 gmodule-2.0 gthread-2.0], , [
 	AC_MSG_RESULT(no)
 	AC_MSG_ERROR([
 
@@ -352,7 +352,7 @@
 	[enable_consoleui=$enableval force_finch=$enableval], [enable_consoleui=yes force_finch=no])
 
 dnl #######################################################################
-dnl # Check for GTK+ 2.0 and other things used by the GTK UI
+dnl # Check for GTK+ 2.10 and other things used by the GTK UI
 dnl #######################################################################
 AC_ARG_ENABLE(screensaver,
 	[AC_HELP_STRING([--disable-screensaver],
@@ -399,11 +399,11 @@
 fi
 
 if test "x$enable_gtkui" = "xyes" ; then
-	PKG_CHECK_MODULES(GTK, [gtk+-2.0 >= 2.4.0], , [
+	PKG_CHECK_MODULES(GTK, [gtk+-2.0 >= 2.10.0], , [
 		AC_MSG_RESULT(no)
 		AC_MSG_ERROR([
 
-You must have GTK+ 2.4.0 or newer development headers installed to compile
+You must have GTK+ 2.10.0 or newer development headers installed to compile
 Pidgin.  If you want to build only Finch then specify --disable-gtkui when
 running configure.
 ])])
@@ -2515,6 +2515,8 @@
 		   pidgin/Makefile
 		   pidgin/pidgin.pc
 		   pidgin/pidgin-uninstalled.pc
+		   pidgin/pidgin-2.pc
+		   pidgin/pidgin-2-uninstalled.pc
 		   pidgin/pixmaps/Makefile
 		   pidgin/pixmaps/emotes/default/24/Makefile
 		   pidgin/pixmaps/emotes/none/Makefile
@@ -2532,6 +2534,8 @@
 		   libpurple/gconf/Makefile
 		   libpurple/purple.pc
 		   libpurple/purple-uninstalled.pc
+		   libpurple/purple-2.pc
+		   libpurple/purple-2-uninstalled.pc
 		   libpurple/plugins/Makefile
 		   libpurple/plugins/mono/Makefile
 		   libpurple/plugins/mono/api/Makefile
--- a/finch/gntsound.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/finch/gntsound.c	Thu Feb 04 05:30:35 2010 +0000
@@ -559,18 +559,12 @@
 #else /* _WIN32 */
 	purple_debug_info("sound", "Playing %s\n", filename);
 
-	if (G_WIN32_HAVE_WIDECHAR_API ()) {
+	{
 		wchar_t *wc_filename = g_utf8_to_utf16(filename,
 				-1, NULL, NULL, NULL);
 		if (!PlaySoundW(wc_filename, NULL, SND_ASYNC | SND_FILENAME))
 			purple_debug(PURPLE_DEBUG_ERROR, "sound", "Error playing sound.\n");
 		g_free(wc_filename);
-	} else {
-		char *l_filename = g_locale_from_utf8(filename,
-				-1, NULL, NULL, NULL);
-		if (!PlaySoundA(l_filename, NULL, SND_ASYNC | SND_FILENAME))
-			purple_debug(PURPLE_DEBUG_ERROR, "sound", "Error playing sound.\n");
-		g_free(l_filename);
 	}
 #endif /* _WIN32 */
 }
--- a/finch/libgnt/configure.ac	Thu Feb 04 02:18:37 2010 +0000
+++ b/finch/libgnt/configure.ac	Thu Feb 04 05:30:35 2010 +0000
@@ -24,10 +24,10 @@
 # Make sure to update ../../configure.ac with libgnt version changes.
 #
 
-m4_define([gnt_lt_current], [6])
+m4_define([gnt_lt_current], [7])
 m4_define([gnt_major_version], [2])
-m4_define([gnt_minor_version], [6])
-m4_define([gnt_micro_version], [2])
+m4_define([gnt_minor_version], [7])
+m4_define([gnt_micro_version], [0])
 m4_define([gnt_version_suffix], [devel])
 m4_define([gnt_version],
           [gnt_major_version.gnt_minor_version.gnt_micro_version])
--- a/libpurple/Makefile.am	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/Makefile.am	Thu Feb 04 05:30:35 2010 +0000
@@ -53,7 +53,12 @@
 	idle.c \
 	imgstore.c \
 	log.c \
-	media.c \
+	media/backend-fs2.c \
+	media/backend-iface.c \
+	media/candidate.c \
+	media/codec.c \
+	media/enum-types.c \
+	media/media.c \
 	mediamanager.c \
 	mime.c \
 	nat-pmp.c \
@@ -156,6 +161,12 @@
 	xmlnode.h \
 	whiteboard.h
 
+purple_mediaheaders = \
+	backend-iface.h \
+	candidate.h \
+	codec.h \
+	enum-types.h
+
 purple_builtheaders = purple.h version.h marshallers.h
 
 marshallers.h: marshallers.list
@@ -192,6 +203,7 @@
                 savedstatuses.h smiley.h status.h server.h util.h xmlnode.h prpl.h
 
 purple_build_coreheaders = $(addprefix $(srcdir)/, $(purple_coreheaders)) \
+		$(addprefix $(srcdir)/media/, $(purple_mediaheaders)) \
 		$(purple_builtheaders)
 dbus_build_exported = $(addprefix $(srcdir)/, $(dbus_exported))
 # We should probably make this better
@@ -226,7 +238,7 @@
 purple-client-bindings.c: dbus-analyze-functions.py $(dbus_exported)
 	cat $(dbus_build_exported) | $(PYTHON) $(srcdir)/dbus-analyze-functions.py --client > $@
 
-purple-client-bindings.h: dbus-analyze-types.py dbus-analyze-functions.py $(purple_coreheaders) $(purple_builtheaders) $(dbus_exported)
+purple-client-bindings.h: dbus-analyze-types.py dbus-analyze-functions.py $(purple_coreheaders) $(addprefix media/, $(purple_mediaheaders)) $(purple_builtheaders) $(dbus_exported)
 	cat $(purple_build_coreheaders) | $(PYTHON) $(srcdir)/dbus-analyze-types.py --keyword=enum --verbatim > $@
 	cat $(dbus_build_exported) | $(PYTHON) $(srcdir)/dbus-analyze-functions.py --client --headers >> $@
 
@@ -275,6 +287,7 @@
 
 noinst_HEADERS= \
 	internal.h \
+	media/backend-fs2.h \
 	valgrind.h
 
 libpurpleincludedir=$(includedir)/libpurple
@@ -283,6 +296,10 @@
 	$(purple_builtheaders) \
 	$(dbus_headers)
 
+mediaincludedir=$(includedir)/libpurple/media
+mediainclude_HEADERS = \
+	$(addprefix $(srcdir)/media/, $(purple_mediaheaders))
+
 libpurple_la_DEPENDENCIES = $(STATIC_LINK_LIBS)
 libpurple_la_LDFLAGS = -export-dynamic -version-info $(PURPLE_LT_VERSION_INFO) -no-undefined
 libpurple_la_LIBADD = \
--- a/libpurple/Makefile.mingw	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/Makefile.mingw	Thu Feb 04 05:30:35 2010 +0000
@@ -48,7 +48,12 @@
 			idle.c \
 			imgstore.c \
 			log.c \
-			media.c \
+			media/backend-fs2.c \
+			media/backend-iface.c \
+			media/candidate.c \
+			media/codec.c \
+			media/enum-types.c \
+			media/media.c \
 			mediamanager.c \
 			mime.c \
 			nat-pmp.c \
--- a/libpurple/account.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/account.c	Thu Feb 04 05:30:35 2010 +0000
@@ -2036,6 +2036,42 @@
 	return account->gc;
 }
 
+const gchar *
+purple_account_get_name_for_display(const PurpleAccount *account)
+{
+	PurpleBuddy *self = NULL;
+	PurpleConnection *gc = NULL;
+	const gchar *name = NULL, *username = NULL, *displayname = NULL;
+
+	name = purple_account_get_alias(account);
+
+	if (name) {
+		return name;
+	}
+
+	username = purple_account_get_username(account);
+	self = purple_find_buddy((PurpleAccount *)account, username);
+
+	if (self) {
+		const gchar *calias= purple_buddy_get_contact_alias(self);
+
+		/* We don't want to return the buddy name if the buddy/contact
+		 * doesn't have an alias set. */
+		if (!purple_strequal(username, calias)) {
+			return calias;
+		}
+	}
+
+	gc = purple_account_get_connection(account);
+	displayname = purple_connection_get_display_name(gc);
+
+	if (displayname) {
+		return displayname;
+	}
+
+	return username;
+}
+
 gboolean
 purple_account_get_remember_password(const PurpleAccount *account)
 {
--- a/libpurple/account.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/account.h	Thu Feb 04 05:30:35 2010 +0000
@@ -630,6 +630,20 @@
 PurpleConnection *purple_account_get_connection(const PurpleAccount *account);
 
 /**
+ * Returns a name for this account appropriate for display to the user. In
+ * order of preference: the account's alias; the contact or buddy alias (if
+ * the account exists on its own buddy list); the connection's display name;
+ * the account's username.
+ *
+ * @param account The account.
+ *
+ * @return The name to display.
+ *
+ * @since 2.7.0
+ */
+const gchar *purple_account_get_name_for_display(const PurpleAccount *account);
+
+/**
  * Returns whether or not this account should save its password.
  *
  * @param account The account.
--- a/libpurple/blist.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/blist.c	Thu Feb 04 05:30:35 2010 +0000
@@ -1739,6 +1739,14 @@
 	g_free(contact);
 }
 
+PurpleGroup *
+purple_contact_get_group(const PurpleContact *contact)
+{
+	g_return_val_if_fail(contact, NULL);
+
+	return (PurpleGroup *)(((PurpleBlistNode *)contact)->parent);
+}
+
 void purple_contact_set_alias(PurpleContact *contact, const char *alias)
 {
 	purple_blist_alias_contact(contact,alias);
@@ -2605,6 +2613,18 @@
 	return buddy->presence;
 }
 
+PurpleMediaCaps purple_buddy_get_media_caps(const PurpleBuddy *buddy)
+{
+	g_return_val_if_fail(buddy != NULL, 0);
+	return buddy->media_caps;
+}
+
+void purple_buddy_set_media_caps(PurpleBuddy *buddy, PurpleMediaCaps media_caps)
+{
+	g_return_if_fail(buddy != NULL);
+	buddy->media_caps = media_caps;
+}
+
 PurpleGroup *purple_buddy_get_group(PurpleBuddy *buddy)
 {
 	g_return_val_if_fail(buddy != NULL, NULL);
@@ -3187,6 +3207,13 @@
 										PURPLE_SUBTYPE_BLIST_NODE),
 						 purple_value_new(PURPLE_TYPE_STRING));
 
+	purple_signal_register(handle, "buddy-caps-changed",
+			purple_marshal_VOID__POINTER_INT_INT, NULL,
+			3, purple_value_new(PURPLE_TYPE_SUBTYPE,
+				PURPLE_SUBTYPE_BLIST_BUDDY),
+			purple_value_new(PURPLE_TYPE_INT),
+			purple_value_new(PURPLE_TYPE_INT));
+
 	purple_signal_connect(purple_accounts_get_handle(), "account-created",
 			handle,
 			PURPLE_CALLBACK(purple_blist_buddies_cache_add_account),
--- a/libpurple/blist.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/blist.h	Thu Feb 04 05:30:35 2010 +0000
@@ -108,6 +108,7 @@
 
 #include "account.h"
 #include "buddyicon.h"
+#include "media.h"
 #include "status.h"
 
 /**************************************************************************/
@@ -143,6 +144,7 @@
 	PurpleBuddyIcon *icon;                    /**< The buddy icon. */
 	PurpleAccount *account;					/**< the account this buddy belongs to */
 	PurplePresence *presence;
+	PurpleMediaCaps media_caps;		/**< The media capabilities of the buddy. */
 };
 
 /**
@@ -657,6 +659,24 @@
 PurplePresence *purple_buddy_get_presence(const PurpleBuddy *buddy);
 
 /**
+ * Gets the media caps from a buddy.
+ *
+ * @param buddy The buddy.
+ * @return      The media caps.
+ *
+ * @since 2.7.0
+ */
+PurpleMediaCaps purple_buddy_get_media_caps(const PurpleBuddy *buddy);
+
+/**
+ * Sets the media caps for a buddy.
+ *
+ * @param buddy      The PurpleBuddy.
+ * @param media_caps The PurpleMediaCaps.
+ */
+void purple_buddy_set_media_caps(PurpleBuddy *buddy, PurpleMediaCaps media_caps);
+
+/**
  * Adds a new buddy to the buddy list.
  *
  * The buddy will be inserted right after node or prepended to the
@@ -715,6 +735,16 @@
 void purple_contact_destroy(PurpleContact *contact);
 
 /**
+ * Gets the PurpleGroup from a PurpleContact
+ *
+ * @param contact  The contact
+ * @return         The group
+ *
+ * @since 2.7.0
+ */
+PurpleGroup *purple_contact_get_group(const PurpleContact *contact);
+
+/**
  * Adds a new contact to the buddy list.
  *
  * The new contact will be inserted after insert or prepended to the list if
--- a/libpurple/connection.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/connection.h	Thu Feb 04 05:30:35 2010 +0000
@@ -45,7 +45,7 @@
 	PURPLE_CONNECTION_NO_URLDESC = 0x0040,  /**< Connection does not support descriptions with links */
 	PURPLE_CONNECTION_NO_IMAGES = 0x0080,  /**< Connection does not support sending of images */
 	PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY = 0x0100 /**< Connection supports sending and receiving custom smileys */
-
+	
 } PurpleConnectionFlags;
 
 typedef enum
--- a/libpurple/conversation.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/conversation.c	Thu Feb 04 05:30:35 2010 +0000
@@ -2302,7 +2302,27 @@
 						 purple_value_new(PURPLE_TYPE_SUBTYPE,
 										PURPLE_SUBTYPE_CONVERSATION),
 						 purple_value_new(PURPLE_TYPE_UINT));
-
+	
+	purple_signal_register(handle, "sent-attention",
+						 purple_marshal_VOID__POINTER_POINTER_POINTER_UINT,
+						 NULL, 4,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_UINT));
+	
+	purple_signal_register(handle, "got-attention",
+						 purple_marshal_VOID__POINTER_POINTER_POINTER_UINT,
+						 NULL, 4,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_ACCOUNT),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+										PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_UINT));
+	
 	purple_signal_register(handle, "sending-im-msg",
 						 purple_marshal_VOID__POINTER_POINTER_POINTER,
 						 NULL, 3,
--- a/libpurple/conversation.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/conversation.h	Thu Feb 04 05:30:35 2010 +0000
@@ -646,7 +646,6 @@
 		const char *message, PurpleMessageFlags flags,
 		time_t mtime);
 
-
 /**
 	Set the features as supported for the given conversation.
 	@param conv      The conversation
--- a/libpurple/core.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/core.c	Thu Feb 04 05:30:35 2010 +0000
@@ -496,7 +496,6 @@
 			if (purple_strequal(entry, "logs"))
 			{
 				char *link;
-#if GLIB_CHECK_VERSION(2,4,0)
 				err = NULL;
 
 				if ((link = g_file_read_link(name, &err)) == NULL)
@@ -512,27 +511,6 @@
 					g_free(old_user_dir);
 					return FALSE;
 				}
-#else
-				char buf[MAXPATHLEN];
-				size_t linklen;
-
-				if ((linklen = readlink(name, buf, sizeof(buf) - 1) == -1))
-				{
-					char *name_utf8 = g_filename_to_utf8(name, -1, NULL, NULL, NULL);
-					purple_debug_error("core", "Error reading symlink %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n",
-					                   name_utf8, g_strerror(errno));
-					g_free(name_utf8);
-					g_free(name);
-					g_dir_close(dir);
-					g_free(status_file);
-					g_free(old_user_dir);
-					return FALSE;
-				}
-				buf[linklen] = '\0';
-
-				/* This way we don't have to GLIB_VERSION_CHECK every g_free(link) below. */
-				link = g_strdup(buf);
-#endif
 
 				logs_dir = g_build_filename(user_dir, "logs", NULL);
 
--- a/libpurple/ft.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/ft.c	Thu Feb 04 05:30:35 2010 +0000
@@ -57,6 +57,7 @@
 		PURPLE_XFER_READY_UI   = 0x1,
 		PURPLE_XFER_READY_PRPL = 0x2,
 	} ready;
+	GByteArray *buffer;
 } PurpleXferPrivData;
 
 static int purple_xfer_choose_file(PurpleXfer *xfer);
@@ -66,6 +67,9 @@
 {
 	PurpleXferPrivData *priv = data;
 
+	if (priv->buffer)
+		g_byte_array_free(priv->buffer, TRUE);
+
 	g_free(priv);
 }
 
@@ -117,7 +121,7 @@
 	xfer->type    = type;
 	xfer->account = account;
 	xfer->who     = g_strdup(who);
-	xfer->ui_ops  = purple_xfers_get_ui_ops();
+	xfer->ui_ops  = ui_ops = purple_xfers_get_ui_ops();
 	xfer->message = NULL;
 	xfer->current_buffer_size = FT_INITIAL_BUFFER_SIZE;
 	xfer->fd = -1;
@@ -125,6 +129,13 @@
 	priv = g_new0(PurpleXferPrivData, 1);
 	priv->ready = PURPLE_XFER_READY_NONE;
 
+	if (ui_ops && ui_ops->data_not_sent) {
+		/* If the ui will handle unsent data no need for buffer */
+		priv->buffer = NULL;
+	} else {
+		priv->buffer = g_byte_array_sized_new(FT_INITIAL_BUFFER_SIZE);
+	}
+
 	g_hash_table_insert(xfers_data, xfer, priv);
 
 	ui_ops = purple_xfer_get_ui_ops(xfer);
@@ -1076,6 +1087,7 @@
 	} else if (xfer->type == PURPLE_XFER_SEND) {
 		size_t result;
 		size_t s = MIN(purple_xfer_get_bytes_remaining(xfer), xfer->current_buffer_size);
+		PurpleXferPrivData *priv = g_hash_table_lookup(xfers_data, xfer);
 
 		/* this is so the prpl can keep the connection open
 		   if it needs to for some odd reason. */
@@ -1090,8 +1102,6 @@
 		if (ui_ops && ui_ops->ui_read) {
 			gssize tmp = ui_ops->ui_read(xfer, &buffer, s);
 			if (tmp == 0) {
-				PurpleXferPrivData *priv = g_hash_table_lookup(xfers_data, xfer);
-
 				/*
 				 * The UI claimed it was ready, but didn't have any data for
 				 * us...  It will call purple_xfer_ui_ready when ready, which
@@ -1105,7 +1115,13 @@
 				/* Need to indicate the prpl is still ready... */
 				priv->ready |= PURPLE_XFER_READY_PRPL;
 
-				g_return_if_reached();
+				/*
+				 * if we requested 0 bytes it's only normal that end up here 
+				 * we shouldn't return as we still have something to 
+				 * write in priv->buffer
+				 */
+				if (s != 0)
+					g_return_if_reached();
 			} else if (tmp < 0) {
 				purple_debug_error("filetransfer", "Unable to read whole buffer.\n");
 				purple_xfer_cancel_local(xfer);
@@ -1123,29 +1139,40 @@
 				return;
 			}
 		}
-
-		/* Write as much as we're allowed to. */
+	
+		if (priv->buffer) {
+			priv->buffer = g_byte_array_append(priv->buffer, buffer, result);
+			g_free(buffer);
+			buffer = priv->buffer->data;
+			result = priv->buffer->len;
+		}
+	
 		r = purple_xfer_write(xfer, buffer, result);
 
 		if (r == -1) {
 			purple_xfer_cancel_remote(xfer);
 			g_free(buffer);
 			return;
-		} else if (r < result) {
-			if (ui_ops == NULL || (ui_ops->ui_read == NULL && ui_ops->ui_write == NULL)) {
-				/* We have to seek back in the file now. */
-				fseek(xfer->dest_fp, r - s, SEEK_CUR);
-			}
-			else {
-				ui_ops->data_not_sent(xfer, buffer + r, result - r);
-			}
-		} else {
+		} else if (r == result) {
 			/*
 			 * We managed to write the entire buffer.  This means our
 			 * network is fast and our buffer is too small, so make it
 			 * bigger.
 			 */
 			purple_xfer_increase_buffer_size(xfer);
+		} else {
+			if (ui_ops && ui_ops->data_not_sent) 
+				ui_ops->data_not_sent(xfer, buffer + r, result -r);
+		}
+
+		if (priv->buffer) {
+			/* 
+			 * Remove what we wrote
+			 * If we wrote the whole buffer the byte array will be empty
+			 * Otherwise we'll kee what wasn't sent for next time.
+			 */
+			buffer = NULL;
+			priv->buffer = g_byte_array_remove_range(priv->buffer, 0, r);
 		}
 	}
 
--- a/libpurple/internal.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/internal.h	Thu Feb 04 05:30:35 2010 +0000
@@ -118,36 +118,13 @@
 # include <unistd.h>
 #endif
 
-/* MAXPATHLEN should only be used with readlink() on glib < 2.4.0.  For
- * anything else, use g_file_read_link() or other dynamic functions.  This is
- * important because Hurd has no hard limits on path length. */
-#if !GLIB_CHECK_VERSION(2,4,0)
-# ifndef MAXPATHLEN
-#  ifdef PATH_MAX
-#   define MAXPATHLEN PATH_MAX
-#  else
-#   define MAXPATHLEN 1024
-#  endif
-# endif
-#endif
-
 #ifndef HOST_NAME_MAX
 # define HOST_NAME_MAX 255
 #endif
 
 #include <glib.h>
-#if !GLIB_CHECK_VERSION(2,4,0)
-#	define G_MAXUINT32 ((guint32) 0xffffffff)
-#endif
 
-#ifndef G_MAXSIZE
-#	if GLIB_SIZEOF_LONG == 8
-#		define G_MAXSIZE ((gsize) 0xffffffffffffffff)
-#	else
-#		define G_MAXSIZE ((gsize) 0xffffffff)
-#	endif
-#endif
-
+/* This wasn't introduced until Glib 2.14 :( */
 #ifndef G_MAXSSIZE
 #	if GLIB_SIZEOF_LONG == 8
 #		define G_MAXSSIZE ((gssize) 0x7fffffffffffffff)
@@ -156,80 +133,12 @@
 #	endif
 #endif
 
-#if GLIB_CHECK_VERSION(2,6,0)
-#	include <glib/gstdio.h>
-#endif
-
-#if !GLIB_CHECK_VERSION(2,6,0)
-#	define g_freopen freopen
-#	define g_fopen fopen
-#	define g_rmdir rmdir
-#	define g_remove remove
-#	define g_unlink unlink
-#	define g_lstat lstat
-#	define g_stat stat
-#	define g_mkdir mkdir
-#	define g_rename rename
-#	define g_open open
-#endif
-
-#if !GLIB_CHECK_VERSION(2,8,0) && !defined _WIN32
-#	define g_access access
-#endif
-
-#if !GLIB_CHECK_VERSION(2,10,0)
-#	define g_slice_new(type) g_new(type, 1)
-#	define g_slice_new0(type) g_new0(type, 1)
-#	define g_slice_free(type, mem) g_free(mem)
-#endif
+#include <glib/gstdio.h>
 
 #ifdef _WIN32
 #include "win32dep.h"
 #endif
 
-/* ugly ugly ugly */
-/* This is a workaround for the fact that G_GINT64_MODIFIER and G_GSIZE_FORMAT
- * are only defined in Glib >= 2.4 */
-#ifndef G_GINT64_MODIFIER
-#	if GLIB_SIZEOF_LONG == 8
-#		define G_GINT64_MODIFIER "l"
-#	else
-#		define G_GINT64_MODIFIER "ll"
-#	endif
-#endif
-
-#ifndef G_GSIZE_MODIFIER
-#	if GLIB_SIZEOF_LONG == 8
-#		define G_GSIZE_MODIFIER "l"
-#	else
-#		define G_GSIZE_MODIFIER ""
-#	endif
-#endif
-
-#ifndef G_GSIZE_FORMAT
-#	if GLIB_SIZEOF_LONG == 8
-#		define G_GSIZE_FORMAT "lu"
-#	else
-#		define G_GSIZE_FORMAT "u"
-#	endif
-#endif
-
-#ifndef G_GSSIZE_FORMAT
-#	if GLIB_SIZEOF_LONG == 8
-#		define G_GSSIZE_FORMAT "li"
-#	else
-#		define G_GSSIZE_FORMAT "i"
-#	endif
-#endif
-
-#ifndef G_GNUC_NULL_TERMINATED
-#	if     __GNUC__ >= 4
-#		define G_GNUC_NULL_TERMINATED __attribute__((__sentinel__))
-#	else
-#		define G_GNUC_NULL_TERMINATED
-#	endif
-#endif
-
 #ifdef HAVE_CONFIG_H
 #if SIZEOF_TIME_T == 4
 #	define PURPLE_TIME_T_MODIFIER "lu"
@@ -242,38 +151,6 @@
 
 #include <glib-object.h>
 
-#ifndef G_DEFINE_TYPE
-#define G_DEFINE_TYPE(TypeName, type_name, TYPE_PARENT) \
-\
-static void     type_name##_init              (TypeName        *self); \
-static void     type_name##_class_init        (TypeName##Class *klass); \
-static gpointer type_name##_parent_class = NULL; \
-static void     type_name##_class_intern_init (gpointer klass) \
-{ \
-  type_name##_parent_class = g_type_class_peek_parent (klass); \
-  type_name##_class_init ((TypeName##Class*) klass); \
-} \
-\
-GType \
-type_name##_get_type (void) \
-{ \
-  static GType g_define_type_id = 0; \
-  if (G_UNLIKELY (g_define_type_id == 0)) \
-    { \
-      g_define_type_id = \
-        g_type_register_static_simple (TYPE_PARENT, \
-                                       g_intern_static_string (#TypeName), \
-                                       sizeof (TypeName##Class), \
-                                       (GClassInitFunc)type_name##_class_intern_init, \
-                                       sizeof (TypeName), \
-                                       (GInstanceInitFunc)type_name##_init, \
-                                       (GTypeFlags) 0); \
-    }					\
-  return g_define_type_id;		\
-} /* closes type_name##_get_type() */
-
-#endif
-
 /* Safer ways to work with static buffers. When using non-static
  * buffers, either use g_strdup_* functions (preferred) or use
  * g_strlcpy/g_strlcpy directly. */
--- a/libpurple/marshallers.list	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/marshallers.list	Thu Feb 04 05:30:35 2010 +0000
@@ -4,3 +4,5 @@
 VOID:STRING,STRING,DOUBLE
 VOID:ENUM,STRING,STRING
 VOID:ENUM,STRING,STRING,BOOLEAN
+VOID:FLAGS,FLAGS
+VOID:STRING,STRING,OBJECT,OBJECT
--- a/libpurple/media.c	Thu Feb 04 02:18:37 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3322 +0,0 @@
-/**
- * @file media.c Media API
- * @ingroup core
- */
-
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This 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 Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-
-#include "internal.h"
-
-#include "account.h"
-#include "media.h"
-#include "mediamanager.h"
-#include "network.h"
-
-#include "debug.h"
-
-#ifdef USE_GSTREAMER
-#include "marshallers.h"
-#include "media-gst.h"
-#endif
-
-#ifdef USE_VV
-
-#include <gst/farsight/fs-conference-iface.h>
-#include <gst/farsight/fs-element-added-notifier.h>
-
-/** @copydoc _PurpleMediaSession */
-typedef struct _PurpleMediaSession PurpleMediaSession;
-/** @copydoc _PurpleMediaStream */
-typedef struct _PurpleMediaStream PurpleMediaStream;
-/** @copydoc _PurpleMediaClass */
-typedef struct _PurpleMediaClass PurpleMediaClass;
-/** @copydoc _PurpleMediaPrivate */
-typedef struct _PurpleMediaPrivate PurpleMediaPrivate;
-/** @copydoc _PurpleMediaCandidateClass */
-typedef struct _PurpleMediaCandidateClass PurpleMediaCandidateClass;
-/** @copydoc _PurpleMediaCandidatePrivate */
-typedef struct _PurpleMediaCandidatePrivate PurpleMediaCandidatePrivate;
-/** @copydoc _PurpleMediaCodecClass */
-typedef struct _PurpleMediaCodecClass PurpleMediaCodecClass;
-/** @copydoc _PurpleMediaCodecPrivate */
-typedef struct _PurpleMediaCodecPrivate PurpleMediaCodecPrivate;
-
-/** The media class */
-struct _PurpleMediaClass
-{
-	GObjectClass parent_class;     /**< The parent class. */
-};
-
-/** The media class's private data */
-struct _PurpleMedia
-{
-	GObject parent;                /**< The parent of this object. */
-	PurpleMediaPrivate *priv;      /**< The private data of this object. */
-};
-
-struct _PurpleMediaSession
-{
-	gchar *id;
-	PurpleMedia *media;
-	GstElement *src;
-	GstElement *tee;
-	FsSession *session;
-
-	PurpleMediaSessionType type;
-	gboolean initiator;
-};
-
-struct _PurpleMediaStream
-{
-	PurpleMediaSession *session;
-	gchar *participant;
-	FsStream *stream;
-	GstElement *src;
-	GstElement *tee;
-	GstElement *volume;
-	GstElement *level;
-
-	GList *local_candidates;
-	GList *remote_candidates;
-
-	gboolean initiator;
-	gboolean accepted;
-	gboolean candidates_prepared;
-	gboolean held;
-	gboolean paused;
-
-	GList *active_local_candidates;
-	GList *active_remote_candidates;
-
-	guint connected_cb_id;
-};
-#endif
-
-struct _PurpleMediaPrivate
-{
-#ifdef USE_VV
-	PurpleMediaManager *manager;
-	PurpleAccount *account;
-	FsConference *conference;
-	gboolean initiator;
-	gpointer prpl_data;
-
-	GHashTable *sessions;	/* PurpleMediaSession table */
-	GHashTable *participants; /* FsParticipant table */
-
-	GList *streams;		/* PurpleMediaStream table */
-
-	GstElement *confbin;
-#else
-	gpointer dummy;
-#endif
-};
-
-#ifdef USE_VV
-#define PURPLE_MEDIA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA, PurpleMediaPrivate))
-#define PURPLE_MEDIA_CANDIDATE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA_CANDIDATE, PurpleMediaCandidatePrivate))
-#define PURPLE_MEDIA_CODEC_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA_CODEC, PurpleMediaCodecPrivate))
-
-static void purple_media_class_init (PurpleMediaClass *klass);
-static void purple_media_init (PurpleMedia *media);
-static void purple_media_dispose (GObject *object);
-static void purple_media_finalize (GObject *object);
-static void purple_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
-static void purple_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
-
-static void purple_media_new_local_candidate_cb(FsStream *stream,
-		FsCandidate *local_candidate, PurpleMediaSession *session);
-static void purple_media_candidates_prepared_cb(FsStream *stream,
-		PurpleMediaSession *session);
-static void purple_media_candidate_pair_established_cb(FsStream *stream,
-		FsCandidate *native_candidate, FsCandidate *remote_candidate,
-		PurpleMediaSession *session);
-static gboolean media_bus_call(GstBus *bus,
-		GstMessage *msg, PurpleMedia *media);
-
-static GObjectClass *parent_class = NULL;
-
-
-
-enum {
-	S_ERROR,
-	CANDIDATES_PREPARED,
-	CODECS_CHANGED,
-	LEVEL,
-	NEW_CANDIDATE,
-	STATE_CHANGED,
-	STREAM_INFO,
-	LAST_SIGNAL
-};
-static guint purple_media_signals[LAST_SIGNAL] = {0};
-
-enum {
-	PROP_0,
-	PROP_MANAGER,
-	PROP_ACCOUNT,
-	PROP_CONFERENCE,
-	PROP_INITIATOR,
-	PROP_PRPL_DATA,
-};
-#endif
-
-
-/*
- * PurpleMediaElementType
- */
-
-GType
-purple_media_session_type_get_type()
-{
-	static GType type = 0;
-	if (type == 0) {
-		static const GFlagsValue values[] = {
-			{ PURPLE_MEDIA_NONE,
-				"PURPLE_MEDIA_NONE", "none" },
-			{ PURPLE_MEDIA_RECV_AUDIO,
-				"PURPLE_MEDIA_RECV_AUDIO", "recv-audio" },
-			{ PURPLE_MEDIA_SEND_AUDIO,
-				"PURPLE_MEDIA_SEND_AUDIO", "send-audio" },
-			{ PURPLE_MEDIA_RECV_VIDEO,
-				"PURPLE_MEDIA_RECV_VIDEO", "recv-video" },
-			{ PURPLE_MEDIA_SEND_VIDEO,
-				"PURPLE_MEDIA_SEND_VIDEO", "send-audio" },
-			{ PURPLE_MEDIA_AUDIO,
-				"PURPLE_MEDIA_AUDIO", "audio" },
-			{ PURPLE_MEDIA_VIDEO,
-				"PURPLE_MEDIA_VIDEO", "video" },
-			{ 0, NULL, NULL }
-		};
-		type = g_flags_register_static(
-				"PurpleMediaSessionType", values);
-	}
-	return type;
-}
-
-GType
-purple_media_get_type()
-{
-#ifdef USE_VV
-	static GType type = 0;
-
-	if (type == 0) {
-		static const GTypeInfo info = {
-			sizeof(PurpleMediaClass),
-			NULL,
-			NULL,
-			(GClassInitFunc) purple_media_class_init,
-			NULL,
-			NULL,
-			sizeof(PurpleMedia),
-			0,
-			(GInstanceInitFunc) purple_media_init,
-			NULL
-		};
-		type = g_type_register_static(G_TYPE_OBJECT, "PurpleMedia", &info, 0);
-	}
-	return type;
-#else
-	return G_TYPE_NONE;
-#endif
-}
-
-GType
-purple_media_state_changed_get_type()
-{
-	static GType type = 0;
-	if (type == 0) {
-		static const GEnumValue values[] = {
-			{ PURPLE_MEDIA_STATE_NEW,
-				"PURPLE_MEDIA_STATE_NEW", "new" },
-			{ PURPLE_MEDIA_STATE_CONNECTED,
-				"PURPLE_MEDIA_STATE_CONNECTED", "connected" },
-			{ PURPLE_MEDIA_STATE_END,
-				"PURPLE_MEDIA_STATE_END", "end" },
-			{ 0, NULL, NULL }
-		};
-		type = g_enum_register_static("PurpleMediaState", values);
-	}
-	return type;
-}
-
-GType
-purple_media_info_type_get_type()
-{
-	static GType type = 0;
-	if (type == 0) {
-		static const GEnumValue values[] = {
-			{ PURPLE_MEDIA_INFO_HANGUP,
-					"PURPLE_MEDIA_INFO_HANGUP", "hangup" },
-			{ PURPLE_MEDIA_INFO_ACCEPT,
-					"PURPLE_MEDIA_INFO_ACCEPT", "accept" },
-			{ PURPLE_MEDIA_INFO_REJECT,
-					"PURPLE_MEDIA_INFO_REJECT", "reject" },
-			{ PURPLE_MEDIA_INFO_MUTE,
-					"PURPLE_MEDIA_INFO_MUTE", "mute" },
-			{ PURPLE_MEDIA_INFO_UNMUTE,
-					"PURPLE_MEDIA_INFO_UNMUTE", "unmute" },
-			{ PURPLE_MEDIA_INFO_PAUSE,
-					"PURPLE_MEDIA_INFO_PAUSE", "pause" },
-			{ PURPLE_MEDIA_INFO_UNPAUSE,
-					"PURPLE_MEDIA_INFO_UNPAUSE", "unpause" },
-			{ PURPLE_MEDIA_INFO_HOLD,
-					"PURPLE_MEDIA_INFO_HOLD", "hold" },
-			{ PURPLE_MEDIA_INFO_UNHOLD,
-					"PURPLE_MEDIA_INFO_UNHOLD", "unhold" },
-			{ 0, NULL, NULL }
-		};
-		type = g_enum_register_static("PurpleMediaInfoType", values);
-	}
-	return type;
-}
-
-#ifdef USE_VV
-static void
-purple_media_class_init (PurpleMediaClass *klass)
-{
-	GObjectClass *gobject_class = (GObjectClass*)klass;
-	parent_class = g_type_class_peek_parent(klass);
-	
-	gobject_class->dispose = purple_media_dispose;
-	gobject_class->finalize = purple_media_finalize;
-	gobject_class->set_property = purple_media_set_property;
-	gobject_class->get_property = purple_media_get_property;
-
-	g_object_class_install_property(gobject_class, PROP_MANAGER,
-			g_param_spec_object("manager",
-			"Purple Media Manager",
-			"The media manager that contains this media session.",
-			PURPLE_TYPE_MEDIA_MANAGER,
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
-
-	g_object_class_install_property(gobject_class, PROP_ACCOUNT,
-			g_param_spec_pointer("account",
-			"PurpleAccount",
-			"The account this media session is on.",
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
-
-	g_object_class_install_property(gobject_class, PROP_CONFERENCE,
-			g_param_spec_object("conference",
-			"Farsight conference",
-			"The FsConference associated with this media.",
-			FS_TYPE_CONFERENCE,
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
-
-	g_object_class_install_property(gobject_class, PROP_INITIATOR,
-			g_param_spec_boolean("initiator",
-			"initiator",
-			"If the local user initiated the conference.",
-			FALSE,
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
-
-	g_object_class_install_property(gobject_class, PROP_PRPL_DATA,
-			g_param_spec_pointer("prpl-data",
-			"gpointer",
-			"Data the prpl plugin set on the media session.",
-			G_PARAM_READWRITE));
-
-	purple_media_signals[S_ERROR] = g_signal_new("error", G_TYPE_FROM_CLASS(klass),
-					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
-					 g_cclosure_marshal_VOID__STRING,
-					 G_TYPE_NONE, 1, G_TYPE_STRING);
-	purple_media_signals[CANDIDATES_PREPARED] = g_signal_new("candidates-prepared", G_TYPE_FROM_CLASS(klass),
-					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
-					 purple_smarshal_VOID__STRING_STRING,
-					 G_TYPE_NONE, 2, G_TYPE_STRING,
-					 G_TYPE_STRING);
-	purple_media_signals[CODECS_CHANGED] = g_signal_new("codecs-changed", G_TYPE_FROM_CLASS(klass),
-					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
-					 g_cclosure_marshal_VOID__STRING,
-					 G_TYPE_NONE, 1, G_TYPE_STRING);
-	purple_media_signals[LEVEL] = g_signal_new("level", G_TYPE_FROM_CLASS(klass),
-					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
-					 purple_smarshal_VOID__STRING_STRING_DOUBLE,
-					 G_TYPE_NONE, 3, G_TYPE_STRING,
-					 G_TYPE_STRING, G_TYPE_DOUBLE);
-	purple_media_signals[NEW_CANDIDATE] = g_signal_new("new-candidate", G_TYPE_FROM_CLASS(klass),
-					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
-					 purple_smarshal_VOID__POINTER_POINTER_OBJECT,
-					 G_TYPE_NONE, 3, G_TYPE_POINTER,
-					 G_TYPE_POINTER, PURPLE_TYPE_MEDIA_CANDIDATE);
-	purple_media_signals[STATE_CHANGED] = g_signal_new("state-changed", G_TYPE_FROM_CLASS(klass),
-					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
-					 purple_smarshal_VOID__ENUM_STRING_STRING,
-					 G_TYPE_NONE, 3, PURPLE_MEDIA_TYPE_STATE,
-					 G_TYPE_STRING, G_TYPE_STRING);
-	purple_media_signals[STREAM_INFO] = g_signal_new("stream-info", G_TYPE_FROM_CLASS(klass),
-					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
-					 purple_smarshal_VOID__ENUM_STRING_STRING_BOOLEAN,
-					 G_TYPE_NONE, 4, PURPLE_MEDIA_TYPE_INFO_TYPE,
-					 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
-	g_type_class_add_private(klass, sizeof(PurpleMediaPrivate));
-}
-
-
-static void
-purple_media_init (PurpleMedia *media)
-{
-	media->priv = PURPLE_MEDIA_GET_PRIVATE(media);
-	memset(media->priv, 0, sizeof(*media->priv));
-}
-
-static void
-purple_media_stream_free(PurpleMediaStream *stream)
-{
-	if (stream == NULL)
-		return;
-
-	/* Remove the connected_cb timeout */
-	if (stream->connected_cb_id != 0)
-		purple_timeout_remove(stream->connected_cb_id);
-
-	g_free(stream->participant);
-
-	if (stream->local_candidates)
-		fs_candidate_list_destroy(stream->local_candidates);
-	if (stream->remote_candidates)
-		fs_candidate_list_destroy(stream->remote_candidates);
-
-	if (stream->active_local_candidates)
-		fs_candidate_list_destroy(stream->active_local_candidates);
-	if (stream->active_remote_candidates)
-		fs_candidate_list_destroy(stream->active_remote_candidates);
-
-	g_free(stream);
-}
-
-static void
-purple_media_session_free(PurpleMediaSession *session)
-{
-	if (session == NULL)
-		return;
-
-	g_free(session->id);
-	g_free(session);
-}
-
-static void
-purple_media_dispose(GObject *media)
-{
-	PurpleMediaPrivate *priv = PURPLE_MEDIA_GET_PRIVATE(media);
-	GList *iter = NULL;
-
-	purple_debug_info("media","purple_media_dispose\n");
-
-	purple_media_manager_remove_media(priv->manager, PURPLE_MEDIA(media));
-
-	if (priv->confbin) {
-		gst_element_set_locked_state(priv->confbin, TRUE);
-		gst_element_set_state(GST_ELEMENT(priv->confbin),
-				GST_STATE_NULL);
-		gst_bin_remove(GST_BIN(purple_media_manager_get_pipeline(
-				priv->manager)), priv->confbin);
-		priv->confbin = NULL;
-		priv->conference = NULL;
-	}
-
-	for (iter = priv->streams; iter; iter = g_list_next(iter)) {
-		PurpleMediaStream *stream = iter->data;
-		if (stream->stream) {
-			g_object_unref(stream->stream);
-			stream->stream = NULL;
-		}
-	}
-
-	if (priv->sessions) {
-		GList *sessions = g_hash_table_get_values(priv->sessions);
-		for (; sessions; sessions = g_list_delete_link(sessions, sessions)) {
-			PurpleMediaSession *session = sessions->data;
-			if (session->session) {
-				g_object_unref(session->session);
-				session->session = NULL;
-			}
-		}
-	}
-
-	if (priv->participants) {
-		GList *participants = g_hash_table_get_values(priv->participants);
-		for (; participants; participants = g_list_delete_link(participants, participants))
-			g_object_unref(participants->data);
-	}
-
-	if (priv->manager) {
-		GstElement *pipeline = purple_media_manager_get_pipeline(
-				priv->manager);
-		GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
-		g_signal_handlers_disconnect_matched(G_OBJECT(bus),
-				G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
-				0, 0, 0, media_bus_call, media);
-		gst_object_unref(bus);
-
-		g_object_unref(priv->manager);
-		priv->manager = NULL;
-	}
-
-	G_OBJECT_CLASS(parent_class)->dispose(media);
-}
-
-static void
-purple_media_finalize(GObject *media)
-{
-	PurpleMediaPrivate *priv = PURPLE_MEDIA_GET_PRIVATE(media);
-	purple_debug_info("media","purple_media_finalize\n");
-
-	for (; priv->streams; priv->streams = g_list_delete_link(priv->streams, priv->streams))
-		purple_media_stream_free(priv->streams->data);
-
-	if (priv->sessions) {
-		GList *sessions = g_hash_table_get_values(priv->sessions);
-		for (; sessions; sessions = g_list_delete_link(sessions, sessions)) {
-			purple_media_session_free(sessions->data);
-		}
-		g_hash_table_destroy(priv->sessions);
-	}
-
-	G_OBJECT_CLASS(parent_class)->finalize(media);
-}
-
-static void
-purple_media_setup_pipeline(PurpleMedia *media)
-{
-	GstBus *bus;
-	gchar *name;
-	GstElement *pipeline;
-
-	if (media->priv->conference == NULL || media->priv->manager == NULL)
-		return;
-
-	pipeline = purple_media_manager_get_pipeline(media->priv->manager);
-
-	name = g_strdup_printf("conf_%p",
-			media->priv->conference);
-	media->priv->confbin = gst_bin_new(name);
-	g_free(name);
-
-	bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
-	g_signal_connect(G_OBJECT(bus), "message",
-			G_CALLBACK(media_bus_call), media);
-	gst_object_unref(bus);
-
-	gst_bin_add(GST_BIN(pipeline),
-			media->priv->confbin);
-	gst_bin_add(GST_BIN(media->priv->confbin),
-			GST_ELEMENT(media->priv->conference));
-	gst_element_set_state(GST_ELEMENT(media->priv->confbin),
-			GST_STATE_PLAYING);
-}
-
-static void
-purple_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
-	PurpleMedia *media;
-	g_return_if_fail(PURPLE_IS_MEDIA(object));
-
-	media = PURPLE_MEDIA(object);
-
-	switch (prop_id) {
-		case PROP_MANAGER:
-			media->priv->manager = g_value_get_object(value);
-			g_object_ref(media->priv->manager);
-
-			purple_media_setup_pipeline(media);
-			break;
-		case PROP_ACCOUNT:
-			media->priv->account = g_value_get_pointer(value);
-			break;
-		case PROP_CONFERENCE: {
-			if (media->priv->conference)
-				gst_object_unref(media->priv->conference);
-			media->priv->conference = g_value_get_object(value);
-			gst_object_ref(media->priv->conference);
-
-			purple_media_setup_pipeline(media);
-			break;
-		}
-		case PROP_INITIATOR:
-			media->priv->initiator = g_value_get_boolean(value);
-			break;
-		case PROP_PRPL_DATA:
-			media->priv->prpl_data = g_value_get_pointer(value);
-			break;
-		default:	
-			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-			break;
-	}
-}
-
-static void
-purple_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
-	PurpleMedia *media;
-	g_return_if_fail(PURPLE_IS_MEDIA(object));
-	
-	media = PURPLE_MEDIA(object);
-
-	switch (prop_id) {
-		case PROP_MANAGER:
-			g_value_set_object(value, media->priv->manager);
-			break;
-		case PROP_ACCOUNT:
-			g_value_set_pointer(value, media->priv->account);
-			break;
-		case PROP_CONFERENCE:
-			g_value_set_object(value, media->priv->conference);
-			break;
-		case PROP_INITIATOR:
-			g_value_set_boolean(value, media->priv->initiator);
-			break;
-		case PROP_PRPL_DATA:
-			g_value_set_pointer(value, media->priv->prpl_data);
-			break;
-		default:	
-			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);	
-			break;
-	}
-
-}
-#endif
-
-/*
- * PurpleMediaCandidateType
- */
-
-GType
-purple_media_candidate_type_get_type()
-{
-	static GType type = 0;
-	if (type == 0) {
-		static const GEnumValue values[] = {
-			{ PURPLE_MEDIA_CANDIDATE_TYPE_HOST,
-					"PURPLE_MEDIA_CANDIDATE_TYPE_HOST",
-					"host" },
-			{ PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX,
-					"PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX",
-					"srflx" },
-			{ PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX,
-					"PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX",
-					"prflx" },
-			{ PURPLE_MEDIA_CANDIDATE_TYPE_RELAY,
-					"PPURPLE_MEDIA_CANDIDATE_TYPE_RELAY",
-					"relay" },
-			{ PURPLE_MEDIA_CANDIDATE_TYPE_MULTICAST,
-					"PURPLE_MEDIA_CANDIDATE_TYPE_MULTICAST",
-					"multicast" },
-			{ 0, NULL, NULL }
-		};
-		type = g_enum_register_static("PurpleMediaCandidateType",
-				values);
-	}
-	return type;
-}
-
-/*
- * PurpleMediaNetworkProtocol
- */
-
-GType
-purple_media_network_protocol_get_type()
-{
-	static GType type = 0;
-	if (type == 0) {
-		static const GEnumValue values[] = {
-			{ PURPLE_MEDIA_NETWORK_PROTOCOL_UDP,
-					"PURPLE_MEDIA_NETWORK_PROTOCOL_UDP",
-					"udp" },
-			{ PURPLE_MEDIA_NETWORK_PROTOCOL_TCP,
-					"PURPLE_MEDIA_NETWORK_PROTOCOL_TCP",
-					"tcp" },
-			{ 0, NULL, NULL }
-		};
-		type = g_enum_register_static("PurpleMediaNetworkProtocol",
-				values);
-	}
-	return type;
-}
-
-/*
- * PurpleMediaCandidate
- */
-
-struct _PurpleMediaCandidateClass
-{
-	GObjectClass parent_class;
-};
-
-struct _PurpleMediaCandidate
-{
-	GObject parent;
-};
-
-#ifdef USE_VV
-struct _PurpleMediaCandidatePrivate
-{
-	gchar *foundation;
-	guint component_id;
-	gchar *ip;
-	guint16 port;
-	gchar *base_ip;
-	guint16 base_port;
-	PurpleMediaNetworkProtocol proto;
-	guint32 priority;
-	PurpleMediaCandidateType type;
-	gchar *username;
-	gchar *password;
-	guint ttl;
-};
-
-enum {
-	PROP_CANDIDATE_0,
-	PROP_FOUNDATION,
-	PROP_COMPONENT_ID,
-	PROP_IP,
-	PROP_PORT,
-	PROP_BASE_IP,
-	PROP_BASE_PORT,
-	PROP_PROTOCOL,
-	PROP_PRIORITY,
-	PROP_TYPE,
-	PROP_USERNAME,
-	PROP_PASSWORD,
-	PROP_TTL,
-};
-
-static void
-purple_media_candidate_init(PurpleMediaCandidate *info)
-{
-	PurpleMediaCandidatePrivate *priv =
-			PURPLE_MEDIA_CANDIDATE_GET_PRIVATE(info);
-	priv->foundation = NULL;
-	priv->component_id = 0;
-	priv->ip = NULL;
-	priv->port = 0;
-	priv->base_ip = NULL;
-	priv->proto = PURPLE_MEDIA_NETWORK_PROTOCOL_UDP;
-	priv->priority = 0;
-	priv->type = PURPLE_MEDIA_CANDIDATE_TYPE_HOST;
-	priv->username = NULL;
-	priv->password = NULL;
-	priv->ttl = 0;
-}
-
-static void
-purple_media_candidate_finalize(GObject *info)
-{
-	PurpleMediaCandidatePrivate *priv =
-			PURPLE_MEDIA_CANDIDATE_GET_PRIVATE(info);
-
-	g_free(priv->foundation);
-	g_free(priv->ip);
-	g_free(priv->base_ip);
-	g_free(priv->username);
-	g_free(priv->password);
-}
-
-static void
-purple_media_candidate_set_property (GObject *object, guint prop_id,
-		const GValue *value, GParamSpec *pspec)
-{
-	PurpleMediaCandidatePrivate *priv;
-	g_return_if_fail(PURPLE_IS_MEDIA_CANDIDATE(object));
-
-	priv = PURPLE_MEDIA_CANDIDATE_GET_PRIVATE(object);
-
-	switch (prop_id) {
-		case PROP_FOUNDATION:
-			g_free(priv->foundation);
-			priv->foundation = g_value_dup_string(value);
-			break;
-		case PROP_COMPONENT_ID:
-			priv->component_id = g_value_get_uint(value);
-			break;
-		case PROP_IP:
-			g_free(priv->ip);
-			priv->ip = g_value_dup_string(value);
-			break;
-		case PROP_PORT:
-			priv->port = g_value_get_uint(value);
-			break;
-		case PROP_BASE_IP:
-			g_free(priv->base_ip);
-			priv->base_ip = g_value_dup_string(value);
-			break;
-		case PROP_BASE_PORT:
-			priv->base_port = g_value_get_uint(value);
-			break;
-		case PROP_PROTOCOL:
-			priv->proto = g_value_get_enum(value);
-			break;
-		case PROP_PRIORITY:
-			priv->priority = g_value_get_uint(value);
-			break;
-		case PROP_TYPE:
-			priv->type = g_value_get_enum(value);
-			break;
-		case PROP_USERNAME:
-			g_free(priv->username);
-			priv->username = g_value_dup_string(value);
-			break;
-		case PROP_PASSWORD:
-			g_free(priv->password);
-			priv->password = g_value_dup_string(value);
-			break;
-		case PROP_TTL:
-			priv->ttl = g_value_get_uint(value);
-			break;
-		default:	
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(
-					object, prop_id, pspec);
-			break;
-	}
-}
-
-static void
-purple_media_candidate_get_property (GObject *object, guint prop_id,
-		GValue *value, GParamSpec *pspec)
-{
-	PurpleMediaCandidatePrivate *priv;
-	g_return_if_fail(PURPLE_IS_MEDIA_CANDIDATE(object));
-	
-	priv = PURPLE_MEDIA_CANDIDATE_GET_PRIVATE(object);
-
-	switch (prop_id) {
-		case PROP_FOUNDATION:
-			g_value_set_string(value, priv->foundation);
-			break;
-		case PROP_COMPONENT_ID:
-			g_value_set_uint(value, priv->component_id);
-			break;
-		case PROP_IP:
-			g_value_set_string(value, priv->ip);
-			break;
-		case PROP_PORT:
-			g_value_set_uint(value, priv->port);
-			break;
-		case PROP_BASE_IP:
-			g_value_set_string(value, priv->base_ip);
-			break;
-		case PROP_BASE_PORT:
-			g_value_set_uint(value, priv->base_port);
-			break;
-		case PROP_PROTOCOL:
-			g_value_set_enum(value, priv->proto);
-			break;
-		case PROP_PRIORITY:
-			g_value_set_uint(value, priv->priority);
-			break;
-		case PROP_TYPE:
-			g_value_set_enum(value, priv->type);
-			break;
-		case PROP_USERNAME:
-			g_value_set_string(value, priv->username);
-			break;
-		case PROP_PASSWORD:
-			g_value_set_string(value, priv->password);
-			break;
-		case PROP_TTL:
-			g_value_set_uint(value, priv->ttl);
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(
-					object, prop_id, pspec);
-			break;
-	}
-}
-
-static void
-purple_media_candidate_class_init(PurpleMediaCandidateClass *klass)
-{
-	GObjectClass *gobject_class = (GObjectClass*)klass;
-	
-	gobject_class->finalize = purple_media_candidate_finalize;
-	gobject_class->set_property = purple_media_candidate_set_property;
-	gobject_class->get_property = purple_media_candidate_get_property;
-
-	g_object_class_install_property(gobject_class, PROP_FOUNDATION,
-			g_param_spec_string("foundation",
-			"Foundation",
-			"The foundation of the candidate.",
-			NULL,
-			G_PARAM_READWRITE));
-
-	g_object_class_install_property(gobject_class, PROP_COMPONENT_ID,
-			g_param_spec_uint("component-id",
-			"Component ID",
-			"The component id of the candidate.",
-			0, G_MAXUINT, 0,
-			G_PARAM_READWRITE));
-
-	g_object_class_install_property(gobject_class, PROP_IP,
-			g_param_spec_string("ip",
-			"IP Address",
-			"The IP address of the candidate.",
-			NULL,
-			G_PARAM_READWRITE));
-
-	g_object_class_install_property(gobject_class, PROP_PORT,
-			g_param_spec_uint("port",
-			"Port",
-			"The port of the candidate.",
-			0, G_MAXUINT16, 0,
-			G_PARAM_READWRITE));
-
-	g_object_class_install_property(gobject_class, PROP_BASE_IP,
-			g_param_spec_string("base-ip",
-			"Base IP",
-			"The internal IP address of the candidate.",
-			NULL,
-			G_PARAM_READWRITE));
-
-	g_object_class_install_property(gobject_class, PROP_BASE_PORT,
-			g_param_spec_uint("base-port",
-			"Base Port",
-			"The internal port of the candidate.",
-			0, G_MAXUINT16, 0,
-			G_PARAM_READWRITE));
-
-	g_object_class_install_property(gobject_class, PROP_PROTOCOL,
-			g_param_spec_enum("protocol",
-			"Protocol",
-			"The protocol of the candidate.",
-			PURPLE_TYPE_MEDIA_NETWORK_PROTOCOL,
-			PURPLE_MEDIA_NETWORK_PROTOCOL_UDP,
-			G_PARAM_READWRITE));
-
-	g_object_class_install_property(gobject_class, PROP_PRIORITY,
-			g_param_spec_uint("priority",
-			"Priority",
-			"The priority of the candidate.",
-			0, G_MAXUINT32, 0,
-			G_PARAM_READWRITE));
-
-	g_object_class_install_property(gobject_class, PROP_TYPE,
-			g_param_spec_enum("type",
-			"Type",
-			"The type of the candidate.",
-			PURPLE_TYPE_MEDIA_CANDIDATE_TYPE,
-			PURPLE_MEDIA_CANDIDATE_TYPE_HOST,
-			G_PARAM_READWRITE));
-
-	g_object_class_install_property(gobject_class, PROP_USERNAME,
-			g_param_spec_string("username",
-			"Username",
-			"The username used to connect to the candidate.",
-			NULL,
-			G_PARAM_READWRITE));
-
-	g_object_class_install_property(gobject_class, PROP_PASSWORD,
-			g_param_spec_string("password",
-			"Password",
-			"The password use to connect to the candidate.",
-			NULL,
-			G_PARAM_READWRITE));
-
-	g_object_class_install_property(gobject_class, PROP_TTL,
-			g_param_spec_uint("ttl",
-			"TTL",
-			"The TTL of the candidate.",
-			0, G_MAXUINT, 0,
-			G_PARAM_READWRITE));
-
-	g_type_class_add_private(klass, sizeof(PurpleMediaCandidatePrivate));
-}
-
-G_DEFINE_TYPE(PurpleMediaCandidate,
-		purple_media_candidate, G_TYPE_OBJECT);
-#else
-GType
-purple_media_candidate_get_type()
-{
-	return G_TYPE_NONE;
-}
-#endif
-
-PurpleMediaCandidate *
-purple_media_candidate_new(const gchar *foundation, guint component_id,
-		PurpleMediaCandidateType type,
-		PurpleMediaNetworkProtocol proto,
-		const gchar *ip, guint port)
-{
-	return g_object_new(PURPLE_TYPE_MEDIA_CANDIDATE,
-			"foundation", foundation,
-			"component-id", component_id,
-			"type", type,
-			"protocol", proto,
-			"ip", ip,
-			"port", port, NULL);
-}
-
-static PurpleMediaCandidate *
-purple_media_candidate_copy(PurpleMediaCandidate *candidate)
-{
-#ifdef USE_VV
-	PurpleMediaCandidatePrivate *priv;
-	PurpleMediaCandidate *new_candidate;
-
-	if (candidate == NULL)
-		return NULL;
-
-	priv = PURPLE_MEDIA_CANDIDATE_GET_PRIVATE(candidate);
-
-	new_candidate = purple_media_candidate_new(priv->foundation,
-			priv->component_id, priv->type, priv->proto,
-			priv->ip, priv->port);
-	g_object_set(new_candidate,
-			"base-ip", priv->base_ip,
-			"base-port", priv->base_port,
-			"priority", priv->priority,
-			"username", priv->username,
-			"password", priv->password,
-			"ttl", priv->ttl, NULL);
-	return new_candidate;
-#else
-	return NULL;
-#endif
-}
-
-#ifdef USE_VV
-static FsCandidate *
-purple_media_candidate_to_fs(PurpleMediaCandidate *candidate)
-{
-	PurpleMediaCandidatePrivate *priv;
-	FsCandidate *fscandidate;
-
-	if (candidate == NULL)
-		return NULL;
-
-	priv = PURPLE_MEDIA_CANDIDATE_GET_PRIVATE(candidate);
-
-	fscandidate = fs_candidate_new(priv->foundation,
-			priv->component_id, priv->type,
-			priv->proto, priv->ip, priv->port);
-
-	fscandidate->base_ip = g_strdup(priv->base_ip);
-	fscandidate->base_port = priv->base_port;
-	fscandidate->priority = priv->priority;
-	fscandidate->username = g_strdup(priv->username);
-	fscandidate->password = g_strdup(priv->password);
-	fscandidate->ttl = priv->ttl;
-	return fscandidate;
-}
-
-static PurpleMediaCandidate *
-purple_media_candidate_from_fs(FsCandidate *fscandidate)
-{
-	PurpleMediaCandidate *candidate;
-
-	if (fscandidate == NULL)
-		return NULL;
-
-	candidate = purple_media_candidate_new(fscandidate->foundation,
-		fscandidate->component_id, fscandidate->type,
-		fscandidate->proto, fscandidate->ip, fscandidate->port);
-	g_object_set(candidate,
-			"base-ip", fscandidate->base_ip,
-			"base-port", fscandidate->base_port,
-			"priority", fscandidate->priority,
-			"username", fscandidate->username,
-			"password", fscandidate->password,
-			"ttl", fscandidate->ttl, NULL);
-	return candidate;
-}
-
-static GList *
-purple_media_candidate_list_from_fs(GList *candidates)
-{
-	GList *new_list = NULL;
-
-	for (; candidates; candidates = g_list_next(candidates)) {
-		new_list = g_list_prepend(new_list,
-				purple_media_candidate_from_fs(
-				candidates->data));
-	}
-
-	new_list = g_list_reverse(new_list);
-	return new_list;
-}
-
-static GList *
-purple_media_candidate_list_to_fs(GList *candidates)
-{
-	GList *new_list = NULL;
-
-	for (; candidates; candidates = g_list_next(candidates)) {
-		new_list = g_list_prepend(new_list,
-				purple_media_candidate_to_fs(
-				candidates->data));
-	}
-
-	new_list = g_list_reverse(new_list);
-	return new_list;
-}
-#endif
-
-GList *
-purple_media_candidate_list_copy(GList *candidates)
-{
-	GList *new_list = NULL;
-
-	for (; candidates; candidates = g_list_next(candidates)) {
-		new_list = g_list_prepend(new_list,
-				purple_media_candidate_copy(candidates->data));
-	}
-
-	new_list = g_list_reverse(new_list);
-	return new_list;
-}
-
-void
-purple_media_candidate_list_free(GList *candidates)
-{
-	for (; candidates; candidates =
-			g_list_delete_link(candidates, candidates)) {
-		g_object_unref(candidates->data);
-	}
-}
-
-gchar *
-purple_media_candidate_get_foundation(PurpleMediaCandidate *candidate)
-{
-	gchar *foundation;
-	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), NULL);
-	g_object_get(candidate, "foundation", &foundation, NULL);
-	return foundation;
-}
-
-guint
-purple_media_candidate_get_component_id(PurpleMediaCandidate *candidate)
-{
-	guint component_id;
-	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), 0);
-	g_object_get(candidate, "component-id", &component_id, NULL);
-	return component_id;
-}
-
-gchar *
-purple_media_candidate_get_ip(PurpleMediaCandidate *candidate)
-{
-	gchar *ip;
-	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), NULL);
-	g_object_get(candidate, "ip", &ip, NULL);
-	return ip;
-}
-
-guint16
-purple_media_candidate_get_port(PurpleMediaCandidate *candidate)
-{
-	guint port;
-	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), 0);
-	g_object_get(candidate, "port", &port, NULL);
-	return port;
-}
-
-gchar *
-purple_media_candidate_get_base_ip(PurpleMediaCandidate *candidate)
-{
-	gchar *base_ip;
-	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), NULL);
-	g_object_get(candidate, "base-ip", &base_ip, NULL);
-	return base_ip;
-}
-
-guint16
-purple_media_candidate_get_base_port(PurpleMediaCandidate *candidate)
-{
-	guint base_port;
-	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), 0);
-	g_object_get(candidate, "base_port", &base_port, NULL);
-	return base_port;
-}
-
-PurpleMediaNetworkProtocol
-purple_media_candidate_get_protocol(PurpleMediaCandidate *candidate)
-{
-	PurpleMediaNetworkProtocol protocol;
-	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate),
-			PURPLE_MEDIA_NETWORK_PROTOCOL_UDP);
-	g_object_get(candidate, "protocol", &protocol, NULL);
-	return protocol;
-}
-
-guint32
-purple_media_candidate_get_priority(PurpleMediaCandidate *candidate)
-{
-	guint priority;
-	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), 0);
-	g_object_get(candidate, "priority", &priority, NULL);
-	return priority;
-}
-
-PurpleMediaCandidateType
-purple_media_candidate_get_candidate_type(PurpleMediaCandidate *candidate)
-{
-	PurpleMediaCandidateType type;
-	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate),
-			PURPLE_MEDIA_CANDIDATE_TYPE_HOST);
-	g_object_get(candidate, "type", &type, NULL);
-	return type;
-}
-
-gchar *
-purple_media_candidate_get_username(PurpleMediaCandidate *candidate)
-{
-	gchar *username;
-	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), NULL);
-	g_object_get(candidate, "username", &username, NULL);
-	return username;
-}
-
-gchar *
-purple_media_candidate_get_password(PurpleMediaCandidate *candidate)
-{
-	gchar *password;
-	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), NULL);
-	g_object_get(candidate, "password", &password, NULL);
-	return password;
-}
-
-guint
-purple_media_candidate_get_ttl(PurpleMediaCandidate *candidate)
-{
-	guint ttl;
-	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), 0);
-	g_object_get(candidate, "ttl", &ttl, NULL);
-	return ttl;
-}
-
-#ifdef USE_VV
-static FsMediaType
-purple_media_to_fs_media_type(PurpleMediaSessionType type)
-{
-	if (type & PURPLE_MEDIA_AUDIO)
-		return FS_MEDIA_TYPE_AUDIO;
-	else if (type & PURPLE_MEDIA_VIDEO)
-		return FS_MEDIA_TYPE_VIDEO;
-	else
-		return 0;
-}
-
-static FsStreamDirection
-purple_media_to_fs_stream_direction(PurpleMediaSessionType type)
-{
-	if ((type & PURPLE_MEDIA_AUDIO) == PURPLE_MEDIA_AUDIO ||
-			(type & PURPLE_MEDIA_VIDEO) == PURPLE_MEDIA_VIDEO)
-		return FS_DIRECTION_BOTH;
-	else if ((type & PURPLE_MEDIA_SEND_AUDIO) ||
-			(type & PURPLE_MEDIA_SEND_VIDEO))
-		return FS_DIRECTION_SEND;
-	else if ((type & PURPLE_MEDIA_RECV_AUDIO) ||
-			(type & PURPLE_MEDIA_RECV_VIDEO))
-		return FS_DIRECTION_RECV;
-	else
-		return FS_DIRECTION_NONE;
-}
-
-static PurpleMediaSessionType
-purple_media_from_fs(FsMediaType type, FsStreamDirection direction)
-{
-	PurpleMediaSessionType result = PURPLE_MEDIA_NONE;
-	if (type == FS_MEDIA_TYPE_AUDIO) {
-		if (direction & FS_DIRECTION_SEND)
-			result |= PURPLE_MEDIA_SEND_AUDIO;
-		if (direction & FS_DIRECTION_RECV)
-			result |= PURPLE_MEDIA_RECV_AUDIO;
-	} else if (type == FS_MEDIA_TYPE_VIDEO) {
-		if (direction & FS_DIRECTION_SEND)
-			result |= PURPLE_MEDIA_SEND_VIDEO;
-		if (direction & FS_DIRECTION_RECV)
-			result |= PURPLE_MEDIA_RECV_VIDEO;
-	}
-	return result;
-}
-#endif
-
-/*
- * PurpleMediaCodec
- */
-
-struct _PurpleMediaCodecClass
-{
-	GObjectClass parent_class;
-};
-
-struct _PurpleMediaCodec
-{
-	GObject parent;
-};
-
-#ifdef USE_VV
-struct _PurpleMediaCodecPrivate
-{
-	gint id;
-	char *encoding_name;
-	PurpleMediaSessionType media_type;
-	guint clock_rate;
-	guint channels;
-	GList *optional_params;
-};
-
-enum {
-	PROP_CODEC_0,
-	PROP_ID,
-	PROP_ENCODING_NAME,
-	PROP_MEDIA_TYPE,
-	PROP_CLOCK_RATE,
-	PROP_CHANNELS,
-	PROP_OPTIONAL_PARAMS,
-};
-
-static void
-purple_media_codec_init(PurpleMediaCodec *info)
-{
-	PurpleMediaCodecPrivate *priv =
-			PURPLE_MEDIA_CODEC_GET_PRIVATE(info);
-	priv->encoding_name = NULL;
-	priv->optional_params = NULL;
-}
-
-static void
-purple_media_codec_finalize(GObject *info)
-{
-	PurpleMediaCodecPrivate *priv =
-			PURPLE_MEDIA_CODEC_GET_PRIVATE(info);
-	g_free(priv->encoding_name);
-	for (; priv->optional_params; priv->optional_params =
-			g_list_delete_link(priv->optional_params,
-			priv->optional_params)) {
-		g_free(priv->optional_params->data);
-	}
-}
-
-static void
-purple_media_codec_set_property (GObject *object, guint prop_id,
-		const GValue *value, GParamSpec *pspec)
-{
-	PurpleMediaCodecPrivate *priv;
-	g_return_if_fail(PURPLE_IS_MEDIA_CODEC(object));
-
-	priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(object);
-
-	switch (prop_id) {
-		case PROP_ID:
-			priv->id = g_value_get_uint(value);
-			break;
-		case PROP_ENCODING_NAME:
-			g_free(priv->encoding_name);
-			priv->encoding_name = g_value_dup_string(value);
-			break;
-		case PROP_MEDIA_TYPE:
-			priv->media_type = g_value_get_flags(value);
-			break;
-		case PROP_CLOCK_RATE:
-			priv->clock_rate = g_value_get_uint(value);
-			break;
-		case PROP_CHANNELS:
-			priv->channels = g_value_get_uint(value);
-			break;
-		case PROP_OPTIONAL_PARAMS:
-			priv->optional_params = g_value_get_pointer(value);
-			break;
-		default:	
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(
-					object, prop_id, pspec);
-			break;
-	}
-}
-
-static void
-purple_media_codec_get_property (GObject *object, guint prop_id,
-		GValue *value, GParamSpec *pspec)
-{
-	PurpleMediaCodecPrivate *priv;
-	g_return_if_fail(PURPLE_IS_MEDIA_CODEC(object));
-	
-	priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(object);
-
-	switch (prop_id) {
-		case PROP_ID:
-			g_value_set_uint(value, priv->id);
-			break;
-		case PROP_ENCODING_NAME:
-			g_value_set_string(value, priv->encoding_name);
-			break;
-		case PROP_MEDIA_TYPE:
-			g_value_set_flags(value, priv->media_type);
-			break;
-		case PROP_CLOCK_RATE:
-			g_value_set_uint(value, priv->clock_rate);
-			break;
-		case PROP_CHANNELS:
-			g_value_set_uint(value, priv->channels);
-			break;
-		case PROP_OPTIONAL_PARAMS:
-			g_value_set_pointer(value, priv->optional_params);
-			break;
-		default:	
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(
-					object, prop_id, pspec);
-			break;
-	}
-}
-
-static void
-purple_media_codec_class_init(PurpleMediaCodecClass *klass)
-{
-	GObjectClass *gobject_class = (GObjectClass*)klass;
-	
-	gobject_class->finalize = purple_media_codec_finalize;
-	gobject_class->set_property = purple_media_codec_set_property;
-	gobject_class->get_property = purple_media_codec_get_property;
-
-	g_object_class_install_property(gobject_class, PROP_ID,
-			g_param_spec_uint("id",
-			"ID",
-			"The numeric identifier of the codec.",
-			0, G_MAXUINT, 0,
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
-
-	g_object_class_install_property(gobject_class, PROP_ENCODING_NAME,
-			g_param_spec_string("encoding-name",
-			"Encoding Name",
-			"The name of the codec.",
-			NULL,
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
-
-	g_object_class_install_property(gobject_class, PROP_MEDIA_TYPE,
-			g_param_spec_flags("media-type",
-			"Media Type",
-			"Whether this is an audio of video codec.",
-			PURPLE_TYPE_MEDIA_SESSION_TYPE,
-			PURPLE_MEDIA_NONE,
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
-
-	g_object_class_install_property(gobject_class, PROP_CLOCK_RATE,
-			g_param_spec_uint("clock-rate",
-			"Create Callback",
-			"The function called to create this element.",
-			0, G_MAXUINT, 0,
-			G_PARAM_READWRITE));
-
-	g_object_class_install_property(gobject_class, PROP_CHANNELS,
-			g_param_spec_uint("channels",
-			"Channels",
-			"The number of channels in this codec.",
-			0, G_MAXUINT, 0,
-			G_PARAM_READWRITE));
-	g_object_class_install_property(gobject_class, PROP_OPTIONAL_PARAMS,
-			g_param_spec_pointer("optional-params",
-			"Optional Params",
-			"A list of optional parameters for the codec.",
-			G_PARAM_READWRITE));
-
-	g_type_class_add_private(klass, sizeof(PurpleMediaCodecPrivate));
-}
-
-G_DEFINE_TYPE(PurpleMediaCodec,
-		purple_media_codec, G_TYPE_OBJECT);
-#else
-GType
-purple_media_codec_get_type()
-{
-	return G_TYPE_NONE;
-}
-#endif
-
-guint
-purple_media_codec_get_id(PurpleMediaCodec *codec)
-{
-	guint id;
-	g_return_val_if_fail(PURPLE_IS_MEDIA_CODEC(codec), 0);
-	g_object_get(codec, "id", &id, NULL);
-	return id;
-}
-
-gchar *
-purple_media_codec_get_encoding_name(PurpleMediaCodec *codec)
-{
-	gchar *name;
-	g_return_val_if_fail(PURPLE_IS_MEDIA_CODEC(codec), NULL);
-	g_object_get(codec, "encoding-name", &name, NULL);
-	return name;
-}
-
-guint
-purple_media_codec_get_clock_rate(PurpleMediaCodec *codec)
-{
-	guint clock_rate;
-	g_return_val_if_fail(PURPLE_IS_MEDIA_CODEC(codec), 0);
-	g_object_get(codec, "clock-rate", &clock_rate, NULL);
-	return clock_rate;
-}
-
-guint
-purple_media_codec_get_channels(PurpleMediaCodec *codec)
-{
-	guint channels;
-	g_return_val_if_fail(PURPLE_IS_MEDIA_CODEC(codec), 0);
-	g_object_get(codec, "channels", &channels, NULL);
-	return channels;
-}
-
-GList *
-purple_media_codec_get_optional_parameters(PurpleMediaCodec *codec)
-{
-	GList *optional_params;
-	g_return_val_if_fail(PURPLE_IS_MEDIA_CODEC(codec), NULL);
-	g_object_get(codec, "optional-params", &optional_params, NULL);
-	return optional_params;
-}
-
-void
-purple_media_codec_add_optional_parameter(PurpleMediaCodec *codec,
-		const gchar *name, const gchar *value)
-{
-#ifdef USE_VV
-	PurpleMediaCodecPrivate *priv;
-	PurpleKeyValuePair *new_param;
-
-	g_return_if_fail(codec != NULL);
-	g_return_if_fail(name != NULL && value != NULL);
-
-	priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(codec);
-
-	new_param = g_new0(PurpleKeyValuePair, 1);
-	new_param->key = g_strdup(name);
-	new_param->value = g_strdup(value);
-	priv->optional_params = g_list_append(
-			priv->optional_params, new_param);
-#endif
-}
-
-void
-purple_media_codec_remove_optional_parameter(PurpleMediaCodec *codec,
-		PurpleKeyValuePair *param)
-{
-#ifdef USE_VV
-	PurpleMediaCodecPrivate *priv;
-
-	g_return_if_fail(codec != NULL && param != NULL);
-
-	priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(codec);
-
-	g_free(param->key);
-	g_free(param->value);
-	g_free(param);
-
-	priv->optional_params =
-			g_list_remove(priv->optional_params, param);
-#endif
-}
-
-PurpleKeyValuePair *
-purple_media_codec_get_optional_parameter(PurpleMediaCodec *codec,
-		const gchar *name, const gchar *value)
-{
-#ifdef USE_VV
-	PurpleMediaCodecPrivate *priv;
-	GList *iter;
-
-	g_return_val_if_fail(codec != NULL, NULL);
-	g_return_val_if_fail(name != NULL, NULL);
-
-	priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(codec);
-
-	for (iter = priv->optional_params; iter; iter = g_list_next(iter)) {
-		PurpleKeyValuePair *param = iter->data;
-		if (!g_ascii_strcasecmp(param->key, name) &&
-				(value == NULL ||
-				!g_ascii_strcasecmp(param->value, value)))
-			return param;
-	}
-#endif
-
-	return NULL;
-}
-
-PurpleMediaCodec *
-purple_media_codec_new(int id, const char *encoding_name,
-		PurpleMediaSessionType media_type, guint clock_rate)
-{
-	PurpleMediaCodec *codec =
-			g_object_new(PURPLE_TYPE_MEDIA_CODEC,
-			"id", id,
-			"encoding_name", encoding_name,
-			"media_type", media_type,
-			"clock-rate", clock_rate, NULL);
-	return codec;
-}
-
-static PurpleMediaCodec *
-purple_media_codec_copy(PurpleMediaCodec *codec)
-{
-#ifdef USE_VV
-	PurpleMediaCodecPrivate *priv;
-	PurpleMediaCodec *new_codec;
-	GList *iter;
-
-	if (codec == NULL)
-		return NULL;
-
-	priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(codec);
-
-	new_codec = purple_media_codec_new(priv->id, priv->encoding_name,
-			priv->media_type, priv->clock_rate);
-	g_object_set(codec, "channels", priv->channels, NULL);
-
-	for (iter = priv->optional_params; iter; iter = g_list_next(iter)) {
-		PurpleKeyValuePair *param =
-				(PurpleKeyValuePair*)iter->data;
-		purple_media_codec_add_optional_parameter(new_codec,
-				param->key, param->value);
-	}
-
-	return new_codec;
-#else
-	return NULL;
-#endif
-}
-
-#ifdef USE_VV
-static FsCodec *
-purple_media_codec_to_fs(const PurpleMediaCodec *codec)
-{
-	PurpleMediaCodecPrivate *priv;
-	FsCodec *new_codec;
-	GList *iter;
-
-	if (codec == NULL)
-		return NULL;
-
-	priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(codec);
-
-	new_codec = fs_codec_new(priv->id, priv->encoding_name,
-			purple_media_to_fs_media_type(priv->media_type),
-			priv->clock_rate);
-	new_codec->channels = priv->channels;
-
-	for (iter = priv->optional_params; iter; iter = g_list_next(iter)) {
-		PurpleKeyValuePair *param = (PurpleKeyValuePair*)iter->data;
-		fs_codec_add_optional_parameter(new_codec,
-				param->key, param->value);
-	}
-
-	return new_codec;
-}
-
-static PurpleMediaCodec *
-purple_media_codec_from_fs(const FsCodec *codec)
-{
-	PurpleMediaCodec *new_codec;
-	GList *iter;
-
-	if (codec == NULL)
-		return NULL;
-
-	new_codec = purple_media_codec_new(codec->id, codec->encoding_name,
-			purple_media_from_fs(codec->media_type,
-			FS_DIRECTION_BOTH), codec->clock_rate);
-	g_object_set(new_codec, "channels", codec->channels, NULL);
-
-	for (iter = codec->optional_params; iter; iter = g_list_next(iter)) {
-		FsCodecParameter *param = (FsCodecParameter*)iter->data;
-		purple_media_codec_add_optional_parameter(new_codec,
-				param->name, param->value);
-	}
-
-	return new_codec;
-}
-#endif
-
-gchar *
-purple_media_codec_to_string(const PurpleMediaCodec *codec)
-{
-#ifdef USE_VV
-	FsCodec *fscodec = purple_media_codec_to_fs(codec);
-	gchar *str = fs_codec_to_string(fscodec);
-	fs_codec_destroy(fscodec);
-	return str;
-#else
-	return g_strdup("");
-#endif
-}
-
-#ifdef USE_VV
-static GList *
-purple_media_codec_list_from_fs(GList *codecs)
-{
-	GList *new_list = NULL;
-
-	for (; codecs; codecs = g_list_next(codecs)) {
-		new_list = g_list_prepend(new_list,
-				purple_media_codec_from_fs(
-				codecs->data));
-	}
-
-	new_list = g_list_reverse(new_list);
-	return new_list;
-}
-
-static GList *
-purple_media_codec_list_to_fs(GList *codecs)
-{
-	GList *new_list = NULL;
-
-	for (; codecs; codecs = g_list_next(codecs)) {
-		new_list = g_list_prepend(new_list,
-				purple_media_codec_to_fs(
-				codecs->data));
-	}
-
-	new_list = g_list_reverse(new_list);
-	return new_list;
-}
-#endif
-
-GList *
-purple_media_codec_list_copy(GList *codecs)
-{
-	GList *new_list = NULL;
-
-	for (; codecs; codecs = g_list_next(codecs)) {
-		new_list = g_list_prepend(new_list,
-				purple_media_codec_copy(codecs->data));
-	}
-
-	new_list = g_list_reverse(new_list);
-	return new_list;
-}
-
-void
-purple_media_codec_list_free(GList *codecs)
-{
-	for (; codecs; codecs =
-			g_list_delete_link(codecs, codecs)) {
-		g_object_unref(codecs->data);
-	}
-}
-
-#ifdef USE_VV
-static PurpleMediaSession*
-purple_media_get_session(PurpleMedia *media, const gchar *sess_id)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-	return (PurpleMediaSession*) (media->priv->sessions) ?
-			g_hash_table_lookup(media->priv->sessions, sess_id) : NULL;
-}
-
-static FsParticipant*
-purple_media_get_participant(PurpleMedia *media, const gchar *name)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-	return (FsParticipant*) (media->priv->participants) ?
-			g_hash_table_lookup(media->priv->participants, name) : NULL;
-}
-
-static PurpleMediaStream*
-purple_media_get_stream(PurpleMedia *media, const gchar *session, const gchar *participant)
-{
-	GList *streams;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-
-	streams = media->priv->streams;
-
-	for (; streams; streams = g_list_next(streams)) {
-		PurpleMediaStream *stream = streams->data;
-		if (!strcmp(stream->session->id, session) &&
-				!strcmp(stream->participant, participant))
-			return stream;
-	}
-
-	return NULL;
-}
-
-static GList *
-purple_media_get_streams(PurpleMedia *media, const gchar *session,
-		const gchar *participant)
-{
-	GList *streams;
-	GList *ret = NULL;
-	
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-
-	streams = media->priv->streams;
-
-	for (; streams; streams = g_list_next(streams)) {
-		PurpleMediaStream *stream = streams->data;
-		if ((session == NULL ||
-				!strcmp(stream->session->id, session)) &&
-				(participant == NULL ||
-				!strcmp(stream->participant, participant)))
-			ret = g_list_append(ret, stream);
-	}
-
-	return ret;
-}
-
-static void
-purple_media_add_session(PurpleMedia *media, PurpleMediaSession *session)
-{
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-	g_return_if_fail(session != NULL);
-
-	if (!media->priv->sessions) {
-		purple_debug_info("media", "Creating hash table for sessions\n");
-		media->priv->sessions = g_hash_table_new(g_str_hash, g_str_equal);
-	}
-	g_hash_table_insert(media->priv->sessions, g_strdup(session->id), session);
-}
-
-static gboolean
-purple_media_remove_session(PurpleMedia *media, PurpleMediaSession *session)
-{
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-	return g_hash_table_remove(media->priv->sessions, session->id);
-}
-
-static FsParticipant *
-purple_media_add_participant(PurpleMedia *media, const gchar *name)
-{
-	FsParticipant *participant;
-	GError *err = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-
-	participant = purple_media_get_participant(media, name);
-
-	if (participant)
-		return participant;
-
-	participant = fs_conference_new_participant(media->priv->conference,
-						    (gchar*)name, &err);
-
-	if (err) {
-		purple_debug_error("media", "Error creating participant: %s\n",
-				   err->message);
-		g_error_free(err);
-		return NULL;
-	}
-
-	if (!media->priv->participants) {
-		purple_debug_info("media", "Creating hash table for participants\n");
-		media->priv->participants = g_hash_table_new_full(g_str_hash,
-				g_str_equal, g_free, NULL);
-	}
-
-	g_hash_table_insert(media->priv->participants, g_strdup(name), participant);
-
-	return participant;
-}
-
-static PurpleMediaStream *
-purple_media_insert_stream(PurpleMediaSession *session, const gchar *name, FsStream *stream)
-{
-	PurpleMediaStream *media_stream;
-	
-	g_return_val_if_fail(session != NULL, NULL);
-
-	media_stream = g_new0(PurpleMediaStream, 1);
-	media_stream->stream = stream;
-	media_stream->participant = g_strdup(name);
-	media_stream->session = session;
-
-	session->media->priv->streams =
-			g_list_append(session->media->priv->streams, media_stream);
-
-	return media_stream;
-}
-
-static void
-purple_media_insert_local_candidate(PurpleMediaSession *session, const gchar *name,
-				     FsCandidate *candidate)
-{
-	PurpleMediaStream *stream;
-
-	g_return_if_fail(session != NULL);
-
-	stream = purple_media_get_stream(session->media, session->id, name);
-	stream->local_candidates = g_list_append(stream->local_candidates, candidate);
-}
-#endif
-
-GList *
-purple_media_get_session_ids(PurpleMedia *media)
-{
-#ifdef USE_VV
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-	return media->priv->sessions != NULL ?
-			g_hash_table_get_keys(media->priv->sessions) : NULL;
-#else
-	return NULL;
-#endif
-}
-
-#ifdef USE_VV
-static void 
-purple_media_set_src(PurpleMedia *media, const gchar *sess_id, GstElement *src)
-{
-	PurpleMediaSession *session;
-	GstPad *sinkpad;
-	GstPad *srcpad;
-
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-	g_return_if_fail(GST_IS_ELEMENT(src));
-
-	session = purple_media_get_session(media, sess_id);
-
-	if (session == NULL) {
-		purple_debug_warning("media", "purple_media_set_src: trying"
-				" to set src on non-existent session\n");
-		return;
-	}
-
-	if (session->src)
-		gst_object_unref(session->src);
-	session->src = src;
-	gst_element_set_locked_state(session->src, TRUE);
-
-	session->tee = gst_element_factory_make("tee", NULL);
-	gst_bin_add(GST_BIN(session->media->priv->confbin), session->tee);
-
-	/* This supposedly isn't necessary, but it silences some warnings */
-	if (GST_ELEMENT_PARENT(session->media->priv->confbin)
-			== GST_ELEMENT_PARENT(session->src)) {
-		GstPad *pad = gst_element_get_static_pad(session->tee, "sink");
-		GstPad *ghost = gst_ghost_pad_new(NULL, pad);
-		gst_object_unref(pad);
-		gst_pad_set_active(ghost, TRUE);
-		gst_element_add_pad(session->media->priv->confbin, ghost);
-	}
-
-	gst_element_set_state(session->tee, GST_STATE_PLAYING);
-	gst_element_link(session->src, session->media->priv->confbin);
-
-	g_object_get(session->session, "sink-pad", &sinkpad, NULL);
-	if (session->type & PURPLE_MEDIA_SEND_AUDIO) {
-		gchar *name = g_strdup_printf("volume_%s", session->id);
-		GstElement *level;
-		GstElement *volume = gst_element_factory_make("volume", name);
-		double input_volume = purple_prefs_get_int(
-				"/purple/media/audio/volume/input")/10.0;
-		g_free(name);
-		name = g_strdup_printf("sendlevel_%s", session->id);
-		level = gst_element_factory_make("level", name);
-		g_free(name);
-		gst_bin_add(GST_BIN(session->media->priv->confbin), volume);
-		gst_bin_add(GST_BIN(session->media->priv->confbin), level);
-		gst_element_set_state(level, GST_STATE_PLAYING);
-		gst_element_set_state(volume, GST_STATE_PLAYING);
-		gst_element_link(volume, level);
-		gst_element_link(session->tee, volume);
-		srcpad = gst_element_get_static_pad(level, "src");
-		g_object_set(volume, "volume", input_volume, NULL);
-	} else {
-		srcpad = gst_element_get_request_pad(session->tee, "src%d");
-	}
-	purple_debug_info("media", "connecting pad: %s\n", 
-			  gst_pad_link(srcpad, sinkpad) == GST_PAD_LINK_OK
-			  ? "success" : "failure");
-	gst_element_set_locked_state(session->src, FALSE);
-	gst_object_unref(session->src);
-}
-#endif
-
-#ifdef USE_GSTREAMER
-GstElement *
-purple_media_get_src(PurpleMedia *media, const gchar *sess_id)
-{
-#ifdef USE_VV
-	PurpleMediaSession *session;
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-	session = purple_media_get_session(media, sess_id);
-	return (session != NULL) ? session->src : NULL;
-#else
-	return NULL;
-#endif
-}
-#endif /* USE_GSTREAMER */
-
-#ifdef USE_VV
-static PurpleMediaSession *
-purple_media_session_from_fs_stream(PurpleMedia *media, FsStream *stream)
-{
-	FsSession *fssession;
-	GList *values;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-	g_return_val_if_fail(FS_IS_STREAM(stream), NULL);
-
-	g_object_get(stream, "session", &fssession, NULL);
-
-	values = g_hash_table_get_values(media->priv->sessions);
-
-	for (; values; values = g_list_delete_link(values, values)) {
-		PurpleMediaSession *session = values->data;
-
-		if (session->session == fssession) {
-			g_list_free(values);
-			g_object_unref(fssession);
-			return session;
-		}
-	}
-
-	g_object_unref(fssession);
-	return NULL;
-}
-
-static gboolean
-media_bus_call(GstBus *bus, GstMessage *msg, PurpleMedia *media)
-{
-	switch(GST_MESSAGE_TYPE(msg)) {
-		case GST_MESSAGE_ELEMENT: {
-			if (g_signal_has_handler_pending(media,
-					purple_media_signals[LEVEL], 0, FALSE)
-					&& gst_structure_has_name(
-					gst_message_get_structure(msg), "level")) {
-				GstElement *src = GST_ELEMENT(GST_MESSAGE_SRC(msg));
-				gchar *name;
-				gchar *participant = NULL;
-				PurpleMediaSession *session = NULL;
-				gdouble rms_db;
-				gdouble percent;
-				const GValue *list;
-				const GValue *value;
-
-				if (!PURPLE_IS_MEDIA(media) ||
-						GST_ELEMENT_PARENT(src) !=
-						media->priv->confbin)
-					break;
-
-				name = gst_element_get_name(src);
-				if (!strncmp(name, "sendlevel_", 10)) {
-					session = purple_media_get_session(
-							media, name+10);
-				} else {
-					GList *iter = media->priv->streams;
-					for (; iter; iter = g_list_next(iter)) {
-						PurpleMediaStream *stream = iter->data;
-						if (stream->level == src) {
-							session = stream->session;
-							participant = stream->participant;
-							break;
-						}
-					}
-				}
-				g_free(name);
-				if (!session)
-					break;
-
-				list = gst_structure_get_value(
-						gst_message_get_structure(msg), "rms");
-				value = gst_value_list_get_value(list, 0);
-				rms_db = g_value_get_double(value);
-				percent = pow(10, rms_db / 20) * 5;
-				if(percent > 1.0)
-					percent = 1.0;
-
-				g_signal_emit(media, purple_media_signals[LEVEL],
-						0, session->id, participant, percent);
-				break;
-			}
-			if (!FS_IS_CONFERENCE(GST_MESSAGE_SRC(msg)) ||
-					!PURPLE_IS_MEDIA(media) ||
-					media->priv->conference !=
-					FS_CONFERENCE(GST_MESSAGE_SRC(msg)))
-				break;
-
-			if (gst_structure_has_name(msg->structure, "farsight-error")) {
-				FsError error_no;
-				gst_structure_get_enum(msg->structure, "error-no",
-						FS_TYPE_ERROR, (gint*)&error_no);
-				switch (error_no) {
-					case FS_ERROR_NO_CODECS:
-						purple_media_error(media, _("No codecs found. Install some GStreamer codecs found in GStreamer plugins packages."));
-						purple_media_end(media, NULL, NULL);
-						break;
-					case FS_ERROR_NO_CODECS_LEFT:
-						purple_media_error(media, _("No codecs left. Your codec preferences in fs-codecs.conf are too strict."));
-						purple_media_end(media, NULL, NULL);
-						break;
-					case FS_ERROR_UNKNOWN_CNAME:
-					/*
-					 * Unknown CName is only a problem for the
-					 * multicast transmitter which isn't used.
-					 * It is also deprecated.
-					 */
-						break;
-					default:
-						purple_debug_error("media", "farsight-error: %i: %s\n", error_no,
-							  	gst_structure_get_string(msg->structure, "error-msg"));
-						break;
-				}
-
-				if (FS_ERROR_IS_FATAL(error_no)) {
-					purple_media_error(media, _("A non-recoverable Farsight2 error has occurred."));
-					purple_media_end(media, NULL, NULL);
-				}
-			} else if (gst_structure_has_name(msg->structure,
-					"farsight-new-local-candidate")) {
-				FsStream *stream = g_value_get_object(gst_structure_get_value(msg->structure, "stream"));
-				FsCandidate *local_candidate = g_value_get_boxed(gst_structure_get_value(msg->structure, "candidate"));
-				PurpleMediaSession *session = purple_media_session_from_fs_stream(media, stream);
-				purple_media_new_local_candidate_cb(stream, local_candidate, session);
-			} else if (gst_structure_has_name(msg->structure,
-					"farsight-local-candidates-prepared")) {
-				FsStream *stream = g_value_get_object(gst_structure_get_value(msg->structure, "stream"));
-				PurpleMediaSession *session = purple_media_session_from_fs_stream(media, stream);
-				purple_media_candidates_prepared_cb(stream, session);
-			} else if (gst_structure_has_name(msg->structure,
-					"farsight-new-active-candidate-pair")) {
-				FsStream *stream = g_value_get_object(gst_structure_get_value(msg->structure, "stream"));
-				FsCandidate *local_candidate = g_value_get_boxed(gst_structure_get_value(msg->structure, "local-candidate"));
-				FsCandidate *remote_candidate = g_value_get_boxed(gst_structure_get_value(msg->structure, "remote-candidate"));
-				PurpleMediaSession *session = purple_media_session_from_fs_stream(media, stream);
-				purple_media_candidate_pair_established_cb(stream, local_candidate, remote_candidate, session);
-			} else if (gst_structure_has_name(msg->structure,
-					"farsight-recv-codecs-changed")) {
-				GList *codecs = g_value_get_boxed(gst_structure_get_value(msg->structure, "codecs"));
-				FsCodec *codec = codecs->data;
-				purple_debug_info("media", "farsight-recv-codecs-changed: %s\n", codec->encoding_name);
-				
-			} else if (gst_structure_has_name(msg->structure,
-					"farsight-component-state-changed")) {
-				FsStreamState fsstate = g_value_get_enum(gst_structure_get_value(msg->structure, "state"));
-				guint component = g_value_get_uint(gst_structure_get_value(msg->structure, "component"));
-				const gchar *state;
-				switch (fsstate) {
-					case FS_STREAM_STATE_FAILED:
-						state = "FAILED";
-						break;
-					case FS_STREAM_STATE_DISCONNECTED:
-						state = "DISCONNECTED";
-						break;
-					case FS_STREAM_STATE_GATHERING:
-						state = "GATHERING";
-						break;
-					case FS_STREAM_STATE_CONNECTING:
-						state = "CONNECTING";
-						break;
-					case FS_STREAM_STATE_CONNECTED:
-						state = "CONNECTED";
-						break;
-					case FS_STREAM_STATE_READY:
-						state = "READY";
-						break;
-					default:
-						state = "UNKNOWN";
-						break;
-				}
-				purple_debug_info("media", "farsight-component-state-changed: component: %u state: %s\n", component, state);
-			} else if (gst_structure_has_name(msg->structure,
-					"farsight-send-codec-changed")) {
-				FsCodec *codec = g_value_get_boxed(gst_structure_get_value(msg->structure, "codec"));
-				gchar *codec_str = fs_codec_to_string(codec);
-				purple_debug_info("media", "farsight-send-codec-changed: codec: %s\n", codec_str);
-				g_free(codec_str);
-			} else if (gst_structure_has_name(msg->structure,
-					"farsight-codecs-changed")) {
-				GList *sessions = g_hash_table_get_values(PURPLE_MEDIA(media)->priv->sessions);
-				FsSession *fssession = g_value_get_object(gst_structure_get_value(msg->structure, "session"));
-				for (; sessions; sessions = g_list_delete_link(sessions, sessions)) {
-					PurpleMediaSession *session = sessions->data;
-					if (session->session == fssession) {
-						gchar *session_id = g_strdup(session->id);
-						g_signal_emit(media, purple_media_signals[CODECS_CHANGED], 0, session_id);
-						g_free(session_id);
-						g_list_free(sessions);
-						break;
-					}
-				}
-			}
-			break;
-		}
-		case GST_MESSAGE_ERROR: {
-			GstElement *element = GST_ELEMENT(GST_MESSAGE_SRC(msg));
-			GstElement *lastElement = NULL;
-			while (!GST_IS_PIPELINE(element)) {
-				if (element == media->priv->confbin) {
-					purple_media_error(media, _("Conference error"));
-					purple_media_end(media, NULL, NULL);
-					break;
-				}
-				lastElement = element;
-				element = GST_ELEMENT_PARENT(element);
-			}
-			if (GST_IS_PIPELINE(element)) {
-				GList *sessions = g_hash_table_get_values(media->priv->sessions);
-				for (; sessions; sessions = g_list_delete_link(sessions, sessions)) {
-					PurpleMediaSession *session = sessions->data;
-
-					if (session->src == lastElement) {
-						if (session->type & PURPLE_MEDIA_AUDIO)
-							purple_media_error(media, _("Error with your microphone"));
-						else
-							purple_media_error(media, _("Error with your webcam"));
-						purple_media_end(media, NULL, NULL);
-						break;
-					}
-				}
-				g_list_free(sessions);
-			}
-		}
-		default:
-			break;
-	}
-
-	return TRUE;
-}
-#endif
-
-PurpleAccount *
-purple_media_get_account(PurpleMedia *media)
-{
-#ifdef USE_VV
-	PurpleAccount *account;
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-	g_object_get(G_OBJECT(media), "account", &account, NULL);
-	return account;
-#else
-	return NULL;
-#endif
-}
-
-gpointer
-purple_media_get_prpl_data(PurpleMedia *media)
-{
-#ifdef USE_VV
-	gpointer prpl_data;
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-	g_object_get(G_OBJECT(media), "prpl-data", &prpl_data, NULL);
-	return prpl_data;
-#else
-	return NULL;
-#endif
-}
-
-void
-purple_media_set_prpl_data(PurpleMedia *media, gpointer prpl_data)
-{
-#ifdef USE_VV
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-	g_object_set(G_OBJECT(media), "prpl-data", prpl_data, NULL);
-#endif
-}
-
-void
-purple_media_error(PurpleMedia *media, const gchar *error, ...)
-{
-#ifdef USE_VV
-	va_list args;
-	gchar *message;
-
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-
-	va_start(args, error);
-	message = g_strdup_vprintf(error, args);
-	va_end(args);
-
-	purple_debug_error("media", "%s\n", message);
-	g_signal_emit(media, purple_media_signals[S_ERROR], 0, message);
-
-	g_free(message);
-#endif
-}
-
-void
-purple_media_end(PurpleMedia *media,
-		const gchar *session_id, const gchar *participant)
-{
-#ifdef USE_VV
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-	if (session_id == NULL && participant == NULL) {
-		g_signal_emit(media, purple_media_signals[STATE_CHANGED],
-				0, PURPLE_MEDIA_STATE_END,
-				NULL, NULL);
-		g_object_unref(media);
-	}
-#endif
-}
-
-void
-purple_media_stream_info(PurpleMedia *media, PurpleMediaInfoType type,
-		const gchar *session_id, const gchar *participant,
-		gboolean local)
-{
-#ifdef USE_VV
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-
-	if (type == PURPLE_MEDIA_INFO_ACCEPT) {
-		GList *streams;
-
-		g_return_if_fail(PURPLE_IS_MEDIA(media));
-
-		streams = purple_media_get_streams(media,
-				session_id, participant);
-
-		for (; streams; streams =
-				g_list_delete_link(streams, streams)) {
-			PurpleMediaStream *stream = streams->data;
-			g_object_set(G_OBJECT(stream->stream), "direction",
-					purple_media_to_fs_stream_direction(
-					stream->session->type), NULL);
-			stream->accepted = TRUE;
-
-			if (stream->remote_candidates != NULL &&
-					stream->initiator == FALSE) {
-				GError *err = NULL;
-				fs_stream_set_remote_candidates(stream->stream,
-						stream->remote_candidates, &err);
-
-				if (err) {
-					purple_debug_error("media", "Error adding remote"
-							" candidates: %s\n", err->message);
-					g_error_free(err);
-				}
-			}
-		}
-	} else if (local == TRUE && (type == PURPLE_MEDIA_INFO_MUTE ||
-			type == PURPLE_MEDIA_INFO_UNMUTE)) {
-		GList *sessions;
-		gboolean active = (type == PURPLE_MEDIA_INFO_MUTE);
-
-		g_return_if_fail(PURPLE_IS_MEDIA(media));
-
-		if (session_id == NULL)
-			sessions = g_hash_table_get_values(
-					media->priv->sessions);
-		else
-			sessions = g_list_prepend(NULL,
-					purple_media_get_session(
-					media, session_id));
-
-		purple_debug_info("media", "Turning mute %s\n",
-				active ? "on" : "off");
-
-		for (; sessions; sessions = g_list_delete_link(
-				sessions, sessions)) {
-			PurpleMediaSession *session = sessions->data;
-			if (session->type & PURPLE_MEDIA_SEND_AUDIO) {
-				gchar *name = g_strdup_printf("volume_%s",
-						session->id);
-				GstElement *volume = gst_bin_get_by_name(
-						GST_BIN(session->media->
-						priv->confbin), name);
-				g_free(name);
-				g_object_set(volume, "mute", active, NULL);
-			}
-		}
-	} else if (local == TRUE && (type == PURPLE_MEDIA_INFO_PAUSE ||
-			type == PURPLE_MEDIA_INFO_UNPAUSE)) {
-		gboolean active = (type == PURPLE_MEDIA_INFO_PAUSE);
-		GList *streams = purple_media_get_streams(media,
-				session_id, participant);
-		for (; streams; streams = g_list_delete_link(streams, streams)) {
-			PurpleMediaStream *stream = streams->data;
-			if (stream->session->type & PURPLE_MEDIA_SEND_VIDEO) {
-				stream->paused = active;
-
-				if (!stream->held)
-					g_object_set(stream->stream, "direction",
-							purple_media_to_fs_stream_direction(
-							stream->session->type & ((active) ?
-							~PURPLE_MEDIA_SEND_VIDEO :
-							PURPLE_MEDIA_VIDEO)), NULL);
-			}
-		}
-	} else if (local == TRUE && (type == PURPLE_MEDIA_INFO_HOLD ||
-			type == PURPLE_MEDIA_INFO_UNHOLD)) {
-		GList *streams;
-		gboolean active = (type == PURPLE_MEDIA_INFO_HOLD);
-
-		g_return_if_fail(PURPLE_IS_MEDIA(media));
-
-		streams = purple_media_get_streams(media,
-				session_id, participant);
-		for (; streams; streams = g_list_delete_link(streams, streams)) {
-			PurpleMediaStream *stream = streams->data;
-			stream->held = active;
-			if (stream->session->type & PURPLE_MEDIA_VIDEO) {
-				FsStreamDirection direction;
-
-				direction = ((active) ?
-						~PURPLE_MEDIA_VIDEO :
-						PURPLE_MEDIA_VIDEO);
-				if (!active && stream->paused)
-					direction &= ~PURPLE_MEDIA_SEND_VIDEO;
-
-				g_object_set(stream->stream, "direction",
-						purple_media_to_fs_stream_direction(
-						stream->session->type & direction), NULL);
-			} else if (stream->session->type & PURPLE_MEDIA_AUDIO) {
-				g_object_set(stream->stream, "direction",
-						purple_media_to_fs_stream_direction(
-						stream->session->type & ((active) ?
-						~PURPLE_MEDIA_AUDIO :
-						PURPLE_MEDIA_AUDIO)), NULL);
-			}
-		}
-	}
-
-	g_signal_emit(media, purple_media_signals[STREAM_INFO],
-			0, type, session_id, participant, local);
-
-	if (type == PURPLE_MEDIA_INFO_HANGUP ||
-			type == PURPLE_MEDIA_INFO_REJECT) {
-		purple_media_end(media, session_id, participant);
-	}
-#endif
-}
-
-#ifdef USE_VV
-static void
-purple_media_new_local_candidate_cb(FsStream *stream,
-				    FsCandidate *local_candidate,
-				    PurpleMediaSession *session)
-{
-	gchar *name;
-	FsParticipant *participant;
-	PurpleMediaCandidate *candidate;
-
-	g_return_if_fail(FS_IS_STREAM(stream));
-	g_return_if_fail(session != NULL);
-
-	purple_debug_info("media", "got new local candidate: %s\n", local_candidate->foundation);
-	g_object_get(stream, "participant", &participant, NULL);
-	g_object_get(participant, "cname", &name, NULL);
-	g_object_unref(participant);
-
-	purple_media_insert_local_candidate(session, name, fs_candidate_copy(local_candidate));
-
-	candidate = purple_media_candidate_from_fs(local_candidate);
-	g_signal_emit(session->media, purple_media_signals[NEW_CANDIDATE],
-		      0, session->id, name, candidate);
-	g_object_unref(candidate);
-
-	g_free(name);
-}
-
-static void
-purple_media_candidates_prepared_cb(FsStream *stream, PurpleMediaSession *session)
-{
-	gchar *name;
-	FsParticipant *participant;
-	PurpleMediaStream *stream_data;
-
-	g_return_if_fail(FS_IS_STREAM(stream));
-	g_return_if_fail(session != NULL);
-
-	g_object_get(stream, "participant", &participant, NULL);
-	g_object_get(participant, "cname", &name, NULL);
-	g_object_unref(participant);
-
-	stream_data = purple_media_get_stream(session->media, session->id, name);
-	stream_data->candidates_prepared = TRUE;
-
-	g_signal_emit(session->media,
-			purple_media_signals[CANDIDATES_PREPARED],
-			0, session->id, name);
-
-	g_free(name);
-}
-
-/* callback called when a pair of transport candidates (local and remote)
- * has been established */
-static void
-purple_media_candidate_pair_established_cb(FsStream *fsstream,
-					   FsCandidate *native_candidate,
-					   FsCandidate *remote_candidate,
-					   PurpleMediaSession *session)
-{
-	gchar *name;
-	FsParticipant *participant;
-	PurpleMediaStream *stream;
-	GList *iter;
-
-	g_return_if_fail(FS_IS_STREAM(fsstream));
-	g_return_if_fail(session != NULL);
-
-	g_object_get(fsstream, "participant", &participant, NULL);
-	g_object_get(participant, "cname", &name, NULL);
-	g_object_unref(participant);
-
-	stream = purple_media_get_stream(session->media, session->id, name);
-
-	iter = stream->active_local_candidates;
-	for(; iter; iter = g_list_next(iter)) {
-		FsCandidate *c = iter->data;
-		if (native_candidate->component_id == c->component_id) {
-			fs_candidate_destroy(c);
-			stream->active_local_candidates =
-					g_list_delete_link(iter, iter);
-			stream->active_local_candidates = g_list_prepend(
-					stream->active_local_candidates,
-					fs_candidate_copy(native_candidate));
-			break;
-		}
-	}
-	if (iter == NULL)
-		stream->active_local_candidates = g_list_prepend(
-				stream->active_local_candidates,
-				fs_candidate_copy(native_candidate));
-
-	iter = stream->active_remote_candidates;
-	for(; iter; iter = g_list_next(iter)) {
-		FsCandidate *c = iter->data;
-		if (native_candidate->component_id == c->component_id) {
-			fs_candidate_destroy(c);
-			stream->active_remote_candidates =
-					g_list_delete_link(iter, iter);
-			stream->active_remote_candidates = g_list_prepend(
-					stream->active_remote_candidates,
-					fs_candidate_copy(remote_candidate));
-			break;
-		}
-	}
-	if (iter == NULL)
-		stream->active_remote_candidates = g_list_prepend(
-				stream->active_remote_candidates,
-				fs_candidate_copy(remote_candidate));
-
-	purple_debug_info("media", "candidate pair established\n");
-}
-
-static gboolean
-purple_media_connected_cb(PurpleMediaStream *stream)
-{
-	g_return_val_if_fail(stream != NULL, FALSE);
-
-	stream->connected_cb_id = 0;
-
-	purple_media_manager_create_output_window(
-			stream->session->media->priv->manager,
-			stream->session->media,
-			stream->session->id, stream->participant);
-
-	g_signal_emit(stream->session->media,
-			purple_media_signals[STATE_CHANGED],
-			0, PURPLE_MEDIA_STATE_CONNECTED,
-			stream->session->id, stream->participant);
-	return FALSE;
-}
-
-static void
-purple_media_src_pad_added_cb(FsStream *fsstream, GstPad *srcpad,
-			      FsCodec *codec, PurpleMediaStream *stream)
-{
-	PurpleMediaPrivate *priv;
-	GstPad *sinkpad;
-
-	g_return_if_fail(FS_IS_STREAM(fsstream));
-	g_return_if_fail(stream != NULL);
-
-	priv = stream->session->media->priv;
-
-	if (stream->src == NULL) {
-		GstElement *sink = NULL;
-
-		if (codec->media_type == FS_MEDIA_TYPE_AUDIO) {
-			GstElement *queue = NULL;
-			double output_volume = purple_prefs_get_int(
-					"/purple/media/audio/volume/output")/10.0;
-			/*
-			 * Should this instead be:
-			 *  audioconvert ! audioresample ! liveadder !
-			 *   audioresample ! audioconvert ! realsink
-			 */
-			queue = gst_element_factory_make("queue", NULL);
-			stream->volume = gst_element_factory_make(
-					"volume", NULL);
-			g_object_set(stream->volume, "volume",
-					output_volume, NULL);
-			stream->level = gst_element_factory_make(
-					"level", NULL);
-			stream->src = gst_element_factory_make(
-					"liveadder", NULL);
-			sink = purple_media_manager_get_element(priv->manager,
-					PURPLE_MEDIA_RECV_AUDIO,
-					stream->session->media,
-					stream->session->id,
-					stream->participant);
-			gst_bin_add(GST_BIN(priv->confbin), queue);
-			gst_bin_add(GST_BIN(priv->confbin), stream->volume);
-			gst_bin_add(GST_BIN(priv->confbin), stream->level);
-			gst_bin_add(GST_BIN(priv->confbin), sink);
-			gst_element_set_state(sink, GST_STATE_PLAYING);
-			gst_element_set_state(stream->level, GST_STATE_PLAYING);
-			gst_element_set_state(stream->volume, GST_STATE_PLAYING);
-			gst_element_set_state(queue, GST_STATE_PLAYING);
-			gst_element_link(stream->level, sink);
-			gst_element_link(stream->volume, stream->level);
-			gst_element_link(queue, stream->volume);
-			sink = queue;
-		} else if (codec->media_type == FS_MEDIA_TYPE_VIDEO) {
-			stream->src = gst_element_factory_make(
-					"fsfunnel", NULL);
-			sink = gst_element_factory_make(
-					"fakesink", NULL);
-			g_object_set(G_OBJECT(sink), "async", FALSE, NULL);
-			gst_bin_add(GST_BIN(priv->confbin), sink);
-			gst_element_set_state(sink, GST_STATE_PLAYING);
-		}
-		stream->tee = gst_element_factory_make("tee", NULL);
-		gst_bin_add_many(GST_BIN(priv->confbin),
-				stream->src, stream->tee, NULL);
-		gst_element_set_state(stream->tee, GST_STATE_PLAYING);
-		gst_element_set_state(stream->src, GST_STATE_PLAYING);
-		gst_element_link_many(stream->src, stream->tee, sink, NULL);
-	}
-
-	sinkpad = gst_element_get_request_pad(stream->src, "sink%d");
-	gst_pad_link(srcpad, sinkpad);
-	gst_object_unref(sinkpad);
-
-	stream->connected_cb_id = purple_timeout_add(0,
-			(GSourceFunc)purple_media_connected_cb, stream);
-}
-
-static void
-purple_media_element_added_cb(FsElementAddedNotifier *self,
-		GstBin *bin, GstElement *element, gpointer user_data)
-{
-	/*
-	 * Hack to make H264 work with Gmail video.
-	 */
-	if (!strncmp(GST_ELEMENT_NAME(element), "x264", 4)) {
-		g_object_set(GST_OBJECT(element), "cabac", FALSE, NULL);
-	}
-}
-#endif  /* USE_VV */
-
-gboolean
-purple_media_add_stream(PurpleMedia *media, const gchar *sess_id,
-		const gchar *who, PurpleMediaSessionType type,
-		gboolean initiator, const gchar *transmitter,
-		guint num_params, GParameter *params)
-{
-#ifdef USE_VV
-	PurpleMediaSession *session;
-	FsParticipant *participant = NULL;
-	PurpleMediaStream *stream = NULL;
-	FsMediaType media_type = purple_media_to_fs_media_type(type);
-	FsStreamDirection type_direction =
-			purple_media_to_fs_stream_direction(type);
-	gboolean is_nice = !strcmp(transmitter, "nice");
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-
-	session = purple_media_get_session(media, sess_id);
-
-	if (!session) {
-		GError *err = NULL;
-		GList *codec_conf = NULL, *iter = NULL;
-		gchar *filename = NULL;
-		PurpleMediaSessionType session_type;
-		GstElement *src = NULL;
-
-		session = g_new0(PurpleMediaSession, 1);
-
-		session->session = fs_conference_new_session(
-				media->priv->conference, media_type, &err);
-
-		if (err != NULL) {
-			purple_media_error(media, _("Error creating session: %s"), err->message);
-			g_error_free(err);
-			g_free(session);
-			return FALSE;
-		}
-
-		filename = g_build_filename(purple_user_dir(), "fs-codec.conf", NULL);
-		codec_conf = fs_codec_list_from_keyfile(filename, &err);
-		g_free(filename);
-
-		if (err != NULL) {
-			if (err->code == 4)
-				purple_debug_info("media", "Couldn't read "
-						"fs-codec.conf: %s\n",
-						err->message);
-			else
-				purple_debug_error("media", "Error reading "
-						"fs-codec.conf: %s\n",
-						err->message);
-			g_error_free(err);
-		}
-
-		/*
-		 * Add SPEEX if the configuration file doesn't exist or
-		 * there isn't a speex entry.
-		 */
-		for (iter = codec_conf; iter; iter = g_list_next(iter)) {
-			FsCodec *codec = iter->data;
-			if (!g_ascii_strcasecmp(codec->encoding_name, "speex"))
-				break;
-		}
-
-		if (iter == NULL) {
-			codec_conf = g_list_prepend(codec_conf,
-					fs_codec_new(FS_CODEC_ID_ANY,
-					"SPEEX", FS_MEDIA_TYPE_AUDIO, 8000));
-			codec_conf = g_list_prepend(codec_conf,
-					fs_codec_new(FS_CODEC_ID_ANY,
-					"SPEEX", FS_MEDIA_TYPE_AUDIO, 16000));
-		}
-
-		fs_session_set_codec_preferences(session->session, codec_conf, NULL);
-
-		/*
-		 * Removes a 5-7 second delay before
-		 * receiving the src-pad-added signal.
-		 * Only works for non-multicast FsRtpSessions.
-		 */
-		if (is_nice || !strcmp(transmitter, "rawudp"))
-			g_object_set(G_OBJECT(session->session),
-					"no-rtcp-timeout", 0, NULL);
-
-		/*
-		 * Hack to make x264 work with Gmail video.
-		 */
-		if (is_nice && !strcmp(sess_id, "google-video")) {
-			FsElementAddedNotifier *notifier =
-					fs_element_added_notifier_new();
-			g_signal_connect(G_OBJECT(notifier), "element-added",
-					G_CALLBACK(purple_media_element_added_cb),
-					stream);
-			fs_element_added_notifier_add(notifier,
-					GST_BIN(media->priv->conference));
-		}
-
-		fs_codec_list_destroy(codec_conf);
-
-		session->id = g_strdup(sess_id);
-		session->media = media;
-		session->type = type;
-		session->initiator = initiator;
-
-		purple_media_add_session(media, session);
-		g_signal_emit(media, purple_media_signals[STATE_CHANGED],
-				0, PURPLE_MEDIA_STATE_NEW,
-				session->id, NULL);
-
-		if (type_direction & FS_DIRECTION_SEND) {
-			session_type = purple_media_from_fs(media_type,
-					FS_DIRECTION_SEND);
-			src = purple_media_manager_get_element(
-					media->priv->manager, session_type,
-					media, session->id, who);
-			if (!GST_IS_ELEMENT(src)) {
-				purple_debug_error("media",
-						"Error creating src for session %s\n",
-						session->id);
-				purple_media_end(media, session->id, NULL);
-				return FALSE;
-			}
-
-			purple_media_set_src(media, session->id, src);
-			gst_element_set_state(session->src, GST_STATE_PLAYING);
-			purple_media_manager_create_output_window(
-					media->priv->manager,
-					session->media,
-					session->id, NULL);
-		}
-	}
-
-	if (!(participant = purple_media_add_participant(media, who))) {
-		purple_media_remove_session(media, session);
-		g_free(session);
-		return FALSE;
-	} else {
-		g_signal_emit(media, purple_media_signals[STATE_CHANGED],
-				0, PURPLE_MEDIA_STATE_NEW,
-				NULL, who);
-	}
-
-	stream = purple_media_get_stream(media, sess_id, who);
-
-	if (!stream) {
-		GError *err = NULL;
-		FsStream *fsstream = NULL;
-		const gchar *stun_ip = purple_network_get_stun_ip();
-		const gchar *turn_ip = purple_network_get_turn_ip();
-		guint new_num_params =
-					!stun_ip && !turn_ip ? num_params + 1 :
-					(stun_ip && is_nice) && turn_ip ?
-					num_params + 3 : num_params + 2;
-		guint next_param_index = num_params;
-		GParameter *param = g_new0(GParameter, new_num_params);
-		memcpy(param, params, sizeof(GParameter) * num_params);
-
-		/* set controlling mode according to direction */
-		param[next_param_index].name = "controlling-mode";
-		g_value_init(&param[next_param_index].value, G_TYPE_BOOLEAN);
-		g_value_set_boolean(&param[next_param_index].value, initiator);
-		next_param_index++;
-		
-		if (stun_ip || turn_ip) {
-			if (stun_ip) {
-				purple_debug_info("media", 
-					"setting property stun-ip on new stream: %s\n", stun_ip);
-
-				param[next_param_index].name = "stun-ip";
-				g_value_init(&param[next_param_index].value, G_TYPE_STRING);
-				g_value_set_string(&param[next_param_index].value, stun_ip);
-				next_param_index++;
-			}
-
-			if (turn_ip && is_nice) {
-				GValueArray *relay_info = g_value_array_new(0);
-				GValue value;
-				gint turn_port = 
-					purple_prefs_get_int("/purple/network/turn_port");
-				const gchar *username =
-					purple_prefs_get_string("/purple/network/turn_username");
-				const gchar *password =
-					purple_prefs_get_string("/purple/network/turn_password");
-				GstStructure *turn_setup = gst_structure_new("relay-info",
-					"ip", G_TYPE_STRING, turn_ip, 
-					"port", G_TYPE_UINT, turn_port,
-					"username", G_TYPE_STRING, username,
-					"password", G_TYPE_STRING, password,
-					NULL);
-
-				if (turn_setup) {
-					memset(&value, 0, sizeof(GValue));
-					g_value_init(&value, GST_TYPE_STRUCTURE);
-					gst_value_set_structure(&value, turn_setup);
-					relay_info = g_value_array_append(relay_info, &value);
-					gst_structure_free(turn_setup);
-
-					purple_debug_info("media",
-						"setting property relay-info on new stream\n");
-					param[next_param_index].name = "relay-info";
-					g_value_init(&param[next_param_index].value, 
-						G_TYPE_VALUE_ARRAY);
-					g_value_set_boxed(&param[next_param_index].value,
-						relay_info);
-					g_value_array_free(relay_info);
-				} else {
-					purple_debug_error("media", "Error relay info");
-					g_object_unref(participant);
-					g_hash_table_remove(media->priv->participants, who);
-					purple_media_remove_session(media, session);
-					g_free(session);
-					return FALSE;
-				}
-			}
-		}
-
-		fsstream = fs_session_new_stream(session->session,
-					participant, initiator == TRUE ?
-					type_direction : (type_direction &
-					FS_DIRECTION_RECV), transmitter,
-					new_num_params, param, &err);
-		g_free(param);
-
-		if (fsstream == NULL) {
-			purple_debug_error("media",
-					"Error creating stream: %s\n",
-					err && err->message ?
-					err->message : "NULL");
-			if (err)
-				g_error_free(err);
-			g_object_unref(participant);
-			g_hash_table_remove(media->priv->participants, who);
-			purple_media_remove_session(media, session);
-			g_free(session);
-			return FALSE;
-		}
-
-		stream = purple_media_insert_stream(session, who, fsstream);
-		stream->initiator = initiator;
-
-		/* callback for source pad added (new stream source ready) */
-		g_signal_connect(G_OBJECT(fsstream),
-				 "src-pad-added", G_CALLBACK(purple_media_src_pad_added_cb), stream);
-
-		g_signal_emit(media, purple_media_signals[STATE_CHANGED],
-				0, PURPLE_MEDIA_STATE_NEW,
-				session->id, who);
-	} else {
-		if (purple_media_to_fs_stream_direction(stream->session->type)
-				!= type_direction) {
-			/* change direction */
-			g_object_set(stream->stream, "direction",
-					type_direction, NULL);
-		}
-	}
-
-	return TRUE;
-#else
-	return FALSE;
-#endif  /* USE_VV */
-}
-
-PurpleMediaManager *
-purple_media_get_manager(PurpleMedia *media)
-{
-	PurpleMediaManager *ret;
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-	g_object_get(media, "manager", &ret, NULL);
-	return ret;
-}
-
-PurpleMediaSessionType
-purple_media_get_session_type(PurpleMedia *media, const gchar *sess_id)
-{
-#ifdef USE_VV
-	PurpleMediaSession *session;
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), PURPLE_MEDIA_NONE);
-	session = purple_media_get_session(media, sess_id);
-	return session->type;
-#else
-	return PURPLE_MEDIA_NONE;
-#endif
-}
-/* XXX: Should wait until codecs-ready is TRUE before using this function */
-GList *
-purple_media_get_codecs(PurpleMedia *media, const gchar *sess_id)
-{
-#ifdef USE_VV
-	GList *fscodecs;
-	GList *codecs;
-	PurpleMediaSession *session;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-
-	session = purple_media_get_session(media, sess_id);
-
-	if (session == NULL)
-		return NULL;
-
-	g_object_get(G_OBJECT(session->session),
-		     "codecs", &fscodecs, NULL);
-	codecs = purple_media_codec_list_from_fs(fscodecs);
-	fs_codec_list_destroy(fscodecs);
-	return codecs;
-#else
-	return NULL;
-#endif
-}
-
-GList *
-purple_media_get_local_candidates(PurpleMedia *media, const gchar *sess_id,
-                                  const gchar *participant)
-{
-#ifdef USE_VV
-	PurpleMediaStream *stream;
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-	stream = purple_media_get_stream(media, sess_id, participant);
-	return stream ? purple_media_candidate_list_from_fs(
-			stream->local_candidates) : NULL;
-#else
-	return NULL;
-#endif
-}
-
-void
-purple_media_add_remote_candidates(PurpleMedia *media, const gchar *sess_id,
-                                   const gchar *participant,
-                                   GList *remote_candidates)
-{
-#ifdef USE_VV
-	PurpleMediaStream *stream;
-	GError *err = NULL;
-
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-	stream = purple_media_get_stream(media, sess_id, participant);
-
-	if (stream == NULL) {
-		purple_debug_error("media",
-				"purple_media_add_remote_candidates: "
-				"couldn't find stream %s %s.\n",
-				sess_id ? sess_id : "(null)",
-				participant ? participant : "(null)");
-		return;
-	}
-
-	stream->remote_candidates = g_list_concat(stream->remote_candidates,
-			purple_media_candidate_list_to_fs(remote_candidates));
-
-	if (stream->initiator == TRUE || stream->accepted == TRUE) {
-		fs_stream_set_remote_candidates(stream->stream,
-				stream->remote_candidates, &err);
-
-		if (err) {
-			purple_debug_error("media", "Error adding remote"
-					" candidates: %s\n", err->message);
-			g_error_free(err);
-		}
-	}
-#endif
-}
-
-#if 0
-/*
- * These two functions aren't being used and I'd rather not lock in the API
- * until they are needed. If they ever are.
- */
-
-GList *
-purple_media_get_active_local_candidates(PurpleMedia *media,
-		const gchar *sess_id, const gchar *participant)
-{
-#ifdef USE_VV
-	PurpleMediaStream *stream;
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-	stream = purple_media_get_stream(media, sess_id, participant);
-	return purple_media_candidate_list_from_fs(
-			stream->active_local_candidates);
-#else
-	return NULL;
-#endif
-}
-
-GList *
-purple_media_get_active_remote_candidates(PurpleMedia *media,
-		const gchar *sess_id, const gchar *participant)
-{
-#ifdef USE_VV
-	PurpleMediaStream *stream;
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-	stream = purple_media_get_stream(media, sess_id, participant);
-	return purple_media_candidate_list_from_fs(
-			stream->active_remote_candidates);
-#else
-	return NULL;
-#endif
-}
-#endif
-
-gboolean
-purple_media_set_remote_codecs(PurpleMedia *media, const gchar *sess_id,
-                               const gchar *participant, GList *codecs)
-{
-#ifdef USE_VV
-	PurpleMediaStream *stream;
-	FsStream *fsstream;
-	GList *fscodecs;
-	GError *err = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-	stream = purple_media_get_stream(media, sess_id, participant);
-
-	if (stream == NULL)
-		return FALSE;
-
-	fsstream = stream->stream;
-	fscodecs = purple_media_codec_list_to_fs(codecs);
-	fs_stream_set_remote_codecs(fsstream, fscodecs, &err);
-	fs_codec_list_destroy(fscodecs);
-
-	if (err) {
-		purple_debug_error("media", "Error setting remote codecs: %s\n",
-				   err->message);
-		g_error_free(err);
-		return FALSE;
-	}
-	return TRUE;
-#else
-	return FALSE;
-#endif
-}
-
-gboolean
-purple_media_candidates_prepared(PurpleMedia *media,
-		const gchar *session_id, const gchar *participant)
-{
-#ifdef USE_VV
-	GList *streams;
-	gboolean prepared = TRUE;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-
-	streams = purple_media_get_streams(media, session_id, participant);
-
-	for (; streams; streams = g_list_delete_link(streams, streams)) {
-		PurpleMediaStream *stream = streams->data;
-		if (stream->candidates_prepared == FALSE) {
-			g_list_free(streams);
-			prepared = FALSE;
-			break;
-		}
-	}
-
-	return prepared;
-#else
-	return FALSE;
-#endif
-}
-
-gboolean
-purple_media_set_send_codec(PurpleMedia *media, const gchar *sess_id, PurpleMediaCodec *codec)
-{
-#ifdef USE_VV
-	PurpleMediaSession *session;
-	FsCodec *fscodec;
-	GError *err = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-
-	session = purple_media_get_session(media, sess_id);
-
-	if (session != NULL)
-		return FALSE;
-
-	fscodec = purple_media_codec_to_fs(codec);
-	fs_session_set_send_codec(session->session, fscodec, &err);
-	fs_codec_destroy(fscodec);
-
-	if (err) {
-		purple_debug_error("media", "Error setting send codec\n");
-		g_error_free(err);
-		return FALSE;
-	}
-	return TRUE;
-#else
-	return FALSE;
-#endif
-}
-
-gboolean
-purple_media_codecs_ready(PurpleMedia *media, const gchar *sess_id)
-{
-#ifdef USE_VV
-	gboolean ret;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-
-	if (sess_id != NULL) {
-		PurpleMediaSession *session;
-		session = purple_media_get_session(media, sess_id);
-
-		if (session == NULL)
-			return FALSE;
-		if (session->type & (PURPLE_MEDIA_SEND_AUDIO |
-				PURPLE_MEDIA_SEND_VIDEO))
-			g_object_get(session->session,
-					"codecs-ready", &ret, NULL);
-		else
-			ret = TRUE;
-	} else {
-		GList *values = g_hash_table_get_values(media->priv->sessions);
-		for (; values; values = g_list_delete_link(values, values)) {
-			PurpleMediaSession *session = values->data;
-			if (session->type & (PURPLE_MEDIA_SEND_AUDIO |
-					PURPLE_MEDIA_SEND_VIDEO))
-				g_object_get(session->session,
-						"codecs-ready", &ret, NULL);
-			else
-				ret = TRUE;
-
-			if (ret == FALSE)
-				break;
-		}
-		if (values != NULL)
-			g_list_free(values);
-	}
-	return ret;
-#else
-	return FALSE;
-#endif
-}
-
-gboolean
-purple_media_is_initiator(PurpleMedia *media,
-		const gchar *sess_id, const gchar *participant)
-{
-#ifdef USE_VV
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-
-	if (sess_id == NULL && participant == NULL)
-		return media->priv->initiator;
-	else if (sess_id != NULL && participant == NULL) {
-		PurpleMediaSession *session =
-				purple_media_get_session(media, sess_id);
-		return session != NULL ? session->initiator : FALSE;
-	} else if (sess_id != NULL && participant != NULL) {
-		PurpleMediaStream *stream = purple_media_get_stream(
-				media, sess_id, participant);
-		return stream != NULL ? stream->initiator : FALSE;
-	}
-#endif
-	return FALSE;
-}
-
-gboolean
-purple_media_accepted(PurpleMedia *media, const gchar *sess_id,
-		const gchar *participant)
-{
-#ifdef USE_VV
-	gboolean accepted = TRUE;
-
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-
-	if (sess_id == NULL && participant == NULL) {
-		GList *streams = media->priv->streams;
-
-		for (; streams; streams = g_list_next(streams)) {
-			PurpleMediaStream *stream = streams->data;
-			if (stream->accepted == FALSE) {
-				accepted = FALSE;
-				break;
-			}
-		}
-	} else if (sess_id != NULL && participant == NULL) {
-		GList *streams = purple_media_get_streams(
-				media, sess_id, NULL);
-		for (; streams; streams =
-				g_list_delete_link(streams, streams)) {
-			PurpleMediaStream *stream = streams->data;
-			if (stream->accepted == FALSE) {
-				g_list_free(streams);
-				accepted = FALSE;
-				break;
-			}
-		}
-	} else if (sess_id != NULL && participant != NULL) {
-		PurpleMediaStream *stream = purple_media_get_stream(
-				media, sess_id, participant);
-		if (stream == NULL || stream->accepted == FALSE)
-			accepted = FALSE;
-	}
-
-	return accepted;
-#else
-	return FALSE;
-#endif
-}
-
-void purple_media_set_input_volume(PurpleMedia *media,
-		const gchar *session_id, double level)
-{
-#ifdef USE_VV
-	GList *sessions;
-
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-
-	purple_prefs_set_int("/purple/media/audio/volume/input", level);
-
-	if (session_id == NULL)
-		sessions = g_hash_table_get_values(media->priv->sessions);
-	else
-		sessions = g_list_append(NULL,
-				purple_media_get_session(media, session_id));
-
-	for (; sessions; sessions = g_list_delete_link(sessions, sessions)) {
-		PurpleMediaSession *session = sessions->data;
-
-		if (session->type & PURPLE_MEDIA_SEND_AUDIO) {
-			gchar *name = g_strdup_printf("volume_%s",
-					session->id);
-			GstElement *volume = gst_bin_get_by_name(
-					GST_BIN(session->media->priv->confbin),
-					name);
-			g_free(name);
-			g_object_set(volume, "volume", level/10.0, NULL);
-		}
-	}
-#endif
-}
-
-void purple_media_set_output_volume(PurpleMedia *media,
-		const gchar *session_id, const gchar *participant,
-		double level)
-{
-#ifdef USE_VV
-	GList *streams;
-
-	g_return_if_fail(PURPLE_IS_MEDIA(media));
-
-	purple_prefs_set_int("/purple/media/audio/volume/output", level);
-
-	streams = purple_media_get_streams(media,
-			session_id, participant);
-
-	for (; streams; streams = g_list_delete_link(streams, streams)) {
-		PurpleMediaStream *stream = streams->data;
-
-		if (stream->session->type & PURPLE_MEDIA_RECV_AUDIO
-				&& GST_IS_ELEMENT(stream->volume)) {
-			g_object_set(stream->volume, "volume", level/10.0, NULL);
-		}
-	}
-#endif
-}
-
-gulong
-purple_media_set_output_window(PurpleMedia *media, const gchar *session_id,
-		const gchar *participant, gulong window_id)
-{
-#ifdef USE_VV
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
-
-	return purple_media_manager_set_output_window(media->priv->manager,
-			media, session_id, participant, window_id);
-#else
-	return 0;
-#endif
-}
-
-void
-purple_media_remove_output_windows(PurpleMedia *media)
-{
-#ifdef USE_VV
-	GList *iter = media->priv->streams;
-	for (; iter; iter = g_list_next(iter)) {
-		PurpleMediaStream *stream = iter->data;
-		purple_media_manager_remove_output_windows(
-				media->priv->manager, media,
-				stream->session->id, stream->participant);
-	}
-
-	iter = purple_media_get_session_ids(media);
-	for (; iter; iter = g_list_delete_link(iter, iter)) {
-		gchar *session_name = iter->data;
-		purple_media_manager_remove_output_windows(
-				media->priv->manager, media,
-				session_name, NULL);
-	}
-#endif
-}
-
-#ifdef USE_GSTREAMER
-GstElement *
-purple_media_get_tee(PurpleMedia *media,
-		const gchar *session_id, const gchar *participant)
-{
-#ifdef USE_VV
-	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
-
-	if (session_id != NULL && participant == NULL) {
-		PurpleMediaSession *session =
-				purple_media_get_session(media, session_id);
-		return (session != NULL) ? session->tee : NULL;
-	} else if (session_id != NULL && participant != NULL) {
-		PurpleMediaStream *stream =
-				purple_media_get_stream(media,
-				session_id, participant);
-		return (stream != NULL) ? stream->tee : NULL;
-	}
-	g_return_val_if_reached(NULL);
-#else
-	return NULL;
-#endif
-}
-#endif /* USE_GSTREAMER */
-
--- a/libpurple/media.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/media.h	Thu Feb 04 05:30:35 2010 +0000
@@ -27,26 +27,15 @@
 #ifndef _PURPLE_MEDIA_H_
 #define _PURPLE_MEDIA_H_
 
+#include "media/candidate.h"
+#include "media/codec.h"
+#include "media/enum-types.h"
+
 #include <glib.h>
 #include <glib-object.h>
 
 G_BEGIN_DECLS
 
-#define PURPLE_TYPE_MEDIA_CANDIDATE           (purple_media_candidate_get_type())
-#define PURPLE_MEDIA_CANDIDATE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_MEDIA_CANDIDATE, PurpleMediaCandidate))
-#define PURPLE_MEDIA_CANDIDATE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_MEDIA_CANDIDATE, PurpleMediaCandidate))
-#define PURPLE_IS_MEDIA_CANDIDATE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_MEDIA_CANDIDATE))
-#define PURPLE_IS_MEDIA_CANDIDATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_MEDIA_CANDIDATE))
-#define PURPLE_MEDIA_CANDIDATE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_MEDIA_CANDIDATE, PurpleMediaCandidate))
-
-#define PURPLE_TYPE_MEDIA_CODEC           (purple_media_codec_get_type())
-#define PURPLE_MEDIA_CODEC(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_MEDIA_CODEC, PurpleMediaCodec))
-#define PURPLE_MEDIA_CODEC_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_MEDIA_CODEC, PurpleMediaCodec))
-#define PURPLE_IS_MEDIA_CODEC(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_MEDIA_CODEC))
-#define PURPLE_IS_MEDIA_CODEC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_MEDIA_CODEC))
-#define PURPLE_MEDIA_CODEC_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_MEDIA_CODEC, PurpleMediaCodec))
-
-#define PURPLE_TYPE_MEDIA_SESSION_TYPE (purple_media_session_type_get_type())
 #define PURPLE_TYPE_MEDIA            (purple_media_get_type())
 #define PURPLE_MEDIA(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_MEDIA, PurpleMedia))
 #define PURPLE_MEDIA_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_MEDIA, PurpleMediaClass))
@@ -54,79 +43,8 @@
 #define PURPLE_IS_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_MEDIA))
 #define PURPLE_MEDIA_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_MEDIA, PurpleMediaClass))
 
-#define PURPLE_TYPE_MEDIA_CANDIDATE_TYPE (purple_media_candidate_type_get_type())
-#define PURPLE_TYPE_MEDIA_NETWORK_PROTOCOL (purple_media_network_protocol_get_type())
-#define PURPLE_MEDIA_TYPE_STATE      (purple_media_state_changed_get_type())
-#define PURPLE_MEDIA_TYPE_INFO_TYPE	(purple_media_info_type_get_type())
-
 /** An opaque structure representing a media call. */
 typedef struct _PurpleMedia PurpleMedia;
-/** An opaque structure representing a network candidate (IP Address and port pair). */
-typedef struct _PurpleMediaCandidate PurpleMediaCandidate;
-/** An opaque structure representing an audio or video codec. */
-typedef struct _PurpleMediaCodec PurpleMediaCodec;
-
-/** Media caps */
-typedef enum {
-	PURPLE_MEDIA_CAPS_NONE = 0,
-	PURPLE_MEDIA_CAPS_AUDIO = 1,
-	PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION = 1 << 1,
-	PURPLE_MEDIA_CAPS_VIDEO = 1 << 2,
-	PURPLE_MEDIA_CAPS_VIDEO_SINGLE_DIRECTION = 1 << 3,
-	PURPLE_MEDIA_CAPS_AUDIO_VIDEO = 1 << 4,
-	PURPLE_MEDIA_CAPS_MODIFY_SESSION = 1 << 5,
-	PURPLE_MEDIA_CAPS_CHANGE_DIRECTION = 1 << 6
-} PurpleMediaCaps;
-
-/** Media session types */
-typedef enum {
-	PURPLE_MEDIA_NONE	= 0,
-	PURPLE_MEDIA_RECV_AUDIO = 1 << 0,
-	PURPLE_MEDIA_SEND_AUDIO = 1 << 1,
-	PURPLE_MEDIA_RECV_VIDEO = 1 << 2,
-	PURPLE_MEDIA_SEND_VIDEO = 1 << 3,
-	PURPLE_MEDIA_AUDIO = PURPLE_MEDIA_RECV_AUDIO | PURPLE_MEDIA_SEND_AUDIO,
-	PURPLE_MEDIA_VIDEO = PURPLE_MEDIA_RECV_VIDEO | PURPLE_MEDIA_SEND_VIDEO
-} PurpleMediaSessionType;
-
-/** Media state-changed types */
-typedef enum {
-	PURPLE_MEDIA_STATE_NEW = 0,
-	PURPLE_MEDIA_STATE_CONNECTED,
-	PURPLE_MEDIA_STATE_END
-} PurpleMediaState;
-
-/** Media info types */
-typedef enum {
-	PURPLE_MEDIA_INFO_HANGUP = 0,
-	PURPLE_MEDIA_INFO_ACCEPT,
-	PURPLE_MEDIA_INFO_REJECT,
-	PURPLE_MEDIA_INFO_MUTE,
-	PURPLE_MEDIA_INFO_UNMUTE,
-	PURPLE_MEDIA_INFO_PAUSE,
-	PURPLE_MEDIA_INFO_UNPAUSE,
-	PURPLE_MEDIA_INFO_HOLD,
-	PURPLE_MEDIA_INFO_UNHOLD
-} PurpleMediaInfoType;
-
-typedef enum {
-	PURPLE_MEDIA_CANDIDATE_TYPE_HOST,
-	PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX,
-	PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX,
-	PURPLE_MEDIA_CANDIDATE_TYPE_RELAY,
-	PURPLE_MEDIA_CANDIDATE_TYPE_MULTICAST
-} PurpleMediaCandidateType;
-
-typedef enum {
-	PURPLE_MEDIA_COMPONENT_NONE = 0,
-	PURPLE_MEDIA_COMPONENT_RTP = 1,
-	PURPLE_MEDIA_COMPONENT_RTCP = 2
-} PurpleMediaComponentType;
-
-typedef enum {
-	PURPLE_MEDIA_NETWORK_PROTOCOL_UDP,
-	PURPLE_MEDIA_NETWORK_PROTOCOL_TCP
-} PurpleMediaNetworkProtocol;
 
 #include "signals.h"
 #include "util.h"
@@ -136,33 +54,6 @@
 #endif
 
 /**
- * Gets the media session type's GType
- *
- * @return The media session type's GType.
- *
- * @since 2.6.0
- */
-GType purple_media_session_type_get_type(void);
-
-/**
- * Gets the media candidate type's GType
- *
- * @return The media candidate type's GType.
- *
- * @since 2.6.0
- */
-GType purple_media_candidate_type_get_type(void);
-
-/**
- * Gets the media network protocol's GType
- *
- * @return The media network protocol's GType.
- *
- * @since 2.6.0
- */
-GType purple_media_network_protocol_get_type(void);
-
-/**
  * Gets the media class's GType
  *
  * @return The media class's GType.
@@ -172,187 +63,6 @@
 GType purple_media_get_type(void);
 
 /**
- * Gets the type of the state-changed enum
- *
- * @return The state-changed enum's GType
- *
- * @since 2.6.0
- */
-GType purple_media_state_changed_get_type(void);
-
-/**
- * Gets the type of the info type enum
- *
- * @return The info type enum's GType
- *
- * @since 2.6.0
- */
-GType purple_media_info_type_get_type(void);
-
-/**
- * Gets the type of the media candidate structure.
- *
- * @return The media canditate's GType
- *
- * @since 2.6.0
- */
-GType purple_media_candidate_get_type(void);
-
-/**
- * Creates a PurpleMediaCandidate instance.
- *
- * @param foundation The foundation of the candidate.
- * @param component_id The component this candidate is for.
- * @param type The type of candidate.
- * @param proto The protocol this component is for.
- * @param ip The IP address of this component.
- * @param port The network port.
- *
- * @return The newly created PurpleMediaCandidate instance.
- *
- * @since 2.6.0
- */
-PurpleMediaCandidate *purple_media_candidate_new(
-		const gchar *foundation, guint component_id,
-		PurpleMediaCandidateType type,
-		PurpleMediaNetworkProtocol proto,
-		const gchar *ip, guint port);
-
-/**
- * Copies a GList of PurpleMediaCandidate and its contents.
- *
- * @param candidates The list of candidates to be copied.
- *
- * @return The copy of the GList.
- *
- * @since 2.6.0
- */
-GList *purple_media_candidate_list_copy(GList *candidates);
-
-/**
- * Frees a GList of PurpleMediaCandidate and its contents.
- *
- * @param candidates The list of candidates to be freed.
- *
- * @since 2.6.0
- */
-void purple_media_candidate_list_free(GList *candidates);
-
-gchar *purple_media_candidate_get_foundation(PurpleMediaCandidate *candidate);
-guint purple_media_candidate_get_component_id(PurpleMediaCandidate *candidate);
-gchar *purple_media_candidate_get_ip(PurpleMediaCandidate *candidate);
-guint16 purple_media_candidate_get_port(PurpleMediaCandidate *candidate);
-gchar *purple_media_candidate_get_base_ip(PurpleMediaCandidate *candidate);
-guint16 purple_media_candidate_get_base_port(PurpleMediaCandidate *candidate);
-PurpleMediaNetworkProtocol purple_media_candidate_get_protocol(
-		PurpleMediaCandidate *candidate);
-guint32 purple_media_candidate_get_priority(PurpleMediaCandidate *candidate);
-PurpleMediaCandidateType purple_media_candidate_get_candidate_type(
-		PurpleMediaCandidate *candidate);
-gchar *purple_media_candidate_get_username(PurpleMediaCandidate *candidate);
-gchar *purple_media_candidate_get_password(PurpleMediaCandidate *candidate);
-guint purple_media_candidate_get_ttl(PurpleMediaCandidate *candidate);
-
-/**
- * Gets the type of the media codec structure.
- *
- * @return The media codec's GType
- *
- * @since 2.6.0
- */
-GType purple_media_codec_get_type(void);
-
-/**
- * Creates a new PurpleMediaCodec instance.
- *
- * @param id Codec identifier.
- * @param encoding_name Name of the media type this encodes.
- * @param media_type PurpleMediaSessionType of this codec.
- * @param clock_rate The clock rate this codec encodes at, if applicable.
- *
- * @return The newly created PurpleMediaCodec.
- *
- * @since 2.6.0
- */
-PurpleMediaCodec *purple_media_codec_new(int id, const char *encoding_name,
-		PurpleMediaSessionType media_type, guint clock_rate);
-
-guint purple_media_codec_get_id(PurpleMediaCodec *codec);
-gchar *purple_media_codec_get_encoding_name(PurpleMediaCodec *codec);
-guint purple_media_codec_get_clock_rate(PurpleMediaCodec *codec);
-guint purple_media_codec_get_channels(PurpleMediaCodec *codec);
-GList *purple_media_codec_get_optional_parameters(PurpleMediaCodec *codec);
-
-/**
- * Creates a string representation of the codec.
- *
- * @param codec The codec to create the string of.
- *
- * @return The new string representation.
- *
- * @since 2.6.0
- */
-gchar *purple_media_codec_to_string(const PurpleMediaCodec *codec);
-
-/**
- * Adds an optional parameter to the codec.
- *
- * @param codec The codec to add the parameter to.
- * @param name The name of the parameter to add.
- * @param value The value of the parameter to add.
- *
- * @since 2.6.0
- */
-void purple_media_codec_add_optional_parameter(PurpleMediaCodec *codec,
-		const gchar *name, const gchar *value);
-
-/**
- * Removes an optional parameter from the codec.
- *
- * @param codec The codec to remove the parameter from.
- * @param param A pointer to the parameter to remove.
- *
- * @since 2.6.0
- */
-void purple_media_codec_remove_optional_parameter(PurpleMediaCodec *codec,
-		PurpleKeyValuePair *param);
-
-/**
- * Gets an optional parameter based on the values given.
- *
- * @param codec The codec to find the parameter in.
- * @param name The name of the parameter to search for.
- * @param value The value to search for or NULL.
- *
- * @return The value found or NULL.
- *
- * @since 2.6.0
- */
-PurpleKeyValuePair *purple_media_codec_get_optional_parameter(
-		PurpleMediaCodec *codec, const gchar *name,
-		const gchar *value);
-
-/**
- * Copies a GList of PurpleMediaCodec and its contents.
- *
- * @param codecs The list of codecs to be copied.
- *
- * @return The copy of the GList.
- *
- * @since 2.6.0
- */
-GList *purple_media_codec_list_copy(GList *codecs);
-
-/**
- * Frees a GList of PurpleMediaCodec and its contents.
- *
- * @param codecs The list of codecs to be freed.
- *
- * @since 2.6.0
- */
-void purple_media_codec_list_free(GList *codecs);
-
-/**
  * Gets a list of session IDs.
  *
  * @param media The media session from which to retrieve session IDs.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/media/backend-fs2.c	Thu Feb 04 05:30:35 2010 +0000
@@ -0,0 +1,2032 @@
+/**
+ * @file backend-fs2.c Farsight 2 backend for media API
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This 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 Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "internal.h"
+
+#ifdef USE_VV
+#include "backend-fs2.h"
+
+#include "backend-iface.h"
+#include "debug.h"
+#include "network.h"
+#include "media-gst.h"
+
+#include <gst/farsight/fs-conference-iface.h>
+#include <gst/farsight/fs-element-added-notifier.h>
+
+/** @copydoc _PurpleMediaBackendFs2Class */
+typedef struct _PurpleMediaBackendFs2Class PurpleMediaBackendFs2Class;
+/** @copydoc _PurpleMediaBackendFs2Private */
+typedef struct _PurpleMediaBackendFs2Private PurpleMediaBackendFs2Private;
+/** @copydoc _PurpleMediaBackendFs2Session */
+typedef struct _PurpleMediaBackendFs2Session PurpleMediaBackendFs2Session;
+/** @copydoc _PurpleMediaBackendFs2Stream */
+typedef struct _PurpleMediaBackendFs2Stream PurpleMediaBackendFs2Stream;
+
+#define PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(obj) \
+		(G_TYPE_INSTANCE_GET_PRIVATE((obj), \
+		PURPLE_TYPE_MEDIA_BACKEND_FS2, PurpleMediaBackendFs2Private))
+
+static void purple_media_backend_iface_init(PurpleMediaBackendIface *iface);
+
+static gboolean
+gst_bus_cb(GstBus *bus, GstMessage *msg, PurpleMediaBackendFs2 *self);
+static void
+state_changed_cb(PurpleMedia *media, PurpleMediaState state,
+		gchar *sid, gchar *name, PurpleMediaBackendFs2 *self);
+static void
+stream_info_cb(PurpleMedia *media, PurpleMediaInfoType type,
+		gchar *sid, gchar *name, gboolean local,
+		PurpleMediaBackendFs2 *self);
+
+static gboolean purple_media_backend_fs2_add_stream(PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *who,
+		PurpleMediaSessionType type, gboolean initiator,
+		const gchar *transmitter,
+		guint num_params, GParameter *params);
+static void purple_media_backend_fs2_add_remote_candidates(
+		PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *participant,
+		GList *remote_candidates);
+static gboolean purple_media_backend_fs2_codecs_ready(PurpleMediaBackend *self,
+		const gchar *sess_id);
+static GList *purple_media_backend_fs2_get_codecs(PurpleMediaBackend *self,
+		const gchar *sess_id);
+static GList *purple_media_backend_fs2_get_local_candidates(
+		PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *participant);
+static gboolean purple_media_backend_fs2_set_remote_codecs(
+		PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *participant,
+		GList *codecs);
+static gboolean purple_media_backend_fs2_set_send_codec(
+		PurpleMediaBackend *self, const gchar *sess_id,
+		PurpleMediaCodec *codec);
+
+struct _PurpleMediaBackendFs2Class
+{
+	GObjectClass parent_class;
+};
+
+struct _PurpleMediaBackendFs2
+{
+	GObject parent;
+};
+
+G_DEFINE_TYPE_WITH_CODE(PurpleMediaBackendFs2, purple_media_backend_fs2,
+		G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE(
+		PURPLE_TYPE_MEDIA_BACKEND, purple_media_backend_iface_init));
+
+struct _PurpleMediaBackendFs2Stream
+{
+	PurpleMediaBackendFs2Session *session;
+	gchar *participant;
+	FsStream *stream;
+
+	GstElement *src;
+	GstElement *tee;
+	GstElement *volume;
+	GstElement *level;
+
+	GList *local_candidates;
+	GList *remote_candidates;
+
+	guint connected_cb_id;
+};
+
+struct _PurpleMediaBackendFs2Session
+{
+	PurpleMediaBackendFs2 *backend;
+	gchar *id;
+	FsSession *session;
+
+	GstElement *src;
+	GstElement *tee;
+
+	PurpleMediaSessionType type;
+};
+
+struct _PurpleMediaBackendFs2Private
+{
+	PurpleMedia *media;
+	GstElement *confbin;
+	FsConference *conference;
+	gchar *conference_type;
+
+	GHashTable *sessions;
+	GHashTable *participants;
+
+	GList *streams;
+};
+
+enum {
+	PROP_0,
+	PROP_CONFERENCE_TYPE,
+	PROP_MEDIA,
+};
+
+static void
+purple_media_backend_fs2_init(PurpleMediaBackendFs2 *self)
+{
+}
+
+static void
+purple_media_backend_fs2_dispose(GObject *obj)
+{
+	PurpleMediaBackendFs2Private *priv =
+			PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(obj);
+	GList *iter = NULL;
+
+	purple_debug_info("backend-fs2", "purple_media_backend_fs2_dispose\n");
+
+	if (priv->confbin) {
+		GstElement *pipeline;
+
+		pipeline = purple_media_manager_get_pipeline(
+				purple_media_get_manager(priv->media));
+
+		gst_element_set_locked_state(priv->confbin, TRUE);
+		gst_element_set_state(GST_ELEMENT(priv->confbin),
+				GST_STATE_NULL);
+
+		if (pipeline) {
+			GstBus *bus;
+			gst_bin_remove(GST_BIN(pipeline), priv->confbin);
+			bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
+			g_signal_handlers_disconnect_matched(G_OBJECT(bus),
+					G_SIGNAL_MATCH_FUNC |
+					G_SIGNAL_MATCH_DATA,
+					0, 0, 0, gst_bus_cb, obj);
+			gst_object_unref(bus);
+		} else {
+			purple_debug_warning("backend-fs2", "Unable to "
+					"properly dispose the conference. "
+					"Couldn't get the pipeline.\n");
+		}
+
+		priv->confbin = NULL;
+		priv->conference = NULL;
+
+	}
+
+	if (priv->sessions) {
+		GList *sessions = g_hash_table_get_values(priv->sessions);
+
+		for (; sessions; sessions =
+				g_list_delete_link(sessions, sessions)) {
+			PurpleMediaBackendFs2Session *session =
+					sessions->data;
+
+			if (session->session) {
+				g_object_unref(session->session);
+				session->session = NULL;
+			}
+		}
+	}
+
+	if (priv->participants) {
+		GList *participants =
+				g_hash_table_get_values(priv->participants);
+		for (; participants; participants = g_list_delete_link(
+				participants, participants))
+			g_object_unref(participants->data);
+		priv->participants = NULL;
+	}
+
+	for (iter = priv->streams; iter; iter = g_list_next(iter)) {
+		PurpleMediaBackendFs2Stream *stream = iter->data;
+		if (stream->stream) {
+			g_object_unref(stream->stream);
+			stream->stream = NULL;
+		}
+	}
+
+	if (priv->media) {
+		g_object_remove_weak_pointer(G_OBJECT(priv->media),
+				(gpointer*)&priv->media);
+		priv->media = NULL;
+	}
+
+	G_OBJECT_CLASS(purple_media_backend_fs2_parent_class)->dispose(obj);
+}
+
+static void
+purple_media_backend_fs2_finalize(GObject *obj)
+{
+	PurpleMediaBackendFs2Private *priv =
+			PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(obj);
+
+	purple_debug_info("backend-fs2", "purple_media_backend_fs2_finalize\n");
+
+	g_free(priv->conference_type);
+
+	for (; priv->streams; priv->streams =
+			g_list_delete_link(priv->streams, priv->streams)) {
+		PurpleMediaBackendFs2Stream *stream = priv->streams->data;
+
+		/* Remove the connected_cb timeout */
+		if (stream->connected_cb_id != 0)
+			purple_timeout_remove(stream->connected_cb_id);
+
+		g_free(stream->participant);
+
+		if (stream->local_candidates)
+			fs_candidate_list_destroy(stream->local_candidates);
+
+		if (stream->remote_candidates)
+			fs_candidate_list_destroy(stream->remote_candidates);
+
+		g_free(stream);
+	}
+
+	if (priv->sessions) {
+		GList *sessions = g_hash_table_get_values(priv->sessions);
+
+		for (; sessions; sessions =
+				g_list_delete_link(sessions, sessions)) {
+			PurpleMediaBackendFs2Session *session =
+					sessions->data;
+			g_free(session->id);
+			g_free(session);
+		}
+
+		g_hash_table_destroy(priv->sessions);
+	}
+
+	G_OBJECT_CLASS(purple_media_backend_fs2_parent_class)->finalize(obj);
+}
+
+static void
+purple_media_backend_fs2_set_property(GObject *object, guint prop_id,
+		const GValue *value, GParamSpec *pspec)
+{
+	PurpleMediaBackendFs2Private *priv;
+	g_return_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(object));
+
+	priv = PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(object);
+
+	switch (prop_id) {
+		case PROP_CONFERENCE_TYPE:
+			priv->conference_type = g_value_dup_string(value);
+			break;
+		case PROP_MEDIA:
+			priv->media = g_value_get_object(value);
+
+			if (priv->media == NULL)
+				break;
+
+			g_object_add_weak_pointer(G_OBJECT(priv->media),
+					(gpointer*)&priv->media);
+
+			g_signal_connect(G_OBJECT(priv->media),
+					"state-changed",
+					G_CALLBACK(state_changed_cb),
+					PURPLE_MEDIA_BACKEND_FS2(object));
+			g_signal_connect(G_OBJECT(priv->media), "stream-info",
+					G_CALLBACK(stream_info_cb),
+					PURPLE_MEDIA_BACKEND_FS2(object));
+			break;
+		default:	
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(
+					object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_media_backend_fs2_get_property(GObject *object, guint prop_id,
+		GValue *value, GParamSpec *pspec)
+{
+	PurpleMediaBackendFs2Private *priv;
+	g_return_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(object));
+	
+	priv = PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(object);
+
+	switch (prop_id) {
+		case PROP_CONFERENCE_TYPE:
+			g_value_set_string(value, priv->conference_type);
+			break;
+		case PROP_MEDIA:
+			g_value_set_object(value, priv->media);
+			break;
+		default:	
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(
+					object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_media_backend_fs2_class_init(PurpleMediaBackendFs2Class *klass)
+{
+	GObjectClass *gobject_class = (GObjectClass*)klass;
+
+	gobject_class->dispose = purple_media_backend_fs2_dispose;
+	gobject_class->finalize = purple_media_backend_fs2_finalize;
+	gobject_class->set_property = purple_media_backend_fs2_set_property;
+	gobject_class->get_property = purple_media_backend_fs2_get_property;
+
+	g_object_class_override_property(gobject_class, PROP_CONFERENCE_TYPE,
+			"conference-type");
+	g_object_class_override_property(gobject_class, PROP_MEDIA, "media");
+
+	g_type_class_add_private(klass, sizeof(PurpleMediaBackendFs2Private));
+}
+
+static void
+purple_media_backend_iface_init(PurpleMediaBackendIface *iface)
+{
+	iface->add_stream = purple_media_backend_fs2_add_stream;
+	iface->add_remote_candidates =
+			purple_media_backend_fs2_add_remote_candidates;
+	iface->codecs_ready = purple_media_backend_fs2_codecs_ready;
+	iface->get_codecs = purple_media_backend_fs2_get_codecs;
+	iface->get_local_candidates =
+			purple_media_backend_fs2_get_local_candidates;
+	iface->set_remote_codecs = purple_media_backend_fs2_set_remote_codecs;
+	iface->set_send_codec = purple_media_backend_fs2_set_send_codec;
+}
+
+static FsMediaType
+session_type_to_fs_media_type(PurpleMediaSessionType type)
+{
+	if (type & PURPLE_MEDIA_AUDIO)
+		return FS_MEDIA_TYPE_AUDIO;
+	else if (type & PURPLE_MEDIA_VIDEO)
+		return FS_MEDIA_TYPE_VIDEO;
+	else
+		return 0;
+}
+
+static FsStreamDirection
+session_type_to_fs_stream_direction(PurpleMediaSessionType type)
+{
+	if ((type & PURPLE_MEDIA_AUDIO) == PURPLE_MEDIA_AUDIO ||
+			(type & PURPLE_MEDIA_VIDEO) == PURPLE_MEDIA_VIDEO)
+		return FS_DIRECTION_BOTH;
+	else if ((type & PURPLE_MEDIA_SEND_AUDIO) ||
+			(type & PURPLE_MEDIA_SEND_VIDEO))
+		return FS_DIRECTION_SEND;
+	else if ((type & PURPLE_MEDIA_RECV_AUDIO) ||
+			(type & PURPLE_MEDIA_RECV_VIDEO))
+		return FS_DIRECTION_RECV;
+	else
+		return FS_DIRECTION_NONE;
+}
+
+static PurpleMediaSessionType
+session_type_from_fs(FsMediaType type, FsStreamDirection direction)
+{
+	PurpleMediaSessionType result = PURPLE_MEDIA_NONE;
+	if (type == FS_MEDIA_TYPE_AUDIO) {
+		if (direction & FS_DIRECTION_SEND)
+			result |= PURPLE_MEDIA_SEND_AUDIO;
+		if (direction & FS_DIRECTION_RECV)
+			result |= PURPLE_MEDIA_RECV_AUDIO;
+	} else if (type == FS_MEDIA_TYPE_VIDEO) {
+		if (direction & FS_DIRECTION_SEND)
+			result |= PURPLE_MEDIA_SEND_VIDEO;
+		if (direction & FS_DIRECTION_RECV)
+			result |= PURPLE_MEDIA_RECV_VIDEO;
+	}
+	return result;
+}
+
+static FsCandidate *
+candidate_to_fs(PurpleMediaCandidate *candidate)
+{
+	FsCandidate *fscandidate;
+	gchar *foundation;
+	guint component_id;
+	gchar *ip;
+	guint port;
+	gchar *base_ip;
+	guint base_port;
+	PurpleMediaNetworkProtocol proto;
+	guint32 priority;
+	PurpleMediaCandidateType type;
+	gchar *username;
+	gchar *password;
+	guint ttl;
+
+	if (candidate == NULL)
+		return NULL;
+
+	g_object_get(G_OBJECT(candidate),
+			"foundation", &foundation,
+			"component-id", &component_id,
+			"ip", &ip,
+			"port", &port,
+			"base-ip", &base_ip,
+			"base-port", &base_port,
+			"protocol", &proto,
+			"priority", &priority,
+			"type", &type,
+			"username", &username,
+			"password", &password,
+			"ttl", &ttl,
+			NULL);
+
+	fscandidate = fs_candidate_new(foundation,
+			component_id, type,
+			proto, ip, port);
+
+	fscandidate->base_ip = base_ip;
+	fscandidate->base_port = base_port;
+	fscandidate->priority = priority;
+	fscandidate->username = username;
+	fscandidate->password = password;
+	fscandidate->ttl = ttl;
+
+	g_free(foundation);
+	g_free(ip);
+	return fscandidate;
+}
+
+static GList *
+candidate_list_to_fs(GList *candidates)
+{
+	GList *new_list = NULL;
+
+	for (; candidates; candidates = g_list_next(candidates)) {
+		new_list = g_list_prepend(new_list,
+				candidate_to_fs(candidates->data));
+	}
+
+	new_list = g_list_reverse(new_list);
+	return new_list;
+}
+
+static PurpleMediaCandidate *
+candidate_from_fs(FsCandidate *fscandidate)
+{
+	PurpleMediaCandidate *candidate;
+
+	if (fscandidate == NULL)
+		return NULL;
+
+	candidate = purple_media_candidate_new(fscandidate->foundation,
+		fscandidate->component_id, fscandidate->type,
+		fscandidate->proto, fscandidate->ip, fscandidate->port);
+	g_object_set(candidate,
+			"base-ip", fscandidate->base_ip,
+			"base-port", fscandidate->base_port,
+			"priority", fscandidate->priority,
+			"username", fscandidate->username,
+			"password", fscandidate->password,
+			"ttl", fscandidate->ttl, NULL);
+	return candidate;
+}
+
+static GList *
+candidate_list_from_fs(GList *candidates)
+{
+	GList *new_list = NULL;
+
+	for (; candidates; candidates = g_list_next(candidates)) {
+		new_list = g_list_prepend(new_list,
+			candidate_from_fs(candidates->data));
+	}
+
+	new_list = g_list_reverse(new_list);
+	return new_list;
+}
+
+static FsCodec *
+codec_to_fs(const PurpleMediaCodec *codec)
+{
+	FsCodec *new_codec;
+	gint id;
+	char *encoding_name;
+	PurpleMediaSessionType media_type;
+	guint clock_rate;
+	guint channels;
+	GList *iter;
+
+	if (codec == NULL)
+		return NULL;
+
+	g_object_get(G_OBJECT(codec),
+			"id", &id,
+			"encoding-name", &encoding_name,
+			"media-type", &media_type,
+			"clock-rate", &clock_rate,
+			"channels", &channels,
+			"optional-params", &iter,
+			NULL);
+
+	new_codec = fs_codec_new(id, encoding_name,
+			session_type_to_fs_media_type(media_type),
+			clock_rate);
+	new_codec->channels = channels;
+
+	for (; iter; iter = g_list_next(iter)) {
+		PurpleKeyValuePair *param = (PurpleKeyValuePair*)iter->data;
+		fs_codec_add_optional_parameter(new_codec,
+				param->key, param->value);
+	}
+
+	g_free(encoding_name);
+	return new_codec;
+}
+
+static PurpleMediaCodec *
+codec_from_fs(const FsCodec *codec)
+{
+	PurpleMediaCodec *new_codec;
+	GList *iter;
+
+	if (codec == NULL)
+		return NULL;
+
+	new_codec = purple_media_codec_new(codec->id, codec->encoding_name,
+			session_type_from_fs(codec->media_type,
+			FS_DIRECTION_BOTH), codec->clock_rate);
+	g_object_set(new_codec, "channels", codec->channels, NULL);
+
+	for (iter = codec->optional_params; iter; iter = g_list_next(iter)) {
+		FsCodecParameter *param = (FsCodecParameter*)iter->data;
+		purple_media_codec_add_optional_parameter(new_codec,
+				param->name, param->value);
+	}
+
+	return new_codec;
+}
+
+static GList *
+codec_list_from_fs(GList *codecs)
+{
+	GList *new_list = NULL;
+
+	for (; codecs; codecs = g_list_next(codecs)) {
+		new_list = g_list_prepend(new_list,
+				codec_from_fs(codecs->data));
+	}
+
+	new_list = g_list_reverse(new_list);
+	return new_list;
+}
+
+static GList *
+codec_list_to_fs(GList *codecs)
+{
+	GList *new_list = NULL;
+
+	for (; codecs; codecs = g_list_next(codecs)) {
+		new_list = g_list_prepend(new_list,
+				codec_to_fs(codecs->data));
+	}
+
+	new_list = g_list_reverse(new_list);
+	return new_list;
+}
+
+static PurpleMediaBackendFs2Session *
+get_session(PurpleMediaBackendFs2 *self, const gchar *sess_id)
+{
+	PurpleMediaBackendFs2Private *priv;
+	PurpleMediaBackendFs2Session *session = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self), NULL);
+
+	priv = PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
+
+	if (priv->sessions != NULL)
+		session = g_hash_table_lookup(priv->sessions, sess_id);
+
+	return session;
+}
+
+static FsParticipant *
+get_participant(PurpleMediaBackendFs2 *self, const gchar *name)
+{
+	PurpleMediaBackendFs2Private *priv;
+	FsParticipant *participant = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self), NULL);
+
+	priv = PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
+
+	if (priv->participants != NULL)
+		participant = g_hash_table_lookup(priv->participants, name);
+
+	return participant;
+}
+
+static PurpleMediaBackendFs2Stream *
+get_stream(PurpleMediaBackendFs2 *self,
+		const gchar *sess_id, const gchar *name)
+{
+	PurpleMediaBackendFs2Private *priv;
+	GList *streams;
+
+	g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self), NULL);
+
+	priv = PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
+	streams = priv->streams;
+
+	for (; streams; streams = g_list_next(streams)) {
+		PurpleMediaBackendFs2Stream *stream = streams->data;
+		if (!strcmp(stream->session->id, sess_id) &&
+				!strcmp(stream->participant, name))
+			return stream;
+	}
+
+	return NULL;
+}
+
+static GList *
+get_streams(PurpleMediaBackendFs2 *self,
+		const gchar *sess_id, const gchar *name)
+{
+	PurpleMediaBackendFs2Private *priv;
+	GList *streams, *ret = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self), NULL);
+
+	priv = PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
+	streams = priv->streams;
+
+	for (; streams; streams = g_list_next(streams)) {
+		PurpleMediaBackendFs2Stream *stream = streams->data;
+
+		if (sess_id != NULL && strcmp(stream->session->id, sess_id))
+			continue;
+		else if (name != NULL && strcmp(stream->participant, name))
+			continue;
+		else
+			ret = g_list_prepend(ret, stream);
+	}
+
+	ret = g_list_reverse(ret);
+	return ret;
+}
+
+static PurpleMediaBackendFs2Session *
+get_session_from_fs_stream(PurpleMediaBackendFs2 *self, FsStream *stream)
+{
+	PurpleMediaBackendFs2Private *priv =
+			PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
+	FsSession *fssession;
+	GList *values;
+
+	g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self), NULL);
+	g_return_val_if_fail(FS_IS_STREAM(stream), NULL);
+
+	g_object_get(stream, "session", &fssession, NULL);
+
+	values = g_hash_table_get_values(priv->sessions);
+
+	for (; values; values = g_list_delete_link(values, values)) {
+		PurpleMediaBackendFs2Session *session = values->data;
+
+		if (session->session == fssession) {
+			g_list_free(values);
+			g_object_unref(fssession);
+			return session;
+		}
+	}
+
+	g_object_unref(fssession);
+	return NULL;
+}
+
+static void
+gst_handle_message_element(GstBus *bus, GstMessage *msg,
+		PurpleMediaBackendFs2 *self)
+{
+	PurpleMediaBackendFs2Private *priv =
+			PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
+	GstElement *src = GST_ELEMENT(GST_MESSAGE_SRC(msg));
+	static guint level_id = 0;
+
+	if (level_id == 0)
+		level_id = g_signal_lookup("level", PURPLE_TYPE_MEDIA);
+
+	if (g_signal_has_handler_pending(priv->media, level_id, 0, FALSE)
+			&& gst_structure_has_name(
+			gst_message_get_structure(msg), "level")) {
+		GstElement *src = GST_ELEMENT(GST_MESSAGE_SRC(msg));
+		gchar *name;
+		gchar *participant = NULL;
+		PurpleMediaBackendFs2Session *session = NULL;
+		gdouble rms_db;
+		gdouble percent;
+		const GValue *list;
+		const GValue *value;
+
+		if (!PURPLE_IS_MEDIA(priv->media) ||
+				GST_ELEMENT_PARENT(src) != priv->confbin)
+			return;
+
+		name = gst_element_get_name(src);
+
+		if (!strncmp(name, "sendlevel_", 10)) {
+			session = get_session(self, name+10);
+		} else {
+			GList *iter = priv->streams;
+			PurpleMediaBackendFs2Stream *stream;
+			for (; iter; iter = g_list_next(iter)) {
+				stream = iter->data;
+				if (stream->level == src) {
+					session = stream->session;
+					participant = stream->participant;
+					break;
+				}
+			}
+		}
+
+		g_free(name);
+
+		if (!session)
+			return;
+
+		list = gst_structure_get_value(
+				gst_message_get_structure(msg), "rms");
+		value = gst_value_list_get_value(list, 0);
+		rms_db = g_value_get_double(value);
+		percent = pow(10, rms_db / 20) * 5;
+
+		if(percent > 1.0)
+			percent = 1.0;
+
+		g_signal_emit(priv->media, level_id, 0,
+				session->id, participant, percent);
+		return;
+	}
+
+	if (!FS_IS_CONFERENCE(src) || !PURPLE_IS_MEDIA_BACKEND(self) ||
+			priv->conference != FS_CONFERENCE(src))
+		return;
+
+	if (gst_structure_has_name(msg->structure, "farsight-error")) {
+		FsError error_no;
+		gst_structure_get_enum(msg->structure, "error-no",
+				FS_TYPE_ERROR, (gint*)&error_no);
+		switch (error_no) {
+			case FS_ERROR_NO_CODECS:
+				purple_media_error(priv->media, _("No codecs"
+						" found. Install some"
+						" GStreamer codecs found"
+						" in GStreamer plugins"
+						" packages."));
+				purple_media_end(priv->media, NULL, NULL);
+				break;
+			case FS_ERROR_NO_CODECS_LEFT:
+				purple_media_error(priv->media, _("No codecs"
+						" left. Your codec"
+						" preferences in"
+						" fs-codecs.conf are too"
+						" strict."));
+				purple_media_end(priv->media, NULL, NULL);
+				break;
+			case FS_ERROR_UNKNOWN_CNAME:
+			/*
+			 * Unknown CName is only a problem for the
+			 * multicast transmitter which isn't used.
+			 * It is also deprecated.
+			 */
+				break;
+			default:
+				purple_debug_error("backend-fs2",
+						"farsight-error: %i: %s\n",
+						error_no,
+					  	gst_structure_get_string(
+						msg->structure, "error-msg"));
+				break;
+		}
+
+		if (FS_ERROR_IS_FATAL(error_no)) {
+			purple_media_error(priv->media, _("A non-recoverable "
+					"Farsight2 error has occurred."));
+			purple_media_end(priv->media, NULL, NULL);
+		}
+	} else if (gst_structure_has_name(msg->structure,
+			"farsight-new-local-candidate")) {
+		const GValue *value;
+		FsStream *stream;
+		FsCandidate *local_candidate;
+		PurpleMediaCandidate *candidate;
+		FsParticipant *participant;
+		PurpleMediaBackendFs2Session *session;
+		PurpleMediaBackendFs2Stream *media_stream;
+		gchar *name;
+
+		value = gst_structure_get_value(msg->structure, "stream");
+		stream = g_value_get_object(value);
+		value = gst_structure_get_value(msg->structure, "candidate");
+		local_candidate = g_value_get_boxed(value);
+
+		session = get_session_from_fs_stream(self, stream);
+
+		purple_debug_info("backend-fs2",
+				"got new local candidate: %s\n",
+				local_candidate->foundation);
+
+		g_object_get(stream, "participant", &participant, NULL);
+		g_object_get(participant, "cname", &name, NULL);
+		g_object_unref(participant);
+
+		media_stream = get_stream(self, session->id, name);
+		media_stream->local_candidates = g_list_append(
+				media_stream->local_candidates,
+				fs_candidate_copy(local_candidate));
+
+		candidate = candidate_from_fs(local_candidate);
+		g_signal_emit_by_name(self, "new-candidate",
+				session->id, name, candidate);
+		g_object_unref(candidate);
+	} else if (gst_structure_has_name(msg->structure,
+			"farsight-local-candidates-prepared")) {
+		const GValue *value;
+		FsStream *stream;
+		FsParticipant *participant;
+		PurpleMediaBackendFs2Session *session;
+		gchar *name;
+
+		value = gst_structure_get_value(msg->structure, "stream");
+		stream = g_value_get_object(value);
+		session = get_session_from_fs_stream(self, stream);
+
+		g_object_get(stream, "participant", &participant, NULL);
+		g_object_get(participant, "cname", &name, NULL);
+		g_object_unref(participant);
+
+		g_signal_emit_by_name(self, "candidates-prepared",
+				session->id, name);
+	} else if (gst_structure_has_name(msg->structure,
+			"farsight-new-active-candidate-pair")) {
+		const GValue *value;
+		FsStream *stream;
+		FsCandidate *local_candidate;
+		FsCandidate *remote_candidate;
+		FsParticipant *participant;
+		PurpleMediaBackendFs2Session *session;
+		PurpleMediaCandidate *lcandidate, *rcandidate;
+		gchar *name;
+
+		value = gst_structure_get_value(msg->structure, "stream");
+		stream = g_value_get_object(value);
+		value = gst_structure_get_value(msg->structure,
+				"local-candidate");
+		local_candidate = g_value_get_boxed(value);
+		value = gst_structure_get_value(msg->structure,
+				"remote-candidate");
+		remote_candidate = g_value_get_boxed(value);
+
+		g_object_get(stream, "participant", &participant, NULL);
+		g_object_get(participant, "cname", &name, NULL);
+		g_object_unref(participant);
+
+		session = get_session_from_fs_stream(self, stream);
+
+		lcandidate = candidate_from_fs(local_candidate);
+		rcandidate = candidate_from_fs(remote_candidate);
+
+		g_signal_emit_by_name(self, "active-candidate-pair",
+				session->id, name, lcandidate, rcandidate);
+
+		g_object_unref(lcandidate);
+		g_object_unref(rcandidate);
+	} else if (gst_structure_has_name(msg->structure,
+			"farsight-recv-codecs-changed")) {
+		const GValue *value;
+		GList *codecs;
+		FsCodec *codec;
+
+		value = gst_structure_get_value(msg->structure, "codecs");
+		codecs = g_value_get_boxed(value);
+		codec = codecs->data;
+
+		purple_debug_info("backend-fs2",
+				"farsight-recv-codecs-changed: %s\n",
+				codec->encoding_name);
+	} else if (gst_structure_has_name(msg->structure,
+			"farsight-component-state-changed")) {
+		const GValue *value;
+		FsStreamState fsstate;
+		guint component;
+		const gchar *state;
+
+		value = gst_structure_get_value(msg->structure, "state");
+		fsstate = g_value_get_enum(value);
+		value = gst_structure_get_value(msg->structure, "component");
+		component = g_value_get_uint(value);
+
+		switch (fsstate) {
+			case FS_STREAM_STATE_FAILED:
+				state = "FAILED";
+				break;
+			case FS_STREAM_STATE_DISCONNECTED:
+				state = "DISCONNECTED";
+				break;
+			case FS_STREAM_STATE_GATHERING:
+				state = "GATHERING";
+				break;
+			case FS_STREAM_STATE_CONNECTING:
+				state = "CONNECTING";
+				break;
+			case FS_STREAM_STATE_CONNECTED:
+				state = "CONNECTED";
+				break;
+			case FS_STREAM_STATE_READY:
+				state = "READY";
+				break;
+			default:
+				state = "UNKNOWN";
+				break;
+		}
+
+		purple_debug_info("backend-fs2",
+				"farsight-component-state-changed: "
+				"component: %u state: %s\n",
+				component, state);
+	} else if (gst_structure_has_name(msg->structure,
+			"farsight-send-codec-changed")) {
+		const GValue *value;
+		FsCodec *codec;
+		gchar *codec_str;
+
+		value = gst_structure_get_value(msg->structure, "codec");
+		codec = g_value_get_boxed(value);
+		codec_str = fs_codec_to_string(codec);
+
+		purple_debug_info("backend-fs2",
+				"farsight-send-codec-changed: codec: %s\n",
+				codec_str);
+
+		g_free(codec_str);
+	} else if (gst_structure_has_name(msg->structure,
+			"farsight-codecs-changed")) {
+		const GValue *value;
+		FsSession *fssession;
+		GList *sessions;
+
+		value = gst_structure_get_value(msg->structure, "session");
+		fssession = g_value_get_object(value);
+		sessions = g_hash_table_get_values(priv->sessions);
+
+		for (; sessions; sessions =
+				g_list_delete_link(sessions, sessions)) {
+			PurpleMediaBackendFs2Session *session = sessions->data;
+			gchar *session_id;
+
+			if (session->session != fssession)
+				continue;
+
+			session_id = g_strdup(session->id);
+			g_signal_emit_by_name(self, "codecs-changed",
+					session_id);
+			g_free(session_id);
+			g_list_free(sessions);
+			break;
+		}
+	}
+}
+
+static void
+gst_handle_message_error(GstBus *bus, GstMessage *msg,
+		PurpleMediaBackendFs2 *self)
+{
+	PurpleMediaBackendFs2Private *priv =
+			PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
+	GstElement *element = GST_ELEMENT(GST_MESSAGE_SRC(msg));
+	GstElement *lastElement = NULL;
+	GList *sessions;
+
+	while (!GST_IS_PIPELINE(element)) {
+		if (element == priv->confbin)
+			break;
+
+		lastElement = element;
+		element = GST_ELEMENT_PARENT(element);
+	}
+
+	if (!GST_IS_PIPELINE(element))
+		return;
+
+	sessions = purple_media_get_session_ids(priv->media);
+
+	for (; sessions; sessions = g_list_delete_link(sessions, sessions)) {
+		if (purple_media_get_src(priv->media, sessions->data)
+				!= lastElement)
+			continue;
+
+		if (purple_media_get_session_type(priv->media, sessions->data)
+				& PURPLE_MEDIA_AUDIO)
+			purple_media_error(priv->media,
+					_("Error with your microphone"));
+		else
+			purple_media_error(priv->media,
+					_("Error with your webcam"));
+
+		break;
+	}
+
+	g_list_free(sessions);
+
+	purple_media_error(priv->media, _("Conference error"));
+	purple_media_end(priv->media, NULL, NULL);
+}
+
+static gboolean
+gst_bus_cb(GstBus *bus, GstMessage *msg, PurpleMediaBackendFs2 *self)
+{
+	switch(GST_MESSAGE_TYPE(msg)) {
+		case GST_MESSAGE_ELEMENT:
+			gst_handle_message_element(bus, msg, self);
+			break;
+		case GST_MESSAGE_ERROR:
+			gst_handle_message_error(bus, msg, self);
+			break;
+		default:
+			break;
+	}
+
+	return TRUE;
+}
+
+static void
+state_changed_cb(PurpleMedia *media, PurpleMediaState state,
+		gchar *sid, gchar *name, PurpleMediaBackendFs2 *self)
+{
+}
+
+static void
+stream_info_cb(PurpleMedia *media, PurpleMediaInfoType type,
+		gchar *sid, gchar *name, gboolean local,
+		PurpleMediaBackendFs2 *self)
+{
+	if (type == PURPLE_MEDIA_INFO_ACCEPT && sid != NULL && name != NULL) {
+		PurpleMediaBackendFs2Stream *stream =
+				get_stream(self, sid, name);
+		GError *err = NULL;
+
+		g_object_set(G_OBJECT(stream->stream), "direction",
+				session_type_to_fs_stream_direction(
+				stream->session->type), NULL);
+
+		if (stream->remote_candidates == NULL ||
+				purple_media_is_initiator(media, sid, name))
+			return;
+
+		fs_stream_set_remote_candidates(stream->stream,
+				stream->remote_candidates, &err);
+
+		if (err == NULL)
+			return;
+
+		purple_debug_error("backend-fs2", "Error adding "
+				"remote candidates: %s\n",
+				err->message);
+		g_error_free(err);
+	} else if (local == TRUE && (type == PURPLE_MEDIA_INFO_MUTE ||
+			type == PURPLE_MEDIA_INFO_UNMUTE)) {
+		PurpleMediaBackendFs2Private *priv =
+				PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
+		gboolean active = (type == PURPLE_MEDIA_INFO_MUTE);
+		GList *sessions;
+
+		if (sid == NULL)
+			sessions = g_hash_table_get_values(priv->sessions);
+		else
+			sessions = g_list_prepend(NULL,
+					get_session(self, sid));
+
+		purple_debug_info("media", "Turning mute %s\n",
+				active ? "on" : "off");
+
+		for (; sessions; sessions = g_list_delete_link(
+				sessions, sessions)) {
+			PurpleMediaBackendFs2Session *session =
+					sessions->data;
+
+			if (session->type & PURPLE_MEDIA_SEND_AUDIO) {
+				gchar *name = g_strdup_printf("volume_%s",
+						session->id);
+				GstElement *volume = gst_bin_get_by_name(
+						GST_BIN(priv->confbin), name);
+				g_free(name);
+				g_object_set(volume, "mute", active, NULL);
+			}
+		}
+	} else if (local == TRUE && (type == PURPLE_MEDIA_INFO_PAUSE ||
+			type == PURPLE_MEDIA_INFO_UNPAUSE)) {
+		gboolean active = (type == PURPLE_MEDIA_INFO_PAUSE);
+		GList *streams = get_streams(self, sid, name);
+		for (; streams; streams =
+				g_list_delete_link(streams, streams)) {
+			PurpleMediaBackendFs2Stream *stream = streams->data;
+			if (stream->session->type & PURPLE_MEDIA_SEND_VIDEO) {
+				g_object_set(stream->stream, "direction",
+						session_type_to_fs_stream_direction(
+						stream->session->type & ((active) ?
+						~PURPLE_MEDIA_SEND_VIDEO :
+						PURPLE_MEDIA_VIDEO)), NULL);
+			}
+		}
+	}
+}
+
+static gboolean
+init_conference(PurpleMediaBackendFs2 *self)
+{
+	PurpleMediaBackendFs2Private *priv =
+			PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
+	GstElement *pipeline;
+	GstBus *bus;
+	gchar *name;
+
+	priv->conference = FS_CONFERENCE(
+			gst_element_factory_make(priv->conference_type, NULL));
+
+	if (priv->conference == NULL) {
+		purple_debug_error("backend-fs2", "Conference == NULL\n");
+		return FALSE;
+	}
+
+	pipeline = purple_media_manager_get_pipeline(
+			purple_media_get_manager(priv->media));
+
+	if (pipeline == NULL) {
+		purple_debug_error("backend-fs2",
+				"Couldn't retrieve pipeline.\n");
+		return FALSE;
+	}
+
+	name = g_strdup_printf("conf_%p", priv->conference);
+	priv->confbin = gst_bin_new(name);
+	if (priv->confbin == NULL) {
+		purple_debug_error("backend-fs2",
+				"Couldn't create confbin.\n");
+		return FALSE;
+	}
+
+	g_free(name);
+
+	bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
+	if (bus == NULL) {
+		purple_debug_error("backend-fs2",
+				"Couldn't get the pipeline's bus.\n");
+		return FALSE;
+	}
+
+	g_signal_connect(G_OBJECT(bus), "message",
+			G_CALLBACK(gst_bus_cb), self);
+	gst_object_unref(bus);
+
+	if (!gst_bin_add(GST_BIN(pipeline),
+			GST_ELEMENT(priv->confbin))) {
+		purple_debug_error("backend-fs2", "Couldn't add confbin "
+				"element to the pipeline\n");
+		return FALSE;
+	}
+
+	if (!gst_bin_add(GST_BIN(priv->confbin),
+			GST_ELEMENT(priv->conference))) {
+		purple_debug_error("backend-fs2", "Couldn't add conference "
+				"element to the confbin\n");
+		return FALSE;
+	}
+
+	if (gst_element_set_state(GST_ELEMENT(priv->confbin),
+			GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
+		purple_debug_error("backend-fs2",
+				"Failed to start conference.\n");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void
+gst_element_added_cb(FsElementAddedNotifier *self,
+		GstBin *bin, GstElement *element, gpointer user_data)
+{
+	/*
+	 * Hack to make H264 work with Gmail video.
+	 */
+	if (!strncmp(GST_ELEMENT_NAME(element), "x264", 4)) {
+		g_object_set(GST_OBJECT(element), "cabac", FALSE, NULL);
+	}
+}
+
+static gboolean
+create_src(PurpleMediaBackendFs2 *self, const gchar *sess_id,
+		PurpleMediaSessionType type)
+{
+	PurpleMediaBackendFs2Private *priv =
+			PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
+	PurpleMediaBackendFs2Session *session;
+	PurpleMediaSessionType session_type;
+	FsMediaType media_type = session_type_to_fs_media_type(type);
+	FsStreamDirection type_direction =
+			session_type_to_fs_stream_direction(type);
+	GstElement *src;
+	GstPad *sinkpad, *srcpad;
+
+	if ((type_direction & FS_DIRECTION_SEND) == 0)
+		return TRUE;
+ 
+	session_type = session_type_from_fs(
+			media_type, FS_DIRECTION_SEND);
+	src = purple_media_manager_get_element(
+			purple_media_get_manager(priv->media),
+			session_type, priv->media, sess_id, NULL);
+
+	if (!GST_IS_ELEMENT(src)) {
+		purple_debug_error("backend-fs2",
+				"Error creating src for session %s\n",
+				sess_id);
+		return FALSE;
+	}
+
+	session = get_session(self, sess_id);
+
+	if (session == NULL) {
+		purple_debug_warning("backend-fs2",
+				"purple_media_set_src: trying to set"
+				" src on non-existent session\n");
+		return FALSE;
+	}
+
+	if (session->src)
+		gst_object_unref(session->src);
+
+	session->src = src;
+	gst_element_set_locked_state(session->src, TRUE);
+
+	session->tee = gst_element_factory_make("tee", NULL);
+	gst_bin_add(GST_BIN(priv->confbin), session->tee);
+
+	/* This supposedly isn't necessary, but it silences some warnings */
+	if (GST_ELEMENT_PARENT(priv->confbin)
+			== GST_ELEMENT_PARENT(session->src)) {
+		GstPad *pad = gst_element_get_static_pad(session->tee, "sink");
+		GstPad *ghost = gst_ghost_pad_new(NULL, pad);
+		gst_object_unref(pad);
+		gst_pad_set_active(ghost, TRUE);
+		gst_element_add_pad(priv->confbin, ghost);
+	}
+
+	gst_element_set_state(session->tee, GST_STATE_PLAYING);
+	gst_element_link(session->src, priv->confbin);
+
+	g_object_get(session->session, "sink-pad", &sinkpad, NULL);
+	if (session->type & PURPLE_MEDIA_SEND_AUDIO) {
+		gchar *name = g_strdup_printf("volume_%s", session->id);
+		GstElement *level;
+		GstElement *volume = gst_element_factory_make("volume", name);
+		double input_volume = purple_prefs_get_int(
+				"/purple/media/audio/volume/input")/10.0;
+		g_free(name);
+		name = g_strdup_printf("sendlevel_%s", session->id);
+		level = gst_element_factory_make("level", name);
+		g_free(name);
+		gst_bin_add(GST_BIN(priv->confbin), volume);
+		gst_bin_add(GST_BIN(priv->confbin), level);
+		gst_element_set_state(level, GST_STATE_PLAYING);
+		gst_element_set_state(volume, GST_STATE_PLAYING);
+		gst_element_link(volume, level);
+		gst_element_link(session->tee, volume);
+		srcpad = gst_element_get_static_pad(level, "src");
+		g_object_set(volume, "volume", input_volume, NULL);
+	} else {
+		srcpad = gst_element_get_request_pad(session->tee, "src%d");
+	}
+
+	purple_debug_info("backend-fs2", "connecting pad: %s\n", 
+			  gst_pad_link(srcpad, sinkpad) == GST_PAD_LINK_OK
+			  ? "success" : "failure");
+	gst_element_set_locked_state(session->src, FALSE);
+	gst_object_unref(session->src);
+
+	gst_element_set_state(session->src, GST_STATE_PLAYING);
+
+	purple_media_manager_create_output_window(purple_media_get_manager(
+			priv->media), priv->media, sess_id, NULL);
+
+	return TRUE;
+}
+
+static gboolean
+create_session(PurpleMediaBackendFs2 *self, const gchar *sess_id,
+		PurpleMediaSessionType type, gboolean initiator,
+		const gchar *transmitter)
+{
+	PurpleMediaBackendFs2Private *priv =
+			PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
+	PurpleMediaBackendFs2Session *session;
+	GError *err = NULL;
+	GList *codec_conf = NULL, *iter = NULL;
+	gchar *filename = NULL;
+	gboolean is_nice = !strcmp(transmitter, "nice");
+
+	session = g_new0(PurpleMediaBackendFs2Session, 1);
+
+	session->session = fs_conference_new_session(priv->conference,
+			session_type_to_fs_media_type(type), &err);
+
+	if (err != NULL) {
+		purple_media_error(priv->media,
+				_("Error creating session: %s"),
+				err->message);
+		g_error_free(err);
+		g_free(session);
+		return FALSE;
+	}
+
+	filename = g_build_filename(purple_user_dir(), "fs-codec.conf", NULL);
+	codec_conf = fs_codec_list_from_keyfile(filename, &err);
+	g_free(filename);
+
+	if (err != NULL) {
+		if (err->code == 4)
+			purple_debug_info("backend-fs2", "Couldn't read "
+					"fs-codec.conf: %s\n",
+					err->message);
+		else
+			purple_debug_error("backend-fs2", "Error reading "
+					"fs-codec.conf: %s\n",
+					err->message);
+		g_error_free(err);
+	}
+
+	/*
+	 * Add SPEEX if the configuration file doesn't exist or
+	 * there isn't a speex entry.
+	 */
+	for (iter = codec_conf; iter; iter = g_list_next(iter)) {
+		FsCodec *codec = iter->data;
+		if (!g_ascii_strcasecmp(codec->encoding_name, "speex"))
+			break;
+	}
+
+	if (iter == NULL) {
+		codec_conf = g_list_prepend(codec_conf,
+				fs_codec_new(FS_CODEC_ID_ANY,
+				"SPEEX", FS_MEDIA_TYPE_AUDIO, 8000));
+		codec_conf = g_list_prepend(codec_conf,
+				fs_codec_new(FS_CODEC_ID_ANY,
+				"SPEEX", FS_MEDIA_TYPE_AUDIO, 16000));
+	}
+
+	fs_session_set_codec_preferences(session->session, codec_conf, NULL);
+	fs_codec_list_destroy(codec_conf);
+
+	/*
+	 * Removes a 5-7 second delay before
+	 * receiving the src-pad-added signal.
+	 * Only works for non-multicast FsRtpSessions.
+	 */
+	if (is_nice || !strcmp(transmitter, "rawudp"))
+		g_object_set(G_OBJECT(session->session),
+				"no-rtcp-timeout", 0, NULL);
+
+	/*
+	 * Hack to make x264 work with Gmail video.
+	 */
+	if (is_nice && !strcmp(sess_id, "google-video")) {
+		FsElementAddedNotifier *notifier =
+				fs_element_added_notifier_new();
+		g_signal_connect(G_OBJECT(notifier), "element-added",
+				G_CALLBACK(gst_element_added_cb), NULL);
+		fs_element_added_notifier_add(notifier,
+				GST_BIN(priv->conference));
+	}
+
+	session->id = g_strdup(sess_id);
+	session->backend = self;
+	session->type = type;
+
+	if (!priv->sessions) {
+		purple_debug_info("backend-fs2",
+				"Creating hash table for sessions\n");
+		priv->sessions = g_hash_table_new(g_str_hash, g_str_equal);
+	}
+
+	g_hash_table_insert(priv->sessions, g_strdup(session->id), session);
+
+	if (!create_src(self, sess_id, type)) {
+		purple_debug_info("backend-fs2", "Error creating the src\n");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean
+create_participant(PurpleMediaBackendFs2 *self, const gchar *name)
+{
+	PurpleMediaBackendFs2Private *priv =
+			PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
+	FsParticipant *participant;
+	GError *err = NULL;
+
+	participant = fs_conference_new_participant(
+			priv->conference, name, &err);
+
+	if (err) {
+		purple_debug_error("backend-fs2",
+				"Error creating participant: %s\n",
+				err->message);
+		g_error_free(err);
+		return FALSE;
+	}
+
+	if (!priv->participants) {
+		purple_debug_info("backend-fs2",
+				"Creating hash table for participants\n");
+		priv->participants = g_hash_table_new_full(g_str_hash,
+				g_str_equal, g_free, NULL);
+	}
+
+	g_hash_table_insert(priv->participants, g_strdup(name), participant);
+
+	return TRUE;
+}
+
+static gboolean
+src_pad_added_cb_cb(PurpleMediaBackendFs2Stream *stream)
+{
+	PurpleMediaBackendFs2Private *priv;
+
+	g_return_val_if_fail(stream != NULL, FALSE);
+
+	priv = PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(stream->session->backend);
+	stream->connected_cb_id = 0;
+
+	purple_media_manager_create_output_window(
+			purple_media_get_manager(priv->media), priv->media,
+			stream->session->id, stream->participant);
+
+	g_signal_emit_by_name(priv->media, "state-changed",
+			PURPLE_MEDIA_STATE_CONNECTED,
+			stream->session->id, stream->participant);
+	return FALSE;
+}
+
+static void
+src_pad_added_cb(FsStream *fsstream, GstPad *srcpad,
+		FsCodec *codec, PurpleMediaBackendFs2Stream *stream)
+{
+	PurpleMediaBackendFs2Private *priv;
+	GstPad *sinkpad;
+
+	g_return_if_fail(FS_IS_STREAM(fsstream));
+	g_return_if_fail(stream != NULL);
+
+	priv = PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(stream->session->backend);
+
+	if (stream->src == NULL) {
+		GstElement *sink = NULL;
+
+		if (codec->media_type == FS_MEDIA_TYPE_AUDIO) {
+			GstElement *queue = NULL;
+			double output_volume = purple_prefs_get_int(
+					"/purple/media/audio/volume/output")/10.0;
+			/*
+			 * Should this instead be:
+			 *  audioconvert ! audioresample ! liveadder !
+			 *   audioresample ! audioconvert ! realsink
+			 */
+			queue = gst_element_factory_make("queue", NULL);
+			stream->volume = gst_element_factory_make(
+					"volume", NULL);
+			g_object_set(stream->volume, "volume",
+					output_volume, NULL);
+			stream->level = gst_element_factory_make(
+					"level", NULL);
+			stream->src = gst_element_factory_make(
+					"liveadder", NULL);
+			sink = purple_media_manager_get_element(
+					purple_media_get_manager(priv->media),
+					PURPLE_MEDIA_RECV_AUDIO, priv->media,
+					stream->session->id,
+					stream->participant);
+			gst_bin_add(GST_BIN(priv->confbin), queue);
+			gst_bin_add(GST_BIN(priv->confbin), stream->volume);
+			gst_bin_add(GST_BIN(priv->confbin), stream->level);
+			gst_bin_add(GST_BIN(priv->confbin), sink);
+			gst_element_set_state(sink, GST_STATE_PLAYING);
+			gst_element_set_state(stream->level, GST_STATE_PLAYING);
+			gst_element_set_state(stream->volume, GST_STATE_PLAYING);
+			gst_element_set_state(queue, GST_STATE_PLAYING);
+			gst_element_link(stream->level, sink);
+			gst_element_link(stream->volume, stream->level);
+			gst_element_link(queue, stream->volume);
+			sink = queue;
+		} else if (codec->media_type == FS_MEDIA_TYPE_VIDEO) {
+			stream->src = gst_element_factory_make(
+					"fsfunnel", NULL);
+			sink = gst_element_factory_make(
+					"fakesink", NULL);
+			g_object_set(G_OBJECT(sink), "async", FALSE, NULL);
+			gst_bin_add(GST_BIN(priv->confbin), sink);
+			gst_element_set_state(sink, GST_STATE_PLAYING);
+		}
+		stream->tee = gst_element_factory_make("tee", NULL);
+		gst_bin_add_many(GST_BIN(priv->confbin),
+				stream->src, stream->tee, NULL);
+		gst_element_set_state(stream->tee, GST_STATE_PLAYING);
+		gst_element_set_state(stream->src, GST_STATE_PLAYING);
+		gst_element_link_many(stream->src, stream->tee, sink, NULL);
+	}
+
+	sinkpad = gst_element_get_request_pad(stream->src, "sink%d");
+	gst_pad_link(srcpad, sinkpad);
+	gst_object_unref(sinkpad);
+
+	stream->connected_cb_id = purple_timeout_add(0,
+			(GSourceFunc)src_pad_added_cb_cb, stream);
+}
+
+static gboolean
+create_stream(PurpleMediaBackendFs2 *self,
+		const gchar *sess_id, const gchar *who,
+		PurpleMediaSessionType type, gboolean initiator,
+		const gchar *transmitter,
+		guint num_params, GParameter *params)
+{
+	PurpleMediaBackendFs2Private *priv =
+			PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
+	GError *err = NULL;
+	FsStream *fsstream = NULL;
+	const gchar *stun_ip = purple_network_get_stun_ip();
+	const gchar *turn_ip = purple_network_get_turn_ip();
+	guint _num_params = num_params;
+	GParameter *_params = g_new0(GParameter, num_params + 2);
+	FsStreamDirection type_direction =
+			session_type_to_fs_stream_direction(type);
+	PurpleMediaBackendFs2Session *session;
+	PurpleMediaBackendFs2Stream *stream;
+	FsParticipant *participant;
+
+	memcpy(_params, params, sizeof(GParameter) * num_params);
+
+	if (stun_ip) {
+		purple_debug_info("backend-fs2", 
+			"Setting stun-ip on new stream: %s\n", stun_ip);
+
+		_params[_num_params].name = "stun-ip";
+		g_value_init(&_params[_num_params].value, G_TYPE_STRING);
+		g_value_set_string(&_params[_num_params].value, stun_ip);
+		++_num_params;
+	}
+
+	if (turn_ip && !strcmp("nice", transmitter)) {
+		GValueArray *relay_info = g_value_array_new(0);
+		GValue value;
+		gint turn_port = purple_prefs_get_int(
+				"/purple/network/turn_port");
+		const gchar *username =	purple_prefs_get_string(
+				"/purple/network/turn_username");
+		const gchar *password = purple_prefs_get_string(
+				"/purple/network/turn_password");
+		GstStructure *turn_setup = gst_structure_new("relay-info",
+				"ip", G_TYPE_STRING, turn_ip, 
+				"port", G_TYPE_UINT, turn_port,
+				"username", G_TYPE_STRING, username,
+				"password", G_TYPE_STRING, password,
+				NULL);
+
+		if (!turn_setup) {
+			purple_debug_error("backend-fs2",
+					"Error creating relay info structure");
+			return FALSE;
+		}
+
+		memset(&value, 0, sizeof(GValue));
+		g_value_init(&value, GST_TYPE_STRUCTURE);
+		gst_value_set_structure(&value, turn_setup);
+		relay_info = g_value_array_append(relay_info, &value);
+		gst_structure_free(turn_setup);
+
+		purple_debug_info("backend-fs2",
+			"Setting relay-info on new stream\n");
+		_params[_num_params].name = "relay-info";
+		g_value_init(&_params[_num_params].value, 
+			G_TYPE_VALUE_ARRAY);
+		g_value_set_boxed(&_params[_num_params].value,
+			relay_info);
+		g_value_array_free(relay_info);
+	}
+
+	session = get_session(self, sess_id);
+
+	if (session == NULL) {
+		purple_debug_error("backend-fs2",
+				"Couldn't find session to create stream.\n");
+		return FALSE;
+	}
+
+	participant = get_participant(self, who);
+
+	if (participant == NULL) {
+		purple_debug_error("backend-fs2", "Couldn't find "
+				"participant to create stream.\n");
+		return FALSE;
+	}
+
+	fsstream = fs_session_new_stream(session->session, participant,
+			initiator == TRUE ? type_direction :
+			(type_direction & FS_DIRECTION_RECV), transmitter,
+			_num_params, _params, &err);
+	g_free(_params);
+
+	if (fsstream == NULL) {
+		if (err) {
+			purple_debug_error("backend-fs2",
+					"Error creating stream: %s\n",
+					err && err->message ?
+					err->message : "NULL");
+			g_error_free(err);
+		} else
+			purple_debug_error("backend-fs2",
+					"Error creating stream\n");
+		return FALSE;
+	}
+
+	stream = g_new0(PurpleMediaBackendFs2Stream, 1);
+	stream->participant = g_strdup(who);
+	stream->session = session;
+	stream->stream = fsstream;
+
+	priv->streams =	g_list_append(priv->streams, stream);
+
+	g_signal_connect(G_OBJECT(fsstream), "src-pad-added",
+			G_CALLBACK(src_pad_added_cb), stream);
+
+	return TRUE;
+}
+
+static gboolean
+purple_media_backend_fs2_add_stream(PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *who,
+		PurpleMediaSessionType type, gboolean initiator,
+		const gchar *transmitter,
+		guint num_params, GParameter *params)
+{
+	PurpleMediaBackendFs2 *backend = PURPLE_MEDIA_BACKEND_FS2(self);
+	PurpleMediaBackendFs2Private *priv =
+			PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(backend);
+	PurpleMediaBackendFs2Stream *stream;
+
+	if (priv->conference == NULL && !init_conference(backend)) {
+		purple_debug_error("backend-fs2",
+				"Error initializing the conference.\n");
+		return FALSE;
+	}
+
+	if (get_session(backend, sess_id) == NULL &&
+			!create_session(backend, sess_id, type,
+			initiator, transmitter)) {
+		purple_debug_error("backend-fs2",
+				"Error creating the session.\n");
+		return FALSE;
+	}
+
+	if (get_participant(backend, who) == NULL &&
+			!create_participant(backend, who)) {
+		purple_debug_error("backend-fs2",
+				"Error creating the participant.\n");
+		return FALSE;
+	}
+
+	stream = get_stream(backend, sess_id, who);
+
+	if (stream != NULL) {
+		FsStreamDirection type_direction =
+				session_type_to_fs_stream_direction(type);
+
+		if (session_type_to_fs_stream_direction(
+				stream->session->type) != type_direction) {
+			/* change direction */
+			g_object_set(stream->stream, "direction",
+					type_direction, NULL);
+		}
+	} else if (!create_stream(backend, sess_id, who, type,
+			initiator, transmitter, num_params, params)) {
+		purple_debug_error("backend-fs2",
+				"Error creating the stream.\n");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void
+purple_media_backend_fs2_add_remote_candidates(PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *participant,
+		GList *remote_candidates)
+{
+	PurpleMediaBackendFs2Private *priv;
+	PurpleMediaBackendFs2Stream *stream;
+	GError *err = NULL;
+
+	g_return_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self));
+
+	priv = PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
+	stream = get_stream(PURPLE_MEDIA_BACKEND_FS2(self),
+			sess_id, participant);
+
+	if (stream == NULL) {
+		purple_debug_error("backend-fs2",
+				"purple_media_add_remote_candidates: "
+				"couldn't find stream %s %s.\n",
+				sess_id ? sess_id : "(null)",
+				participant ? participant : "(null)");
+		return;
+	}
+
+	stream->remote_candidates = g_list_concat(stream->remote_candidates,
+			candidate_list_to_fs(remote_candidates));
+
+	if (purple_media_is_initiator(priv->media, sess_id, participant) ||
+			purple_media_accepted(
+			priv->media, sess_id, participant)) {
+		fs_stream_set_remote_candidates(stream->stream,
+				stream->remote_candidates, &err);
+
+		if (err) {
+			purple_debug_error("backend-fs2", "Error adding remote"
+					" candidates: %s\n", err->message);
+			g_error_free(err);
+		}
+	}
+}
+
+static gboolean
+purple_media_backend_fs2_codecs_ready(PurpleMediaBackend *self,
+		const gchar *sess_id)
+{
+	PurpleMediaBackendFs2Private *priv;
+	gboolean ret;
+
+	g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self), FALSE);
+
+	priv = PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
+
+	if (sess_id != NULL) {
+		PurpleMediaBackendFs2Session *session = get_session(
+				PURPLE_MEDIA_BACKEND_FS2(self), sess_id);
+
+		if (session == NULL)
+			return FALSE;
+
+		if (session->type & (PURPLE_MEDIA_SEND_AUDIO |
+				PURPLE_MEDIA_SEND_VIDEO))
+			g_object_get(session->session,
+					"codecs-ready", &ret, NULL);
+		else
+			ret = TRUE;
+	} else {
+		GList *values = g_hash_table_get_values(priv->sessions);
+
+		for (; values; values = g_list_delete_link(values, values)) {
+			PurpleMediaBackendFs2Session *session = values->data;
+			if (session->type & (PURPLE_MEDIA_SEND_AUDIO |
+					PURPLE_MEDIA_SEND_VIDEO))
+				g_object_get(session->session,
+						"codecs-ready", &ret, NULL);
+			else
+				ret = TRUE;
+
+			if (ret == FALSE)
+				break;
+		}
+
+		if (values != NULL)
+			g_list_free(values);
+	}
+
+	return ret;
+}
+
+static GList *
+purple_media_backend_fs2_get_codecs(PurpleMediaBackend *self,
+		const gchar *sess_id)
+{
+	PurpleMediaBackendFs2Private *priv;
+	PurpleMediaBackendFs2Session *session;
+	GList *fscodecs;
+	GList *codecs;
+
+	g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self), NULL);
+
+	priv = PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
+
+	session = get_session(PURPLE_MEDIA_BACKEND_FS2(self), sess_id);
+
+	if (session == NULL)
+		return NULL;
+
+	g_object_get(G_OBJECT(session->session),
+		     "codecs", &fscodecs, NULL);
+	codecs = codec_list_from_fs(fscodecs);
+	fs_codec_list_destroy(fscodecs);
+
+	return codecs;
+}
+
+static GList *
+purple_media_backend_fs2_get_local_candidates(PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *participant)
+{
+	PurpleMediaBackendFs2Stream *stream;
+	GList *candidates = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self), NULL);
+
+	stream = get_stream(PURPLE_MEDIA_BACKEND_FS2(self),
+			sess_id, participant);
+
+	if (stream != NULL)
+		candidates = candidate_list_from_fs(
+				stream->local_candidates);
+	return candidates;
+}
+
+static gboolean
+purple_media_backend_fs2_set_remote_codecs(PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *participant,
+		GList *codecs)
+{
+	PurpleMediaBackendFs2Stream *stream;
+	GList *fscodecs;
+	GError *err = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self), FALSE);
+	stream = get_stream(PURPLE_MEDIA_BACKEND_FS2(self),
+			sess_id, participant);
+
+	if (stream == NULL)
+		return FALSE;
+
+	fscodecs = codec_list_to_fs(codecs);
+	fs_stream_set_remote_codecs(stream->stream, fscodecs, &err);
+	fs_codec_list_destroy(fscodecs);
+
+	if (err) {
+		purple_debug_error("backend-fs2",
+				"Error setting remote codecs: %s\n",
+				err->message);
+		g_error_free(err);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean
+purple_media_backend_fs2_set_send_codec(PurpleMediaBackend *self,
+		const gchar *sess_id, PurpleMediaCodec *codec)
+{
+	PurpleMediaBackendFs2Session *session;
+	FsCodec *fscodec;
+	GError *err = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self), FALSE);
+
+	session = get_session(PURPLE_MEDIA_BACKEND_FS2(self), sess_id);
+
+	if (session == NULL)
+		return FALSE;
+
+	fscodec = codec_to_fs(codec);
+	fs_session_set_send_codec(session->session, fscodec, &err);
+	fs_codec_destroy(fscodec);
+
+	if (err) {
+		purple_debug_error("media", "Error setting send codec\n");
+		g_error_free(err);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+#else
+GType
+purple_media_backend_fs2_get_type(void)
+{
+	return G_TYPE_NONE;
+}
+#endif /* USE_VV */
+
+#ifdef USE_GSTREAMER
+GstElement *
+purple_media_backend_fs2_get_src(PurpleMediaBackendFs2 *self,
+		const gchar *sess_id)
+{
+#ifdef USE_VV
+	PurpleMediaBackendFs2Session *session = get_session(self, sess_id);
+	return session != NULL ? session->src : NULL;
+#else
+	return NULL;
+#endif
+}
+
+GstElement *
+purple_media_backend_fs2_get_tee(PurpleMediaBackendFs2 *self,
+		const gchar *sess_id, const gchar *who)
+{
+#ifdef USE_VV
+	if (sess_id != NULL && who == NULL) {
+		PurpleMediaBackendFs2Session *session =
+				get_session(self, sess_id);
+		return (session != NULL) ? session->tee : NULL;
+	} else if (sess_id != NULL && who != NULL) {
+		PurpleMediaBackendFs2Stream *stream =
+				get_stream(self, sess_id, who);
+		return (stream != NULL) ? stream->tee : NULL;
+	}
+
+#endif /* USE_VV */
+	g_return_val_if_reached(NULL);
+}
+
+void
+purple_media_backend_fs2_set_input_volume(PurpleMediaBackendFs2 *self,
+		const gchar *sess_id, double level)
+{
+#ifdef USE_VV
+	PurpleMediaBackendFs2Private *priv;
+	GList *sessions;
+
+	g_return_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self));
+
+	priv = PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
+
+	purple_prefs_set_int("/purple/media/audio/volume/input", level);
+
+	if (sess_id == NULL)
+		sessions = g_hash_table_get_values(priv->sessions);
+	else
+		sessions = g_list_append(NULL, get_session(self, sess_id));
+
+	for (; sessions; sessions = g_list_delete_link(sessions, sessions)) {
+		PurpleMediaBackendFs2Session *session = sessions->data;
+
+		if (session->type & PURPLE_MEDIA_SEND_AUDIO) {
+			gchar *name = g_strdup_printf("volume_%s",
+					session->id);
+			GstElement *volume = gst_bin_get_by_name(
+					GST_BIN(priv->confbin), name);
+			g_free(name);
+			g_object_set(volume, "volume", level/10.0, NULL);
+		}
+	}
+#endif /* USE_VV */
+}
+
+void
+purple_media_backend_fs2_set_output_volume(PurpleMediaBackendFs2 *self,
+		const gchar *sess_id, const gchar *who, double level)
+{
+#ifdef USE_VV
+	PurpleMediaBackendFs2Private *priv;
+	GList *streams;
+
+	g_return_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self));
+
+	priv = PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
+
+	purple_prefs_set_int("/purple/media/audio/volume/output", level);
+
+	streams = get_streams(self, sess_id, who);
+
+	for (; streams; streams = g_list_delete_link(streams, streams)) {
+		PurpleMediaBackendFs2Stream *stream = streams->data;
+
+		if (stream->session->type & PURPLE_MEDIA_RECV_AUDIO
+				&& GST_IS_ELEMENT(stream->volume)) {
+			g_object_set(stream->volume, "volume",
+					level/10.0, NULL);
+		}
+	}
+#endif /* USE_VV */
+}
+#endif /* USE_GSTREAMER */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/media/backend-fs2.h	Thu Feb 04 05:30:35 2010 +0000
@@ -0,0 +1,77 @@
+/**
+ * @file backend-fs2.h Farsight 2 backend for media API
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This 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 Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+/*
+ * This file should not yet be part of libpurple's API.
+ * It should remain internal only for now.
+ */
+
+#ifndef _MEDIA_BACKEND_FS2_H_
+#define _MEDIA_BACKEND_FS2_H_
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define PURPLE_TYPE_MEDIA_BACKEND_FS2            (purple_media_backend_fs2_get_type())
+#define PURPLE_IS_MEDIA_BACKEND_FS2(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_MEDIA_BACKEND_FS2))
+#define PURPLE_IS_MEDIA_BACKEND_FS2_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_MEDIA_BACKEND_FS2))
+#define PURPLE_MEDIA_BACKEND_FS2(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_MEDIA_BACKEND_FS2, PurpleMediaBackendFs2))
+#define PURPLE_MEDIA_BACKEND_FS2_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_MEDIA_BACKEND_FS2, PurpleMediaBackendFs2))
+#define PURPLE_MEDIA_BACKEND_FS2_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_MEDIA_BACKEND_FS2, PurpleMediaBackendFs2))
+
+/** An opaque structure representing the Farsight 2 media backend. */
+typedef struct _PurpleMediaBackendFs2 PurpleMediaBackendFs2;
+
+/**
+ * Gets the type of the Farsight 2 media backend object.
+ *
+ * @return The Farsight 2 media backend's GType
+ *
+ * @since 2.7.0
+ */
+GType purple_media_backend_fs2_get_type(void);
+
+/*
+ * Temporary function in order to be able to test while
+ * integrating with PurpleMedia
+ */
+#include <gst/gst.h>
+GstElement *purple_media_backend_fs2_get_src(
+		PurpleMediaBackendFs2 *self,
+		const gchar *sess_id);
+GstElement *purple_media_backend_fs2_get_tee(
+		PurpleMediaBackendFs2 *self,
+		const gchar *sess_id, const gchar *who);
+void purple_media_backend_fs2_set_input_volume(PurpleMediaBackendFs2 *self,
+		const gchar *sess_id, double level);
+void purple_media_backend_fs2_set_output_volume(PurpleMediaBackendFs2 *self,
+		const gchar *sess_id, const gchar *who, double level);
+/* end tmp */
+
+G_END_DECLS
+
+#endif /* _MEDIA_BACKEND_FS2_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/media/backend-iface.c	Thu Feb 04 05:30:35 2010 +0000
@@ -0,0 +1,194 @@
+/**
+ * @file backend-iface.c Interface for media backend
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This 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 Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "backend-iface.h"
+
+#include "marshallers.h"
+
+enum {
+	S_ERROR,
+	CANDIDATES_PREPARED,
+	CODECS_CHANGED,
+	NEW_CANDIDATE,
+	ACTIVE_CANDIDATE_PAIR,
+	LAST_SIGNAL
+};
+
+static guint purple_media_backend_signals[LAST_SIGNAL] = {0};
+
+static void
+purple_media_backend_base_init(gpointer iface)
+{
+	static gboolean is_initialized = FALSE;
+
+	if (is_initialized)
+		return;
+
+	g_object_interface_install_property(iface,
+			g_param_spec_string("conference-type",
+			"Conference Type",
+			"The type of conference that this backend "
+			"has been created to provide.",
+			NULL,
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+	g_object_interface_install_property(iface,
+			g_param_spec_object("media",
+			"Purple Media",
+			"The media object that this backend is bound to.",
+			PURPLE_TYPE_MEDIA,
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+	purple_media_backend_signals[S_ERROR] =
+			g_signal_new("error", G_TYPE_FROM_CLASS(iface),
+			G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+			g_cclosure_marshal_VOID__STRING,
+			G_TYPE_NONE, 1, G_TYPE_STRING);
+	purple_media_backend_signals[CANDIDATES_PREPARED] =
+			g_signal_new("candidates-prepared",
+			G_TYPE_FROM_CLASS(iface),
+			G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+			purple_smarshal_VOID__STRING_STRING,
+			G_TYPE_NONE, 2, G_TYPE_STRING,
+			G_TYPE_STRING);
+	purple_media_backend_signals[CODECS_CHANGED] =
+			g_signal_new("codecs-changed",
+			G_TYPE_FROM_CLASS(iface),
+			G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+			g_cclosure_marshal_VOID__STRING,
+			G_TYPE_NONE, 1, G_TYPE_STRING);
+	purple_media_backend_signals[NEW_CANDIDATE] =
+			g_signal_new("new-candidate",
+			G_TYPE_FROM_CLASS(iface),
+			G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+			purple_smarshal_VOID__POINTER_POINTER_OBJECT,
+			G_TYPE_NONE, 3, G_TYPE_POINTER,
+			G_TYPE_POINTER, PURPLE_TYPE_MEDIA_CANDIDATE);
+	purple_media_backend_signals[ACTIVE_CANDIDATE_PAIR] =
+			g_signal_new("active-candidate-pair",
+			G_TYPE_FROM_CLASS(iface),
+			G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+			purple_smarshal_VOID__STRING_STRING_OBJECT_OBJECT,
+			G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_STRING,
+			PURPLE_TYPE_MEDIA_CANDIDATE,
+			PURPLE_TYPE_MEDIA_CANDIDATE);
+
+	is_initialized = TRUE;
+}
+
+GType
+purple_media_backend_get_type(void)
+{
+	static GType iface_type = 0;
+	if (iface_type == 0) {
+		static const GTypeInfo info = {
+			sizeof(PurpleMediaBackendIface),
+			purple_media_backend_base_init,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			0,
+			0,
+			NULL,
+			NULL
+		};
+
+		iface_type = g_type_register_static (G_TYPE_INTERFACE,
+				"PurpleMediaBackend", &info, 0);
+	}
+
+	return iface_type;
+}
+
+gboolean
+purple_media_backend_add_stream(PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *who,
+		PurpleMediaSessionType type, gboolean initiator,
+		const gchar *transmitter,
+		guint num_params, GParameter *params)
+{
+	g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND(self), FALSE);
+	return PURPLE_MEDIA_BACKEND_GET_INTERFACE(self)->add_stream(self,
+			sess_id, who, type, initiator, transmitter,
+			num_params, params);
+}
+
+void
+purple_media_backend_add_remote_candidates(PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *participant,
+		GList *remote_candidates)
+{
+	g_return_if_fail(PURPLE_IS_MEDIA_BACKEND(self));
+	PURPLE_MEDIA_BACKEND_GET_INTERFACE(self)->add_remote_candidates(self,
+			sess_id, participant, remote_candidates);
+}
+
+gboolean
+purple_media_backend_codecs_ready(PurpleMediaBackend *self,
+		const gchar *sess_id)
+{
+	g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND(self), FALSE);
+	return PURPLE_MEDIA_BACKEND_GET_INTERFACE(self)->codecs_ready(self,
+			sess_id);
+}
+
+GList *
+purple_media_backend_get_codecs(PurpleMediaBackend *self,
+		const gchar *sess_id)
+{
+	g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND(self), NULL);
+	return PURPLE_MEDIA_BACKEND_GET_INTERFACE(self)->get_codecs(self,
+			sess_id);
+}
+
+GList *
+purple_media_backend_get_local_candidates(PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *participant)
+{
+	g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND(self), NULL);
+	return PURPLE_MEDIA_BACKEND_GET_INTERFACE(self)->
+			get_local_candidates(self,
+			sess_id, participant);
+}
+
+gboolean
+purple_media_backend_set_remote_codecs(PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *participant,
+		GList *codecs)
+{
+	g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND(self), FALSE);
+	return PURPLE_MEDIA_BACKEND_GET_INTERFACE(self)->set_remote_codecs(
+			self, sess_id, participant, codecs);
+}
+
+gboolean
+purple_media_backend_set_send_codec(PurpleMediaBackend *self,
+		const gchar *sess_id, PurpleMediaCodec *codec)
+{
+	g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND(self), FALSE);
+	return PURPLE_MEDIA_BACKEND_GET_INTERFACE(self)->set_send_codec(self,
+			sess_id, codec);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/media/backend-iface.h	Thu Feb 04 05:30:35 2010 +0000
@@ -0,0 +1,196 @@
+/**
+ * @file backend-iface.h Interface for media backends
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This 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 Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef _MEDIA_BACKEND_IFACE_H_
+#define _MEDIA_BACKEND_IFACE_H_
+
+#include "codec.h"
+#include "enum-types.h"
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define PURPLE_TYPE_MEDIA_BACKEND		(purple_media_backend_get_type())
+#define PURPLE_IS_MEDIA_BACKEND(obj)		(G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_MEDIA_BACKEND))
+#define PURPLE_MEDIA_BACKEND(obj)		(G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_MEDIA_BACKEND, PurpleMediaBackend))
+#define PURPLE_MEDIA_BACKEND_GET_INTERFACE(inst)(G_TYPE_INSTANCE_GET_INTERFACE((inst), PURPLE_TYPE_MEDIA_BACKEND, PurpleMediaBackendIface))
+
+/** A placeholder to represent any media backend */
+typedef struct _PurpleMediaBackend PurpleMediaBackend;
+/** A structure to derive media backends from. */
+typedef struct _PurpleMediaBackendIface PurpleMediaBackendIface;
+
+struct _PurpleMediaBackendIface
+{
+	GTypeInterface parent_iface; /**< The parent iface class */ 
+
+	/** Implementable functions called with purple_media_backend_* */
+	gboolean (*add_stream) (PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *who,
+		PurpleMediaSessionType type, gboolean initiator,
+		const gchar *transmitter,
+		guint num_params, GParameter *params);
+	void (*add_remote_candidates) (PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *participant,
+		GList *remote_candidates);
+	gboolean (*codecs_ready) (PurpleMediaBackend *self,
+		const gchar *sess_id);
+	GList *(*get_codecs) (PurpleMediaBackend *self,
+		const gchar *sess_id);
+	GList *(*get_local_candidates) (PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *participant);
+	gboolean (*set_remote_codecs) (PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *participant,
+		GList *codecs);
+	gboolean (*set_send_codec) (PurpleMediaBackend *self,
+		const gchar *sess_id, PurpleMediaCodec *codec);
+};
+
+/**
+ * Gets the media backend's GType.
+ *
+ * @return The media backend's GType.
+ *
+ * @since 2.7.0
+ */
+GType purple_media_backend_get_type(void);
+
+/**
+ * Creates and adds a stream to the media backend.
+ *
+ * @param self The backend to add the stream to.
+ * @param sess_id The session id of the stream to add.
+ * @param who The remote participant of the stream to add.
+ * @param type The media type and direction of the stream to add.
+ * @param initiator True if the local user initiated the stream.
+ * @param transmitter The string id of the tranmsitter to use.
+ * @param num_params The number of parameters in the param parameter.
+ * @param params The additional parameters to pass when creating the stream.
+ *
+ * @return True if the stream was successfully created, othewise False.
+ *
+ * @since 2.7.0
+ */
+gboolean purple_media_backend_add_stream(PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *who,
+		PurpleMediaSessionType type, gboolean initiator,
+		const gchar *transmitter,
+		guint num_params, GParameter *params);
+
+/**
+ * Add remote candidates to a stream.
+ *
+ * @param self The backend the stream is in.
+ * @param sess_id The session id associated with the stream.
+ * @param participant The participant associated with the stream.
+ * @param remote_candidates The list of remote candidates to add.
+ *
+ * @since 2.7.0
+ */
+void purple_media_backend_add_remote_candidates(PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *participant,
+		GList *remote_candidates);
+
+/**
+ * Get whether or not a session's codecs are ready.
+ *
+ * A codec is ready if all of the attributes and additional
+ * parameters have been collected.
+ *
+ * @param self The media backend the session is in.
+ * @param sess_id The session id of the session to check.
+ *
+ * @return True if the codecs are ready, otherwise False.
+ *
+ * @since 2.7.0
+ */
+gboolean purple_media_backend_codecs_ready(PurpleMediaBackend *self,
+		const gchar *sess_id);
+
+/**
+ * Gets the codec intersection list for a session.
+ *
+ * The intersection list consists of all codecs that are compatible
+ * between the local and remote software.
+ *
+ * @param self The media backend the session is in.
+ * @param sess_id The session id of the session to use.
+ *
+ * @return The codec intersection list.
+ *
+ * @since 2.7.0
+ */
+GList *purple_media_backend_get_codecs(PurpleMediaBackend *self,
+		const gchar *sess_id);
+
+/**
+ * Gets the list of local candidates for a stream.
+ *
+ * @param self The media backend the stream is in.
+ * @param sess_id The session id associated with the stream.
+ * @param particilant The participant associated with the stream.
+ *
+ * @return The list of local candidates.
+ *
+ * @since 2.7.0
+ */
+GList *purple_media_backend_get_local_candidates(PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *participant);
+
+/**
+ * Sets the remote codecs on a stream.
+ *
+ * @param self The media backend the stream is in.
+ * @param sess_id The session id the stream is associated with.
+ * @param participant The participant the stream is associated with.
+ * @param codecs The list of remote codecs to set.
+ *
+ * @return True if the remote codecs were set successfully, otherwise False.
+ *
+ * @since 2.7.0
+ */
+gboolean purple_media_backend_set_remote_codecs(PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *participant,
+		GList *codecs);
+
+/**
+ * Sets which codec format to send media content in for a session.
+ *
+ * @param self The media backend the session is in.
+ * @param sess_id The session id of the session to set the codec for.
+ * @param codec The codec to set.
+ *
+ * @return True if set successfully, otherwise False.
+ *
+ * @since 2.7.0
+ */
+gboolean purple_media_backend_set_send_codec(PurpleMediaBackend *self,
+		const gchar *sess_id, PurpleMediaCodec *codec);
+
+G_END_DECLS
+
+#endif /* _MEDIA_BACKEND_IFACE_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/media/candidate.c	Thu Feb 04 05:30:35 2010 +0000
@@ -0,0 +1,495 @@
+/**
+ * @file candidate.c Candidate for Media API
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This 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 Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "candidate.h"
+
+/** @copydoc _PurpleMediaCandidateClass */
+typedef struct _PurpleMediaCandidateClass PurpleMediaCandidateClass;
+/** @copydoc _PurpleMediaCandidatePrivate */
+typedef struct _PurpleMediaCandidatePrivate PurpleMediaCandidatePrivate;
+
+#define PURPLE_MEDIA_CANDIDATE_GET_PRIVATE(obj) \
+		(G_TYPE_INSTANCE_GET_PRIVATE((obj), \
+		PURPLE_TYPE_MEDIA_CANDIDATE, \
+		PurpleMediaCandidatePrivate))
+
+
+struct _PurpleMediaCandidateClass
+{
+	GObjectClass parent_class;
+};
+
+struct _PurpleMediaCandidate
+{
+	GObject parent;
+};
+
+G_DEFINE_TYPE(PurpleMediaCandidate, purple_media_candidate, G_TYPE_OBJECT);
+
+struct _PurpleMediaCandidatePrivate
+{
+	gchar *foundation;
+	guint component_id;
+	gchar *ip;
+	guint16 port;
+	gchar *base_ip;
+	guint16 base_port;
+	PurpleMediaNetworkProtocol proto;
+	guint32 priority;
+	PurpleMediaCandidateType type;
+	gchar *username;
+	gchar *password;
+	guint ttl;
+};
+
+enum {
+	PROP_CANDIDATE_0,
+	PROP_FOUNDATION,
+	PROP_COMPONENT_ID,
+	PROP_IP,
+	PROP_PORT,
+	PROP_BASE_IP,
+	PROP_BASE_PORT,
+	PROP_PROTOCOL,
+	PROP_PRIORITY,
+	PROP_TYPE,
+	PROP_USERNAME,
+	PROP_PASSWORD,
+	PROP_TTL,
+};
+
+static void
+purple_media_candidate_init(PurpleMediaCandidate *info)
+{
+	PurpleMediaCandidatePrivate *priv =
+			PURPLE_MEDIA_CANDIDATE_GET_PRIVATE(info);
+	priv->foundation = NULL;
+	priv->component_id = 0;
+	priv->ip = NULL;
+	priv->port = 0;
+	priv->base_ip = NULL;
+	priv->proto = PURPLE_MEDIA_NETWORK_PROTOCOL_UDP;
+	priv->priority = 0;
+	priv->type = PURPLE_MEDIA_CANDIDATE_TYPE_HOST;
+	priv->username = NULL;
+	priv->password = NULL;
+	priv->ttl = 0;
+}
+
+static void
+purple_media_candidate_finalize(GObject *info)
+{
+	PurpleMediaCandidatePrivate *priv =
+			PURPLE_MEDIA_CANDIDATE_GET_PRIVATE(info);
+
+	g_free(priv->foundation);
+	g_free(priv->ip);
+	g_free(priv->base_ip);
+	g_free(priv->username);
+	g_free(priv->password);
+}
+
+static void
+purple_media_candidate_set_property (GObject *object, guint prop_id,
+		const GValue *value, GParamSpec *pspec)
+{
+	PurpleMediaCandidatePrivate *priv;
+	g_return_if_fail(PURPLE_IS_MEDIA_CANDIDATE(object));
+
+	priv = PURPLE_MEDIA_CANDIDATE_GET_PRIVATE(object);
+
+	switch (prop_id) {
+		case PROP_FOUNDATION:
+			g_free(priv->foundation);
+			priv->foundation = g_value_dup_string(value);
+			break;
+		case PROP_COMPONENT_ID:
+			priv->component_id = g_value_get_uint(value);
+			break;
+		case PROP_IP:
+			g_free(priv->ip);
+			priv->ip = g_value_dup_string(value);
+			break;
+		case PROP_PORT:
+			priv->port = g_value_get_uint(value);
+			break;
+		case PROP_BASE_IP:
+			g_free(priv->base_ip);
+			priv->base_ip = g_value_dup_string(value);
+			break;
+		case PROP_BASE_PORT:
+			priv->base_port = g_value_get_uint(value);
+			break;
+		case PROP_PROTOCOL:
+			priv->proto = g_value_get_enum(value);
+			break;
+		case PROP_PRIORITY:
+			priv->priority = g_value_get_uint(value);
+			break;
+		case PROP_TYPE:
+			priv->type = g_value_get_enum(value);
+			break;
+		case PROP_USERNAME:
+			g_free(priv->username);
+			priv->username = g_value_dup_string(value);
+			break;
+		case PROP_PASSWORD:
+			g_free(priv->password);
+			priv->password = g_value_dup_string(value);
+			break;
+		case PROP_TTL:
+			priv->ttl = g_value_get_uint(value);
+			break;
+		default:	
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(
+					object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_media_candidate_get_property (GObject *object, guint prop_id,
+		GValue *value, GParamSpec *pspec)
+{
+	PurpleMediaCandidatePrivate *priv;
+	g_return_if_fail(PURPLE_IS_MEDIA_CANDIDATE(object));
+	
+	priv = PURPLE_MEDIA_CANDIDATE_GET_PRIVATE(object);
+
+	switch (prop_id) {
+		case PROP_FOUNDATION:
+			g_value_set_string(value, priv->foundation);
+			break;
+		case PROP_COMPONENT_ID:
+			g_value_set_uint(value, priv->component_id);
+			break;
+		case PROP_IP:
+			g_value_set_string(value, priv->ip);
+			break;
+		case PROP_PORT:
+			g_value_set_uint(value, priv->port);
+			break;
+		case PROP_BASE_IP:
+			g_value_set_string(value, priv->base_ip);
+			break;
+		case PROP_BASE_PORT:
+			g_value_set_uint(value, priv->base_port);
+			break;
+		case PROP_PROTOCOL:
+			g_value_set_enum(value, priv->proto);
+			break;
+		case PROP_PRIORITY:
+			g_value_set_uint(value, priv->priority);
+			break;
+		case PROP_TYPE:
+			g_value_set_enum(value, priv->type);
+			break;
+		case PROP_USERNAME:
+			g_value_set_string(value, priv->username);
+			break;
+		case PROP_PASSWORD:
+			g_value_set_string(value, priv->password);
+			break;
+		case PROP_TTL:
+			g_value_set_uint(value, priv->ttl);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(
+					object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_media_candidate_class_init(PurpleMediaCandidateClass *klass)
+{
+	GObjectClass *gobject_class = (GObjectClass*)klass;
+	
+	gobject_class->finalize = purple_media_candidate_finalize;
+	gobject_class->set_property = purple_media_candidate_set_property;
+	gobject_class->get_property = purple_media_candidate_get_property;
+
+	g_object_class_install_property(gobject_class, PROP_FOUNDATION,
+			g_param_spec_string("foundation",
+			"Foundation",
+			"The foundation of the candidate.",
+			NULL,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_COMPONENT_ID,
+			g_param_spec_uint("component-id",
+			"Component ID",
+			"The component id of the candidate.",
+			0, G_MAXUINT, 0,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_IP,
+			g_param_spec_string("ip",
+			"IP Address",
+			"The IP address of the candidate.",
+			NULL,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_PORT,
+			g_param_spec_uint("port",
+			"Port",
+			"The port of the candidate.",
+			0, G_MAXUINT16, 0,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_BASE_IP,
+			g_param_spec_string("base-ip",
+			"Base IP",
+			"The internal IP address of the candidate.",
+			NULL,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_BASE_PORT,
+			g_param_spec_uint("base-port",
+			"Base Port",
+			"The internal port of the candidate.",
+			0, G_MAXUINT16, 0,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_PROTOCOL,
+			g_param_spec_enum("protocol",
+			"Protocol",
+			"The protocol of the candidate.",
+			PURPLE_TYPE_MEDIA_NETWORK_PROTOCOL,
+			PURPLE_MEDIA_NETWORK_PROTOCOL_UDP,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_PRIORITY,
+			g_param_spec_uint("priority",
+			"Priority",
+			"The priority of the candidate.",
+			0, G_MAXUINT32, 0,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_TYPE,
+			g_param_spec_enum("type",
+			"Type",
+			"The type of the candidate.",
+			PURPLE_TYPE_MEDIA_CANDIDATE_TYPE,
+			PURPLE_MEDIA_CANDIDATE_TYPE_HOST,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_USERNAME,
+			g_param_spec_string("username",
+			"Username",
+			"The username used to connect to the candidate.",
+			NULL,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_PASSWORD,
+			g_param_spec_string("password",
+			"Password",
+			"The password use to connect to the candidate.",
+			NULL,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_TTL,
+			g_param_spec_uint("ttl",
+			"TTL",
+			"The TTL of the candidate.",
+			0, G_MAXUINT, 0,
+			G_PARAM_READWRITE));
+
+	g_type_class_add_private(klass, sizeof(PurpleMediaCandidatePrivate));
+}
+
+PurpleMediaCandidate *
+purple_media_candidate_new(const gchar *foundation, guint component_id,
+		PurpleMediaCandidateType type,
+		PurpleMediaNetworkProtocol proto,
+		const gchar *ip, guint port)
+{
+	return g_object_new(PURPLE_TYPE_MEDIA_CANDIDATE,
+			"foundation", foundation,
+			"component-id", component_id,
+			"type", type,
+			"protocol", proto,
+			"ip", ip,
+			"port", port, NULL);
+}
+
+PurpleMediaCandidate *
+purple_media_candidate_copy(PurpleMediaCandidate *candidate)
+{
+	PurpleMediaCandidatePrivate *priv;
+	PurpleMediaCandidate *new_candidate;
+
+	if (candidate == NULL)
+		return NULL;
+
+	priv = PURPLE_MEDIA_CANDIDATE_GET_PRIVATE(candidate);
+
+	new_candidate = purple_media_candidate_new(priv->foundation,
+			priv->component_id, priv->type, priv->proto,
+			priv->ip, priv->port);
+	g_object_set(new_candidate,
+			"base-ip", priv->base_ip,
+			"base-port", priv->base_port,
+			"priority", priv->priority,
+			"username", priv->username,
+			"password", priv->password,
+			"ttl", priv->ttl, NULL);
+	return new_candidate;
+}
+
+GList *
+purple_media_candidate_list_copy(GList *candidates)
+{
+	GList *new_list = NULL;
+
+	for (; candidates; candidates = g_list_next(candidates)) {
+		new_list = g_list_prepend(new_list,
+				purple_media_candidate_copy(candidates->data));
+	}
+
+	new_list = g_list_reverse(new_list);
+	return new_list;
+}
+
+void
+purple_media_candidate_list_free(GList *candidates)
+{
+	for (; candidates; candidates =
+			g_list_delete_link(candidates, candidates)) {
+		g_object_unref(candidates->data);
+	}
+}
+
+gchar *
+purple_media_candidate_get_foundation(PurpleMediaCandidate *candidate)
+{
+	gchar *foundation;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), NULL);
+	g_object_get(candidate, "foundation", &foundation, NULL);
+	return foundation;
+}
+
+guint
+purple_media_candidate_get_component_id(PurpleMediaCandidate *candidate)
+{
+	guint component_id;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), 0);
+	g_object_get(candidate, "component-id", &component_id, NULL);
+	return component_id;
+}
+
+gchar *
+purple_media_candidate_get_ip(PurpleMediaCandidate *candidate)
+{
+	gchar *ip;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), NULL);
+	g_object_get(candidate, "ip", &ip, NULL);
+	return ip;
+}
+
+guint16
+purple_media_candidate_get_port(PurpleMediaCandidate *candidate)
+{
+	guint port;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), 0);
+	g_object_get(candidate, "port", &port, NULL);
+	return port;
+}
+
+gchar *
+purple_media_candidate_get_base_ip(PurpleMediaCandidate *candidate)
+{
+	gchar *base_ip;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), NULL);
+	g_object_get(candidate, "base-ip", &base_ip, NULL);
+	return base_ip;
+}
+
+guint16
+purple_media_candidate_get_base_port(PurpleMediaCandidate *candidate)
+{
+	guint base_port;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), 0);
+	g_object_get(candidate, "base_port", &base_port, NULL);
+	return base_port;
+}
+
+PurpleMediaNetworkProtocol
+purple_media_candidate_get_protocol(PurpleMediaCandidate *candidate)
+{
+	PurpleMediaNetworkProtocol protocol;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate),
+			PURPLE_MEDIA_NETWORK_PROTOCOL_UDP);
+	g_object_get(candidate, "protocol", &protocol, NULL);
+	return protocol;
+}
+
+guint32
+purple_media_candidate_get_priority(PurpleMediaCandidate *candidate)
+{
+	guint priority;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), 0);
+	g_object_get(candidate, "priority", &priority, NULL);
+	return priority;
+}
+
+PurpleMediaCandidateType
+purple_media_candidate_get_candidate_type(PurpleMediaCandidate *candidate)
+{
+	PurpleMediaCandidateType type;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate),
+			PURPLE_MEDIA_CANDIDATE_TYPE_HOST);
+	g_object_get(candidate, "type", &type, NULL);
+	return type;
+}
+
+gchar *
+purple_media_candidate_get_username(PurpleMediaCandidate *candidate)
+{
+	gchar *username;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), NULL);
+	g_object_get(candidate, "username", &username, NULL);
+	return username;
+}
+
+gchar *
+purple_media_candidate_get_password(PurpleMediaCandidate *candidate)
+{
+	gchar *password;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), NULL);
+	g_object_get(candidate, "password", &password, NULL);
+	return password;
+}
+
+guint
+purple_media_candidate_get_ttl(PurpleMediaCandidate *candidate)
+{
+	guint ttl;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_CANDIDATE(candidate), 0);
+	g_object_get(candidate, "ttl", &ttl, NULL);
+	return ttl;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/media/candidate.h	Thu Feb 04 05:30:35 2010 +0000
@@ -0,0 +1,252 @@
+/**
+ * @file candidate.h Candidate for Media API
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This 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 Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef _PURPLE_MEDIA_CANDIDATE_H_
+#define _PURPLE_MEDIA_CANDIDATE_H_
+
+#include "enum-types.h"
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define PURPLE_TYPE_MEDIA_CANDIDATE            (purple_media_candidate_get_type())
+#define PURPLE_IS_MEDIA_CANDIDATE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_MEDIA_CANDIDATE))
+#define PURPLE_IS_MEDIA_CANDIDATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_MEDIA_CANDIDATE))
+#define PURPLE_MEDIA_CANDIDATE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_MEDIA_CANDIDATE, PurpleMediaCandidate))
+#define PURPLE_MEDIA_CANDIDATE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_MEDIA_CANDIDATE, PurpleMediaCandidate))
+#define PURPLE_MEDIA_CANDIDATE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_MEDIA_CANDIDATE, PurpleMediaCandidate))
+
+/** An opaque structure representing a network candidate (IP Address and port pair). */
+typedef struct _PurpleMediaCandidate PurpleMediaCandidate;
+
+/**
+ * Gets the type of the media candidate structure.
+ *
+ * @return The media canditate's GType
+ *
+ * @since 2.6.0
+ */
+GType purple_media_candidate_get_type(void);
+
+/**
+ * Creates a PurpleMediaCandidate instance.
+ *
+ * @param foundation The foundation of the candidate.
+ * @param component_id The component this candidate is for.
+ * @param type The type of candidate.
+ * @param proto The protocol this component is for.
+ * @param ip The IP address of this component.
+ * @param port The network port.
+ *
+ * @return The newly created PurpleMediaCandidate instance.
+ *
+ * @since 2.6.0
+ */
+PurpleMediaCandidate *purple_media_candidate_new(
+		const gchar *foundation, guint component_id,
+		PurpleMediaCandidateType type,
+		PurpleMediaNetworkProtocol proto,
+		const gchar *ip, guint port);
+
+/**
+ * Copies a PurpleMediaCandidate.
+ *
+ * @param candidate The candidate to copy.
+ *
+ * @return The copy of the PurpleMediaCandidate.
+ *
+ * @since 2.7.0
+ */
+PurpleMediaCandidate *purple_media_candidate_copy(
+		PurpleMediaCandidate *candidate);
+
+/**
+ * Copies a GList of PurpleMediaCandidate and its contents.
+ *
+ * @param candidates The list of candidates to be copied.
+ *
+ * @return The copy of the GList.
+ *
+ * @since 2.6.0
+ */
+GList *purple_media_candidate_list_copy(GList *candidates);
+
+/**
+ * Frees a GList of PurpleMediaCandidate and its contents.
+ *
+ * @param candidates The list of candidates to be freed.
+ *
+ * @since 2.6.0
+ */
+void purple_media_candidate_list_free(GList *candidates);
+
+/**
+ * Gets the foundation (identifier) from the candidate.
+ *
+ * @param candidate The candidate to get the foundation from.
+ *
+ * @return The foundation.
+ *
+ * @since 2.6.0
+ */
+gchar *purple_media_candidate_get_foundation(PurpleMediaCandidate *candidate);
+
+/**
+ * Gets the component id (rtp or rtcp)
+ *
+ * @param candidate The candidate to get the compnent id from.
+ *
+ * @return The component id.
+ *
+ * @since 2.6.0
+ */
+guint purple_media_candidate_get_component_id(PurpleMediaCandidate *candidate);
+
+/**
+ * Gets the IP address.
+ *
+ * @param candidate The candidate to get the IP address from.
+ *
+ * @return The IP address.
+ *
+ * @since 2.6.0
+ */
+gchar *purple_media_candidate_get_ip(PurpleMediaCandidate *candidate);
+
+/**
+ * Gets the port.
+ *
+ * @param candidate The candidate to get the port from.
+ *
+ * @return The port.
+ *
+ * @since 2.6.0
+ */
+guint16 purple_media_candidate_get_port(PurpleMediaCandidate *candidate);
+
+/**
+ * Gets the base (internal) IP address.
+ *
+ * This can be NULL.
+ *
+ * @param candidate The candidate to get the base IP address from.
+ *
+ * @return The base IP address.
+ *
+ * @since 2.6.0
+ */
+gchar *purple_media_candidate_get_base_ip(PurpleMediaCandidate *candidate);
+
+/**
+ * Gets the base (internal) port.
+ *
+ * Invalid if the base IP is NULL.
+ *
+ * @param candidate The candidate to get the base port.
+ *
+ * @return The base port.
+ *
+ * @since 2.6.0
+ */
+guint16 purple_media_candidate_get_base_port(PurpleMediaCandidate *candidate);
+
+/**
+ * Gets the protocol (TCP or UDP).
+ *
+ * @param candidate The candidate to get the protocol from.
+ *
+ * @return The protocol.
+ *
+ * @since 2.6.0
+ */
+PurpleMediaNetworkProtocol purple_media_candidate_get_protocol(
+		PurpleMediaCandidate *candidate);
+
+/**
+ * Gets the priority.
+ *
+ * @param candidate The candidate to get the priority from.
+ *
+ * @return The priority.
+ *
+ * @since 2.6.0
+ */
+guint32 purple_media_candidate_get_priority(PurpleMediaCandidate *candidate);
+
+/**
+ * Gets the candidate type.
+ *
+ * @param candidate The candidate to get the candidate type from.
+ *
+ * @return The candidate type.
+ *
+ * @since 2.6.0
+ */
+PurpleMediaCandidateType purple_media_candidate_get_candidate_type(
+		PurpleMediaCandidate *candidate);
+
+/**
+ * Gets the username.
+ *
+ * This can be NULL. It depends on the transmission type.
+ *
+ * @param The candidate to get the username from.
+ *
+ * @return The username.
+ *
+ * @since 2.6.0
+ */
+gchar *purple_media_candidate_get_username(PurpleMediaCandidate *candidate);
+
+/**
+ * Gets the password.
+ *
+ * This can be NULL. It depends on the transmission type.
+ *
+ * @param The candidate to get the password from.
+ *
+ * @return The password.
+ *
+ * @since 2.6.0
+ */
+gchar *purple_media_candidate_get_password(PurpleMediaCandidate *candidate);
+
+/**
+ * Gets the TTL.
+ *
+ * @param The candidate to get the TTL from.
+ *
+ * @return The TTL.
+ *
+ * @since 2.6.0
+ */
+guint purple_media_candidate_get_ttl(PurpleMediaCandidate *candidate);
+
+G_END_DECLS
+
+#endif  /* _PURPLE_MEDIA_CANDIDATE_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/media/codec.c	Thu Feb 04 05:30:35 2010 +0000
@@ -0,0 +1,419 @@
+/**
+ * @file codec.c Codec for Media API
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This 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 Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "codec.h"
+
+/** @copydoc _PurpleMediaCodecClass */
+typedef struct _PurpleMediaCodecClass PurpleMediaCodecClass;
+/** @copydoc _PurpleMediaCodecPrivate */
+typedef struct _PurpleMediaCodecPrivate PurpleMediaCodecPrivate;
+
+#define PURPLE_MEDIA_CODEC_GET_PRIVATE(obj) \
+		(G_TYPE_INSTANCE_GET_PRIVATE((obj), \
+		PURPLE_TYPE_MEDIA_CODEC, PurpleMediaCodecPrivate))
+
+struct _PurpleMediaCodecClass
+{
+	GObjectClass parent_class;
+};
+
+struct _PurpleMediaCodec
+{
+	GObject parent;
+};
+
+G_DEFINE_TYPE(PurpleMediaCodec, purple_media_codec, G_TYPE_OBJECT);
+
+struct _PurpleMediaCodecPrivate
+{
+	gint id;
+	char *encoding_name;
+	PurpleMediaSessionType media_type;
+	guint clock_rate;
+	guint channels;
+	GList *optional_params;
+};
+
+enum {
+	PROP_CODEC_0,
+	PROP_ID,
+	PROP_ENCODING_NAME,
+	PROP_MEDIA_TYPE,
+	PROP_CLOCK_RATE,
+	PROP_CHANNELS,
+	PROP_OPTIONAL_PARAMS,
+};
+
+static void
+purple_media_codec_init(PurpleMediaCodec *info)
+{
+	PurpleMediaCodecPrivate *priv =
+			PURPLE_MEDIA_CODEC_GET_PRIVATE(info);
+	priv->encoding_name = NULL;
+	priv->optional_params = NULL;
+}
+
+static void
+purple_media_codec_finalize(GObject *info)
+{
+	PurpleMediaCodecPrivate *priv =
+			PURPLE_MEDIA_CODEC_GET_PRIVATE(info);
+	g_free(priv->encoding_name);
+	for (; priv->optional_params; priv->optional_params =
+			g_list_delete_link(priv->optional_params,
+			priv->optional_params)) {
+		g_free(priv->optional_params->data);
+	}
+}
+
+static void
+purple_media_codec_set_property (GObject *object, guint prop_id,
+		const GValue *value, GParamSpec *pspec)
+{
+	PurpleMediaCodecPrivate *priv;
+	g_return_if_fail(PURPLE_IS_MEDIA_CODEC(object));
+
+	priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(object);
+
+	switch (prop_id) {
+		case PROP_ID:
+			priv->id = g_value_get_uint(value);
+			break;
+		case PROP_ENCODING_NAME:
+			g_free(priv->encoding_name);
+			priv->encoding_name = g_value_dup_string(value);
+			break;
+		case PROP_MEDIA_TYPE:
+			priv->media_type = g_value_get_flags(value);
+			break;
+		case PROP_CLOCK_RATE:
+			priv->clock_rate = g_value_get_uint(value);
+			break;
+		case PROP_CHANNELS:
+			priv->channels = g_value_get_uint(value);
+			break;
+		case PROP_OPTIONAL_PARAMS:
+			priv->optional_params = g_value_get_pointer(value);
+			break;
+		default:	
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(
+					object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_media_codec_get_property (GObject *object, guint prop_id,
+		GValue *value, GParamSpec *pspec)
+{
+	PurpleMediaCodecPrivate *priv;
+	g_return_if_fail(PURPLE_IS_MEDIA_CODEC(object));
+	
+	priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(object);
+
+	switch (prop_id) {
+		case PROP_ID:
+			g_value_set_uint(value, priv->id);
+			break;
+		case PROP_ENCODING_NAME:
+			g_value_set_string(value, priv->encoding_name);
+			break;
+		case PROP_MEDIA_TYPE:
+			g_value_set_flags(value, priv->media_type);
+			break;
+		case PROP_CLOCK_RATE:
+			g_value_set_uint(value, priv->clock_rate);
+			break;
+		case PROP_CHANNELS:
+			g_value_set_uint(value, priv->channels);
+			break;
+		case PROP_OPTIONAL_PARAMS:
+			g_value_set_pointer(value, priv->optional_params);
+			break;
+		default:	
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(
+					object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_media_codec_class_init(PurpleMediaCodecClass *klass)
+{
+	GObjectClass *gobject_class = (GObjectClass*)klass;
+	
+	gobject_class->finalize = purple_media_codec_finalize;
+	gobject_class->set_property = purple_media_codec_set_property;
+	gobject_class->get_property = purple_media_codec_get_property;
+
+	g_object_class_install_property(gobject_class, PROP_ID,
+			g_param_spec_uint("id",
+			"ID",
+			"The numeric identifier of the codec.",
+			0, G_MAXUINT, 0,
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_ENCODING_NAME,
+			g_param_spec_string("encoding-name",
+			"Encoding Name",
+			"The name of the codec.",
+			NULL,
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_MEDIA_TYPE,
+			g_param_spec_flags("media-type",
+			"Media Type",
+			"Whether this is an audio of video codec.",
+			PURPLE_TYPE_MEDIA_SESSION_TYPE,
+			PURPLE_MEDIA_NONE,
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_CLOCK_RATE,
+			g_param_spec_uint("clock-rate",
+			"Create Callback",
+			"The function called to create this element.",
+			0, G_MAXUINT, 0,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_CHANNELS,
+			g_param_spec_uint("channels",
+			"Channels",
+			"The number of channels in this codec.",
+			0, G_MAXUINT, 0,
+			G_PARAM_READWRITE));
+	g_object_class_install_property(gobject_class, PROP_OPTIONAL_PARAMS,
+			g_param_spec_pointer("optional-params",
+			"Optional Params",
+			"A list of optional parameters for the codec.",
+			G_PARAM_READWRITE));
+
+	g_type_class_add_private(klass, sizeof(PurpleMediaCodecPrivate));
+}
+
+PurpleMediaCodec *
+purple_media_codec_new(int id, const char *encoding_name,
+		PurpleMediaSessionType media_type, guint clock_rate)
+{
+	PurpleMediaCodec *codec =
+			g_object_new(PURPLE_TYPE_MEDIA_CODEC,
+			"id", id,
+			"encoding_name", encoding_name,
+			"media_type", media_type,
+			"clock-rate", clock_rate, NULL);
+	return codec;
+}
+
+guint
+purple_media_codec_get_id(PurpleMediaCodec *codec)
+{
+	guint id;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_CODEC(codec), 0);
+	g_object_get(codec, "id", &id, NULL);
+	return id;
+}
+
+gchar *
+purple_media_codec_get_encoding_name(PurpleMediaCodec *codec)
+{
+	gchar *name;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_CODEC(codec), NULL);
+	g_object_get(codec, "encoding-name", &name, NULL);
+	return name;
+}
+
+guint
+purple_media_codec_get_clock_rate(PurpleMediaCodec *codec)
+{
+	guint clock_rate;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_CODEC(codec), 0);
+	g_object_get(codec, "clock-rate", &clock_rate, NULL);
+	return clock_rate;
+}
+
+guint
+purple_media_codec_get_channels(PurpleMediaCodec *codec)
+{
+	guint channels;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_CODEC(codec), 0);
+	g_object_get(codec, "channels", &channels, NULL);
+	return channels;
+}
+
+GList *
+purple_media_codec_get_optional_parameters(PurpleMediaCodec *codec)
+{
+	GList *optional_params;
+	g_return_val_if_fail(PURPLE_IS_MEDIA_CODEC(codec), NULL);
+	g_object_get(codec, "optional-params", &optional_params, NULL);
+	return optional_params;
+}
+
+void
+purple_media_codec_add_optional_parameter(PurpleMediaCodec *codec,
+		const gchar *name, const gchar *value)
+{
+	PurpleMediaCodecPrivate *priv;
+	PurpleKeyValuePair *new_param;
+
+	g_return_if_fail(codec != NULL);
+	g_return_if_fail(name != NULL && value != NULL);
+
+	priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(codec);
+
+	new_param = g_new0(PurpleKeyValuePair, 1);
+	new_param->key = g_strdup(name);
+	new_param->value = g_strdup(value);
+	priv->optional_params = g_list_append(
+			priv->optional_params, new_param);
+}
+
+void
+purple_media_codec_remove_optional_parameter(PurpleMediaCodec *codec,
+		PurpleKeyValuePair *param)
+{
+	PurpleMediaCodecPrivate *priv;
+
+	g_return_if_fail(codec != NULL && param != NULL);
+
+	priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(codec);
+
+	g_free(param->key);
+	g_free(param->value);
+	g_free(param);
+
+	priv->optional_params =
+			g_list_remove(priv->optional_params, param);
+}
+
+PurpleKeyValuePair *
+purple_media_codec_get_optional_parameter(PurpleMediaCodec *codec,
+		const gchar *name, const gchar *value)
+{
+	PurpleMediaCodecPrivate *priv;
+	GList *iter;
+
+	g_return_val_if_fail(codec != NULL, NULL);
+	g_return_val_if_fail(name != NULL, NULL);
+
+	priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(codec);
+
+	for (iter = priv->optional_params; iter; iter = g_list_next(iter)) {
+		PurpleKeyValuePair *param = iter->data;
+		if (!g_ascii_strcasecmp(param->key, name) &&
+				(value == NULL ||
+				!g_ascii_strcasecmp(param->value, value)))
+			return param;
+	}
+
+	return NULL;
+}
+
+PurpleMediaCodec *
+purple_media_codec_copy(PurpleMediaCodec *codec)
+{
+	PurpleMediaCodecPrivate *priv;
+	PurpleMediaCodec *new_codec;
+	GList *iter;
+
+	if (codec == NULL)
+		return NULL;
+
+	priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(codec);
+
+	new_codec = purple_media_codec_new(priv->id, priv->encoding_name,
+			priv->media_type, priv->clock_rate);
+	g_object_set(codec, "channels", priv->channels, NULL);
+
+	for (iter = priv->optional_params; iter; iter = g_list_next(iter)) {
+		PurpleKeyValuePair *param =
+				(PurpleKeyValuePair*)iter->data;
+		purple_media_codec_add_optional_parameter(new_codec,
+				param->key, param->value);
+	}
+
+	return new_codec;
+}
+
+GList *
+purple_media_codec_list_copy(GList *codecs)
+{
+	GList *new_list = NULL;
+
+	for (; codecs; codecs = g_list_next(codecs)) {
+		new_list = g_list_prepend(new_list,
+				purple_media_codec_copy(codecs->data));
+	}
+
+	new_list = g_list_reverse(new_list);
+	return new_list;
+}
+
+void
+purple_media_codec_list_free(GList *codecs)
+{
+	for (; codecs; codecs =
+			g_list_delete_link(codecs, codecs)) {
+		g_object_unref(codecs->data);
+	}
+}
+
+gchar *
+purple_media_codec_to_string(const PurpleMediaCodec *codec)
+{
+	PurpleMediaCodecPrivate *priv;
+	GString *string = NULL;
+	GList *item;
+	gchar *charstring;
+	const gchar *media_type_str = NULL;
+
+	if (codec == NULL)
+		return g_strdup("(NULL)");
+
+	priv = PURPLE_MEDIA_CODEC_GET_PRIVATE(codec);
+
+	string = g_string_new("");
+
+	if (priv->media_type & PURPLE_MEDIA_AUDIO)
+		media_type_str = "audio";
+	else if (priv->media_type & PURPLE_MEDIA_VIDEO)
+		media_type_str = "video";
+
+	g_string_printf(string, "%d: %s %s clock:%d channels:%d", priv->id,
+			media_type_str, priv->encoding_name,
+			priv->clock_rate, priv->channels);
+
+	for (item = priv->optional_params; item; item = g_list_next (item)) {
+		PurpleKeyValuePair *param = item->data;
+		g_string_append_printf (string, " %s=%s",
+				param->key, (gchar *)param->value);
+	}
+
+	charstring = string->str;
+	g_string_free (string, FALSE);
+
+	return charstring;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/media/codec.h	Thu Feb 04 05:30:35 2010 +0000
@@ -0,0 +1,213 @@
+/**
+ * @file codec.h Codec for Media API
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This 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 Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef _PURPLE_MEDIA_CODEC_H_
+#define _PURPLE_MEDIA_CODEC_H_
+
+#include "enum-types.h"
+
+/** An opaque structure representing an audio or video codec. */
+typedef struct _PurpleMediaCodec PurpleMediaCodec;
+
+#include "../util.h"
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define PURPLE_TYPE_MEDIA_CODEC            (purple_media_codec_get_type())
+#define PURPLE_IS_MEDIA_CODEC(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_MEDIA_CODEC))
+#define PURPLE_IS_MEDIA_CODEC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_MEDIA_CODEC))
+#define PURPLE_MEDIA_CODEC(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_MEDIA_CODEC, PurpleMediaCodec))
+#define PURPLE_MEDIA_CODEC_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_MEDIA_CODEC, PurpleMediaCodec))
+#define PURPLE_MEDIA_CODEC_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_MEDIA_CODEC, PurpleMediaCodec))
+
+
+/**
+ * Gets the type of the media codec structure.
+ *
+ * @return The media codec's GType
+ *
+ * @since 2.6.0
+ */
+GType purple_media_codec_get_type(void);
+
+/**
+ * Creates a new PurpleMediaCodec instance.
+ *
+ * @param id Codec identifier.
+ * @param encoding_name Name of the media type this encodes.
+ * @param media_type PurpleMediaSessionType of this codec.
+ * @param clock_rate The clock rate this codec encodes at, if applicable.
+ *
+ * @return The newly created PurpleMediaCodec.
+ *
+ * @since 2.6.0
+ */
+PurpleMediaCodec *purple_media_codec_new(int id, const char *encoding_name,
+		PurpleMediaSessionType media_type, guint clock_rate);
+
+/**
+ * Gets the codec id.
+ *
+ * @param The codec to get the id from.
+ *
+ * @return The codec id.
+ *
+ * @since 2.6.0
+ */
+guint purple_media_codec_get_id(PurpleMediaCodec *codec);
+
+/**
+ * Gets the encoding name.
+ *
+ * @param The codec to get the encoding name from.
+ *
+ * @return The encoding name.
+ *
+ * @since 2.6.0
+ */
+gchar *purple_media_codec_get_encoding_name(PurpleMediaCodec *codec);
+
+/**
+ * Gets the clock rate.
+ *
+ * @param The codec to get the clock rate from.
+ *
+ * @return The clock rate.
+ *
+ * @since 2.6.0
+ */
+guint purple_media_codec_get_clock_rate(PurpleMediaCodec *codec);
+
+/**
+ * Gets the number of channels.
+ *
+ * @param The codec to get the number of channels from.
+ *
+ * @return The number of channels.
+ *
+ * @since 2.6.0
+ */
+guint purple_media_codec_get_channels(PurpleMediaCodec *codec);
+
+/**
+ * Gets a list of the optional parameters.
+ *
+ * The list consists of PurpleKeyValuePair's. 
+ *
+ * @param The codec to get the optional parameters from.
+ *
+ * @return The list of optional parameters.
+ *
+ * @since 2.6.0
+ */
+GList *purple_media_codec_get_optional_parameters(PurpleMediaCodec *codec);
+
+/**
+ * Adds an optional parameter to the codec.
+ *
+ * @param codec The codec to add the parameter to.
+ * @param name The name of the parameter to add.
+ * @param value The value of the parameter to add.
+ *
+ * @since 2.6.0
+ */
+void purple_media_codec_add_optional_parameter(PurpleMediaCodec *codec,
+		const gchar *name, const gchar *value);
+
+/**
+ * Removes an optional parameter from the codec.
+ *
+ * @param codec The codec to remove the parameter from.
+ * @param param A pointer to the parameter to remove.
+ *
+ * @since 2.6.0
+ */
+void purple_media_codec_remove_optional_parameter(PurpleMediaCodec *codec,
+		PurpleKeyValuePair *param);
+
+/**
+ * Gets an optional parameter based on the values given.
+ *
+ * @param codec The codec to find the parameter in.
+ * @param name The name of the parameter to search for.
+ * @param value The value to search for or NULL.
+ *
+ * @return The value found or NULL.
+ *
+ * @since 2.6.0
+ */
+PurpleKeyValuePair *purple_media_codec_get_optional_parameter(
+		PurpleMediaCodec *codec, const gchar *name,
+		const gchar *value);
+
+/**
+ * Copies a PurpleMediaCodec object.
+ *
+ * @param codec The codec to copy.
+ *
+ * @return The copy of the codec.
+ *
+ * @since 2.7.0
+ */
+PurpleMediaCodec *purple_media_codec_copy(PurpleMediaCodec *codec);
+
+/**
+ * Copies a GList of PurpleMediaCodec and its contents.
+ *
+ * @param codecs The list of codecs to be copied.
+ *
+ * @return The copy of the GList.
+ *
+ * @since 2.6.0
+ */
+GList *purple_media_codec_list_copy(GList *codecs);
+
+/**
+ * Frees a GList of PurpleMediaCodec and its contents.
+ *
+ * @param codecs The list of codecs to be freed.
+ *
+ * @since 2.6.0
+ */
+void purple_media_codec_list_free(GList *codecs);
+
+/**
+ * Creates a string representation of the codec.
+ *
+ * @param codec The codec to create the string of.
+ *
+ * @return The new string representation.
+ *
+ * @since 2.6.0
+ */
+gchar *purple_media_codec_to_string(const PurpleMediaCodec *codec);
+
+G_END_DECLS
+
+#endif  /* _PURPLE_MEDIA_CODEC_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/media/enum-types.c	Thu Feb 04 05:30:35 2010 +0000
@@ -0,0 +1,213 @@
+/**
+ * @file enum-types.c Enum types for Media API
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This 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 Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "enum-types.h"
+
+/*
+ * PurpleMediaCandidateType
+ */
+
+GType
+purple_media_candidate_type_get_type()
+{
+	static GType type = 0;
+	if (type == 0) {
+		static const GEnumValue values[] = {
+			{ PURPLE_MEDIA_CANDIDATE_TYPE_HOST,
+					"PURPLE_MEDIA_CANDIDATE_TYPE_HOST",
+					"host" },
+			{ PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX,
+					"PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX",
+					"srflx" },
+			{ PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX,
+					"PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX",
+					"prflx" },
+			{ PURPLE_MEDIA_CANDIDATE_TYPE_RELAY,
+					"PURPLE_MEDIA_CANDIDATE_TYPE_RELAY",
+					"relay" },
+			{ PURPLE_MEDIA_CANDIDATE_TYPE_MULTICAST,
+					"PURPLE_MEDIA_CANDIDATE_TYPE_MULTICAST",
+					"multicast" },
+			{ 0, NULL, NULL }
+		};
+		type = g_enum_register_static("PurpleMediaCandidateType",
+				values);
+	}
+	return type;
+}
+
+/*
+ * PurpleMediaCaps
+ */
+
+GType
+purple_media_caps_get_type()
+{
+	static GType type = 0;
+	if (type == 0) {
+		static const GEnumValue values[] = {
+			{ PURPLE_MEDIA_CAPS_NONE,
+					"PURPLE_MEDIA_CAPS_NONE", "none" },
+			{ PURPLE_MEDIA_CAPS_AUDIO,
+					"PURPLE_MEDIA_CAPS_AUDIO", "audio" },
+			{ PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION,
+					"PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION",
+					"audio-single-direction" },
+			{ PURPLE_MEDIA_CAPS_VIDEO,
+					"PURPLE_MEDIA_CAPS_VIDEO", "video" },
+			{ PURPLE_MEDIA_CAPS_VIDEO_SINGLE_DIRECTION,
+					"PURPLE_MEDIA_CAPS_VIDEO_SINGLE_DIRECTION",
+					"video-single-direction" },
+			{ PURPLE_MEDIA_CAPS_AUDIO_VIDEO,
+					"PURPLE_MEDIA_CAPS_AUDIO_VIDEO",
+					"audio-video" },
+			{ PURPLE_MEDIA_CAPS_MODIFY_SESSION,
+					"PURPLE_MEDIA_CAPS_MODIFY_SESSION",
+					"modify-session" },
+			{ PURPLE_MEDIA_CAPS_CHANGE_DIRECTION,
+					"PURPLE_MEDIA_CAPS_CHANGE_DIRECTION",
+					"change-direction" },
+			{ 0, NULL, NULL }
+		};
+		type = g_enum_register_static("PurpleMediaCaps", values);
+	}
+	return type;
+}
+
+/*
+ * PurpleMediaInfoType
+ */
+
+GType
+purple_media_info_type_get_type()
+{
+	static GType type = 0;
+	if (type == 0) {
+		static const GEnumValue values[] = {
+			{ PURPLE_MEDIA_INFO_HANGUP,
+					"PURPLE_MEDIA_INFO_HANGUP", "hangup" },
+			{ PURPLE_MEDIA_INFO_ACCEPT,
+					"PURPLE_MEDIA_INFO_ACCEPT", "accept" },
+			{ PURPLE_MEDIA_INFO_REJECT,
+					"PURPLE_MEDIA_INFO_REJECT", "reject" },
+			{ PURPLE_MEDIA_INFO_MUTE,
+					"PURPLE_MEDIA_INFO_MUTE", "mute" },
+			{ PURPLE_MEDIA_INFO_UNMUTE,
+					"PURPLE_MEDIA_INFO_UNMUTE", "unmute" },
+			{ PURPLE_MEDIA_INFO_PAUSE,
+					"PURPLE_MEDIA_INFO_PAUSE", "pause" },
+			{ PURPLE_MEDIA_INFO_UNPAUSE,
+					"PURPLE_MEDIA_INFO_UNPAUSE", "unpause" },
+			{ PURPLE_MEDIA_INFO_HOLD,
+					"PURPLE_MEDIA_INFO_HOLD", "hold" },
+			{ PURPLE_MEDIA_INFO_UNHOLD,
+					"PURPLE_MEDIA_INFO_HOLD", "unhold" },
+			{ 0, NULL, NULL }
+		};
+		type = g_enum_register_static("PurpleMediaInfoType", values);
+	}
+	return type;
+}
+
+/*
+ * PurpleMediaNetworkProtocol
+ */
+
+GType
+purple_media_network_protocol_get_type()
+{
+	static GType type = 0;
+	if (type == 0) {
+		static const GEnumValue values[] = {
+			{ PURPLE_MEDIA_NETWORK_PROTOCOL_UDP,
+					"PURPLE_MEDIA_NETWORK_PROTOCOL_UDP",
+					"udp" },
+			{ PURPLE_MEDIA_NETWORK_PROTOCOL_TCP,
+					"PURPLE_MEDIA_NETWORK_PROTOCOL_TCP",
+					"tcp" },
+			{ 0, NULL, NULL }
+		};
+		type = g_enum_register_static("PurpleMediaNetworkProtocol",
+				values);
+	}
+	return type;
+}
+
+/*
+ * PurpleMediaSessionType
+ */
+
+GType
+purple_media_session_type_get_type()
+{
+	static GType type = 0;
+	if (type == 0) {
+		static const GFlagsValue values[] = {
+			{ PURPLE_MEDIA_NONE,
+				"PURPLE_MEDIA_NONE", "none" },
+			{ PURPLE_MEDIA_RECV_AUDIO,
+				"PURPLE_MEDIA_RECV_AUDIO", "recv-audio" },
+			{ PURPLE_MEDIA_SEND_AUDIO,
+				"PURPLE_MEDIA_SEND_AUDIO", "send-audio" },
+			{ PURPLE_MEDIA_RECV_VIDEO,
+				"PURPLE_MEDIA_RECV_VIDEO", "recv-video" },
+			{ PURPLE_MEDIA_SEND_VIDEO,
+				"PURPLE_MEDIA_SEND_VIDEO", "send-audio" },
+			{ PURPLE_MEDIA_AUDIO,
+				"PURPLE_MEDIA_AUDIO", "audio" },
+			{ PURPLE_MEDIA_VIDEO,
+				"PURPLE_MEDIA_VIDEO", "video" },
+			{ 0, NULL, NULL }
+		};
+		type = g_flags_register_static(
+				"PurpleMediaSessionType", values);
+	}
+	return type;
+}
+
+/*
+ * PurpleMediaState
+ */
+
+GType
+purple_media_state_changed_get_type()
+{
+	static GType type = 0;
+	if (type == 0) {
+		static const GEnumValue values[] = {
+			{ PURPLE_MEDIA_STATE_NEW,
+				"PURPLE_MEDIA_STATE_NEW", "new" },
+			{ PURPLE_MEDIA_STATE_CONNECTED,
+				"PURPLE_MEDIA_STATE_CONNECTED", "connected" },
+			{ PURPLE_MEDIA_STATE_END,
+				"PURPLE_MEDIA_STATE_END", "end" },
+			{ 0, NULL, NULL }
+		};
+		type = g_enum_register_static("PurpleMediaState", values);
+	}
+	return type;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/media/enum-types.h	Thu Feb 04 05:30:35 2010 +0000
@@ -0,0 +1,162 @@
+/**
+ * @file enum-types.h Enum types for Media API
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This 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 Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef _PURPLE_MEDIA_ENUM_TYPES_H_
+#define _PURPLE_MEDIA_ENUM_TYPES_H_
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define PURPLE_TYPE_MEDIA_CANDIDATE_TYPE   (purple_media_candidate_type_get_type())
+#define PURPLE_MEDIA_TYPE_CAPS	           (purple_media_caps_get_type())
+#define PURPLE_MEDIA_TYPE_INFO_TYPE	   (purple_media_info_type_get_type())
+#define PURPLE_TYPE_MEDIA_NETWORK_PROTOCOL (purple_media_network_protocol_get_type())
+#define PURPLE_TYPE_MEDIA_SESSION_TYPE     (purple_media_session_type_get_type())
+#define PURPLE_MEDIA_TYPE_STATE            (purple_media_state_changed_get_type())
+
+/** Media candidate types */
+typedef enum {
+	PURPLE_MEDIA_CANDIDATE_TYPE_HOST,
+	PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX,
+	PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX,
+	PURPLE_MEDIA_CANDIDATE_TYPE_RELAY,
+	PURPLE_MEDIA_CANDIDATE_TYPE_MULTICAST,
+} PurpleMediaCandidateType;
+
+/** Media caps */
+typedef enum {
+	PURPLE_MEDIA_CAPS_NONE = 0,
+	PURPLE_MEDIA_CAPS_AUDIO = 1,
+	PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION = 1 << 1,
+	PURPLE_MEDIA_CAPS_VIDEO = 1 << 2,
+	PURPLE_MEDIA_CAPS_VIDEO_SINGLE_DIRECTION = 1 << 3,
+	PURPLE_MEDIA_CAPS_AUDIO_VIDEO = 1 << 4,
+	PURPLE_MEDIA_CAPS_MODIFY_SESSION = 1 << 5,
+	PURPLE_MEDIA_CAPS_CHANGE_DIRECTION = 1 << 6,
+} PurpleMediaCaps;
+
+/** Media component types */
+typedef enum {
+	PURPLE_MEDIA_COMPONENT_NONE = 0,
+	PURPLE_MEDIA_COMPONENT_RTP = 1,
+	PURPLE_MEDIA_COMPONENT_RTCP = 2,
+} PurpleMediaComponentType;
+
+/** Media info types */
+typedef enum {
+	PURPLE_MEDIA_INFO_HANGUP = 0,
+	PURPLE_MEDIA_INFO_ACCEPT,
+	PURPLE_MEDIA_INFO_REJECT,
+	PURPLE_MEDIA_INFO_MUTE,
+	PURPLE_MEDIA_INFO_UNMUTE,
+	PURPLE_MEDIA_INFO_PAUSE,
+	PURPLE_MEDIA_INFO_UNPAUSE,
+	PURPLE_MEDIA_INFO_HOLD,
+	PURPLE_MEDIA_INFO_UNHOLD,
+} PurpleMediaInfoType;
+
+/** Media network protocols */
+typedef enum {
+	PURPLE_MEDIA_NETWORK_PROTOCOL_UDP,
+	PURPLE_MEDIA_NETWORK_PROTOCOL_TCP,
+} PurpleMediaNetworkProtocol;
+
+/** Media session types */
+typedef enum {
+	PURPLE_MEDIA_NONE	= 0,
+	PURPLE_MEDIA_RECV_AUDIO = 1 << 0,
+	PURPLE_MEDIA_SEND_AUDIO = 1 << 1,
+	PURPLE_MEDIA_RECV_VIDEO = 1 << 2,
+	PURPLE_MEDIA_SEND_VIDEO = 1 << 3,
+	PURPLE_MEDIA_AUDIO = PURPLE_MEDIA_RECV_AUDIO | PURPLE_MEDIA_SEND_AUDIO,
+	PURPLE_MEDIA_VIDEO = PURPLE_MEDIA_RECV_VIDEO | PURPLE_MEDIA_SEND_VIDEO
+} PurpleMediaSessionType;
+
+/** Media state-changed types */
+typedef enum {
+	PURPLE_MEDIA_STATE_NEW = 0,
+	PURPLE_MEDIA_STATE_CONNECTED,
+	PURPLE_MEDIA_STATE_END,
+} PurpleMediaState;
+
+/**
+ * Gets the media candidate type's GType
+ *
+ * @return The media candidate type's GType.
+ *
+ * @since 2.6.0
+ */
+GType purple_media_candidate_type_get_type(void);
+
+/**
+ * Gets the type of the media caps flags
+ *
+ * @return The media caps flags' GType
+ *
+ * @since 2.7.0
+ */
+GType purple_media_caps_get_type(void);
+
+/**
+ * Gets the type of the info type enum
+ *
+ * @return The info type enum's GType
+ *
+ * @since 2.6.0
+ */
+GType purple_media_info_type_get_type(void);
+
+/**
+ * Gets the media network protocol's GType
+ *
+ * @return The media network protocol's GType.
+ *
+ * @since 2.6.0
+ */
+GType purple_media_network_protocol_get_type(void);
+
+/**
+ * Gets the media session type's GType
+ *
+ * @return The media session type's GType.
+ *
+ * @since 2.6.0
+ */
+GType purple_media_session_type_get_type(void);
+
+/**
+ * Gets the type of the state-changed enum
+ *
+ * @return The state-changed enum's GType
+ *
+ * @since 2.6.0
+ */
+GType purple_media_state_changed_get_type(void);
+
+G_END_DECLS
+
+#endif  /* _PURPLE_MEDIA_ENUM_TYPES_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/media/media.c	Thu Feb 04 05:30:35 2010 +0000
@@ -0,0 +1,1407 @@
+/**
+ * @file media.c Media API
+ * @ingroup core
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This 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 Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#include "internal.h"
+
+#include "account.h"
+#include "media.h"
+#include "media/backend-iface.h"
+#include "mediamanager.h"
+
+#include "debug.h"
+
+#ifdef USE_GSTREAMER
+#include "media/backend-fs2.h"
+#include "marshallers.h"
+#include "media-gst.h"
+#endif
+
+#ifdef USE_VV
+
+/** @copydoc _PurpleMediaSession */
+typedef struct _PurpleMediaSession PurpleMediaSession;
+/** @copydoc _PurpleMediaStream */
+typedef struct _PurpleMediaStream PurpleMediaStream;
+/** @copydoc _PurpleMediaClass */
+typedef struct _PurpleMediaClass PurpleMediaClass;
+/** @copydoc _PurpleMediaPrivate */
+typedef struct _PurpleMediaPrivate PurpleMediaPrivate;
+
+/** The media class */
+struct _PurpleMediaClass
+{
+	GObjectClass parent_class;     /**< The parent class. */
+};
+
+/** The media class's private data */
+struct _PurpleMedia
+{
+	GObject parent;                /**< The parent of this object. */
+	PurpleMediaPrivate *priv;      /**< The private data of this object. */
+};
+
+struct _PurpleMediaSession
+{
+	gchar *id;
+	PurpleMedia *media;
+	PurpleMediaSessionType type;
+	gboolean initiator;
+};
+
+struct _PurpleMediaStream
+{
+	PurpleMediaSession *session;
+	gchar *participant;
+
+	GList *local_candidates;
+	GList *remote_candidates;
+
+	gboolean initiator;
+	gboolean accepted;
+	gboolean candidates_prepared;
+
+	GList *active_local_candidates;
+	GList *active_remote_candidates;
+};
+#endif
+
+struct _PurpleMediaPrivate
+{
+#ifdef USE_VV
+	PurpleMediaManager *manager;
+	PurpleAccount *account;
+	PurpleMediaBackend *backend;
+	gchar *conference_type;
+	gboolean initiator;
+	gpointer prpl_data;
+
+	GHashTable *sessions;	/* PurpleMediaSession table */
+	GList *participants;
+	GList *streams;		/* PurpleMediaStream table */
+#else
+	gpointer dummy;
+#endif
+};
+
+#ifdef USE_VV
+#define PURPLE_MEDIA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA, PurpleMediaPrivate))
+
+static void purple_media_class_init (PurpleMediaClass *klass);
+static void purple_media_init (PurpleMedia *media);
+static void purple_media_dispose (GObject *object);
+static void purple_media_finalize (GObject *object);
+static void purple_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+static void purple_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+
+static void purple_media_new_local_candidate_cb(PurpleMediaBackend *backend,
+		const gchar *sess_id, const gchar *participant,
+		PurpleMediaCandidate *candidate, PurpleMedia *media);
+static void purple_media_candidates_prepared_cb(PurpleMediaBackend *backend,
+		const gchar *sess_id, const gchar *name, PurpleMedia *media);
+static void purple_media_candidate_pair_established_cb(
+		PurpleMediaBackend *backend,
+		const gchar *sess_id, const gchar *name,
+		PurpleMediaCandidate *local_candidate,
+		PurpleMediaCandidate *remote_candidate,
+		PurpleMedia *media);
+static void purple_media_codecs_changed_cb(PurpleMediaBackend *backend,
+		const gchar *sess_id, PurpleMedia *media);
+
+static GObjectClass *parent_class = NULL;
+
+
+
+enum {
+	S_ERROR,
+	CANDIDATES_PREPARED,
+	CODECS_CHANGED,
+	LEVEL,
+	NEW_CANDIDATE,
+	STATE_CHANGED,
+	STREAM_INFO,
+	LAST_SIGNAL
+};
+static guint purple_media_signals[LAST_SIGNAL] = {0};
+
+enum {
+	PROP_0,
+	PROP_MANAGER,
+	PROP_BACKEND,
+	PROP_ACCOUNT,
+	PROP_CONFERENCE_TYPE,
+	PROP_INITIATOR,
+	PROP_PRPL_DATA,
+};
+#endif
+
+
+GType
+purple_media_get_type()
+{
+#ifdef USE_VV
+	static GType type = 0;
+
+	if (type == 0) {
+		static const GTypeInfo info = {
+			sizeof(PurpleMediaClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) purple_media_class_init,
+			NULL,
+			NULL,
+			sizeof(PurpleMedia),
+			0,
+			(GInstanceInitFunc) purple_media_init,
+			NULL
+		};
+		type = g_type_register_static(G_TYPE_OBJECT, "PurpleMedia", &info, 0);
+	}
+	return type;
+#else
+	return G_TYPE_NONE;
+#endif
+}
+
+#ifdef USE_VV
+static void
+purple_media_class_init (PurpleMediaClass *klass)
+{
+	GObjectClass *gobject_class = (GObjectClass*)klass;
+	parent_class = g_type_class_peek_parent(klass);
+	
+	gobject_class->dispose = purple_media_dispose;
+	gobject_class->finalize = purple_media_finalize;
+	gobject_class->set_property = purple_media_set_property;
+	gobject_class->get_property = purple_media_get_property;
+
+	g_object_class_install_property(gobject_class, PROP_MANAGER,
+			g_param_spec_object("manager",
+			"Purple Media Manager",
+			"The media manager that contains this media session.",
+			PURPLE_TYPE_MEDIA_MANAGER,
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+	/*
+	 * This one should be PURPLE_TYPE_MEDIA_BACKEND, but it doesn't
+	 * like interfaces because they "aren't GObjects"
+	 */
+	g_object_class_install_property(gobject_class, PROP_BACKEND,
+			g_param_spec_object("backend",
+			"Purple Media Backend",
+			"The backend object this media object uses.",
+			G_TYPE_OBJECT,
+			G_PARAM_READABLE));
+
+	g_object_class_install_property(gobject_class, PROP_ACCOUNT,
+			g_param_spec_pointer("account",
+			"PurpleAccount",
+			"The account this media session is on.",
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_CONFERENCE_TYPE,
+			g_param_spec_string("conference-type",
+			"Conference Type",
+			"The type of conference that this media object "
+			"has been created to provide.",
+			NULL,
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_INITIATOR,
+			g_param_spec_boolean("initiator",
+			"initiator",
+			"If the local user initiated the conference.",
+			FALSE,
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_PRPL_DATA,
+			g_param_spec_pointer("prpl-data",
+			"gpointer",
+			"Data the prpl plugin set on the media session.",
+			G_PARAM_READWRITE));
+
+	purple_media_signals[S_ERROR] = g_signal_new("error", G_TYPE_FROM_CLASS(klass),
+					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+					 g_cclosure_marshal_VOID__STRING,
+					 G_TYPE_NONE, 1, G_TYPE_STRING);
+	purple_media_signals[CANDIDATES_PREPARED] = g_signal_new("candidates-prepared", G_TYPE_FROM_CLASS(klass),
+					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+					 purple_smarshal_VOID__STRING_STRING,
+					 G_TYPE_NONE, 2, G_TYPE_STRING,
+					 G_TYPE_STRING);
+	purple_media_signals[CODECS_CHANGED] = g_signal_new("codecs-changed", G_TYPE_FROM_CLASS(klass),
+					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+					 g_cclosure_marshal_VOID__STRING,
+					 G_TYPE_NONE, 1, G_TYPE_STRING);
+	purple_media_signals[LEVEL] = g_signal_new("level", G_TYPE_FROM_CLASS(klass),
+					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+					 purple_smarshal_VOID__STRING_STRING_DOUBLE,
+					 G_TYPE_NONE, 3, G_TYPE_STRING,
+					 G_TYPE_STRING, G_TYPE_DOUBLE);
+	purple_media_signals[NEW_CANDIDATE] = g_signal_new("new-candidate", G_TYPE_FROM_CLASS(klass),
+					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+					 purple_smarshal_VOID__POINTER_POINTER_OBJECT,
+					 G_TYPE_NONE, 3, G_TYPE_POINTER,
+					 G_TYPE_POINTER, PURPLE_TYPE_MEDIA_CANDIDATE);
+	purple_media_signals[STATE_CHANGED] = g_signal_new("state-changed", G_TYPE_FROM_CLASS(klass),
+					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+					 purple_smarshal_VOID__ENUM_STRING_STRING,
+					 G_TYPE_NONE, 3, PURPLE_MEDIA_TYPE_STATE,
+					 G_TYPE_STRING, G_TYPE_STRING);
+	purple_media_signals[STREAM_INFO] = g_signal_new("stream-info", G_TYPE_FROM_CLASS(klass),
+					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+					 purple_smarshal_VOID__ENUM_STRING_STRING_BOOLEAN,
+					 G_TYPE_NONE, 4, PURPLE_MEDIA_TYPE_INFO_TYPE,
+					 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
+	g_type_class_add_private(klass, sizeof(PurpleMediaPrivate));
+}
+
+
+static void
+purple_media_init (PurpleMedia *media)
+{
+	media->priv = PURPLE_MEDIA_GET_PRIVATE(media);
+	memset(media->priv, 0, sizeof(*media->priv));
+}
+
+static void
+purple_media_stream_free(PurpleMediaStream *stream)
+{
+	if (stream == NULL)
+		return;
+
+	g_free(stream->participant);
+
+	if (stream->local_candidates)
+		purple_media_candidate_list_free(stream->local_candidates);
+	if (stream->remote_candidates)
+		purple_media_candidate_list_free(stream->remote_candidates);
+
+	if (stream->active_local_candidates)
+		purple_media_candidate_list_free(
+				stream->active_local_candidates);
+	if (stream->active_remote_candidates)
+		purple_media_candidate_list_free(
+				stream->active_remote_candidates);
+
+	g_free(stream);
+}
+
+static void
+purple_media_session_free(PurpleMediaSession *session)
+{
+	if (session == NULL)
+		return;
+
+	g_free(session->id);
+	g_free(session);
+}
+
+static void
+purple_media_dispose(GObject *media)
+{
+	PurpleMediaPrivate *priv = PURPLE_MEDIA_GET_PRIVATE(media);
+
+	purple_debug_info("media","purple_media_dispose\n");
+
+	purple_media_manager_remove_media(priv->manager, PURPLE_MEDIA(media));
+
+	if (priv->backend) {
+		g_object_unref(priv->backend);
+		priv->backend = NULL;
+	}
+
+	if (priv->manager) {
+		g_object_unref(priv->manager);
+		priv->manager = NULL;
+	}
+
+	G_OBJECT_CLASS(parent_class)->dispose(media);
+}
+
+static void
+purple_media_finalize(GObject *media)
+{
+	PurpleMediaPrivate *priv = PURPLE_MEDIA_GET_PRIVATE(media);
+	purple_debug_info("media","purple_media_finalize\n");
+
+	for (; priv->streams; priv->streams = g_list_delete_link(priv->streams, priv->streams))
+		purple_media_stream_free(priv->streams->data);
+
+	for (; priv->participants; priv->participants = g_list_delete_link(
+			priv->participants, priv->participants))
+		g_free(priv->participants->data);
+
+	if (priv->sessions) {
+		GList *sessions = g_hash_table_get_values(priv->sessions);
+		for (; sessions; sessions = g_list_delete_link(sessions, sessions)) {
+			purple_media_session_free(sessions->data);
+		}
+		g_hash_table_destroy(priv->sessions);
+	}
+
+	G_OBJECT_CLASS(parent_class)->finalize(media);
+}
+
+static void
+purple_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+	PurpleMedia *media;
+	g_return_if_fail(PURPLE_IS_MEDIA(object));
+
+	media = PURPLE_MEDIA(object);
+
+	switch (prop_id) {
+		case PROP_MANAGER:
+			media->priv->manager = g_value_dup_object(value);
+			break;
+		case PROP_ACCOUNT:
+			media->priv->account = g_value_get_pointer(value);
+			break;
+		case PROP_CONFERENCE_TYPE:
+			media->priv->conference_type =
+					g_value_dup_string(value);
+			media->priv->backend = g_object_new(
+					purple_media_manager_get_backend_type(
+					purple_media_manager_get()),
+					"conference-type",
+					media->priv->conference_type,
+					"media", media,
+					NULL);
+			g_signal_connect(media->priv->backend,
+					"active-candidate-pair",
+					G_CALLBACK(
+					purple_media_candidate_pair_established_cb),
+					media);
+			g_signal_connect(media->priv->backend,
+					"candidates-prepared",
+					G_CALLBACK(
+					purple_media_candidates_prepared_cb),
+					media);
+			g_signal_connect(media->priv->backend,
+					"codecs-changed",
+					G_CALLBACK(
+					purple_media_codecs_changed_cb),
+					media);
+			g_signal_connect(media->priv->backend,
+					"new-candidate",
+					G_CALLBACK(
+					purple_media_new_local_candidate_cb),
+					media);
+			break;
+		case PROP_INITIATOR:
+			media->priv->initiator = g_value_get_boolean(value);
+			break;
+		case PROP_PRPL_DATA:
+			media->priv->prpl_data = g_value_get_pointer(value);
+			break;
+		default:	
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+	PurpleMedia *media;
+	g_return_if_fail(PURPLE_IS_MEDIA(object));
+	
+	media = PURPLE_MEDIA(object);
+
+	switch (prop_id) {
+		case PROP_MANAGER:
+			g_value_set_object(value, media->priv->manager);
+			break;
+		case PROP_BACKEND:
+			g_value_set_object(value, media->priv->backend);
+			break;
+		case PROP_ACCOUNT:
+			g_value_set_pointer(value, media->priv->account);
+			break;
+		case PROP_CONFERENCE_TYPE:
+			g_value_set_string(value,
+					media->priv->conference_type);
+			break;
+		case PROP_INITIATOR:
+			g_value_set_boolean(value, media->priv->initiator);
+			break;
+		case PROP_PRPL_DATA:
+			g_value_set_pointer(value, media->priv->prpl_data);
+			break;
+		default:	
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);	
+			break;
+	}
+
+}
+
+static PurpleMediaSession*
+purple_media_get_session(PurpleMedia *media, const gchar *sess_id)
+{
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
+	return (PurpleMediaSession*) (media->priv->sessions) ?
+			g_hash_table_lookup(media->priv->sessions, sess_id) : NULL;
+}
+
+static PurpleMediaStream*
+purple_media_get_stream(PurpleMedia *media, const gchar *session, const gchar *participant)
+{
+	GList *streams;
+
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
+
+	streams = media->priv->streams;
+
+	for (; streams; streams = g_list_next(streams)) {
+		PurpleMediaStream *stream = streams->data;
+		if (!strcmp(stream->session->id, session) &&
+				!strcmp(stream->participant, participant))
+			return stream;
+	}
+
+	return NULL;
+}
+
+static GList *
+purple_media_get_streams(PurpleMedia *media, const gchar *session,
+		const gchar *participant)
+{
+	GList *streams;
+	GList *ret = NULL;
+	
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
+
+	streams = media->priv->streams;
+
+	for (; streams; streams = g_list_next(streams)) {
+		PurpleMediaStream *stream = streams->data;
+		if ((session == NULL ||
+				!strcmp(stream->session->id, session)) &&
+				(participant == NULL ||
+				!strcmp(stream->participant, participant)))
+			ret = g_list_append(ret, stream);
+	}
+
+	return ret;
+}
+
+static void
+purple_media_add_session(PurpleMedia *media, PurpleMediaSession *session)
+{
+	g_return_if_fail(PURPLE_IS_MEDIA(media));
+	g_return_if_fail(session != NULL);
+
+	if (!media->priv->sessions) {
+		purple_debug_info("media", "Creating hash table for sessions\n");
+		media->priv->sessions = g_hash_table_new(g_str_hash, g_str_equal);
+	}
+	g_hash_table_insert(media->priv->sessions, g_strdup(session->id), session);
+}
+
+#if 0
+static gboolean
+purple_media_remove_session(PurpleMedia *media, PurpleMediaSession *session)
+{
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
+	return g_hash_table_remove(media->priv->sessions, session->id);
+}
+#endif
+
+static PurpleMediaStream *
+purple_media_insert_stream(PurpleMediaSession *session,
+		const gchar *name, gboolean initiator)
+{
+	PurpleMediaStream *media_stream;
+	
+	g_return_val_if_fail(session != NULL, NULL);
+
+	media_stream = g_new0(PurpleMediaStream, 1);
+	media_stream->participant = g_strdup(name);
+	media_stream->session = session;
+	media_stream->initiator = initiator;
+
+	session->media->priv->streams =
+			g_list_append(session->media->priv->streams, media_stream);
+
+	return media_stream;
+}
+
+static void
+purple_media_insert_local_candidate(PurpleMediaSession *session, const gchar *name,
+				     PurpleMediaCandidate *candidate)
+{
+	PurpleMediaStream *stream;
+
+	g_return_if_fail(session != NULL);
+
+	stream = purple_media_get_stream(session->media, session->id, name);
+	stream->local_candidates = g_list_append(stream->local_candidates, candidate);
+}
+#endif
+
+GList *
+purple_media_get_session_ids(PurpleMedia *media)
+{
+#ifdef USE_VV
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
+	return media->priv->sessions != NULL ?
+			g_hash_table_get_keys(media->priv->sessions) : NULL;
+#else
+	return NULL;
+#endif
+}
+
+#ifdef USE_GSTREAMER
+GstElement *
+purple_media_get_src(PurpleMedia *media, const gchar *sess_id)
+{
+#ifdef USE_VV
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
+
+	if (PURPLE_IS_MEDIA_BACKEND_FS2(media->priv->backend))
+		return purple_media_backend_fs2_get_src(
+				PURPLE_MEDIA_BACKEND_FS2(
+				media->priv->backend), sess_id);
+
+	g_return_val_if_reached(NULL);
+#else
+	return NULL;
+#endif
+}
+#endif /* USE_GSTREAMER */
+
+PurpleAccount *
+purple_media_get_account(PurpleMedia *media)
+{
+#ifdef USE_VV
+	PurpleAccount *account;
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
+	g_object_get(G_OBJECT(media), "account", &account, NULL);
+	return account;
+#else
+	return NULL;
+#endif
+}
+
+gpointer
+purple_media_get_prpl_data(PurpleMedia *media)
+{
+#ifdef USE_VV
+	gpointer prpl_data;
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
+	g_object_get(G_OBJECT(media), "prpl-data", &prpl_data, NULL);
+	return prpl_data;
+#else
+	return NULL;
+#endif
+}
+
+void
+purple_media_set_prpl_data(PurpleMedia *media, gpointer prpl_data)
+{
+#ifdef USE_VV
+	g_return_if_fail(PURPLE_IS_MEDIA(media));
+	g_object_set(G_OBJECT(media), "prpl-data", prpl_data, NULL);
+#endif
+}
+
+void
+purple_media_error(PurpleMedia *media, const gchar *error, ...)
+{
+#ifdef USE_VV
+	va_list args;
+	gchar *message;
+
+	g_return_if_fail(PURPLE_IS_MEDIA(media));
+
+	va_start(args, error);
+	message = g_strdup_vprintf(error, args);
+	va_end(args);
+
+	purple_debug_error("media", "%s\n", message);
+	g_signal_emit(media, purple_media_signals[S_ERROR], 0, message);
+
+	g_free(message);
+#endif
+}
+
+void
+purple_media_end(PurpleMedia *media,
+		const gchar *session_id, const gchar *participant)
+{
+#ifdef USE_VV
+	GList *iter, *sessions = NULL, *participants = NULL;
+
+	g_return_if_fail(PURPLE_IS_MEDIA(media));
+
+	iter = purple_media_get_streams(media, session_id, participant);
+
+	/* Free matching streams */
+	for (; iter; iter = g_list_delete_link(iter, iter)) {
+		PurpleMediaStream *stream = iter->data;
+
+		g_signal_emit(media, purple_media_signals[STATE_CHANGED],
+				0, PURPLE_MEDIA_STATE_END,
+				stream->session->id, stream->participant);
+
+		media->priv->streams =
+				g_list_remove(media->priv->streams, stream);
+
+		if (g_list_find(sessions, stream->session) == NULL)
+			sessions = g_list_prepend(sessions, stream->session);
+
+		if (g_list_find_custom(participants, stream->participant,
+				(GCompareFunc)strcmp) == NULL)
+			participants = g_list_prepend(participants,
+					g_strdup(stream->participant));
+
+		purple_media_stream_free(stream);
+	}
+
+	iter = media->priv->streams;
+
+	/* Reduce to list of sessions to remove */
+	for (; iter; iter = g_list_next(iter)) {
+		PurpleMediaStream *stream = iter->data;
+
+		sessions = g_list_remove(sessions, stream->session);
+	}
+
+	/* Free sessions with no streams left */
+	for (; sessions; sessions = g_list_delete_link(sessions, sessions)) {
+		PurpleMediaSession *session = sessions->data;
+
+		g_signal_emit(media, purple_media_signals[STATE_CHANGED],
+				0, PURPLE_MEDIA_STATE_END,
+				session->id, NULL);
+
+		g_hash_table_remove(media->priv->sessions, session->id);
+		purple_media_session_free(session);
+	}
+
+	iter = media->priv->streams;
+
+	/* Reduce to list of participants to remove */
+	for (; iter; iter = g_list_next(iter)) {
+		PurpleMediaStream *stream = iter->data;
+		GList *tmp;
+
+		tmp = g_list_find_custom(participants,
+				stream->participant, (GCompareFunc)strcmp);
+
+		if (tmp != NULL) {
+			g_free(tmp->data);
+			participants = g_list_delete_link(participants,	tmp);
+		}
+	}
+
+	/* Remove participants with no streams left (just emit the signal) */
+	for (; participants; participants =
+			g_list_delete_link(participants, participants)) {
+		gchar *participant = participants->data;
+		GList *link = g_list_find_custom(media->priv->participants,
+				participant, (GCompareFunc)strcmp);
+
+		g_signal_emit(media, purple_media_signals[STATE_CHANGED],
+				0, PURPLE_MEDIA_STATE_END,
+				NULL, participant);
+
+		if (link != NULL) {
+			g_free(link->data);
+			media->priv->participants = g_list_delete_link(
+					media->priv->participants, link);
+		}
+
+		g_free(participant);
+	}
+
+	/* Free the conference if no sessions left */
+	if (media->priv->sessions != NULL &&
+			g_hash_table_size(media->priv->sessions) == 0) {
+		g_signal_emit(media, purple_media_signals[STATE_CHANGED],
+				0, PURPLE_MEDIA_STATE_END,
+				NULL, NULL);
+		g_object_unref(media);
+		return;
+	}
+#endif
+}
+
+void
+purple_media_stream_info(PurpleMedia *media, PurpleMediaInfoType type,
+		const gchar *session_id, const gchar *participant,
+		gboolean local)
+{
+#ifdef USE_VV
+	g_return_if_fail(PURPLE_IS_MEDIA(media));
+
+	if (type == PURPLE_MEDIA_INFO_ACCEPT) {
+		GList *streams, *sessions = NULL, *participants = NULL;
+
+		g_return_if_fail(PURPLE_IS_MEDIA(media));
+
+		streams = purple_media_get_streams(media,
+				session_id, participant);
+
+		/* Emit stream acceptance */
+		for (; streams; streams =
+				g_list_delete_link(streams, streams)) {
+			PurpleMediaStream *stream = streams->data;
+
+			stream->accepted = TRUE;
+
+			g_signal_emit(media,
+					purple_media_signals[STREAM_INFO],
+					0, type, stream->session->id,
+					stream->participant, local);
+
+			if (g_list_find(sessions, stream->session) == NULL)
+				sessions = g_list_prepend(sessions,
+						stream->session);
+
+			if (g_list_find_custom(participants,
+					stream->participant,
+					(GCompareFunc)strcmp) == NULL)
+				participants = g_list_prepend(participants,
+						g_strdup(stream->participant));
+		}
+
+		/* Emit session acceptance */
+		for (; sessions; sessions =
+				g_list_delete_link(sessions, sessions)) {
+			PurpleMediaSession *session = sessions->data;
+
+			if (purple_media_accepted(media, session->id, NULL))
+				g_signal_emit(media, purple_media_signals[
+						STREAM_INFO], 0,
+						PURPLE_MEDIA_INFO_ACCEPT,
+						session->id, NULL, local);
+		}
+
+		/* Emit participant acceptance */
+		for (; participants; participants = g_list_delete_link(
+				participants, participants)) {
+			gchar *participant = participants->data;
+
+			if (purple_media_accepted(media, NULL, participant))
+				g_signal_emit(media, purple_media_signals[
+						STREAM_INFO], 0,
+						PURPLE_MEDIA_INFO_ACCEPT,
+						NULL, participant, local);
+
+			g_free(participant);
+		}
+
+		/* Emit conference acceptance */
+		if (purple_media_accepted(media, NULL, NULL))
+			g_signal_emit(media,
+					purple_media_signals[STREAM_INFO],
+					0, PURPLE_MEDIA_INFO_ACCEPT,
+					NULL, NULL, local);
+
+		return;
+	} else if (type == PURPLE_MEDIA_INFO_HANGUP ||
+			type == PURPLE_MEDIA_INFO_REJECT) {
+		GList *streams;
+
+		g_return_if_fail(PURPLE_IS_MEDIA(media));
+
+		streams = purple_media_get_streams(media,
+				session_id, participant);
+
+		/* Emit for stream */
+		for (; streams; streams =
+				g_list_delete_link(streams, streams)) {
+			PurpleMediaStream *stream = streams->data;
+
+			g_signal_emit(media,
+					purple_media_signals[STREAM_INFO],
+					0, type, stream->session->id,
+					stream->participant, local);
+		}
+
+		if (session_id != NULL && participant != NULL) {
+			/* Everything that needs to be emitted has been */
+		} else if (session_id == NULL && participant == NULL) {
+			/* Emit for everything in the conference */
+			GList *sessions = NULL;
+			GList *participants = media->priv->participants;
+
+			if (media->priv->sessions != NULL)
+				sessions = g_hash_table_get_values(
+					media->priv->sessions);
+
+			/* Emit for sessions */
+			for (; sessions; sessions = g_list_delete_link(
+					sessions, sessions)) {
+				PurpleMediaSession *session = sessions->data;
+
+				g_signal_emit(media, purple_media_signals[
+						STREAM_INFO], 0, type,
+						session->id, NULL, local);
+			}
+
+			/* Emit for participants */
+			for (; participants; participants =
+					g_list_next(participants)) {
+				gchar *participant = participants->data;
+
+				g_signal_emit(media, purple_media_signals[
+						STREAM_INFO], 0, type,
+						NULL, participant, local);
+			}
+
+			/* Emit for conference */
+			g_signal_emit(media,
+					purple_media_signals[STREAM_INFO],
+					0, type, NULL, NULL, local);
+		} else if (session_id != NULL) {
+			/* Emit just the specific session */
+			PurpleMediaSession *session =
+					purple_media_get_session(
+					media, session_id);
+
+			if (session == NULL) {
+				purple_debug_warning("media",
+						"Couldn't find session"
+						" to hangup/reject.\n");
+			} else {
+				g_signal_emit(media, purple_media_signals[
+						STREAM_INFO], 0, type,
+						session->id, NULL, local);
+			}
+		} else if (participant != NULL) {
+			/* Emit just the specific participant */
+			if (!g_list_find_custom(media->priv->participants,
+					participant, (GCompareFunc)strcmp)) {
+				purple_debug_warning("media",
+						"Couldn't find participant"
+						" to hangup/reject.\n");
+			} else {
+				g_signal_emit(media, purple_media_signals[
+						STREAM_INFO], 0, type, NULL,
+						participant, local);
+			}
+		}
+
+		purple_media_end(media, session_id, participant);
+		return;
+	}
+
+	g_signal_emit(media, purple_media_signals[STREAM_INFO],
+			0, type, session_id, participant, local);
+#endif
+}
+
+#ifdef USE_VV
+static void
+purple_media_new_local_candidate_cb(PurpleMediaBackend *backend,
+		const gchar *sess_id, const gchar *participant,
+		PurpleMediaCandidate *candidate, PurpleMedia *media)
+{
+	PurpleMediaSession *session =
+			purple_media_get_session(media, sess_id);
+
+	purple_media_insert_local_candidate(session, participant,
+			purple_media_candidate_copy(candidate));
+
+	g_signal_emit(session->media, purple_media_signals[NEW_CANDIDATE],
+		      0, session->id, participant, candidate);
+}
+
+static void
+purple_media_candidates_prepared_cb(PurpleMediaBackend *backend,
+		const gchar *sess_id, const gchar *name, PurpleMedia *media)
+{
+	PurpleMediaStream *stream_data;
+
+	g_return_if_fail(PURPLE_IS_MEDIA(media));
+
+	stream_data = purple_media_get_stream(media, sess_id, name);
+	stream_data->candidates_prepared = TRUE;
+
+	g_signal_emit(media, purple_media_signals[CANDIDATES_PREPARED],
+			0, sess_id, name);
+}
+
+/* callback called when a pair of transport candidates (local and remote)
+ * has been established */
+static void
+purple_media_candidate_pair_established_cb(PurpleMediaBackend *backend,
+		const gchar *sess_id, const gchar *name,
+		PurpleMediaCandidate *local_candidate,
+		PurpleMediaCandidate *remote_candidate,
+		PurpleMedia *media)
+{
+	PurpleMediaStream *stream;
+	GList *iter;
+	guint id;
+
+	g_return_if_fail(PURPLE_IS_MEDIA(media));
+
+	stream = purple_media_get_stream(media, sess_id, name);
+	id = purple_media_candidate_get_component_id(local_candidate);
+
+	iter = stream->active_local_candidates;
+	for(; iter; iter = g_list_next(iter)) {
+		PurpleMediaCandidate *c = iter->data;
+		if (id == purple_media_candidate_get_component_id(c)) {
+			g_object_unref(c);
+			stream->active_local_candidates =
+					g_list_delete_link(iter, iter);
+			stream->active_local_candidates = g_list_prepend(
+					stream->active_local_candidates,
+					purple_media_candidate_copy(
+					local_candidate));
+			break;
+		}
+	}
+	if (iter == NULL)
+		stream->active_local_candidates = g_list_prepend(
+				stream->active_local_candidates,
+				purple_media_candidate_copy(
+				local_candidate));
+
+	id = purple_media_candidate_get_component_id(local_candidate);
+
+	iter = stream->active_remote_candidates;
+	for(; iter; iter = g_list_next(iter)) {
+		PurpleMediaCandidate *c = iter->data;
+		if (id == purple_media_candidate_get_component_id(c)) {
+			g_object_unref(c);
+			stream->active_remote_candidates =
+					g_list_delete_link(iter, iter);
+			stream->active_remote_candidates = g_list_prepend(
+					stream->active_remote_candidates,
+					purple_media_candidate_copy(
+					remote_candidate));
+			break;
+		}
+	}
+	if (iter == NULL)
+		stream->active_remote_candidates = g_list_prepend(
+				stream->active_remote_candidates,
+				purple_media_candidate_copy(
+				remote_candidate));
+
+	purple_debug_info("media", "candidate pair established\n");
+}
+
+static void
+purple_media_codecs_changed_cb(PurpleMediaBackend *backend,
+		const gchar *sess_id, PurpleMedia *media)
+{
+	g_signal_emit(media, purple_media_signals[CODECS_CHANGED], 0, sess_id);
+}
+#endif  /* USE_VV */
+
+gboolean
+purple_media_add_stream(PurpleMedia *media, const gchar *sess_id,
+		const gchar *who, PurpleMediaSessionType type,
+		gboolean initiator, const gchar *transmitter,
+		guint num_params, GParameter *params)
+{
+#ifdef USE_VV
+	PurpleMediaSession *session;
+	PurpleMediaStream *stream = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
+
+	if (!purple_media_backend_add_stream(media->priv->backend,
+			sess_id, who, type, initiator, transmitter,
+			num_params, params)) {
+		purple_debug_error("media", "Error adding stream.\n");
+		return FALSE;
+	}
+
+	session = purple_media_get_session(media, sess_id);
+
+	if (!session) {
+		session = g_new0(PurpleMediaSession, 1);
+		session->id = g_strdup(sess_id);
+		session->media = media;
+		session->type = type;
+		session->initiator = initiator;
+
+		purple_media_add_session(media, session);
+		g_signal_emit(media, purple_media_signals[STATE_CHANGED],
+				0, PURPLE_MEDIA_STATE_NEW,
+				session->id, NULL);
+	}
+
+	if (!g_list_find_custom(media->priv->participants,
+			who, (GCompareFunc)strcmp)) {
+		media->priv->participants = g_list_prepend(
+				media->priv->participants, g_strdup(who));
+
+		g_signal_emit_by_name(media, "state-changed",
+				PURPLE_MEDIA_STATE_NEW, NULL, who);
+	}
+
+	if (purple_media_get_stream(media, sess_id, who) == NULL) {
+		stream = purple_media_insert_stream(session, who, initiator);
+
+		g_signal_emit(media, purple_media_signals[STATE_CHANGED],
+				0, PURPLE_MEDIA_STATE_NEW,
+				session->id, who);
+	}
+
+	return TRUE;
+#else
+	return FALSE;
+#endif  /* USE_VV */
+}
+
+PurpleMediaManager *
+purple_media_get_manager(PurpleMedia *media)
+{
+	PurpleMediaManager *ret;
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
+	g_object_get(media, "manager", &ret, NULL);
+	return ret;
+}
+
+PurpleMediaSessionType
+purple_media_get_session_type(PurpleMedia *media, const gchar *sess_id)
+{
+#ifdef USE_VV
+	PurpleMediaSession *session;
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), PURPLE_MEDIA_NONE);
+	session = purple_media_get_session(media, sess_id);
+	return session->type;
+#else
+	return PURPLE_MEDIA_NONE;
+#endif
+}
+/* XXX: Should wait until codecs-ready is TRUE before using this function */
+GList *
+purple_media_get_codecs(PurpleMedia *media, const gchar *sess_id)
+{
+#ifdef USE_VV
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
+
+	return purple_media_backend_get_codecs(media->priv->backend, sess_id);
+#else
+	return NULL;
+#endif
+}
+
+GList *
+purple_media_get_local_candidates(PurpleMedia *media, const gchar *sess_id,
+                                  const gchar *participant)
+{
+#ifdef USE_VV
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
+
+	return purple_media_backend_get_local_candidates(media->priv->backend,
+			sess_id, participant);
+#else
+	return NULL;
+#endif
+}
+
+void
+purple_media_add_remote_candidates(PurpleMedia *media, const gchar *sess_id,
+                                   const gchar *participant,
+                                   GList *remote_candidates)
+{
+#ifdef USE_VV
+	PurpleMediaStream *stream;
+
+	g_return_if_fail(PURPLE_IS_MEDIA(media));
+	stream = purple_media_get_stream(media, sess_id, participant);
+
+	if (stream == NULL) {
+		purple_debug_error("media",
+				"purple_media_add_remote_candidates: "
+				"couldn't find stream %s %s.\n",
+				sess_id ? sess_id : "(null)",
+				participant ? participant : "(null)");
+		return;
+	}
+
+	stream->remote_candidates = g_list_concat(stream->remote_candidates,
+			purple_media_candidate_list_copy(remote_candidates));
+
+	purple_media_backend_add_remote_candidates(media->priv->backend,
+			sess_id, participant, remote_candidates);
+#endif
+}
+
+#if 0
+/*
+ * These two functions aren't being used and I'd rather not lock in the API
+ * until they are needed. If they ever are.
+ */
+
+GList *
+purple_media_get_active_local_candidates(PurpleMedia *media,
+		const gchar *sess_id, const gchar *participant)
+{
+#ifdef USE_VV
+	PurpleMediaStream *stream;
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
+	stream = purple_media_get_stream(media, sess_id, participant);
+	return purple_media_candidate_list_copy(
+			stream->active_local_candidates);
+#else
+	return NULL;
+#endif
+}
+
+GList *
+purple_media_get_active_remote_candidates(PurpleMedia *media,
+		const gchar *sess_id, const gchar *participant)
+{
+#ifdef USE_VV
+	PurpleMediaStream *stream;
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
+	stream = purple_media_get_stream(media, sess_id, participant);
+	return purple_media_candidate_list_copy(
+			stream->active_remote_candidates);
+#else
+	return NULL;
+#endif
+}
+#endif
+
+gboolean
+purple_media_set_remote_codecs(PurpleMedia *media, const gchar *sess_id,
+                               const gchar *participant, GList *codecs)
+{
+#ifdef USE_VV
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
+
+	return purple_media_backend_set_remote_codecs(media->priv->backend,
+			sess_id, participant, codecs);
+#else
+	return FALSE;
+#endif
+}
+
+gboolean
+purple_media_candidates_prepared(PurpleMedia *media,
+		const gchar *session_id, const gchar *participant)
+{
+#ifdef USE_VV
+	GList *streams;
+	gboolean prepared = TRUE;
+
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
+
+	streams = purple_media_get_streams(media, session_id, participant);
+
+	for (; streams; streams = g_list_delete_link(streams, streams)) {
+		PurpleMediaStream *stream = streams->data;
+		if (stream->candidates_prepared == FALSE) {
+			g_list_free(streams);
+			prepared = FALSE;
+			break;
+		}
+	}
+
+	return prepared;
+#else
+	return FALSE;
+#endif
+}
+
+gboolean
+purple_media_set_send_codec(PurpleMedia *media, const gchar *sess_id, PurpleMediaCodec *codec)
+{
+#ifdef USE_VV
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
+
+	return purple_media_backend_set_send_codec(
+			media->priv->backend, sess_id, codec);
+#else
+	return FALSE;
+#endif
+}
+
+gboolean
+purple_media_codecs_ready(PurpleMedia *media, const gchar *sess_id)
+{
+#ifdef USE_VV
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
+
+	return purple_media_backend_codecs_ready(
+			media->priv->backend, sess_id);
+#else
+	return FALSE;
+#endif
+}
+
+gboolean
+purple_media_is_initiator(PurpleMedia *media,
+		const gchar *sess_id, const gchar *participant)
+{
+#ifdef USE_VV
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
+
+	if (sess_id == NULL && participant == NULL)
+		return media->priv->initiator;
+	else if (sess_id != NULL && participant == NULL) {
+		PurpleMediaSession *session =
+				purple_media_get_session(media, sess_id);
+		return session != NULL ? session->initiator : FALSE;
+	} else if (sess_id != NULL && participant != NULL) {
+		PurpleMediaStream *stream = purple_media_get_stream(
+				media, sess_id, participant);
+		return stream != NULL ? stream->initiator : FALSE;
+	}
+#endif
+	return FALSE;
+}
+
+gboolean
+purple_media_accepted(PurpleMedia *media, const gchar *sess_id,
+		const gchar *participant)
+{
+#ifdef USE_VV
+	gboolean accepted = TRUE;
+
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
+
+	if (sess_id == NULL && participant == NULL) {
+		GList *streams = media->priv->streams;
+
+		for (; streams; streams = g_list_next(streams)) {
+			PurpleMediaStream *stream = streams->data;
+			if (stream->accepted == FALSE) {
+				accepted = FALSE;
+				break;
+			}
+		}
+	} else if (sess_id != NULL && participant == NULL) {
+		GList *streams = purple_media_get_streams(
+				media, sess_id, NULL);
+		for (; streams; streams =
+				g_list_delete_link(streams, streams)) {
+			PurpleMediaStream *stream = streams->data;
+			if (stream->accepted == FALSE) {
+				g_list_free(streams);
+				accepted = FALSE;
+				break;
+			}
+		}
+	} else if (sess_id != NULL && participant != NULL) {
+		PurpleMediaStream *stream = purple_media_get_stream(
+				media, sess_id, participant);
+		if (stream == NULL || stream->accepted == FALSE)
+			accepted = FALSE;
+	}
+
+	return accepted;
+#else
+	return FALSE;
+#endif
+}
+
+void purple_media_set_input_volume(PurpleMedia *media,
+		const gchar *session_id, double level)
+{
+#ifdef USE_VV
+	g_return_if_fail(PURPLE_IS_MEDIA(media));
+	g_return_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(media->priv->backend));
+
+	purple_media_backend_fs2_set_input_volume(
+			PURPLE_MEDIA_BACKEND_FS2(
+			media->priv->backend),
+			session_id, level);
+#endif
+}
+
+void purple_media_set_output_volume(PurpleMedia *media,
+		const gchar *session_id, const gchar *participant,
+		double level)
+{
+#ifdef USE_VV
+	g_return_if_fail(PURPLE_IS_MEDIA(media));
+	g_return_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(media->priv->backend));
+
+	purple_media_backend_fs2_set_output_volume(
+			PURPLE_MEDIA_BACKEND_FS2(
+			media->priv->backend),
+			session_id, participant, level);
+#endif
+}
+
+gulong
+purple_media_set_output_window(PurpleMedia *media, const gchar *session_id,
+		const gchar *participant, gulong window_id)
+{
+#ifdef USE_VV
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE);
+
+	return purple_media_manager_set_output_window(media->priv->manager,
+			media, session_id, participant, window_id);
+#else
+	return 0;
+#endif
+}
+
+void
+purple_media_remove_output_windows(PurpleMedia *media)
+{
+#ifdef USE_VV
+	GList *iter = media->priv->streams;
+	for (; iter; iter = g_list_next(iter)) {
+		PurpleMediaStream *stream = iter->data;
+		purple_media_manager_remove_output_windows(
+				media->priv->manager, media,
+				stream->session->id, stream->participant);
+	}
+
+	iter = purple_media_get_session_ids(media);
+	for (; iter; iter = g_list_delete_link(iter, iter)) {
+		gchar *session_name = iter->data;
+		purple_media_manager_remove_output_windows(
+				media->priv->manager, media,
+				session_name, NULL);
+	}
+#endif
+}
+
+#ifdef USE_GSTREAMER
+GstElement *
+purple_media_get_tee(PurpleMedia *media,
+		const gchar *session_id, const gchar *participant)
+{
+#ifdef USE_VV
+	g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
+
+	if (PURPLE_IS_MEDIA_BACKEND_FS2(media->priv->backend))
+		return purple_media_backend_fs2_get_tee(
+				PURPLE_MEDIA_BACKEND_FS2(
+				media->priv->backend),
+				session_id, participant);
+	g_return_val_if_reached(NULL);
+#else
+	return NULL;
+#endif
+}
+#endif /* USE_GSTREAMER */
+
--- a/libpurple/mediamanager.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/mediamanager.c	Thu Feb 04 05:30:35 2010 +0000
@@ -37,8 +37,8 @@
 #endif
 
 #ifdef USE_VV
+#include <media/backend-fs2.h>
 
-#include <gst/farsight/fs-conference-iface.h>
 #include <gst/farsight/fs-element-added-notifier.h>
 #include <gst/interfaces/xoverlay.h>
 
@@ -80,6 +80,7 @@
 	GList *elements;
 	GList *output_windows;
 	gulong next_output_window_id;
+	GType backend_type;
 
 	PurpleMediaElementInfo *video_src;
 	PurpleMediaElementInfo *video_sink;
@@ -100,6 +101,7 @@
 
 enum {
 	INIT_MEDIA,
+	UI_CAPS_CHANGED,
 	LAST_SIGNAL
 };
 static guint purple_media_manager_signals[LAST_SIGNAL] = {0};
@@ -148,6 +150,15 @@
 		purple_smarshal_BOOLEAN__OBJECT_POINTER_STRING,
 		G_TYPE_BOOLEAN, 3, PURPLE_TYPE_MEDIA,
 		G_TYPE_POINTER, G_TYPE_STRING);
+
+	purple_media_manager_signals[UI_CAPS_CHANGED] = g_signal_new ("ui-caps-changed",
+		G_TYPE_FROM_CLASS (klass),
+		G_SIGNAL_RUN_LAST,
+		0, NULL, NULL,
+		purple_smarshal_VOID__FLAGS_FLAGS,
+		G_TYPE_NONE, 2, PURPLE_MEDIA_TYPE_CAPS,
+		PURPLE_MEDIA_TYPE_CAPS);
+
 	g_type_class_add_private(klass, sizeof(PurpleMediaManagerPrivate));
 }
 
@@ -157,6 +168,9 @@
 	media->priv = PURPLE_MEDIA_MANAGER_GET_PRIVATE(media);
 	media->priv->medias = NULL;
 	media->priv->next_output_window_id = 1;
+#ifdef USE_VV
+	media->priv->backend_type = PURPLE_TYPE_MEDIA_BACKEND_FS2;
+#endif
 
 	purple_prefs_add_none("/purple/media");
 	purple_prefs_add_none("/purple/media/audio");
@@ -304,34 +318,15 @@
 {
 #ifdef USE_VV
 	PurpleMedia *media;
-	FsConference *conference = FS_CONFERENCE(gst_element_factory_make(conference_type, NULL));
-	GstStateChangeReturn ret;
 	gboolean signal_ret;
 
-	if (conference == NULL) {
-		purple_conv_present_error(remote_user, account,
-					  _("Error creating conference."));
-		purple_debug_error("media", "Conference == NULL\n");
-		return NULL;
-	}
-
 	media = PURPLE_MEDIA(g_object_new(purple_media_get_type(),
 			     "manager", manager,
 			     "account", account,
-			     "conference", conference,
+			     "conference-type", conference_type,
 			     "initiator", initiator,
 			     NULL));
 
-	ret = gst_element_set_state(GST_ELEMENT(conference), GST_STATE_PLAYING);
-
-	if (ret == GST_STATE_CHANGE_FAILURE) {
-		purple_conv_present_error(remote_user, account,
-					  _("Error creating conference."));
-		purple_debug_error("media", "Failed to start conference.\n");
-		g_object_unref(media);
-		return NULL;
-	}
-
 	g_signal_emit(manager, purple_media_manager_signals[INIT_MEDIA], 0,
 			media, account, remote_user, &signal_ret);
 
@@ -894,8 +889,17 @@
 		PurpleMediaCaps caps)
 {
 #ifdef USE_VV
+	PurpleMediaCaps oldcaps;
+
 	g_return_if_fail(PURPLE_IS_MEDIA_MANAGER(manager));
+
+	oldcaps = manager->priv->ui_caps;
 	manager->priv->ui_caps = caps;
+
+	if (caps != oldcaps)
+		g_signal_emit(manager,
+				purple_media_manager_signals[UI_CAPS_CHANGED],
+				0, caps, oldcaps);
 #endif
 }
 
@@ -911,6 +915,30 @@
 #endif
 }
 
+void
+purple_media_manager_set_backend_type(PurpleMediaManager *manager,
+		GType backend_type)
+{
+#ifdef USE_VV
+	g_return_if_fail(PURPLE_IS_MEDIA_MANAGER(manager));
+
+	manager->priv->backend_type = backend_type;
+#endif
+}
+
+GType
+purple_media_manager_get_backend_type(PurpleMediaManager *manager)
+{	
+#ifdef USE_VV
+	g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager),
+			PURPLE_MEDIA_CAPS_NONE);
+
+	return manager->priv->backend_type;
+#else
+	return G_TYPE_NONE;
+#endif
+}
+
 #ifdef USE_GSTREAMER
 
 /*
--- a/libpurple/mediamanager.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/mediamanager.h	Thu Feb 04 05:30:35 2010 +0000
@@ -213,6 +213,28 @@
  */
 PurpleMediaCaps purple_media_manager_get_ui_caps(PurpleMediaManager *manager);
 
+/**
+ * Sets which media backend type media objects will use.
+ *
+ * @param manager The manager to set the caps on.
+ * @param backend_type The media backend type to use.
+ *
+ * @since 2.7.0
+ */
+void purple_media_manager_set_backend_type(PurpleMediaManager *manager,
+		GType backend_type);
+
+/**
+ * Gets which media backend type media objects will use.
+ *
+ * @param manager The manager to get the media backend type from.
+ *
+ * @return The type of media backend type media objects will use.
+ *
+ * @since 2.7.0
+ */
+GType purple_media_manager_get_backend_type(PurpleMediaManager *manager);
+
 /*}@*/
 
 #ifdef __cplusplus
--- a/libpurple/network.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/network.c	Thu Feb 04 05:30:35 2010 +0000
@@ -200,6 +200,45 @@
 	return "0.0.0.0";
 }
 
+GList *
+purple_network_get_all_local_system_ips(void)
+{
+	GList *result = NULL;
+	int source = source = socket(PF_INET,SOCK_STREAM, 0);
+	char buffer[1024];
+	char *tmp;
+	struct ifconf ifc;
+	struct ifreq *ifr;
+	
+	ifc.ifc_len = sizeof(buffer);
+	ifc.ifc_req = (struct ifreq *)buffer;
+	ioctl(source, SIOCGIFCONF, &ifc);
+	close(source);
+
+	tmp = buffer;
+	while (tmp < buffer + ifc.ifc_len) {
+		char dst[INET_ADDRSTRLEN];
+
+		ifr = (struct ifreq *)tmp;
+		tmp += HX_SIZE_OF_IFREQ(*ifr);
+
+		/* TODO: handle IPv6 */
+		if (ifr->ifr_addr.sa_family == AF_INET) {
+			struct sockaddr_in *sinptr = (struct sockaddr_in *)&ifr->ifr_addr;
+
+			inet_ntop(AF_INET, &sinptr->sin_addr, dst,
+				sizeof(dst));
+			purple_debug_info("network", 
+				"found local i/f with address %s on IPv4\n", dst);
+			if (!purple_strequal(dst, "127.0.0.1")) {
+				result = g_list_append(result, g_strdup(dst));
+			}
+		}
+	}
+
+	return result;
+}
+
 const char *
 purple_network_get_my_ip(int fd)
 {
--- a/libpurple/network.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/network.h	Thu Feb 04 05:30:35 2010 +0000
@@ -88,6 +88,17 @@
 const char *purple_network_get_local_system_ip(int fd);
 
 /**
+ * Returns all IP addresses of the local system.
+ *
+ * @note The caller must free this list, this function currently only
+ *       handles IPv4 addresses
+ * @since 2.7.0
+ *
+ * @return A list of local IP addresses.
+ */
+GList *purple_network_get_all_local_system_ips(void);
+
+/**
  * Returns the IP address that should be used anywhere a
  * public IP addresses is needed (listening for an incoming
  * file transfer, etc).
--- a/libpurple/plugin.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/plugin.c	Thu Feb 04 05:30:35 2010 +0000
@@ -254,11 +254,7 @@
 		 *
 		 * G_MODULE_BIND_LOCAL was added in glib 2.3.3.
 		 */
-#if GLIB_CHECK_VERSION(2,3,3)
 		plugin->handle = g_module_open(filename, G_MODULE_BIND_LOCAL);
-#else
-		plugin->handle = g_module_open(filename, 0);
-#endif
 
 		if (plugin->handle == NULL)
 		{
@@ -287,11 +283,7 @@
 				purple_debug_error("plugins", "%s is not loadable: %s\n",
 						 plugin->path, plugin->error);
 			}
-#if GLIB_CHECK_VERSION(2,3,3)
 			plugin->handle = g_module_open(filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
-#else
-			plugin->handle = g_module_open(filename, G_MODULE_BIND_LAZY);
-#endif
 
 			if (plugin->handle == NULL)
 			{
--- a/libpurple/plugins/autoaccept.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/plugins/autoaccept.c	Thu Feb 04 05:30:35 2010 +0000
@@ -28,13 +28,7 @@
 
 /* System headers */
 #include <glib.h>
-#if GLIB_CHECK_VERSION(2,6,0)
-#	include <glib/gstdio.h>
-#else
-#	include <sys/types.h>
-#	include <sys/stat.h>
-#	define	g_mkdir mkdir
-#endif
+#include <glib/gstdio.h>
 
 /* Purple headers */
 #include <plugin.h>
--- a/libpurple/protocols/jabber/google.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/protocols/jabber/google.c	Thu Feb 04 05:30:35 2010 +0000
@@ -1407,7 +1407,7 @@
 	JabberStream *js;
 	JabberChat *chat;
 	gchar *room;
-	guint32 tmp, a, b;
+	gchar *uuid = purple_uuid_random();
 
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
@@ -1416,26 +1416,14 @@
 	g_return_if_fail(gc != NULL);
 	js = purple_connection_get_protocol_data(gc);
 
-	/* Generate a version 4 UUID */
-	tmp = g_random_int();
-	a = 0x4000 | (tmp & 0xFFF); /* 0x4000 to 0x4FFF */
-	tmp >>= 12;
-	b = ((1 << 3) << 12) | (tmp & 0x3FFF); /* 0x8000 to 0xBFFF */
-
-	tmp = g_random_int();
-	room = g_strdup_printf("private-chat-%08x-%04x-%04x-%04x-%04x%08x",
-			g_random_int(),
-			tmp & 0xFFFF,
-			a,
-			b,
-			(tmp >> 16) & 0xFFFF, g_random_int());
-
+	room = g_strdup_printf("private-chat-%s", uuid);	
 	chat = jabber_join_chat(js, room, GOOGLE_GROUPCHAT_SERVER, js->user->node,
 	                        NULL, NULL);
 	if (chat) {
 		chat->muc = TRUE;
-		jabber_chat_invite(gc, chat->id, "", buddy->name);
+		jabber_chat_invite(gc, chat->id, "", purple_buddy_get_name(buddy));
 	}
 
 	g_free(room);
+	g_free(uuid);
 }
--- a/libpurple/protocols/jabber/jabber.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Thu Feb 04 05:30:35 2010 +0000
@@ -2876,6 +2876,11 @@
 {
 	JabberStream *js = conv->account->gc->proto_data;
 	const gchar *who;
+	gchar *description;
+	PurpleBuddy *buddy;
+	const char *alias;
+	PurpleAttentionType *attn = 
+		purple_get_attention_type_from_code(conv->account, 0);
 
 	if (!args || !args[0]) {
 		/* use the buddy from conversation, if it's a one-to-one conversation */
@@ -2888,27 +2893,18 @@
 		who = args[0];
 	}
 
-	if (_jabber_send_buzz(js, who, error)) {
-		const gchar *alias;
-		gchar *str;
-		PurpleBuddy *buddy =
-			purple_find_buddy(purple_connection_get_account(conv->account->gc),
-				who);
-
-		if (buddy != NULL)
-			alias = purple_buddy_get_contact_alias(buddy);
-		else
-			alias = who;
-
-		str = g_strdup_printf(_("Buzzing %s..."), alias);
-		purple_conversation_write(conv, NULL, str,
-			PURPLE_MESSAGE_SYSTEM|PURPLE_MESSAGE_NOTIFY, time(NULL));
-		g_free(str);
-
-		return PURPLE_CMD_RET_OK;
-	} else {
-		return PURPLE_CMD_RET_FAILED;
-	}
+	buddy = purple_find_buddy(conv->account, who);
+	if (buddy != NULL)
+		alias = purple_buddy_get_contact_alias(buddy);
+	else
+		alias = who;
+	
+	description = 
+		g_strdup_printf(purple_attention_type_get_outgoing_desc(attn), alias);
+	purple_conversation_write(conv, NULL, description, 
+		PURPLE_MESSAGE_NOTIFY | PURPLE_MESSAGE_SYSTEM, time(NULL));
+	g_free(description);
+	return _jabber_send_buzz(js, who, error)  ? PURPLE_CMD_RET_OK : PURPLE_CMD_RET_FAILED;
 }
 
 GList *jabber_attention_types(PurpleAccount *account)
@@ -3520,6 +3516,9 @@
 	jabber_add_feature(JINGLE_APP_RTP_SUPPORT_VIDEO, jabber_video_enabled);
 	jabber_add_feature(JINGLE_TRANSPORT_RAWUDP, 0);
 	jabber_add_feature(JINGLE_TRANSPORT_ICEUDP, 0);
+
+	g_signal_connect(G_OBJECT(purple_media_manager_get()), "ui-caps-changed",
+			G_CALLBACK(jabber_caps_broadcast_change), NULL);
 #endif
 
 	jabber_auth_init();
--- a/libpurple/protocols/jabber/jingle/rtp.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/protocols/jabber/jingle/rtp.c	Thu Feb 04 05:30:35 2010 +0000
@@ -468,13 +468,22 @@
 
 	g_return_if_fail(JINGLE_IS_SESSION(session));
 
-	if (type == PURPLE_MEDIA_INFO_HANGUP) {
+	if (type == PURPLE_MEDIA_INFO_HANGUP ||
+			type == PURPLE_MEDIA_INFO_REJECT) {
 		jabber_iq_send(jingle_session_terminate_packet(
-				session, "success"));
-		g_object_unref(session);
-	} else if (type == PURPLE_MEDIA_INFO_REJECT) {
-		jabber_iq_send(jingle_session_terminate_packet(
-				session, "decline"));
+				session, type == PURPLE_MEDIA_INFO_HANGUP ?
+				"success" : "decline"));
+
+		g_signal_handlers_disconnect_by_func(G_OBJECT(media),
+				G_CALLBACK(jingle_rtp_state_changed_cb),
+				session);
+		g_signal_handlers_disconnect_by_func(G_OBJECT(media),
+				G_CALLBACK(jingle_rtp_stream_info_cb),
+				session);
+		g_signal_handlers_disconnect_by_func(G_OBJECT(media),
+				G_CALLBACK(jingle_rtp_new_candidate_cb),
+				session);
+
 		g_object_unref(session);
 	} else if (type == PURPLE_MEDIA_INFO_ACCEPT &&
 			jingle_session_is_initiator(session) == FALSE) {
--- a/libpurple/protocols/jabber/jingle/session.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/protocols/jabber/jingle/session.c	Thu Feb 04 05:30:35 2010 +0000
@@ -371,7 +371,6 @@
 	return session;
 }
 
-#if GLIB_CHECK_VERSION(2,4,0)
 static gboolean find_by_jid_ghr(gpointer key,
 		gpointer value, gpointer user_data)
 {
@@ -391,58 +390,12 @@
 	return FALSE;
 }
 
-#else /* GLIB_CHECK_VERSION 2.4.0 */
-
-/* Ugly code; g_hash_table_find version above is much nicer */
-struct session_find_jid
-{
-	const gchar *jid;
-	JingleSession *ret;
-	gboolean use_bare;
-};
-
-static void find_by_jid_ghr(gpointer key, gpointer value, gpointer user_data)
-{
-	JingleSession *session = (JingleSession *)value;
-	struct session_find_jid *data = user_data;
-	gchar *remote_jid;
-	gchar *cmp_jid;
-
-	if (data->ret != NULL)
-		return;
-
-	remote_jid = jingle_session_get_remote_jid(session);
-	cmp_jid = data->use_bare ? jabber_get_bare_jid(remote_jid)
-				: g_strdup(remote_jid);
-	g_free(remote_jid);
-
-	if (g_str_equal(data->jid, cmp_jid))
-		data->ret = session;
-
-	g_free(cmp_jid);
-}
-#endif /* GLIB_CHECK_VERSION 2.4.0 */
-
 JingleSession *
 jingle_session_find_by_jid(JabberStream *js, const gchar *jid)
 {
-#if GLIB_CHECK_VERSION(2,4,0)
 	return js->sessions != NULL ?
 			g_hash_table_find(js->sessions,
 			find_by_jid_ghr, (gpointer)jid) : NULL; 
-#else
-	struct session_find_jid data;
-
-	if (js->sessions == NULL)
-		return NULL;
-
-	data.jid = jid;
-	data.ret = NULL;
-	data.use_bare = strchr(jid, '/') == NULL;
-
-	g_hash_table_foreach(js->sessions, find_by_jid_ghr, &data);
-	return data.ret;
-#endif
 }
 
 static xmlnode *
--- a/libpurple/protocols/jabber/presence.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/protocols/jabber/presence.c	Thu Feb 04 05:30:35 2010 +0000
@@ -458,6 +458,10 @@
 	jbr->caps.info = info;
 	jbr->caps.exts = exts;
 
+	purple_prpl_got_media_caps(
+			purple_connection_get_account(userdata->js->gc),
+			userdata->from);
+
 	if (info == NULL)
 		goto out;
 
--- a/libpurple/protocols/jabber/si.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/protocols/jabber/si.c	Thu Feb 04 05:30:35 2010 +0000
@@ -852,8 +852,11 @@
 	/* If we successfully started listening locally */
 	if (sock >= 0) {
 		gchar *jid;
-		const char *local_ip, *public_ip;
-
+		GList *local_ips =
+			purple_network_get_all_local_system_ips();
+		const char *public_ip;
+		gboolean has_public_ip = FALSE;
+		
 		jsx->local_streamhost_fd = sock;
 
 		jid = g_strdup_printf("%s@%s/%s", jsx->js->user->node,
@@ -861,19 +864,24 @@
 		xfer->local_port = purple_network_get_port_from_fd(sock);
 		g_snprintf(port, sizeof(port), "%hu", xfer->local_port);
 
-		/* Include the localhost's IP (for in-network transfers) */
-		local_ip = purple_network_get_local_system_ip(jsx->js->fd);
-		if (strcmp(local_ip, "0.0.0.0") != 0) {
+		public_ip = purple_network_get_my_ip(jsx->js->fd);
+
+		/* Include the localhost's IPs (for in-network transfers) */
+		while (local_ips) {
+			gchar *local_ip = local_ips->data;
 			streamhost_count++;
 			streamhost = xmlnode_new_child(query, "streamhost");
 			xmlnode_set_attrib(streamhost, "jid", jid);
 			xmlnode_set_attrib(streamhost, "host", local_ip);
 			xmlnode_set_attrib(streamhost, "port", port);
+			if (purple_strequal(local_ip, public_ip))
+				has_public_ip = TRUE;
+			g_free(local_ip);
+			local_ips = g_list_delete_link(local_ips, local_ips);
 		}
 
 		/* Include the public IP (assuming that there is a port mapped somehow) */
-		public_ip = purple_network_get_my_ip(jsx->js->fd);
-		if (strcmp(public_ip, local_ip) != 0 && strcmp(public_ip, "0.0.0.0") != 0) {
+		if (!has_public_ip && strcmp(public_ip, "0.0.0.0") != 0) {
 			streamhost_count++;
 			streamhost = xmlnode_new_child(query, "streamhost");
 			xmlnode_set_attrib(streamhost, "jid", jid);
--- a/libpurple/protocols/msn/msg.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/protocols/msn/msg.c	Thu Feb 04 05:30:35 2010 +0000
@@ -1043,7 +1043,6 @@
 
 			else
 				purple_prpl_got_attention(account->gc, user, MSN_NUDGE);
-
 		} else {
 			purple_prpl_got_attention(account->gc, user, MSN_NUDGE);
 		}
--- a/libpurple/protocols/msn/nexus.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/protocols/msn/nexus.c	Thu Feb 04 05:30:35 2010 +0000
@@ -244,15 +244,6 @@
 	gpointer data;
 };
 
-#if !GLIB_CHECK_VERSION(2, 12, 0)
-static gboolean
-nexus_remove_all_cb(gpointer key, gpointer val, gpointer data)
-{
-	return TRUE;
-}
-#endif
-
-
 static gboolean
 nexus_parse_token(MsnNexus *nexus, int id, xmlnode *node)
 {
@@ -281,12 +272,7 @@
 	if (token_str == NULL)
 		return FALSE;
 
-#if GLIB_CHECK_VERSION(2, 12, 0)
 	g_hash_table_remove_all(nexus->tokens[id].token);
-#else
-	g_hash_table_foreach_remove(nexus->tokens[id].token,
-		nexus_remove_all_cb, NULL);
-#endif
 
 	elems = g_strsplit(token_str, "&", 0);
 
--- a/libpurple/protocols/msn/state.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/protocols/msn/state.c	Thu Feb 04 05:30:35 2010 +0000
@@ -112,11 +112,7 @@
 	 *  6: Album
 	 *  7: ?
 	 */
-#if GLIB_CHECK_VERSION(2,6,0)
 	strings  = g_strv_length(cmedia_array);
-#else
-	while (cmedia_array[++strings] != NULL);
-#endif
 
 	if (strings >= 4 && !strcmp(cmedia_array[2], "1")) {
 		media = g_new(CurrentMedia, 1);
--- a/libpurple/protocols/msnp9/msn.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/protocols/msnp9/msn.c	Thu Feb 04 05:30:35 2010 +0000
@@ -775,7 +775,8 @@
 
 	gc->proto_data = session;
 	gc->flags |= PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_FORMATTING_WBFO | PURPLE_CONNECTION_NO_BGCOLOR |
-		PURPLE_CONNECTION_NO_FONTSIZE | PURPLE_CONNECTION_NO_URLDESC | PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY;
+		PURPLE_CONNECTION_NO_FONTSIZE | PURPLE_CONNECTION_NO_URLDESC | PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY |
+		PURPLE_CONNECTION_ALLOW_ATTENTION;
 
 	msn_session_set_login_step(session, MSN_LOGIN_STEP_START);
 
--- a/libpurple/protocols/mxit/mxit.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/protocols/mxit/mxit.c	Thu Feb 04 05:30:35 2010 +0000
@@ -188,7 +188,11 @@
 
 	/* find the buddy object */
 	buddy = purple_find_buddy( session->acc, who );
-	if ( ( !buddy ) || ( !buddy->proto_data ) )
+	if ( !buddy )
+		return;
+
+	contact = purple_buddy_get_protocol_data(buddy);
+	if ( !contact )
 		return;
 
 	/* we ignore all conversations with which we have chatted with in this session */
@@ -196,7 +200,6 @@
 		return;
 
 	/* determite if this buddy is a MXit service */
-	contact = buddy->proto_data;
 	switch ( contact->type ) {
 		case MXIT_TYPE_BOT :
 		case MXIT_TYPE_CHATROOM :
@@ -258,7 +261,7 @@
  */
 static const char* mxit_list_emblem( PurpleBuddy* buddy )
 {
-	struct contact*	contact = buddy->proto_data;
+	struct contact*	contact = purple_buddy_get_protocol_data(buddy);
 
 	if ( !contact )
 		return NULL;
@@ -295,7 +298,7 @@
  */
 char* mxit_status_text( PurpleBuddy* buddy )
 {
-	struct contact*	contact = buddy->proto_data;
+	struct contact*	contact = purple_buddy_get_protocol_data(buddy);
 
 	if ( !contact )
 		return NULL;
@@ -320,7 +323,7 @@
  */
 static void mxit_tooltip( PurpleBuddy* buddy, PurpleNotifyUserInfo* info, gboolean full )
 {
-	struct contact*	contact = buddy->proto_data;
+	struct contact*	contact = purple_buddy_get_protocol_data(buddy);
 
 	if ( !contact )
 		return;
@@ -455,7 +458,7 @@
 
 	purple_debug_info( MXIT_PLUGIN_ID, "mxit_free_buddy\n" );
 
-	contact = buddy->proto_data;
+	contact = purple_buddy_get_protocol_data(buddy);
 	if ( contact ) {
 		if ( contact->statusMsg )
 			g_free( contact->statusMsg );
@@ -463,7 +466,8 @@
 			g_free( contact->avatarId );
 		g_free( contact );
 	}
-	buddy->proto_data = NULL;
+
+	purple_buddy_set_protocol_data(buddy, NULL);
 }
 
 
--- a/libpurple/protocols/mxit/profile.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/protocols/mxit/profile.c	Thu Feb 04 05:30:35 2010 +0000
@@ -115,9 +115,9 @@
 
 	buddy = purple_find_buddy( session->acc, username );
 	if ( buddy ) {
-		purple_notify_user_info_add_pair( info, _( "Alias" ), buddy->alias );
+		purple_notify_user_info_add_pair( info, _( "Alias" ), purple_buddy_get_alias( buddy ) );
 		purple_notify_user_info_add_section_break( info );
-		contact = buddy->proto_data;
+		contact = purple_buddy_get_protocol_data(buddy);
 	}
 
 	purple_notify_user_info_add_pair( info, _( "Nick Name" ), profile->nickname );
--- a/libpurple/protocols/mxit/roster.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/protocols/mxit/roster.c	Thu Feb 04 05:30:35 2010 +0000
@@ -318,7 +318,7 @@
 
 		/* create new buddy */
 		buddy = purple_buddy_new( session->acc, contact->username, contact->alias );
-		buddy->proto_data = contact;
+		purple_buddy_set_protocol_data(buddy, contact);
 
 		/* add new buddy to list */
 		purple_blist_add_buddy( buddy, NULL, group, NULL );
@@ -326,13 +326,15 @@
 	else {
 		/* buddy was found in the group */
 
+		gpointer data = NULL;
+
 		/* now update the buddy's alias */
 		purple_blist_alias_buddy( buddy, contact->alias );
 
 		/* replace the buddy's contact struct */
-		if ( buddy->proto_data )
-			free( buddy->proto_data );
-		buddy->proto_data = contact;
+		if ( ( data = purple_buddy_get_protocol_data( buddy ) ) )
+			free( data );
+		purple_buddy_set_protocol_data( buddy, contact );
 	}
 
 	/* load buddy's avatar id */
@@ -379,7 +381,7 @@
 		return;
 	}
 
-	contact = buddy->proto_data;
+	contact = purple_buddy_get_protocol_data( buddy );
 	if ( !contact )
 		return;
 
@@ -439,9 +441,12 @@
 	for ( i = 0; i < g_slist_length( list ); i++ ) {
 		buddy = g_slist_nth_data( list, i );
 
-		if ( !buddy->proto_data ) {
+		if ( !purple_buddy_get_protocol_data( buddy ) ) {
+			const gchar *alias = purple_buddy_get_alias( buddy );
+			const gchar *name = purple_buddy_get_name( buddy );
+
 			/* this buddy should be removed, because we did not receive him in our roster update from MXit */
-			purple_debug_info( MXIT_PLUGIN_ID, "Removed 'old' buddy from the blist '%s' (%s)\n", buddy->alias, buddy->name );
+			purple_debug_info( MXIT_PLUGIN_ID, "Removed 'old' buddy from the blist '%s' (%s)\n", alias, name );
 			purple_blist_remove_buddy( buddy );
 		}
 	}
@@ -535,7 +540,7 @@
 		return FALSE;
 	}
 
-	contact = buddy->proto_data;
+	contact = purple_buddy_get_protocol_data( buddy );
 	if ( !contact )
 		return FALSE;
 
@@ -560,10 +565,13 @@
 	GSList*				list	= NULL;
 	PurpleBuddy*		mxbuddy	= NULL;
 	unsigned int		i;
+	const gchar *		buddy_name = purple_buddy_get_name( buddy );
+	const gchar *		buddy_alias = purple_buddy_get_alias( buddy );
+	const gchar *		group_name = purple_group_get_name( group );
 
-	purple_debug_info( MXIT_PLUGIN_ID, "mxit_add_buddy '%s' (group='%s')\n", buddy->name, group->name );
+	purple_debug_info( MXIT_PLUGIN_ID, "mxit_add_buddy '%s' (group='%s')\n", buddy_name, group_name );
 
-	list = purple_find_buddies( session->acc, buddy->name );
+	list = purple_find_buddies( session->acc, buddy_name );
 	if ( g_slist_length( list ) == 1 ) {
 		purple_debug_info( MXIT_PLUGIN_ID, "mxit_add_buddy (scenario 1) (list:%i)\n", g_slist_length( list ) );
 		/*
@@ -572,7 +580,7 @@
 		 * you accept an invite.  so in that case the user is already
 		 * in our blist and ready to be chatted to.
 		 */
-		mxit_send_invite( session, buddy->name, buddy->alias, group->name );
+		mxit_send_invite( session, buddy_name, buddy_alias, group_name );
 	}
 	else {
 		purple_debug_info( MXIT_PLUGIN_ID, "mxit_add_buddy (scenario 2) (list:%i)\n", g_slist_length( list ) );
@@ -585,17 +593,17 @@
 		for ( i = 0; i < g_slist_length( list ); i++ ) {
 			mxbuddy = g_slist_nth_data( list, i );
 
-			if ( mxbuddy->proto_data != NULL ) {
+			if ( purple_buddy_get_protocol_data( mxbuddy ) != NULL ) {
 				/* this is our REAL MXit buddy! */
 
 				/* now update the buddy's alias */
-				purple_blist_alias_buddy( mxbuddy, buddy->alias );
+				purple_blist_alias_buddy( mxbuddy, buddy_alias );
 
 				/* now update the buddy's group */
 //				mxbuddy = mxit_update_buddy_group( session, mxbuddy, group );
 
 				/* send the update to the MXit server */
-				mxit_send_update_contact( session, mxbuddy->name, mxbuddy->alias, group->name );
+				mxit_send_update_contact( session, purple_buddy_get_name( mxbuddy ), purple_buddy_get_alias( mxbuddy ), group_name );
 			}
 		}
 	}
@@ -623,10 +631,11 @@
 void mxit_remove_buddy( PurpleConnection* gc, PurpleBuddy* buddy, PurpleGroup* group )
 {
 	struct MXitSession*	session	= (struct MXitSession*) gc->proto_data;
+	const gchar *		buddy_name = purple_buddy_get_name( buddy );
 
-	purple_debug_info( MXIT_PLUGIN_ID, "mxit_remove_buddy '%s'\n", buddy->name );
+	purple_debug_info( MXIT_PLUGIN_ID, "mxit_remove_buddy '%s'\n", buddy_name );
 
-	mxit_send_remove( session, buddy->name );
+	mxit_send_remove( session, buddy_name );
 }
 
 
@@ -659,7 +668,7 @@
 		return;
 	}
 
-	mxit_send_update_contact( session, who, alias, group->name );
+	mxit_send_update_contact( session, who, alias, purple_group_get_name( group ) );
 }
 
 
@@ -685,7 +694,7 @@
 		return;
 	}
 
-	mxit_send_update_contact( session, who, buddy->alias, new_group );
+	mxit_send_update_contact( session, who, purple_buddy_get_alias( buddy ), new_group );
 }
 
 
@@ -704,7 +713,7 @@
 	PurpleBuddy*		buddy	= NULL;
 	GList*				item	= NULL;
 
-	purple_debug_info( MXIT_PLUGIN_ID, "mxit_rename_group from '%s' to '%s\n", old_name, group->name );
+	purple_debug_info( MXIT_PLUGIN_ID, "mxit_rename_group from '%s' to '%s\n", old_name, purple_group_get_name( group ) );
 
 	//  TODO: Might be more efficient to use the "rename group" command (cmd=29).
 
@@ -712,7 +721,7 @@
 	item = moved_buddies;
 	while ( item ) {
 		buddy = item->data;
-		mxit_send_update_contact( session, buddy->name, buddy->alias, group->name );
+		mxit_send_update_contact( session, purple_buddy_get_name( buddy ), purple_buddy_get_alias( buddy ), purple_group_get_name( group ) );
 		item = g_list_next( item );
 	}
 }
--- a/libpurple/protocols/myspace/user.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/protocols/myspace/user.c	Thu Feb 04 05:30:35 2010 +0000
@@ -54,11 +54,13 @@
 
 	user = purple_buddy_get_protocol_data(buddy);
 	if (create && !user) {
+		PurpleBlistNode *node = PURPLE_BLIST_NODE(buddy);
+
 		/* No MsimUser for this buddy; make one. */
 
 		user = g_new0(MsimUser, 1);
 		user->buddy = buddy;
-		user->id = purple_blist_node_get_int(&buddy->node, "UserID");
+		user->id = purple_blist_node_get_int(node, "UserID");
 		purple_buddy_set_protocol_data(buddy, user);
 	}
 
--- a/libpurple/protocols/qq/buddy_memo.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/protocols/qq/buddy_memo.c	Thu Feb 04 05:30:35 2010 +0000
@@ -119,7 +119,7 @@
 
 	who = uid_to_purple_name(bd_uid);
 	buddy = purple_find_buddy(account, who);
-	if (buddy == NULL || buddy->proto_data == NULL) {
+	if (buddy == NULL || purple_buddy_get_protocol_data(buddy) == NULL) {
 		g_free(who);
 		purple_debug_info("QQ", "Error...Can NOT find %d!\n", bd_uid);
 		return;
--- a/libpurple/protocols/yahoo/libymsg.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/protocols/yahoo/libymsg.c	Thu Feb 04 05:30:35 2010 +0000
@@ -1116,9 +1116,12 @@
 		m = m2;
 		purple_util_chrreplace(m, '\r', '\n');
 		if (!strcmp(m, "<ding>")) {
+			PurpleConversation *conv = NULL;
 			char *username;
 
 			username = g_markup_escape_text(im->fed_from, -1);
+			conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY,
+				username, account);
 			purple_prpl_got_attention(gc, username, YAHOO_BUZZ);
 			g_free(username);
 			g_free(m);
@@ -1764,11 +1767,8 @@
 		char *crumb = NULL;
 		char *crypt = NULL;
 
-#if GLIB_CHECK_VERSION(2,6,0)
 		totalelements = g_strv_length(split_data);
-#else
-		while (split_data[++totalelements] != NULL);
-#endif
+
 		if (totalelements >= 4) {
 			response_no = strtol(split_data[0], NULL, 10);
 			crumb = g_strdup(split_data[1] + strlen("crumb="));
@@ -1850,11 +1850,8 @@
 		int response_no = -1;
 		char *token = NULL;
 
-#if GLIB_CHECK_VERSION(2,6,0)
 		totalelements = g_strv_length(split_data);
-#else
-		while (split_data[++totalelements] != NULL);
-#endif
+
 		if(totalelements == 1)
 			response_no = strtol(split_data[0], NULL, 10);
 		else if(totalelements >= 2) {
--- a/libpurple/protocols/yahoo/yahoo_filexfer.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/protocols/yahoo/yahoo_filexfer.c	Thu Feb 04 05:30:35 2010 +0000
@@ -509,9 +509,6 @@
 		return 0;
 	}
 
-	if ((purple_xfer_get_bytes_sent(xfer) + len) >= purple_xfer_get_size(xfer))
-		purple_xfer_set_completed(xfer, TRUE);
-
 	return len;
 }
 
--- a/libpurple/prpl.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/prpl.c	Thu Feb 04 05:30:35 2010 +0000
@@ -288,8 +288,10 @@
 
 	/* The buddy is no longer online, they are therefore by definition not
 	 * still typing to us. */
-	if (!purple_status_is_online(status))
+	if (!purple_status_is_online(status)) {
 		serv_got_typing_stopped(purple_account_get_connection(account), name);
+		purple_prpl_got_media_caps(account, name);
+	}
 }
 
 void purple_prpl_got_user_status_deactive(PurpleAccount *account, const char *name,
@@ -407,6 +409,16 @@
 	return statuses;
 }
 
+static void
+purple_prpl_attention(PurpleConversation *conv, const char *who,
+	guint type, PurpleMessageFlags flags, time_t mtime)
+{
+	PurpleAccount *account = purple_conversation_get_account(conv);
+	purple_signal_emit(purple_conversations_get_handle(),
+		flags == PURPLE_MESSAGE_SEND ? "sent-attention" : "got-attention",
+		account, who, conv, type);
+}
+
 void
 purple_prpl_send_attention(PurpleConnection *gc, const char *who, guint type_code)
 {
@@ -452,6 +464,7 @@
 
 	conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, gc->account, who);
 	purple_conv_im_write(PURPLE_CONV_IM(conv), NULL, description, flags, mtime);
+	purple_prpl_attention(conv, who, type_code, PURPLE_MESSAGE_SEND, time(NULL));
 
 	g_free(description);
 }
@@ -503,7 +516,15 @@
 void
 purple_prpl_got_attention(PurpleConnection *gc, const char *who, guint type_code)
 {
+	PurpleConversation *conv = NULL;
+	PurpleAccount *account = purple_connection_get_account(gc);
+
 	got_attention(gc, -1, who, type_code);
+	conv = 
+		purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, who, account);
+	if (conv)
+		purple_prpl_attention(conv, who, type_code, PURPLE_MESSAGE_RECV,
+			time(NULL));
 }
 
 void
@@ -560,6 +581,39 @@
 	return PURPLE_MEDIA_CAPS_NONE;
 }
 
+void
+purple_prpl_got_media_caps(PurpleAccount *account, const char *name)
+{
+#ifdef USE_VV
+	GSList *list;
+
+	g_return_if_fail(account != NULL);
+	g_return_if_fail(name    != NULL);
+
+	if ((list = purple_find_buddies(account, name)) == NULL)
+		return;
+
+	while (list) {
+		PurpleBuddy *buddy = list->data;
+		PurpleMediaCaps oldcaps = purple_buddy_get_media_caps(buddy);
+		PurpleMediaCaps newcaps = 0;
+		const gchar *bname = purple_buddy_get_name(buddy);
+		list = g_slist_delete_link(list, list);
+
+		
+		newcaps = purple_prpl_get_media_caps(account, bname);
+		purple_buddy_set_media_caps(buddy, newcaps);
+
+		if (oldcaps == newcaps)
+			continue;
+
+		purple_signal_emit(purple_blist_get_handle(),
+				"buddy-caps-changed", buddy,
+				newcaps, oldcaps);
+	}
+#endif
+}
+
 /**************************************************************************
  * Protocol Plugin Subsystem API
  **************************************************************************/
--- a/libpurple/prpl.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/prpl.h	Thu Feb 04 05:30:35 2010 +0000
@@ -903,6 +903,17 @@
 					const char *who,
 					PurpleMediaSessionType type);
 
+/**
+ * Signals that the prpl received capabilities for the given contact.
+ *
+ * This function is intended to be used only by prpls.
+ *
+ * @param account The account the user is on.
+ * @param who The name of the contact for which capabilities have been received.
+ * @since 2.7.0
+ */
+void purple_prpl_got_media_caps(PurpleAccount *account, const char *who);
+
 /*@}*/
 
 /**************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purple-2-uninstalled.pc.in	Thu Feb 04 05:30:35 2010 +0000
@@ -0,0 +1,22 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+datarootdir=@datarootdir@
+datadir=@datadir@
+sysconfdir=@sysconfdir@
+
+abs_srcdir=@abs_srcdir@
+abs_builddir=@abs_builddir@
+
+abs_top_srcdir=@abs_top_srcdir@
+abs_top_builddir=@abs_top_builddir@
+
+plugindir=${libdir}/purple-@PURPLE_MAJOR_VERSION@
+
+Name: libpurple
+Description: libpurple is a GLib-based instant messenger library.
+Version: @VERSION@
+Requires: glib-2.0
+Cflags: -I${abs_top_srcdir} -I${abs_top_builddir}
+Libs: ${abs_builddir}/libpurple.la
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purple-2.pc.in	Thu Feb 04 05:30:35 2010 +0000
@@ -0,0 +1,16 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+datarootdir=@datarootdir@
+datadir=@datadir@
+sysconfdir=@sysconfdir@
+
+plugindir=${libdir}/purple-@PURPLE_MAJOR_VERSION@
+
+Name: libpurple
+Description: libpurple is a GLib-based instant messenger library.
+Version: @VERSION@
+Requires: glib-2.0
+Cflags: -I${includedir}
+Libs: -L${libdir} -lpurple
--- a/libpurple/purple-uninstalled.pc.in	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/purple-uninstalled.pc.in	Thu Feb 04 05:30:35 2010 +0000
@@ -9,6 +9,8 @@
 abs_srcdir=@abs_srcdir@
 abs_builddir=@abs_builddir@
 
+plugindir=${libdir}/purple-@PURPLE_MAJOR_VERSION@
+
 Name: libpurple
 Description: libpurple is a GLib-based instant messenger library.
 Version: @VERSION@
--- a/libpurple/purple.pc.in	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/purple.pc.in	Thu Feb 04 05:30:35 2010 +0000
@@ -6,6 +6,8 @@
 datadir=@datadir@
 sysconfdir=@sysconfdir@
 
+plugindir=${libdir}/purple-@PURPLE_MAJOR_VERSION@
+
 Name: libpurple
 Description: libpurple is a GLib-based instant messenger library.
 Version: @VERSION@
--- a/libpurple/sound.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/sound.h	Thu Feb 04 05:30:35 2010 +0000
@@ -51,6 +51,7 @@
 	PURPLE_SOUND_CHAT_SAY,         /**< Someone else says somthing in a chat. */
 	PURPLE_SOUND_POUNCE_DEFAULT,   /**< Default sound for a buddy pounce.     */
 	PURPLE_SOUND_CHAT_NICK,        /**< Someone says your name in a chat.     */
+	PURPLE_SOUND_GOT_ATTENTION,	   /**< Got an attention					  */
 	PURPLE_NUM_SOUNDS              /**< Total number of sounds.               */
 
 } PurpleSoundEventID;
--- a/libpurple/util.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/util.c	Thu Feb 04 05:30:35 2010 +0000
@@ -220,50 +220,12 @@
 gchar *
 purple_base64_encode(const guchar *data, gsize len)
 {
-#if GLIB_CHECK_VERSION(2,12,0)
 	return g_base64_encode(data, len);
-#else
-	char *out, *rv;
-
-	g_return_val_if_fail(data != NULL, NULL);
-	g_return_val_if_fail(len > 0,  NULL);
-
-	rv = out = g_malloc(((len/3)+1)*4 + 1);
-
-	for (; len >= 3; len -= 3)
-	{
-		*out++ = alphabet[data[0] >> 2];
-		*out++ = alphabet[((data[0] << 4) & 0x30) | (data[1] >> 4)];
-		*out++ = alphabet[((data[1] << 2) & 0x3c) | (data[2] >> 6)];
-		*out++ = alphabet[data[2] & 0x3f];
-		data += 3;
-	}
-
-	if (len > 0)
-	{
-		unsigned char fragment;
-
-		*out++ = alphabet[data[0] >> 2];
-		fragment = (data[0] << 4) & 0x30;
-
-		if (len > 1)
-			fragment |= data[1] >> 4;
-
-		*out++ = alphabet[fragment];
-		*out++ = (len < 2) ? '=' : alphabet[(data[1] << 2) & 0x3c];
-		*out++ = '=';
-	}
-
-	*out = '\0';
-
-	return rv;
-#endif /* GLIB < 2.12.0 */
 }
 
 guchar *
 purple_base64_decode(const char *str, gsize *ret_len)
 {
-#if GLIB_CHECK_VERSION(2,12,0)
 	/*
 	 * We want to allow ret_len to be NULL for backward compatibility,
 	 * but g_base64_decode() requires a valid length variable.  So if
@@ -271,69 +233,6 @@
 	 */
 	gsize unused;
 	return g_base64_decode(str, ret_len != NULL ? ret_len : &unused);
-#else
-	guchar *out = NULL;
-	char tmp = 0;
-	const char *c;
-	gint32 tmp2 = 0;
-	int len = 0, n = 0;
-
-	g_return_val_if_fail(str != NULL, NULL);
-
-	c = str;
-
-	while (*c) {
-		if (*c >= 'A' && *c <= 'Z') {
-			tmp = *c - 'A';
-		} else if (*c >= 'a' && *c <= 'z') {
-			tmp = 26 + (*c - 'a');
-		} else if (*c >= '0' && *c <= 57) {
-			tmp = 52 + (*c - '0');
-		} else if (*c == '+') {
-			tmp = 62;
-		} else if (*c == '/') {
-			tmp = 63;
-		} else if (*c == '\r' || *c == '\n') {
-			c++;
-			continue;
-		} else if (*c == '=') {
-			if (n == 3) {
-				out = g_realloc(out, len + 2);
-				out[len] = (guchar)(tmp2 >> 10) & 0xff;
-				len++;
-				out[len] = (guchar)(tmp2 >> 2) & 0xff;
-				len++;
-			} else if (n == 2) {
-				out = g_realloc(out, len + 1);
-				out[len] = (guchar)(tmp2 >> 4) & 0xff;
-				len++;
-			}
-			break;
-		}
-		tmp2 = ((tmp2 << 6) | (tmp & 0xff));
-		n++;
-		if (n == 4) {
-			out = g_realloc(out, len + 3);
-			out[len] = (guchar)((tmp2 >> 16) & 0xff);
-			len++;
-			out[len] = (guchar)((tmp2 >> 8) & 0xff);
-			len++;
-			out[len] = (guchar)(tmp2 & 0xff);
-			len++;
-			tmp2 = 0;
-			n = 0;
-		}
-		c++;
-	}
-
-	out = g_realloc(out, len + 1);
-	out[len] = 0;
-
-	if (ret_len != NULL)
-		*ret_len = len;
-
-	return out;
-#endif /* GLIB < 2.12.0 */
 }
 
 /**************************************************************************
@@ -2656,56 +2555,7 @@
 
 int purple_build_dir (const char *path, int mode)
 {
-#if GLIB_CHECK_VERSION(2,8,0)
 	return g_mkdir_with_parents(path, mode);
-#else
-	char *dir, **components, delim[] = { G_DIR_SEPARATOR, '\0' };
-	int cur, len;
-
-	g_return_val_if_fail(path != NULL, -1);
-
-	dir = g_new0(char, strlen(path) + 1);
-	components = g_strsplit(path, delim, -1);
-	len = 0;
-	for (cur = 0; components[cur] != NULL; cur++) {
-		/* If you don't know what you're doing on both
-		 * win32 and *NIX, stay the hell away from this code */
-		if(cur > 1)
-			dir[len++] = G_DIR_SEPARATOR;
-		strcpy(dir + len, components[cur]);
-		len += strlen(components[cur]);
-		if(cur == 0)
-			dir[len++] = G_DIR_SEPARATOR;
-
-		if(g_file_test(dir, G_FILE_TEST_IS_DIR)) {
-			continue;
-#ifdef _WIN32
-		/* allow us to create subdirs on UNC paths
-		 * (\\machinename\path\to\blah)
-		 * g_file_test() doesn't work on "\\machinename" */
-		} else if (cur == 2 && dir[0] == '\\' && dir[1] == '\\'
-				&& components[cur + 1] != NULL) {
-			continue;
-#endif
-		} else if(g_file_test(dir, G_FILE_TEST_EXISTS)) {
-			purple_debug_warning("build_dir", "bad path: %s\n", path);
-			g_strfreev(components);
-			g_free(dir);
-			return -1;
-		}
-
-		if (g_mkdir(dir, mode) < 0) {
-			purple_debug_warning("build_dir", "mkdir: %s\n", g_strerror(errno));
-			g_strfreev(components);
-			g_free(dir);
-			return -1;
-		}
-	}
-
-	g_strfreev(components);
-	g_free(dir);
-	return 0;
-#endif
 }
 
 /*
@@ -3218,30 +3068,13 @@
 gboolean
 purple_str_has_prefix(const char *s, const char *p)
 {
-#if GLIB_CHECK_VERSION(2,2,0)
 	return g_str_has_prefix(s, p);
-#else
-	g_return_val_if_fail(s != NULL, FALSE);
-	g_return_val_if_fail(p != NULL, FALSE);
-
-	return (!strncmp(s, p, strlen(p)));
-#endif
 }
 
 gboolean
 purple_str_has_suffix(const char *s, const char *x)
 {
-#if GLIB_CHECK_VERSION(2,2,0)
 	return g_str_has_suffix(s, x);
-#else
-	int off;
-
-	g_return_val_if_fail(s != NULL, FALSE);
-	g_return_val_if_fail(x != NULL, FALSE);
-
-	off = strlen(s) - strlen(x);
-	return (off >= 0 && purple_strequal(s + off, x));
-#endif
 }
 
 char *
@@ -5138,18 +4971,25 @@
 const gchar *
 purple_get_host_name(void)
 {
-#if GLIB_CHECK_VERSION(2,8,0)
 	return g_get_host_name();
-#else
-	static char hostname[256];
-	int ret = gethostname(hostname, sizeof(hostname));
-	hostname[sizeof(hostname) - 1] = '\0';
-
-	if (ret == -1 || hostname[0] == '\0') {
-		purple_debug_info("purple_get_host_name: ", "could not find host name");
-		return "localhost";
-	} else {
-		return hostname;
-	}
-#endif
 }
+
+gchar *
+purple_uuid_random(void)
+{
+	guint32 tmp, a, b;
+
+	tmp = g_random_int();
+	a = 0x4000 | (tmp & 0xFFF); /* 0x4000 to 0x4FFF */
+	tmp >>= 12;
+	b = ((1 << 3) << 12) | (tmp & 0x3FFF); /* 0x8000 to 0xBFFF */
+
+	tmp = g_random_int();
+
+	return g_strdup_printf("%08x-%04x-%04x-%04x-%04x%08x",
+			g_random_int(),
+			tmp & 0xFFFF,
+			a,
+			b,
+			(tmp >> 16) & 0xFFFF, g_random_int());
+}
--- a/libpurple/util.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/util.h	Thu Feb 04 05:30:35 2010 +0000
@@ -42,6 +42,7 @@
 typedef struct _PurpleKeyValuePair PurpleKeyValuePair;
 
 #include "account.h"
+#include "signals.h"
 #include "xmlnode.h"
 #include "notify.h"
 
@@ -1427,6 +1428,14 @@
  */
 const gchar *purple_get_host_name(void);
 
+/**
+ * Returns a type 4 (random) UUID
+ *
+ * @return A UUID, caller is responsible for freeing it
+ * @since 2.7.0
+ */
+gchar *purple_uuid_random(void);
+
 #ifdef __cplusplus
 }
 #endif
--- a/libpurple/win32/libc_interface.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/win32/libc_interface.c	Thu Feb 04 05:30:35 2010 +0000
@@ -469,65 +469,7 @@
 /* stdio.h */
 
 int wpurple_rename (const char *oldname, const char *newname) {
-
-#if GLIB_CHECK_VERSION(2,8,5)
-
 	return g_rename(oldname, newname);
-
-#else
-
-	/* This is a ugly, but we still compile with 2.6.10 but use newer runtimes */
-	struct stat oldstat, newstat;
-
-	/* As of Glib 2.8.5, g_rename() uses MoveFileEx() with MOVEFILE_REPLACE_EXISTING to behave more sanely */
-	if (glib_check_version(2, 8, 5) == NULL) {
-		return g_rename(oldname, newname);
-	}
-
-	if(g_stat(oldname, &oldstat) == 0) {
-		/* newname exists */
-		if(g_stat(newname, &newstat) == 0) {
-			/* oldname is a dir */
-			if(S_ISDIR(oldstat.st_mode)) {
-				if(!S_ISDIR(newstat.st_mode)) {
-					return g_rename(oldname, newname);
-				}
-				/* newname is a dir */
-				else {
-					/* This is not quite right.. If newname is empty and
-					   is not a sub dir of oldname, newname should be
-					   deleted and oldname should be renamed.
-					*/
-					purple_debug(PURPLE_DEBUG_WARNING, "wpurple", "wpurple_rename does not behave here as it should\n");
-					return g_rename(oldname, newname);
-				}
-			}
-			/* oldname is not a dir */
-			else {
-				/* newname is a dir */
-				if(S_ISDIR(newstat.st_mode)) {
-					errno = EISDIR;
-					return -1;
-				}
-				/* newname is not a dir */
-				else {
-					g_remove(newname);
-					return g_rename(oldname, newname);
-				}
-			}
-		}
-		/* newname doesn't exist */
-		else
-			return g_rename(oldname, newname);
-	}
-	else {
-		/* oldname doesn't exist */
-		errno = ENOENT;
-		return -1;
-	}
-
-#endif
-
 }
 
 /* time.h */
@@ -1129,54 +1071,7 @@
 wpurple_g_access (const gchar *filename,
 	  int          mode)
 {
-#if GLIB_CHECK_VERSION(2,8,0)
-
 	return g_access(filename, mode);
-
-#else
-
-  if (G_WIN32_HAVE_WIDECHAR_API ())
-    {
-      wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
-      int retval;
-      int save_errno;
-
-      if (wfilename == NULL)
-	{
-	  errno = EINVAL;
-	  return -1;
-	}
-
-      retval = _waccess (wfilename, mode);
-      save_errno = errno;
-
-      g_free (wfilename);
-
-      errno = save_errno;
-      return retval;
-    }
-  else
-    {
-      gchar *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
-      int retval;
-      int save_errno;
-
-      if (cp_filename == NULL)
-	{
-	  errno = EINVAL;
-	  return -1;
-	}
-
-      retval = access (cp_filename, mode);
-      save_errno = errno;
-
-      g_free (cp_filename);
-
-      errno = save_errno;
-      return retval;
-    }
-
-#endif
 }
 
 
--- a/libpurple/win32/libc_interface.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/win32/libc_interface.h	Thu Feb 04 05:30:35 2010 +0000
@@ -115,11 +115,6 @@
 #define close( fd ) \
 wpurple_close( fd )
 
-#if !GLIB_CHECK_VERSION(2,8,0)
-#define g_access( filename, mode) \
-wpurple_g_access( filename, mode )
-#endif
-
 #ifndef sleep
 #define sleep(x) Sleep((x)*1000)
 #endif
@@ -140,14 +135,12 @@
 #define rename( oldname, newname ) \
 wpurple_rename( oldname, newname )
 
-#if GLIB_CHECK_VERSION(2,6,0)
 #ifdef g_rename
 # undef g_rename
 #endif
 /* This is necessary because we want rename on win32 to be able to overwrite an existing file, it is done in internal.h if GLib < 2.6*/
 #define g_rename(oldname, newname) \
 wpurple_rename(oldname, newname)
-#endif
 
 /* sys/stat.h */
 #define fchmod(a,b)
--- a/libpurple/win32/libc_internal.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/win32/libc_internal.h	Thu Feb 04 05:30:35 2010 +0000
@@ -141,10 +141,6 @@
 int wpurple_gethostname(char *name, size_t size);
 
 
-#if !GLIB_CHECK_VERSION(2,8,0)
-int wpurple_g_access(const gchar *filename, int mode);
-#endif
-
 /* stdio.h */
 int wpurple_rename(const char *oldname, const char *newname);
 
--- a/libpurple/win32/win32dep.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/libpurple/win32/win32dep.c	Thu Feb 04 05:30:35 2010 +0000
@@ -30,14 +30,6 @@
 #include "notify.h"
 
 /*
- *  DEFINES & MACROS
- */
-
-/* For shfolder.dll */
-typedef HRESULT (CALLBACK* LPFNSHGETFOLDERPATHA)(HWND, int, HANDLE, DWORD, LPSTR);
-typedef HRESULT (CALLBACK* LPFNSHGETFOLDERPATHW)(HWND, int, HANDLE, DWORD, LPWSTR);
-
-/*
  * LOCALS
  */
 static char *app_data_dir = NULL, *install_dir = NULL,
@@ -115,37 +107,12 @@
 
 /* Get paths to special Windows folders. */
 gchar *wpurple_get_special_folder(int folder_type) {
-	static LPFNSHGETFOLDERPATHA MySHGetFolderPathA = NULL;
-	static LPFNSHGETFOLDERPATHW MySHGetFolderPathW = NULL;
 	gchar *retval = NULL;
-
-	if (!MySHGetFolderPathW) {
-		MySHGetFolderPathW = (LPFNSHGETFOLDERPATHW)
-			wpurple_find_and_loadproc("shfolder.dll", "SHGetFolderPathW");
-	}
-
-	if (MySHGetFolderPathW) {
-		wchar_t utf_16_dir[MAX_PATH + 1];
+	wchar_t utf_16_dir[MAX_PATH + 1];
 
-		if (SUCCEEDED(MySHGetFolderPathW(NULL, folder_type, NULL,
-						SHGFP_TYPE_CURRENT, utf_16_dir))) {
-			retval = g_utf16_to_utf8(utf_16_dir, -1, NULL, NULL, NULL);
-		}
-	}
-
-	if (!retval) {
-		if (!MySHGetFolderPathA) {
-			MySHGetFolderPathA = (LPFNSHGETFOLDERPATHA)
-				wpurple_find_and_loadproc("shfolder.dll", "SHGetFolderPathA");
-		}
-		if (MySHGetFolderPathA) {
-			char locale_dir[MAX_PATH + 1];
-
-			if (SUCCEEDED(MySHGetFolderPathA(NULL, folder_type, NULL,
-							SHGFP_TYPE_CURRENT, locale_dir))) {
-				retval = g_locale_to_utf8(locale_dir, -1, NULL, NULL, NULL);
-			}
-		}
+	if (SUCCEEDED(SHGetFolderPathW(NULL, folder_type, NULL,
+					SHGFP_TYPE_CURRENT, utf_16_dir))) {
+		retval = g_utf16_to_utf8(utf_16_dir, -1, NULL, NULL, NULL);
 	}
 
 	return retval;
@@ -156,20 +123,11 @@
 
 	if (!initialized) {
 		char *tmp = NULL;
-		if (G_WIN32_HAVE_WIDECHAR_API()) {
-			wchar_t winstall_dir[MAXPATHLEN];
-			if (GetModuleFileNameW(NULL, winstall_dir,
-					MAXPATHLEN) > 0) {
-				tmp = g_utf16_to_utf8(winstall_dir, -1,
-					NULL, NULL, NULL);
-			}
-		} else {
-			gchar cpinstall_dir[MAXPATHLEN];
-			if (GetModuleFileNameA(NULL, cpinstall_dir,
-					MAXPATHLEN) > 0) {
-				tmp = g_locale_to_utf8(cpinstall_dir,
-					-1, NULL, NULL, NULL);
-			}
+		wchar_t winstall_dir[MAXPATHLEN];
+		if (GetModuleFileNameW(NULL, winstall_dir,
+				MAXPATHLEN) > 0) {
+			tmp = g_utf16_to_utf8(winstall_dir, -1,
+				NULL, NULL, NULL);
 		}
 
 		if (tmp == NULL) {
@@ -246,61 +204,33 @@
 	HKEY reg_key;
 	gboolean success = FALSE;
 
-	if(G_WIN32_HAVE_WIDECHAR_API()) {
-		wchar_t *wc_subkey = g_utf8_to_utf16(subkey, -1, NULL,
-			NULL, NULL);
-
-		if(RegOpenKeyExW(rootkey, wc_subkey, 0,
-				KEY_SET_VALUE, &reg_key) == ERROR_SUCCESS) {
-			wchar_t *wc_valname = NULL;
-
-			if (valname)
-				wc_valname = g_utf8_to_utf16(valname, -1,
-					NULL, NULL, NULL);
+	wchar_t *wc_subkey = g_utf8_to_utf16(subkey, -1, NULL,
+		NULL, NULL);
 
-			if(value) {
-				wchar_t *wc_value = g_utf8_to_utf16(value, -1,
-					NULL, NULL, NULL);
-				int len = (wcslen(wc_value) * sizeof(wchar_t)) + 1;
-				if(RegSetValueExW(reg_key, wc_valname, 0, REG_SZ,
-						(LPBYTE)wc_value, len
-						) == ERROR_SUCCESS)
-					success = TRUE;
-				g_free(wc_value);
-			} else
-				if(RegDeleteValueW(reg_key, wc_valname) ==  ERROR_SUCCESS)
-					success = TRUE;
+	if(RegOpenKeyExW(rootkey, wc_subkey, 0,
+			KEY_SET_VALUE, &reg_key) == ERROR_SUCCESS) {
+		wchar_t *wc_valname = NULL;
+
+		if (valname)
+			wc_valname = g_utf8_to_utf16(valname, -1,
+				NULL, NULL, NULL);
 
-			g_free(wc_valname);
-		}
-		g_free(wc_subkey);
-	} else {
-		char *cp_subkey = g_locale_from_utf8(subkey, -1, NULL,
-			NULL, NULL);
-		if(RegOpenKeyExA(rootkey, cp_subkey, 0,
-				KEY_SET_VALUE, &reg_key) == ERROR_SUCCESS) {
-			char *cp_valname = NULL;
-			if(valname)
-				cp_valname = g_locale_from_utf8(valname, -1,
-					NULL, NULL, NULL);
+		if(value) {
+			wchar_t *wc_value = g_utf8_to_utf16(value, -1,
+				NULL, NULL, NULL);
+			int len = (wcslen(wc_value) * sizeof(wchar_t)) + 1;
+			if(RegSetValueExW(reg_key, wc_valname, 0, REG_SZ,
+					(LPBYTE)wc_value, len
+					) == ERROR_SUCCESS)
+				success = TRUE;
+			g_free(wc_value);
+		} else
+			if(RegDeleteValueW(reg_key, wc_valname) ==  ERROR_SUCCESS)
+				success = TRUE;
 
-			if (value) {
-				char *cp_value = g_locale_from_utf8(value, -1,
-					NULL, NULL, NULL);
-				int len = strlen(cp_value) + 1;
-				if(RegSetValueExA(reg_key, cp_valname, 0, REG_SZ,
-						cp_value, len
-						) == ERROR_SUCCESS)
-					success = TRUE;
-				g_free(cp_value);
-			} else
-				if(RegDeleteValueA(reg_key, cp_valname) ==  ERROR_SUCCESS)
-					success = TRUE;
-
-			g_free(cp_valname);
-		}
-		g_free(cp_subkey);
+		g_free(wc_valname);
 	}
+	g_free(wc_subkey);
 
 	if(reg_key != NULL)
 		RegCloseKey(reg_key);
@@ -312,17 +242,11 @@
 	HKEY reg_key = NULL;
 	LONG rv;
 
-	if(G_WIN32_HAVE_WIDECHAR_API()) {
-		wchar_t *wc_subkey = g_utf8_to_utf16(subkey, -1, NULL,
-			NULL, NULL);
-		rv = RegOpenKeyExW(rootkey, wc_subkey, 0, access, &reg_key);
-		g_free(wc_subkey);
-	} else {
-		char *cp_subkey = g_locale_from_utf8(subkey, -1, NULL,
-			NULL, NULL);
-		rv = RegOpenKeyExA(rootkey, cp_subkey, 0, access, &reg_key);
-		g_free(cp_subkey);
-	}
+	wchar_t *wc_subkey = g_utf8_to_utf16(subkey, -1, NULL,
+		NULL, NULL);
+	rv = RegOpenKeyExW(rootkey, wc_subkey, 0, access, &reg_key);
+
+	g_free(wc_subkey);
 
 	if (rv != ERROR_SUCCESS) {
 		char *errmsg = g_win32_error_message(rv);
@@ -340,19 +264,11 @@
 static gboolean _reg_read(HKEY reg_key, const char *valname, LPDWORD type, LPBYTE data, LPDWORD data_len) {
 	LONG rv;
 
-	if(G_WIN32_HAVE_WIDECHAR_API()) {
-		wchar_t *wc_valname = NULL;
-		if (valname)
-			wc_valname = g_utf8_to_utf16(valname, -1, NULL, NULL, NULL);
-		rv = RegQueryValueExW(reg_key, wc_valname, 0, type, data, data_len);
-		g_free(wc_valname);
-	} else {
-		char *cp_valname = NULL;
-		if(valname)
-			cp_valname = g_locale_from_utf8(valname, -1, NULL, NULL, NULL);
-		rv = RegQueryValueExA(reg_key, cp_valname, 0, type, data, data_len);
-		g_free(cp_valname);
-	}
+	wchar_t *wc_valname = NULL;
+	if (valname)
+		wc_valname = g_utf8_to_utf16(valname, -1, NULL, NULL, NULL);
+	rv = RegQueryValueExW(reg_key, wc_valname, 0, type, data, data_len);
+	g_free(wc_valname);
 
 	if (rv != ERROR_SUCCESS) {
 		char *errmsg = g_win32_error_message(rv);
@@ -389,24 +305,13 @@
 
 	if(reg_key) {
 		if(_reg_read(reg_key, valname, &type, NULL, &nbytes) && type == REG_SZ) {
-			LPBYTE data;
-			if(G_WIN32_HAVE_WIDECHAR_API())
-				data = (LPBYTE) g_new(wchar_t, ((nbytes + 1) / sizeof(wchar_t)) + 1);
-			else
-				data = (LPBYTE) g_malloc(nbytes + 1);
+			LPBYTE data = (LPBYTE) g_new(wchar_t, ((nbytes + 1) / sizeof(wchar_t)) + 1);
 
 			if(_reg_read(reg_key, valname, &type, data, &nbytes)) {
-				if(G_WIN32_HAVE_WIDECHAR_API()) {
-					wchar_t *wc_temp = (wchar_t*) data;
-					wc_temp[nbytes / sizeof(wchar_t)] = '\0';
-					result = g_utf16_to_utf8(wc_temp, -1,
-						NULL, NULL, NULL);
-				} else {
-					char *cp_temp = (char*) data;
-					cp_temp[nbytes] = '\0';
-					result = g_locale_to_utf8(cp_temp, -1,
-						NULL, NULL, NULL);
-				}
+				wchar_t *wc_temp = (wchar_t*) data;
+				wc_temp[nbytes / sizeof(wchar_t)] = '\0';
+				result = g_utf16_to_utf8(wc_temp, -1,
+					NULL, NULL, NULL);
 			}
 			g_free(data);
 		}
--- a/pidgin/Makefile.am	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/Makefile.am	Thu Feb 04 05:30:35 2010 +0000
@@ -74,17 +74,12 @@
 
 pidgin_SOURCES = \
 	eggtrayicon.c \
-	pidgincombobox.c \
 	pidginstock.c \
 	gtkaccount.c \
 	gtkblist.c \
 	gtkblist-theme.c \
 	gtkblist-theme-loader.c \
-	gtkcelllayout.c \
 	gtkcellrendererexpander.c \
-	gtkcellrendererprogress.c \
-	gtkcellview.c \
-	gtkcellviewmenuitem.c \
 	gtkcertmgr.c \
 	gtkconn.c \
 	gtkconv.c \
@@ -92,9 +87,9 @@
 	gtkdialogs.c \
 	gtkdnd-hints.c \
 	gtkdocklet.c \
+	gtkdocklet-gtk.c \
 	gtkdocklet-x11.c \
 	gtkeventloop.c \
-	gtkexpander.c \
 	gtkft.c \
 	gtkicon-theme.c \
 	gtkicon-theme-loader.c \
@@ -135,13 +130,8 @@
 	gtkblist.h \
 	gtkblist-theme.h \
 	gtkblist-theme-loader.h \
-	gtkcelllayout.h \
 	gtkcellrendererexpander.h \
-	gtkcellrendererprogress.h \
-	gtkcellview.h \
-	gtkcellviewmenuitem.h \
 	gtkcertmgr.h \
-	pidgincombobox.h \
 	gtkconn.h \
 	gtkconv.h \
 	gtkconvwin.h \
@@ -150,7 +140,6 @@
 	gtkdnd-hints.h \
 	gtkdocklet.h \
 	gtkeventloop.h \
-	gtkexpander.h \
 	gtkft.h \
 	gtkicon-theme.h \
 	gtkicon-theme-loader.h \
--- a/pidgin/Makefile.mingw	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/Makefile.mingw	Thu Feb 04 05:30:35 2010 +0000
@@ -61,7 +61,6 @@
 			gtkblist-theme.c \
 			gtkblist.c \
 			gtkcellrendererexpander.c \
-			gtkcellrendererprogress.c \
 			gtkcertmgr.c \
 			gtkconn.c \
 			gtkconv.c \
@@ -70,7 +69,6 @@
 			gtkdnd-hints.c \
 			gtkdocklet.c \
 			gtkeventloop.c \
-			gtkexpander.c \
 			gtkft.c \
 			gtkicon-theme-loader.c \
 			gtkicon-theme.c \
--- a/pidgin/gtkaccount.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkaccount.c	Thu Feb 04 05:30:35 2010 +0000
@@ -474,9 +474,7 @@
 
 	/* Username */
 	dialog->username_entry = gtk_entry_new();
-#if GTK_CHECK_VERSION(2,10,0)
 	g_object_set(G_OBJECT(dialog->username_entry), "truncate-multiline", TRUE, NULL);
-#endif
 
 	add_pref_box(dialog, vbox, _("_Username:"), dialog->username_entry);
 
@@ -2081,25 +2079,12 @@
 	return ret;
 }
 
-#if !GTK_CHECK_VERSION(2,2,0)
-static void
-get_selected_helper(GtkTreeModel *model, GtkTreePath *path,
-					GtkTreeIter *iter, gpointer user_data)
-{
-	*((gboolean *)user_data) = TRUE;
-}
-#endif
-
 static void
 account_selected_cb(GtkTreeSelection *sel, AccountsWindow *dialog)
 {
 	gboolean selected = FALSE;
 
-#if GTK_CHECK_VERSION(2,2,0)
 	selected = (gtk_tree_selection_count_selected_rows(sel) > 0);
-#else
-	gtk_tree_selection_selected_foreach(sel, get_selected_helper, &selected);
-#endif
 
 	gtk_widget_set_sensitive(dialog->modify_button, selected);
 	gtk_widget_set_sensitive(dialog->delete_button, selected);
--- a/pidgin/gtkblist.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkblist.c	Thu Feb 04 05:30:35 2010 +0000
@@ -137,13 +137,9 @@
 static struct pidgin_blist_sort_method *current_sort_method = NULL;
 static void sort_method_none(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
 
-/* The functions we use for sorting aren't available in gtk 2.0.x, and
- * segfault in 2.2.0.  2.2.1 is known to work, so I'll require that */
-#if GTK_CHECK_VERSION(2,2,1)
 static void sort_method_alphabetical(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
 static void sort_method_status(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
 static void sort_method_log_activity(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
-#endif
 static PidginBuddyList *gtkblist = NULL;
 
 static GList *groups_tree(void);
@@ -201,7 +197,6 @@
 
 static gboolean gtk_blist_window_state_cb(GtkWidget *w, GdkEventWindowState *event, gpointer data)
 {
-#if GTK_CHECK_VERSION(2,2,0)
 	if(event->changed_mask & GDK_WINDOW_STATE_WITHDRAWN) {
 		if(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN)
 			purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/list_visible", FALSE);
@@ -223,28 +218,6 @@
 		if (!(event->new_window_state & GDK_WINDOW_STATE_ICONIFIED))
 			pidgin_blist_refresh_timer(purple_get_blist());
 	}
-#else
-	/* At least gtk+ 2.0.6 does not properly set the change_mask when unsetting a
-	 * GdkWindowState flag. To work around, the window state will be explicitly
-	 * queried on these older versions of gtk+. See pidgin ticket #739.
-	 */
-	GdkWindowState new_window_state = gdk_window_get_state(G_OBJECT(gtkblist->window->window));
-
-	if(new_window_state & GDK_WINDOW_STATE_WITHDRAWN) {
-		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/list_visible", FALSE);
-	} else {
-		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/list_visible", TRUE);
-		pidgin_blist_refresh_timer(purple_get_blist());
-	}
-
-	if(new_window_state & GDK_WINDOW_STATE_MAXIMIZED)
-		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/list_maximized", TRUE);
-	else
-		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/list_maximized", FALSE);
-
-	if (!(new_window_state & GDK_WINDOW_STATE_ICONIFIED))
-		pidgin_blist_refresh_timer(purple_get_blist());
-#endif
 
 	return FALSE;
 }
@@ -434,7 +407,6 @@
 	gtk_blist_join_chat(chat);
 }
 
-#if GTK_CHECK_VERSION(2,6,0)
 static void gtk_blist_renderer_editing_cancelled_cb(GtkCellRenderer *renderer, PurpleBuddyList *list)
 {
 	editing_blist = FALSE;
@@ -483,7 +455,6 @@
 	}
 	editing_blist = TRUE;
 }
-#endif
 
 static void
 gtk_blist_do_personize(GList *merges)
@@ -763,12 +734,8 @@
 	g_object_set(G_OBJECT(gtkblist->text_rend), "editable", TRUE, NULL);
 	gtk_tree_view_set_enable_search (GTK_TREE_VIEW(gtkblist->treeview), FALSE);
 	gtk_widget_grab_focus(gtkblist->treeview);
-#if GTK_CHECK_VERSION(2,2,0)
 	gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(gtkblist->treeview), path,
 			gtkblist->text_column, gtkblist->text_rend, TRUE);
-#else
-	gtk_tree_view_set_cursor(GTK_TREE_VIEW(gtkblist->treeview), path, gtkblist->text_column, TRUE);
-#endif
 	gtk_tree_path_free(path);
 }
 
@@ -1241,9 +1208,9 @@
 
 		purple_blist_node_set_bool(node, "collapsed", TRUE);
 
-		for(cnode = node->child; cnode; cnode = cnode->next) {
+		for(cnode = purple_blist_node_get_first_child(node); cnode; cnode = purple_blist_node_get_sibling_next(cnode)) {
 			if (PURPLE_BLIST_NODE_IS_CONTACT(cnode)) {
-				gtknode = cnode->ui_data;
+				gtknode = purple_blist_node_get_ui_data(cnode);
 				if (!gtknode->contact_expanded)
 					continue;
 				gtknode->contact_expanded = FALSE;
@@ -1275,7 +1242,7 @@
 		else
 			buddy = (PurpleBuddy*)node;
 
-		pidgin_dialogs_im_with_user(buddy->account, buddy->name);
+		pidgin_dialogs_im_with_user(purple_buddy_get_account(buddy), purple_buddy_get_name(buddy));
 	} else if (PURPLE_BLIST_NODE_IS_CHAT(node)) {
 		gtk_blist_join_chat((PurpleChat *)node);
 	} else if (PURPLE_BLIST_NODE_IS_GROUP(node)) {
@@ -1295,9 +1262,9 @@
 	if(gtk_tree_selection_get_selected(sel, NULL, &iter)){
 		gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &node, -1);
 		if (PURPLE_BLIST_NODE_IS_BUDDY(node))
-			purple_blist_request_add_chat(NULL, (PurpleGroup*)node->parent->parent, NULL, NULL);
+			purple_blist_request_add_chat(NULL, purple_buddy_get_group(PURPLE_BUDDY(node)), NULL, NULL);
 		if (PURPLE_BLIST_NODE_IS_CONTACT(node) || PURPLE_BLIST_NODE_IS_CHAT(node))
-			purple_blist_request_add_chat(NULL, (PurpleGroup*)node->parent, NULL, NULL);
+			purple_blist_request_add_chat(NULL, purple_contact_get_group(PURPLE_CONTACT(node)), NULL, NULL);
 		else if (PURPLE_BLIST_NODE_IS_GROUP(node))
 			purple_blist_request_add_chat(NULL, (PurpleGroup*)node, NULL, NULL);
 	}
@@ -1315,13 +1282,13 @@
 	if(gtk_tree_selection_get_selected(sel, NULL, &iter)){
 		gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), &iter, NODE_COLUMN, &node, -1);
 		if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
-			purple_blist_request_add_buddy(NULL, NULL, ((PurpleGroup*)node->parent->parent)->name,
-					NULL);
-		} else if (PURPLE_BLIST_NODE_IS_CONTACT(node)
-				|| PURPLE_BLIST_NODE_IS_CHAT(node)) {
-			purple_blist_request_add_buddy(NULL, NULL, ((PurpleGroup*)node->parent)->name, NULL);
+			PurpleGroup *group = purple_buddy_get_group(PURPLE_BUDDY(node));
+			purple_blist_request_add_buddy(NULL, NULL, purple_group_get_name(group), NULL);
+		} else if (PURPLE_BLIST_NODE_IS_CONTACT(node) || PURPLE_BLIST_NODE_IS_CHAT(node)) {
+			PurpleGroup *group = purple_contact_get_group(PURPLE_CONTACT(node));
+			purple_blist_request_add_buddy(NULL, NULL, purple_group_get_name(group), NULL);
 		} else if (PURPLE_BLIST_NODE_IS_GROUP(node)) {
-			purple_blist_request_add_buddy(NULL, NULL, ((PurpleGroup*)node)->name, NULL);
+			purple_blist_request_add_buddy(NULL, NULL, purple_group_get_name(PURPLE_GROUP(node)), NULL);
 		}
 	}
 	else {
@@ -1373,11 +1340,11 @@
 	if(!PURPLE_BLIST_NODE_IS_CONTACT(node))
 		return;
 
-	gtknode = (struct _pidgin_blist_node *)node->ui_data;
+	gtknode = purple_blist_node_get_ui_data(node);
 
 	gtknode->contact_expanded = TRUE;
 
-	for(bnode = node->child; bnode; bnode = bnode->next) {
+	for(bnode = purple_blist_node_get_first_child(node); bnode; bnode = purple_blist_node_get_sibling_next(bnode)) {
 		pidgin_blist_update(NULL, bnode);
 	}
 
@@ -1392,7 +1359,7 @@
 		/* Let the treeview draw so it knows where to scroll */
 		ex->treeview = GTK_TREE_VIEW(gtkblist->treeview);
 		ex->path = path;
-		ex->node = node->child;
+		ex->node = purple_blist_node_get_first_child(node);
 		g_idle_add(scroll_to_expanded_cell, ex);
 	}
 }
@@ -1406,11 +1373,11 @@
 	if(!PURPLE_BLIST_NODE_IS_CONTACT(node))
 		return;
 
-	gtknode = (struct _pidgin_blist_node *)node->ui_data;
+	gtknode = purple_blist_node_get_ui_data(node);
 
 	gtknode->contact_expanded = FALSE;
 
-	for(bnode = node->child; bnode; bnode = bnode->next) {
+	for(bnode = purple_blist_node_get_first_child(node); bnode; bnode = purple_blist_node_get_sibling_next(bnode)) {
 		pidgin_blist_update(NULL, bnode);
 	}
 }
@@ -1501,10 +1468,10 @@
 	submenu = gtk_menu_new();
 	gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
 
-	for (group = purple_blist_get_root(); group; group = group->next) {
-		if (group->type != PURPLE_BLIST_GROUP_NODE)
+	for (group = purple_blist_get_root(); group; group = purple_blist_node_get_sibling_next(group)) {
+		if (!PURPLE_BLIST_NODE_IS_GROUP(group))
 			continue;
-		if (group == node->parent)
+		if (group == purple_blist_node_get_parent(node))
 			continue;
 		menuitem = pidgin_new_item_from_stock(submenu, purple_group_get_name((PurpleGroup *)group), NULL,
 						      G_CALLBACK(gtk_blist_menu_move_to_cb), node, 0, 0, NULL);
@@ -1515,6 +1482,8 @@
 
 void
 pidgin_blist_make_buddy_menu(GtkWidget *menu, PurpleBuddy *buddy, gboolean sub) {
+	PurpleAccount *account = NULL;
+	PurpleConnection *pc = NULL;
 	PurplePluginProtocolInfo *prpl_info;
 	PurpleContact *contact;
 	PurpleBlistNode *node;
@@ -1523,13 +1492,16 @@
 	g_return_if_fail(menu);
 	g_return_if_fail(buddy);
 
-	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(buddy->account->gc->prpl);
-
-	node = (PurpleBlistNode*)buddy;
+	account = purple_buddy_get_account(buddy);
+	pc = purple_account_get_connection(account);
+	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(pc));
+
+	node = PURPLE_BLIST_NODE(buddy);
 
 	contact = purple_buddy_get_contact(buddy);
 	if (contact) {
-		contact_expanded = ((struct _pidgin_blist_node *)(((PurpleBlistNode*)contact)->ui_data))->contact_expanded;
+		PidginBlistNode *node = purple_blist_node_get_ui_data(PURPLE_BLIST_NODE(contact));
+		contact_expanded = node->contact_expanded;
 	}
 
 	if (prpl_info && prpl_info->get_info) {
@@ -3065,7 +3037,6 @@
 						current_height-1,td->avatar_width+2, td->avatar_height+2);
 		}
 
-#if GTK_CHECK_VERSION(2,2,0)
 		if (td->status_icon) {
 			if (dir == GTK_TEXT_DIR_RTL)
 				gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, td->status_icon,
@@ -3092,16 +3063,6 @@
 					current_height + ((td->name_height / 2) - (PRPL_SIZE / 2)),
 					-1 , -1, GDK_RGB_DITHER_NONE, 0, 0);
 
-#else
-		if (td->status_icon) {
-			gdk_pixbuf_render_to_drawable(td->status_icon, GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, 0, 0, 12, current_height, -1, -1, GDK_RGB_DITHER_NONE, 0, 0);
-		}
-		if(td->avatar)
-			gdk_pixbuf_render_to_drawable(td->avatar,
-					GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, 0, 0,
-					max_width - (td->avatar_width + TOOLTIP_BORDER),
-					current_height, -1, -1, GDK_RGB_DITHER_NONE, 0, 0);
-#endif
 		if (td->name_layout) {
 			if (dir == GTK_TEXT_DIR_RTL) {
 				gtk_paint_layout(style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, FALSE,
@@ -3480,12 +3441,13 @@
 	/* Help */
 	{ N_("/_Help"), NULL, NULL, 0, "<Branch>", NULL },
 	{ N_("/Help/Online _Help"), "F1", gtk_blist_show_onlinehelp_cb, 0, "<StockItem>", GTK_STOCK_HELP },
+	{ "/Help/sep1", NULL, NULL, 0, "<Separator>", NULL },
+	{ N_("/Help/_Build Information"), NULL, pidgin_dialogs_buildinfo, 0, "<Item>", NULL },
 	{ N_("/Help/_Debug Window"), NULL, toggle_debug, 0, "<Item>", NULL },
-#if GTK_CHECK_VERSION(2,6,0)
+	{ N_("/Help/De_veloper Information"), NULL, pidgin_dialogs_developers, 0, "<Item>", NULL },
+	{ N_("/Help/_Translator Information"), NULL, pidgin_dialogs_translators, 0, "<Item>", NULL },
+	{ "/Help/sep2", NULL, NULL, 0, "<Separator>", NULL },
 	{ N_("/Help/_About"), NULL, pidgin_dialogs_about, 4,  "<StockItem>", GTK_STOCK_ABOUT },
-#else
-	{ N_("/Help/_About"), NULL, pidgin_dialogs_about, 4,  "<Item>", NULL },
-#endif
 };
 
 /*********************************************************
@@ -4075,44 +4037,11 @@
 				g_free(tmp);
 				tmp = new;
 			}
-			/* add ... to messages that are too long, GTK 2.6+ does it automatically */
-#if !GTK_CHECK_VERSION(2,6,0)
-			if(tmp) {
-				char buf[32];
-				char *c = tmp;
-				int length = 0, vis=0;
-				gboolean inside = FALSE;
-				g_strdelimit(tmp, "\n", ' ');
-				purple_str_strip_char(tmp, '\r');
-
-				while(*c && vis < 20) {
-					if(*c == '&')
-						inside = TRUE;
-					else if(*c == ';')
-						inside = FALSE;
-					if(!inside)
-						vis++;
-					c = g_utf8_next_char(c); /* this is fun */
-				}
-
-				length = c - tmp;
-
-				if(vis == 20)
-					g_snprintf(buf, sizeof(buf), "%%.%ds...", length);
-				else
-					g_snprintf(buf, sizeof(buf), "%%s ");
-
-				statustext = g_strdup_printf(buf, tmp);
-
-				g_free(tmp);
-			}
-#else
 			if(tmp) {
 				g_strdelimit(tmp, "\n", ' ');
 				purple_str_strip_char(tmp, '\r');
 			}
 			statustext = tmp;
-#endif
 		}
 
 		if(!purple_presence_is_online(presence) && !statustext)
@@ -4671,11 +4600,9 @@
 	const char *id;
 
 	pidgin_blist_sort_method_reg("none", _("Manually"), sort_method_none);
-#if GTK_CHECK_VERSION(2,2,1)
 	pidgin_blist_sort_method_reg("alphabetical", _("Alphabetically"), sort_method_alphabetical);
 	pidgin_blist_sort_method_reg("status", _("By status"), sort_method_status);
 	pidgin_blist_sort_method_reg("log_size", _("By recent log activity"), sort_method_log_activity);
-#endif
 
 	id = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/blist/sort_type");
 	if (id == NULL) {
@@ -4699,9 +4626,7 @@
 	}
 
 	redo_buddy_list(purple_get_blist(), FALSE, FALSE);
-#if GTK_CHECK_VERSION(2,6,0)
 	gtk_tree_view_columns_autosize(GTK_TREE_VIEW(gtkblist->treeview));
-#endif
 
 	if (node)
 	{
@@ -4737,11 +4662,7 @@
 
 	/* this is far too ugly thanks to me not wanting to fix #3989 properly right now */
 	if (priv->error_scrollbook != NULL) {
-#if GTK_CHECK_VERSION(2,2,0)
 		errors = gtk_notebook_get_n_pages(GTK_NOTEBOOK(priv->error_scrollbook->notebook));
-#else
-		errors = g_list_length(GTK_NOTEBOOK(priv->error_scrollbook->notebook)->children);
-#endif
 	}
 	if ((list = purple_accounts_get_all_active()) != NULL || errors) {
 		gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkblist->notebook), 1);
@@ -4818,23 +4739,11 @@
 	gdk_window_set_cursor(widget->window, gtkblist->hand_cursor);
 
 	if (gtkblist->headline_close) {
-#if GTK_CHECK_VERSION(2,2,0)
 		gdk_draw_pixbuf(widget->window, NULL, gtkblist->headline_close,
-#else
-		gdk_pixbuf_render_to_drawable(gtkblist->headline_close,
-				GDK_DRAWABLE(widget->window), NULL,
-#endif
 					0, 0,
 					widget->allocation.width - 2 - HEADLINE_CLOSE_SIZE, 2,
 					HEADLINE_CLOSE_SIZE, HEADLINE_CLOSE_SIZE,
 					GDK_RGB_DITHER_NONE, 0, 0);
-#if 0
-		/* The presence of one opening paren in each branch of
-		 * GTK_CHECK_VERSION confuses vim's bracket matching for the
-		 * rest of the file.
-		 */
-		)
-#endif
 		gtk_paint_focus(widget->style, widget->window, GTK_STATE_PRELIGHT,
 				NULL, widget, NULL,
 				widget->allocation.width - HEADLINE_CLOSE_SIZE - 3, 1,
@@ -5193,9 +5102,7 @@
 	gtk_label_set_markup(GTK_LABEL(label), markup);
 	g_free(markup);
 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
-#if GTK_CHECK_VERSION(2,6,0)
 	g_object_set(G_OBJECT(label), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
-#endif
 #if GTK_CHECK_VERSION(2,12,0)
 	{ /* avoid unused variable warnings on pre-2.12 Gtk */
 		char *description =
@@ -5398,12 +5305,7 @@
 		return;
 
 	tooltips = gtk_tooltips_new ();
-#if GLIB_CHECK_VERSION(2,10,0)
 	g_object_ref_sink (tooltips);
-#else
-	g_object_ref(tooltips);
-	gtk_object_sink(GTK_OBJECT(tooltips));
-#endif
 
 	gtk_tooltips_force_window (tooltips);
 #if GTK_CHECK_VERSION(2, 12, 0)
@@ -5511,10 +5413,8 @@
 	gtk_tree_view_column_set_attributes(column, rend,
 					    "visible", GROUP_EXPANDER_VISIBLE_COLUMN,
 					    "expander-visible", GROUP_EXPANDER_COLUMN,
-#if GTK_CHECK_VERSION(2,6,0)
 					    "sensitive", GROUP_EXPANDER_COLUMN,
 					    "cell-background-gdk", BGCOLOR_COLUMN,
-#endif
 					    NULL);
 
 	/* contact */
@@ -5523,10 +5423,8 @@
 	gtk_tree_view_column_set_attributes(column, rend,
 					    "visible", CONTACT_EXPANDER_VISIBLE_COLUMN,
 					    "expander-visible", CONTACT_EXPANDER_COLUMN,
-#if GTK_CHECK_VERSION(2,6,0)
 					    "sensitive", CONTACT_EXPANDER_COLUMN,
 					    "cell-background-gdk", BGCOLOR_COLUMN,
-#endif
 					    NULL);
 
 	for (i = 0; i < 5; i++) {
@@ -5538,9 +5436,7 @@
 			gtk_tree_view_column_set_attributes(column, rend,
 							    "pixbuf", STATUS_ICON_COLUMN,
 							    "visible", STATUS_ICON_VISIBLE_COLUMN,
-#if GTK_CHECK_VERSION(2,6,0)
 							    "cell-background-gdk", BGCOLOR_COLUMN,
-#endif
 							    NULL);
 			g_object_set(rend, "xalign", 0.0, "xpad", 6, "ypad", 0, NULL);
 
@@ -5549,20 +5445,14 @@
 			gtkblist->text_rend = rend = gtk_cell_renderer_text_new();
 			gtk_tree_view_column_pack_start(column, rend, TRUE);
 			gtk_tree_view_column_set_attributes(column, rend,
-#if GTK_CHECK_VERSION(2,6,0)
 							    "cell-background-gdk", BGCOLOR_COLUMN,
-#endif
 							    "markup", NAME_COLUMN,
 							    NULL);
-#if GTK_CHECK_VERSION(2,6,0)
 			g_signal_connect(G_OBJECT(rend), "editing-started", G_CALLBACK(gtk_blist_renderer_editing_started_cb), NULL);
 			g_signal_connect(G_OBJECT(rend), "editing-canceled", G_CALLBACK(gtk_blist_renderer_editing_cancelled_cb), list);
-#endif
 			g_signal_connect(G_OBJECT(rend), "edited", G_CALLBACK(gtk_blist_renderer_edited_cb), list);
 			g_object_set(rend, "ypad", 0, "yalign", 0.5, NULL);
-#if GTK_CHECK_VERSION(2,6,0)
 			g_object_set(rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
-#endif
 
 			/* idle */
 			rend = gtk_cell_renderer_text_new();
@@ -5571,9 +5461,7 @@
 			gtk_tree_view_column_set_attributes(column, rend,
 							    "markup", IDLE_COLUMN,
 							    "visible", IDLE_VISIBLE_COLUMN,
-#if GTK_CHECK_VERSION(2,6,0)
 							    "cell-background-gdk", BGCOLOR_COLUMN,
-#endif
 							    NULL);
 		} else if (emblem == i) {
 			/* emblem */
@@ -5581,9 +5469,7 @@
 			g_object_set(rend, "xalign", 1.0, "yalign", 0.5, "ypad", 0, "xpad", 3, NULL);
 			gtk_tree_view_column_pack_start(column, rend, FALSE);
 			gtk_tree_view_column_set_attributes(column, rend, "pixbuf", EMBLEM_COLUMN,
-#if GTK_CHECK_VERSION(2,6,0)
 									  "cell-background-gdk", BGCOLOR_COLUMN,
-#endif
 									  "visible", EMBLEM_VISIBLE_COLUMN, NULL);
 
 		} else if (protocol_icon == i) {
@@ -5593,9 +5479,7 @@
 			gtk_tree_view_column_set_attributes(column, rend,
 							   "pixbuf", PROTOCOL_ICON_COLUMN,
 							   "visible", PROTOCOL_ICON_VISIBLE_COLUMN,
-#if GTK_CHECK_VERSION(2,6,0)
 							   "cell-background-gdk", BGCOLOR_COLUMN,
-#endif
 							  NULL);
 			g_object_set(rend, "xalign", 0.0, "xpad", 3, "ypad", 0, NULL);
 
@@ -5605,9 +5489,7 @@
 			g_object_set(rend, "xalign", 1.0, "ypad", 0, NULL);
 			gtk_tree_view_column_pack_start(column, rend, FALSE);
 			gtk_tree_view_column_set_attributes(column, rend, "pixbuf", BUDDY_ICON_COLUMN,
-#if GTK_CHECK_VERSION(2,6,0)
 							    "cell-background-gdk", BGCOLOR_COLUMN,
-#endif
 							    "visible", BUDDY_ICON_VISIBLE_COLUMN,
 							    NULL);
 		}
@@ -6794,9 +6676,6 @@
 			return;
 	}
 
-#if !GTK_CHECK_VERSION(2,6,0)
-	gtk_tree_view_columns_autosize(GTK_TREE_VIEW(gtkblist->treeview));
-#endif
 }
 
 static void pidgin_blist_destroy(PurpleBuddyList *list)
@@ -7595,8 +7474,6 @@
 			sibling ? &sibling_iter : NULL);
 }
 
-#if GTK_CHECK_VERSION(2,2,1)
-
 static void sort_method_alphabetical(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter)
 {
 	GtkTreeIter more_z;
@@ -7840,8 +7717,6 @@
 	}
 }
 
-#endif
-
 static void
 plugin_act(GtkObject *obj, PurplePluginAction *pam)
 {
--- a/pidgin/gtkblist.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkblist.h	Thu Feb 04 05:30:35 2010 +0000
@@ -132,9 +132,9 @@
 	gpointer priv;                   /**< Pointer to opaque private data */
 };
 
-#define PIDGIN_BLIST(list) ((PidginBuddyList *)(list)->ui_data)
+#define PIDGIN_BLIST(list) ((PidginBuddyList *)purple_blist_get_ui_data())
 #define PIDGIN_IS_PIDGIN_BLIST(list) \
-	((list)->ui_ops == pidgin_blist_get_ui_ops())
+	(purple_blist_get_ui_ops() == pidgin_blist_get_ui_ops())
 
 /**************************************************************************
  * @name GTK+ Buddy List API
--- a/pidgin/gtkcelllayout.c	Thu Feb 04 02:18:37 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,283 +0,0 @@
-/* gtkcelllayout.c
- * Copyright (C) 2003  Kristian Rietveld  <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02111-1301, USA.
- */
-
-/*
-#include <config.h>
-*/
-#include <gtk/gtkversion.h>
-#if !GTK_CHECK_VERSION(2,4,0)
-#include "gtkcelllayout.h"
-
-GType
-gtk_cell_layout_get_type (void)
-{
-  static GType cell_layout_type = 0;
-
-  if (! cell_layout_type)
-    {
-      static const GTypeInfo cell_layout_info =
-      {
-        sizeof (GtkCellLayoutIface),
-        NULL,
-        NULL,
-        NULL,
-        NULL,
-        NULL,
-        0,
-        0,
-        NULL
-      };
-
-      cell_layout_type =
-        g_type_register_static (G_TYPE_INTERFACE, "PidginCellLayout",
-                                &cell_layout_info, 0);
-
-      g_type_interface_add_prerequisite (cell_layout_type, G_TYPE_OBJECT);
-    }
-
-  return cell_layout_type;
-}
-
-/**
- * gtk_cell_layout_pack_start:
- * @cell_layout: A #GtkCellLayout.
- * @cell: A #GtkCellRenderer.
- * @expand: %TRUE if @cell is to be given extra space allocated to @cell_layout.
- *
- * Packs the @cell into the beginning of @cell_layout. If @expand is %FALSE,
- * then the @cell is allocated no more space than it needs. Any unused space
- * is divided evenly between cells for which @expand is %TRUE.
- *
- * Since: 2.4
- */
-void
-gtk_cell_layout_pack_start (GtkCellLayout   *cell_layout,
-                            GtkCellRenderer *cell,
-                            gboolean         expand)
-{
-  g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
-
-  (* GTK_CELL_LAYOUT_GET_IFACE (cell_layout)->pack_start) (cell_layout,
-                                                           cell,
-                                                           expand);
-}
-
-/**
- * gtk_cell_layout_pack_end:
- * @cell_layout: A #GtkCellLayout.
- * @cell: A #GtkCellRenderer.
- * @expand: %TRUE if @cell is to be given extra space allocated to @cell_layout.
- *
- * Adds the @cell to the end of @cell_layout. If @expand is %FALSE, then the
- * @cell is allocated no more space than it needs. Any unused space is
- * divided evenly between cells for which @expand is %TRUE.
- *
- * Since: 2.4
- */
-void
-gtk_cell_layout_pack_end (GtkCellLayout   *cell_layout,
-                          GtkCellRenderer *cell,
-                          gboolean         expand)
-{
-  g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
-
-  (* GTK_CELL_LAYOUT_GET_IFACE (cell_layout)->pack_end) (cell_layout,
-                                                         cell,
-                                                         expand);
-}
-
-/**
- * gtk_cell_layout_clear:
- * @cell_layout: A #GtkCellLayout.
- *
- * Unsets all the mappings on all renderers on @cell_layout and
- * removes all renderers from @cell_layout.
- *
- * Since: 2.4
- */
-void
-gtk_cell_layout_clear (GtkCellLayout *cell_layout)
-{
-  g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
-
-  (* GTK_CELL_LAYOUT_GET_IFACE (cell_layout)->clear) (cell_layout);
-}
-
-static void
-gtk_cell_layout_set_attributesv (GtkCellLayout   *cell_layout,
-                                 GtkCellRenderer *cell,
-                                 va_list          args)
-{
-  gchar *attribute;
-  gint column;
-  GtkCellLayoutIface *iface;
-
-  attribute = va_arg (args, gchar *);
-
-  iface = GTK_CELL_LAYOUT_GET_IFACE (cell_layout);
-
-  (* iface->clear_attributes) (cell_layout, cell);
-
-  while (attribute != NULL)
-    {
-      column = va_arg (args, gint);
-      (* iface->add_attribute) (cell_layout, cell, attribute, column);
-      attribute = va_arg (args, gchar *);
-    }
-}
-
-/**
- * gtk_cell_layout_set_attributes:
- * @cell_layout: A #GtkCellLayout.
- * @cell: A #GtkCellRenderer.
- * @Varargs: A %NULL-terminated list of attributes.
- *
- * Sets the attributes in list as the attributes of @cell_layout. The
- * attributes should be in attribute/column order, as in
- * gtk_cell_layout_add_attribute(). All existing attributes are removed, and
- * replaced with the new attributes.
- *
- * Since: 2.4
- */
-void
-gtk_cell_layout_set_attributes (GtkCellLayout   *cell_layout,
-                                GtkCellRenderer *cell,
-                                ...)
-{
-  va_list args;
-
-  g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
-
-  va_start (args, cell);
-  gtk_cell_layout_set_attributesv (cell_layout, cell, args);
-  va_end (args);
-}
-
-/**
- * gtk_cell_layout_add_attribute:
- * @cell_layout: A #GtkCellLayout.
- * @cell: A #GtkCellRenderer.
- * @attribute: An attribute on the renderer.
- * @column: The column position on the model to get the attribute from.
- *
- * Adds an attribute mapping to the list in @cell_layout. The @column is the
- * column of the model to get a value from, and the @attribute is the
- * parameter on @cell to be set from the value. So for example if column 2
- * of the model contains strings, you could have the "text" attribute of a
- * #GtkCellRendererText get its values from column 2.
- *
- * Since: 2.4
- */
-void
-gtk_cell_layout_add_attribute (GtkCellLayout   *cell_layout,
-                               GtkCellRenderer *cell,
-                               const gchar     *attribute,
-                               gint             column)
-{
-  g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
-  g_return_if_fail (attribute != NULL);
-  g_return_if_fail (column >= 0);
-
-  (* GTK_CELL_LAYOUT_GET_IFACE (cell_layout)->add_attribute) (cell_layout,
-                                                              cell,
-                                                              attribute,
-                                                              column);
-}
-
-/**
- * gtk_cell_layout_set_cell_data_func:
- * @cell_layout: A #GtkCellLayout.
- * @cell: A #GtkCellRenderer.
- * @func: The #GtkCellLayoutDataFunc to use.
- * @func_data: The user data for @func.
- * @destroy: The destroy notification for @func_data.
- *
- * Sets the #GtkCellLayoutDataFunc to use for @cell_layout. This function
- * is used instead of the standard attributes mapping for setting the
- * column value, and should set the value of @cell_layout's cell renderer(s)
- * as appropriate. @func may be %NULL to remove and older one.
- *
- * Since: 2.4
- */
-void
-gtk_cell_layout_set_cell_data_func (GtkCellLayout         *cell_layout,
-                                    GtkCellRenderer       *cell,
-                                    GtkCellLayoutDataFunc  func,
-                                    gpointer               func_data,
-                                    GDestroyNotify         destroy)
-{
-  g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
-
-  (* GTK_CELL_LAYOUT_GET_IFACE (cell_layout)->set_cell_data_func) (cell_layout,
-                                                                   cell,
-                                                                   func,
-                                                                   func_data,
-                                                                   destroy);
-}
-
-/**
- * gtk_cell_layout_clear_attributes:
- * @cell_layout: A #GtkCellLayout.
- * @cell: A #GtkCellRenderer to clear the attribute mapping on.
- *
- * Clears all existing attributes previously set with
- * gtk_cell_layout_set_attributes().
- *
- * Since: 2.4
- */
-void
-gtk_cell_layout_clear_attributes (GtkCellLayout   *cell_layout,
-                                  GtkCellRenderer *cell)
-{
-  g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
-
-  (* GTK_CELL_LAYOUT_GET_IFACE (cell_layout)->clear_attributes) (cell_layout,
-                                                                 cell);
-}
-
-/**
- * gtk_cell_layout_reorder:
- * @cell_layout: A #GtkCellLayout.
- * @cell: A #GtkCellRenderer to reorder.
- * @position: New position to insert @cell at.
- *
- * Re-inserts @cell at @position. Note that @cell has already to be packed
- * into @cell_layout for this to function properly.
- *
- * Since: 2.4
- */
-void
-gtk_cell_layout_reorder (GtkCellLayout   *cell_layout,
-                         GtkCellRenderer *cell,
-                         gint             position)
-{
-  g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
-
-  (* GTK_CELL_LAYOUT_GET_IFACE (cell_layout)->reorder) (cell_layout,
-                                                        cell,
-                                                        position);
-}
-#endif /* Gtk 2.4 */
--- a/pidgin/gtkcelllayout.h	Thu Feb 04 02:18:37 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-/* gtkcelllayout.h
- * Copyright (C) 2003  Kristian Rietveld  <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02111-1301, USA.
- */
-
-#ifndef __GTK_CELL_LAYOUT_H__
-#define __GTK_CELL_LAYOUT_H__
-
-#include <glib-object.h>
-
-#include <gtk/gtkcellrenderer.h>
-#include <gtk/gtktreeviewcolumn.h>
-
-G_BEGIN_DECLS
-
-#define GTK_TYPE_CELL_LAYOUT            (gtk_cell_layout_get_type ())
-#define GTK_CELL_LAYOUT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CELL_LAYOUT, GtkCellLayout))
-#define GTK_IS_CELL_LAYOUT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CELL_LAYOUT))
-#define GTK_CELL_LAYOUT_GET_IFACE(obj)  (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GTK_TYPE_CELL_LAYOUT, GtkCellLayoutIface))
-
-typedef struct _GtkCellLayout           GtkCellLayout; /* dummy typedef */
-typedef struct _GtkCellLayoutIface      GtkCellLayoutIface;
-
-/* keep in sync with GtkTreeCellDataFunc */
-typedef void (* GtkCellLayoutDataFunc) (GtkCellLayout   *cell_layout,
-                                        GtkCellRenderer *cell,
-                                        GtkTreeModel    *tree_model,
-                                        GtkTreeIter     *iter,
-                                        gpointer         data);
-
-struct _GtkCellLayoutIface
-{
-  GTypeInterface g_iface;
-
-  /* Virtual Table */
-  void (* pack_start)         (GtkCellLayout         *cell_layout,
-                               GtkCellRenderer       *cell,
-                               gboolean               expand);
-  void (* pack_end)           (GtkCellLayout         *cell_layout,
-                               GtkCellRenderer       *cell,
-                               gboolean               expand);
-  void (* clear)              (GtkCellLayout         *cell_layout);
-  void (* add_attribute)      (GtkCellLayout         *cell_layout,
-                               GtkCellRenderer       *cell,
-                               const gchar           *attribute,
-                               gint                   column);
-  void (* set_cell_data_func) (GtkCellLayout         *cell_layout,
-                               GtkCellRenderer       *cell,
-                               GtkCellLayoutDataFunc  func,
-                               gpointer               func_data,
-                               GDestroyNotify         destroy);
-  void (* clear_attributes)   (GtkCellLayout         *cell_layout,
-                               GtkCellRenderer       *cell);
-  void (* reorder)            (GtkCellLayout         *cell_layout,
-                               GtkCellRenderer       *cell,
-                               gint                   position);
-};
-
-GType gtk_cell_layout_get_type           (void);
-void  gtk_cell_layout_pack_start         (GtkCellLayout         *cell_layout,
-                                          GtkCellRenderer       *cell,
-                                          gboolean               expand);
-void  gtk_cell_layout_pack_end           (GtkCellLayout         *cell_layout,
-                                          GtkCellRenderer       *cell,
-                                          gboolean               expand);
-void  gtk_cell_layout_clear              (GtkCellLayout         *cell_layout);
-void  gtk_cell_layout_set_attributes     (GtkCellLayout         *cell_layout,
-                                          GtkCellRenderer       *cell,
-                                          ...);
-void  gtk_cell_layout_add_attribute      (GtkCellLayout         *cell_layout,
-                                          GtkCellRenderer       *cell,
-                                          const gchar           *attribute,
-                                          gint                   column);
-void  gtk_cell_layout_set_cell_data_func (GtkCellLayout         *cell_layout,
-                                          GtkCellRenderer       *cell,
-                                          GtkCellLayoutDataFunc  func,
-                                          gpointer               func_data,
-                                          GDestroyNotify         destroy);
-void  gtk_cell_layout_clear_attributes   (GtkCellLayout         *cell_layout,
-                                          GtkCellRenderer       *cell);
-void  gtk_cell_layout_reorder            (GtkCellLayout         *cell_layout,
-                                          GtkCellRenderer       *cell,
-                                          gint                   position);
-
-
-G_END_DECLS
-
-#endif /* __GTK_CELL_LAYOUT_H__ */
--- a/pidgin/gtkcellrendererexpander.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkcellrendererexpander.c	Thu Feb 04 05:30:35 2010 +0000
@@ -246,13 +246,8 @@
 	width = cell_area->width;
 	height = cell_area->height;
 
-#if GTK_CHECK_VERSION(2,6,0)
 	if (!cell->sensitive)
 		state = GTK_STATE_INSENSITIVE;
-#else
-	if (GTK_WIDGET_STATE(widget) == GTK_STATE_INSENSITIVE)
-		state = GTK_STATE_INSENSITIVE;
-#endif
 	else if (flags & GTK_CELL_RENDERER_PRELIT)
 		state = GTK_STATE_PRELIGHT;
 	else if (GTK_WIDGET_HAS_FOCUS (widget) && flags & GTK_CELL_RENDERER_SELECTED)
--- a/pidgin/gtkcellrendererprogress.c	Thu Feb 04 02:18:37 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,296 +0,0 @@
-/*
- * @file gtkcellrendererprogress.c GTK+ Cell Renderer Progress
- * @ingroup pidgin
- */
-
-/* pidgin
- *
- * Pidgin is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This 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 Street, Fifth Floor, Boston, MA  02111-1301  USA
- *
- */
-
-/* This is taken largely from GtkCellRenderer[Text|Pixbuf|Toggle] by
- * Jonathon Blandford <jrb@redhat.com> for RedHat, Inc.
- */
-
-#include "gtkcellrendererprogress.h"
-
-static void pidgin_cell_renderer_progress_get_property  (GObject                    *object,
-						      guint                       param_id,
-						      GValue                     *value,
-						      GParamSpec                 *pspec);
-static void pidgin_cell_renderer_progress_set_property  (GObject                    *object,
-						      guint                       param_id,
-						      const GValue               *value,
-						      GParamSpec                 *pspec);
-static void pidgin_cell_renderer_progress_init       (PidginCellRendererProgress      *cellprogress);
-static void pidgin_cell_renderer_progress_class_init (PidginCellRendererProgressClass *class);
-static void pidgin_cell_renderer_progress_get_size   (GtkCellRenderer            *cell,
-						   GtkWidget                  *widget,
-						   GdkRectangle               *cell_area,
-						   gint                       *x_offset,
-						   gint                       *y_offset,
-						   gint                       *width,
-						   gint                       *height);
-static void pidgin_cell_renderer_progress_render     (GtkCellRenderer            *cell,
-						   GdkWindow                  *window,
-						   GtkWidget                  *widget,
-						   GdkRectangle               *background_area,
-						   GdkRectangle               *cell_area,
-						   GdkRectangle               *expose_area,
-						   guint                       flags);
-#if 0
-static gboolean pidgin_cell_renderer_progress_activate  (GtkCellRenderer            *cell,
-						      GdkEvent                   *event,
-						      GtkWidget                  *widget,
-						      const gchar                *path,
-						      GdkRectangle               *background_area,
-						      GdkRectangle               *cell_area,
-						      guint                       flags);
-#endif
-static void  pidgin_cell_renderer_progress_finalize (GObject *gobject);
-
-enum {
-	LAST_SIGNAL
-};
-
-enum {
-	PROP_0,
-	PROP_PERCENTAGE,
-	PROP_TEXT,
-	PROP_SHOW_TEXT
-};
-
-static gpointer parent_class;
-/* static guint progress_cell_renderer_signals [LAST_SIGNAL]; */
-
-GType  pidgin_cell_renderer_progress_get_type (void)
-{
-	static GType cell_progress_type = 0;
-
-	if (!cell_progress_type)
-		{
-			static const GTypeInfo cell_progress_info =
-				{
-					sizeof (PidginCellRendererProgressClass),
-					NULL,           /* base_init */
-					NULL,           /* base_finalize */
-					(GClassInitFunc) pidgin_cell_renderer_progress_class_init,
-					NULL,           /* class_finalize */
-					NULL,           /* class_data */
-					sizeof (PidginCellRendererProgress),
-					0,              /* n_preallocs */
-					(GInstanceInitFunc) pidgin_cell_renderer_progress_init,
-					NULL		/* value_table */
-				};
-
-			cell_progress_type =
-				g_type_register_static (GTK_TYPE_CELL_RENDERER,
-										"PidginCellRendererProgress",
-										&cell_progress_info, 0);
-		}
-
-	return cell_progress_type;
-}
-
-static void pidgin_cell_renderer_progress_init (PidginCellRendererProgress *cellprogress)
-{
-	GTK_CELL_RENDERER(cellprogress)->mode = GTK_CELL_RENDERER_MODE_INERT;
-	GTK_CELL_RENDERER(cellprogress)->xpad = 2;
-	GTK_CELL_RENDERER(cellprogress)->ypad = 2;
-}
-
-static void pidgin_cell_renderer_progress_class_init (PidginCellRendererProgressClass *class)
-{
-	GObjectClass *object_class = G_OBJECT_CLASS(class);
-	GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS(class);
-
-	parent_class = g_type_class_peek_parent (class);
-	object_class->finalize = pidgin_cell_renderer_progress_finalize;
-
-	object_class->get_property = pidgin_cell_renderer_progress_get_property;
-	object_class->set_property = pidgin_cell_renderer_progress_set_property;
-
-	cell_class->get_size = pidgin_cell_renderer_progress_get_size;
-	cell_class->render   = pidgin_cell_renderer_progress_render;
-
-	g_object_class_install_property (object_class,
-					 PROP_PERCENTAGE,
-					 g_param_spec_double ("percentage",
-							      "Percentage",
-							      "The fractional progress to display",
-							      0, 1, 0,
-							      G_PARAM_READWRITE));
-	g_object_class_install_property (object_class,
-					 PROP_TEXT,
-					 g_param_spec_string ("text",
-							      "Text",
-							      "Text to overlay over progress bar",
-							      NULL,
-							      G_PARAM_READWRITE));
-	g_object_class_install_property(object_class,
-					PROP_SHOW_TEXT,
-					g_param_spec_string("text_set",
-							    "Text set",
-							    "Whether to overlay text on the progress bar",
-							    FALSE,
-							    G_PARAM_READABLE | G_PARAM_WRITABLE));
-}
-
-static void pidgin_cell_renderer_progress_finalize (GObject *object)
-{
-/*
-	PidginCellRendererProgress *cellprogress = PIDGIN_CELL_RENDERER_PROGRESS(object);
-*/
-
-	(* G_OBJECT_CLASS (parent_class)->finalize) (object);
-}
-
-static void pidgin_cell_renderer_progress_get_property (GObject    *object,
-						     guint      param_id,
-						     GValue     *value,
-						     GParamSpec *psec)
-{
-	PidginCellRendererProgress *cellprogress = PIDGIN_CELL_RENDERER_PROGRESS(object);
-
-	switch (param_id)
-		{
-		case PROP_PERCENTAGE:
-			g_value_set_double(value, cellprogress->progress);
-			break;
-		case PROP_TEXT:
-			g_value_set_string(value, cellprogress->text);
-			break;
-		case PROP_SHOW_TEXT:
-			g_value_set_boolean(value, cellprogress->text_set);
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, psec);
-			break;
-		}
-}
-
-static void pidgin_cell_renderer_progress_set_property (GObject      *object,
-						     guint        param_id,
-						     const GValue *value,
-						     GParamSpec   *pspec)
-{
-	PidginCellRendererProgress *cellprogress = PIDGIN_CELL_RENDERER_PROGRESS (object);
-
-	switch (param_id)
-		{
-		case PROP_PERCENTAGE:
-			cellprogress->progress = g_value_get_double(value);
-			break;
-		case PROP_TEXT:
-			if (cellprogress->text)
-				g_free(cellprogress->text);
-			cellprogress->text = g_strdup(g_value_get_string(value));
-			g_object_notify(object, "text");
-			break;
-		case PROP_SHOW_TEXT:
-			cellprogress->text_set = g_value_get_boolean(value);
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
-			break;
-		}
-}
-
-GtkCellRenderer *pidgin_cell_renderer_progress_new(void)
-{
-	return g_object_new(PIDGIN_TYPE_GTK_CELL_RENDERER_PROGRESS, NULL);
-}
-
-static void pidgin_cell_renderer_progress_get_size (GtkCellRenderer *cell,
-						 GtkWidget       *widget,
-						 GdkRectangle    *cell_area,
-						 gint            *x_offset,
-						 gint            *y_offset,
-						 gint            *width,
-						 gint            *height)
-{
-	gint calc_width;
-	gint calc_height;
-
-	calc_width = (gint) cell->xpad * 2 + 50;
-	calc_height = (gint) cell->ypad * 2 + 12;
-
-	if (width)
-		*width = calc_width;
-
-	if (height)
-		*height = calc_height;
-
-	if (cell_area)
-		{
-			if (x_offset)
-				{
-					*x_offset = cell->xalign * (cell_area->width - calc_width);
-					*x_offset = MAX (*x_offset, 0);
-				}
-			if (y_offset)
-				{
-					*y_offset = cell->yalign * (cell_area->height - calc_height);
-					*y_offset = MAX (*y_offset, 0);
-				}
-		}
-}
-
-
-static void pidgin_cell_renderer_progress_render (GtkCellRenderer *cell,
-					       GdkWindow       *window,
-					       GtkWidget       *widget,
-					       GdkRectangle    *background_area,
-					       GdkRectangle    *cell_area,
-					       GdkRectangle    *expose_area,
-					       guint            flags)
-{
-	PidginCellRendererProgress *cellprogress = (PidginCellRendererProgress *) cell;
-
-	gint width, height;
-	GtkStateType state;
-
-	width = cell_area->width;
-	height = cell_area->height;
-
-	if (GTK_WIDGET_HAS_FOCUS (widget))
-		state = GTK_STATE_ACTIVE;
-	else
-		state = GTK_STATE_NORMAL;
-
-	width -= cell->xpad*2;
-	height -= cell->ypad*2;
-
-	gtk_paint_box (widget->style,
-		       window,
-		       GTK_STATE_NORMAL, GTK_SHADOW_IN,
-		       NULL, widget, "trough",
-		       cell_area->x + cell->xpad,
-		       cell_area->y + cell->ypad,
-		       width - 1, height - 1);
-	gtk_paint_box (widget->style,
-		       window,
-		       state, GTK_SHADOW_OUT,
-		       NULL, widget, "bar",
-		       cell_area->x + cell->xpad + 1,
-		       cell_area->y + cell->ypad + 1,
-		       (width - 3) * cellprogress->progress,
-		       height - 3);
-}
--- a/pidgin/gtkcellrendererprogress.h	Thu Feb 04 02:18:37 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/* gtkxcellrendererprogress.h
- * Pidgin is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This 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 Street, Fifth Floor, Boston, MA  02111-1301  USA
- *
- */
-#ifndef _PIDGINCELLRENDERERPROGRESS_H_
-#define _PIDGINCELLRENDERERPROGRESS_H_
-
-#include <gtk/gtk.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
-#define PIDGIN_TYPE_GTK_CELL_RENDERER_PROGRESS         (pidgin_cell_renderer_progress_get_type())
-#define PIDGIN_CELL_RENDERER_PROGRESS(obj)         (G_TYPE_CHECK_INSTANCE_CAST((obj), PIDGIN_TYPE_GTK_CELL_RENDERER_PROGRESS, PidginCellRendererProgress))
-#define PIDGIN_CELL_RENDERER_PROGRESS_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), PIDGIN_TYPE_GTK_CELL_RENDERER_PROGRESS, PidginCellRendererProgressClass))
-#define PIDGIN_IS_GTK_CELL_PROGRESS_PROGRESS(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIDGIN_TYPE_GTK_CELL_RENDERER_PROGRESS))
-#define PIDGIN_IS_GTK_CELL_PROGRESS_PROGRESS_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), PIDGIN_TYPE_GTK_CELL_RENDERER_PROGRESS))
-#define PIDGIN_CELL_RENDERER_PROGRESS_GET_CLASS(obj)         (G_TYPE_INSTANCE_GET_CLASS ((obj), PIDGIN_TYPE_GTK_CELL_RENDERER_PROGRESS, PidginCellRendererProgressClass))
-
-typedef struct _PidginCellRendererProgress PidginCellRendererProgress;
-typedef struct _PidginCellRendererProgressClass PidginCellRendererProgressClass;
-
-struct _PidginCellRendererProgress {
-	GtkCellRenderer parent;
-
-	gdouble progress;
-	gchar *text;
-	gboolean text_set;
-};
-
-struct _PidginCellRendererProgressClass {
-	GtkCellRendererClass parent_class;
-};
-
-GType            pidgin_cell_renderer_progress_get_type     (void);
-GtkCellRenderer  *pidgin_cell_renderer_progress_new          (void);
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* _PIDGINCELLRENDERERPROGRESS_H_ */
--- a/pidgin/gtkcellview.c	Thu Feb 04 02:18:37 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1002 +0,0 @@
-/* gtkellview.c
- * Copyright (C) 2002, 2003  Kristian Rietveld <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02111-1301, USA.
- */
-
-/*
-#include <config.h>
-*/
-#include "gtkcellview.h"
-#include <gtk/gtkversion.h>
-#if !GTK_CHECK_VERSION(2,6,0)
-#if GTK_CHECK_VERSION(2,4,0)
-#include <gtk/gtkcelllayout.h>
-#else
-#include "gtkcelllayout.h"
-#endif
-#include <gtk/gtksignal.h>
-#include <gtk/gtkcellrenderertext.h>
-#include <gtk/gtkcellrendererpixbuf.h>
-#include <gobject/gmarshal.h>
-
-#define P_(x) (x)
-
-typedef struct _GtkCellViewCellInfo GtkCellViewCellInfo;
-struct _GtkCellViewCellInfo
-{
-  GtkCellRenderer *cell;
-
-  gint requested_width;
-  gint real_width;
-  guint expand : 1;
-  guint pack : 1;
-
-  GSList *attributes;
-
-  GtkCellLayoutDataFunc func;
-  gpointer func_data;
-  GDestroyNotify destroy;
-};
-
-struct _GtkCellViewPrivate
-{
-  GtkTreeModel *model;
-  GtkTreeRowReference *displayed_row;
-  GList *cell_list;
-  gint spacing;
-
-  GdkColor background;
-  gboolean background_set;
-};
-
-
-static void        gtk_cell_view_class_init               (GtkCellViewClass *klass);
-static void        gtk_cell_view_cell_layout_init         (GtkCellLayoutIface *iface);
-static void        gtk_cell_view_get_property             (GObject           *object,
-                                                           guint             param_id,
-                                                           GValue           *value,
-                                                           GParamSpec       *pspec);
-static void        gtk_cell_view_set_property             (GObject          *object,
-                                                           guint             param_id,
-                                                           const GValue     *value,
-                                                           GParamSpec       *pspec);
-static void        gtk_cell_view_init                     (GtkCellView      *cellview);
-static void        gtk_cell_view_finalize                 (GObject          *object);
-static void        gtk_cell_view_style_set                (GtkWidget        *widget,
-                                                           GtkStyle         *previous_style);
-static void        gtk_cell_view_size_request             (GtkWidget        *widget,
-                                                           GtkRequisition   *requisition);
-static void        gtk_cell_view_size_allocate            (GtkWidget        *widget,
-                                                           GtkAllocation    *allocation);
-static gboolean    gtk_cell_view_expose                   (GtkWidget        *widget,
-                                                           GdkEventExpose   *event);
-static void        gtk_cell_view_set_valuesv              (GtkCellView      *cellview,
-                                                           GtkCellRenderer  *renderer,
-                                                           va_list           args);
-static GtkCellViewCellInfo *gtk_cell_view_get_cell_info   (GtkCellView      *cellview,
-                                                           GtkCellRenderer  *renderer);
-static void        gtk_cell_view_set_cell_data            (GtkCellView      *cellview);
-
-
-static void        gtk_cell_view_cell_layout_pack_start        (GtkCellLayout         *layout,
-                                                                GtkCellRenderer       *renderer,
-                                                                gboolean               expand);
-static void        gtk_cell_view_cell_layout_pack_end          (GtkCellLayout         *layout,
-                                                                GtkCellRenderer       *renderer,
-                                                                gboolean               expand);
-static void        gtk_cell_view_cell_layout_add_attribute     (GtkCellLayout         *layout,
-                                                                GtkCellRenderer       *renderer,
-                                                                const gchar           *attribute,
-                                                                gint                   column);
-static void       gtk_cell_view_cell_layout_clear              (GtkCellLayout         *layout);
-static void       gtk_cell_view_cell_layout_clear_attributes   (GtkCellLayout         *layout,
-                                                                GtkCellRenderer       *renderer);
-static void       gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout         *layout,
-                                                                GtkCellRenderer       *cell,
-                                                                GtkCellLayoutDataFunc  func,
-                                                                gpointer               func_data,
-                                                                GDestroyNotify         destroy);
-static void       gtk_cell_view_cell_layout_reorder            (GtkCellLayout         *layout,
-                                                                GtkCellRenderer       *cell,
-                                                                gint                   position);
-
-
-enum
-{
-  PROP_0,
-  PROP_BACKGROUND,
-  PROP_BACKGROUND_GDK,
-  PROP_BACKGROUND_SET
-};
-
-static GtkObjectClass *parent_class = NULL;
-
-
-GType
-gtk_cell_view_get_type (void)
-{
-  static GType cell_view_type = 0;
-
-  if (!cell_view_type)
-    {
-      static const GTypeInfo cell_view_info =
-        {
-          sizeof (GtkCellViewClass),
-          NULL, /* base_init */
-          NULL, /* base_finalize */
-          (GClassInitFunc) gtk_cell_view_class_init,
-          NULL, /* class_finalize */
-          NULL, /* class_data */
-          sizeof (GtkCellView),
-          0,
-          (GInstanceInitFunc) gtk_cell_view_init
-        };
-
-      static const GInterfaceInfo cell_layout_info =
-       {
-         (GInterfaceInitFunc) gtk_cell_view_cell_layout_init,
-         NULL,
-         NULL
-       };
-
-      cell_view_type = g_type_register_static (GTK_TYPE_WIDGET, "PidginCellView",
-                                               &cell_view_info, 0);
-
-      g_type_add_interface_static (cell_view_type, GTK_TYPE_CELL_LAYOUT,
-                                   &cell_layout_info);
-    }
-
-  return cell_view_type;
-}
-
-static void
-gtk_cell_view_class_init (GtkCellViewClass *klass)
-{
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-
-  parent_class = g_type_class_peek_parent (klass);
-
-  gobject_class->get_property = gtk_cell_view_get_property;
-  gobject_class->set_property = gtk_cell_view_set_property;
-  gobject_class->finalize = gtk_cell_view_finalize;
-
-  widget_class->expose_event = gtk_cell_view_expose;
-  widget_class->size_allocate = gtk_cell_view_size_allocate;
-  widget_class->size_request = gtk_cell_view_size_request;
-  widget_class->style_set = gtk_cell_view_style_set;
-
-  /* properties */
-  g_object_class_install_property (gobject_class,
-                                   PROP_BACKGROUND,
-                                   g_param_spec_string ("background",
-                                                        P_("Background color name"),
-                                                        P_("Background color as a string"),
-                                                        NULL,
-                                                        G_PARAM_WRITABLE));
-  g_object_class_install_property (gobject_class,
-                                   PROP_BACKGROUND_GDK,
-                                   g_param_spec_boxed ("background_gdk",
-                                                      P_("Background color"),
-                                                      P_("Background color as a GdkColor"),
-                                                      GDK_TYPE_COLOR,
-                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
-
-#define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (gobject_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, G_PARAM_READABLE | G_PARAM_WRITABLE))
-
-  ADD_SET_PROP ("background_set", PROP_BACKGROUND_SET,
-                P_("Background set"),
-                P_("Whether this tag affects the background color"));
-}
-
-static void
-gtk_cell_view_cell_layout_init (GtkCellLayoutIface *iface)
-{
-  iface->pack_start = gtk_cell_view_cell_layout_pack_start;
-  iface->pack_end = gtk_cell_view_cell_layout_pack_end;
-  iface->clear = gtk_cell_view_cell_layout_clear;
-  iface->add_attribute = gtk_cell_view_cell_layout_add_attribute;
-  iface->set_cell_data_func = gtk_cell_view_cell_layout_set_cell_data_func;
-  iface->clear_attributes = gtk_cell_view_cell_layout_clear_attributes;
-  iface->reorder = gtk_cell_view_cell_layout_reorder;
-}
-
-static void
-gtk_cell_view_get_property (GObject    *object,
-                            guint       param_id,
-                            GValue     *value,
-                            GParamSpec *pspec)
-{
-  GtkCellView *view = GTK_CELL_VIEW (object);
-
-  switch (param_id)
-    {
-      case PROP_BACKGROUND_GDK:
-        {
-          GdkColor color;
-
-          color = view->priv->background;
-
-          g_value_set_boxed (value, &color);
-        }
-        break;
-      case PROP_BACKGROUND_SET:
-        g_value_set_boolean (value, view->priv->background_set);
-        break;
-      default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
-        break;
-    }
-}
-
-static void
-gtk_cell_view_set_property (GObject      *object,
-                            guint         param_id,
-                            const GValue *value,
-                            GParamSpec   *pspec)
-{
-  GtkCellView *view = GTK_CELL_VIEW (object);
-
-  switch (param_id)
-    {
-      case PROP_BACKGROUND:
-        {
-          GdkColor color;
-
-          if (!g_value_get_string (value))
-            gtk_cell_view_set_background_color (view, NULL);
-          else if (gdk_color_parse (g_value_get_string (value), &color))
-            gtk_cell_view_set_background_color (view, &color);
-          else
-            g_warning ("Don't know color `%s'", g_value_get_string (value));
-
-          g_object_notify (object, "background_gdk");
-        }
-        break;
-      case PROP_BACKGROUND_GDK:
-        gtk_cell_view_set_background_color (view, g_value_get_boxed (value));
-        break;
-      case PROP_BACKGROUND_SET:
-        view->priv->background_set = g_value_get_boolean (value);
-        break;
-      default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
-        break;
-    }
-}
-
-static void
-gtk_cell_view_init (GtkCellView *cellview)
-{
-  GTK_WIDGET_SET_FLAGS (cellview, GTK_NO_WINDOW);
-
-  cellview->priv = g_new0(GtkCellViewPrivate,1);
-}
-
-static void
-gtk_cell_view_style_set (GtkWidget *widget,
-                         GtkStyle  *previous_style)
-{
-  if (previous_style && GTK_WIDGET_REALIZED (widget))
-    gdk_window_set_background (widget->window,
-                               &widget->style->base[GTK_WIDGET_STATE (widget)]);
-}
-
-static void
-gtk_cell_view_finalize (GObject *object)
-{
-  GtkCellView *cellview = GTK_CELL_VIEW (object);
-
-  gtk_cell_view_cell_layout_clear (GTK_CELL_LAYOUT (cellview));
-
-  if (cellview->priv->model)
-     g_object_unref (cellview->priv->model);
-
-  if (cellview->priv->displayed_row)
-     gtk_tree_row_reference_free (cellview->priv->displayed_row);
-
-  if (G_OBJECT_CLASS (parent_class)->finalize)
-    (* G_OBJECT_CLASS (parent_class)->finalize) (object);
-
-  g_free (cellview->priv);
-}
-
-static void
-gtk_cell_view_size_request (GtkWidget      *widget,
-                            GtkRequisition *requisition)
-{
-  GList *i;
-  gboolean first_cell = TRUE;
-  GtkCellView *cellview;
-
-  cellview = GTK_CELL_VIEW (widget);
-
-  requisition->width = 0;
-  requisition->height = 0;
-
-  if (cellview->priv->displayed_row)
-    gtk_cell_view_set_cell_data (cellview);
-
-  for (i = cellview->priv->cell_list; i; i = i->next)
-    {
-      gint width, height;
-      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
-
-      if (!info->cell->visible)
-        continue;
-
-      if (!first_cell)
-        requisition->width += cellview->priv->spacing;
-
-      gtk_cell_renderer_get_size (info->cell, widget, NULL, NULL, NULL,
-                                  &width, &height);
-
-      info->requested_width = width;
-      requisition->width += width;
-      requisition->height = MAX (requisition->height, height);
-
-      first_cell = FALSE;
-    }
-}
-
-static void
-gtk_cell_view_size_allocate (GtkWidget     *widget,
-                             GtkAllocation *allocation)
-{
-  GList *i;
-  gint expand_cell_count = 0;
-  gint full_requested_width = 0;
-  gint extra_space;
-  GtkCellView *cellview;
-
-  widget->allocation = *allocation;
-
-  cellview = GTK_CELL_VIEW (widget);
-
-  /* checking how much extra space we have */
-  for (i = cellview->priv->cell_list; i; i = i->next)
-    {
-      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
-
-      if (!info->cell->visible)
-        continue;
-
-      if (info->expand)
-        expand_cell_count++;
-
-      full_requested_width += info->requested_width;
-    }
-
-  extra_space = widget->allocation.width - full_requested_width;
-  if (extra_space < 0)
-    extra_space = 0;
-  else if (extra_space > 0 && expand_cell_count > 0)
-    extra_space /= expand_cell_count;
-
-  /* iterate list for PACK_START cells */
-  for (i = cellview->priv->cell_list; i; i = i->next)
-    {
-      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
-
-      if (info->pack == GTK_PACK_END)
-        continue;
-
-      if (!info->cell->visible)
-        continue;
-
-      info->real_width = info->requested_width + (info->expand ? extra_space : 0);
-    }
-
-  /* iterate list for PACK_END cells */
-  for (i = cellview->priv->cell_list; i; i = i->next)
-    {
-      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
-
-      if (info->pack == GTK_PACK_START)
-        continue;
-
-      if (!info->cell->visible)
-        continue;
-
-      info->real_width = info->requested_width + (info->expand ? extra_space : 0);
-    }
-}
-
-static gboolean
-gtk_cell_view_expose (GtkWidget      *widget,
-                      GdkEventExpose *event)
-{
-  GList *i;
-  GtkCellView *cellview;
-  GdkRectangle area;
-  GtkCellRendererState state;
-  gboolean rtl = (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL);
-
-  cellview = GTK_CELL_VIEW (widget);
-
-  if (! GTK_WIDGET_DRAWABLE (widget))
-    return FALSE;
-
-  /* "blank" background */
-  if (cellview->priv->background_set)
-    {
-      GdkGC *gc;
-
-      gc = gdk_gc_new (GTK_WIDGET (cellview)->window);
-      gdk_gc_set_rgb_fg_color (gc, &cellview->priv->background);
-
-      gdk_draw_rectangle (GTK_WIDGET (cellview)->window,
-                          gc,
-                          TRUE,
-
-                          /*0, 0,*/
-                          widget->allocation.x,
-                          widget->allocation.y,
-
-                          widget->allocation.width,
-                          widget->allocation.height);
-
-      g_object_unref (G_OBJECT (gc));
-    }
-
-  /* set cell data (if available) */
-  if (cellview->priv->displayed_row)
-    gtk_cell_view_set_cell_data (cellview);
-  else if (cellview->priv->model)
-    return FALSE;
-
-  /* render cells */
-  area = widget->allocation;
-
-  /* we draw on our very own window, initialize x and y to zero */
-  area.x = widget->allocation.x + (rtl ? widget->allocation.width : 0);
-  area.y = widget->allocation.y;
-
-  if (GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT)
-    state = GTK_CELL_RENDERER_PRELIT;
-  else
-    state = 0;
-
-  /* PACK_START */
-  for (i = cellview->priv->cell_list; i; i = i->next)
-    {
-      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
-
-      if (info->pack == GTK_PACK_END)
-        continue;
-
-      if (!info->cell->visible)
-        continue;
-
-      area.width = info->real_width;
-      if (rtl)
-         area.x -= area.width;
-
-      gtk_cell_renderer_render (info->cell,
-                                event->window,
-                                widget,
-                                /* FIXME! */
-                                &area, &area, &event->area, state);
-
-      if (!rtl)
-         area.x += info->real_width;
-    }
-
-   area.x = rtl ? widget->allocation.x : (widget->allocation.x + widget->allocation.width);
-
-  /* PACK_END */
-  for (i = cellview->priv->cell_list; i; i = i->next)
-    {
-      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
-
-      if (info->pack == GTK_PACK_START)
-        continue;
-
-      if (!info->cell->visible)
-        continue;
-
-      area.width = info->real_width;
-      if (!rtl)
-         area.x -= area.width;
-
-      gtk_cell_renderer_render (info->cell,
-                                widget->window,
-                                widget,
-                                /* FIXME ! */
-                                &area, &area, &event->area, state);
-      if (rtl)
-         area.x += info->real_width;
-    }
-
-  return FALSE;
-}
-
-static GtkCellViewCellInfo *
-gtk_cell_view_get_cell_info (GtkCellView     *cellview,
-                             GtkCellRenderer *renderer)
-{
-  GList *i;
-
-  for (i = cellview->priv->cell_list; i; i = i->next)
-    {
-      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
-
-      if (info->cell == renderer)
-        return info;
-    }
-
-  return NULL;
-}
-
-static void
-gtk_cell_view_set_cell_data (GtkCellView *cellview)
-{
-  GList *i;
-  GtkTreeIter iter;
-  GtkTreePath *path;
-
-  g_return_if_fail (cellview->priv->displayed_row != NULL);
-
-  path = gtk_tree_row_reference_get_path (cellview->priv->displayed_row);
-  gtk_tree_model_get_iter (cellview->priv->model, &iter, path);
-  gtk_tree_path_free (path);
-
-  for (i = cellview->priv->cell_list; i; i = i->next)
-    {
-      GSList *j;
-      GtkCellViewCellInfo *info = i->data;
-
-      g_object_freeze_notify (G_OBJECT (info->cell));
-
-      for (j = info->attributes; j && j->next; j = j->next->next)
-        {
-          gchar *property = j->data;
-          gint column = GPOINTER_TO_INT (j->next->data);
-          GValue value = {0, };
-
-          gtk_tree_model_get_value (cellview->priv->model, &iter,
-                                    column, &value);
-          g_object_set_property (G_OBJECT (info->cell),
-                                 property, &value);
-          g_value_unset (&value);
-        }
-
-      if (info->func)
-	(* info->func) (GTK_CELL_LAYOUT (cellview),
-			info->cell,
-			cellview->priv->model,
-			&iter,
-			info->func_data);
-
-      g_object_thaw_notify (G_OBJECT (info->cell));
-    }
-}
-
-/* GtkCellLayout implementation */
-static void
-gtk_cell_view_cell_layout_pack_start (GtkCellLayout   *layout,
-                                      GtkCellRenderer *renderer,
-                                      gboolean         expand)
-{
-  GtkCellViewCellInfo *info;
-  GtkCellView *cellview = GTK_CELL_VIEW (layout);
-
-  g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
-  g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer));
-
-  g_object_ref (G_OBJECT (renderer));
-  gtk_object_sink (GTK_OBJECT (renderer));
-
-  info = g_new0 (GtkCellViewCellInfo, 1);
-  info->cell = renderer;
-  info->expand = expand ? TRUE : FALSE;
-  info->pack = GTK_PACK_START;
-
-  cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info);
-}
-
-static void
-gtk_cell_view_cell_layout_pack_end (GtkCellLayout   *layout,
-                                    GtkCellRenderer *renderer,
-                                    gboolean         expand)
-{
-  GtkCellViewCellInfo *info;
-  GtkCellView *cellview = GTK_CELL_VIEW (layout);
-
-  g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
-  g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer));
-
-  g_object_ref (G_OBJECT (renderer));
-  gtk_object_sink (GTK_OBJECT (renderer));
-
-  info = g_new0 (GtkCellViewCellInfo, 1);
-  info->cell = renderer;
-  info->expand = expand ? TRUE : FALSE;
-  info->pack = GTK_PACK_END;
-
-  cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info);
-}
-
-static void
-gtk_cell_view_cell_layout_add_attribute (GtkCellLayout   *layout,
-                                         GtkCellRenderer *renderer,
-                                         const gchar     *attribute,
-                                         gint             column)
-{
-  GtkCellViewCellInfo *info;
-  GtkCellView *cellview = GTK_CELL_VIEW (layout);
-
-  g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
-  info = gtk_cell_view_get_cell_info (cellview, renderer);
-  g_return_if_fail (info != NULL);
-
-  info->attributes = g_slist_prepend (info->attributes,
-                                      GINT_TO_POINTER (column));
-  info->attributes = g_slist_prepend (info->attributes,
-                                      g_strdup (attribute));
-}
-
-static void
-gtk_cell_view_cell_layout_clear (GtkCellLayout *layout)
-{
-  GtkCellView *cellview = GTK_CELL_VIEW (layout);
-
-  g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
-
-  while (cellview->priv->cell_list)
-    {
-      GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)cellview->priv->cell_list->data;
-
-      gtk_cell_view_cell_layout_clear_attributes (layout, info->cell);
-      g_object_unref (G_OBJECT (info->cell));
-      g_free (info);
-      cellview->priv->cell_list = g_list_delete_link (cellview->priv->cell_list,
-						      cellview->priv->cell_list);
-    }
-}
-
-static void
-gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout         *layout,
-                                              GtkCellRenderer       *cell,
-                                              GtkCellLayoutDataFunc  func,
-                                              gpointer               func_data,
-                                              GDestroyNotify         destroy)
-{
-  GtkCellView *cellview = GTK_CELL_VIEW (layout);
-  GtkCellViewCellInfo *info;
-
-  g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
-
-  info = gtk_cell_view_get_cell_info (cellview, cell);
-  g_return_if_fail (info != NULL);
-
-  if (info->destroy)
-    {
-      GDestroyNotify d = info->destroy;
-
-      info->destroy = NULL;
-      d (info->func_data);
-    }
-
-  info->func = func;
-  info->func_data = func_data;
-  info->destroy = destroy;
-}
-
-static void
-gtk_cell_view_cell_layout_clear_attributes (GtkCellLayout   *layout,
-                                            GtkCellRenderer *renderer)
-{
-  GtkCellViewCellInfo *info;
-  GtkCellView *cellview = GTK_CELL_VIEW (layout);
-  GSList *list;
-
-  g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
-
-  info = gtk_cell_view_get_cell_info (cellview, renderer);
-  if (info != NULL)
-    {
-      list = info->attributes;
-      while (list && list->next)
-	{
-	  g_free (list->data);
-	  list = list->next->next;
-	}
-
-      g_slist_free (info->attributes);
-      info->attributes = NULL;
-    }
-}
-
-static void
-gtk_cell_view_cell_layout_reorder (GtkCellLayout   *layout,
-                                   GtkCellRenderer *cell,
-                                   gint             position)
-{
-  GList *link;
-  GtkCellViewCellInfo *info;
-  GtkCellView *cellview = GTK_CELL_VIEW (layout);
-
-  g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
-
-  info = gtk_cell_view_get_cell_info (cellview, cell);
-
-  g_return_if_fail (info != NULL);
-  g_return_if_fail (position >= 0);
-
-  link = g_list_find (cellview->priv->cell_list, info);
-
-  g_return_if_fail (link != NULL);
-
-  cellview->priv->cell_list = g_list_remove_link (cellview->priv->cell_list,
-                                                  link);
-  cellview->priv->cell_list = g_list_insert (cellview->priv->cell_list,
-                                             info, position);
-
-  gtk_widget_queue_draw (GTK_WIDGET (cellview));
-}
-
-/* public API */
-GtkWidget *
-gtk_cell_view_new (void)
-{
-  GtkCellView *cellview;
-
-  cellview = GTK_CELL_VIEW (g_object_new (gtk_cell_view_get_type (), NULL));
-
-  return GTK_WIDGET (cellview);
-}
-
-GtkWidget *
-gtk_cell_view_new_with_text (const gchar *text)
-{
-  GtkCellView *cellview;
-  GtkCellRenderer *renderer;
-  GValue value = {0, };
-
-  cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
-
-  renderer = gtk_cell_renderer_text_new ();
-  gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
-                                        renderer, TRUE);
-
-  g_value_init (&value, G_TYPE_STRING);
-  g_value_set_string (&value, text);
-  gtk_cell_view_set_values (cellview, renderer, "text", &value, NULL);
-  g_value_unset (&value);
-
-  return GTK_WIDGET (cellview);
-}
-
-GtkWidget *
-gtk_cell_view_new_with_markup (const gchar *markup)
-{
-  GtkCellView *cellview;
-  GtkCellRenderer *renderer;
-  GValue value = {0, };
-
-  cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
-
-  renderer = gtk_cell_renderer_text_new ();
-  gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
-                                        renderer, TRUE);
-
-  g_value_init (&value, G_TYPE_STRING);
-  g_value_set_string (&value, markup);
-  gtk_cell_view_set_values (cellview, renderer, "markup", &value, NULL);
-  g_value_unset (&value);
-
-  return GTK_WIDGET (cellview);
-}
-
-GtkWidget *
-gtk_cell_view_new_with_pixbuf (GdkPixbuf *pixbuf)
-{
-  GtkCellView *cellview;
-  GtkCellRenderer *renderer;
-  GValue value = {0, };
-
-  cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
-
-  renderer = gtk_cell_renderer_pixbuf_new ();
-  gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
-                                        renderer, TRUE);
-
-  g_value_init (&value, GDK_TYPE_PIXBUF);
-  g_value_set_object (&value, pixbuf);
-  gtk_cell_view_set_values (cellview, renderer, "pixbuf", &value, NULL);
-  g_value_unset (&value);
-
-  return GTK_WIDGET (cellview);
-}
-
-void
-gtk_cell_view_set_value (GtkCellView     *cell_view,
-                         GtkCellRenderer *renderer,
-                         gchar           *property,
-                         GValue          *value)
-{
-  g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
-
-  g_object_set_property (G_OBJECT (renderer), property, value);
-
-  /* force resize and redraw */
-  gtk_widget_queue_resize (GTK_WIDGET (cell_view));
-  gtk_widget_queue_draw (GTK_WIDGET (cell_view));
-}
-
-static void
-gtk_cell_view_set_valuesv (GtkCellView     *cell_view,
-                           GtkCellRenderer *renderer,
-                           va_list          args)
-{
-  gchar *attribute;
-  GValue *value;
-
-  attribute = va_arg (args, gchar *);
-
-  while (attribute)
-    {
-      value = va_arg (args, GValue *);
-      gtk_cell_view_set_value (cell_view, renderer, attribute, value);
-      attribute = va_arg (args, gchar *);
-    }
-}
-
-void
-gtk_cell_view_set_values (GtkCellView     *cell_view,
-                          GtkCellRenderer *renderer,
-                          ...)
-{
-  va_list args;
-
-  g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
-  g_return_if_fail (gtk_cell_view_get_cell_info (cell_view, renderer));
-
-  va_start (args, renderer);
-  gtk_cell_view_set_valuesv (cell_view, renderer, args);
-  va_end (args);
-}
-
-void
-gtk_cell_view_set_model (GtkCellView  *cell_view,
-                         GtkTreeModel *model)
-{
-  g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
-  g_return_if_fail (GTK_IS_TREE_MODEL (model));
-
-  if (cell_view->priv->model)
-    {
-      if (cell_view->priv->displayed_row)
-        gtk_tree_row_reference_free (cell_view->priv->displayed_row);
-      cell_view->priv->displayed_row = NULL;
-
-      g_object_unref (G_OBJECT (cell_view->priv->model));
-      cell_view->priv->model = NULL;
-    }
-
-  cell_view->priv->model = model;
-
-  if (cell_view->priv->model)
-    g_object_ref (G_OBJECT (cell_view->priv->model));
-}
-
-/**
- * gtk_cell_view_set_displayed_row:
- * @cell_view: a #GtkCellView
- * @path: a #GtkTreePath or %NULL to unset.
- *
- * Sets the row of the model that is currently displayed
- * by the #GtkCellView. If the path is unset, then the
- * contents of the cellview "stick" at their last value;
- * this is not normally a desired result, but may be
- * a needed intermediate state if say, the model for
- * the #GtkCellView becomes temporarily empty.
- **/
-void
-gtk_cell_view_set_displayed_row (GtkCellView *cell_view,
-                                 GtkTreePath *path)
-{
-  g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
-  g_return_if_fail (GTK_IS_TREE_MODEL (cell_view->priv->model));
-
-  if (cell_view->priv->displayed_row)
-    gtk_tree_row_reference_free (cell_view->priv->displayed_row);
-
-  if (path)
-    {
-      cell_view->priv->displayed_row =
-	gtk_tree_row_reference_new (cell_view->priv->model, path);
-    }
-  else
-    cell_view->priv->displayed_row = NULL;
-
-  /* force resize and redraw */
-  gtk_widget_queue_resize (GTK_WIDGET (cell_view));
-  gtk_widget_queue_draw (GTK_WIDGET (cell_view));
-}
-
-GtkTreePath *
-gtk_cell_view_get_displayed_row (GtkCellView *cell_view)
-{
-  g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), NULL);
-
-  if (!cell_view->priv->displayed_row)
-    return NULL;
-
-  return gtk_tree_row_reference_get_path (cell_view->priv->displayed_row);
-}
-
-gboolean
-gtk_cell_view_get_size_of_row (GtkCellView    *cell_view,
-                               GtkTreePath    *path,
-                               GtkRequisition *requisition)
-{
-  GtkTreeRowReference *tmp;
-  GtkRequisition req;
-
-  g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), FALSE);
-  g_return_val_if_fail (path != NULL, FALSE);
-  g_return_val_if_fail (requisition != NULL, FALSE);
-
-  tmp = cell_view->priv->displayed_row;
-  cell_view->priv->displayed_row =
-    gtk_tree_row_reference_new (cell_view->priv->model, path);
-
-  gtk_cell_view_size_request (GTK_WIDGET (cell_view), requisition);
-
-  gtk_tree_row_reference_free (cell_view->priv->displayed_row);
-  cell_view->priv->displayed_row = tmp;
-
-  /* restore actual size info */
-  gtk_cell_view_size_request (GTK_WIDGET (cell_view), &req);
-
-  return TRUE;
-}
-
-void
-gtk_cell_view_set_background_color (GtkCellView    *view,
-                                    const GdkColor *color)
-{
-  g_return_if_fail (GTK_IS_CELL_VIEW (view));
-
-  if (color)
-    {
-      if (!view->priv->background_set)
-        {
-          view->priv->background_set = TRUE;
-          g_object_notify (G_OBJECT (view), "background_set");
-        }
-
-      view->priv->background = *color;
-    }
-  else
-    {
-      if (view->priv->background_set)
-        {
-          view->priv->background_set = FALSE;
-          g_object_notify (G_OBJECT (view), "background_set");
-        }
-    }
-}
-#endif /* Gtk 2.6 */
--- a/pidgin/gtkcellview.h	Thu Feb 04 02:18:37 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/* gtkcellview.h
- * Copyright (C) 2002, 2003  Kristian Rietveld <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02111-1301, USA.
- */
-
-#ifndef __GTK_CELL_VIEW_H__
-#define __GTK_CELL_VIEW_H__
-
-#include <gtk/gtkwidget.h>
-#include <gtk/gtkcellrenderer.h>
-#include <gtk/gtktreemodel.h>
-
-G_BEGIN_DECLS
-
-#define GTK_TYPE_CELL_VIEW                (gtk_cell_view_get_type ())
-#define GTK_CELL_VIEW(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CELL_VIEW, GtkCellView))
-#define GTK_CELL_VIEW_CLASS(vtable)       (G_TYPE_CHECK_CLASS_CAST ((vtable), GTK_TYPE_CELL_VIEW, GtkCellViewClass))
-#define GTK_IS_CELL_VIEW(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CELL_VIEW))
-#define GTK_IS_CELL_VIEW_CLASS(vtable)    (G_TYPE_CHECK_CLASS_TYPE ((vtable), GTK_TYPE_CELL_VIEW))
-#define GTK_CELL_VIEW_GET_CLASS(inst)     (G_TYPE_INSTANCE_GET_CLASS ((inst), GTK_TYPE_CELL_VIEW, GtkCellViewClass))
-
-typedef struct _GtkCellView             GtkCellView;
-typedef struct _GtkCellViewClass        GtkCellViewClass;
-typedef struct _GtkCellViewPrivate      GtkCellViewPrivate;
-
-struct _GtkCellView
-{
-  GtkWidget parent_instance;
-
-  /*< private >*/
-  GtkCellViewPrivate *priv;
-};
-
-struct _GtkCellViewClass
-{
-  GtkWidgetClass parent_class;
-};
-
-GType             gtk_cell_view_get_type               (void);
-GtkWidget        *gtk_cell_view_new                    (void);
-GtkWidget        *gtk_cell_view_new_with_text          (const gchar     *text);
-GtkWidget        *gtk_cell_view_new_with_markup        (const gchar     *markup);
-GtkWidget        *gtk_cell_view_new_with_pixbuf        (GdkPixbuf       *pixbuf);
-
-
-void              gtk_cell_view_set_value               (GtkCellView     *cell_view,
-                                                         GtkCellRenderer *renderer,
-                                                         gchar           *property,
-                                                         GValue          *value);
-void              gtk_cell_view_set_values              (GtkCellView     *cell_view,
-                                                         GtkCellRenderer *renderer,
-                                                         ...);
-
-void              gtk_cell_view_set_model               (GtkCellView     *cell_view,
-                                                         GtkTreeModel    *model);
-void              gtk_cell_view_set_displayed_row       (GtkCellView     *cell_view,
-                                                         GtkTreePath     *path);
-GtkTreePath      *gtk_cell_view_get_displayed_row       (GtkCellView     *cell_view);
-gboolean          gtk_cell_view_get_size_of_row         (GtkCellView     *cell_view,
-                                                         GtkTreePath     *path,
-                                                         GtkRequisition  *requisition);
-
-void              gtk_cell_view_set_background_color    (GtkCellView     *cell_view,
-                                                         const GdkColor  *color);
-
-G_END_DECLS
-
-#endif /* __GTK_CELL_VIEW_H__ */
--- a/pidgin/gtkcellviewmenuitem.c	Thu Feb 04 02:18:37 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,163 +0,0 @@
-/* gtkcellviewmenuitem.c
- * Copyright (C) 2003  Kristian Rietveld <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02111-1301, USA.
- */
-
-/*
-#include <config.h>
-*/
-#include <gtk/gtkversion.h>
-#if !GTK_CHECK_VERSION(2,6,0)
-#include "gtkcellviewmenuitem.h"
-#include "gtkcellview.h"
-
-struct _GtkCellViewMenuItemPrivate
-{
-  GtkWidget *cell_view;
-};
-
-static void gtk_cell_view_menu_item_init       (GtkCellViewMenuItem      *item);
-static void gtk_cell_view_menu_item_class_init (GtkCellViewMenuItemClass *klass);
-static void gtk_cell_view_menu_item_finalize   (GObject                  *object);
-
-
-GType
-gtk_cell_view_menu_item_get_type (void)
-{
-  static GType cell_view_menu_item_type = 0;
-
-  if (!cell_view_menu_item_type)
-    {
-      static const GTypeInfo cell_view_menu_item_info =
-        {
-          sizeof (GtkCellViewMenuItemClass),
-          NULL,
-          NULL,
-          (GClassInitFunc) gtk_cell_view_menu_item_class_init,
-          NULL,
-          NULL,
-          sizeof (GtkCellViewMenuItem),
-          0,
-          (GInstanceInitFunc) gtk_cell_view_menu_item_init
-        };
-
-      cell_view_menu_item_type =
-        g_type_register_static (GTK_TYPE_MENU_ITEM, "PidginCellViewMenuItem",
-                                &cell_view_menu_item_info, 0);
-    }
-
-  return cell_view_menu_item_type;
-}
-
-static void
-gtk_cell_view_menu_item_class_init (GtkCellViewMenuItemClass *klass)
-{
-  GObjectClass *object_class;
-
-  object_class = (GObjectClass *)klass;
-  object_class->finalize = gtk_cell_view_menu_item_finalize;
-}
-
-static void
-gtk_cell_view_menu_item_init (GtkCellViewMenuItem *item)
-{
-  item->priv = g_new0(GtkCellViewMenuItemPrivate,1);
-}
-
-GtkWidget *
-gtk_cell_view_menu_item_new (void)
-{
-  GtkCellViewMenuItem *item;
-
-  item = g_object_new (GTK_TYPE_CELL_VIEW_MENU_ITEM, NULL);
-
-  item->priv->cell_view = gtk_cell_view_new ();
-  gtk_container_add (GTK_CONTAINER (item), item->priv->cell_view);
-  gtk_widget_show (item->priv->cell_view);
-
-  return GTK_WIDGET (item);
-}
-
-GtkWidget *
-gtk_cell_view_menu_item_new_with_pixbuf (GdkPixbuf *pixbuf)
-{
-  GtkCellViewMenuItem *item;
-
-  item = g_object_new (GTK_TYPE_CELL_VIEW_MENU_ITEM, NULL);
-
-  item->priv->cell_view = gtk_cell_view_new_with_pixbuf (pixbuf);
-  gtk_container_add (GTK_CONTAINER (item), item->priv->cell_view);
-  gtk_widget_show (item->priv->cell_view);
-
-  return GTK_WIDGET (item);
-}
-
-GtkWidget *
-gtk_cell_view_menu_item_new_with_text (const gchar *text)
-{
-  GtkCellViewMenuItem *item;
-
-  item = g_object_new (GTK_TYPE_CELL_VIEW_MENU_ITEM, NULL);
-
-  item->priv->cell_view = gtk_cell_view_new_with_text (text);
-  gtk_container_add (GTK_CONTAINER (item), item->priv->cell_view);
-  gtk_widget_show (item->priv->cell_view);
-
-  return GTK_WIDGET (item);
-}
-
-GtkWidget *
-gtk_cell_view_menu_item_new_with_markup (const gchar *markup)
-{
-  GtkCellViewMenuItem *item;
-
-  item = g_object_new (GTK_TYPE_CELL_VIEW_MENU_ITEM, NULL);
-
-  item->priv->cell_view = gtk_cell_view_new_with_markup (markup);
-  gtk_container_add (GTK_CONTAINER (item), item->priv->cell_view);
-  gtk_widget_show (item->priv->cell_view);
-
-  return GTK_WIDGET (item);
-}
-
-GtkWidget *
-gtk_cell_view_menu_item_new_from_model (GtkTreeModel *model,
-                                        GtkTreePath  *path)
-{
-  GtkCellViewMenuItem *item;
-
-  item = g_object_new (GTK_TYPE_CELL_VIEW_MENU_ITEM, NULL);
-
-  item->priv->cell_view = gtk_cell_view_new ();
-  gtk_container_add (GTK_CONTAINER (item), item->priv->cell_view);
-
-  gtk_cell_view_set_model (GTK_CELL_VIEW (item->priv->cell_view), model);
-  gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (item->priv->cell_view), path);
-
-  gtk_widget_show (item->priv->cell_view);
-
-  return GTK_WIDGET (item);
-}
-
-static void
-gtk_cell_view_menu_item_finalize (GObject *object)
-{
-  GtkCellViewMenuItem *item = GTK_CELL_VIEW_MENU_ITEM (object);
-
-  g_free (item->priv);
-}
-#endif /* Gtk 2.6 */
--- a/pidgin/gtkcellviewmenuitem.h	Thu Feb 04 02:18:37 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/* gtkcellviewmenuitem.h
- * Copyright (C) 2003  Kristian Rietveld <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02111-1301, USA.
- */
-
-#ifndef __GTK_CELL_VIEW_MENU_ITEM_H__
-#define __GTK_CELL_VIEW_MENU_ITEM_H__
-
-#include <gtk/gtkmenuitem.h>
-#include <gtk/gtktreemodel.h>
-
-G_BEGIN_DECLS
-
-#define GTK_TYPE_CELL_VIEW_MENU_ITEM              (gtk_cell_view_menu_item_get_type ())
-#define GTK_CELL_VIEW_MENU_ITEM(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CELL_VIEW_MENU_ITEM, GtkCellViewMenuItem))
-#define GTK_CELL_VIEW_MENU_ITEM_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_CELL_VIEW_MENU_ITEM, GtkCellViewMenuItemClass))
-#define GTK_IS_CELL_VIEW_MENU_ITEM(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CELL_VIEW_MENU_ITEM))
-#define GTK_IS_CELL_VIEW_MENU_ITEM_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_CELL_VIEW_MENU_ITEM))
-#define GTK_CELL_VIEW_MENU_ITEM_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CELL_VIEW_MENU_ITEM, GtkCellViewMenuItemClass))
-
-
-typedef struct _GtkCellViewMenuItem        GtkCellViewMenuItem;
-typedef struct _GtkCellViewMenuItemClass   GtkCellViewMenuItemClass;
-typedef struct _GtkCellViewMenuItemPrivate GtkCellViewMenuItemPrivate;
-
-struct _GtkCellViewMenuItem
-{
-  GtkMenuItem parent_instance;
-
-  /*< private >*/
-  GtkCellViewMenuItemPrivate *priv;
-};
-
-struct _GtkCellViewMenuItemClass
-{
-  GtkMenuItemClass parent_class;
-};
-
-
-GType      gtk_cell_view_menu_item_get_type        (void);
-GtkWidget *gtk_cell_view_menu_item_new             (void);
-
-GtkWidget *gtk_cell_view_menu_item_new_with_pixbuf (GdkPixbuf   *pixbuf);
-GtkWidget *gtk_cell_view_menu_item_new_with_text   (const gchar *text);
-GtkWidget *gtk_cell_view_menu_item_new_with_markup (const gchar *markup);
-
-GtkWidget *gtk_cell_view_menu_item_new_from_model  (GtkTreeModel *model,
-                                                    GtkTreePath  *path);
-
-
-G_END_DECLS
-
-#endif /* __GTK_CELL_VIEW_MENU_ITEM_H__ */
--- a/pidgin/gtkconv.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkconv.c	Thu Feb 04 05:30:35 2010 +0000
@@ -1077,11 +1077,7 @@
 	gdk_window_set_cursor(gtkblist->window->window, cursor);
 	gdk_window_set_cursor(win->window->window, cursor);
 	gdk_cursor_unref(cursor);
-#if GTK_CHECK_VERSION(2,4,0)
 	gdk_display_flush(gdk_drawable_get_display(GDK_DRAWABLE(widget->window)));
-#else
-	gdk_flush();
-#endif
 
 	name = purple_conversation_get_name(conv);
 	account = purple_conversation_get_account(conv);
@@ -1117,114 +1113,13 @@
 	clear_conversation_scrollback(conv);
 }
 
-struct _search {
-	PidginWindow *gtkwin;
-	GtkWidget *entry;
-};
-
-static void do_search_cb(GtkWidget *widget, gint resp, struct _search *s)
-{
-	PurpleConversation *conv;
-	PidginConversation *gtk_active_conv;
-	GList *iter;
-
-	conv = pidgin_conv_window_get_active_conversation(s->gtkwin);
-	gtk_active_conv = PIDGIN_CONVERSATION(conv);
-
-	switch (resp)
-	{
-		case GTK_RESPONSE_OK:
-			/* clear highlighting except the active conversation window
-			 * highlight the keywords in the active conversation window */
-			for (iter = pidgin_conv_window_get_gtkconvs(s->gtkwin) ; iter ; iter = iter->next)
-			{
-				PidginConversation *gtkconv = iter->data;
-
-				if (gtkconv != gtk_active_conv)
-				{
-					gtk_imhtml_search_clear(GTK_IMHTML(gtkconv->imhtml));
-				}
-				else
-				{
-					gtk_imhtml_search_find(GTK_IMHTML(gtk_active_conv->imhtml),
-					                       gtk_entry_get_text(GTK_ENTRY(s->entry)));
-				}
-			}
-			break;
-
-		case GTK_RESPONSE_DELETE_EVENT:
-		case GTK_RESPONSE_CLOSE:
-			/* clear the keyword highlighting in all the conversation windows */
-			for (iter = pidgin_conv_window_get_gtkconvs(s->gtkwin); iter; iter=iter->next)
-			{
-				PidginConversation *gconv = iter->data;
-				gtk_imhtml_search_clear(GTK_IMHTML(gconv->imhtml));
-			}
-
-			gtk_widget_destroy(s->gtkwin->dialogs.search);
-			s->gtkwin->dialogs.search = NULL;
-			g_free(s);
-			break;
-	}
-}
-
 static void
 menu_find_cb(gpointer data, guint action, GtkWidget *widget)
 {
 	PidginWindow *gtkwin = data;
-	GtkWidget *hbox;
-	GtkWidget *img = gtk_image_new_from_stock(PIDGIN_STOCK_DIALOG_QUESTION,
-						  gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_HUGE));
-	GtkWidget *label;
-	struct _search *s;
-
-	if (gtkwin->dialogs.search) {
-		gtk_window_present(GTK_WINDOW(gtkwin->dialogs.search));
-		return;
-	}
-
-	s = g_malloc(sizeof(struct _search));
-	s->gtkwin = gtkwin;
-
-	gtkwin->dialogs.search = gtk_dialog_new_with_buttons(_("Find"),
-			GTK_WINDOW(gtkwin->window), GTK_DIALOG_DESTROY_WITH_PARENT,
-			GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
-			GTK_STOCK_FIND, GTK_RESPONSE_OK, NULL);
-	gtk_dialog_set_default_response(GTK_DIALOG(gtkwin->dialogs.search),
-									GTK_RESPONSE_OK);
-	g_signal_connect(G_OBJECT(gtkwin->dialogs.search), "response",
-					 G_CALLBACK(do_search_cb), s);
-
-	gtk_container_set_border_width(GTK_CONTAINER(gtkwin->dialogs.search), PIDGIN_HIG_BOX_SPACE);
-	gtk_window_set_resizable(GTK_WINDOW(gtkwin->dialogs.search), FALSE);
-	gtk_dialog_set_has_separator(GTK_DIALOG(gtkwin->dialogs.search), FALSE);
-	gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(gtkwin->dialogs.search)->vbox), PIDGIN_HIG_BORDER);
-	gtk_container_set_border_width(
-		GTK_CONTAINER(GTK_DIALOG(gtkwin->dialogs.search)->vbox), PIDGIN_HIG_BOX_SPACE);
-
-	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER);
-	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(gtkwin->dialogs.search)->vbox),
-					  hbox);
-	gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
-
-	gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
-	gtk_dialog_set_response_sensitive(GTK_DIALOG(gtkwin->dialogs.search),
-									  GTK_RESPONSE_OK, FALSE);
-
-	label = gtk_label_new(NULL);
-	gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("_Search for:"));
-	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
-
-	s->entry = gtk_entry_new();
-	gtk_entry_set_activates_default(GTK_ENTRY(s->entry), TRUE);
-	gtk_label_set_mnemonic_widget(GTK_LABEL(label), GTK_WIDGET(s->entry));
-	g_signal_connect(G_OBJECT(s->entry), "changed",
-					 G_CALLBACK(pidgin_set_sensitive_if_input),
-					 gtkwin->dialogs.search);
-	gtk_box_pack_start(GTK_BOX(hbox), s->entry, FALSE, FALSE, 0);
-
-	gtk_widget_show_all(gtkwin->dialogs.search);
-	gtk_widget_grab_focus(s->entry);
+	PidginConversation *gtkconv = pidgin_conv_window_get_active_gtkconv(gtkwin);
+	gtk_widget_show_all(gtkconv->quickfind.container);
+	gtk_widget_grab_focus(gtkconv->quickfind.entry);
 }
 
 #ifdef USE_VV
@@ -1257,6 +1152,18 @@
 }
 
 static void
+menu_get_attention_cb(gpointer data, guint action, GtkWidget *widget)
+{
+	PidginWindow *win = data;
+	PurpleConversation *conv = pidgin_conv_window_get_active_conversation(win);
+
+	if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
+		purple_prpl_send_attention(purple_conversation_get_gc(conv), 
+			purple_conversation_get_name(conv), 0);
+	}
+}
+
+static void
 menu_add_pounce_cb(gpointer data, guint action, GtkWidget *widget)
 {
 	PidginWindow *win = data;
@@ -2050,11 +1957,7 @@
 			case GDK_period:
 				gtk_notebook_reorder_child(GTK_NOTEBOOK(win->notebook),
 						gtk_notebook_get_nth_page(GTK_NOTEBOOK(win->notebook), curconv),
-#if GTK_CHECK_VERSION(2,2,0)
 						(curconv + 1) % gtk_notebook_get_n_pages(GTK_NOTEBOOK(win->notebook)));
-#else
-						(curconv + 1) % g_list_length(GTK_NOTEBOOK(win->notebook)->children));
-#endif
 				return TRUE;
 				break;
 			case GDK_F6:
@@ -2322,6 +2225,11 @@
 	gtkconv = PIDGIN_CONVERSATION(conv);
 	old_conv = gtkconv->active_conv;
 
+	purple_debug_info("gtkconv", "setting active conversation on toolbar %p\n",
+		conv);
+	gtk_imhtmltoolbar_switch_active_conversation(GTK_IMHTMLTOOLBAR(gtkconv->toolbar), 
+		conv);
+
 	if (old_conv == conv)
 		return;
 
@@ -3185,6 +3093,7 @@
 #endif
 
 	{ N_("/Conversation/Se_nd File..."), NULL, menu_send_file_cb, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_SEND_FILE },
+	{ N_("/Conversation/Get _Attention"), NULL, menu_get_attention_cb, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_SEND_ATTENTION },
 	{ N_("/Conversation/Add Buddy _Pounce..."), NULL, menu_add_pounce_cb,
 			0, "<Item>", NULL },
 	{ N_("/Conversation/_Get Info"), "<CTL>O", menu_get_info_cb, 0,
@@ -3569,6 +3478,9 @@
 		gtk_item_factory_get_widget(win->menu.item_factory,
 		                            N_("/Conversation/Send File..."));
 
+	g_object_set_data(G_OBJECT(win->window), "get_attention",
+		gtk_item_factory_get_widget(win->menu.item_factory,
+			                    N_("/Conversation/Get Attention")));
 	win->menu.add_pounce =
 		gtk_item_factory_get_widget(win->menu.item_factory,
 		                            N_("/Conversation/Add Buddy Pounce..."));
@@ -3887,7 +3799,7 @@
 	gtk_size_group_add_widget(sg, image);
 
 	/* Make our menu item */
-	text = g_strdup_printf("%s (%s)", name, purple_account_get_username(account));
+	text = g_strdup_printf("%s (%s)", name, purple_account_get_name_for_display(account));
 	menuitem = gtk_radio_menu_item_new_with_label(*group, text);
 	g_free(text);
 	*group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menuitem));
@@ -4116,7 +4028,6 @@
 		color = (GdkColor*)get_nick_color(gtkconv, name);
 	}
 
-#if GTK_CHECK_VERSION(2,6,0)
 	gtk_list_store_insert_with_values(ls, &iter,
 /*
 * The GTK docs are mute about the effects of the "row" value for performance.
@@ -4134,18 +4045,6 @@
 			CHAT_USERS_COLOR_COLUMN, color,
 			CHAT_USERS_WEIGHT_COLUMN, is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
 			-1);
-#else
-	gtk_list_store_append(ls, &iter);
-	gtk_list_store_set(ls, &iter,
-			CHAT_USERS_ICON_STOCK_COLUMN,  stock,
-			CHAT_USERS_ALIAS_COLUMN, alias,
-			CHAT_USERS_ALIAS_KEY_COLUMN, alias_key,
-			CHAT_USERS_NAME_COLUMN,  name,
-			CHAT_USERS_FLAGS_COLUMN, flags,
-			CHAT_USERS_COLOR_COLUMN, color,
-			CHAT_USERS_WEIGHT_COLUMN, is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
-			-1);
-#endif
 
 	if (is_me && color)
 		gdk_color_free(color);
@@ -4798,9 +4697,7 @@
 
 	/* Setup the label telling how many people are in the room. */
 	gtkchat->count = gtk_label_new(_("0 people in room"));
-#if GTK_CHECK_VERSION(2,6,0)
 	gtk_label_set_ellipsize(GTK_LABEL(gtkchat->count), PANGO_ELLIPSIZE_END);
-#endif
 	gtk_box_pack_start(GTK_BOX(lbox), gtkchat->count, FALSE, FALSE, 0);
 	gtk_widget_show(gtkchat->count);
 
@@ -4870,10 +4767,8 @@
 	purple_signal_connect(blist_handle, "blist-node-aliased",
 						gtkchat, PURPLE_CALLBACK(blist_node_aliased_cb), conv);
 
-#if GTK_CHECK_VERSION(2,6,0)
 	gtk_tree_view_column_set_expand(col, TRUE);
 	g_object_set(rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
-#endif
 
 	gtk_tree_view_append_column(GTK_TREE_VIEW(list), col);
 
@@ -4911,6 +4806,121 @@
 	return FALSE;
 }
 
+/* Close button {{{ */
+static gboolean
+close_button_left_cb(GtkWidget *widget, GdkEventCrossing *event, GtkLabel *label)
+{
+	static GdkCursor *ptr = NULL;
+	if (ptr == NULL) {
+		ptr = gdk_cursor_new(GDK_LEFT_PTR);
+	}
+
+	gtk_label_set_markup(label, "×");
+	gdk_window_set_cursor(event->window, ptr);
+	return FALSE;
+}
+
+static gboolean
+close_button_entered_cb(GtkWidget *widget, GdkEventCrossing *event, GtkLabel *label)
+{
+	static GdkCursor *hand = NULL;
+	if (hand == NULL) {
+		hand = gdk_cursor_new(GDK_HAND2);
+	}
+
+	gtk_label_set_markup(label, "<u>×</u>");
+	gdk_window_set_cursor(event->window, hand);
+	return FALSE;
+}
+
+static GtkWidget *
+create_close_button(void)
+{
+	GtkWidget *ebox = gtk_event_box_new();
+	GtkWidget *close_image;
+
+	gtk_event_box_set_visible_window(GTK_EVENT_BOX(ebox), FALSE);
+	gtk_widget_set_events(ebox, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
+	close_image = gtk_label_new("×");
+	g_signal_connect(G_OBJECT(ebox), "enter-notify-event", G_CALLBACK(close_button_entered_cb), close_image);
+	g_signal_connect(G_OBJECT(ebox), "leave-notify-event", G_CALLBACK(close_button_left_cb), close_image);
+	gtk_widget_show(close_image);
+	gtk_container_add(GTK_CONTAINER(ebox), close_image);
+
+	return ebox;
+}
+
+/* }}} */
+
+/* Quick Find {{{ */
+static gboolean
+pidgin_conv_end_quickfind(PidginConversation *gtkconv)
+{
+	gtk_widget_modify_base(gtkconv->quickfind.entry, GTK_STATE_NORMAL, NULL);
+
+	gtk_imhtml_search_clear(GTK_IMHTML(gtkconv->imhtml));
+	gtk_widget_hide_all(gtkconv->quickfind.container);
+
+	gtk_widget_grab_focus(gtkconv->entry);
+	return TRUE;
+}
+
+static gboolean
+quickfind_process_input(GtkWidget *entry, GdkEventKey *event, PidginConversation *gtkconv)
+{
+	switch (event->keyval) {
+		case GDK_Return:
+		case GDK_KP_Enter:
+			if (gtk_imhtml_search_find(GTK_IMHTML(gtkconv->imhtml), gtk_entry_get_text(GTK_ENTRY(entry)))) {
+				gtk_widget_modify_base(gtkconv->quickfind.entry, GTK_STATE_NORMAL, NULL);
+			} else {
+				GdkColor col;
+				col.red = 0xffff;
+				col.green = 0xafff;
+				col.blue = 0xafff;
+				gtk_widget_modify_base(gtkconv->quickfind.entry, GTK_STATE_NORMAL, &col);
+			}
+			break;
+		case GDK_Escape:
+			pidgin_conv_end_quickfind(gtkconv);
+			break;
+		default:
+			return FALSE;
+	}
+	return TRUE;
+}
+
+static void
+pidgin_conv_setup_quickfind(PidginConversation *gtkconv, GtkWidget *container)
+{
+	GtkWidget *widget = gtk_hbox_new(FALSE, 0);
+	GtkWidget *label, *entry, *close;
+
+	gtk_box_pack_start(GTK_BOX(container), widget, FALSE, FALSE, 0);
+
+	close = create_close_button();
+	gtk_box_pack_start(GTK_BOX(widget), close, FALSE, FALSE, 0);
+	gtk_tooltips_set_tip(gtkconv->tooltips, close,
+	                     _("Close Find bar"), NULL);
+
+	label = gtk_label_new(_("Find:"));
+	gtk_box_pack_start(GTK_BOX(widget), label, FALSE, FALSE, 10);
+
+	entry = gtk_entry_new();
+	gtk_box_pack_start(GTK_BOX(widget), entry, TRUE, TRUE, 0);
+
+	gtkconv->quickfind.entry = entry;
+	gtkconv->quickfind.container = widget;
+
+	/* Hook to signals and stuff */
+	g_signal_connect(G_OBJECT(entry), "key_press_event",
+			G_CALLBACK(quickfind_process_input), gtkconv);
+	g_signal_connect_swapped(G_OBJECT(close), "button-press-event",
+			G_CALLBACK(pidgin_conv_end_quickfind), gtkconv);
+}
+
+/* }}} */
+
 static GtkWidget *
 setup_common_pane(PidginConversation *gtkconv)
 {
@@ -4929,9 +4939,7 @@
 
 	/* Setup the info pane */
 	event_box = gtk_event_box_new();
-#if GTK_CHECK_VERSION(2,4,0)
 	gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box), FALSE);
-#endif
 	gtk_widget_show(event_box);
 	gtkconv->infopane_hbox = gtk_hbox_new(FALSE, 0);
 	gtk_box_pack_start(GTK_BOX(vbox), event_box, FALSE, FALSE, 0);
@@ -5001,9 +5009,7 @@
 	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(gtkconv->infopane), rend, "markup", CONV_TEXT_COLUMN, NULL);
 	g_object_set(rend, "ypad", 0, "yalign", 0.5, NULL);
 
-#if GTK_CHECK_VERSION(2, 6, 0)
 	g_object_set(rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
-#endif
 
 	rend = gtk_cell_renderer_pixbuf_new();
 	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(gtkconv->infopane), rend, FALSE);
@@ -5053,6 +5059,8 @@
 	g_signal_connect(G_OBJECT(gtkconv->imhtml), "key_release_event",
 	                 G_CALLBACK(refocus_entry_cb), gtkconv);
 
+	pidgin_conv_setup_quickfind(gtkconv, vbox);
+
 	gtkconv->lower_hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
 	gtk_box_pack_start(GTK_BOX(vbox), gtkconv->lower_hbox, FALSE, FALSE, 0);
 	gtk_widget_show(gtkconv->lower_hbox);
@@ -6141,10 +6149,8 @@
 
 	ls = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(gtkchat->list)));
 
-#if GTK_CHECK_VERSION(2,6,0)
 	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(ls),  GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
 										 GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID);
-#endif
 
 	l = cbuddies;
 	while (l != NULL) {
@@ -6246,12 +6252,7 @@
 							   CHAT_USERS_NAME_COLUMN, &val, -1);
 
 			if (!purple_utf8_strcasecmp((char *)l->data, val)) {
-#if GTK_CHECK_VERSION(2,2,0)
 				f = gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
-#else
-				gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
-				f = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter);
-#endif
 			}
 			else
 				f = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter);
@@ -6509,6 +6510,7 @@
 		/* Deal with menu items */
 		gtk_widget_show(win->menu.view_log);
 		gtk_widget_show(win->menu.send_file);
+		gtk_widget_show(g_object_get_data(G_OBJECT(win->window), "get_attention"));
 		gtk_widget_show(win->menu.add_pounce);
 		gtk_widget_show(win->menu.get_info);
 		gtk_widget_hide(win->menu.invite);
@@ -6537,6 +6539,7 @@
 		/* Deal with menu items */
 		gtk_widget_show(win->menu.view_log);
 		gtk_widget_hide(win->menu.send_file);
+		gtk_widget_hide(g_object_get_data(G_OBJECT(win->window), "get_attention"));
 		gtk_widget_hide(win->menu.add_pounce);
 		gtk_widget_hide(win->menu.get_info);
 		gtk_widget_show(win->menu.invite);
@@ -6614,6 +6617,7 @@
 			gtk_widget_set_sensitive(win->menu.send_file,
 									 (prpl_info->send_file != NULL && (!prpl_info->can_receive_file ||
 									  prpl_info->can_receive_file(gc, purple_conversation_get_name(conv)))));
+			gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(win->window), "get_attention"), (prpl_info->send_attention != NULL));
 			gtk_widget_set_sensitive(win->menu.alias,
 									 (account != NULL) &&
 									 (purple_find_buddy(account, purple_conversation_get_name(conv)) != NULL));
@@ -6634,6 +6638,8 @@
 		/* Then deal with menu items */
 		gtk_widget_set_sensitive(win->menu.view_log, TRUE);
 		gtk_widget_set_sensitive(win->menu.send_file, FALSE);
+		gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(win->window),
+			"get_attention"), FALSE);
 		gtk_widget_set_sensitive(win->menu.add_pounce, TRUE);
 		gtk_widget_set_sensitive(win->menu.get_info, FALSE);
 		gtk_widget_set_sensitive(win->menu.invite, FALSE);
@@ -6767,31 +6773,7 @@
 				? gtk_entry_get_text(GTK_ENTRY(gtkconv->u.chat->topic_text))
 				: NULL;
 			char *esc = NULL, *tmp;
-#if GTK_CHECK_VERSION(2,6,0)
 			esc = topic ? g_markup_escape_text(topic, -1) : NULL;
-#else
-			/* GTK < 2.6 doesn't have auto ellipsization, so we do a crude
-			 * trucation to prevent forcing the window to be as wide as the topic */
-			int len = 0;
-			char *c;
-
-			if (topic != NULL) {
-				tmp = g_strdup(topic);
-				c = tmp;
-				while(*c && len < 72) {
-					c = g_utf8_next_char(c);
-					len++;
-				}
-				if (len == 72) {
-					*c = '\0';
-					c = g_strdup_printf("%s...", tmp);
-					g_free(tmp);
-					tmp = c;
-				}
-				esc = g_markup_escape_text(tmp, -1);
-				g_free(tmp);
-			}
-#endif
 			tmp = g_markup_escape_text(purple_conversation_get_title(conv), -1);
 			markup = g_strdup_printf("%s%s<span color='%s' size='smaller'>%s</span>",
 						tmp, esc  && *esc ? "\n" : "",
@@ -7142,9 +7124,7 @@
 
 	event = gtk_event_box_new();
 	gtk_container_add(GTK_CONTAINER(gtkconv->u.im->icon_container), event);
-#if GTK_CHECK_VERSION(2,4,0)
 	gtk_event_box_set_visible_window(GTK_EVENT_BOX(event), FALSE);
-#endif
 	gtk_widget_add_events(event,
                               GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
 	g_signal_connect(G_OBJECT(event), "button-press-event",
@@ -7217,12 +7197,7 @@
 	horiz = (gtk_notebook_get_tab_pos(notebook) == GTK_POS_TOP ||
 			gtk_notebook_get_tab_pos(notebook) == GTK_POS_BOTTOM);
 
-#if GTK_CHECK_VERSION(2,2,0)
 	count = gtk_notebook_get_n_pages(GTK_NOTEBOOK(notebook));
-#else
-	/* this is hacky, but it's only for Gtk 2.0.0... */
-	count = g_list_length(GTK_NOTEBOOK(notebook)->children);
-#endif
 
 	for (i = 0; i < count; i++) {
 
@@ -8226,9 +8201,7 @@
 		}
 		gtk_rc_parse_string(str->str);
 		g_string_free(str, TRUE);
-#if GTK_CHECK_VERSION(2,4,0)
 		gtk_rc_reset_styles(settings);
-#endif
 	}
 }
 
@@ -8475,16 +8448,6 @@
 	return FALSE;
 }
 
-#if !GTK_CHECK_VERSION(2,6,0)
-/* Courtesy of Galeon! */
-static void
-tab_close_button_state_changed_cb(GtkWidget *widget, GtkStateType prev_state)
-{
-	if (GTK_WIDGET_STATE(widget) == GTK_STATE_ACTIVE)
-		gtk_widget_set_state(widget, GTK_STATE_NORMAL);
-}
-#endif
-
 static void
 notebook_init_grab(PidginWindow *gtkwin, GtkWidget *widget)
 {
@@ -9126,9 +9089,7 @@
 	entry = gtk_entry_new();
 	gtk_entry_set_has_frame(GTK_ENTRY(entry), FALSE);
 	gtk_entry_set_width_chars(GTK_ENTRY(entry), 10);
-#if GTK_CHECK_VERSION(2,4,0)
 	gtk_entry_set_alignment(GTK_ENTRY(entry), 0.5);
-#endif
 
 	gtk_box_pack_start(GTK_BOX(gtkconv->infopane_hbox), entry, TRUE, TRUE, 0);
 	/* after the tab label */
@@ -9327,9 +9288,7 @@
 	GtkPositionType pos;
 	GtkWidget *testidea;
 	GtkWidget *menubar;
-#if GTK_CHECK_VERSION(2,6,0)
 	GdkModifierType state;
-#endif
 
 	win = g_malloc0(sizeof(PidginWindow));
 
@@ -9337,10 +9296,9 @@
 
 	/* Create the window. */
 	win->window = pidgin_create_window(NULL, 0, "conversation", TRUE);
-#if GTK_CHECK_VERSION(2,6,0)
 	if (!gtk_get_current_event_state(&state))
 		gtk_window_set_focus_on_map(GTK_WINDOW(win->window), FALSE);
-#endif
+
 	/* Etan: I really think this entire function call should happen only
 	 * when we are on Windows but I was informed that back before we used
 	 * to save the window position we stored the window size, so I'm
@@ -9483,32 +9441,6 @@
 }
 
 static gboolean
-close_button_left_cb(GtkWidget *widget, GdkEventCrossing *event, GtkLabel *label)
-{
-	static GdkCursor *ptr = NULL;
-	if (ptr == NULL) {
-		ptr = gdk_cursor_new(GDK_LEFT_PTR);
-	}
-
-	gtk_label_set_markup(label, "×");
-	gdk_window_set_cursor(event->window, ptr);
-	return FALSE;
-}
-
-static gboolean
-close_button_entered_cb(GtkWidget *widget, GdkEventCrossing *event, GtkLabel *label)
-{
-	static GdkCursor *hand = NULL;
-	if (hand == NULL) {
-		hand = gdk_cursor_new(GDK_HAND2);
-	}
-
-	gtk_label_set_markup(label, "<u>×</u>");
-	gdk_window_set_cursor(event->window, hand);
-	return FALSE;
-}
-
-static gboolean
 gtkconv_tab_set_tip(GtkWidget *widget, GdkEventCrossing *event, PidginConversation *gtkconv)
 {
 #if GTK_CHECK_VERSION(2, 12, 0)
@@ -9532,7 +9464,6 @@
 	PurpleConversation *conv = gtkconv->active_conv;
 	PidginConversation *focus_gtkconv;
 	GtkWidget *tab_cont = gtkconv->tab_cont;
-	GtkWidget *close_image;
 	PurpleConversationType conv_type;
 	const gchar *tmp_lab;
 
@@ -9546,32 +9477,13 @@
 
 
 	/* Close button. */
-	gtkconv->close = gtk_event_box_new();
-#if GTK_CHECK_VERSION(2,4,0)
-	gtk_event_box_set_visible_window(GTK_EVENT_BOX(gtkconv->close), FALSE);
-#endif
-	gtk_widget_set_events(gtkconv->close, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
-	close_image = gtk_label_new("×");
-	g_signal_connect(G_OBJECT(gtkconv->close), "enter-notify-event", G_CALLBACK(close_button_entered_cb), close_image);
-	g_signal_connect(G_OBJECT(gtkconv->close), "leave-notify-event", G_CALLBACK(close_button_left_cb), close_image);
-	gtk_widget_show(close_image);
-	gtk_container_add(GTK_CONTAINER(gtkconv->close), close_image);
+	gtkconv->close = create_close_button();
 	gtk_tooltips_set_tip(gtkconv->tooltips, gtkconv->close,
 	                     _("Close conversation"), NULL);
 
 	g_signal_connect(G_OBJECT(gtkconv->close), "button-press-event",
 			 G_CALLBACK(close_conv_cb), gtkconv);
 
-#if !GTK_CHECK_VERSION(2,6,0)
-	/*
-	* I love Galeon. They have a fix for that stupid annoying visible
-	* border bug. I love you guys! -- ChipX86
-	*/
-	/* This is fixed properly in some version of Gtk before 2.6.0  */
-	g_signal_connect(G_OBJECT(gtkconv->close), "state_changed",
-	                 G_CALLBACK(tab_close_button_state_changed_cb), NULL);
-#endif
-
 	/* Status icon. */
 	gtkconv->icon = gtk_image_new();
 	gtkconv->menu_icon = gtk_image_new();
@@ -9640,7 +9552,6 @@
 	else if (purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/tab_side") == (GTK_POS_RIGHT|8))
 		angle = 270;
 
-#if GTK_CHECK_VERSION(2,6,0)
 	if (!angle) {
 		g_object_set(G_OBJECT(gtkconv->tab_label), "ellipsize", PANGO_ELLIPSIZE_END,  NULL);
 		gtk_label_set_width_chars(GTK_LABEL(gtkconv->tab_label), 4);
@@ -9657,7 +9568,6 @@
 	}
 
 	gtk_label_set_angle(GTK_LABEL(gtkconv->tab_label), angle);
-#endif
 
 #if 0
 	gtk_misc_set_alignment(GTK_MISC(gtkconv->tab_label), 0.00, 0.5);
@@ -9680,9 +9590,7 @@
 	}
 
 	ebox = gtk_event_box_new();
-#if GTK_CHECK_VERSION(2,4,0)
 	gtk_event_box_set_visible_window(GTK_EVENT_BOX(ebox), FALSE);
-#endif
 	gtk_container_add(GTK_CONTAINER(ebox), gtkconv->tabby);
 	g_signal_connect(G_OBJECT(ebox), "enter-notify-event",
 			G_CALLBACK(gtkconv_tab_set_tip), gtkconv);
--- a/pidgin/gtkconv.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkconv.h	Thu Feb 04 05:30:35 2010 +0000
@@ -177,6 +177,12 @@
 		int timer;
 		GList *current;
 	} attach;
+
+	/* Quick Find (since 2.7.0) */
+	struct {
+		GtkWidget *entry;
+		GtkWidget *container;
+	} quickfind;
 };
 
 /*@}*/
--- a/pidgin/gtkdebug.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkdebug.c	Thu Feb 04 05:30:35 2010 +0000
@@ -720,9 +720,7 @@
 		/* Setup our top button bar thingie. */
 		toolbar = gtk_toolbar_new();
 		gtk_toolbar_set_tooltips(GTK_TOOLBAR(toolbar), TRUE);
-#if GTK_CHECK_VERSION(2,4,0)
 		gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolbar), TRUE);
-#endif
 		g_signal_connect(G_OBJECT(toolbar), "button-press-event", G_CALLBACK(toolbar_context), win);
 
 		gtk_toolbar_set_style(GTK_TOOLBAR(toolbar),
--- a/pidgin/gtkdialogs.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkdialogs.c	Thu Feb 04 05:30:35 2010 +0000
@@ -46,8 +46,6 @@
 
 static GList *dialogwindows = NULL;
 
-static GtkWidget *about = NULL;
-
 struct _PidginGroupMergeObject {
 	PurpleGroup* parent;
 	char *new_name;
@@ -354,11 +352,9 @@
 	}
 }
 
-static void destroy_about(void)
+static void destroy_win(GtkWidget *button, GtkWidget *win)
 {
-	if (about != NULL)
-		gtk_widget_destroy(about);
-	about = NULL;
+	gtk_widget_destroy(win);
 }
 
 #if 0
@@ -401,130 +397,129 @@
 }
 #endif
 
-void pidgin_dialogs_about()
+/* Note: Frees 'string' */
+static GtkWidget *
+pidgin_build_help_dialog(const char *title, const char *role, GString *string)
 {
-	GtkWidget *vbox;
-	GtkWidget *logo;
-	GtkWidget *frame;
-	GtkWidget *text;
-	GtkWidget *button;
-	GtkTextIter iter;
-	GString *str;
-	AtkObject *obj;
-	char* filename, *tmp;
+	GtkWidget *win, *vbox, *frame, *logo, *imhtml, *button;
 	GdkPixbuf *pixbuf;
-	PidginBuddyList *buddylist;
-
-	if (about != NULL) {
-		gtk_window_present(GTK_WINDOW(about));
-		return;
-	}
+	GtkTextIter iter;
+	AtkObject *obj;
+	char *filename, *tmp;
 
-	tmp = g_strdup_printf(_("About %s"), PIDGIN_NAME);
-	about = pidgin_create_dialog(tmp, PIDGIN_HIG_BORDER, "about", TRUE);
-	g_free(tmp);
-	gtk_window_set_default_size(GTK_WINDOW(about), 340, 450);
-
-	vbox = pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(about), FALSE, PIDGIN_HIG_BORDER);
+	win = pidgin_create_dialog(title, PIDGIN_HIG_BORDER, role, TRUE);
+	vbox = pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(win), FALSE, PIDGIN_HIG_BORDER);
+	gtk_window_set_default_size(GTK_WINDOW(win), 450, 450);
 
 	/* Generate a logo with a version number */
-	logo = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-	gtk_widget_realize(logo);
 	filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "logo.png", NULL);
 	pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
 	g_free(filename);
+
 #if 0  /* Don't versionize the logo when the logo has the version in it */
 	pidgin_logo_versionize(&pixbuf, logo);
 #endif
-	gtk_widget_destroy(logo);
+
+	/* Insert the logo */
 	logo = gtk_image_new_from_pixbuf(pixbuf);
 	g_object_unref(G_OBJECT(pixbuf));
-	/* Insert the logo */
 	obj = gtk_widget_get_accessible(logo);
 	tmp = g_strconcat(PIDGIN_NAME, " " DISPLAY_VERSION, NULL);
 	atk_object_set_description(obj, tmp);
 	g_free(tmp);
 	gtk_box_pack_start(GTK_BOX(vbox), logo, FALSE, FALSE, 0);
 
-	frame = pidgin_create_imhtml(FALSE, &text, NULL, NULL);
-	gtk_imhtml_set_format_functions(GTK_IMHTML(text), GTK_IMHTML_ALL ^ GTK_IMHTML_SMILEY);
+	frame = pidgin_create_imhtml(FALSE, &imhtml, NULL, NULL);
+	gtk_imhtml_set_format_functions(GTK_IMHTML(imhtml), GTK_IMHTML_ALL ^ GTK_IMHTML_SMILEY);
 	gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
 
+	gtk_imhtml_append_text(GTK_IMHTML(imhtml), string->str, GTK_IMHTML_NO_SCROLL);
+	gtk_text_buffer_get_start_iter(gtk_text_view_get_buffer(GTK_TEXT_VIEW(imhtml)), &iter);
+	gtk_text_buffer_place_cursor(gtk_text_view_get_buffer(GTK_TEXT_VIEW(imhtml)), &iter);
+
+	button = pidgin_dialog_add_button(GTK_DIALOG(win), GTK_STOCK_CLOSE,
+	                G_CALLBACK(destroy_win), win);
+
+	GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
+	gtk_widget_grab_default(button);
+
+	gtk_widget_show_all(win);
+	gtk_window_present(GTK_WINDOW(win));
+
+	g_string_free(string, TRUE);
+
+	return win;
+}
+
+void pidgin_dialogs_about(void)
+{
+	GString *str;
+	char *tmp;
+	static GtkWidget *about = NULL;
+
+	if (about != NULL) {
+		gtk_window_present(GTK_WINDOW(about));
+		return;
+	}
+
 	str = g_string_sized_new(4096);
 
 	g_string_append_printf(str,
-		"<CENTER><FONT SIZE=\"4\"><B>%s %s</B></FONT></CENTER><BR>(libpurple %s)<BR>%s<BR><BR>", PIDGIN_NAME, DISPLAY_VERSION, purple_core_get_version(), REVISION);
+		"<CENTER><FONT SIZE=\"4\"><B>%s %s</B></FONT></CENTER> (libpurple %s)"
+		"<BR>%s<BR><BR>", PIDGIN_NAME, DISPLAY_VERSION,
+		purple_core_get_version(), REVISION);
+
+	g_string_append_printf(str,
+		_("%s is a messaging client based on libpurple which is capable of "
+		  "connecting to multiple messaging services at once.  %s is written "
+		  "in C using GTK+.  %s is released, and may be modified and "
+		  "redistributed,  under the terms of the GPL version 2 (or later).  "
+		  "A copy of the GPL is distributed with %s.  %s is copyrighted by "
+		  "its contributors, a list of whom is also distributed with %s.  "
+		  "There is no warranty for %s.<BR><BR>"), PIDGIN_NAME, PIDGIN_NAME,
+		PIDGIN_NAME, PIDGIN_NAME, PIDGIN_NAME, PIDGIN_NAME, PIDGIN_NAME);
+
+	g_string_append_printf(str,
+			_("<FONT SIZE=\"4\"><B>Helpful Resources</B></FONT><BR>\t<A "
+			  "HREF=\"%s\">Website</A><BR>\t<A HREF=\"%s\">Frequently Asked "
+			  "Questions</A><BR>\tIRC Channel: #pidgin on irc.freenode.net<BR>"
+			  "\tXMPP MUC: devel@conference.pidgin.im<BR><BR>"), PURPLE_WEBSITE,
+			"http://developer.pidgin.im/wiki/FAQ");
 
 	g_string_append_printf(str,
-		_("%s is a graphical modular messaging client based on "
-		  "libpurple which is capable of connecting to "
-		  "AIM, MSN, Yahoo!, XMPP, ICQ, IRC, SILC, SIP/SIMPLE, "
-		  "Novell GroupWise, Lotus Sametime, Bonjour, Zephyr, "
-		  "MySpaceIM, Gadu-Gadu, and QQ all at once.  "
-		  "It is written using GTK+.<BR><BR>"
-		  "You may modify and redistribute the program under "
-		  "the terms of the GPL (version 2 or later).  A copy of the GPL is "
-		  "contained in the 'COPYING' file distributed with %s.  "
-		  "%s is copyrighted by its contributors.  See the 'COPYRIGHT' "
-		  "file for the complete list of contributors.  We provide no "
-		  "warranty for this program.<BR><BR>"), PIDGIN_NAME, PIDGIN_NAME, PIDGIN_NAME);
+			_("<font size=\"4\"><b>Help from other Pidgin users</b></font> is "
+			  "available by e-mailing <a "
+			  "href=\"mailto:support@pidgin.im\">support@pidgin.im</a><br/>"
+			  "This is a <b>public</b> mailing list! "
+			  "(<a href=\"http://pidgin.im/pipermail/support/\">archive</a>)<br/>"
+			  "We can't help with third-party protocols or plugins!<br/>"
+			  "This list's primary language is <b>English</b>.  You are "
+			  "welcome to post in another language, but the responses may "
+			  "be less helpful.<br/>"));
 
-	g_string_append(str, "<FONT SIZE=\"4\">URL:</FONT> <A HREF=\""
-				PURPLE_WEBSITE "\">" PURPLE_WEBSITE "</A><BR/><BR/>");
-	g_string_append_printf(str, _("<FONT SIZE=\"4\">FAQ:</FONT> <A HREF=\""
-				"http://developer.pidgin.im/wiki/FAQ\">"
-				"http://developer.pidgin.im/wiki/FAQ</A><BR/><BR/>"));
-	g_string_append_printf(str,
-			_("<font size=\"4\">Help from other Pidgin users:</font> "
-			"<a href=\"mailto:support@pidgin.im\">support@pidgin.im</a><br/>"
-			"This is a <b>public</b> mailing list! "
-			"(<a href=\"http://pidgin.im/pipermail/support/\">archive</a>)<br/>"
-			"We can't help with 3rd party protocols or plugins!<br/>"
-			"This list's primary language is <b>English</b>.  You are "
-			"welcome to post in another language, but the responses may "
-			"be less helpful.<br/><br/>"));
-	g_string_append_printf(str, _("<FONT SIZE=\"4\">IRC Channel:</FONT> "
-				"#pidgin on irc.freenode.net<BR><BR>"));
-	g_string_append_printf(str, _("<FONT SIZE=\"4\">XMPP MUC:</FONT> "
-				"devel@conference.pidgin.im<BR><BR>"));
+	tmp = g_strdup_printf(_("About %s"), PIDGIN_NAME);
+	about = pidgin_build_help_dialog(tmp, "about", str);
+	g_signal_connect(G_OBJECT(about), "destroy", G_CALLBACK(gtk_widget_destroyed), &about);
+	g_free(tmp);
+}
 
-	/* Current Developers */
-	g_string_append_printf(str, "<FONT SIZE=\"4\">%s:</FONT><BR/>",
-						   _("Current Developers"));
-	add_developers(str, developers);
-	g_string_append(str, "<BR/>");
-
-	/* Crazy Patch Writers */
-	g_string_append_printf(str, "<FONT SIZE=\"4\">%s:</FONT><BR/>",
-						   _("Crazy Patch Writers"));
-	add_developers(str, patch_writers);
-	g_string_append(str, "<BR/>");
-
-	/* Retired Developers */
-	g_string_append_printf(str, "<FONT SIZE=\"4\">%s:</FONT><BR/>",
-						   _("Retired Developers"));
-	add_developers(str, retired_developers);
-	g_string_append(str, "<BR/>");
+void pidgin_dialogs_buildinfo(void)
+{
+	GString *str;
+	char *tmp;
+	static GtkWidget *buildinfo = NULL;
 
-	/* Retired Crazy Patch Writers */
-	g_string_append_printf(str, "<FONT SIZE=\"4\">%s:</FONT><BR/>",
-						   _("Retired Crazy Patch Writers"));
-	add_developers(str, retired_patch_writers);
-	g_string_append(str, "<BR/>");
+	if (buildinfo != NULL) {
+		gtk_window_present(GTK_WINDOW(buildinfo));
+		return;
+	}
 
-	/* Current Translators */
-	g_string_append_printf(str, "<FONT SIZE=\"4\">%s:</FONT><BR/>",
-						   _("Current Translators"));
-	add_translators(str, translators);
-	g_string_append(str, "<BR/>");
+	str = g_string_sized_new(4096);
 
-	/* Past Translators */
-	g_string_append_printf(str, "<FONT SIZE=\"4\">%s:</FONT><BR/>",
-						   _("Past Translators"));
-	add_translators(str, past_translators);
-	g_string_append(str, "<BR/>");
+	g_string_append_printf(str,
+		"<FONT SIZE=\"4\"><B>%s %s</B></FONT> (libpurple %s)<BR>%s<BR><BR>", PIDGIN_NAME, DISPLAY_VERSION, purple_core_get_version(), REVISION);
 
-	g_string_append_printf(str, "<FONT SIZE=\"4\">%s</FONT><br/>", _("Debugging Information"));
+	g_string_append_printf(str, "<FONT SIZE=\"4\"><B>%s</B></FONT><br/>", _("Build Information"));
 
 	/* The following primarly intented for user/developer interaction and thus
 	   ought not be translated */
@@ -701,31 +696,82 @@
 
 	/* End of not to be translated section */
 
-	gtk_imhtml_append_text(GTK_IMHTML(text), str->str, GTK_IMHTML_NO_SCROLL);
-	g_string_free(str, TRUE);
+	tmp = g_strdup_printf(_("%s Build Information"), PIDGIN_NAME);
+	buildinfo = pidgin_build_help_dialog(tmp, "buildinfo", str);
+	g_signal_connect(G_OBJECT(buildinfo), "destroy", G_CALLBACK(gtk_widget_destroyed), &buildinfo);
+	g_free(tmp);
+}
 
-	gtk_text_buffer_get_start_iter(gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), &iter);
-	gtk_text_buffer_place_cursor(gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), &iter);
+void pidgin_dialogs_developers(void)
+{
+	GString *str;
+	char *tmp;
+	static GtkWidget *developer_info = NULL;
+
+	if (developer_info != NULL) {
+		gtk_window_present(GTK_WINDOW(developer_info));
+		return;
+	}
 
-	/* Close Button */
-	button = pidgin_dialog_add_button(GTK_DIALOG(about), GTK_STOCK_CLOSE,
-	                G_CALLBACK(destroy_about), about);
+	str = g_string_sized_new(4096);
+
+	/* Current Developers */
+	g_string_append_printf(str, "<FONT SIZE=\"4\"><B>%s:</B></FONT><BR/>",
+						   _("Current Developers"));
+	add_developers(str, developers);
+	g_string_append(str, "<BR/>");
 
-	g_signal_connect(G_OBJECT(about), "destroy",
-					 G_CALLBACK(destroy_about), G_OBJECT(about));
+	/* Crazy Patch Writers */
+	g_string_append_printf(str, "<FONT SIZE=\"4\"><B>%s:</B></FONT><BR/>",
+						   _("Crazy Patch Writers"));
+	add_developers(str, patch_writers);
+	g_string_append(str, "<BR/>");
+
+	/* Retired Developers */
+	g_string_append_printf(str, "<FONT SIZE=\"4\"><B>%s:</B></FONT><BR/>",
+						   _("Retired Developers"));
+	add_developers(str, retired_developers);
+	g_string_append(str, "<BR/>");
 
-	/* this makes the sizes not work? */
-	GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
-	gtk_widget_grab_default(button);
+	/* Retired Crazy Patch Writers */
+	g_string_append_printf(str, "<FONT SIZE=\"4\"><B>%s:</B></FONT><BR/>",
+						   _("Retired Crazy Patch Writers"));
+	add_developers(str, retired_patch_writers);
+
+	tmp = g_strdup_printf(_("%s Developer Information"), PIDGIN_NAME);
+	developer_info = pidgin_build_help_dialog(tmp, "developer_info", str);
+	g_signal_connect(G_OBJECT(developer_info), "destroy", G_CALLBACK(gtk_widget_destroyed), &developer_info);
+	g_free(tmp);
+}
+
+void pidgin_dialogs_translators(void)
+{
+	GString *str;
+	char *tmp;
+	static GtkWidget *translator_info = NULL;
 
-	/* Let's give'em something to talk about -- woah woah woah */
-	buddylist = pidgin_blist_get_default_gtk_blist();
-	if (buddylist)
-		gtk_window_set_transient_for(GTK_WINDOW(about),
-				GTK_WINDOW(buddylist->window));
+	if (translator_info != NULL) {
+		gtk_window_present(GTK_WINDOW(translator_info));
+		return;
+	}
+
+	str = g_string_sized_new(4096);
 
-	gtk_widget_show_all(about);
-	gtk_window_present(GTK_WINDOW(about));
+	/* Current Translators */
+	g_string_append_printf(str, "<FONT SIZE=\"4\">%s:</FONT><BR/>",
+						   _("Current Translators"));
+	add_translators(str, translators);
+	g_string_append(str, "<BR/>");
+
+	/* Past Translators */
+	g_string_append_printf(str, "<FONT SIZE=\"4\">%s:</FONT><BR/>",
+						   _("Past Translators"));
+	add_translators(str, past_translators);
+
+	tmp = g_strdup_printf(_("%s Translator Information"), PIDGIN_NAME);
+	translator_info = pidgin_build_help_dialog(tmp, "translator_info", str);
+	g_signal_connect(G_OBJECT(translator_info), "destroy", G_CALLBACK(gtk_widget_destroyed), &translator_info);
+	g_free(tmp);
 }
 
 static void
--- a/pidgin/gtkdialogs.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkdialogs.h	Thu Feb 04 05:30:35 2010 +0000
@@ -33,6 +33,9 @@
 /* Functions in gtkdialogs.c (these should actually stay in this file) */
 void pidgin_dialogs_destroy_all(void);
 void pidgin_dialogs_about(void);
+void pidgin_dialogs_buildinfo(void);
+void pidgin_dialogs_developers(void);
+void pidgin_dialogs_translators(void);
 void pidgin_dialogs_im(void);
 void pidgin_dialogs_im_with_user(PurpleAccount *, const char *);
 void pidgin_dialogs_info(void);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/gtkdocklet-gtk.c	Thu Feb 04 05:30:35 2010 +0000
@@ -0,0 +1,164 @@
+/*
+ * System tray icon (aka docklet) plugin for Purple
+ *
+ * Copyright (C) 2007 Anders Hasselqvist
+ * 
+ * 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., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "internal.h"
+#include "pidgin.h"
+#include "debug.h"
+#include "prefs.h"
+#include "pidginstock.h"
+#include "gtkdocklet.h"
+
+#if GTK_CHECK_VERSION(2,10,0)
+
+/* globals */
+GtkStatusIcon *docklet = NULL;
+
+static void
+docklet_gtk_status_activated_cb(GtkStatusIcon *status_icon, gpointer user_data)
+{
+	purple_debug_info("docklet", "button clicked %d\n", 1);
+
+	pidgin_docklet_clicked(1); 
+}
+
+static void
+docklet_gtk_status_clicked_cb(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data)
+{
+	purple_debug_info("docklet", "button clicked %d\n", button);
+
+	pidgin_docklet_clicked(button); 
+}
+
+static void
+docklet_gtk_status_update_icon(PurpleStatusPrimitive status, gboolean connecting, gboolean pending)
+{
+	const gchar *icon_name = NULL;
+
+	switch (status) {
+		case PURPLE_STATUS_OFFLINE:
+			icon_name = PIDGIN_STOCK_TRAY_OFFLINE;
+			break;
+		case PURPLE_STATUS_AWAY:
+			icon_name = PIDGIN_STOCK_TRAY_AWAY;
+			break;
+		case PURPLE_STATUS_UNAVAILABLE:
+			icon_name = PIDGIN_STOCK_TRAY_BUSY;
+			break;
+		case PURPLE_STATUS_EXTENDED_AWAY:
+			icon_name = PIDGIN_STOCK_TRAY_XA;
+			break;
+		case PURPLE_STATUS_INVISIBLE:
+			icon_name = PIDGIN_STOCK_TRAY_INVISIBLE;
+			break;
+		default:
+			icon_name = PIDGIN_STOCK_TRAY_AVAILABLE;
+			break;
+	}
+
+	if (pending)
+		icon_name = PIDGIN_STOCK_TRAY_PENDING;
+	if (connecting)
+		icon_name = PIDGIN_STOCK_TRAY_CONNECT;
+
+	if (icon_name) {
+		gtk_status_icon_set_from_icon_name(docklet, icon_name);
+	}
+}
+
+static void
+docklet_gtk_status_set_tooltip(gchar *tooltip)
+{
+	if (tooltip) {
+		gtk_status_icon_set_tooltip(docklet, tooltip);
+	} else {
+		gtk_status_icon_set_tooltip(docklet, NULL);
+	}
+}
+
+static void
+docklet_gtk_status_position_menu(GtkMenu *menu,
+                                 int *x, int *y, gboolean *push_in,
+                                 gpointer user_data)
+{
+	gtk_status_icon_position_menu(menu, x, y, push_in, docklet);
+}
+
+static void
+docklet_gtk_status_destroy(void)
+{
+	g_return_if_fail(docklet != NULL);
+
+	pidgin_docklet_remove();
+	
+	g_object_unref(G_OBJECT(docklet));
+	docklet = NULL;
+
+	purple_debug_info("docklet", "destroyed\n");
+}
+
+static void
+docklet_gtk_status_create(gboolean recreate)
+{
+	if (docklet) {
+		/* if this is being called when a tray icon exists, it's because
+		   something messed up. try destroying it before we proceed,
+		   although docklet_refcount may be all hosed. hopefully won't happen. */
+		purple_debug_warning("docklet", "trying to create icon but it already exists?\n");
+		docklet_gtk_status_destroy();
+	}
+
+	docklet = gtk_status_icon_new();
+	g_return_if_fail(docklet != NULL);
+
+	g_signal_connect(G_OBJECT(docklet), "activate", G_CALLBACK(docklet_gtk_status_activated_cb), NULL);
+	g_signal_connect(G_OBJECT(docklet), "popup-menu", G_CALLBACK(docklet_gtk_status_clicked_cb), NULL);
+
+	pidgin_docklet_embedded();
+	gtk_status_icon_set_visible(docklet, TRUE);
+	purple_debug_info("docklet", "created\n");
+}
+
+static void
+docklet_gtk_status_create_ui_op(void)
+{
+	docklet_gtk_status_create(FALSE);
+}
+
+static struct docklet_ui_ops ui_ops =
+{
+	docklet_gtk_status_create_ui_op,
+	docklet_gtk_status_destroy,
+	docklet_gtk_status_update_icon,
+	NULL,
+	docklet_gtk_status_set_tooltip,
+	docklet_gtk_status_position_menu
+};
+
+void
+docklet_ui_init(void)
+{
+	pidgin_docklet_set_ui_ops(&ui_ops);
+	gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(),
+		DATADIR G_DIR_SEPARATOR_S "pixmaps" G_DIR_SEPARATOR_S "pidgin" G_DIR_SEPARATOR_S "tray");
+}
+
+#endif  /* GTK_CHECK_VERSION(2,10,0) */
+
--- a/pidgin/gtkdocklet-x11.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkdocklet-x11.c	Thu Feb 04 05:30:35 2010 +0000
@@ -34,6 +34,8 @@
 #include "gtkdocklet.h"
 #include <gdk/gdkkeysyms.h>
 
+#if !GTK_CHECK_VERSION(2,10,0)
+
 #define SHORT_EMBED_TIMEOUT 5000
 #define LONG_EMBED_TIMEOUT 15000
 
@@ -205,7 +207,6 @@
 	}
 }
 
-#if GTK_CHECK_VERSION(2,2,0)
 static void
 docklet_x11_position_menu(GtkMenu *menu, int *x, int *y, gboolean *push_in,
 						  gpointer user_data)
@@ -230,7 +231,6 @@
 
 	*push_in = TRUE;
 }
-#endif
 
 static void
 docklet_x11_destroy(void)
@@ -344,11 +344,7 @@
 	docklet_x11_update_icon,
 	docklet_x11_blank_icon,
 	docklet_x11_set_tooltip,
-#if GTK_CHECK_VERSION(2,2,0)
 	docklet_x11_position_menu
-#else
-	NULL
-#endif
 };
 
 void
@@ -358,3 +354,6 @@
 	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/docklet/x11");
 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/docklet/x11/embedded", FALSE);
 }
+
+#endif  /* !GTK_CHECK_VERSION(2,10,0) */
+
--- a/pidgin/gtkdocklet.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkdocklet.h	Thu Feb 04 05:30:35 2010 +0000
@@ -49,7 +49,7 @@
 void pidgin_docklet_uninit(void);
 void*pidgin_docklet_get_handle(void);
 
-/* function in gtkdocklet-{x11,win32}.c */
+/* function in gtkdocklet-{gtk,x11,win32}.c */
 void docklet_ui_init(void);
 
 #endif /* _GTKDOCKLET_H_ */
--- a/pidgin/gtkexpander.c	Thu Feb 04 02:18:37 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1659 +0,0 @@
-/* GTK - The GIMP Toolkit
- *
- * Copyright (C) 2003 Sun Microsystems, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02111-1301, USA.
- *
- * Authors:
- *	Mark McLoughlin <mark@skynet.ie>
- */
-
-/*
-#include <config.h>
-*/
-
-#include <gtk/gtkversion.h>
-#if !GTK_CHECK_VERSION(2,4,0)
-#include "gtkexpander.h"
-
-#include <gtk/gtklabel.h>
-#include <gtk/gtkcontainer.h>
-#include <gtk/gtkmarshal.h>
-#include <gtk/gtkmain.h>
-#include <gtk/gtkprivate.h>
-#include <gdk/gdkkeysyms.h>
-
-#define P_(x) (x)
-
-#define DEFAULT_EXPANDER_SIZE 10
-#define DEFAULT_EXPANDER_SPACING 2
-
-enum
-{
-  PROP_0,
-  PROP_EXPANDED,
-  PROP_LABEL,
-  PROP_USE_UNDERLINE,
-  PROP_USE_MARKUP,
-  PROP_SPACING,
-  PROP_LABEL_WIDGET
-};
-
-struct _GtkExpanderPrivate
-{
-  GtkWidget        *label_widget;
-  GdkWindow        *event_window;
-  gint              spacing;
-
-  GtkExpanderStyle  expander_style;
-  guint             animation_timeout;
-
-  guint             expanded : 1;
-  guint             use_underline : 1;
-  guint             use_markup : 1;
-  guint             button_down : 1;
-  guint             prelight : 1;
-};
-
-static void gtk_expander_class_init (GtkExpanderClass *klass);
-static void gtk_expander_init       (GtkExpander      *expander);
-
-static void gtk_expander_set_property (GObject          *object,
-				       guint             prop_id,
-				       const GValue     *value,
-				       GParamSpec       *pspec);
-static void gtk_expander_get_property (GObject          *object,
-				       guint             prop_id,
-				       GValue           *value,
-				       GParamSpec       *pspec);
-
-static void gtk_expander_finalize (GObject *object);
-
-static void gtk_expander_destroy (GtkObject *object);
-
-static void     gtk_expander_realize        (GtkWidget        *widget);
-static void     gtk_expander_unrealize      (GtkWidget        *widget);
-static void     gtk_expander_size_request   (GtkWidget        *widget,
-					     GtkRequisition   *requisition);
-static void     gtk_expander_size_allocate  (GtkWidget        *widget,
-					     GtkAllocation    *allocation);
-static void     gtk_expander_map            (GtkWidget        *widget);
-static void     gtk_expander_unmap          (GtkWidget        *widget);
-static gboolean gtk_expander_expose         (GtkWidget        *widget,
-					     GdkEventExpose   *event);
-static gboolean gtk_expander_button_press   (GtkWidget        *widget,
-					     GdkEventButton   *event);
-static gboolean gtk_expander_button_release (GtkWidget        *widget,
-					     GdkEventButton   *event);
-static gboolean gtk_expander_enter_notify   (GtkWidget        *widget,
-					     GdkEventCrossing *event);
-static gboolean gtk_expander_leave_notify   (GtkWidget        *widget,
-					     GdkEventCrossing *event);
-static gboolean gtk_expander_focus          (GtkWidget        *widget,
-					     GtkDirectionType  direction);
-static void     gtk_expander_grab_notify    (GtkWidget        *widget,
-					     gboolean          was_grabbed);
-static void     gtk_expander_state_changed  (GtkWidget        *widget,
-					     GtkStateType      previous_state);
-
-static void gtk_expander_add    (GtkContainer *container,
-				 GtkWidget    *widget);
-static void gtk_expander_remove (GtkContainer *container,
-				 GtkWidget    *widget);
-static void gtk_expander_forall (GtkContainer *container,
-				 gboolean        include_internals,
-				 GtkCallback     callback,
-				 gpointer        callback_data);
-
-static void gtk_expander_activate (GtkExpander *expander);
-
-static void get_expander_bounds (GtkExpander  *expander,
-				 GdkRectangle *rect);
-
-static GtkBinClass *parent_class = NULL;
-
-GType
-gtk_expander_get_type (void)
-{
-  static GType expander_type = 0;
-
-  if (!expander_type)
-    {
-      static const GTypeInfo expander_info =
-      {
-	sizeof (GtkExpanderClass),
-	NULL,		/* base_init */
-	NULL,		/* base_finalize */
-	(GClassInitFunc) gtk_expander_class_init,
-	NULL,		/* class_finalize */
-	NULL,		/* class_data */
-	sizeof (GtkExpander),
-	0,		/* n_preallocs */
-	(GInstanceInitFunc) gtk_expander_init,
-      };
-
-      expander_type = g_type_register_static (GTK_TYPE_BIN,
-					      "GtkExpander",
-					      &expander_info, 0);
-    }
-
-  return expander_type;
-}
-
-static void
-gtk_expander_class_init (GtkExpanderClass *klass)
-{
-  GObjectClass *gobject_class;
-  GtkObjectClass *object_class;
-  GtkWidgetClass *widget_class;
-  GtkContainerClass *container_class;
-
-  parent_class = g_type_class_peek_parent (klass);
-
-  gobject_class   = (GObjectClass *) klass;
-  object_class    = (GtkObjectClass *) klass;
-  widget_class    = (GtkWidgetClass *) klass;
-  container_class = (GtkContainerClass *) klass;
-
-  gobject_class->set_property = gtk_expander_set_property;
-  gobject_class->get_property = gtk_expander_get_property;
-  gobject_class->finalize     = gtk_expander_finalize;
-
-  object_class->destroy = gtk_expander_destroy;
-
-  widget_class->realize              = gtk_expander_realize;
-  widget_class->unrealize            = gtk_expander_unrealize;
-  widget_class->size_request         = gtk_expander_size_request;
-  widget_class->size_allocate        = gtk_expander_size_allocate;
-  widget_class->map                  = gtk_expander_map;
-  widget_class->unmap                = gtk_expander_unmap;
-  widget_class->expose_event         = gtk_expander_expose;
-  widget_class->button_press_event   = gtk_expander_button_press;
-  widget_class->button_release_event = gtk_expander_button_release;
-  widget_class->enter_notify_event   = gtk_expander_enter_notify;
-  widget_class->leave_notify_event   = gtk_expander_leave_notify;
-  widget_class->focus                = gtk_expander_focus;
-  widget_class->grab_notify          = gtk_expander_grab_notify;
-  widget_class->state_changed        = gtk_expander_state_changed;
-
-  container_class->add    = gtk_expander_add;
-  container_class->remove = gtk_expander_remove;
-  container_class->forall = gtk_expander_forall;
-
-  klass->activate = gtk_expander_activate;
-
-  g_object_class_install_property (gobject_class,
-				   PROP_EXPANDED,
-				   g_param_spec_boolean ("expanded",
-							 P_("Expanded"),
-							 P_("Whether the expander has been opened to reveal the child widget"),
-							 FALSE,
-							 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-
-  g_object_class_install_property (gobject_class,
-				   PROP_LABEL,
-				   g_param_spec_string ("label",
-							P_("Label"),
-							P_("Text of the expander's label"),
-							NULL,
-							G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-
-  g_object_class_install_property (gobject_class,
-				   PROP_USE_UNDERLINE,
-				   g_param_spec_boolean ("use_underline",
-							 P_("Use underline"),
-							 P_("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
-							 FALSE,
-							 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-
-  g_object_class_install_property (gobject_class,
-				   PROP_USE_MARKUP,
-				   g_param_spec_boolean ("use_markup",
-							 P_("Use markup"),
-							 P_("The text of the label includes XML markup. See pango_parse_markup()"),
-							 FALSE,
-							 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-
-  g_object_class_install_property (gobject_class,
-				   PROP_SPACING,
-				   g_param_spec_int ("spacing",
-						     P_("Spacing"),
-						     P_("Space to put between the label and the child"),
-						     0,
-						     G_MAXINT,
-						     0,
-						     G_PARAM_READWRITE));
-
-  g_object_class_install_property (gobject_class,
-				   PROP_LABEL_WIDGET,
-				   g_param_spec_object ("label_widget",
-							P_("Label widget"),
-							P_("A widget to display in place of the usual expander label"),
-							GTK_TYPE_WIDGET,
-							G_PARAM_READWRITE));
-
-  gtk_widget_class_install_style_property (widget_class,
-					   g_param_spec_int ("expander-size",
-							     P_("Expander Size"),
-							     P_("Size of the expander arrow"),
-							     0,
-							     G_MAXINT,
-							     DEFAULT_EXPANDER_SIZE,
-							     G_PARAM_READABLE));
-
-  gtk_widget_class_install_style_property (widget_class,
-					   g_param_spec_int ("expander-spacing",
-							     P_("Indicator Spacing"),
-							     P_("Spacing around expander arrow"),
-							     0,
-							     G_MAXINT,
-							     DEFAULT_EXPANDER_SPACING,
-							     G_PARAM_READABLE));
-
-  widget_class->activate_signal =
-    g_signal_new ("activate",
-		  G_TYPE_FROM_CLASS (gobject_class),
-		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-		  G_STRUCT_OFFSET (GtkExpanderClass, activate),
-		  NULL, NULL,
-		  gtk_marshal_VOID__VOID,
-		  G_TYPE_NONE, 0);
-}
-
-static void
-gtk_expander_finalize (GObject *obj)
-{
-	GtkExpander *self = (GtkExpander *)obj;
-
-	g_free(self->priv);
-
-	G_OBJECT_CLASS(parent_class)->finalize (obj);
-}
-
-static void
-gtk_expander_init (GtkExpander *expander)
-{
-  GtkExpanderPrivate *priv;
-
-  expander->priv = priv = g_new0(GtkExpanderPrivate, 1);
-
-  GTK_WIDGET_SET_FLAGS (expander, GTK_CAN_FOCUS);
-  GTK_WIDGET_SET_FLAGS (expander, GTK_NO_WINDOW);
-
-  priv->label_widget = NULL;
-  priv->event_window = NULL;
-  priv->spacing = 0;
-
-  priv->expander_style = GTK_EXPANDER_COLLAPSED;
-  priv->animation_timeout = 0;
-
-  priv->expanded = FALSE;
-  priv->use_underline = FALSE;
-  priv->use_markup = FALSE;
-  priv->button_down = FALSE;
-  priv->prelight = FALSE;
-}
-
-static void
-gtk_expander_set_property (GObject      *object,
-			   guint         prop_id,
-			   const GValue *value,
-			   GParamSpec   *pspec)
-{
-  GtkExpander *expander = GTK_EXPANDER (object);
-
-  switch (prop_id)
-    {
-    case PROP_EXPANDED:
-      gtk_expander_set_expanded (expander, g_value_get_boolean (value));
-      break;
-    case PROP_LABEL:
-      gtk_expander_set_label (expander, g_value_get_string (value));
-      break;
-    case PROP_USE_UNDERLINE:
-      gtk_expander_set_use_underline (expander, g_value_get_boolean (value));
-      break;
-    case PROP_USE_MARKUP:
-      gtk_expander_set_use_markup (expander, g_value_get_boolean (value));
-      break;
-    case PROP_SPACING:
-      gtk_expander_set_spacing (expander, g_value_get_int (value));
-      break;
-    case PROP_LABEL_WIDGET:
-      gtk_expander_set_label_widget (expander, g_value_get_object (value));
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-gtk_expander_get_property (GObject    *object,
-			   guint       prop_id,
-			   GValue     *value,
-			   GParamSpec *pspec)
-{
-  GtkExpander *expander = GTK_EXPANDER (object);
-  GtkExpanderPrivate *priv = expander->priv;
-
-  switch (prop_id)
-    {
-    case PROP_EXPANDED:
-      g_value_set_boolean (value, priv->expanded);
-      break;
-    case PROP_LABEL:
-      g_value_set_string (value, gtk_expander_get_label (expander));
-      break;
-    case PROP_USE_UNDERLINE:
-      g_value_set_boolean (value, priv->use_underline);
-      break;
-    case PROP_USE_MARKUP:
-      g_value_set_boolean (value, priv->use_markup);
-      break;
-    case PROP_SPACING:
-      g_value_set_int (value, priv->spacing);
-      break;
-    case PROP_LABEL_WIDGET:
-      g_value_set_object (value,
-			  priv->label_widget ?
-			  G_OBJECT (priv->label_widget) : NULL);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-gtk_expander_destroy (GtkObject *object)
-{
-  GtkExpanderPrivate *priv = GTK_EXPANDER (object)->priv;
-
-  if (priv->animation_timeout)
-    {
-      g_source_remove (priv->animation_timeout);
-      priv->animation_timeout = 0;
-    }
-
-  GTK_OBJECT_CLASS (parent_class)->destroy (object);
-}
-
-static void
-gtk_expander_realize (GtkWidget *widget)
-{
-  GtkExpanderPrivate *priv;
-  GdkWindowAttr attributes;
-  gint attributes_mask;
-  gint border_width;
-  GdkRectangle expander_rect;
-
-  priv = GTK_EXPANDER (widget)->priv;
-  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
-
-  border_width = GTK_CONTAINER (widget)->border_width;
-
-  get_expander_bounds (GTK_EXPANDER (widget), &expander_rect);
-
-  attributes.window_type = GDK_WINDOW_CHILD;
-  attributes.x = widget->allocation.x + border_width;
-  attributes.y = expander_rect.y;
-  attributes.width = MAX (widget->allocation.width - 2 * border_width, 1);
-  attributes.height = expander_rect.width;
-  attributes.wclass = GDK_INPUT_ONLY;
-  attributes.event_mask = gtk_widget_get_events (widget)     |
-				GDK_BUTTON_PRESS_MASK        |
-				GDK_BUTTON_RELEASE_MASK      |
-				GDK_ENTER_NOTIFY_MASK        |
-				GDK_LEAVE_NOTIFY_MASK;
-
-  attributes_mask = GDK_WA_X | GDK_WA_Y;
-
-  widget->window = gtk_widget_get_parent_window (widget);
-  g_object_ref (widget->window);
-
-  priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
-				       &attributes, attributes_mask);
-  gdk_window_set_user_data (priv->event_window, widget);
-
-  widget->style = gtk_style_attach (widget->style, widget->window);
-  gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
-}
-
-static void
-gtk_expander_unrealize (GtkWidget *widget)
-{
-  GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
-
-  if (priv->event_window)
-    {
-      gdk_window_set_user_data (priv->event_window, NULL);
-      gdk_window_destroy (priv->event_window);
-      priv->event_window = NULL;
-    }
-
-  GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
-}
-
-static void
-gtk_expander_size_request (GtkWidget      *widget,
-			   GtkRequisition *requisition)
-{
-  GtkExpander *expander;
-  GtkBin *bin;
-  GtkExpanderPrivate *priv;
-  gint border_width;
-  gint expander_size;
-  gint expander_spacing;
-  gboolean interior_focus;
-  gint focus_width;
-  gint focus_pad;
-
-  bin = GTK_BIN (widget);
-  expander = GTK_EXPANDER (widget);
-  priv = expander->priv;
-
-  border_width = GTK_CONTAINER (widget)->border_width;
-
-  gtk_widget_style_get (widget,
-			"interior-focus", &interior_focus,
-			"focus-line-width", &focus_width,
-			"focus-padding", &focus_pad,
-			"expander-size", &expander_size,
-			"expander-spacing", &expander_spacing,
-			NULL);
-
-  requisition->width = expander_size + 2 * expander_spacing +
-		       2 * focus_width + 2 * focus_pad;
-  requisition->height = interior_focus ? (2 * focus_width + 2 * focus_pad) : 0;
-
-  if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
-    {
-      GtkRequisition label_requisition;
-
-      gtk_widget_size_request (priv->label_widget, &label_requisition);
-
-      requisition->width  += label_requisition.width;
-      requisition->height += label_requisition.height;
-    }
-
-  requisition->height = MAX (expander_size + 2 * expander_spacing, requisition->height);
-
-  if (!interior_focus)
-    requisition->height += 2 * focus_width + 2 * focus_pad;
-
-  if (bin->child && GTK_WIDGET_CHILD_VISIBLE (bin->child))
-    {
-      GtkRequisition child_requisition;
-
-      gtk_widget_size_request (bin->child, &child_requisition);
-
-      requisition->width = MAX (requisition->width, child_requisition.width);
-      requisition->height += child_requisition.height + priv->spacing;
-    }
-
-  requisition->width  += 2 * border_width;
-  requisition->height += 2 * border_width;
-}
-
-static void
-get_expander_bounds (GtkExpander  *expander,
-		     GdkRectangle *rect)
-{
-  GtkWidget *widget;
-  GtkBin *bin;
-  GtkExpanderPrivate *priv;
-  gint border_width;
-  gint expander_size;
-  gint expander_spacing;
-  gboolean interior_focus;
-  gint focus_width;
-  gint focus_pad;
-  gboolean ltr;
-
-  widget = GTK_WIDGET (expander);
-  bin = GTK_BIN (expander);
-  priv = expander->priv;
-
-  border_width = GTK_CONTAINER (expander)->border_width;
-
-  gtk_widget_style_get (widget,
-			"interior-focus", &interior_focus,
-			"focus-line-width", &focus_width,
-			"focus-padding", &focus_pad,
-			"expander-size", &expander_size,
-			"expander-spacing", &expander_spacing,
-			NULL);
-
-  ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
-
-  rect->x = widget->allocation.x + border_width;
-  rect->y = widget->allocation.y + border_width;
-
-  if (ltr)
-    rect->x += expander_spacing;
-  else
-    rect->x += widget->allocation.width - 2 * border_width -
-               expander_spacing - expander_size;
-
-  if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
-    {
-      GtkAllocation label_allocation;
-
-      label_allocation = priv->label_widget->allocation;
-
-      if (expander_size < label_allocation.height)
-	rect->y += focus_width + focus_pad + (label_allocation.height - expander_size) / 2;
-      else
-	rect->y += expander_spacing;
-    }
-  else
-    {
-      rect->y += expander_spacing;
-    }
-
-  if (!interior_focus)
-    {
-      if (ltr)
-	rect->x += focus_width + focus_pad;
-      else
-	rect->x -= focus_width + focus_pad;
-      rect->y += focus_width + focus_pad;
-    }
-
-  rect->width = rect->height = expander_size;
-}
-
-static void
-gtk_expander_size_allocate (GtkWidget     *widget,
-			    GtkAllocation *allocation)
-{
-  GtkExpander *expander;
-  GtkBin *bin;
-  GtkExpanderPrivate *priv;
-  GtkRequisition child_requisition;
-  gboolean child_visible = FALSE;
-  gint border_width;
-  gint expander_size;
-  gint expander_spacing;
-  gboolean interior_focus;
-  gint focus_width;
-  gint focus_pad;
-  gint label_height;
-
-  expander = GTK_EXPANDER (widget);
-  bin = GTK_BIN (widget);
-  priv = expander->priv;
-
-  border_width = GTK_CONTAINER (widget)->border_width;
-
-  gtk_widget_style_get (widget,
-			"interior-focus", &interior_focus,
-			"focus-line-width", &focus_width,
-			"focus-padding", &focus_pad,
-			"expander-size", &expander_size,
-			"expander-spacing", &expander_spacing,
-			NULL);
-
-  child_requisition.width = 0;
-  child_requisition.height = 0;
-  if (bin->child && GTK_WIDGET_CHILD_VISIBLE (bin->child))
-    {
-      child_visible = TRUE;
-      gtk_widget_get_child_requisition (bin->child, &child_requisition);
-    }
-
-  widget->allocation = *allocation;
-
-  if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
-    {
-      GtkAllocation label_allocation;
-      GtkRequisition label_requisition;
-      gboolean ltr;
-
-      gtk_widget_get_child_requisition (priv->label_widget, &label_requisition);
-
-      ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
-
-      if (ltr)
-	label_allocation.x = (widget->allocation.x +
-                              border_width + focus_width + focus_pad +
-                              expander_size + 2 * expander_spacing);
-      else
-        label_allocation.x = (widget->allocation.x + widget->allocation.width -
-                              (label_requisition.width +
-                               border_width + focus_width + focus_pad +
-                               expander_size + 2 * expander_spacing));
-
-      label_allocation.y = widget->allocation.y + border_width + focus_width + focus_pad;
-
-      label_allocation.width = MIN (label_requisition.width,
-				    allocation->width - 2 * border_width -
-				    expander_size - 2 * expander_spacing -
-				    2 * focus_width - 2 * focus_pad);
-      label_allocation.width = MAX (label_allocation.width, 1);
-
-      label_allocation.height = MIN (label_requisition.height,
-				     allocation->height - 2 * border_width -
-				     2 * focus_width - 2 * focus_pad -
-				     (child_visible ? priv->spacing : 0));
-      label_allocation.height = MAX (label_allocation.height, 1);
-
-      gtk_widget_size_allocate (priv->label_widget, &label_allocation);
-
-      label_height = label_allocation.height;
-    }
-  else
-    {
-      label_height = 0;
-    }
-
-  if (GTK_WIDGET_REALIZED (widget))
-    {
-      GdkRectangle rect;
-
-      get_expander_bounds (expander, &rect);
-
-      gdk_window_move_resize (priv->event_window,
-			      allocation->x + border_width, rect.y,
-			      MAX (allocation->width - 2 * border_width, 1), rect.width);
-    }
-
-  if (child_visible)
-    {
-      GtkAllocation child_allocation;
-      gint top_height;
-
-      top_height = MAX (2 * expander_spacing + expander_size,
-			label_height +
-			(interior_focus ? 2 * focus_width + 2 * focus_pad : 0));
-
-      child_allocation.x = widget->allocation.x + border_width;
-      child_allocation.y = widget->allocation.y + border_width + top_height + priv->spacing;
-
-      if (!interior_focus)
-	child_allocation.y += 2 * focus_width + 2 * focus_pad;
-
-      child_allocation.width = MAX (allocation->width - 2 * border_width, 1);
-
-      child_allocation.height = allocation->height - top_height -
-				2 * border_width - priv->spacing -
-				(!interior_focus ? 2 * focus_width + 2 * focus_pad : 0);
-      child_allocation.height = MAX (child_allocation.height, 1);
-
-      gtk_widget_size_allocate (bin->child, &child_allocation);
-    }
-}
-
-static void
-gtk_expander_map (GtkWidget *widget)
-{
-  GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
-
-  if (priv->label_widget)
-    gtk_widget_map (priv->label_widget);
-
-  GTK_WIDGET_CLASS (parent_class)->map (widget);
-
-  if (priv->event_window)
-    gdk_window_show (priv->event_window);
-}
-
-static void
-gtk_expander_unmap (GtkWidget *widget)
-{
-  GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
-
-  if (priv->event_window)
-    gdk_window_hide (priv->event_window);
-
-  GTK_WIDGET_CLASS (parent_class)->unmap (widget);
-
-  if (priv->label_widget)
-    gtk_widget_unmap (priv->label_widget);
-}
-
-static void
-gtk_expander_paint_prelight (GtkExpander *expander)
-{
-  GtkWidget *widget;
-  GtkContainer *container;
-  GtkExpanderPrivate *priv;
-  GdkRectangle area;
-  gboolean interior_focus;
-  int focus_width;
-  int focus_pad;
-  int expander_size;
-  int expander_spacing;
-
-  priv = expander->priv;
-  widget = GTK_WIDGET (expander);
-  container = GTK_CONTAINER (expander);
-
-  gtk_widget_style_get (widget,
-			"interior-focus", &interior_focus,
-			"focus-line-width", &focus_width,
-			"focus-padding", &focus_pad,
-			"expander-size", &expander_size,
-			"expander-spacing", &expander_spacing,
-			NULL);
-
-  area.x = widget->allocation.x + container->border_width;
-  area.y = widget->allocation.y + container->border_width;
-  area.width = widget->allocation.width - (2 * container->border_width);
-
-  if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
-    area.height = priv->label_widget->allocation.height;
-  else
-    area.height = 0;
-
-  area.height += interior_focus ? (focus_width + focus_pad) * 2 : 0;
-  area.height = MAX (area.height, expander_size + 2 * expander_spacing);
-  area.height += !interior_focus ? (focus_width + focus_pad) * 2 : 0;
-
-  gtk_paint_flat_box (widget->style, widget->window,
-		      GTK_STATE_PRELIGHT,
-		      GTK_SHADOW_ETCHED_OUT,
-		      &area, widget, "expander",
-		      area.x, area.y,
-		      area.width, area.height);
-}
-
-static void
-gtk_expander_paint (GtkExpander *expander)
-{
-  GtkWidget *widget;
-  GdkRectangle clip;
-  GtkStateType state;
-
-  widget = GTK_WIDGET (expander);
-
-  get_expander_bounds (expander, &clip);
-
-  state = widget->state;
-  if (expander->priv->prelight)
-    {
-      state = GTK_STATE_PRELIGHT;
-
-      gtk_expander_paint_prelight (expander);
-    }
-
-  gtk_paint_expander (widget->style,
-		      widget->window,
-		      state,
-		      &clip,
-		      widget,
-		      "expander",
-		      clip.x + clip.width / 2,
-		      clip.y + clip.height / 2,
-		      expander->priv->expander_style);
-}
-
-static void
-gtk_expander_paint_focus (GtkExpander  *expander,
-			  GdkRectangle *area)
-{
-  GtkWidget *widget;
-  GtkExpanderPrivate *priv;
-  gint x, y, width, height;
-  gboolean interior_focus;
-  gint border_width;
-  gint focus_width;
-  gint focus_pad;
-  gint expander_size;
-  gint expander_spacing;
-  gboolean ltr;
-
-  widget = GTK_WIDGET (expander);
-  priv = expander->priv;
-
-  border_width = GTK_CONTAINER (widget)->border_width;
-
-  gtk_widget_style_get (widget,
-			"interior-focus", &interior_focus,
-			"focus-line-width", &focus_width,
-			"focus-padding", &focus_pad,
-			"expander-size", &expander_size,
-			"expander-spacing", &expander_spacing,
-			NULL);
-
-  ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
-
-  x = widget->allocation.x + border_width;
-  y = widget->allocation.y + border_width;
-
-  if (ltr && interior_focus)
-    x += expander_spacing * 2 + expander_size;
-
-  width = height = 0;
-
-  if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
-    {
-      GtkAllocation label_allocation = priv->label_widget->allocation;
-
-      width  = label_allocation.width;
-      height = label_allocation.height;
-    }
-
-  if (!interior_focus)
-    {
-      width += expander_size + 2 * expander_spacing;
-      height = MAX (height, expander_size + 2 * expander_spacing);
-    }
-
-  width  += 2 * focus_pad + 2 * focus_width;
-  height += 2 * focus_pad + 2 * focus_width;
-
-  gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget),
-		   area, widget, "expander",
-		   x, y, width, height);
-}
-
-static gboolean
-gtk_expander_expose (GtkWidget      *widget,
-		     GdkEventExpose *event)
-{
-  if (GTK_WIDGET_DRAWABLE (widget))
-    {
-      GtkExpander *expander = GTK_EXPANDER (widget);
-
-      gtk_expander_paint (expander);
-
-      if (GTK_WIDGET_HAS_FOCUS (expander))
-	gtk_expander_paint_focus (expander, &event->area);
-
-      GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
-    }
-
-  return FALSE;
-}
-
-static gboolean
-gtk_expander_button_press (GtkWidget      *widget,
-			   GdkEventButton *event)
-{
-  GtkExpander *expander = GTK_EXPANDER (widget);
-
-  if (event->button == 1 && event->window == expander->priv->event_window)
-    {
-      expander->priv->button_down = TRUE;
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-static gboolean
-gtk_expander_button_release (GtkWidget      *widget,
-			     GdkEventButton *event)
-{
-  GtkExpander *expander = GTK_EXPANDER (widget);
-
-  if (event->button == 1 && expander->priv->button_down)
-    {
-      gtk_widget_activate (widget);
-      expander->priv->button_down = FALSE;
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-static void
-gtk_expander_grab_notify (GtkWidget *widget,
-			  gboolean   was_grabbed)
-{
-  if (!was_grabbed)
-    GTK_EXPANDER (widget)->priv->button_down = FALSE;
-}
-
-static void
-gtk_expander_state_changed (GtkWidget    *widget,
-			    GtkStateType  previous_state)
-{
-  if (!GTK_WIDGET_IS_SENSITIVE (widget))
-    GTK_EXPANDER (widget)->priv->button_down = FALSE;
-}
-
-static void
-gtk_expander_redraw_expander (GtkExpander *expander)
-{
-  GtkWidget *widget;
-
-  widget = GTK_WIDGET (expander);
-
-  if (GTK_WIDGET_REALIZED (widget))
-    gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
-}
-
-static gboolean
-gtk_expander_enter_notify (GtkWidget        *widget,
-			   GdkEventCrossing *event)
-{
-  GtkExpander *expander = GTK_EXPANDER (widget);
-  GtkWidget *event_widget;
-
-  event_widget = gtk_get_event_widget ((GdkEvent *) event);
-
-  if (event_widget == widget &&
-      event->detail != GDK_NOTIFY_INFERIOR)
-    {
-      expander->priv->prelight = TRUE;
-
-      if (expander->priv->label_widget)
-	gtk_widget_set_state (expander->priv->label_widget, GTK_STATE_PRELIGHT);
-
-      gtk_expander_redraw_expander (expander);
-    }
-
-  return FALSE;
-}
-
-static gboolean
-gtk_expander_leave_notify (GtkWidget        *widget,
-			   GdkEventCrossing *event)
-{
-  GtkExpander *expander = GTK_EXPANDER (widget);
-  GtkWidget *event_widget;
-
-  event_widget = gtk_get_event_widget ((GdkEvent *) event);
-
-  if (event_widget == widget &&
-      event->detail != GDK_NOTIFY_INFERIOR)
-    {
-      expander->priv->prelight = FALSE;
-
-      if (expander->priv->label_widget)
-	gtk_widget_set_state (expander->priv->label_widget, GTK_STATE_NORMAL);
-
-      gtk_expander_redraw_expander (expander);
-    }
-
-  return FALSE;
-}
-
-typedef enum
-{
-  FOCUS_NONE,
-  FOCUS_WIDGET,
-  FOCUS_LABEL,
-  FOCUS_CHILD
-} FocusSite;
-
-static gboolean
-focus_current_site (GtkExpander      *expander,
-		    GtkDirectionType  direction)
-{
-  GtkWidget *current_focus;
-
-  current_focus = GTK_CONTAINER (expander)->focus_child;
-
-  if (!current_focus)
-    return FALSE;
-
-  return gtk_widget_child_focus (current_focus, direction);
-}
-
-static gboolean
-focus_in_site (GtkExpander      *expander,
-	       FocusSite         site,
-	       GtkDirectionType  direction)
-{
-  switch (site)
-    {
-    case FOCUS_WIDGET:
-      gtk_widget_grab_focus (GTK_WIDGET (expander));
-      return TRUE;
-    case FOCUS_LABEL:
-      if (expander->priv->label_widget)
-	return gtk_widget_child_focus (expander->priv->label_widget, direction);
-      else
-	return FALSE;
-    case FOCUS_CHILD:
-      {
-	GtkWidget *child = gtk_bin_get_child (GTK_BIN (expander));
-
-	if (child && GTK_WIDGET_CHILD_VISIBLE (child))
-	  return gtk_widget_child_focus (child, direction);
-	else
-	  return FALSE;
-      }
-    case FOCUS_NONE:
-      break;
-    }
-
-  g_assert_not_reached ();
-  return FALSE;
-}
-
-static FocusSite
-get_next_site (GtkExpander      *expander,
-	       FocusSite         site,
-	       GtkDirectionType  direction)
-{
-  gboolean ltr;
-
-  ltr = gtk_widget_get_direction (GTK_WIDGET (expander)) != GTK_TEXT_DIR_RTL;
-
-  switch (site)
-    {
-    case FOCUS_NONE:
-      switch (direction)
-	{
-	case GTK_DIR_TAB_BACKWARD:
-	case GTK_DIR_LEFT:
-	case GTK_DIR_UP:
-	  return FOCUS_CHILD;
-	case GTK_DIR_TAB_FORWARD:
-	case GTK_DIR_DOWN:
-	case GTK_DIR_RIGHT:
-	  return FOCUS_WIDGET;
-	}
-    case FOCUS_WIDGET:
-      switch (direction)
-	{
-	case GTK_DIR_TAB_BACKWARD:
-	case GTK_DIR_UP:
-	  return FOCUS_NONE;
-	case GTK_DIR_LEFT:
-	  return ltr ? FOCUS_NONE : FOCUS_LABEL;
-	case GTK_DIR_TAB_FORWARD:
-	case GTK_DIR_DOWN:
-	  return FOCUS_LABEL;
-	case GTK_DIR_RIGHT:
-	  return ltr ? FOCUS_LABEL : FOCUS_NONE;
-	  break;
-	}
-    case FOCUS_LABEL:
-      switch (direction)
-	{
-	case GTK_DIR_TAB_BACKWARD:
-	case GTK_DIR_UP:
-	  return FOCUS_WIDGET;
-	case GTK_DIR_LEFT:
-	  return ltr ? FOCUS_WIDGET : FOCUS_CHILD;
-	case GTK_DIR_TAB_FORWARD:
-	case GTK_DIR_DOWN:
-	  return FOCUS_CHILD;
-	case GTK_DIR_RIGHT:
-	  return ltr ? FOCUS_CHILD : FOCUS_WIDGET;
-	  break;
-	}
-    case FOCUS_CHILD:
-      switch (direction)
-	{
-	case GTK_DIR_TAB_BACKWARD:
-	case GTK_DIR_LEFT:
-	case GTK_DIR_UP:
-	  return FOCUS_LABEL;
-	case GTK_DIR_TAB_FORWARD:
-	case GTK_DIR_DOWN:
-	case GTK_DIR_RIGHT:
-	  return FOCUS_NONE;
-	}
-    }
-
-  g_assert_not_reached ();
-  return FOCUS_NONE;
-}
-
-static gboolean
-gtk_expander_focus (GtkWidget        *widget,
-		    GtkDirectionType  direction)
-{
-  GtkExpander *expander = GTK_EXPANDER (widget);
-
-  if (!focus_current_site (expander, direction))
-    {
-      GtkWidget *old_focus_child;
-      gboolean widget_is_focus;
-      FocusSite site = FOCUS_NONE;
-
-      widget_is_focus = gtk_widget_is_focus (widget);
-      old_focus_child = GTK_CONTAINER (widget)->focus_child;
-
-      if (old_focus_child && old_focus_child == expander->priv->label_widget)
-	site = FOCUS_LABEL;
-      else if (old_focus_child)
-	site = FOCUS_CHILD;
-      else if (widget_is_focus)
-	site = FOCUS_WIDGET;
-
-      while ((site = get_next_site (expander, site, direction)) != FOCUS_NONE)
-	{
-	  if (focus_in_site (expander, site, direction))
-	    return TRUE;
-	}
-
-      return FALSE;
-    }
-
-  return TRUE;
-}
-
-static void
-gtk_expander_add (GtkContainer *container,
-		  GtkWidget    *widget)
-{
-  GTK_CONTAINER_CLASS (parent_class)->add (container, widget);
-
-  gtk_widget_set_child_visible (widget, GTK_EXPANDER (container)->priv->expanded);
-  gtk_widget_queue_resize (GTK_WIDGET (container));
-}
-
-static void
-gtk_expander_remove (GtkContainer *container,
-		     GtkWidget    *widget)
-{
-  GtkExpander *expander = GTK_EXPANDER (container);
-
-  if (GTK_EXPANDER (expander)->priv->label_widget == widget)
-    gtk_expander_set_label_widget (expander, NULL);
-  else
-    GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
-}
-
-static void
-gtk_expander_forall (GtkContainer *container,
-		     gboolean      include_internals,
-		     GtkCallback   callback,
-		     gpointer      callback_data)
-{
-  GtkBin *bin = GTK_BIN (container);
-  GtkExpanderPrivate *priv = GTK_EXPANDER (container)->priv;
-
-  if (bin->child)
-    (* callback) (bin->child, callback_data);
-
-  if (priv->label_widget)
-    (* callback) (priv->label_widget, callback_data);
-}
-
-static void
-gtk_expander_activate (GtkExpander *expander)
-{
-  gtk_expander_set_expanded (expander, !expander->priv->expanded);
-}
-
-
-/**
- * gtk_expander_new:
- * @label: the text of the label
- *
- * Creates a new expander using @label as the text of the label.
- *
- * Return value: a new #GtkExpander widget.
- *
- * Since: 2.4
- **/
-GtkWidget *
-gtk_expander_new (const gchar *label)
-{
-  return g_object_new (GTK_TYPE_EXPANDER, "label", label, NULL);
-}
-
-/**
- * gtk_expander_new_with_mnemonic:
- * @label: the text of the label with an underscore in front of the
- *         mnemonic character
- *
- * Creates a new expander using @label as the text of the label.
- * If characters in @label are preceded by an underscore, they are underlined.
- * If you need a literal underscore character in a label, use '__' (two
- * underscores). The first underlined character represents a keyboard
- * accelerator called a mnemonic.
- * Pressing Alt and that key activates the button.
- *
- * Return value: a new #GtkExpander widget.
- *
- * Since: 2.4
- **/
-GtkWidget *
-gtk_expander_new_with_mnemonic (const gchar *label)
-{
-  return g_object_new (GTK_TYPE_EXPANDER,
-		       "label", label,
-		       "use_underline", TRUE,
-		       NULL);
-}
-
-static gboolean
-gtk_expander_animation_timeout (GtkExpander *expander)
-{
-  GtkExpanderPrivate *priv = expander->priv;
-  GdkRectangle area;
-  gboolean finish = FALSE;
-
-  GDK_THREADS_ENTER();
-
-  if (GTK_WIDGET_REALIZED (expander))
-    {
-      get_expander_bounds (expander, &area);
-      gdk_window_invalidate_rect (GTK_WIDGET (expander)->window, &area, TRUE);
-    }
-
-  if (priv->expanded)
-    {
-      if (priv->expander_style == GTK_EXPANDER_COLLAPSED)
-	{
-	  priv->expander_style = GTK_EXPANDER_SEMI_EXPANDED;
-	}
-      else
-	{
-	  priv->expander_style = GTK_EXPANDER_EXPANDED;
-	  finish = TRUE;
-	}
-    }
-  else
-    {
-      if (priv->expander_style == GTK_EXPANDER_EXPANDED)
-	{
-	  priv->expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
-	}
-      else
-	{
-	  priv->expander_style = GTK_EXPANDER_COLLAPSED;
-	  finish = TRUE;
-	}
-    }
-
-  if (finish)
-    {
-      priv->animation_timeout = 0;
-      if (GTK_BIN (expander)->child)
-	gtk_widget_set_child_visible (GTK_BIN (expander)->child, priv->expanded);
-      gtk_widget_queue_resize (GTK_WIDGET (expander));
-    }
-
-  GDK_THREADS_LEAVE();
-
-  return !finish;
-}
-
-static void
-gtk_expander_start_animation (GtkExpander *expander)
-{
-  GtkExpanderPrivate *priv = expander->priv;
-
-  if (priv->animation_timeout)
-    g_source_remove (priv->animation_timeout);
-
-  priv->animation_timeout =
-		g_timeout_add (50,
-			       (GSourceFunc) gtk_expander_animation_timeout,
-			       expander);
-}
-
-/**
- * gtk_expander_set_expanded:
- * @expander: a #GtkExpander
- * @expanded: whether the child widget is revealed
- *
- * Sets the state of the expander. Set to %TRUE, if you want
- * the child widget to be revealed, and %FALSE if you want the
- * child widget to be hidden.
- *
- * Since: 2.4
- **/
-void
-gtk_expander_set_expanded (GtkExpander *expander,
-			   gboolean     expanded)
-{
-  GtkExpanderPrivate *priv;
-
-  g_return_if_fail (GTK_IS_EXPANDER (expander));
-
-  priv = expander->priv;
-
-  expanded = expanded != FALSE;
-
-  if (priv->expanded != expanded)
-    {
-      priv->expanded = expanded;
-
-      if (GTK_WIDGET_REALIZED (expander))
-	{
-	  gtk_expander_start_animation (expander);
-	}
-      else
-	{
-	  priv->expander_style = expanded ? GTK_EXPANDER_EXPANDED :
-					    GTK_EXPANDER_COLLAPSED;
-
-	  if (GTK_BIN (expander)->child)
-	    {
-	      gtk_widget_set_child_visible (GTK_BIN (expander)->child, priv->expanded);
-	      gtk_widget_queue_resize (GTK_WIDGET (expander));
-	    }
-	}
-
-      g_object_notify (G_OBJECT (expander), "expanded");
-    }
-}
-
-/**
- * gtk_expander_get_expanded:
- * @expander:a #GtkExpander
- *
- * Queries a #GtkExpander and returns its current state. Returns %TRUE
- * if the child widget is revealed.
- *
- * See gtk_expander_set_expanded().
- *
- * Return value: the current state of the expander.
- *
- * Since: 2.4
- **/
-gboolean
-gtk_expander_get_expanded (GtkExpander *expander)
-{
-  g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
-
-  return expander->priv->expanded;
-}
-
-/**
- * gtk_expander_set_spacing:
- * @expander: a #GtkExpander
- * @spacing: distance between the expander and child in pixels.
- *
- * Sets the spacing field of @expander, which is the number of pixels to
- * place between expander and the child.
- *
- * Since: 2.4
- **/
-void
-gtk_expander_set_spacing (GtkExpander *expander,
-			  gint         spacing)
-{
-  g_return_if_fail (GTK_IS_EXPANDER (expander));
-  g_return_if_fail (spacing >= 0);
-
-  if (expander->priv->spacing != spacing)
-    {
-      expander->priv->spacing = spacing;
-
-      gtk_widget_queue_resize (GTK_WIDGET (expander));
-
-      g_object_notify (G_OBJECT (expander), "spacing");
-    }
-}
-
-/**
- * gtk_expander_get_spacing:
- * @expander: a #GtkExpander
- *
- * Gets the value set by gtk_expander_set_spacing().
- *
- * Return value: spacing between the expander and child.
- *
- * Since: 2.4
- **/
-gint
-gtk_expander_get_spacing (GtkExpander *expander)
-{
-  g_return_val_if_fail (GTK_IS_EXPANDER (expander), 0);
-
-  return expander->priv->spacing;
-}
-
-/**
- * gtk_expander_set_label:
- * @expander: a #GtkExpander
- * @label: a string
- *
- * Sets the text of the label of the expander to @label.
- *
- * This will also clear any previously set labels.
- *
- * Since: 2.4
- **/
-void
-gtk_expander_set_label (GtkExpander *expander,
-			const gchar *label)
-{
-  g_return_if_fail (GTK_IS_EXPANDER (expander));
-
-  if (!label)
-    {
-      gtk_expander_set_label_widget (expander, NULL);
-    }
-  else
-    {
-      GtkWidget *child;
-
-      child = gtk_label_new (label);
-      gtk_label_set_use_underline (GTK_LABEL (child), expander->priv->use_underline);
-      gtk_label_set_use_markup (GTK_LABEL (child), expander->priv->use_markup);
-      gtk_widget_show (child);
-
-      gtk_expander_set_label_widget (expander, child);
-    }
-
-  g_object_notify (G_OBJECT (expander), "label");
-}
-
-/**
- * gtk_expander_get_label:
- * @expander: a #GtkExpander
- *
- * Fetches the text from the label of the expander, as set by
- * gtk_expander_set_label(). If the label text has not
- * been set the return value will be %NULL. This will be the
- * case if you create an empty button with gtk_button_new() to
- * use as a container.
- *
- * Return value: The text of the label widget. This string is owned
- * by the widget and must not be modified or freed.
- *
- * Since: 2.4
- **/
-G_CONST_RETURN char *
-gtk_expander_get_label (GtkExpander *expander)
-{
-  GtkExpanderPrivate *priv;
-
-  g_return_val_if_fail (GTK_IS_EXPANDER (expander), NULL);
-
-  priv = expander->priv;
-
-  if (priv->label_widget && GTK_IS_LABEL (priv->label_widget))
-    return gtk_label_get_text (GTK_LABEL (priv->label_widget));
-  else
-    return NULL;
-}
-
-/**
- * gtk_expander_set_use_underline:
- * @expander: a #GtkExpander
- * @use_underline: %TRUE if underlines in the text indicate mnemonics
- *
- * If true, an underline in the text of the expander label indicates
- * the next character should be used for the mnemonic accelerator key.
- *
- * Since: 2.4
- **/
-void
-gtk_expander_set_use_underline (GtkExpander *expander,
-				gboolean     use_underline)
-{
-  GtkExpanderPrivate *priv;
-
-  g_return_if_fail (GTK_IS_EXPANDER (expander));
-
-  priv = expander->priv;
-
-  use_underline = use_underline != FALSE;
-
-  if (priv->use_underline != use_underline)
-    {
-      priv->use_underline = use_underline;
-
-      if (priv->label_widget && GTK_IS_LABEL (priv->label_widget))
-	gtk_label_set_use_underline (GTK_LABEL (priv->label_widget), use_underline);
-
-      g_object_notify (G_OBJECT (expander), "use-underline");
-    }
-}
-
-/**
- * gtk_expander_get_use_underline:
- * @expander: a #GtkExpander
- *
- * Returns whether an embedded underline in the expander label indicates a
- * mnemonic. See gtk_expander_set_use_underline().
- *
- * Return value: %TRUE if an embedded underline in the expander label
- *               indicates the mnemonic accelerator keys.
- *
- * Since: 2.4
- **/
-gboolean
-gtk_expander_get_use_underline (GtkExpander *expander)
-{
-  g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
-
-  return expander->priv->use_underline;
-}
-
-/**
- * gtk_expander_set_use_markup:
- * @expander: a #GtkExpander
- * @use_markup: %TRUE if the label's text should be parsed for markup
- *
- * Sets whether the text of the label contains markup in <link
- * linkend="PangoMarkupFormat">Pango's text markup
- * language</link>. See gtk_label_set_markup().
- *
- * Since: 2.4
- **/
-void
-gtk_expander_set_use_markup (GtkExpander *expander,
-			     gboolean     use_markup)
-{
-  GtkExpanderPrivate *priv;
-
-  g_return_if_fail (GTK_IS_EXPANDER (expander));
-
-  priv = expander->priv;
-
-  use_markup = use_markup != FALSE;
-
-  if (priv->use_markup != use_markup)
-    {
-      priv->use_markup = use_markup;
-
-      if (priv->label_widget && GTK_IS_LABEL (priv->label_widget))
-	gtk_label_set_use_markup (GTK_LABEL (priv->label_widget), use_markup);
-
-      g_object_notify (G_OBJECT (expander), "use-markup");
-    }
-}
-
-/**
- * gtk_expander_get_use_markup:
- * @expander: a #GtkExpander
- *
- * Returns whether the label's text is interpreted as marked up with
- * the <link linkend="PangoMarkupFormat">Pango text markup
- * language</link>. See gtk_expander_set_use_markup ().
- *
- * Return value: %TRUE if the label's text will be parsed for markup
- *
- * Since: 2.4
- **/
-gboolean
-gtk_expander_get_use_markup (GtkExpander *expander)
-{
-  g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
-
-  return expander->priv->use_markup;
-}
-
-/**
- * gtk_expander_set_label_widget:
- * @expander: a #GtkExpander
- * @label_widget: the new label widget
- *
- * Set the label widget for the expander. This is the widget
- * that will appear embedded alongside the expander arrow.
- *
- * Since: 2.4
- **/
-void
-gtk_expander_set_label_widget (GtkExpander *expander,
-			       GtkWidget   *label_widget)
-{
-  GtkExpanderPrivate *priv;
-
-  g_return_if_fail (GTK_IS_EXPANDER (expander));
-  g_return_if_fail (label_widget == NULL || GTK_IS_WIDGET (label_widget));
-  g_return_if_fail (label_widget == NULL || label_widget->parent == NULL);
-
-  priv = expander->priv;
-
-  if (priv->label_widget == label_widget)
-    return;
-
-  if (priv->label_widget)
-    {
-      gtk_widget_set_state (priv->label_widget, GTK_STATE_NORMAL);
-      gtk_widget_unparent (priv->label_widget);
-    }
-
-  priv->label_widget = label_widget;
-
-  if (label_widget)
-    {
-      priv->label_widget = label_widget;
-
-      gtk_widget_set_parent (label_widget, GTK_WIDGET (expander));
-
-      if (priv->prelight)
-	gtk_widget_set_state (label_widget, GTK_STATE_PRELIGHT);
-    }
-
-  if (GTK_WIDGET_VISIBLE (expander))
-    gtk_widget_queue_resize (GTK_WIDGET (expander));
-
-  g_object_freeze_notify (G_OBJECT (expander));
-  g_object_notify (G_OBJECT (expander), "label-widget");
-  g_object_notify (G_OBJECT (expander), "label");
-  g_object_thaw_notify (G_OBJECT (expander));
-}
-
-/**
- * gtk_expander_get_label_widget:
- * @expander: a #GtkExpander
- *
- * Retrieves the label widget for the frame. See
- * gtk_expander_set_label_widget().
- *
- * Return value: the label widget, or %NULL if there is none.
- *
- * Since: 2.4
- **/
-GtkWidget *
-gtk_expander_get_label_widget (GtkExpander *expander)
-{
-  g_return_val_if_fail (GTK_IS_EXPANDER (expander), NULL);
-
-  return expander->priv->label_widget;
-}
-
-#define __GTK_EXPANDER_C__
-
-#endif /* Gtk 2.4 */
--- a/pidgin/gtkexpander.h	Thu Feb 04 02:18:37 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/* GTK - The GIMP Toolkit
- *
- * Copyright (C) 2003 Sun Microsystems, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02111-1301, USA.
- *
- * Authors:
- *	Mark McLoughlin <mark@skynet.ie>
- */
-
-#ifndef __GTK_EXPANDER_H__
-#define __GTK_EXPANDER_H__
-
-#include <gtk/gtkbin.h>
-
-G_BEGIN_DECLS
-
-#define GTK_TYPE_EXPANDER            (gtk_expander_get_type ())
-#define GTK_EXPANDER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_EXPANDER, GtkExpander))
-#define GTK_EXPANDER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_EXPANDER, GtkExpanderClass))
-#define GTK_IS_EXPANDER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_EXPANDER))
-#define GTK_IS_EXPANDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_EXPANDER))
-#define GTK_EXPANDER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_EXPANDER, GtkExpanderClass))
-
-typedef struct _GtkExpander        GtkExpander;
-typedef struct _GtkExpanderClass   GtkExpanderClass;
-typedef struct _GtkExpanderPrivate GtkExpanderPrivate;
-
-struct _GtkExpander
-{
-  GtkBin              bin;
-
-  GtkExpanderPrivate *priv;
-};
-
-struct _GtkExpanderClass
-{
-  GtkBinClass    parent_class;
-
-  /* Key binding signal; to get notification on the expansion
-   * state connect to notify:expanded.
-   */
-  void        (* activate) (GtkExpander *expander);
-};
-
-GType                 gtk_expander_get_type          (void) G_GNUC_CONST;
-
-GtkWidget            *gtk_expander_new               (const gchar *label);
-GtkWidget            *gtk_expander_new_with_mnemonic (const gchar *label);
-
-void                  gtk_expander_set_expanded      (GtkExpander *expander,
-						      gboolean     expanded);
-gboolean              gtk_expander_get_expanded      (GtkExpander *expander);
-
-/* Spacing between the expander/label and the child */
-void                  gtk_expander_set_spacing       (GtkExpander *expander,
-						      gint         spacing);
-gint                  gtk_expander_get_spacing       (GtkExpander *expander);
-
-void                  gtk_expander_set_label         (GtkExpander *expander,
-						      const gchar *label);
-G_CONST_RETURN gchar *gtk_expander_get_label         (GtkExpander *expander);
-
-void                  gtk_expander_set_use_underline (GtkExpander *expander,
-						      gboolean     use_underline);
-gboolean              gtk_expander_get_use_underline (GtkExpander *expander);
-
-void                  gtk_expander_set_use_markup    (GtkExpander *expander,
-						      gboolean    use_markup);
-gboolean              gtk_expander_get_use_markup    (GtkExpander *expander);
-
-void                  gtk_expander_set_label_widget  (GtkExpander *expander,
-						      GtkWidget   *label_widget);
-GtkWidget            *gtk_expander_get_label_widget  (GtkExpander *expander);
-
-G_END_DECLS
-
-#endif /* __GTK_EXPANDER_H__ */
--- a/pidgin/gtkft.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkft.c	Thu Feb 04 05:30:35 2010 +0000
@@ -32,10 +32,8 @@
 #include "prpl.h"
 #include "util.h"
 
-#include "gtkcellrendererprogress.h"
 #include "gtkft.h"
 #include "prefs.h"
-#include "gtkexpander.h"
 #include "pidginstock.h"
 #include "gtkutils.h"
 
@@ -460,27 +458,15 @@
 #ifdef _WIN32
 	/* If using Win32... */
 	int code;
-	if (G_WIN32_HAVE_WIDECHAR_API ()) {
-		wchar_t *wc_filename = g_utf8_to_utf16(
-				purple_xfer_get_local_filename(
-					dialog->selected_xfer),
-				-1, NULL, NULL, NULL);
-
-		code = (int) ShellExecuteW(NULL, NULL, wc_filename, NULL, NULL,
-				SW_SHOW);
+	wchar_t *wc_filename = g_utf8_to_utf16(
+			purple_xfer_get_local_filename(
+				dialog->selected_xfer),
+			-1, NULL, NULL, NULL);
 
-		g_free(wc_filename);
-	} else {
-		char *l_filename = g_locale_from_utf8(
-				purple_xfer_get_local_filename(
-					dialog->selected_xfer),
-				-1, NULL, NULL, NULL);
+	code = (int) ShellExecuteW(NULL, NULL, wc_filename, NULL, NULL,
+			SW_SHOW);
 
-		code = (int) ShellExecuteA(NULL, NULL, l_filename, NULL, NULL,
-				SW_SHOW);
-
-		g_free(l_filename);
-	}
+	g_free(wc_filename);
 
 	if (code == SE_ERR_ASSOCINCOMPLETE || code == SE_ERR_NOASSOC)
 	{
@@ -621,7 +607,7 @@
 	gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
 
 	/* Progress bar column */
-	renderer = pidgin_cell_renderer_progress_new();
+	renderer = gtk_cell_renderer_progress_new();
 	column = gtk_tree_view_column_new_with_attributes(_("Progress"), renderer,
 				"percentage", COLUMN_PROGRESS, NULL);
 	gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
--- a/pidgin/gtkimhtml.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkimhtml.c	Thu Feb 04 05:30:35 2010 +0000
@@ -63,18 +63,8 @@
 
 #include <pango/pango-font.h>
 
-/* GTK+ < 2.4.x hack, see pidgin.h for details. */
-#if (!GTK_CHECK_VERSION(2,4,0))
-#define GTK_WRAP_WORD_CHAR GTK_WRAP_WORD
-#endif
-
 #define TOOLTIP_TIMEOUT 500
 
-/* GTK+ 2.0 hack */
-#if (!GTK_CHECK_VERSION(2,2,0))
-#define gtk_widget_get_clipboard(x, y) gtk_clipboard_get(y)
-#endif
-
 static GtkTextViewClass *parent_class = NULL;
 
 struct scalable_data {
@@ -552,10 +542,8 @@
 	gtk_window_set_title(GTK_WINDOW(imhtml->tip_window), "GtkIMHtml");
 	gtk_window_set_resizable (GTK_WINDOW (imhtml->tip_window), FALSE);
 	gtk_widget_set_name (imhtml->tip_window, "gtk-tooltips");
-#if GTK_CHECK_VERSION(2,10,0)
 	gtk_window_set_type_hint (GTK_WINDOW (imhtml->tip_window),
 		GDK_WINDOW_TYPE_HINT_TOOLTIP);
-#endif
 	g_signal_connect_swapped (G_OBJECT (imhtml->tip_window), "expose_event",
 							  G_CALLBACK (gtk_imhtml_tip_paint), imhtml);
 
@@ -746,32 +734,6 @@
 	return FALSE;
 }
 
-#if (!GTK_CHECK_VERSION(2,2,0))
-/*
- * XXX - This should be removed eventually.
- *
- * This function exists to work around a gross bug in GtkTextView.
- * Basically, we short circuit ctrl+a and ctrl+end because they make
- * el program go boom.
- *
- * It's supposed to be fixed in gtk2.2.  You can view the bug report at
- * http://bugzilla.gnome.org/show_bug.cgi?id=107939
- */
-static gboolean
-gtk_key_pressed_cb(GtkIMHtml *imhtml, GdkEventKey *event, gpointer data)
-{
-	if (event->state & GDK_CONTROL_MASK) {
-		switch (event->keyval) {
-			case 'a':
-			case GDK_Home:
-			case GDK_End:
-				return TRUE;
-		}
-	}
-	return FALSE;
-}
-#endif /* !(GTK+ >= 2.2.0) */
-
 static gint
 gtk_imhtml_expose_event (GtkWidget      *widget,
 			 GdkEventExpose *event)
@@ -1686,10 +1648,6 @@
 	g_signal_connect(G_OBJECT(imhtml), "motion-notify-event", G_CALLBACK(gtk_motion_event_notify), NULL);
 	g_signal_connect(G_OBJECT(imhtml), "leave-notify-event", G_CALLBACK(gtk_leave_event_notify), NULL);
 	g_signal_connect(G_OBJECT(imhtml), "enter-notify-event", G_CALLBACK(gtk_enter_event_notify), NULL);
-#if (!GTK_CHECK_VERSION(2,2,0))
-	/* See the comment for gtk_key_pressed_cb */
-	g_signal_connect(G_OBJECT(imhtml), "key_press_event", G_CALLBACK(gtk_key_pressed_cb), NULL);
-#endif
 	g_signal_connect(G_OBJECT(imhtml), "button_press_event", G_CALLBACK(gtk_imhtml_button_press_event), NULL);
 	g_signal_connect(G_OBJECT(imhtml->text_buffer), "insert-text", G_CALLBACK(preinsert_cb), imhtml);
 	g_signal_connect(G_OBJECT(imhtml->text_buffer), "delete_range", G_CALLBACK(delete_cb), imhtml);
@@ -3689,22 +3647,12 @@
 	image->filesel = NULL;
 
 	if (save->data && save->datasize) {
-#if GLIB_CHECK_VERSION(2,8,0)
 		g_file_set_contents(filename, save->data, save->datasize, &error);
-#else
-		purple_util_write_data_to_file_absolute(filename, save->data, save->datasize);
-#endif
 	} else {
 		gchar *type = NULL;
-#if GTK_CHECK_VERSION(2,2,0)
 		GSList *formats = gdk_pixbuf_get_formats();
-#else
-		char *basename = g_path_get_basename(filename);
-		char *ext = strrchr(basename, '.');
-#endif
 		char *newfilename;
 
-#if GTK_CHECK_VERSION(2,2,0)
 		while (formats) {
 			GdkPixbufFormat *format = formats->data;
 			gchar **extensions = gdk_pixbuf_format_get_extensions(format);
@@ -3731,31 +3679,14 @@
 		}
 
 		g_slist_free(formats);
-#else
-		/* this is really ugly code, but I think it will work */
-		if (ext) {
-			ext++;
-			if (!g_ascii_strcasecmp(ext, "jpeg") || !g_ascii_strcasecmp(ext, "jpg"))
-				type = g_strdup("jpeg");
-			else if (!g_ascii_strcasecmp(ext, "png"))
-				type = g_strdup("png");
-		}
-
-		g_free(basename);
-#endif
 
 		/* If I can't find a valid type, I will just tell the user about it and then assume
 		   it's a png */
 		if (!type){
 			char *basename, *tmp;
 			char *dirname;
-#if GTK_CHECK_VERSION(2,4,0)
 			GtkWidget *dialog = gtk_message_dialog_new_with_markup(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
 							_("<span size='larger' weight='bold'>Unrecognized file type</span>\n\nDefaulting to PNG."));
-#else
-			GtkWidget *dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
-							_("Unrecognized file type\n\nDefaulting to PNG."));
-#endif
 
 			g_signal_connect_swapped(dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog);
 			gtk_widget_show(dialog);
@@ -3784,20 +3715,14 @@
 	}
 
 	if (error){
-#if GTK_CHECK_VERSION(2,4,0)
 		GtkWidget *dialog = gtk_message_dialog_new_with_markup(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
 				_("<span size='larger' weight='bold'>Error saving image</span>\n\n%s"), error->message);
-#else
-		GtkWidget *dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
-				_("Error saving image\n\n%s"), error->message);
-#endif
 		g_signal_connect_swapped(dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog);
 		gtk_widget_show(dialog);
 		g_error_free(error);
 	}
 }
 
-#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
 static void
 image_save_check_if_exists_cb(GtkWidget *widget, gint response, GtkIMHtmlImageSave *save)
 {
@@ -3811,32 +3736,6 @@
 	}
 
 	filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
-#else /* FILECHOOSER */
-static void
-image_save_check_if_exists_cb(GtkWidget *button, GtkIMHtmlImageSave *save)
-{
-	gchar *filename;
-	GtkIMHtmlImage *image = (GtkIMHtmlImage *)save->image;
-
-	filename = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(image->filesel)));
-
-	if (g_file_test(filename, G_FILE_TEST_IS_DIR)) {
-		gchar *dirname;
-		/* append a / is needed */
-		if (filename[strlen(filename) - 1] != G_DIR_SEPARATOR) {
-			dirname = g_strconcat(filename, G_DIR_SEPARATOR_S, NULL);
-		} else {
-			dirname = g_strdup(filename);
-		}
-		gtk_file_selection_set_filename(GTK_FILE_SELECTION(image->filesel), dirname);
-		g_free(dirname);
-		g_free(filename);
-		return;
-	}
-#endif /* FILECHOOSER */
-#if 0 /* mismatched curly braces */
-	}
-#endif
 
 	/*
 	 * XXX - We should probably prompt the user to determine if they really
@@ -3854,15 +3753,6 @@
 	g_free(filename);
 }
 
-#if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
-static void
-image_save_cancel_cb(GtkIMHtmlImage *image)
-{
-	gtk_widget_destroy(image->filesel);
-	image->filesel = NULL;
-}
-#endif /* FILECHOOSER */
-
 static void
 gtk_imhtml_image_save(GtkWidget *w, GtkIMHtmlImageSave *save)
 {
@@ -3873,7 +3763,6 @@
 		return;
 	}
 
-#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
 	image->filesel = gtk_file_chooser_dialog_new(_("Save Image"),
 						NULL,
 						GTK_FILE_CHOOSER_ACTION_SAVE,
@@ -3885,17 +3774,6 @@
 		gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(image->filesel), image->filename);
 	g_signal_connect(G_OBJECT(GTK_FILE_CHOOSER(image->filesel)), "response",
 					 G_CALLBACK(image_save_check_if_exists_cb), save);
-#else /* FILECHOOSER */
-	image->filesel = gtk_file_selection_new(_("Save Image"));
-	if (image->filename != NULL)
-		gtk_file_selection_set_filename(GTK_FILE_SELECTION(image->filesel), image->filename);
-	g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(image->filesel)), "delete_event",
-							 G_CALLBACK(image_save_cancel_cb), image);
-	g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(image->filesel)->cancel_button),
-							 "clicked", G_CALLBACK(image_save_cancel_cb), image);
-	g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(image->filesel)->ok_button), "clicked",
-					 G_CALLBACK(image_save_check_if_exists_cb), save);
-#endif /* FILECHOOSER */
 
 	gtk_widget_show(image->filesel);
 }
@@ -5004,9 +4882,7 @@
 
 	if (imhtml_smiley && imhtml_smiley->flags & GTK_IMHTML_SMILEY_CUSTOM) {
 		ebox = gtk_event_box_new();
-#if GTK_CHECK_VERSION(2,4,0)
 		gtk_event_box_set_visible_window(GTK_EVENT_BOX(ebox), FALSE);
-#endif
 		gtk_widget_show(ebox);
 	}
 
--- a/pidgin/gtkimhtmltoolbar.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkimhtmltoolbar.c	Thu Feb 04 05:30:35 2010 +0000
@@ -33,6 +33,7 @@
 #include "request.h"
 #include "pidginstock.h"
 #include "util.h"
+#include "debug.h"
 
 #include "gtkdialogs.h"
 #include "gtkimhtmltoolbar.h"
@@ -478,35 +479,19 @@
 	GtkTextIter iter;
 	GtkTextMark *ins;
 
-#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
 	if (response != GTK_RESPONSE_ACCEPT)
-#else /* FILECHOOSER */
-	if (response != GTK_RESPONSE_OK)
-#endif /* FILECHOOSER */
 	{
 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toolbar->image), FALSE);
 		return;
 	}
 
-#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
 	filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
-#else /* FILECHOOSER */
-	filename = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(widget)));
-#endif /* FILECHOOSER */
 
 	if (filename == NULL) {
 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toolbar->image), FALSE);
 		return;
 	}
 
-#if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
-	if (pidgin_check_if_dir(filename, GTK_FILE_SELECTION(widget))) {
-		g_free(filename);
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toolbar->image), FALSE);
-		return;
-	}
-#endif /* FILECHOOSER */
-
 	/* The following triggers a callback that closes the widget */
 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toolbar->image), FALSE);
 
@@ -549,7 +534,6 @@
 	GtkWidget *window;
 
 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toolbar->image))) {
-#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
 		window = gtk_file_chooser_dialog_new(_("Insert Image"),
 						NULL,
 						GTK_FILE_CHOOSER_ACTION_OPEN,
@@ -559,12 +543,6 @@
 		gtk_dialog_set_default_response(GTK_DIALOG(window), GTK_RESPONSE_ACCEPT);
 		g_signal_connect(G_OBJECT(GTK_FILE_CHOOSER(window)),
 				"response", G_CALLBACK(do_insert_image_cb), toolbar);
-#else /* FILECHOOSER */
-		window = gtk_file_selection_new(_("Insert Image"));
-		gtk_dialog_set_default_response(GTK_DIALOG(window), GTK_RESPONSE_OK);
-		g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(window)),
-				"response", G_CALLBACK(do_insert_image_cb), toolbar);
-#endif /* FILECHOOSER */
 
 		gtk_widget_show(window);
 		toolbar->image_dialog = window;
@@ -921,6 +899,17 @@
 	gtk_widget_grab_focus(toolbar->imhtml);
 }
 
+static void send_attention_cb(GtkWidget *attention, GtkIMHtmlToolbar *toolbar)
+{
+	PurpleConversation *conv =
+		g_object_get_data(G_OBJECT(toolbar), "active_conv");
+	const gchar *who = purple_conversation_get_name(conv);
+	PurpleConnection *gc = purple_conversation_get_gc(conv);
+
+	toggle_button_set_active_block(GTK_TOGGLE_BUTTON(attention), FALSE, toolbar);
+	purple_prpl_send_attention(gc, who, 0);
+}
+
 static void update_buttons_cb(GtkIMHtml *imhtml, GtkIMHtmlButtons buttons, GtkIMHtmlToolbar *toolbar)
 {
 	gtk_widget_set_sensitive(GTK_WIDGET(toolbar->bold), buttons & GTK_IMHTML_BOLD);
@@ -1241,6 +1230,8 @@
 		{PIDGIN_STOCK_TOOLBAR_INSERT_LINK, insert_link_cb, &toolbar->link, _("Insert Link")},
 		{"", NULL, NULL, NULL},
 		{PIDGIN_STOCK_TOOLBAR_SMILEY, insert_smiley_cb, &toolbar->smiley, _("Insert Smiley")},
+		/*{PIDGIN_STOCK_TOOLBAR_SEND_ATTENTION, send_attention_cb, 
+			g_object_get_data(G_OBJECT(toolbar->imhtml), "attention"), _("Send Attention")},*/
 		{NULL, NULL, NULL, NULL}
 	};
 	int iter;
@@ -1258,6 +1249,13 @@
 			button = gtk_vseparator_new();
 		gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
 	}
+	/* create the attention button (this is a bit hacky to not break ABI) */
+	button = pidgin_pixbuf_toolbar_button_from_stock(PIDGIN_STOCK_TOOLBAR_SEND_ATTENTION);
+	g_signal_connect(G_OBJECT(button), "clicked",
+		G_CALLBACK(send_attention_cb), toolbar);
+	g_object_set_data(G_OBJECT(toolbar), "attention", button);
+	gtk_tooltips_set_tip(toolbar->tooltips, button, _("Send Attention"), NULL);
+	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
 
 	gtk_box_pack_start(GTK_BOX(toolbar), hbox, FALSE, FALSE, 0);
 	g_object_set_data(G_OBJECT(toolbar), "wide-view", hbox);
@@ -1306,6 +1304,7 @@
 	GtkWidget *insert_button;
 	GtkWidget *font_button;
 	GtkWidget *smiley_button;
+	GtkWidget *attention_button;
 	GtkWidget *font_menu;
 	GtkWidget *insert_menu;
 	GtkWidget *menuitem;
@@ -1447,6 +1446,35 @@
 	g_signal_connect_swapped(G_OBJECT(smiley_button), "clicked", G_CALLBACK(gtk_button_clicked), toolbar->smiley);
 	gtk_widget_show_all(smiley_button);
 
+	/* Sep */
+	sep = gtk_vseparator_new();
+	gtk_box_pack_start(GTK_BOX(box), sep, FALSE, FALSE, 0);
+	gtk_widget_show_all(sep);
+
+	/* Attention */
+	attention_button = gtk_button_new();
+	gtk_button_set_relief(GTK_BUTTON(attention_button), GTK_RELIEF_NONE);
+	bbox = gtk_hbox_new(FALSE, 3);
+	gtk_container_add(GTK_CONTAINER(attention_button), bbox);
+	image = gtk_image_new_from_stock(PIDGIN_STOCK_TOOLBAR_SEND_ATTENTION, 
+		gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL));
+	gtk_box_pack_start(GTK_BOX(bbox), image, FALSE, FALSE, 0);
+	label = gtk_label_new_with_mnemonic(_("_Attention!"));
+	gtk_box_pack_start(GTK_BOX(bbox), label, FALSE, FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(box), attention_button, FALSE, FALSE, 0);
+	g_signal_connect_swapped(G_OBJECT(attention_button), "clicked", 
+		G_CALLBACK(gtk_button_clicked),
+	    g_object_get_data(G_OBJECT(toolbar), "attention"));
+	gtk_widget_show_all(attention_button);
+	
+	g_signal_connect(G_OBJECT(g_object_get_data(G_OBJECT(toolbar), "attention")),
+	        "notify::sensitive",
+			G_CALLBACK(button_sensitiveness_changed), attention_button);
+
+	/* set attention button to be greyed out until we get a conversation */
+	gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(toolbar), "attention"),
+		FALSE);
+	
 	gtk_box_pack_start(GTK_BOX(hbox), box, FALSE, FALSE, 0);
 	g_object_set_data(G_OBJECT(hbox), "lean-view", box);
 	gtk_widget_show(box);
@@ -1457,9 +1485,7 @@
 			G_CALLBACK(purple_prefs_trigger_callback), PIDGIN_PREFS_ROOT "/conversations/toolbar/wide",
 			NULL, G_CONNECT_AFTER | G_CONNECT_SWAPPED);
 
-#if GTK_CHECK_VERSION(2,4,0)
 	gtk_event_box_set_visible_window(GTK_EVENT_BOX(event), FALSE);
-#endif
 
 	gtk_widget_add_events(event, GDK_BUTTON_PRESS_MASK);
 	gtk_box_pack_start(GTK_BOX(hbox), event, TRUE, TRUE, 0);
@@ -1524,3 +1550,21 @@
 	g_free(toolbar->sml);
 	toolbar->sml = g_strdup(proto_id);
 }
+
+void gtk_imhtmltoolbar_switch_active_conversation(GtkIMHtmlToolbar *toolbar,
+	PurpleConversation *conv)
+{
+	PurpleConnection *gc = purple_conversation_get_gc(conv);
+	PurplePlugin *prpl = purple_connection_get_prpl(gc);
+	GtkWidget *attention =
+		g_object_get_data(G_OBJECT(toolbar), "attention");
+
+	g_object_set_data(G_OBJECT(toolbar), "active_conv", conv);
+	
+	/* gray out attention button on protocols that don't support it
+	 for the time being it is always disabled for chats */
+	gtk_widget_set_sensitive(attention,
+		conv && prpl && purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM && 
+		PURPLE_PLUGIN_PROTOCOL_INFO(prpl)->send_attention != NULL);
+}
+
--- a/pidgin/gtkimhtmltoolbar.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkimhtmltoolbar.h	Thu Feb 04 05:30:35 2010 +0000
@@ -90,6 +90,11 @@
 void gtk_imhtmltoolbar_attach    (GtkIMHtmlToolbar *toolbar, GtkWidget *imhtml);
 void gtk_imhtmltoolbar_associate_smileys (GtkIMHtmlToolbar *toolbar, const char *proto_id);
 
+/**
+ * @since 2.7.0
+ */
+void gtk_imhtmltoolbar_switch_active_conversation(GtkIMHtmlToolbar *toolbar,
+	PurpleConversation *conv);
 
 #ifdef __cplusplus
 }
--- a/pidgin/gtklog.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtklog.c	Thu Feb 04 05:30:35 2010 +0000
@@ -252,7 +252,6 @@
 		GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(treestore), iter);
 		gboolean first = !gtk_tree_path_prev(path);
 
-#if GTK_CHECK_VERSION(2,2,0)
 		if (!gtk_tree_store_remove(treestore, iter) && first)
 		{
 			/* iter was the last child at its level */
@@ -263,9 +262,7 @@
 				gtk_tree_store_remove(treestore, iter);
 			}
 		}
-#else
-		gtk_tree_store_remove(treestore, iter);
-#endif
+
 		gtk_tree_path_free(path);
 	}
 
--- a/pidgin/gtkmain.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkmain.c	Thu Feb 04 05:30:35 2010 +0000
@@ -805,9 +805,7 @@
 		return 1;
 	}
 
-#if GLIB_CHECK_VERSION(2,2,0)
 	g_set_application_name(PIDGIN_NAME);
-#endif /* glib-2.0 >= 2.2.0 */
 
 #ifdef _WIN32
 	winpidgin_init(hint);
--- a/pidgin/gtkmenutray.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkmenutray.c	Thu Feb 04 05:30:35 2010 +0000
@@ -138,9 +138,7 @@
 static void
 pidgin_menu_tray_init(PidginMenuTray *menu_tray) {
 	GtkWidget *widget = GTK_WIDGET(menu_tray);
-#if GTK_CHECK_VERSION(2,2,0)
 	GtkSettings *settings;
-#endif
 	gint height = -1;
 
 	gtk_menu_item_set_right_justified(GTK_MENU_ITEM(menu_tray), TRUE);
@@ -148,15 +146,11 @@
 	if(!GTK_IS_WIDGET(menu_tray->tray))
 		menu_tray->tray = gtk_hbox_new(FALSE, 0);
 
-#if GTK_CHECK_VERSION(2,2,0)
 	settings =
 		gtk_settings_get_for_screen(gtk_widget_get_screen(widget));
 
 	if(gtk_icon_size_lookup_for_settings(settings, GTK_ICON_SIZE_MENU,
 										 NULL, &height))
-#else
-	if(gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, NULL, &height))
-#endif
 	{
 		gtk_widget_set_size_request(widget, -1, height);
 	}
--- a/pidgin/gtknotify.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtknotify.c	Thu Feb 04 05:30:35 2010 +0000
@@ -627,12 +627,7 @@
 						PIDGIN_MAIL_DATA, &data, -1);
 				if (data && data->account == account) {
 					if (clear) {
-#if GTK_CHECK_VERSION(2,2,0)
 						advanced = gtk_tree_store_remove(treemodel, &iter);
-#else
-						gtk_tree_store_remove(treemodel, &iter);
-						advanced = (iter.stamp == 0) ? FALSE : TRUE;
-#endif
 						mail_dialog->total_count -= data->count;
 
 						if (data->purple_has_handle)
--- a/pidgin/gtkplugin.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkplugin.c	Thu Feb 04 05:30:35 2010 +0000
@@ -670,15 +670,11 @@
 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
 
 	website_button = gtk_event_box_new();
-#if GTK_CHECK_VERSION(2,4,0)
 	gtk_event_box_set_visible_window(GTK_EVENT_BOX(website_button), FALSE);
-#endif
 
 	plugin_website = GTK_LABEL(gtk_label_new(NULL));
-#if GTK_CHECK_VERSION(2,6,0)
 	g_object_set(G_OBJECT(plugin_website),
 		"ellipsize", PANGO_ELLIPSIZE_MIDDLE, NULL);
-#endif
 	gtk_misc_set_alignment(GTK_MISC(plugin_website), 0, 0);
 	gtk_container_add(GTK_CONTAINER(website_button),
 		GTK_WIDGET(plugin_website));
@@ -778,10 +774,8 @@
 							"markup", 1,
 							"foreground-set", 3,
 							NULL);
-#if GTK_CHECK_VERSION(2,6,0)
 	gtk_tree_view_column_set_expand (col, TRUE);
 	g_object_set(rendt, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
-#endif
 	gtk_tree_view_append_column (GTK_TREE_VIEW(event_view), col);
 	gtk_tree_view_column_set_sort_column_id(col, 1);
 	g_object_unref(G_OBJECT(ls));
--- a/pidgin/gtkpounce.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkpounce.c	Thu Feb 04 05:30:35 2010 +0000
@@ -1063,15 +1063,6 @@
 	return FALSE;
 }
 
-#if !GTK_CHECK_VERSION(2,2,0)
-static void
-count_selected_helper(GtkTreeModel *model, GtkTreePath *path,
-					GtkTreeIter *iter, gpointer user_data)
-{
-	(*(gint *)user_data)++;
-}
-#endif
-
 static void
 pounces_manager_connection_cb(PurpleConnection *gc, GtkWidget *add_button)
 {
@@ -1163,11 +1154,7 @@
 	PouncesManager *dialog = user_data;
 	int num_selected = 0;
 
-#if GTK_CHECK_VERSION(2,2,0)
 	num_selected = gtk_tree_selection_count_selected_rows(sel);
-#else
-	gtk_tree_selection_selected_foreach(sel, count_selected_helper, &num_selected);
-#endif
 
 	gtk_widget_set_sensitive(dialog->modify_button, (num_selected > 0));
 	gtk_widget_set_sensitive(dialog->delete_button, (num_selected > 0));
@@ -1549,34 +1536,19 @@
 			PROCESS_INFORMATION pi;
 			BOOL retval;
 			gchar *message = NULL;
+			STARTUPINFOW si;
+
+			wchar_t *wc_cmd = g_utf8_to_utf16(command,
+					-1, NULL, NULL, NULL);
 
 			memset(&pi, 0, sizeof(pi));
-
-			if (G_WIN32_HAVE_WIDECHAR_API ()) {
-				STARTUPINFOW si;
-				wchar_t *wc_cmd = g_utf8_to_utf16(command,
-						-1, NULL, NULL, NULL);
-
-				memset(&si, 0 , sizeof(si));
-				si.cb = sizeof(si);
+			memset(&si, 0 , sizeof(si));
+			si.cb = sizeof(si);
 
-				retval = CreateProcessW(NULL, wc_cmd, NULL,
-						NULL, 0, 0, NULL, NULL,
-						&si, &pi);
-				g_free(wc_cmd);
-			} else {
-				STARTUPINFOA si;
-				char *l_cmd = g_locale_from_utf8(command,
-						-1, NULL, NULL, NULL);
-
-				memset(&si, 0 , sizeof(si));
-				si.cb = sizeof(si);
-
-				retval = CreateProcessA(NULL, l_cmd, NULL,
-						NULL, 0, 0, NULL, NULL,
-						&si, &pi);
-				g_free(l_cmd);
-			}
+			retval = CreateProcessW(NULL, wc_cmd, NULL,
+					NULL, 0, 0, NULL, NULL,
+					&si, &pi);
+			g_free(wc_cmd);
 
 			if (retval) {
 				CloseHandle(pi.hProcess);
--- a/pidgin/gtkprefs.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkprefs.c	Thu Feb 04 05:30:35 2010 +0000
@@ -1419,10 +1419,8 @@
 					_("Bottom"), GTK_POS_BOTTOM,
 					_("Left"), GTK_POS_LEFT,
 					_("Right"), GTK_POS_RIGHT,
-#if GTK_CHECK_VERSION(2,6,0)
 					_("Left Vertical"), GTK_POS_LEFT|8,
 					_("Right Vertical"), GTK_POS_RIGHT|8,
-#endif
 					NULL);
 	gtk_size_group_add_widget(sg, label);
 	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
@@ -1501,7 +1499,7 @@
 		PIDGIN_PREFS_ROOT "/conversations/minimum_entry_lines",
 		1, 8, NULL);
 
-#if GTK_CHECK_VERSION(2,4,0) && defined _WIN32
+#ifdef _WIN32
 	{
 	GtkWidget *fontpref, *font_button, *hbox;
 	const char *font_name;
@@ -2712,12 +2710,7 @@
 static int
 prefs_notebook_add_page(const char *text, GtkWidget *page, int ind)
 {
-#if GTK_CHECK_VERSION(2,4,0)
 	return gtk_notebook_append_page(GTK_NOTEBOOK(prefsnotebook), page, gtk_label_new(text));
-#else
-	gtk_notebook_append_page(GTK_NOTEBOOK(prefsnotebook), page, gtk_label_new(text));
-	return gtk_notebook_page_num(GTK_NOTEBOOK(prefsnotebook), page);
-#endif
 }
 
 static void
--- a/pidgin/gtkrequest.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkrequest.c	Thu Feb 04 05:30:35 2010 +0000
@@ -626,9 +626,7 @@
 	/* Create the dialog. */
 	data->dialog = dialog = gtk_dialog_new();
 
-#if GTK_CHECK_VERSION(2,10,0)
 	gtk_window_set_deletable(GTK_WINDOW(data->dialog), FALSE);
-#endif
 
 	if (title != NULL)
 		gtk_window_set_title(GTK_WINDOW(dialog), title);
@@ -1503,7 +1501,6 @@
 	}
 }
 
-#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
 static void
 file_ok_check_if_exists_cb(GtkWidget *widget, gint response, PidginRequestData *data)
 {
@@ -1528,51 +1525,6 @@
 		}
 		g_free(current_folder);
 	}
-
-#else /* FILECHOOSER */
-
-static void
-file_ok_check_if_exists_cb(GtkWidget *button, PidginRequestData *data)
-{
-	const gchar *name;
-	gchar *current_folder;
-
-	generic_response_start(data);
-
-	name = gtk_file_selection_get_filename(GTK_FILE_SELECTION(data->dialog));
-
-	/* If name is a directory then change directories */
-	if (data->type == PURPLE_REQUEST_FILE) {
-		if (pidgin_check_if_dir(name, GTK_FILE_SELECTION(data->dialog)))
-			return;
-	}
-
-	current_folder = g_path_get_dirname(name);
-
-	g_free(data->u.file.name);
-	if (data->type == PURPLE_REQUEST_FILE)
-		data->u.file.name = g_strdup(name);
-	else
-	{
-		if (g_file_test(name, G_FILE_TEST_IS_DIR))
-			data->u.file.name = g_strdup(name);
-		else
-			data->u.file.name = g_strdup(current_folder);
-	}
-
-	if (current_folder != NULL) {
-		if (data->u.file.savedialog) {
-			purple_prefs_set_path(PIDGIN_PREFS_ROOT "/filelocations/last_save_folder", current_folder);
-		} else {
-			purple_prefs_set_path(PIDGIN_PREFS_ROOT "/filelocations/last_open_folder", current_folder);
-		}
-		g_free(current_folder);
-	}
-
-#endif /* FILECHOOSER */
-#if 0 /* mismatched curly braces */
-	}
-#endif
 	if ((data->u.file.savedialog == TRUE) &&
 		(g_file_test(data->u.file.name, G_FILE_TEST_EXISTS))) {
 		purple_request_action(data, NULL, _("That file already exists"),
@@ -1585,20 +1537,6 @@
 		file_yes_no_cb(data, 1);
 }
 
-#if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
-static gboolean
-file_cancel_cb(PidginRequestData *data)
-{
-	generic_response_start(data);
-
-	if (data->cbs[0] != NULL)
-		((PurpleRequestFileCb)data->cbs[0])(data->user_data, NULL);
-
-	purple_request_close(data->type, data);
-	return FALSE;
-}
-#endif /* FILECHOOSER */
-
 static void *
 pidgin_request_file(const char *title, const char *filename,
 					  gboolean savedialog,
@@ -1609,9 +1547,7 @@
 	PidginRequestData *data;
 	GtkWidget *filesel;
 	const gchar *current_folder;
-#if GTK_CHECK_VERSION(2,4,0)
 	gboolean folder_set = FALSE;
-#endif
 
 	data = g_new0(PidginRequestData, 1);
 	data->type = PURPLE_REQUEST_FILE;
@@ -1622,7 +1558,6 @@
 	data->cbs[1] = ok_cb;
 	data->u.file.savedialog = savedialog;
 
-#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
 	filesel = gtk_file_chooser_dialog_new(
 						title ? title : (savedialog ? _("Save File...")
 													: _("Open File...")),
@@ -1668,30 +1603,6 @@
 #endif
 	g_signal_connect(G_OBJECT(GTK_FILE_CHOOSER(filesel)), "response",
 					 G_CALLBACK(file_ok_check_if_exists_cb), data);
-#else /* FILECHOOSER */
-	filesel = gtk_file_selection_new(
-			title ? title : (savedialog ? _("Save File...")
-				: _("Open File...")));
-	if (savedialog) {
-		current_folder = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/filelocations/last_save_folder");
-	} else {
-		current_folder = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/filelocations/last_open_folder");
-	}
-	if (current_folder != NULL) {
-		gchar *path = g_strdup_printf("%s%s", current_folder, G_DIR_SEPARATOR_S);
-		gtk_file_selection_set_filename(GTK_FILE_SELECTION(filesel), path);
-		g_free(path);
-	}
-	if (filename != NULL)
-		gtk_file_selection_set_filename(GTK_FILE_SELECTION(filesel), filename);
-
-	g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(filesel)), "delete_event",
-							 G_CALLBACK(file_cancel_cb), data);
-	g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(filesel)->cancel_button),
-					 "clicked", G_CALLBACK(file_cancel_cb), data);
-	g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button), "clicked",
-					 G_CALLBACK(file_ok_check_if_exists_cb), data);
-#endif /* FILECHOOSER */
 
 	pidgin_auto_parent_window(filesel);
 
@@ -1719,7 +1630,6 @@
 	data->cbs[1] = ok_cb;
 	data->u.file.savedialog = FALSE;
 
-#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
 	dirsel = gtk_file_chooser_dialog_new(
 						title ? title : _("Select Folder..."),
 						NULL,
@@ -1734,16 +1644,6 @@
 
 	g_signal_connect(G_OBJECT(GTK_FILE_CHOOSER(dirsel)), "response",
 						G_CALLBACK(file_ok_check_if_exists_cb), data);
-#else
-	dirsel = gtk_file_selection_new(title ? title : _("Select Folder..."));
-
-	g_signal_connect_swapped(G_OBJECT(dirsel), "delete_event",
-							 G_CALLBACK(file_cancel_cb), data);
-	g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(dirsel)->cancel_button),
-					 "clicked", G_CALLBACK(file_cancel_cb), data);
-	g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(dirsel)->ok_button), "clicked",
-					 G_CALLBACK(file_ok_check_if_exists_cb), data);
-#endif
 
 	data->dialog = dirsel;
 	pidgin_auto_parent_window(dirsel);
--- a/pidgin/gtksavedstatuses.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtksavedstatuses.c	Thu Feb 04 05:30:35 2010 +0000
@@ -34,7 +34,6 @@
 #include "util.h"
 
 #include "gtkblist.h"
-#include "gtkexpander.h"
 #include "pidgin.h"
 #include "gtkimhtml.h"
 #include "gtkimhtmltoolbar.h"
@@ -180,23 +179,6 @@
 	return FALSE;
 }
 
-#if !GTK_CHECK_VERSION(2,2,0)
-static void
-count_selected_helper(GtkTreeModel *model, GtkTreePath *path,
-					GtkTreeIter *iter, gpointer user_data)
-{
-	(*(gint *)user_data)++;
-}
-
-static void
-list_selected_helper(GtkTreeModel *model, GtkTreePath *path,
-					GtkTreeIter *iter, gpointer user_data)
-{
-	GList **list = (GList **)user_data;
-	*list = g_list_append(*list, gtk_tree_path_copy(path));
-}
-#endif
-
 static void
 status_window_use_cb(GtkButton *button, StatusWindow *dialog)
 {
@@ -207,11 +189,7 @@
 
 	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview));
 
-#if GTK_CHECK_VERSION(2,2,0)
 	num_selected = gtk_tree_selection_count_selected_rows(selection);
-#else
-	gtk_tree_selection_selected_foreach(selection, count_selected_helper, &num_selected);
-#endif
 	if (num_selected != 1)
 		/*
 		 * This shouldn't happen because the "Use" button should have
@@ -219,11 +197,7 @@
 		 */
 		return;
 
-#if GTK_CHECK_VERSION(2,2,0)
 	list = gtk_tree_selection_get_selected_rows(selection, NULL);
-#else
-	gtk_tree_selection_selected_foreach(selection, list_selected_helper, &list);
-#endif
 
 	if (gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model),
 								&iter, list->data))
@@ -311,11 +285,7 @@
 	gpointer handle;
 
 	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview));
-#if GTK_CHECK_VERSION(2,2,0)
 	sel_paths = gtk_tree_selection_get_selected_rows(selection, NULL);
-#else
-	gtk_tree_selection_selected_foreach(selection, list_selected_helper, &sel_paths);
-#endif
 
 	/* This is ugly because we're not allowed to modify the model from within
 	 * gtk_tree_selection_selected_foreach() and the GtkTreePaths can become invalid
@@ -365,11 +335,7 @@
 	int num_selected;
 	GtkTreeModel *model = GTK_TREE_MODEL(dialog->model);
 
-#if GTK_CHECK_VERSION(2,2,0)
 	sel_paths = gtk_tree_selection_get_selected_rows(sel, NULL);
-#else
-	gtk_tree_selection_selected_foreach(sel, list_selected_helper, &sel_paths);
-#endif
 
 	for (tmp = sel_paths, num_selected = 0; tmp; tmp = tmp->next, num_selected++) {
 		GtkTreeIter iter;
@@ -521,9 +487,7 @@
 	gtk_tree_view_column_pack_start(column, renderer, TRUE);
 	gtk_tree_view_column_add_attribute(column, renderer, "text",
 									   STATUS_WINDOW_COLUMN_TITLE);
-#if GTK_CHECK_VERSION(2,6,0)
 	g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
-#endif
 
 	column = gtk_tree_view_column_new();
 	gtk_tree_view_column_set_title(column, _("Type"));
@@ -550,9 +514,7 @@
 	gtk_tree_view_column_pack_start(column, renderer, TRUE);
 	gtk_tree_view_column_add_attribute(column, renderer, "text",
 									   STATUS_WINDOW_COLUMN_MESSAGE);
-#if GTK_CHECK_VERSION(2,6,0)
 	g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
-#endif
 
 	/* Enable CTRL+F searching */
 	gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview), STATUS_WINDOW_COLUMN_TITLE);
--- a/pidgin/gtkscrollbook.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkscrollbook.c	Thu Feb 04 05:30:35 2010 +0000
@@ -80,11 +80,7 @@
 {
 	int index, count;
 	index = gtk_notebook_get_current_page(GTK_NOTEBOOK(scroll_book->notebook));
-#if GTK_CHECK_VERSION(2,2,0)
 	count = gtk_notebook_get_n_pages(GTK_NOTEBOOK(scroll_book->notebook));
-#else
-	count = g_list_length(GTK_NOTEBOOK(scroll_book->notebook)->children);
-#endif
 
 	if (index + 1 < count)
 		gtk_notebook_set_current_page(GTK_NOTEBOOK(scroll_book->notebook), index + 1);
@@ -130,11 +126,7 @@
 {
 	int count;
 	int index = gtk_notebook_get_current_page(GTK_NOTEBOOK(scroll_book->notebook));
-#if GTK_CHECK_VERSION(2,2,0)
 	count = gtk_notebook_get_n_pages(GTK_NOTEBOOK(scroll_book->notebook));
-#else
-	count = g_list_length(GTK_NOTEBOOK(scroll_book->notebook)->children);
-#endif
 	refresh_scroll_box(scroll_book, index, count);
 }
 
@@ -149,11 +141,7 @@
 switch_page_cb(GtkNotebook *notebook, GtkNotebookPage *page, guint page_num, PidginScrollBook *scroll_book)
 {
 	int count;
-#if GTK_CHECK_VERSION(2,2,0)
 	count = gtk_notebook_get_n_pages(GTK_NOTEBOOK(scroll_book->notebook));
-#else
-	count = g_list_length(GTK_NOTEBOOK(scroll_book->notebook)->children);
-#endif
 	refresh_scroll_box(scroll_book, page_num, count);
 }
 
@@ -268,9 +256,7 @@
 	/* Close */
 	eb = gtk_event_box_new();
 	gtk_box_pack_end(GTK_BOX(scroll_book->hbox), eb, FALSE, FALSE, 0);
-#if GTK_CHECK_VERSION(2,4,0)
 	gtk_event_box_set_visible_window(GTK_EVENT_BOX(eb), FALSE);
-#endif
 	gtk_widget_set_events(eb, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
 	close_button = gtk_label_new("×");
 	g_signal_connect(G_OBJECT(eb), "enter-notify-event", G_CALLBACK(close_button_entered_cb), close_button);
--- a/pidgin/gtksession.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtksession.c	Thu Feb 04 05:30:35 2010 +0000
@@ -163,10 +163,8 @@
 		ret[j++] = g_strdup(config_dir);
 	}
 
-#if GTK_CHECK_VERSION(2,2,0)
 	ret[j++] = g_strdup("--display");
 	ret[j++] = g_strdup((gchar *)gdk_display_get_name(gdk_display_get_default()));
-#endif
 
 	ret[j++] = NULL;
 
--- a/pidgin/gtksound.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtksound.c	Thu Feb 04 05:30:35 2010 +0000
@@ -72,7 +72,8 @@
 	{N_("Others talk in chat"), "chat_msg_recv", "receive.wav"},
 	/* this isn't a terminator, it's the buddy pounce default sound event ;-) */
 	{NULL, "pounce_default", "alert.wav"},
-	{N_("Someone says your username in chat"), "nick_said", "alert.wav"}
+	{N_("Someone says your username in chat"), "nick_said", "alert.wav"},
+	{N_("Attention received"), "got_attention", "alert.wav"}
 };
 
 static gboolean
@@ -144,7 +145,7 @@
 				   char *message, PurpleConversation *conv,
 				   PurpleMessageFlags flags, PurpleSoundEventID event)
 {
-	if (flags & PURPLE_MESSAGE_DELAYED)
+	if (flags & PURPLE_MESSAGE_DELAYED || flags & PURPLE_MESSAGE_NOTIFY)
 		return;
 
 	if (conv==NULL)
@@ -199,7 +200,7 @@
 {
 	PurpleConvChat *chat;
 
-	if (flags & PURPLE_MESSAGE_DELAYED)
+	if (flags & PURPLE_MESSAGE_DELAYED || flags & PURPLE_MESSAGE_NOTIFY)
 		return;
 
 	chat = purple_conversation_get_chat_data(conv);
@@ -219,6 +220,13 @@
 		play_conv_event(conv, event);
 }
 
+static void
+got_attention_cb(PurpleAccount *account, const char *who, 
+	PurpleConversation *conv, guint type, PurpleSoundEventID event)
+{
+	play_conv_event(conv, event);
+}
+
 /*
  * We mute sounds for the 10 seconds after you log in so that
  * you don't get flooded with sounds when the blist shows all
@@ -299,6 +307,10 @@
 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/sound/enabled/pounce_default", TRUE);
 	purple_prefs_add_path(PIDGIN_PREFS_ROOT "/sound/file/pounce_default", "");
 	purple_prefs_add_string(PIDGIN_PREFS_ROOT "/sound/theme", "");
+	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/sound/enabled/sent_attention", TRUE);
+	purple_prefs_add_path(PIDGIN_PREFS_ROOT "/sound/file/sent_attention", "");
+	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/sound/enabled/got_attention", TRUE);
+	purple_prefs_add_path(PIDGIN_PREFS_ROOT "/sound/file/got_attention", "");
 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/sound/conv_focus", TRUE);
 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/sound/mute", FALSE);
 	purple_prefs_add_path(PIDGIN_PREFS_ROOT "/sound/command", "");
@@ -345,6 +357,12 @@
 	purple_signal_connect(conv_handle, "received-chat-msg",
 						gtk_sound_handle, PURPLE_CALLBACK(chat_msg_received_cb),
 						GINT_TO_POINTER(PURPLE_SOUND_CHAT_SAY));
+	purple_signal_connect(conv_handle, "got-attention", gtk_sound_handle,
+						PURPLE_CALLBACK(got_attention_cb),
+						  GINT_TO_POINTER(PURPLE_SOUND_GOT_ATTENTION));
+	/* for the time being, don't handle sent-attention here, since playing a
+	 sound would result induplicate sounds. And fixing that would require changing the
+	 conversation signal for msg-recv */	
 }
 
 static void
@@ -539,18 +557,12 @@
 #else /* _WIN32 */
 	purple_debug_info("sound", "Playing %s\n", filename);
 
-	if (G_WIN32_HAVE_WIDECHAR_API ()) {
+	{
 		wchar_t *wc_filename = g_utf8_to_utf16(filename,
 				-1, NULL, NULL, NULL);
 		if (!PlaySoundW(wc_filename, NULL, SND_ASYNC | SND_FILENAME))
 			purple_debug(PURPLE_DEBUG_ERROR, "sound", "Error playing sound.\n");
 		g_free(wc_filename);
-	} else {
-		char *l_filename = g_locale_from_utf8(filename,
-				-1, NULL, NULL, NULL);
-		if (!PlaySoundA(l_filename, NULL, SND_ASYNC | SND_FILENAME))
-			purple_debug(PURPLE_DEBUG_ERROR, "sound", "Error playing sound.\n");
-		g_free(l_filename);
 	}
 #endif /* _WIN32 */
 
--- a/pidgin/gtkstatusbox.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkstatusbox.c	Thu Feb 04 05:30:35 2010 +0000
@@ -1180,7 +1180,6 @@
 	return FALSE;
 }
 
-#if GTK_CHECK_VERSION(2,6,0)
 static gboolean
 dropdown_store_row_separator_func(GtkTreeModel *model,
 								  GtkTreeIter *iter, gpointer data)
@@ -1194,7 +1193,6 @@
 
 	return FALSE;
 }
-#endif
 
 static void
 cache_pixbufs(PidginStatusBox *status_box)
@@ -1305,11 +1303,9 @@
 static void
 pidgin_status_box_list_position (PidginStatusBox *status_box, int *x, int *y, int *width, int *height)
 {
-#if GTK_CHECK_VERSION(2,2,0)
   GdkScreen *screen;
   gint monitor_num;
   GdkRectangle monitor;
-#endif
   GtkRequisition popup_req;
   GtkPolicyType hpolicy, vpolicy;
 
@@ -1335,7 +1331,6 @@
 
   *height = popup_req.height;
 
-#if GTK_CHECK_VERSION(2,2,0)
   screen = gtk_widget_get_screen (GTK_WIDGET (status_box));
   monitor_num = gdk_screen_get_monitor_at_window (screen,
 						  GTK_WIDGET (status_box)->window);
@@ -1368,7 +1363,6 @@
       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (status_box->scrolled_window),
 				      hpolicy, vpolicy);
     }
-#endif
 }
 
 static gboolean
@@ -1376,29 +1370,20 @@
 		      guint32    activate_time,
 		      gboolean   grab_keyboard)
 {
-  if ((gdk_pointer_grab (window, TRUE,
+	if ((gdk_pointer_grab (window, TRUE,
 			 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
 			 GDK_POINTER_MOTION_MASK,
 			 NULL, NULL, activate_time) == 0))
-    {
-      if (!grab_keyboard ||
-	  gdk_keyboard_grab (window, TRUE,
-			     activate_time) == 0)
-	return TRUE;
-      else
 	{
-#if GTK_CHECK_VERSION(2,2,0)
-	  gdk_display_pointer_ungrab (gdk_drawable_get_display (window),
-				      activate_time);
-#else
-	  gdk_pointer_ungrab(activate_time);
-	  gdk_keyboard_ungrab(activate_time);
-#endif
-	  return FALSE;
+		if (!grab_keyboard || gdk_keyboard_grab (window, TRUE, activate_time) == 0)
+			return TRUE;
+		else {
+			gdk_display_pointer_ungrab (gdk_drawable_get_display (window), activate_time);
+			return FALSE;
+		}
 	}
-    }
-
-  return FALSE;
+
+	return FALSE;
 }
 
 
@@ -1793,9 +1778,7 @@
 	gtk_box_pack_start(GTK_BOX(status_box->hbox), status_box->vsep, FALSE, FALSE, 0);
 	gtk_box_pack_start(GTK_BOX(status_box->hbox), status_box->arrow, FALSE, FALSE, 0);
 	gtk_widget_show_all(status_box->toggle_button);
-#if GTK_CHECK_VERSION(2,4,0)
 	gtk_button_set_focus_on_click(GTK_BUTTON(status_box->toggle_button), FALSE);
-#endif
 
 	text_rend = gtk_cell_renderer_text_new();
 	icon_rend = gtk_cell_renderer_pixbuf_new();
@@ -1809,14 +1792,10 @@
 	}
 
 	gtk_window_set_resizable (GTK_WINDOW (status_box->popup_window), FALSE);
-#if GTK_CHECK_VERSION(2,10,0)
 	gtk_window_set_type_hint (GTK_WINDOW (status_box->popup_window),
 			GDK_WINDOW_TYPE_HINT_POPUP_MENU);
-#endif
-#if GTK_CHECK_VERSION(2,2,0)
 	gtk_window_set_screen (GTK_WINDOW (status_box->popup_window),
 			gtk_widget_get_screen (GTK_WIDGET (status_box)));
-#endif
 	status_box->popup_frame = gtk_frame_new (NULL);
 	gtk_frame_set_shadow_type (GTK_FRAME (status_box->popup_frame),
 			GTK_SHADOW_ETCHED_IN);
@@ -1843,10 +1822,8 @@
 	gtk_tree_selection_set_mode (sel, GTK_SELECTION_BROWSE);
 	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (status_box->tree_view),
 			FALSE);
-#if GTK_CHECK_VERSION(2,6,0)
 	gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (status_box->tree_view),
 			TRUE);
-#endif
 	gtk_tree_view_set_model (GTK_TREE_VIEW (status_box->tree_view),
 			GTK_TREE_MODEL(status_box->dropdown_store));
 	status_box->column = gtk_tree_view_column_new ();
@@ -1864,9 +1841,7 @@
 	gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(status_box->tree_view),
 				pidgin_tree_view_search_equal_func, NULL, NULL);
 
-#if GTK_CHECK_VERSION(2, 6, 0)
 	g_object_set(text_rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
-#endif
 
 	status_box->icon_rend = gtk_cell_renderer_pixbuf_new();
 	status_box->text_rend = gtk_cell_renderer_text_new();
@@ -1877,9 +1852,7 @@
 	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(status_box->cell_view), status_box->icon_rend, "stock-id", ICON_STOCK_COLUMN, NULL);
 	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(status_box->cell_view), status_box->text_rend, "markup", TEXT_COLUMN, NULL);
 	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(status_box->cell_view), emblem_rend, "pixbuf", EMBLEM_COLUMN, "visible", EMBLEM_VISIBLE_COLUMN, NULL);
-#if GTK_CHECK_VERSION(2, 6, 0)
 	g_object_set(status_box->text_rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
-#endif
 
 	status_box->vbox = gtk_vbox_new(0, FALSE);
 	status_box->sw = pidgin_create_imhtml(FALSE, &status_box->imhtml, NULL, NULL);
@@ -1924,9 +1897,7 @@
 	g_signal_connect(G_OBJECT(status_box->tree_view), "cursor-changed",
 					 G_CALLBACK(treeview_cursor_changed_cb), status_box->dropdown_store);
 
-#if GTK_CHECK_VERSION(2,6,0)
 	gtk_tree_view_set_row_separator_func(GTK_TREE_VIEW(status_box->tree_view), dropdown_store_row_separator_func, NULL, NULL);
-#endif
 
 	status_box->token_status_account = check_active_accounts_for_identical_statuses();
 
@@ -2210,14 +2181,12 @@
 {
 	/* Don't do anything unless GTK actually supports
 	 * gtk_combo_box_set_row_separator_func */
-#if GTK_CHECK_VERSION(2,6,0)
 	GtkTreeIter iter;
 
 	gtk_list_store_append(status_box->dropdown_store, &iter);
 	gtk_list_store_set(status_box->dropdown_store, &iter,
 			   TYPE_COLUMN, PIDGIN_STATUS_BOX_TYPE_SEPARATOR,
 			   -1);
-#endif
 }
 
 void
@@ -2241,7 +2210,6 @@
 static void
 pixbuf_size_prepared_cb(GdkPixbufLoader *loader, int width, int height, gpointer data)
 {
-#if GTK_CHECK_VERSION(2,2,0)
 	int w, h;
 	GtkIconSize icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_MEDIUM);
 	gtk_icon_size_lookup(icon_size, &w, &h);
@@ -2250,7 +2218,6 @@
 	else if (width > height)
 		h = height * w / width;
 	gdk_pixbuf_loader_set_size(loader, w, h);
-#endif
 }
 
 static void
--- a/pidgin/gtkutils.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkutils.c	Thu Feb 04 05:30:35 2010 +0000
@@ -1247,7 +1247,6 @@
 							gboolean *push_in,
 							gpointer data)
 {
-#if GTK_CHECK_VERSION(2,2,0)
 	GtkWidget *widget;
 	GtkRequisition requisition;
 	GdkScreen *screen;
@@ -1388,7 +1387,6 @@
 	{
 		*y = monitor.y;
 	}
-#endif
 }
 
 
@@ -1630,7 +1628,6 @@
 			char key[64];
 			const char *itemname = NULL;
 
-#if GTK_CHECK_VERSION(2,6,0)
 			const char * const *langs;
 			int i;
 			langs = g_get_language_names();
@@ -1639,15 +1636,7 @@
 				itemname = purple_desktop_item_get_string(item, key);
 				break;
 			}
-#else
-			const char *lang = g_getenv("LANG");
-			char *dot;
-			dot = strchr(lang, '.');
-			if (dot)
-				*dot = '\0';
-			g_snprintf(key, sizeof(key), "Name[%s]", lang);
-			itemname = purple_desktop_item_get_string(item, key);
-#endif
+
 			if (!itemname)
 				itemname = purple_desktop_item_get_string(item, "Name");
 
@@ -1664,10 +1653,13 @@
 						       purple_desktop_item_get_string(item, "URL"), itemname);
 				break;
 			default:
-				/* I don't know if we really want to do anything here.  Most of the desktop item types are crap like
-				 * "MIME Type" (I have no clue how that would be a desktop item) and "Comment"... nothing we can really
-				 * send.  The only logical one is "Application," but do we really want to send a binary and nothing else?
-				 * Probably not.  I'll just give an error and return. */
+				/* I don't know if we really want to do anything here.  Most of
+				 * the desktop item types are crap like "MIME Type" (I have no
+				 * clue how that would be a desktop item) and "Comment"...
+				 * nothing we can really send.  The only logical one is
+				 * "Application," but do we really want to send a binary and
+				 * nothing else? Probably not.  I'll just give an error and
+				 * return. */
 				/* The original patch sent the icon used by the launcher.  That's probably wrong */
 				purple_notify_error(NULL, NULL, _("Cannot send launcher"),
 				                    _("You dragged a desktop launcher. Most "
@@ -1862,10 +1854,6 @@
 	return menuitem;
 }
 
-#if GTK_CHECK_VERSION(2,3,0)
-# define NEW_STYLE_COMPLETION
-#endif
-
 typedef struct
 {
 	GtkWidget *entry;
@@ -1874,97 +1862,9 @@
 	PidginFilterBuddyCompletionEntryFunc filter_func;
 	gpointer filter_func_user_data;
 
-#ifdef NEW_STYLE_COMPLETION
 	GtkListStore *store;
-#else
-	GCompletion *completion;
-	gboolean completion_started;
-	GList *log_items;
-#endif /* NEW_STYLE_COMPLETION */
 } PidginCompletionData;
 
-#ifndef NEW_STYLE_COMPLETION
-static gboolean
-completion_entry_event(GtkEditable *entry, GdkEventKey *event,
-					   PidginCompletionData *data)
-{
-	int pos, end_pos;
-
-	if (event->type == GDK_KEY_PRESS && event->keyval == GDK_Tab)
-	{
-		gtk_editable_get_selection_bounds(entry, &pos, &end_pos);
-
-		if (data->completion_started &&
-			pos != end_pos && pos > 1 &&
-			end_pos == strlen(gtk_entry_get_text(GTK_ENTRY(entry))))
-		{
-			gtk_editable_select_region(entry, 0, 0);
-			gtk_editable_set_position(entry, -1);
-
-			return TRUE;
-		}
-	}
-	else if (event->type == GDK_KEY_PRESS && event->length > 0)
-	{
-		char *prefix, *nprefix;
-
-		gtk_editable_get_selection_bounds(entry, &pos, &end_pos);
-
-		if (data->completion_started &&
-			pos != end_pos && pos > 1 &&
-			end_pos == strlen(gtk_entry_get_text(GTK_ENTRY(entry))))
-		{
-			char *temp;
-
-			temp = gtk_editable_get_chars(entry, 0, pos);
-			prefix = g_strconcat(temp, event->string, NULL);
-			g_free(temp);
-		}
-		else if (pos == end_pos && pos > 1 &&
-				 end_pos == strlen(gtk_entry_get_text(GTK_ENTRY(entry))))
-		{
-			prefix = g_strconcat(gtk_entry_get_text(GTK_ENTRY(entry)),
-								 event->string, NULL);
-		}
-		else
-			return FALSE;
-
-		pos = strlen(prefix);
-		nprefix = NULL;
-
-		g_completion_complete(data->completion, prefix, &nprefix);
-
-		if (nprefix != NULL)
-		{
-			gtk_entry_set_text(GTK_ENTRY(entry), nprefix);
-			gtk_editable_set_position(entry, pos);
-			gtk_editable_select_region(entry, pos, -1);
-
-			data->completion_started = TRUE;
-
-			g_free(nprefix);
-			g_free(prefix);
-
-			return TRUE;
-		}
-
-		g_free(prefix);
-	}
-
-	return FALSE;
-}
-
-static void
-destroy_completion_data(GtkWidget *w, PidginCompletionData *data)
-{
-	g_list_foreach(data->completion->items, (GFunc)g_free, NULL);
-	g_completion_free(data->completion);
-
-	g_free(data);
-}
-#endif /* !NEW_STYLE_COMPLETION */
-
-#ifdef NEW_STYLE_COMPLETION
 static gboolean buddyname_completion_match_func(GtkEntryCompletion *completion,
 		const gchar *key, GtkTreeIter *iter, gpointer user_data)
 {
@@ -2098,7 +1998,6 @@
 
 	g_free(normalized_buddyname);
 }
-#endif /* NEW_STYLE_COMPLETION */
 
 static void get_log_set_name(PurpleLogSet *set, gpointer value, PidginCompletionData *data)
 {
@@ -2113,14 +2012,8 @@
 		entry.entry.logged_buddy = set;
 
 		if (filter_func(&entry, user_data)) {
-#ifdef NEW_STYLE_COMPLETION
 			add_buddyname_autocomplete_entry(data->store,
 												NULL, NULL, set->account, set->name);
-#else
-			/* Steal the name for the GCompletion. */
-			data->log_items = g_list_append(data->log_items, set->name);
-			set->name = set->normalized_name = NULL;
-#endif /* NEW_STYLE_COMPLETION */
 		}
 	}
 }
@@ -2133,14 +2026,7 @@
 	gpointer user_data = data->filter_func_user_data;
 	GHashTable *sets;
 
-#ifdef NEW_STYLE_COMPLETION
 	gtk_list_store_clear(data->store);
-#else
-	GList *item = g_list_append(NULL, NULL);
-
-	g_list_foreach(data->completion->items, (GFunc)g_free, NULL);
-	g_completion_clear_items(data->completion);
-#endif /* NEW_STYLE_COMPLETION */
 
 	for (gnode = purple_get_blist()->root; gnode != NULL; gnode = gnode->next)
 	{
@@ -2159,35 +2045,21 @@
 				entry.entry.buddy = (PurpleBuddy *) bnode;
 
 				if (filter_func(&entry, user_data)) {
-#ifdef NEW_STYLE_COMPLETION
 					add_buddyname_autocomplete_entry(data->store,
 														((PurpleContact *)cnode)->alias,
 														purple_buddy_get_contact_alias(entry.entry.buddy),
 														entry.entry.buddy->account,
 														entry.entry.buddy->name
 													 );
-#else
-					item->data = g_strdup(entry.entry.buddy->name);
-					g_completion_add_items(data->completion, item);
-#endif /* NEW_STYLE_COMPLETION */
 				}
 			}
 		}
 	}
 
-#ifndef NEW_STYLE_COMPLETION
-	g_list_free(item);
-	data->log_items = NULL;
-#endif /* NEW_STYLE_COMPLETION */
-
 	sets = purple_log_get_log_sets();
 	g_hash_table_foreach(sets, (GHFunc)get_log_set_name, data);
 	g_hash_table_destroy(sets);
 
-#ifndef NEW_STYLE_COMPLETION
-	g_completion_add_items(data->completion, data->log_items);
-	g_list_free(data->log_items);
-#endif /* NEW_STYLE_COMPLETION */
 }
 
 static void
@@ -2208,7 +2080,6 @@
 {
 	PidginCompletionData *data;
 
-#ifdef NEW_STYLE_COMPLETION
 	/*
 	 * Store the displayed completion value, the buddy name, the UTF-8
 	 * normalized & casefolded buddy name, the UTF-8 normalized &
@@ -2252,33 +2123,6 @@
 
 	gtk_entry_completion_set_text_column(completion, 0);
 
-#else /* !NEW_STYLE_COMPLETION */
-
-	data = g_new0(PidginCompletionData, 1);
-
-	data->entry = entry;
-	data->accountopt = accountopt;
-	if (filter_func == NULL) {
-		data->filter_func = pidgin_screenname_autocomplete_default_filter;
-		data->filter_func_user_data = NULL;
-	} else {
-		data->filter_func = filter_func;
-		data->filter_func_user_data = user_data;
-	}
-	data->completion = g_completion_new(NULL);
-	data->completion_started = FALSE;
-
-	add_completion_list(data);
-
-	g_completion_set_compare(data->completion, g_ascii_strncasecmp);
-
-	g_signal_connect(G_OBJECT(entry), "event",
-					 G_CALLBACK(completion_entry_event), data);
-	g_signal_connect(G_OBJECT(entry), "destroy",
-					 G_CALLBACK(destroy_completion_data), data);
-
-#endif /* !NEW_STYLE_COMPLETION */
-
 	purple_signal_connect(purple_connections_get_handle(), "signed-on", entry,
 						PURPLE_CALLBACK(repopulate_autocomplete), data);
 	purple_signal_connect(purple_connections_get_handle(), "signed-off", entry,
@@ -2322,11 +2166,7 @@
 	gdk_window_set_cursor(widget->window, cursor);
 	gdk_cursor_unref(cursor);
 
-#if GTK_CHECK_VERSION(2,4,0)
 	gdk_display_flush(gdk_drawable_get_display(GDK_DRAWABLE(widget->window)));
-#else
-	gdk_flush();
-#endif
 }
 
 void pidgin_clear_cursor(GtkWidget *widget)
@@ -2347,23 +2187,6 @@
 	gpointer data;
 };
 
-#if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
-static void
-icon_filesel_delete_cb(GtkWidget *w, struct _icon_chooser *dialog)
-{
-	if (dialog->icon_filesel != NULL)
-		gtk_widget_destroy(dialog->icon_filesel);
-
-	if (dialog->callback)
-		dialog->callback(NULL, dialog->data);
-
-	g_free(dialog);
-}
-#endif /* FILECHOOSER */
-
-
-
-#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
 static void
 icon_filesel_choose_cb(GtkWidget *widget, gint response, struct _icon_chooser *dialog)
 {
@@ -2387,33 +2210,7 @@
 		g_free(current_folder);
 	}
 
-#else /* FILECHOOSER */
-static void
-icon_filesel_choose_cb(GtkWidget *w, struct _icon_chooser *dialog)
-{
-	char *filename, *current_folder;
-
-	filename = g_strdup(gtk_file_selection_get_filename(
-				GTK_FILE_SELECTION(dialog->icon_filesel)));
-
-	/* If they typed in a directory, change there */
-	if (pidgin_check_if_dir(filename,
-				GTK_FILE_SELECTION(dialog->icon_filesel)))
-	{
-		g_free(filename);
-		return;
-	}
-
-	current_folder = g_path_get_dirname(filename);
-	if (current_folder != NULL) {
-		purple_prefs_set_path(PIDGIN_PREFS_ROOT "/filelocations/last_icon_folder", current_folder);
-		g_free(current_folder);
-	}
-
-#endif /* FILECHOOSER */
-#if 0 /* mismatched curly braces */
-	}
-#endif
+
 	if (dialog->callback)
 		dialog->callback(filename, dialog->data);
 	gtk_widget_destroy(dialog->icon_filesel);
@@ -2423,11 +2220,7 @@
 
 
 static void
-#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
 icon_preview_change_cb(GtkFileChooser *widget, struct _icon_chooser *dialog)
-#else /* FILECHOOSER */
-icon_preview_change_cb(GtkTreeSelection *sel, struct _icon_chooser *dialog)
-#endif /* FILECHOOSER */
 {
 	GdkPixbuf *pixbuf, *scale;
 	int height, width;
@@ -2435,13 +2228,8 @@
 	struct stat st;
 	char *filename;
 
-#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
 	filename = gtk_file_chooser_get_preview_filename(
 					GTK_FILE_CHOOSER(dialog->icon_filesel));
-#else /* FILECHOOSER */
-	filename = g_strdup(gtk_file_selection_get_filename(
-		GTK_FILE_SELECTION(dialog->icon_filesel)));
-#endif /* FILECHOOSER */
 
 	if (!filename || g_stat(filename, &st) || !(pixbuf = gdk_pixbuf_new_from_file(filename, NULL)))
 	{
@@ -2477,20 +2265,13 @@
 GtkWidget *pidgin_buddy_icon_chooser_new(GtkWindow *parent, void(*callback)(const char *, gpointer), gpointer data) {
 	struct _icon_chooser *dialog = g_new0(struct _icon_chooser, 1);
 
-#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
 	GtkWidget *vbox;
-#else
-	GtkWidget *hbox;
-	GtkWidget *tv;
-	GtkTreeSelection *sel;
-#endif /* FILECHOOSER */
 	const char *current_folder;
 
 	dialog->callback = callback;
 	dialog->data = data;
 
 	current_folder = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/filelocations/last_icon_folder");
-#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
 
 	dialog->icon_filesel = gtk_file_chooser_dialog_new(_("Buddy Icon"),
 							   parent,
@@ -2521,39 +2302,6 @@
 	g_signal_connect(G_OBJECT(dialog->icon_filesel), "response",
 					 G_CALLBACK(icon_filesel_choose_cb), dialog);
 	icon_preview_change_cb(NULL, dialog);
-#else /* FILECHOOSER */
-	dialog->icon_filesel = gtk_file_selection_new(_("Buddy Icon"));
-	dialog->icon_preview = gtk_image_new();
-	dialog->icon_text = gtk_label_new(NULL);
-	if ((current_folder != NULL) && (*current_folder != '\0'))
-		gtk_file_selection_set_filename(GTK_FILE_SELECTION(dialog->icon_filesel),
-										current_folder);
-
-	gtk_widget_set_size_request(GTK_WIDGET(dialog->icon_preview),-1, 50);
-	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
-	gtk_box_pack_start(
-		GTK_BOX(GTK_FILE_SELECTION(dialog->icon_filesel)->main_vbox),
-		hbox, FALSE, FALSE, 0);
-	gtk_box_pack_end(GTK_BOX(hbox), dialog->icon_preview,
-			 FALSE, FALSE, 0);
-	gtk_box_pack_end(GTK_BOX(hbox), dialog->icon_text, FALSE, FALSE, 0);
-
-	tv = GTK_FILE_SELECTION(dialog->icon_filesel)->file_list;
-	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv));
-
-	g_signal_connect(G_OBJECT(sel), "changed",
-					 G_CALLBACK(icon_preview_change_cb), dialog);
-	g_signal_connect(
-		G_OBJECT(GTK_FILE_SELECTION(dialog->icon_filesel)->ok_button),
-		"clicked",
-		G_CALLBACK(icon_filesel_choose_cb), dialog);
-	g_signal_connect(
-		G_OBJECT(GTK_FILE_SELECTION(dialog->icon_filesel)->cancel_button),
-		"clicked",
-		G_CALLBACK(icon_filesel_delete_cb), dialog);
-	g_signal_connect(G_OBJECT(dialog->icon_filesel), "destroy",
-					 G_CALLBACK(icon_filesel_delete_cb), dialog);
-#endif /* FILECHOOSER */
 
 #ifdef _WIN32
 	g_signal_connect(G_OBJECT(dialog->icon_filesel), "show",
@@ -2564,7 +2312,6 @@
 }
 
 
-#if GTK_CHECK_VERSION(2,2,0)
 static gboolean
 str_array_match(char **a, char **b)
 {
@@ -2578,22 +2325,16 @@
 				return TRUE;
 	return FALSE;
 }
-#endif
 
 gpointer
 pidgin_convert_buddy_icon(PurplePlugin *plugin, const char *path, size_t *len)
 {
 	PurplePluginProtocolInfo *prpl_info;
-#if GTK_CHECK_VERSION(2,2,0)
 	char **prpl_formats;
 	int width, height;
 	char **pixbuf_formats = NULL;
 	GdkPixbufFormat *format;
 	GdkPixbuf *pixbuf;
-#if !GTK_CHECK_VERSION(2,4,0)
-	GdkPixbufLoader *loader;
-#endif
-#endif
 	gchar *contents;
 	gsize length;
 
@@ -2602,22 +2343,8 @@
 	g_return_val_if_fail(prpl_info->icon_spec.format != NULL, NULL);
 
 
-#if GTK_CHECK_VERSION(2,2,0)
-#if GTK_CHECK_VERSION(2,4,0)
 	format = gdk_pixbuf_get_file_info(path, &width, &height);
-#else
-	loader = gdk_pixbuf_loader_new();
-	if (g_file_get_contents(path, &contents, &length, NULL)) {
-		gdk_pixbuf_loader_write(loader, contents, length, NULL);
-		g_free(contents);
-	}
-	gdk_pixbuf_loader_close(loader, NULL);
-	pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
-	width = gdk_pixbuf_get_width(pixbuf);
-	height = gdk_pixbuf_get_height(pixbuf);
-	format = gdk_pixbuf_loader_get_format(loader);
-	g_object_unref(G_OBJECT(loader));
-#endif
+
 	if (format == NULL)
 		return NULL;
 
@@ -2629,25 +2356,18 @@
 		   prpl_info->icon_spec.max_width >= width &&
 		   prpl_info->icon_spec.min_height <= height &&
 		   prpl_info->icon_spec.max_height >= height)))                   /* The icon is the correct size */
-#endif
 	{
-#if GTK_CHECK_VERSION(2,2,0)
 		g_strfreev(prpl_formats);
 		g_strfreev(pixbuf_formats);
-#endif
+
 		/* We don't need to scale the image. */
-
 		contents = NULL;
 		if (!g_file_get_contents(path, &contents, &length, NULL))
 		{
 			g_free(contents);
-#if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0)
-		g_object_unref(G_OBJECT(pixbuf));
-#endif
 			return NULL;
 		}
 	}
-#if GTK_CHECK_VERSION(2,2,0)
 	else
 	{
 		int i;
@@ -2769,156 +2489,8 @@
 	if (len)
 		*len = length;
 	return contents;
-#else
-	/*
-	 * The chosen icon wasn't the right size, and we're using
-	 * GTK+ 2.0 so we can't scale it.
-	 */
-	return NULL;
-#endif
 }
 
-#if !GTK_CHECK_VERSION(2,6,0)
-static void
-_gdk_file_scale_size_prepared_cb (GdkPixbufLoader *loader,
-		  int              width,
-		  int              height,
-		  gpointer         data)
-{
-	struct {
-		gint width;
-		gint height;
-		gboolean preserve_aspect_ratio;
-	} *info = data;
-
-	g_return_if_fail (width > 0 && height > 0);
-
-	if (info->preserve_aspect_ratio &&
-		(info->width > 0 || info->height > 0)) {
-		if (info->width < 0)
-		{
-			width = width * (double)info->height/(double)height;
-			height = info->height;
-		}
-		else if (info->height < 0)
-		{
-			height = height * (double)info->width/(double)width;
-			width = info->width;
-		}
-		else if ((double)height * (double)info->width >
-				 (double)width * (double)info->height) {
-			width = 0.5 + (double)width * (double)info->height / (double)height;
-			height = info->height;
-		} else {
-			height = 0.5 + (double)height * (double)info->width / (double)width;
-			width = info->width;
-		}
-	} else {
-			if (info->width > 0)
-				width = info->width;
-			if (info->height > 0)
-				height = info->height;
-	}
-
-#if GTK_CHECK_VERSION(2,2,0) /* 2.0 users are going to have very strangely sized things */
-	gdk_pixbuf_loader_set_size (loader, width, height);
-#else
-#warning  nosnilmot could not be bothered to fix this properly for you
-#warning  ... good luck ... your images may end up strange sizes
-#endif
-}
-
-GdkPixbuf *
-gdk_pixbuf_new_from_file_at_scale(const char *filename, int width, int height,
-				  				  gboolean preserve_aspect_ratio,
-								  GError **error)
-{
-	GdkPixbufLoader *loader;
-	GdkPixbuf       *pixbuf;
-	guchar buffer [4096];
-	int length;
-	FILE *f;
-	struct {
-		gint width;
-		gint height;
-		gboolean preserve_aspect_ratio;
-	} info;
-	GdkPixbufAnimation *animation;
-	GdkPixbufAnimationIter *iter;
-	gboolean has_frame;
-
-	g_return_val_if_fail (filename != NULL, NULL);
-	g_return_val_if_fail (width > 0 || width == -1, NULL);
-	g_return_val_if_fail (height > 0 || height == -1, NULL);
-
-	f = g_fopen (filename, "rb");
-	if (!f) {
-		gint save_errno = errno;
-		gchar *display_name = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
-		g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (save_errno),
-					 _("Failed to open file '%s': %s"),
-					 display_name ? display_name : "(unknown)",
-					 g_strerror (save_errno));
-		g_free (display_name);
-		return NULL;
-	}
-
-	loader = gdk_pixbuf_loader_new ();
-
-	info.width = width;
-	info.height = height;
-	info.preserve_aspect_ratio = preserve_aspect_ratio;
-
-	g_signal_connect (loader, "size-prepared", G_CALLBACK (_gdk_file_scale_size_prepared_cb), &info);
-
-	has_frame = FALSE;
-	while (!has_frame && !feof (f) && !ferror (f)) {
-		length = fread (buffer, 1, sizeof (buffer), f);
-		if (length > 0)
-			if (!gdk_pixbuf_loader_write (loader, buffer, length, error)) {
-				gdk_pixbuf_loader_close (loader, NULL);
-				fclose (f);
-				g_object_unref (loader);
-				return NULL;
-			}
-
-		animation = gdk_pixbuf_loader_get_animation (loader);
-		if (animation) {
-			iter = gdk_pixbuf_animation_get_iter (animation, 0);
-			if (!gdk_pixbuf_animation_iter_on_currently_loading_frame (iter)) {
-				has_frame = TRUE;
-			}
-			g_object_unref (iter);
-		}
-	}
-
-	fclose (f);
-
-	if (!gdk_pixbuf_loader_close (loader, error) && !has_frame) {
-		g_object_unref (loader);
-		return NULL;
-	}
-
-	pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
-
-	if (!pixbuf) {
-		gchar *display_name = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
-		g_object_unref (loader);
-		g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
-					 _("Failed to load image '%s': reason not known, probably a corrupt image file"),
-					 display_name ? display_name : "(unknown)");
-		g_free (display_name);
-		return NULL;
-	}
-
-	g_object_ref (pixbuf);
-
-	g_object_unref (loader);
-
-	return pixbuf;
-}
-#endif /* ! Gtk 2.6.0 */
-
 void pidgin_set_custom_buddy_icon(PurpleAccount *account, const char *who, const char *filename)
 {
 	PurpleBuddy *buddy;
@@ -2951,34 +2523,10 @@
 
 void pidgin_set_urgent(GtkWindow *window, gboolean urgent)
 {
-#if GTK_CHECK_VERSION(2,8,0)
-	gtk_window_set_urgency_hint(window, urgent);
-#elif defined _WIN32
+#if defined _WIN32
 	winpidgin_window_flash(window, urgent);
-#elif defined GDK_WINDOWING_X11
-	GdkWindow *gdkwin;
-	XWMHints *hints;
-
-	g_return_if_fail(window != NULL);
-
-	gdkwin = GTK_WIDGET(window)->window;
-
-	g_return_if_fail(gdkwin != NULL);
-
-	hints = XGetWMHints(GDK_WINDOW_XDISPLAY(gdkwin),
-	                    GDK_WINDOW_XWINDOW(gdkwin));
-	if(!hints)
-		hints = XAllocWMHints();
-
-	if (urgent)
-		hints->flags |= XUrgencyHint;
-	else
-		hints->flags &= ~XUrgencyHint;
-	XSetWMHints(GDK_WINDOW_XDISPLAY(gdkwin),
-	            GDK_WINDOW_XWINDOW(gdkwin), hints);
-	XFree(hints);
 #else
-	/* do something else? */
+	gtk_window_set_urgency_hint(window, urgent);
 #endif
 }
 
@@ -3287,31 +2835,6 @@
 	return dim_grey_string;
 }
 
-#if !GTK_CHECK_VERSION(2,2,0)
-GtkTreePath *
-gtk_tree_path_new_from_indices (gint first_index, ...)
-{
-	int arg;
-	va_list args;
-	GtkTreePath *path;
-
-	path = gtk_tree_path_new ();
-
-	va_start (args, first_index);
-	arg = first_index;
-
-	while (arg != -1)
-	{
-		gtk_tree_path_append_index (path, arg);
-		arg = va_arg (args, gint);
-	}
-
-	va_end (args);
-
-	return path;
-}
-#endif
-
 static void
 combo_box_changed_cb(GtkComboBox *combo_box, GtkEntry *entry)
 {
@@ -3457,7 +2980,6 @@
 	return FALSE;
 #endif
 #else
-#if GTK_CHECK_VERSION(2,4,0)
 	/* This finds the currently active window and makes that the parent window. */
 	GList *windows = NULL;
 	GtkWidget *parent = NULL;
@@ -3500,7 +3022,6 @@
 		gtk_window_set_transient_for(GTK_WINDOW(widget), GTK_WINDOW(parent));
 		return TRUE;
 	}
-#endif
 	return FALSE;
 #endif
 }
@@ -3584,23 +3105,13 @@
 #ifdef _WIN32
 	/* If using Win32... */
 	int code;
-	if (G_WIN32_HAVE_WIDECHAR_API()) {
-		wchar_t *wc_filename = g_utf8_to_utf16(
-				uri, -1, NULL, NULL, NULL);
-
-		code = (int)ShellExecuteW(NULL, NULL, wc_filename, NULL, NULL,
-				SW_SHOW);
-
-		g_free(wc_filename);
-	} else {
-		char *l_filename = g_locale_from_utf8(
-				uri, -1, NULL, NULL, NULL);
-
-		code = (int)ShellExecuteA(NULL, NULL, l_filename, NULL, NULL,
-				SW_SHOW);
-
-		g_free(l_filename);
-	}
+	wchar_t *wc_filename = g_utf8_to_utf16(
+			uri, -1, NULL, NULL, NULL);
+
+	code = (int)ShellExecuteW(NULL, NULL, wc_filename, NULL, NULL,
+			SW_SHOW);
+
+	g_free(wc_filename);
 
 	if (code == SE_ERR_ASSOCINCOMPLETE || code == SE_ERR_NOASSOC)
 	{
@@ -3697,13 +3208,10 @@
 	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
 
 	/* Open Containing Directory */
-#if GTK_CHECK_VERSION(2,6,0)
 	img = gtk_image_new_from_stock(GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU);
 	item = gtk_image_menu_item_new_with_mnemonic(_("Open _Containing Directory"));
 	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
-#else
-	item = gtk_menu_item_new_with_mnemonic(_("Open _Containing Directory"));
-#endif
+
 	g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(open_containing_cb), (gpointer)url);
 	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
 
@@ -3769,13 +3277,10 @@
 	url = gtk_imhtml_link_get_url(link);
 
 	/* Play Sound */
-#if GTK_CHECK_VERSION(2,6,0)
 	img = gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_MENU);
 	item = gtk_image_menu_item_new_with_mnemonic(_("_Play Sound"));
 	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
-#else
-	item = gtk_menu_item_new_with_mnemonic(_("_Play Sound"));
-#endif
+
 	g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_link_activate), link);
 	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
 
@@ -3897,17 +3402,18 @@
 
 	do {
 		DWORD nameSize = 256;
-		char start[256];
-		/* I don't think we need to worry about non-ASCII protocol names */
-		ret = RegEnumKeyExA(HKEY_CLASSES_ROOT, idx++, start, &nameSize,
+		wchar_t start[256];
+		ret = RegEnumKeyExW(HKEY_CLASSES_ROOT, idx++, start, &nameSize,
 							NULL, NULL, NULL, NULL);
 		if (ret == ERROR_SUCCESS) {
 			HKEY reg_key = NULL;
-			ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, start, 0, KEY_READ, &reg_key);
+			ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, start, 0, KEY_READ, &reg_key);
 			if (ret == ERROR_SUCCESS) {
-				ret = RegQueryValueExA(reg_key, "URL Protocol", NULL, NULL, NULL, NULL);
+				ret = RegQueryValueExW(reg_key, L"URL Protocol", NULL, NULL, NULL, NULL);
 				if (ret == ERROR_SUCCESS) {
-					gchar *protocol = g_strdup_printf("%s:", start);
+					gchar *utf8 = g_utf16_to_utf8(start, -1, NULL, NULL, NULL);
+					gchar *protocol = g_strdup_printf("%s:", utf8);
+					g_free(utf8);
 					registered_url_handlers = g_slist_prepend(registered_url_handlers, protocol);
 					/* We still pass everything to the "http" "open" handler for security reasons */
 					gtk_imhtml_class_register_protocol(protocol, url_clicked_cb, link_context_menu);
--- a/pidgin/gtkutils.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkutils.h	Thu Feb 04 05:30:35 2010 +0000
@@ -648,17 +648,6 @@
  */
 gpointer pidgin_convert_buddy_icon(PurplePlugin *plugin, const char *path, size_t *len);
 
-#if !GTK_CHECK_VERSION(2,6,0)
-/**
- * Creates a new pixbuf by loading an image from a file. The image will
- * be scaled to fit in the requested size, optionally preserving the image's
- * aspect ratio.
- */
-GdkPixbuf *gdk_pixbuf_new_from_file_at_scale(const char *filename, int width, int height,
-											 gboolean preserve_aspect_ratio,
-											 GError **error);
-#endif
-
 #if !(defined PIDGIN_DISABLE_DEPRECATED) || (defined _PIDGIN_GTKUTILS_C_)
 /**
  * Set or unset a custom buddyicon for a user.
@@ -760,20 +749,6 @@
  */
 const char *pidgin_get_dim_grey_string(GtkWidget *widget);
 
-#if !GTK_CHECK_VERSION(2,2,0)
-/**
- * This is copied from Gtk to support Gtk 2.0
- *
- * Creates a new path with @a first_index and the varargs as indices.
- *
- * @param first_index    first integer
- * @param ...            list of integers terminated by -1
- *
- * @return               A newly created GtkTreePath.
- */
-GtkTreePath *gtk_tree_path_new_from_indices (gint first_index, ...);
-#endif
-
 /**
  * Create a simple text GtkComboBoxEntry equivalent
  *
--- a/pidgin/gtkwhiteboard.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/gtkwhiteboard.c	Thu Feb 04 05:30:35 2010 +0000
@@ -755,7 +755,6 @@
 
 	int result;
 
-#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
 	dialog = gtk_file_chooser_dialog_new (_("Save File"),
 										  GTK_WINDOW(gtkwb->window),
 										  GTK_FILE_CHOOSER_ACTION_SAVE,
@@ -774,21 +773,15 @@
 	else
 		gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog), filename_for_existing_document);
 	*/
-#else
-	dialog = gtk_file_selection_new(_("Save File"));
-	gtk_file_selection_set_filename(GTK_FILE_SELECTION(dialog), "whiteboard.jpg");
-#endif
+
 	result = gtk_dialog_run(GTK_DIALOG(dialog));
 
 	if(result == GTK_RESPONSE_ACCEPT)
 	{
 		char *filename;
 
-#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
 		filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
-#else
-		filename = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(dialog)));
-#endif
+
 		gtk_widget_destroy(dialog);
 
 		/* Makes an icon from the whiteboard's canvas 'image' */
--- a/pidgin/minidialog.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/minidialog.c	Thu Feb 04 05:30:35 2010 +0000
@@ -339,26 +339,20 @@
 
 	param_spec = g_param_spec_string("title", "title",
 		"String specifying the mini-dialog's title", NULL,
-#if GTK_CHECK_VERSION(2,8,0)
 		G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
-#endif
 		G_PARAM_READWRITE);
 	g_object_class_install_property (object_class, PROP_TITLE, param_spec);
 
 	param_spec = g_param_spec_string("description", "description",
 		"Description text for the mini-dialog, if desired", NULL,
-#if GTK_CHECK_VERSION(2,8,0)
 		G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
-#endif
 		G_PARAM_READWRITE);
 	g_object_class_install_property (object_class, PROP_DESCRIPTION, param_spec);
 
 	param_spec = g_param_spec_string("icon-name", "icon-name",
 		"String specifying the Gtk stock name of the dialog's icon",
 		NULL,
-#if GTK_CHECK_VERSION(2,8,0)
 		G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
-#endif
 		G_PARAM_READWRITE);
 	g_object_class_install_property (object_class, PROP_ICON_NAME, param_spec);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/pidgin-2-uninstalled.pc.in	Thu Feb 04 05:30:35 2010 +0000
@@ -0,0 +1,21 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+datarootdir=@datarootdir@
+datadir=@datadir@
+sysconfdir=@sysconfdir@
+
+abs_srcdir=@abs_srcdir@
+abs_builddir=@abs_builddir@
+
+abs_top_srcdir=@abs_top_srcdir@
+abs_top_builddir=@abs_top_builddir@
+
+plugindir=${libdir}/pidgin
+
+Name: Pidgin
+Description: Pidgin is a GTK2-based instant messenger application.
+Version: @VERSION@
+Requires: gtk+-2.0 purple
+Cflags: -I${abs_top_srcdir}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/pidgin-2.pc.in	Thu Feb 04 05:30:35 2010 +0000
@@ -0,0 +1,15 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+datarootdir=@datarootdir@
+datadir=@datadir@
+sysconfdir=@sysconfdir@
+
+plugindir=${libdir}/pidgin
+
+Name: Pidgin
+Description: Pidgin is a GTK2-based instant messenger application.
+Version: @VERSION@
+Requires: gtk+-2.0 purple
+Cflags: -I${includedir}
--- a/pidgin/pidgin-uninstalled.pc.in	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/pidgin-uninstalled.pc.in	Thu Feb 04 05:30:35 2010 +0000
@@ -9,6 +9,8 @@
 abs_srcdir=@abs_srcdir@
 abs_builddir=@abs_builddir@
 
+plugindir=${libdir}/pidgin
+
 Name: Pidgin
 Description: Pidgin is a GTK2-based instant messenger application.
 Version: @VERSION@
--- a/pidgin/pidgin.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/pidgin.h	Thu Feb 04 05:30:35 2010 +0000
@@ -57,33 +57,6 @@
 #endif
 
 /*
- * This is backwards-compatibility code for older versions of GTK+ (< 2.4.x)
- * It defines the new wrap behavior (unknown in earlier versions)
- * as the old (slightly buggy) wrap behavior.
- * It also includes our back-ported GtkExpander
- */
-/** @cond */
-#if (!GTK_CHECK_VERSION(2,4,0))
-# define GTK_WRAP_WORD_CHAR GTK_WRAP_WORD
-# include "gtkexpander.h"
-#endif
-/** @endcond */
-
-/*
- * We include the sources for GtkComboBox and GtkCellView because
- * they don't exist in older versions of GTK+, and we use them
- * in a few places.
- */
-#if !GTK_CHECK_VERSION(2,6,0)
-#   include "gtkcellview.h"
-#   include "gtkcellviewmenuitem.h"
-#   include "pidgincombobox.h"
-#   if !GTK_CHECK_VERSION(2,4,0)
-#       include "gtkcelllayout.h"
-#   endif /* Less than GTK+ 2.4 */
-#endif /* Less than GTK+ 2.6 */
-
-/*
  * Spacings between components, as defined by the
  * GNOME Human Interface Guidelines.
  */
--- a/pidgin/pidgin.pc.in	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/pidgin.pc.in	Thu Feb 04 05:30:35 2010 +0000
@@ -6,6 +6,8 @@
 datadir=@datadir@
 sysconfdir=@sysconfdir@
 
+plugindir=${libdir}/pidgin
+
 Name: Pidgin
 Description: Pidgin is a GTK2-based instant messenger application.
 Version: @VERSION@
--- a/pidgin/pidgincombobox.c	Thu Feb 04 02:18:37 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3749 +0,0 @@
-/* pidgincombobox.c
- * Copyright (C) 2002, 2003  Kristian Rietveld <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02111-1301, USA.
- */
-
-/*
-#include <config.h>
-*/
-#include <gtk/gtkversion.h>
-#if !GTK_CHECK_VERSION(2,6,0)
-#include "pidgincombobox.h"
-
-#if !GTK_CHECK_VERSION(2,4,0)
-#include <gtk/gtkarrow.h>
-#include <gtk/gtkbindings.h>
-#include "gtkcelllayout.h"
-#include <gtk/gtkcellrenderertext.h>
-#include "gtkcellview.h"
-#include "gtkcellviewmenuitem.h"
-#include <gtk/gtkeventbox.h>
-#include <gtk/gtkframe.h>
-#include <gtk/gtkhbox.h>
-#include <gtk/gtkliststore.h>
-#include <gtk/gtkmain.h>
-#include <gtk/gtkmenu.h>
-#include <gtk/gtktogglebutton.h>
-#include <gtk/gtktreeselection.h>
-/*
-#include <gtk/gtktreeprivate.h>
-*/
-#include <gtk/gtkvseparator.h>
-#include <gtk/gtkwindow.h>
-#include <gtk/gtkversion.h>
-
-#include <gdk/gdkkeysyms.h>
-
-#include <gobject/gvaluecollector.h>
-
-#include <string.h>
-#include <stdarg.h>
-
-#define P_(x) (x)
-
-/* WELCOME, to THE house of evil code */
-
-typedef struct _ComboCellInfo ComboCellInfo;
-struct _ComboCellInfo
-{
-  GtkCellRenderer *cell;
-  GSList *attributes;
-
-  GtkCellLayoutDataFunc func;
-  gpointer func_data;
-  GDestroyNotify destroy;
-
-  guint expand : 1;
-  guint pack : 1;
-};
-
-struct _GtkComboBoxPrivate
-{
-  GtkTreeModel *model;
-
-  gint col_column;
-  gint row_column;
-
-  gint wrap_width;
-
-  gint active_item;
-
-  GtkWidget *tree_view;
-  GtkTreeViewColumn *column;
-
-  GtkWidget *cell_view;
-  GtkWidget *cell_view_frame;
-
-  GtkWidget *button;
-  GtkWidget *box;
-  GtkWidget *arrow;
-  GtkWidget *separator;
-
-  GtkWidget *popup_widget;
-  GtkWidget *popup_window;
-  GtkWidget *popup_frame;
-
-  guint inserted_id;
-  guint deleted_id;
-  guint reordered_id;
-  guint changed_id;
-
-  gint width;
-  GSList *cells;
-
-  guint popup_in_progress : 1;
-  guint destroying : 1;
-};
-
-/* While debugging this evil code, I have learned that
- * there are actually 4 modes to this widget, which can
- * be characterized as follows
- *
- * 1) menu mode, no child added
- *
- * tree_view -> NULL
- * cell_view -> GtkCellView, regular child
- * cell_view_frame -> NULL
- * button -> GtkToggleButton set_parent to combo
- * box -> child of button
- * arrow -> child of box
- * separator -> child of box
- * popup_widget -> GtkMenu
- * popup_window -> NULL
- * popup_frame -> NULL
- *
- * 2) menu mode, child added
- *
- * tree_view -> NULL
- * cell_view -> NULL
- * cell_view_frame -> NULL
- * button -> GtkToggleButton set_parent to combo
- * box -> NULL
- * arrow -> GtkArrow, child of button
- * separator -> NULL
- * popup_widget -> GtkMenu
- * popup_window -> NULL
- * popup_frame -> NULL
- *
- * 3) list mode, no child added
- *
- * tree_view -> GtkTreeView, child of popup_frame
- * cell_view -> GtkCellView, regular child
- * cell_view_frame -> GtkFrame, set parent to combo
- * button -> GtkToggleButton, set_parent to combo
- * box -> NULL
- * arrow -> GtkArrow, child of button
- * separator -> NULL
- * popup_widget -> tree_view
- * popup_window -> GtkWindow
- * popup_frame -> GtkFrame, child of popup_window
- *
- * 4) list mode, child added
- *
- * tree_view -> GtkTreeView, child of popup_frame
- * cell_view -> NULL
- * cell_view_frame -> NULL
- * button -> GtkToggleButton, set_parent to combo
- * box -> NULL
- * arrow -> GtkArrow, child of button
- * separator -> NULL
- * popup_widget -> tree_view
- * popup_window -> GtkWindow
- * popup_frame -> GtkFrame, child of popup_window
- *
- */
-
-enum {
-  CHANGED,
-  LAST_SIGNAL
-};
-
-enum {
-  PROP_0,
-  PROP_MODEL,
-  PROP_WRAP_WIDTH,
-  PROP_ROW_SPAN_COLUMN,
-  PROP_COLUMN_SPAN_COLUMN,
-  PROP_ACTIVE
-};
-
-static GtkBinClass *parent_class = NULL;
-static guint combo_box_signals[LAST_SIGNAL] = {0,};
-
-#define BONUS_PADDING 4
-
-
-/* common */
-static void     gtk_combo_box_class_init           (GtkComboBoxClass *klass);
-static void     gtk_combo_box_cell_layout_init     (GtkCellLayoutIface *iface);
-static void     gtk_combo_box_init                 (GtkComboBox      *combo_box);
-static void     gtk_combo_box_finalize             (GObject          *object);
-static void     gtk_combo_box_destroy              (GtkObject        *object);
-
-static void     gtk_combo_box_set_property         (GObject         *object,
-                                                    guint            prop_id,
-                                                    const GValue    *value,
-                                                    GParamSpec      *spec);
-static void     gtk_combo_box_get_property         (GObject         *object,
-                                                    guint            prop_id,
-                                                    GValue          *value,
-                                                    GParamSpec      *spec);
-
-static void     gtk_combo_box_state_changed        (GtkWidget        *widget,
-			                            GtkStateType      previous);
-static void     gtk_combo_box_style_set            (GtkWidget       *widget,
-                                                    GtkStyle        *previous);
-static void     gtk_combo_box_button_toggled       (GtkWidget       *widget,
-                                                    gpointer         data);
-static void     gtk_combo_box_add                  (GtkContainer    *container,
-                                                    GtkWidget       *widget);
-static void     gtk_combo_box_remove               (GtkContainer    *container,
-                                                    GtkWidget       *widget);
-
-static ComboCellInfo *gtk_combo_box_get_cell_info  (GtkComboBox      *combo_box,
-                                                    GtkCellRenderer  *cell);
-
-static void     gtk_combo_box_menu_show            (GtkWidget        *menu,
-                                                    gpointer          user_data);
-static void     gtk_combo_box_menu_hide            (GtkWidget        *menu,
-                                                    gpointer          user_data);
-
-static void     gtk_combo_box_set_popup_widget     (GtkComboBox      *combo_box,
-                                                    GtkWidget        *popup);
-#if GTK_CHECK_VERSION(2,2,0)
-static void     gtk_combo_box_menu_position_below  (GtkMenu          *menu,
-                                                    gint             *x,
-                                                    gint             *y,
-                                                    gint             *push_in,
-                                                    gpointer          user_data);
-static void     gtk_combo_box_menu_position_over   (GtkMenu          *menu,
-                                                    gint             *x,
-                                                    gint             *y,
-                                                    gint             *push_in,
-                                                    gpointer          user_data);
-static void     gtk_combo_box_menu_position        (GtkMenu          *menu,
-                                                    gint             *x,
-                                                    gint             *y,
-                                                    gint             *push_in,
-                                                    gpointer          user_data);
-#endif
-
-static gint     gtk_combo_box_calc_requested_width (GtkComboBox      *combo_box,
-                                                    GtkTreePath      *path);
-static void     gtk_combo_box_remeasure            (GtkComboBox      *combo_box);
-
-static void     gtk_combo_box_unset_model          (GtkComboBox      *combo_box);
-
-static void     gtk_combo_box_size_request         (GtkWidget        *widget,
-                                                    GtkRequisition   *requisition);
-static void     gtk_combo_box_size_allocate        (GtkWidget        *widget,
-                                                    GtkAllocation    *allocation);
-static void     gtk_combo_box_forall               (GtkContainer     *container,
-                                                    gboolean          include_internals,
-                                                    GtkCallback       callback,
-                                                    gpointer          callback_data);
-static gboolean gtk_combo_box_expose_event         (GtkWidget        *widget,
-                                                    GdkEventExpose   *event);
-static gboolean gtk_combo_box_scroll_event         (GtkWidget        *widget,
-                                                    GdkEventScroll   *event);
-static void     gtk_combo_box_set_active_internal  (GtkComboBox      *combo_box,
-						    gint              index);
-static gboolean gtk_combo_box_key_press            (GtkWidget        *widget,
-						    GdkEventKey      *event,
-						    gpointer          data);
-
-/* listening to the model */
-static void     gtk_combo_box_model_row_inserted   (GtkTreeModel     *model,
-						    GtkTreePath      *path,
-						    GtkTreeIter      *iter,
-						    gpointer          user_data);
-static void     gtk_combo_box_model_row_deleted    (GtkTreeModel     *model,
-						    GtkTreePath      *path,
-						    gpointer          user_data);
-static void     gtk_combo_box_model_rows_reordered (GtkTreeModel     *model,
-						    GtkTreePath      *path,
-						    GtkTreeIter      *iter,
-						    gint             *new_order,
-						    gpointer          user_data);
-static void     gtk_combo_box_model_row_changed    (GtkTreeModel     *model,
-						    GtkTreePath      *path,
-						    GtkTreeIter      *iter,
-						    gpointer          data);
-
-/* list */
-static void     gtk_combo_box_list_position        (GtkComboBox      *combo_box,
-						    gint             *x,
-						    gint             *y,
-						    gint             *width,
-						    gint             *height);
-
-static void     gtk_combo_box_list_setup           (GtkComboBox      *combo_box);
-static void     gtk_combo_box_list_destroy         (GtkComboBox      *combo_box);
-
-static void     gtk_combo_box_list_remove_grabs    (GtkComboBox      *combo_box);
-
-static gboolean gtk_combo_box_list_button_released (GtkWidget        *widget,
-                                                    GdkEventButton   *event,
-                                                    gpointer          data);
-static gboolean gtk_combo_box_list_key_press       (GtkWidget        *widget,
-                                                    GdkEventKey      *event,
-                                                    gpointer          data);
-static gboolean gtk_combo_box_list_button_pressed  (GtkWidget        *widget,
-                                                    GdkEventButton   *event,
-                                                    gpointer          data);
-
-static void     gtk_combo_box_list_row_changed     (GtkTreeModel     *model,
-                                                    GtkTreePath      *path,
-                                                    GtkTreeIter      *iter,
-                                                    gpointer          data);
-
-/* menu */
-static void     gtk_combo_box_menu_setup           (GtkComboBox      *combo_box,
-                                                    gboolean          add_children);
-static void     gtk_combo_box_menu_fill            (GtkComboBox      *combo_box);
-static void     gtk_combo_box_menu_destroy         (GtkComboBox      *combo_box);
-
-static void     gtk_combo_box_item_get_size        (GtkComboBox      *combo_box,
-                                                    gint              index,
-                                                    gint             *cols,
-                                                    gint             *rows);
-static void     gtk_combo_box_relayout_item        (GtkComboBox      *combo_box,
-                                                    gint              index);
-static void     gtk_combo_box_relayout             (GtkComboBox      *combo_box);
-
-static gboolean gtk_combo_box_menu_button_press    (GtkWidget        *widget,
-                                                    GdkEventButton   *event,
-                                                    gpointer          user_data);
-static void     gtk_combo_box_menu_item_activate   (GtkWidget        *item,
-                                                    gpointer          user_data);
-static void     gtk_combo_box_menu_row_inserted    (GtkTreeModel     *model,
-                                                    GtkTreePath      *path,
-                                                    GtkTreeIter      *iter,
-                                                    gpointer          user_data);
-static void     gtk_combo_box_menu_row_deleted     (GtkTreeModel     *model,
-                                                    GtkTreePath      *path,
-                                                    gpointer          user_data);
-static void     gtk_combo_box_menu_rows_reordered  (GtkTreeModel     *model,
-						    GtkTreePath      *path,
-						    GtkTreeIter      *iter,
-						    gint             *new_order,
-						    gpointer          user_data);
-static void     gtk_combo_box_menu_row_changed     (GtkTreeModel     *model,
-                                                    GtkTreePath      *path,
-                                                    GtkTreeIter      *iter,
-                                                    gpointer          data);
-static gboolean gtk_combo_box_menu_key_press       (GtkWidget        *widget,
-						    GdkEventKey      *event,
-						    gpointer          data);
-
-/* cell layout */
-static void     gtk_combo_box_cell_layout_pack_start         (GtkCellLayout         *layout,
-                                                              GtkCellRenderer       *cell,
-                                                              gboolean               expand);
-static void     gtk_combo_box_cell_layout_pack_end           (GtkCellLayout         *layout,
-                                                              GtkCellRenderer       *cell,
-                                                              gboolean               expand);
-static void     gtk_combo_box_cell_layout_clear              (GtkCellLayout         *layout);
-static void     gtk_combo_box_cell_layout_add_attribute      (GtkCellLayout         *layout,
-                                                              GtkCellRenderer       *cell,
-                                                              const gchar           *attribute,
-                                                              gint                   column);
-static void     gtk_combo_box_cell_layout_set_cell_data_func (GtkCellLayout         *layout,
-                                                              GtkCellRenderer       *cell,
-                                                              GtkCellLayoutDataFunc  func,
-                                                              gpointer               func_data,
-                                                              GDestroyNotify         destroy);
-static void     gtk_combo_box_cell_layout_clear_attributes   (GtkCellLayout         *layout,
-                                                              GtkCellRenderer       *cell);
-static void     gtk_combo_box_cell_layout_reorder            (GtkCellLayout         *layout,
-                                                              GtkCellRenderer       *cell,
-                                                              gint                   position);
-static gboolean gtk_combo_box_mnemonic_activate              (GtkWidget    *widget,
-							      gboolean      group_cycling);
-
-static void     cell_view_sync_cells (GtkComboBox *combo_box,
-                                      GtkCellView *cell_view);
-
-#if !GTK_CHECK_VERSION(2,4,0)
-static void     gtk_menu_attach (GtkMenu   *menu,
-                                 GtkWidget *child,
-                                 guint      left_attach,
-                                 guint      right_attach,
-                                 guint      top_attach,
-                                 guint      bottom_attach);
-#endif
-
-GType
-gtk_combo_box_get_type (void)
-{
-  static GType combo_box_type = 0;
-
-  if (!combo_box_type)
-    {
-      static const GTypeInfo combo_box_info =
-        {
-          sizeof (GtkComboBoxClass),
-          NULL, /* base_init */
-          NULL, /* base_finalize */
-          (GClassInitFunc) gtk_combo_box_class_init,
-          NULL, /* class_finalize */
-          NULL, /* class_data */
-          sizeof (GtkComboBox),
-          0,
-          (GInstanceInitFunc) gtk_combo_box_init
-        };
-
-      static const GInterfaceInfo cell_layout_info =
-        {
-          (GInterfaceInitFunc) gtk_combo_box_cell_layout_init,
-          NULL,
-          NULL
-        };
-
-      combo_box_type = g_type_register_static (GTK_TYPE_BIN,
-                                               "PidginComboBox",
-                                               &combo_box_info,
-                                               0);
-
-      g_type_add_interface_static (combo_box_type,
-                                   GTK_TYPE_CELL_LAYOUT,
-                                   &cell_layout_info);
-    }
-
-  return combo_box_type;
-}
-
-/* common */
-static void
-gtk_combo_box_class_init (GtkComboBoxClass *klass)
-{
-  GObjectClass *object_class;
-  GtkBindingSet *binding_set;
-  GtkObjectClass *gtk_object_class;
-  GtkContainerClass *container_class;
-  GtkWidgetClass *widget_class;
-
-  binding_set = gtk_binding_set_by_class (klass);
-
-  container_class = (GtkContainerClass *)klass;
-  container_class->forall = gtk_combo_box_forall;
-  container_class->add = gtk_combo_box_add;
-  container_class->remove = gtk_combo_box_remove;
-
-  widget_class = (GtkWidgetClass *)klass;
-  widget_class->size_allocate = gtk_combo_box_size_allocate;
-  widget_class->size_request = gtk_combo_box_size_request;
-  widget_class->expose_event = gtk_combo_box_expose_event;
-  widget_class->scroll_event = gtk_combo_box_scroll_event;
-  widget_class->mnemonic_activate = gtk_combo_box_mnemonic_activate;
-  widget_class->style_set = gtk_combo_box_style_set;
-  widget_class->state_changed = gtk_combo_box_state_changed;
-
-  gtk_object_class = (GtkObjectClass *)klass;
-  gtk_object_class->destroy = gtk_combo_box_destroy;
-
-  object_class = (GObjectClass *)klass;
-  object_class->finalize = gtk_combo_box_finalize;
-  object_class->set_property = gtk_combo_box_set_property;
-  object_class->get_property = gtk_combo_box_get_property;
-
-  parent_class = g_type_class_peek_parent (klass);
-
-  /* signals */
-  combo_box_signals[CHANGED] =
-    g_signal_new ("changed",
-                  G_OBJECT_CLASS_TYPE (klass),
-                  G_SIGNAL_RUN_LAST,
-                  G_STRUCT_OFFSET (GtkComboBoxClass, changed),
-                  NULL, NULL,
-                  g_cclosure_marshal_VOID__VOID,
-                  G_TYPE_NONE, 0);
-
-  /* properties */
-  g_object_class_install_property (object_class,
-                                   PROP_MODEL,
-                                   g_param_spec_object ("model",
-                                                        P_("ComboBox model"),
-                                                        P_("The model for the combo box"),
-                                                        GTK_TYPE_TREE_MODEL,
-                                                        G_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_WRAP_WIDTH,
-                                   g_param_spec_int ("wrap_width",
-                                                     P_("Wrap width"),
-                                                     P_("Wrap width for layouting the items in a grid"),
-                                                     0,
-                                                     G_MAXINT,
-                                                     0,
-                                                     G_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_ROW_SPAN_COLUMN,
-                                   g_param_spec_int ("row_span_column",
-                                                     P_("Row span column"),
-                                                     P_("TreeModel column containing the row span values"),
-                                                     0,
-                                                     G_MAXINT,
-                                                     0,
-                                                     G_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_COLUMN_SPAN_COLUMN,
-                                   g_param_spec_int ("column_span_column",
-                                                     P_("Column span column"),
-
-                                                     P_("TreeModel column containing the column span values"),
-                                                     0,
-                                                     G_MAXINT,
-                                                     0,
-                                                     G_PARAM_READWRITE));
-
-  g_object_class_install_property (object_class,
-                                   PROP_ACTIVE,
-                                   g_param_spec_int ("active",
-                                                     P_("Active item"),
-                                                     P_("The item which is currently active"),
-                                                     -1,
-                                                     G_MAXINT,
-                                                     -1,
-                                                     G_PARAM_READWRITE));
-
-  gtk_widget_class_install_style_property (widget_class,
-                                           g_param_spec_boolean ("appears-as-list",
-                                                                 P_("Appears as list"),
-                                                                 P_("Whether combobox dropdowns should look like lists rather than menus"),
-                                                                 FALSE,
-                                                                 G_PARAM_READABLE));
-}
-
-static void
-gtk_combo_box_cell_layout_init (GtkCellLayoutIface *iface)
-{
-  iface->pack_start = gtk_combo_box_cell_layout_pack_start;
-  iface->pack_end = gtk_combo_box_cell_layout_pack_end;
-  iface->clear = gtk_combo_box_cell_layout_clear;
-  iface->add_attribute = gtk_combo_box_cell_layout_add_attribute;
-  iface->set_cell_data_func = gtk_combo_box_cell_layout_set_cell_data_func;
-  iface->clear_attributes = gtk_combo_box_cell_layout_clear_attributes;
-  iface->reorder = gtk_combo_box_cell_layout_reorder;
-}
-
-static void
-gtk_combo_box_init (GtkComboBox *combo_box)
-{
-  combo_box->priv = g_new0(GtkComboBoxPrivate,1);
-
-  combo_box->priv->cell_view = gtk_cell_view_new ();
-  gtk_widget_set_parent (combo_box->priv->cell_view, GTK_WIDGET (combo_box));
-  GTK_BIN (combo_box)->child = combo_box->priv->cell_view;
-  gtk_widget_show (combo_box->priv->cell_view);
-
-  combo_box->priv->width = 0;
-  combo_box->priv->wrap_width = 0;
-
-  combo_box->priv->active_item = -1;
-  combo_box->priv->col_column = -1;
-  combo_box->priv->row_column = -1;
-}
-
-static void
-gtk_combo_box_set_property (GObject      *object,
-                            guint         prop_id,
-                            const GValue *value,
-                            GParamSpec   *pspec)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (object);
-
-  switch (prop_id)
-    {
-      case PROP_MODEL:
-        gtk_combo_box_set_model (combo_box, g_value_get_object (value));
-        break;
-
-      case PROP_WRAP_WIDTH:
-        gtk_combo_box_set_wrap_width (combo_box, g_value_get_int (value));
-        break;
-
-      case PROP_ROW_SPAN_COLUMN:
-        gtk_combo_box_set_row_span_column (combo_box, g_value_get_int (value));
-        break;
-
-      case PROP_COLUMN_SPAN_COLUMN:
-        gtk_combo_box_set_column_span_column (combo_box, g_value_get_int (value));
-        break;
-
-      case PROP_ACTIVE:
-        gtk_combo_box_set_active (combo_box, g_value_get_int (value));
-        break;
-
-      default:
-        break;
-    }
-}
-
-static void
-gtk_combo_box_get_property (GObject    *object,
-                            guint       prop_id,
-                            GValue     *value,
-                            GParamSpec *pspec)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (object);
-
-  switch (prop_id)
-    {
-      case PROP_MODEL:
-        g_value_set_object (value, combo_box->priv->model);
-        break;
-
-      case PROP_WRAP_WIDTH:
-        g_value_set_int (value, combo_box->priv->wrap_width);
-        break;
-
-      case PROP_ROW_SPAN_COLUMN:
-        g_value_set_int (value, combo_box->priv->row_column);
-        break;
-
-      case PROP_COLUMN_SPAN_COLUMN:
-        g_value_set_int (value, combo_box->priv->col_column);
-        break;
-
-      case PROP_ACTIVE:
-        g_value_set_int (value, gtk_combo_box_get_active (combo_box));
-        break;
-
-      default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-        break;
-    }
-}
-
-static void
-gtk_combo_box_state_changed (GtkWidget    *widget,
-			     GtkStateType  previous)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
-
-  if (GTK_WIDGET_REALIZED (widget))
-    {
-      if (combo_box->priv->tree_view && combo_box->priv->cell_view)
-	gtk_cell_view_set_background_color (GTK_CELL_VIEW (combo_box->priv->cell_view),
-					    &widget->style->base[GTK_WIDGET_STATE (widget)]);
-    }
-
-  gtk_widget_queue_draw (widget);
-}
-
-static void
-gtk_combo_box_check_appearance (GtkComboBox *combo_box)
-{
-  gboolean appears_as_list;
-
-  /* if wrap_width > 0, then we are in grid-mode and forced to use
-   * unix style
-   */
-  if (combo_box->priv->wrap_width)
-    appears_as_list = FALSE;
-  else
-    gtk_widget_style_get (GTK_WIDGET (combo_box),
-			  "appears-as-list", &appears_as_list,
-			  NULL);
-
-  if (appears_as_list)
-    {
-      /* Destroy all the menu mode widgets, if they exist. */
-      if (GTK_IS_MENU (combo_box->priv->popup_widget))
-	gtk_combo_box_menu_destroy (combo_box);
-
-      /* Create the list mode widgets, if they don't already exist. */
-      if (!GTK_IS_TREE_VIEW (combo_box->priv->tree_view))
-	gtk_combo_box_list_setup (combo_box);
-    }
-  else
-    {
-      /* Destroy all the list mode widgets, if they exist. */
-      if (GTK_IS_TREE_VIEW (combo_box->priv->tree_view))
-	gtk_combo_box_list_destroy (combo_box);
-
-      /* Create the menu mode widgets, if they don't already exist. */
-      if (!GTK_IS_MENU (combo_box->priv->popup_widget))
-	gtk_combo_box_menu_setup (combo_box, TRUE);
-    }
-}
-
-static void
-gtk_combo_box_style_set (GtkWidget *widget,
-                         GtkStyle  *previous)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
-
-  gtk_combo_box_check_appearance (combo_box);
-
-  if (combo_box->priv->tree_view && combo_box->priv->cell_view)
-    gtk_cell_view_set_background_color (GTK_CELL_VIEW (combo_box->priv->cell_view),
-					&widget->style->base[GTK_WIDGET_STATE (widget)]);
-}
-
-static void
-gtk_combo_box_button_toggled (GtkWidget *widget,
-                              gpointer   data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (data);
-
-  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
-    {
-      if (!combo_box->priv->popup_in_progress)
-        gtk_combo_box_popup (combo_box);
-    }
-  else
-    gtk_combo_box_popdown (combo_box);
-}
-
-static void
-gtk_combo_box_add (GtkContainer *container,
-                   GtkWidget    *widget)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (container);
-
-  if (combo_box->priv->cell_view && combo_box->priv->cell_view->parent)
-    {
-      gtk_widget_unparent (combo_box->priv->cell_view);
-      GTK_BIN (container)->child = NULL;
-      gtk_widget_queue_resize (GTK_WIDGET (container));
-    }
-
-  gtk_widget_set_parent (widget, GTK_WIDGET (container));
-  GTK_BIN (container)->child = widget;
-
-  if (combo_box->priv->cell_view &&
-      widget != combo_box->priv->cell_view)
-    {
-      /* since the cell_view was unparented, it's gone now */
-      combo_box->priv->cell_view = NULL;
-
-      if (!combo_box->priv->tree_view && combo_box->priv->separator)
-        {
-	  gtk_container_remove (GTK_CONTAINER (combo_box->priv->separator->parent),
-				combo_box->priv->separator);
-	  combo_box->priv->separator = NULL;
-
-          gtk_widget_queue_resize (GTK_WIDGET (container));
-        }
-      else if (combo_box->priv->cell_view_frame)
-        {
-          gtk_widget_unparent (combo_box->priv->cell_view_frame);
-          combo_box->priv->cell_view_frame = NULL;
-        }
-    }
-}
-
-static void
-gtk_combo_box_remove (GtkContainer *container,
-		      GtkWidget    *widget)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (container);
-  gboolean appears_as_list;
-
-  gtk_widget_unparent (widget);
-  GTK_BIN (container)->child = NULL;
-
-  if (combo_box->priv->destroying)
-    return;
-
-  gtk_widget_queue_resize (GTK_WIDGET (container));
-
-  if (!combo_box->priv->tree_view)
-    appears_as_list = FALSE;
-  else
-    appears_as_list = TRUE;
-
-  if (appears_as_list)
-    gtk_combo_box_list_destroy (combo_box);
-  else if (GTK_IS_MENU (combo_box->priv->popup_widget))
-    {
-      gtk_combo_box_menu_destroy (combo_box);
-      gtk_menu_detach (GTK_MENU (combo_box->priv->popup_widget));
-      combo_box->priv->popup_widget = NULL;
-    }
-
-  if (!combo_box->priv->cell_view)
-    {
-      combo_box->priv->cell_view = gtk_cell_view_new ();
-      gtk_widget_set_parent (combo_box->priv->cell_view, GTK_WIDGET (container));
-      GTK_BIN (container)->child = combo_box->priv->cell_view;
-
-      gtk_widget_show (combo_box->priv->cell_view);
-      gtk_cell_view_set_model (GTK_CELL_VIEW (combo_box->priv->cell_view),
-			       combo_box->priv->model);
-      cell_view_sync_cells (combo_box, GTK_CELL_VIEW (combo_box->priv->cell_view));
-    }
-
-
-  if (appears_as_list)
-    gtk_combo_box_list_setup (combo_box);
-  else
-    gtk_combo_box_menu_setup (combo_box, TRUE);
-
-  gtk_combo_box_set_active_internal (combo_box, combo_box->priv->active_item);
-}
-
-static ComboCellInfo *
-gtk_combo_box_get_cell_info (GtkComboBox     *combo_box,
-                             GtkCellRenderer *cell)
-{
-  GSList *i;
-
-  for (i = combo_box->priv->cells; i; i = i->next)
-    {
-      ComboCellInfo *info = (ComboCellInfo *)i->data;
-
-      if (info && info->cell == cell)
-        return info;
-    }
-
-  return NULL;
-}
-
-static void
-gtk_combo_box_menu_show (GtkWidget *menu,
-                         gpointer   user_data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
-
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
-                                TRUE);
-  combo_box->priv->popup_in_progress = FALSE;
-}
-
-static void
-gtk_combo_box_menu_hide (GtkWidget *menu,
-                         gpointer   user_data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
-
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
-                                FALSE);
-}
-
-static void
-gtk_combo_box_detacher (GtkWidget *widget,
-			GtkMenu	  *menu)
-{
-  GtkComboBox *combo_box;
-
-  g_return_if_fail (GTK_IS_COMBO_BOX (widget));
-
-  combo_box = GTK_COMBO_BOX (widget);
-  g_return_if_fail (combo_box->priv->popup_widget == (GtkWidget*) menu);
-
-  g_signal_handlers_disconnect_by_func (menu,
-					gtk_combo_box_menu_show,
-					combo_box);
-  g_signal_handlers_disconnect_by_func (menu,
-					gtk_combo_box_menu_hide,
-					combo_box);
-
-  combo_box->priv->popup_widget = NULL;
-}
-
-static void
-gtk_combo_box_set_popup_widget (GtkComboBox *combo_box,
-                                GtkWidget   *popup)
-{
-  if (GTK_IS_MENU (combo_box->priv->popup_widget))
-    {
-      gtk_menu_detach (GTK_MENU (combo_box->priv->popup_widget));
-      combo_box->priv->popup_widget = NULL;
-    }
-  else if (combo_box->priv->popup_widget)
-    {
-      gtk_container_remove (GTK_CONTAINER (combo_box->priv->popup_frame),
-                            combo_box->priv->popup_widget);
-      g_object_unref (G_OBJECT (combo_box->priv->popup_widget));
-      combo_box->priv->popup_widget = NULL;
-    }
-
-  if (GTK_IS_MENU (popup))
-    {
-      if (combo_box->priv->popup_window)
-        {
-          gtk_widget_destroy (combo_box->priv->popup_window);
-          combo_box->priv->popup_window = NULL;
-	  combo_box->priv->popup_frame = NULL;
-        }
-
-      combo_box->priv->popup_widget = popup;
-
-      g_signal_connect (popup, "show",
-                        G_CALLBACK (gtk_combo_box_menu_show), combo_box);
-      g_signal_connect (popup, "hide",
-                        G_CALLBACK (gtk_combo_box_menu_hide), combo_box);
-
-      gtk_menu_attach_to_widget (GTK_MENU (popup),
-				 GTK_WIDGET (combo_box),
-				 gtk_combo_box_detacher);
-    }
-  else
-    {
-      if (!combo_box->priv->popup_window)
-        {
-          combo_box->priv->popup_window = gtk_window_new (GTK_WINDOW_POPUP);
-	  gtk_window_set_resizable (GTK_WINDOW (combo_box->priv->popup_window), FALSE);
-#if GTK_CHECK_VERSION(2,2,0)
-          gtk_window_set_screen (GTK_WINDOW (combo_box->priv->popup_window),
-                                 gtk_widget_get_screen (GTK_WIDGET (combo_box)));
-#endif
-
-          combo_box->priv->popup_frame = gtk_frame_new (NULL);
-          gtk_frame_set_shadow_type (GTK_FRAME (combo_box->priv->popup_frame),
-                                     GTK_SHADOW_ETCHED_IN);
-          gtk_container_add (GTK_CONTAINER (combo_box->priv->popup_window),
-                             combo_box->priv->popup_frame);
-
-          gtk_widget_show (combo_box->priv->popup_frame);
-        }
-
-      gtk_container_add (GTK_CONTAINER (combo_box->priv->popup_frame),
-                         popup);
-      gtk_widget_show (popup);
-      g_object_ref (G_OBJECT (popup));
-      combo_box->priv->popup_widget = popup;
-    }
-}
-
-#if GTK_CHECK_VERSION(2,2,0)
-static void
-gtk_combo_box_menu_position_below (GtkMenu  *menu,
-				   gint     *x,
-				   gint     *y,
-				   gint     *push_in,
-				   gpointer  user_data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
-  gint sx, sy;
-  GtkWidget *child;
-  GtkRequisition req;
-  GdkScreen *screen;
-  gint monitor_num;
-  GdkRectangle monitor;
-
-  /* FIXME: is using the size request here broken? */
-   child = GTK_BIN (combo_box)->child;
-
-   gdk_window_get_origin (child->window, &sx, &sy);
-
-   if (GTK_WIDGET_NO_WINDOW (child))
-      {
-	sx += child->allocation.x;
-	sy += child->allocation.y;
-      }
-
-   gtk_widget_size_request (GTK_WIDGET (menu), &req);
-
-   if (gtk_widget_get_direction (GTK_WIDGET (combo_box)) == GTK_TEXT_DIR_LTR)
-     *x = sx;
-   else
-     *x = sx + child->allocation.width - req.width;
-   *y = sy;
-
-  screen = gtk_widget_get_screen (GTK_WIDGET (combo_box));
-  monitor_num = gdk_screen_get_monitor_at_window (screen,
-						  GTK_WIDGET (combo_box)->window);
-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
-
-  if (*x < monitor.x)
-    *x = monitor.x;
-  else if (*x + req.width > monitor.x + monitor.width)
-    *x = monitor.x + monitor.width - req.width;
-
-  if (monitor.y + monitor.height - *y - child->allocation.height >= req.height)
-    *y += child->allocation.height;
-  else if (*y - monitor.y >= req.height)
-    *y -= req.height;
-  else if (monitor.y + monitor.height - *y - child->allocation.height > *y - monitor.y)
-    *y += child->allocation.height;
-  else
-    *y -= req.height;
-
-   *push_in = FALSE;
-}
-
-static void
-gtk_combo_box_menu_position_over (GtkMenu  *menu,
-				  gint     *x,
-				  gint     *y,
-				  gboolean *push_in,
-				  gpointer  user_data)
-{
-  GtkComboBox *combo_box;
-  GtkWidget *active;
-  GtkWidget *child;
-  GtkWidget *widget;
-  GtkRequisition requisition;
-  GList *children;
-  gint screen_width;
-  gint menu_xpos;
-  gint menu_ypos;
-  gint menu_width;
-
-  g_return_if_fail (GTK_IS_COMBO_BOX (user_data));
-
-  combo_box = GTK_COMBO_BOX (user_data);
-  widget = GTK_WIDGET (combo_box);
-
-  gtk_widget_get_child_requisition (GTK_WIDGET (menu), &requisition);
-  menu_width = requisition.width;
-
-  active = gtk_menu_get_active (GTK_MENU (combo_box->priv->popup_widget));
-  gdk_window_get_origin (widget->window, &menu_xpos, &menu_ypos);
-
-  menu_xpos += widget->allocation.x;
-  menu_ypos += widget->allocation.y + widget->allocation.height / 2 - 2;
-
-  if (active != NULL)
-    {
-      gtk_widget_get_child_requisition (active, &requisition);
-      menu_ypos -= requisition.height / 2;
-    }
-
-  children = GTK_MENU_SHELL (combo_box->priv->popup_widget)->children;
-  while (children)
-    {
-      child = children->data;
-
-      if (active == child)
-	break;
-
-      if (GTK_WIDGET_VISIBLE (child))
-	{
-	  gtk_widget_get_child_requisition (child, &requisition);
-	  menu_ypos -= requisition.height;
-	}
-
-      children = children->next;
-    }
-
-  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
-    menu_xpos = menu_xpos + widget->allocation.width - menu_width;
-
-  /* Clamp the position on screen */
-  screen_width = gdk_screen_get_width (gtk_widget_get_screen (widget));
-
-  if (menu_xpos < 0)
-    menu_xpos = 0;
-  else if ((menu_xpos + menu_width) > screen_width)
-    menu_xpos -= ((menu_xpos + menu_width) - screen_width);
-
-  *x = menu_xpos;
-  *y = menu_ypos;
-
-  *push_in = TRUE;
-}
-
-static void
-gtk_combo_box_menu_position (GtkMenu  *menu,
-			     gint     *x,
-			     gint     *y,
-			     gint     *push_in,
-			     gpointer  user_data)
-{
-  GtkComboBox *combo_box;
-  GtkWidget *menu_item;
-
-  combo_box = GTK_COMBO_BOX (user_data);
-
-  if (combo_box->priv->wrap_width > 0 || combo_box->priv->cell_view == NULL)
-    gtk_combo_box_menu_position_below (menu, x, y, push_in, user_data);
-  else
-    {
-      menu_item = gtk_menu_get_active (GTK_MENU (combo_box->priv->popup_widget));
-      if (menu_item)
-	gtk_menu_shell_select_item (GTK_MENU_SHELL (combo_box->priv->popup_widget),
-				    menu_item);
-
-      gtk_combo_box_menu_position_over (menu, x, y, push_in, user_data);
-    }
-
-}
-#endif /* Gtk 2.2 */
-
-static void
-gtk_combo_box_list_position (GtkComboBox *combo_box,
-			     gint        *x,
-			     gint        *y,
-			     gint        *width,
-			     gint        *height)
-{
-  GtkWidget *sample;
-  GtkRequisition popup_req;
-#if GTK_CHECK_VERSION(2,2,0)
-  GdkScreen *screen;
-  gint monitor_num;
-  GdkRectangle monitor;
-#endif
-
-  sample = GTK_BIN (combo_box)->child;
-
-  *width = sample->allocation.width;
-  gtk_widget_size_request (combo_box->priv->popup_window, &popup_req);
-  *height = popup_req.height;
-
-  gdk_window_get_origin (sample->window, x, y);
-
-  if (combo_box->priv->cell_view_frame)
-    {
-       *x -= GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
-	     GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness;
-       *width += 2 * (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
-            GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness);
-    }
-
-  if (GTK_WIDGET_NO_WINDOW (sample))
-    {
-      *x += sample->allocation.x;
-      *y += sample->allocation.y;
-    }
-
-#if GTK_CHECK_VERSION(2,2,0)
-  screen = gtk_widget_get_screen (GTK_WIDGET (combo_box));
-  monitor_num = gdk_screen_get_monitor_at_window (screen,
-						  GTK_WIDGET (combo_box)->window);
-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
-
-  if (*x < monitor.x)
-    *x = monitor.x;
-  else if (*x + *width > monitor.x + monitor.width)
-    *x = monitor.x + monitor.width - *width;
-
-  if (*y + sample->allocation.height + *height <= monitor.y + monitor.height)
-    *y += sample->allocation.height;
-  else
-    *y -= *height;
-#endif /* Gtk 2.2 */
-}
-
-/**
- * gtk_combo_box_popup:
- * @combo_box: a #GtkComboBox
- *
- * Pops up the menu or dropdown list of @combo_box.
- *
- * This function is mostly intended for use by accessibility technologies;
- * applications should have little use for it.
- *
- * Since: 2.4
- **/
-void
-gtk_combo_box_popup (GtkComboBox *combo_box)
-{
-  gint x, y, width, height;
-
-  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
-
-  if (GTK_WIDGET_MAPPED (combo_box->priv->popup_widget))
-    return;
-
-  if (GTK_IS_MENU (combo_box->priv->popup_widget))
-    {
-      gtk_menu_set_active (GTK_MENU (combo_box->priv->popup_widget),
-			   combo_box->priv->active_item);
-
-      if (combo_box->priv->wrap_width == 0)
-	{
-          GtkRequisition requisition;
-
-	  width = GTK_WIDGET (combo_box)->allocation.width;
-          gtk_widget_size_request (combo_box->priv->popup_widget, &requisition);
-
-	  gtk_widget_set_size_request (combo_box->priv->popup_widget,
-                                       MAX (width, requisition.width), -1);
-	}
-
-      gtk_menu_popup (GTK_MENU (combo_box->priv->popup_widget),
-		      NULL, NULL,
-#if GTK_CHECK_VERSION(2,2,0)
-		      gtk_combo_box_menu_position,
-#else
-		      NULL,
-#endif
-		      combo_box, 0, 0);
-      return;
-    }
-
-  gtk_widget_show_all (combo_box->priv->popup_frame);
-  gtk_combo_box_list_position (combo_box, &x, &y, &width, &height);
-
-  gtk_widget_set_size_request (combo_box->priv->popup_window, width, -1);
-  gtk_window_move (GTK_WINDOW (combo_box->priv->popup_window), x, y);
-
-  /* popup */
-  gtk_widget_show (combo_box->priv->popup_window);
-
-  gtk_widget_grab_focus (combo_box->priv->popup_window);
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
-                                TRUE);
-
-  if (!GTK_WIDGET_HAS_FOCUS (combo_box->priv->tree_view))
-    {
-      gdk_keyboard_grab (combo_box->priv->popup_window->window,
-                         FALSE, GDK_CURRENT_TIME);
-      gtk_widget_grab_focus (combo_box->priv->tree_view);
-    }
-
-  gtk_grab_add (combo_box->priv->popup_window);
-  gdk_pointer_grab (combo_box->priv->popup_window->window, TRUE,
-                    GDK_BUTTON_PRESS_MASK |
-                    GDK_BUTTON_RELEASE_MASK |
-                    GDK_POINTER_MOTION_MASK,
-                    NULL, NULL, GDK_CURRENT_TIME);
-
-  gtk_grab_add (combo_box->priv->tree_view);
-}
-
-/**
- * gtk_combo_box_popdown:
- * @combo_box: a #GtkComboBox
- *
- * Hides the menu or dropdown list of @combo_box.
- *
- * This function is mostly intended for use by accessibility technologies;
- * applications should have little use for it.
- *
- * Since: 2.4
- **/
-void
-gtk_combo_box_popdown (GtkComboBox *combo_box)
-{
-  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
-
-  if (!GTK_WIDGET_REALIZED (GTK_WIDGET (combo_box)))
-    return;
-
-  if (GTK_IS_MENU (combo_box->priv->popup_widget))
-    {
-      gtk_menu_popdown (GTK_MENU (combo_box->priv->popup_widget));
-      return;
-    }
-
-  gtk_combo_box_list_remove_grabs (combo_box);
-  gtk_widget_hide_all (combo_box->priv->popup_window);
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
-                                FALSE);
-}
-
-static gint
-gtk_combo_box_calc_requested_width (GtkComboBox *combo_box,
-                                    GtkTreePath *path)
-{
-  gint padding;
-  GtkRequisition req;
-
-  if (combo_box->priv->cell_view)
-    gtk_widget_style_get (combo_box->priv->cell_view,
-                          "focus-line-width", &padding,
-                          NULL);
-  else
-    padding = 0;
-
-  /* add some pixels for good measure */
-  padding += BONUS_PADDING;
-
-  if (combo_box->priv->cell_view)
-    gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (combo_box->priv->cell_view),
-                                   path, &req);
-  else
-    req.width = 0;
-
-  return req.width + padding;
-}
-
-static void
-gtk_combo_box_remeasure (GtkComboBox *combo_box)
-{
-  GtkTreeIter iter;
-  GtkTreePath *path;
-  gint padding = 0;
-
-  if (!combo_box->priv->model ||
-      !gtk_tree_model_get_iter_first (combo_box->priv->model, &iter))
-    return;
-
-  combo_box->priv->width = 0;
-
-#if GTK_CHECK_VERSION(2,2,0)
-  path = gtk_tree_path_new_from_indices (0, -1);
-#else
-  path = gtk_tree_path_new_first();
-#endif
-
-  if (combo_box->priv->cell_view)
-    gtk_widget_style_get (combo_box->priv->cell_view,
-                          "focus-line-width", &padding,
-                          NULL);
-  else
-    padding = 0;
-
-  /* add some pixels for good measure */
-  padding += BONUS_PADDING;
-
-  do
-    {
-      GtkRequisition req;
-
-      if (combo_box->priv->cell_view)
-	gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (combo_box->priv->cell_view),
-                                       path, &req);
-      else
-        req.width = 0;
-
-      combo_box->priv->width = MAX (combo_box->priv->width,
-                                    req.width + padding);
-
-      gtk_tree_path_next (path);
-    }
-  while (gtk_tree_model_iter_next (combo_box->priv->model, &iter));
-
-  gtk_tree_path_free (path);
-}
-
-static void
-gtk_combo_box_size_request (GtkWidget      *widget,
-                            GtkRequisition *requisition)
-{
-  gint width, height;
-  GtkRequisition bin_req;
-
-  GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
-
-  /* common */
-  gtk_widget_size_request (GTK_BIN (widget)->child, &bin_req);
-  gtk_combo_box_remeasure (combo_box);
-  bin_req.width = MAX (bin_req.width, combo_box->priv->width);
-
-  gtk_combo_box_check_appearance (combo_box);
-
-  if (!combo_box->priv->tree_view)
-    {
-      /* menu mode */
-
-      if (combo_box->priv->cell_view)
-        {
-          GtkRequisition button_req, sep_req, arrow_req;
-          gint border_width, xthickness, ythickness;
-
-          gtk_widget_size_request (combo_box->priv->button, &button_req);
-          border_width = GTK_CONTAINER (combo_box->priv->button)->border_width;
-          xthickness = combo_box->priv->button->style->xthickness;
-          ythickness = combo_box->priv->button->style->ythickness;
-
-          bin_req.width = MAX (bin_req.width, combo_box->priv->width);
-
-          gtk_widget_size_request (combo_box->priv->separator, &sep_req);
-          gtk_widget_size_request (combo_box->priv->arrow, &arrow_req);
-
-          height = MAX (sep_req.height, arrow_req.height);
-          height = MAX (height, bin_req.height);
-
-          width = bin_req.width + sep_req.width + arrow_req.width;
-
-          height += border_width + 1 + ythickness * 2 + 4;
-          width += border_width + 1 + xthickness * 2 + 4;
-
-          requisition->width = width;
-          requisition->height = height;
-        }
-      else
-        {
-          GtkRequisition but_req;
-
-          gtk_widget_size_request (combo_box->priv->button, &but_req);
-
-          requisition->width = bin_req.width + but_req.width;
-          requisition->height = MAX (bin_req.height, but_req.height);
-        }
-    }
-  else
-    {
-      /* list mode */
-      GtkRequisition button_req, frame_req;
-
-      /* sample + frame */
-      *requisition = bin_req;
-
-      if (combo_box->priv->cell_view_frame)
-        {
-	  gtk_widget_size_request (combo_box->priv->cell_view_frame, &frame_req);
-          requisition->width += 2 *
-            (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
-             GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness);
-          requisition->height += 2 *
-            (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
-             GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness);
-        }
-
-      /* the button */
-      gtk_widget_size_request (combo_box->priv->button, &button_req);
-
-      requisition->height = MAX (requisition->height, button_req.height);
-      requisition->width += button_req.width;
-    }
-}
-
-static void
-gtk_combo_box_size_allocate (GtkWidget     *widget,
-                             GtkAllocation *allocation)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
-  GtkAllocation child;
-  GtkRequisition req;
-  gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
-
-  widget->allocation = *allocation;
-
-  gtk_combo_box_check_appearance (combo_box);
-
-  if (!combo_box->priv->tree_view)
-    {
-      if (combo_box->priv->cell_view)
-        {
-          gint border_width, xthickness, ythickness;
-          gint width;
-
-          /* menu mode */
-          gtk_widget_size_allocate (combo_box->priv->button, allocation);
-
-          /* set some things ready */
-          border_width = GTK_CONTAINER (combo_box->priv->button)->border_width;
-          xthickness = combo_box->priv->button->style->xthickness;
-          ythickness = combo_box->priv->button->style->ythickness;
-
-          child.x = allocation->x + border_width + 1 + xthickness + 2;
-          child.y = allocation->y + border_width + 1 + ythickness + 2;
-
-          width = MAX(1, allocation->width - (border_width + 1 + xthickness * 2 + 4));
-
-          /* handle the children */
-          gtk_widget_size_request (combo_box->priv->arrow, &req);
-          child.width = req.width;
-          child.height = MAX(1, allocation->height - 2 * (child.y - allocation->y));
-          if (!is_rtl)
-            child.x += width - req.width;
-          gtk_widget_size_allocate (combo_box->priv->arrow, &child);
-          if (is_rtl)
-            child.x += req.width;
-          gtk_widget_size_request (combo_box->priv->separator, &req);
-          child.width = req.width;
-          if (!is_rtl)
-            child.x -= req.width;
-          gtk_widget_size_allocate (combo_box->priv->separator, &child);
-
-          if (is_rtl)
-            {
-              child.x += req.width;
-              child.width = MAX(1, allocation->x + allocation->width
-                - (border_width + 1 + xthickness + 2) - child.x);
-            }
-          else
-            {
-              child.width = child.x;
-              child.x = allocation->x + border_width + 1 + xthickness + 2;
-              child.width = MAX(1, child.width - child.x);
-            }
-
-          gtk_widget_size_allocate (GTK_BIN (widget)->child, &child);
-        }
-      else
-        {
-          gtk_widget_size_request (combo_box->priv->button, &req);
-          if (is_rtl)
-            child.x = allocation->x;
-          else
-            child.x = allocation->x + allocation->width - req.width;
-          child.y = allocation->y;
-          child.width = req.width;
-          child.height = allocation->height;
-          gtk_widget_size_allocate (combo_box->priv->button, &child);
-
-          if (is_rtl)
-            child.x = allocation->x + req.width;
-          else
-            child.x = allocation->x;
-          child.y = allocation->y;
-          child.width = MAX(1, allocation->width - req.width);
-          gtk_widget_size_allocate (GTK_BIN (widget)->child, &child);
-        }
-    }
-  else
-    {
-      /* list mode */
-
-      /* button */
-      gtk_widget_size_request (combo_box->priv->button, &req);
-      if (is_rtl)
-        child.x = allocation->x;
-      else
-        child.x = allocation->x + allocation->width - req.width;
-      child.y = allocation->y;
-      child.width = req.width;
-      child.height = allocation->height;
-      gtk_widget_size_allocate (combo_box->priv->button, &child);
-
-      /* frame */
-      if (is_rtl)
-        child.x = allocation->x + req.width;
-      else
-        child.x = allocation->x;
-      child.y = allocation->y;
-      child.width = MAX (1, allocation->width - req.width);
-      child.height = allocation->height;
-
-      if (combo_box->priv->cell_view_frame)
-        {
-          gtk_widget_size_allocate (combo_box->priv->cell_view_frame, &child);
-
-          /* the sample */
-          child.x +=
-            GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
-            GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness;
-          child.y +=
-            GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
-            GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness;
-          child.width -= 2 * (
-            GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
-            GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness);
-	  child.width = MAX(1,child.width);
-          child.height -= 2 * (
-            GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width +
-            GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness);
-	  child.height = MAX(1,child.height);
-        }
-
-      gtk_widget_size_allocate (GTK_BIN (combo_box)->child, &child);
-    }
-}
-
-static void
-gtk_combo_box_unset_model (GtkComboBox *combo_box)
-{
-  if (combo_box->priv->model)
-    {
-      g_signal_handler_disconnect (combo_box->priv->model,
-				   combo_box->priv->inserted_id);
-      g_signal_handler_disconnect (combo_box->priv->model,
-				   combo_box->priv->deleted_id);
-      g_signal_handler_disconnect (combo_box->priv->model,
-				   combo_box->priv->reordered_id);
-      g_signal_handler_disconnect (combo_box->priv->model,
-				   combo_box->priv->changed_id);
-    }
-
-  /* menu mode */
-  if (!combo_box->priv->tree_view)
-    {
-      if (combo_box->priv->popup_widget)
-        gtk_container_foreach (GTK_CONTAINER (combo_box->priv->popup_widget),
-                               (GtkCallback)gtk_widget_destroy, NULL);
-    }
-
-  if (combo_box->priv->model)
-    {
-      g_object_unref (G_OBJECT (combo_box->priv->model));
-      combo_box->priv->model = NULL;
-    }
-
-  if (combo_box->priv->cell_view)
-    gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->cell_view), NULL);
-}
-
-static void
-gtk_combo_box_forall (GtkContainer *container,
-                      gboolean      include_internals,
-                      GtkCallback   callback,
-                      gpointer      callback_data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (container);
-
-  if (include_internals)
-    {
-      if (combo_box->priv->button)
-	(* callback) (combo_box->priv->button, callback_data);
-      if (combo_box->priv->cell_view_frame)
-	(* callback) (combo_box->priv->cell_view_frame, callback_data);
-    }
-
-  if (GTK_BIN (container)->child)
-    (* callback) (GTK_BIN (container)->child, callback_data);
-}
-
-static gboolean
-gtk_combo_box_expose_event (GtkWidget      *widget,
-                            GdkEventExpose *event)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
-
-  if (!combo_box->priv->tree_view)
-    {
-      gtk_container_propagate_expose (GTK_CONTAINER (widget),
-                                      combo_box->priv->button, event);
-    }
-  else
-    {
-      gtk_container_propagate_expose (GTK_CONTAINER (widget),
-                                      combo_box->priv->button, event);
-
-      if (combo_box->priv->cell_view_frame)
-        gtk_container_propagate_expose (GTK_CONTAINER (widget),
-                                        combo_box->priv->cell_view_frame, event);
-    }
-
-  gtk_container_propagate_expose (GTK_CONTAINER (widget),
-                                  GTK_BIN (widget)->child, event);
-
-  return FALSE;
-}
-
-static gboolean
-gtk_combo_box_scroll_event (GtkWidget          *widget,
-                            GdkEventScroll     *event)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
-  gint index;
-  gint items;
-
-  index = gtk_combo_box_get_active (combo_box);
-
-  if (index != -1)
-    {
-      items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL);
-
-      if (event->direction == GDK_SCROLL_UP)
-        index--;
-      else
-        index++;
-
-      gtk_combo_box_set_active (combo_box, CLAMP (index, 0, items - 1));
-    }
-
-  return TRUE;
-}
-
-/*
- * menu style
- */
-
-static void
-cell_view_sync_cells (GtkComboBox *combo_box,
-                      GtkCellView *cell_view)
-{
-  GSList *k;
-
-  for (k = combo_box->priv->cells; k; k = k->next)
-    {
-      GSList *j;
-      ComboCellInfo *info = (ComboCellInfo *)k->data;
-
-      if (info->pack == GTK_PACK_START)
-        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cell_view),
-                                    info->cell, info->expand);
-      else if (info->pack == GTK_PACK_END)
-        gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (cell_view),
-                                  info->cell, info->expand);
-
-      gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (cell_view),
-                                          info->cell,
-                                          info->func, info->func_data, NULL);
-
-      for (j = info->attributes; j; j = j->next->next)
-        {
-          gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (cell_view),
-                                         info->cell,
-                                         j->data,
-                                         GPOINTER_TO_INT (j->next->data));
-        }
-    }
-}
-
-static void
-gtk_combo_box_menu_setup (GtkComboBox *combo_box,
-                          gboolean     add_children)
-{
-  GtkWidget *menu;
-
-  if (combo_box->priv->cell_view)
-    {
-      combo_box->priv->button = gtk_toggle_button_new ();
-      g_signal_connect (combo_box->priv->button, "toggled",
-                        G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
-      g_signal_connect_after (combo_box->priv->button, "key_press_event",
-			      G_CALLBACK (gtk_combo_box_key_press), combo_box);
-      gtk_widget_set_parent (combo_box->priv->button,
-                             GTK_BIN (combo_box)->child->parent);
-
-      combo_box->priv->box = gtk_hbox_new (FALSE, 0);
-      gtk_container_add (GTK_CONTAINER (combo_box->priv->button),
-			 combo_box->priv->box);
-
-      combo_box->priv->separator = gtk_vseparator_new ();
-      gtk_container_add (GTK_CONTAINER (combo_box->priv->box),
-			 combo_box->priv->separator);
-
-      combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
-      gtk_container_add (GTK_CONTAINER (combo_box->priv->box),
-			 combo_box->priv->arrow);
-
-      gtk_widget_show_all (combo_box->priv->button);
-    }
-  else
-    {
-      combo_box->priv->button = gtk_toggle_button_new ();
-      g_signal_connect (combo_box->priv->button, "toggled",
-                        G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
-      g_signal_connect_after (combo_box, "key_press_event",
-			      G_CALLBACK (gtk_combo_box_key_press), combo_box);
-      gtk_widget_set_parent (combo_box->priv->button,
-                             GTK_BIN (combo_box)->child->parent);
-
-      combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
-      gtk_container_add (GTK_CONTAINER (combo_box->priv->button),
-                         combo_box->priv->arrow);
-      gtk_widget_show_all (combo_box->priv->button);
-    }
-
-  g_signal_connect (combo_box->priv->button, "button_press_event",
-                    G_CALLBACK (gtk_combo_box_menu_button_press),
-                    combo_box);
-
-  /* create our funky menu */
-  menu = gtk_menu_new ();
-  g_signal_connect (menu, "key_press_event",
-		    G_CALLBACK (gtk_combo_box_menu_key_press), combo_box);
-  gtk_combo_box_set_popup_widget (combo_box, menu);
-
-  /* add items */
-  if (add_children)
-    gtk_combo_box_menu_fill (combo_box);
-
-}
-
-static void
-gtk_combo_box_menu_fill (GtkComboBox *combo_box)
-{
-  gint i, items;
-  GtkWidget *menu;
-  GtkWidget *tmp;
-
-  if (!combo_box->priv->model)
-    return;
-
-  items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL);
-  menu = combo_box->priv->popup_widget;
-
-  for (i = 0; i < items; i++)
-    {
-      GtkTreePath *path;
-#if GTK_CHECK_VERSION(2,2,0)
-      path = gtk_tree_path_new_from_indices (i, -1);
-#else
-      char buf[32];
-      g_snprintf(buf, sizeof(buf), "%d", i);
-      path = gtk_tree_path_new_from_string(buf);
-#endif
-      tmp = gtk_cell_view_menu_item_new_from_model (combo_box->priv->model,
-                                                    path);
-      g_signal_connect (tmp, "activate",
-                        G_CALLBACK (gtk_combo_box_menu_item_activate),
-                        combo_box);
-
-      cell_view_sync_cells (combo_box,
-                            GTK_CELL_VIEW (GTK_BIN (tmp)->child));
-
-      gtk_menu_shell_append (GTK_MENU_SHELL (menu), tmp);
-
-      if (combo_box->priv->wrap_width)
-        gtk_combo_box_relayout_item (combo_box, i);
-
-      gtk_widget_show (tmp);
-
-      gtk_tree_path_free (path);
-    }
-}
-
-static void
-gtk_combo_box_menu_destroy (GtkComboBox *combo_box)
-{
-  g_signal_handlers_disconnect_matched (combo_box->priv->button,
-                                        G_SIGNAL_MATCH_DATA,
-                                        0, 0, NULL,
-                                        gtk_combo_box_menu_button_press, NULL);
-
-  /* unparent will remove our latest ref */
-  gtk_widget_unparent (combo_box->priv->button);
-
-  combo_box->priv->box = NULL;
-  combo_box->priv->button = NULL;
-  combo_box->priv->arrow = NULL;
-  combo_box->priv->separator = NULL;
-
-  /* changing the popup window will unref the menu and the children */
-}
-
-/*
- * grid
- */
-
-static void
-gtk_combo_box_item_get_size (GtkComboBox *combo_box,
-                             gint         index_,
-                             gint        *cols,
-                             gint        *rows)
-{
-  GtkTreeIter iter;
-
-  gtk_tree_model_iter_nth_child (combo_box->priv->model, &iter, NULL, index_);
-
-  if (cols)
-    {
-      if (combo_box->priv->col_column == -1)
-        *cols = 1;
-      else
-        gtk_tree_model_get (combo_box->priv->model, &iter,
-                            combo_box->priv->col_column, cols,
-                            -1);
-    }
-
-  if (rows)
-    {
-      if (combo_box->priv->row_column == -1)
-        *rows = 1;
-      else
-        gtk_tree_model_get (combo_box->priv->model, &iter,
-                            combo_box->priv->row_column, rows,
-                            -1);
-    }
-}
-
-static gboolean
-menu_occupied (GtkMenu *menu,
-               guint    left_attach,
-               guint    right_attach,
-               guint    top_attach,
-               guint    bottom_attach)
-{
-  GList *i;
-
-  g_return_val_if_fail (GTK_IS_MENU (menu), TRUE);
-  g_return_val_if_fail (left_attach < right_attach, TRUE);
-  g_return_val_if_fail (top_attach < bottom_attach, TRUE);
-
-  for (i = GTK_MENU_SHELL (menu)->children; i; i = i->next)
-    {
-      guint l, r, b, t;
-      gboolean h_intersect = FALSE;
-      gboolean v_intersect = FALSE;
-
-      gtk_container_child_get (GTK_CONTAINER (menu), i->data,
-                               "left_attach", &l,
-                               "right_attach", &r,
-                               "bottom_attach", &b,
-                               "top_attach", &t,
-                               NULL);
-
-      /* look if this item intersects with the given coordinates */
-      h_intersect  = left_attach <= l && l <= right_attach;
-      h_intersect &= left_attach <= r && r <= right_attach;
-
-      v_intersect  = top_attach <= t && t <= bottom_attach;
-      v_intersect &= top_attach <= b && b <= bottom_attach;
-
-      if (h_intersect && v_intersect)
-        return TRUE;
-    }
-
-  return FALSE;
-}
-
-static void
-gtk_combo_box_relayout_item (GtkComboBox *combo_box,
-                             gint         index)
-{
-  gint current_col = 0, current_row = 0;
-  gint rows, cols;
-  GList *list, *nth;
-  GtkWidget *item, *last;
-  GtkWidget *menu;
-
-  menu = combo_box->priv->popup_widget;
-  if (!GTK_IS_MENU_SHELL (menu))
-    return;
-
-  list = gtk_container_get_children (GTK_CONTAINER (menu));
-  nth = g_list_nth (list, index);
-  item = nth->data;
-  if (nth->prev)
-    last = nth->prev->data;
-  else
-    last = NULL;
-  g_list_free (list);
-
-  gtk_combo_box_item_get_size (combo_box, index, &cols, &rows);
-
-   if (combo_box->priv->col_column == -1 &&
-      combo_box->priv->row_column == -1 &&
-      last)
-    {
-      gtk_container_child_get (GTK_CONTAINER (menu),
-			       last,
-			       "right_attach", &current_col,
-			       "top_attach", &current_row,
-			       NULL);
-      if (current_col + cols > combo_box->priv->wrap_width)
-	{
-	  current_col = 0;
-	  current_row++;
-	}
-    }
-  else
-    {
-      /* look for a good spot */
-      while (1)
-	{
-	  if (current_col + cols > combo_box->priv->wrap_width)
-	    {
-	      current_col = 0;
-	      current_row++;
-	    }
-
-	  if (!menu_occupied (GTK_MENU (menu),
-			      current_col, current_col + cols,
-			      current_row, current_row + rows))
-	    break;
-
-	  current_col++;
-	}
-    }
-
-  /* set attach props */
-  gtk_menu_attach (GTK_MENU (menu), item,
-                   current_col, current_col + cols,
-                   current_row, current_row + rows);
-}
-
-static void
-gtk_combo_box_relayout (GtkComboBox *combo_box)
-{
-  GList *list, *j;
-  GtkWidget *menu;
-
-  menu = combo_box->priv->popup_widget;
-
-  /* do nothing unless we are in menu style and realized */
-  if (combo_box->priv->tree_view || !GTK_IS_MENU_SHELL (menu))
-    return;
-
-  /* get rid of all children */
-  list = gtk_container_get_children (GTK_CONTAINER (menu));
-
-  for (j = g_list_last (list); j; j = j->prev)
-    gtk_container_remove (GTK_CONTAINER (menu), j->data);
-
-  g_list_free (list);
-
-  /* and relayout */
-  gtk_combo_box_menu_fill (combo_box);
-}
-
-/* callbacks */
-static gboolean
-gtk_combo_box_menu_button_press (GtkWidget      *widget,
-                                 GdkEventButton *event,
-                                 gpointer        user_data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
-
-  if (! GTK_IS_MENU (combo_box->priv->popup_widget))
-    return FALSE;
-
-  if (event->type == GDK_BUTTON_PRESS && event->button == 1)
-    {
-      combo_box->priv->popup_in_progress = TRUE;
-
-      gtk_menu_set_active (GTK_MENU (combo_box->priv->popup_widget),
-			   combo_box->priv->active_item);
-
-      if (combo_box->priv->wrap_width == 0)
-	{
-          GtkRequisition requisition;
-          gint width;
-
-	  width = GTK_WIDGET (combo_box)->allocation.width;
-          gtk_widget_size_request (combo_box->priv->popup_widget, &requisition);
-
-	  gtk_widget_set_size_request (combo_box->priv->popup_widget,
-                                       MAX (width, requisition.width), -1);
-	}
-
-      gtk_menu_popup (GTK_MENU (combo_box->priv->popup_widget),
-                      NULL, NULL,
-#if GTK_CHECK_VERSION(2,2,0)
-                      gtk_combo_box_menu_position,
-#else
-		      NULL,
-#endif
-		      combo_box, event->button, event->time);
-
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-static void
-gtk_combo_box_menu_item_activate (GtkWidget *item,
-                                  gpointer   user_data)
-{
-  gint index;
-  GtkWidget *menu;
-  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
-
-  menu = combo_box->priv->popup_widget;
-  g_return_if_fail (GTK_IS_MENU (menu));
-
-  index = g_list_index (GTK_MENU_SHELL (menu)->children, item);
-
-  gtk_combo_box_set_active (combo_box, index);
-}
-
-static void
-gtk_combo_box_model_row_inserted (GtkTreeModel     *model,
-				  GtkTreePath      *path,
-				  GtkTreeIter      *iter,
-				  gpointer          user_data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
-  gint index = gtk_tree_path_get_indices (path)[0];
-
-  if (combo_box->priv->active_item >= index)
-    combo_box->priv->active_item++;
-
-  if (!combo_box->priv->tree_view)
-    gtk_combo_box_menu_row_inserted (model, path, iter, user_data);
-}
-
-static void
-gtk_combo_box_model_row_deleted (GtkTreeModel     *model,
-				 GtkTreePath      *path,
-				 gpointer          user_data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
-  gint index = gtk_tree_path_get_indices (path)[0];
-
-  if (!combo_box->priv->tree_view)
-    gtk_combo_box_menu_row_deleted (model, path, user_data);
-
-  if (index == combo_box->priv->active_item)
-    {
-      gint items = gtk_tree_model_iter_n_children (model, NULL);
-
-      if (items == 0)
-	gtk_combo_box_set_active_internal (combo_box, -1);
-      else if (index == items)
-	gtk_combo_box_set_active_internal (combo_box, index - 1);
-      else
-	gtk_combo_box_set_active_internal (combo_box, index);
-    }
-  else if (combo_box->priv->active_item > index)
-    combo_box->priv->active_item--;
-}
-
-static void
-gtk_combo_box_model_rows_reordered (GtkTreeModel    *model,
-				    GtkTreePath     *path,
-				    GtkTreeIter     *iter,
-				    gint            *new_order,
-				    gpointer         user_data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
-  gint items = gtk_tree_model_iter_n_children (model, NULL);
-  gint i;
-
-  for (i = 0; i < items; i++)
-    if (new_order[i] == combo_box->priv->active_item)
-      {
-	combo_box->priv->active_item = i;
-	break;
-      }
-
-  if (!combo_box->priv->tree_view)
-    gtk_combo_box_menu_rows_reordered (model, path, iter, new_order, user_data);
-}
-
-static void
-gtk_combo_box_model_row_changed (GtkTreeModel     *model,
-				 GtkTreePath      *path,
-				 GtkTreeIter      *iter,
-				 gpointer          user_data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
-  gint index = gtk_tree_path_get_indices (path)[0];
-
-  if (index == combo_box->priv->active_item &&
-      combo_box->priv->cell_view)
-    gtk_widget_queue_resize (GTK_WIDGET (combo_box->priv->cell_view));
-
-  if (combo_box->priv->tree_view)
-    gtk_combo_box_list_row_changed (model, path, iter, user_data);
-  else
-    gtk_combo_box_menu_row_changed (model, path, iter, user_data);
-}
-
-
-static void
-gtk_combo_box_menu_row_inserted (GtkTreeModel *model,
-                                 GtkTreePath  *path,
-                                 GtkTreeIter  *iter,
-                                 gpointer      user_data)
-{
-  GtkWidget *menu;
-  GtkWidget *item;
-  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
-
-  if (!combo_box->priv->popup_widget)
-    return;
-
-  menu = combo_box->priv->popup_widget;
-  g_return_if_fail (GTK_IS_MENU (menu));
-
-  item = gtk_cell_view_menu_item_new_from_model (model, path);
-  g_signal_connect (item, "activate",
-                    G_CALLBACK (gtk_combo_box_menu_item_activate),
-                    combo_box);
-
-  cell_view_sync_cells (combo_box, GTK_CELL_VIEW (GTK_BIN (item)->child));
-
-  gtk_menu_shell_insert (GTK_MENU_SHELL (menu), item,
-                         gtk_tree_path_get_indices (path)[0]);
-  gtk_widget_show (item);
-}
-
-static void
-gtk_combo_box_menu_row_deleted (GtkTreeModel *model,
-                                GtkTreePath  *path,
-                                gpointer      user_data)
-{
-  gint index;
-  GtkWidget *menu;
-  GtkWidget *item;
-  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
-
-  if (!combo_box->priv->popup_widget)
-    return;
-
-  index = gtk_tree_path_get_indices (path)[0];
-
-  menu = combo_box->priv->popup_widget;
-  g_return_if_fail (GTK_IS_MENU (menu));
-
-  item = g_list_nth_data (GTK_MENU_SHELL (menu)->children, index);
-  g_return_if_fail (GTK_IS_MENU_ITEM (item));
-
-  gtk_container_remove (GTK_CONTAINER (menu), item);
-}
-
-static void
-gtk_combo_box_menu_rows_reordered  (GtkTreeModel     *model,
-				    GtkTreePath      *path,
-				    GtkTreeIter      *iter,
-				    gint             *new_order,
-				    gpointer          user_data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
-
-  gtk_combo_box_relayout (combo_box);
-}
-
-static void
-gtk_combo_box_menu_row_changed (GtkTreeModel *model,
-                                GtkTreePath  *path,
-                                GtkTreeIter  *iter,
-                                gpointer      user_data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
-  gint width;
-
-  if (!combo_box->priv->popup_widget)
-    return;
-
-  if (combo_box->priv->wrap_width)
-    gtk_combo_box_relayout_item (combo_box,
-                                 gtk_tree_path_get_indices (path)[0]);
-
-  width = gtk_combo_box_calc_requested_width (combo_box, path);
-
-  if (width > combo_box->priv->width)
-    {
-      if (combo_box->priv->cell_view)
-	{
-	  gtk_widget_set_size_request (combo_box->priv->cell_view, width, -1);
-	  gtk_widget_queue_resize (combo_box->priv->cell_view);
-	}
-      combo_box->priv->width = width;
-    }
-}
-
-/*
- * list style
- */
-
-static void
-gtk_combo_box_list_setup (GtkComboBox *combo_box)
-{
-  GSList *i;
-  GtkTreeSelection *sel;
-
-  combo_box->priv->button = gtk_toggle_button_new ();
-  gtk_widget_set_parent (combo_box->priv->button,
-                         GTK_BIN (combo_box)->child->parent);
-  g_signal_connect (combo_box->priv->button, "button_press_event",
-                    G_CALLBACK (gtk_combo_box_list_button_pressed), combo_box);
-  g_signal_connect (combo_box->priv->button, "toggled",
-                    G_CALLBACK (gtk_combo_box_button_toggled), combo_box);
-  g_signal_connect_after (combo_box, "key_press_event",
-			  G_CALLBACK (gtk_combo_box_key_press), combo_box);
-
-  combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
-  gtk_container_add (GTK_CONTAINER (combo_box->priv->button),
-                     combo_box->priv->arrow);
-  combo_box->priv->separator = NULL;
-  gtk_widget_show_all (combo_box->priv->button);
-
-  if (combo_box->priv->cell_view)
-    {
-      combo_box->priv->cell_view_frame = gtk_frame_new (NULL);
-      gtk_widget_set_parent (combo_box->priv->cell_view_frame,
-                             GTK_BIN (combo_box)->child->parent);
-      gtk_frame_set_shadow_type (GTK_FRAME (combo_box->priv->cell_view_frame),
-                                 GTK_SHADOW_IN);
-
-      gtk_cell_view_set_background_color (GTK_CELL_VIEW (combo_box->priv->cell_view),
-					  &GTK_WIDGET (combo_box)->style->base[GTK_WIDGET_STATE (combo_box)]);
-
-      combo_box->priv->box = gtk_event_box_new ();
-      /*
-      gtk_event_box_set_visible_window (GTK_EVENT_BOX (combo_box->priv->box),
-					FALSE);
-      */
-
-      gtk_container_add (GTK_CONTAINER (combo_box->priv->cell_view_frame),
-			 combo_box->priv->box);
-
-      gtk_widget_show_all (combo_box->priv->cell_view_frame);
-
-      g_signal_connect (combo_box->priv->box, "button_press_event",
-			G_CALLBACK (gtk_combo_box_list_button_pressed),
-			combo_box);
-    }
-
-  combo_box->priv->tree_view = gtk_tree_view_new ();
-  sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view));
-  gtk_tree_selection_set_mode (sel, GTK_SELECTION_BROWSE);
-  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (combo_box->priv->tree_view),
-                                     FALSE);
-  /*
-  _gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (combo_box->priv->tree_view),
-				      TRUE);
-  */
-  if (combo_box->priv->model)
-    gtk_tree_view_set_model (GTK_TREE_VIEW (combo_box->priv->tree_view),
-			     combo_box->priv->model);
-
-  g_signal_connect (combo_box->priv->tree_view, "button_press_event",
-                    G_CALLBACK (gtk_combo_box_list_button_pressed),
-                    combo_box);
-  g_signal_connect (combo_box->priv->tree_view, "button_release_event",
-                    G_CALLBACK (gtk_combo_box_list_button_released),
-                    combo_box);
-  g_signal_connect (combo_box->priv->tree_view, "key_press_event",
-                    G_CALLBACK (gtk_combo_box_list_key_press),
-                    combo_box);
-
-  combo_box->priv->column = gtk_tree_view_column_new ();
-  gtk_tree_view_append_column (GTK_TREE_VIEW (combo_box->priv->tree_view),
-                               combo_box->priv->column);
-
-  /* sync up */
-  for (i = combo_box->priv->cells; i; i = i->next)
-    {
-      GSList *j;
-      ComboCellInfo *info = (ComboCellInfo *)i->data;
-
-      if (info->pack == GTK_PACK_START)
-        gtk_tree_view_column_pack_start (combo_box->priv->column,
-                                         info->cell, info->expand);
-      else if (info->pack == GTK_PACK_END)
-        gtk_tree_view_column_pack_end (combo_box->priv->column,
-                                       info->cell, info->expand);
-
-      for (j = info->attributes; j; j = j->next->next)
-        {
-          gtk_tree_view_column_add_attribute (combo_box->priv->column,
-                                              info->cell,
-                                              j->data,
-                                              GPOINTER_TO_INT (j->next->data));
-        }
-    }
-
-  if (combo_box->priv->active_item != -1)
-    {
-      GtkTreePath *path;
-
-#if GTK_CHECK_VERSION(2,2,0)
-      path = gtk_tree_path_new_from_indices (combo_box->priv->active_item, -1);
-#else
-      char buf[32];
-      g_snprintf(buf, sizeof(buf), "%d", combo_box->priv->active_item);
-      path = gtk_tree_path_new_from_string(buf);
-#endif
-      if (path)
-        {
-          gtk_tree_view_set_cursor (GTK_TREE_VIEW (combo_box->priv->tree_view),
-                                    path, NULL, FALSE);
-          gtk_tree_path_free (path);
-        }
-    }
-
-  /* set sample/popup widgets */
-  gtk_combo_box_set_popup_widget (combo_box, combo_box->priv->tree_view);
-
-  gtk_widget_show (combo_box->priv->tree_view);
-}
-
-static void
-gtk_combo_box_list_destroy (GtkComboBox *combo_box)
-{
-  /* disconnect signals */
-  g_signal_handlers_disconnect_matched (combo_box->priv->tree_view,
-                                        G_SIGNAL_MATCH_DATA,
-                                        0, 0, NULL, NULL, combo_box);
-  g_signal_handlers_disconnect_matched (combo_box->priv->button,
-                                        G_SIGNAL_MATCH_DATA,
-                                        0, 0, NULL,
-                                        gtk_combo_box_list_button_pressed,
-                                        NULL);
-  if (combo_box->priv->box)
-    g_signal_handlers_disconnect_matched (combo_box->priv->box,
-					  G_SIGNAL_MATCH_DATA,
-					  0, 0, NULL,
-					  gtk_combo_box_list_button_pressed,
-					  NULL);
-
-  /* destroy things (unparent will kill the latest ref from us)
-   * last unref on button will destroy the arrow
-   */
-  gtk_widget_unparent (combo_box->priv->button);
-  combo_box->priv->button = NULL;
-  combo_box->priv->arrow = NULL;
-
-  if (combo_box->priv->cell_view)
-    {
-      g_object_set (G_OBJECT (combo_box->priv->cell_view),
-                    "background_set", FALSE,
-                    NULL);
-    }
-
-  if (combo_box->priv->cell_view_frame)
-    {
-      gtk_widget_unparent (combo_box->priv->cell_view_frame);
-      combo_box->priv->cell_view_frame = NULL;
-      combo_box->priv->box = NULL;
-    }
-
-  gtk_widget_destroy (combo_box->priv->tree_view);
-
-  combo_box->priv->tree_view = NULL;
-  combo_box->priv->popup_widget = NULL;
-}
-
-/* callbacks */
-static void
-gtk_combo_box_list_remove_grabs (GtkComboBox *combo_box)
-{
-  if (combo_box->priv->tree_view &&
-      GTK_WIDGET_HAS_GRAB (combo_box->priv->tree_view))
-    {
-      gtk_grab_remove (combo_box->priv->tree_view);
-    }
-
-  if (combo_box->priv->popup_window &&
-      GTK_WIDGET_HAS_GRAB (combo_box->priv->popup_window))
-    {
-      gtk_grab_remove (combo_box->priv->popup_window);
-      gdk_keyboard_ungrab (GDK_CURRENT_TIME);
-      gdk_pointer_ungrab (GDK_CURRENT_TIME);
-    }
-}
-
-static gboolean
-gtk_combo_box_list_button_pressed (GtkWidget      *widget,
-                                   GdkEventButton *event,
-                                   gpointer        data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (data);
-
-  GtkWidget *ewidget = gtk_get_event_widget ((GdkEvent *)event);
-
-  if (ewidget == combo_box->priv->tree_view)
-    return TRUE;
-
-  if ((ewidget != combo_box->priv->button && ewidget != combo_box->priv->box) ||
-      gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (combo_box->priv->button)))
-    return FALSE;
-
-  gtk_combo_box_popup (combo_box);
-
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button),
-                                TRUE);
-
-  combo_box->priv->popup_in_progress = TRUE;
-
-  return TRUE;
-}
-
-static gboolean
-gtk_combo_box_list_button_released (GtkWidget      *widget,
-                                    GdkEventButton *event,
-                                    gpointer        data)
-{
-  gboolean ret;
-  GtkTreePath *path = NULL;
-
-  GtkComboBox *combo_box = GTK_COMBO_BOX (data);
-
-  gboolean popup_in_progress = FALSE;
-
-  GtkWidget *ewidget = gtk_get_event_widget ((GdkEvent *)event);
-
-  if (combo_box->priv->popup_in_progress)
-    {
-      popup_in_progress = TRUE;
-      combo_box->priv->popup_in_progress = FALSE;
-    }
-
-  if (ewidget != combo_box->priv->tree_view)
-    {
-      if (ewidget == combo_box->priv->button &&
-          !popup_in_progress &&
-          gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (combo_box->priv->button)))
-        {
-          gtk_combo_box_popdown (combo_box);
-          return TRUE;
-        }
-
-      /* released outside treeview */
-      if (ewidget != combo_box->priv->button)
-        {
-          gtk_combo_box_popdown (combo_box);
-
-          return TRUE;
-        }
-
-      return FALSE;
-    }
-
-  /* select something cool */
-  ret = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
-                                       event->x, event->y,
-                                       &path,
-                                       NULL, NULL, NULL);
-
-  if (!ret)
-    return TRUE; /* clicked outside window? */
-
-  gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]);
-  gtk_combo_box_popdown (combo_box);
-
-  gtk_tree_path_free (path);
-
-  return TRUE;
-}
-
-static gboolean
-gtk_combo_box_key_press (GtkWidget   *widget,
-			 GdkEventKey *event,
-			 gpointer     data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (data);
-  guint state = event->state & gtk_accelerator_get_default_mod_mask ();
-  gint items = 0;
-  gint index = gtk_combo_box_get_active (combo_box);
-  gint new_index;
-
-  if (combo_box->priv->model)
-    items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL);
-
-  if ((event->keyval == GDK_Down || event->keyval == GDK_KP_Down) &&
-      state == GDK_MOD1_MASK)
-    {
-      gtk_combo_box_popup (combo_box);
-
-      return TRUE;
-    }
-
-  switch (event->keyval)
-    {
-    case GDK_Down:
-    case GDK_KP_Down:
-      new_index = index + 1;
-      break;
-    case GDK_Up:
-    case GDK_KP_Up:
-      new_index = index - 1;
-      break;
-    case GDK_Page_Up:
-    case GDK_KP_Page_Up:
-    case GDK_Home:
-    case GDK_KP_Home:
-      new_index = 0;
-      break;
-    case GDK_Page_Down:
-    case GDK_KP_Page_Down:
-    case GDK_End:
-    case GDK_KP_End:
-      new_index = items - 1;
-      break;
-    default:
-      return FALSE;
-    }
-
-  if (items > 0)
-    gtk_combo_box_set_active (combo_box, CLAMP (new_index, 0, items - 1));
-
-  return TRUE;
-}
-
-static gboolean
-gtk_combo_box_menu_key_press (GtkWidget   *widget,
-			      GdkEventKey *event,
-			      gpointer     data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (data);
-  guint state = event->state & gtk_accelerator_get_default_mod_mask ();
-
-  if ((event->keyval == GDK_Up || event->keyval == GDK_KP_Up) &&
-      state == GDK_MOD1_MASK)
-    {
-      gtk_combo_box_popdown (combo_box);
-
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-static gboolean
-gtk_combo_box_list_key_press (GtkWidget   *widget,
-                              GdkEventKey *event,
-                              gpointer     data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (data);
-  guint state = event->state & gtk_accelerator_get_default_mod_mask ();
-
-  if (event->keyval == GDK_Escape ||
-      ((event->keyval == GDK_Up || event->keyval == GDK_KP_Up) &&
-       state == GDK_MOD1_MASK))
-    {
-      /* reset active item -- this is incredibly lame and ugly */
-      gtk_combo_box_set_active (combo_box,
-				gtk_combo_box_get_active (combo_box));
-
-      gtk_combo_box_popdown (combo_box);
-
-      return TRUE;
-    }
-
-  if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter ||
-      event->keyval == GDK_space || event->keyval == GDK_KP_Space)
-  {
-    gboolean ret = FALSE;
-    GtkTreeIter iter;
-    GtkTreeModel *model = NULL;
-
-    if (combo_box->priv->model)
-      {
-	GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view));
-
-	ret = gtk_tree_selection_get_selected (sel, &model, &iter);
-      }
-    if (ret)
-      {
-	GtkTreePath *path;
-
-	path = gtk_tree_model_get_path (model, &iter);
-	if (path)
-	  {
-	    gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]);
-	    gtk_tree_path_free (path);
-	  }
-      }
-
-    gtk_combo_box_popdown (combo_box);
-
-    return TRUE;
-  }
-
-  return FALSE;
-}
-
-static void
-gtk_combo_box_list_row_changed (GtkTreeModel *model,
-                                GtkTreePath  *path,
-                                GtkTreeIter  *iter,
-                                gpointer      data)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (data);
-  gint width;
-
-  width = gtk_combo_box_calc_requested_width (combo_box, path);
-
-  if (width > combo_box->priv->width)
-    {
-      if (combo_box->priv->cell_view)
-	{
-	  gtk_widget_set_size_request (combo_box->priv->cell_view, width, -1);
-	  gtk_widget_queue_resize (combo_box->priv->cell_view);
-	}
-      combo_box->priv->width = width;
-    }
-}
-
-/*
- * GtkCellLayout implementation
- */
-static void
-gtk_combo_box_cell_layout_pack_start (GtkCellLayout   *layout,
-                                      GtkCellRenderer *cell,
-                                      gboolean         expand)
-{
-  ComboCellInfo *info;
-  GtkComboBox *combo_box;
-  GtkWidget *menu;
-
-  g_return_if_fail (GTK_IS_COMBO_BOX (layout));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
-
-  combo_box = GTK_COMBO_BOX (layout);
-
-  g_object_ref (G_OBJECT (cell));
-  gtk_object_sink (GTK_OBJECT (cell));
-
-  info = g_new0 (ComboCellInfo, 1);
-  info->cell = cell;
-  info->expand = expand;
-  info->pack = GTK_PACK_START;
-
-  combo_box->priv->cells = g_slist_append (combo_box->priv->cells, info);
-
-  if (combo_box->priv->cell_view)
-    gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box->priv->cell_view),
-                                cell, expand);
-
-  if (combo_box->priv->column)
-    gtk_tree_view_column_pack_start (combo_box->priv->column, cell, expand);
-
-  menu = combo_box->priv->popup_widget;
-  if (GTK_IS_MENU (menu))
-    {
-      GList *i, *list;
-
-      list = gtk_container_get_children (GTK_CONTAINER (menu));
-      for (i = list; i; i = i->next)
-        {
-          GtkCellView *view;
-
-          if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
-            view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
-          else
-            view = GTK_CELL_VIEW (i->data);
-
-          gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (view), cell, expand);
-        }
-      g_list_free (list);
-    }
-}
-
-static void
-gtk_combo_box_cell_layout_pack_end (GtkCellLayout   *layout,
-                                    GtkCellRenderer *cell,
-                                    gboolean         expand)
-{
-  ComboCellInfo *info;
-  GtkComboBox *combo_box;
-  GtkWidget *menu;
-
-  g_return_if_fail (GTK_IS_COMBO_BOX (layout));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
-
-  combo_box = GTK_COMBO_BOX (layout);
-
-  g_object_ref (G_OBJECT (cell));
-  gtk_object_sink (GTK_OBJECT (cell));
-
-  info = g_new0 (ComboCellInfo, 1);
-  info->cell = cell;
-  info->expand = expand;
-  info->pack = GTK_PACK_END;
-
-  combo_box->priv->cells = g_slist_append (combo_box->priv->cells, info);
-
-  if (combo_box->priv->cell_view)
-    gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (combo_box->priv->cell_view),
-                              cell, expand);
-
-  if (combo_box->priv->column)
-    gtk_tree_view_column_pack_end (combo_box->priv->column, cell, expand);
-
-  menu = combo_box->priv->popup_widget;
-  if (GTK_IS_MENU (menu))
-    {
-      GList *i, *list;
-
-      list = gtk_container_get_children (GTK_CONTAINER (menu));
-      for (i = list; i; i = i->next)
-        {
-          GtkCellView *view;
-
-          if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
-            view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
-          else
-            view = GTK_CELL_VIEW (i->data);
-
-          gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (view), cell, expand);
-        }
-      g_list_free (list);
-    }
-}
-
-static void
-gtk_combo_box_cell_layout_clear (GtkCellLayout *layout)
-{
-  GtkWidget *menu;
-  GtkComboBox *combo_box;
-  GSList *i;
-
-  g_return_if_fail (GTK_IS_COMBO_BOX (layout));
-
-  combo_box = GTK_COMBO_BOX (layout);
-
-  if (combo_box->priv->cell_view)
-    gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo_box->priv->cell_view));
-
-  if (combo_box->priv->column)
-    gtk_tree_view_column_clear (combo_box->priv->column);
-
-  for (i = combo_box->priv->cells; i; i = i->next)
-    {
-     ComboCellInfo *info = (ComboCellInfo *)i->data;
-
-      gtk_combo_box_cell_layout_clear_attributes (layout, info->cell);
-      g_object_unref (G_OBJECT (info->cell));
-      g_free (info);
-      i->data = NULL;
-    }
-  g_slist_free (combo_box->priv->cells);
-  combo_box->priv->cells = NULL;
-
-  menu = combo_box->priv->popup_widget;
-  if (GTK_IS_MENU (menu))
-    {
-      GList *i, *list;
-
-      list = gtk_container_get_children (GTK_CONTAINER (menu));
-      for (i = list; i; i = i->next)
-        {
-          GtkCellView *view;
-
-          if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
-            view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
-          else
-            view = GTK_CELL_VIEW (i->data);
-
-          gtk_cell_layout_clear (GTK_CELL_LAYOUT (view));
-        }
-      g_list_free (list);
-    }
-}
-
-static void
-gtk_combo_box_cell_layout_add_attribute (GtkCellLayout   *layout,
-                                         GtkCellRenderer *cell,
-                                         const gchar     *attribute,
-                                         gint             column)
-{
-  ComboCellInfo *info;
-  GtkComboBox *combo_box;
-  GtkWidget *menu;
-
-  g_return_if_fail (GTK_IS_COMBO_BOX (layout));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
-
-  combo_box = GTK_COMBO_BOX (layout);
-
-  info = gtk_combo_box_get_cell_info (combo_box, cell);
-
-  info->attributes = g_slist_prepend (info->attributes,
-                                      GINT_TO_POINTER (column));
-  info->attributes = g_slist_prepend (info->attributes,
-                                      g_strdup (attribute));
-
-  if (combo_box->priv->cell_view)
-    gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box->priv->cell_view),
-                                   cell, attribute, column);
-
-  if (combo_box->priv->column)
-    gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box->priv->column),
-                                   cell, attribute, column);
-
-  menu = combo_box->priv->popup_widget;
-  if (GTK_IS_MENU (menu))
-    {
-      GList *i, *list;
-
-      list = gtk_container_get_children (GTK_CONTAINER (menu));
-      for (i = list; i; i = i->next)
-        {
-          GtkCellView *view;
-
-          if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
-            view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
-          else
-            view = GTK_CELL_VIEW (i->data);
-
-          gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (view), cell,
-                                         attribute, column);
-        }
-      g_list_free (list);
-    }
-
-  gtk_widget_queue_resize (GTK_WIDGET (combo_box));
-}
-
-static void
-gtk_combo_box_cell_layout_set_cell_data_func (GtkCellLayout         *layout,
-                                              GtkCellRenderer       *cell,
-                                              GtkCellLayoutDataFunc  func,
-                                              gpointer               func_data,
-                                              GDestroyNotify         destroy)
-{
-  ComboCellInfo *info;
-  GtkComboBox *combo_box;
-  GtkWidget *menu;
-
-  g_return_if_fail (GTK_IS_COMBO_BOX (layout));
-
-  combo_box = GTK_COMBO_BOX (layout);
-
-  info = gtk_combo_box_get_cell_info (combo_box, cell);
-  g_return_if_fail (info != NULL);
-
-  if (info->destroy)
-    {
-      GDestroyNotify d = info->destroy;
-
-      info->destroy = NULL;
-      d (info->func_data);
-    }
-
-  info->func = func;
-  info->func_data = func_data;
-  info->destroy = destroy;
-
-  if (combo_box->priv->cell_view)
-    gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box->priv->cell_view), cell, func, func_data, NULL);
-
-  if (combo_box->priv->column)
-    gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box->priv->column), cell, func, func_data, NULL);
-
-  menu = combo_box->priv->popup_widget;
-  if (GTK_IS_MENU (menu))
-    {
-      GList *i, *list;
-
-      list = gtk_container_get_children (GTK_CONTAINER (menu));
-      for (i = list; i; i = i->next)
-        {
-          GtkCellView *view;
-
-          if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
-            view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
-          else
-            view = GTK_CELL_VIEW (i->data);
-
-          gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (view), cell,
-                                              func, func_data, NULL);
-        }
-      g_list_free (list);
-    }
-
-  gtk_widget_queue_resize (GTK_WIDGET (combo_box));
-}
-
-static void
-gtk_combo_box_cell_layout_clear_attributes (GtkCellLayout   *layout,
-                                            GtkCellRenderer *cell)
-{
-  ComboCellInfo *info;
-  GtkComboBox *combo_box;
-  GtkWidget *menu;
-  GSList *list;
-
-  g_return_if_fail (GTK_IS_COMBO_BOX (layout));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
-
-  combo_box = GTK_COMBO_BOX (layout);
-
-  info = gtk_combo_box_get_cell_info (combo_box, cell);
-  if (info)
-    {
-      list = info->attributes;
-      while (list && list->next)
-	{
-	  g_free (list->data);
-	  list = list->next->next;
-	}
-      g_slist_free (info->attributes);
-      info->attributes = NULL;
-    }
-
-  if (combo_box->priv->cell_view)
-    gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (combo_box->priv->cell_view), cell);
-
-  if (combo_box->priv->column)
-    gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (combo_box->priv->column), cell);
-
-  menu = combo_box->priv->popup_widget;
-  if (GTK_IS_MENU (menu))
-    {
-      GList *i, *list;
-
-      list = gtk_container_get_children (GTK_CONTAINER (menu));
-      for (i = list; i; i = i->next)
-        {
-          GtkCellView *view;
-
-          if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
-            view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
-          else
-            view = GTK_CELL_VIEW (i->data);
-
-          gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (view), cell);
-        }
-      g_list_free (list);
-    }
-
-  gtk_widget_queue_resize (GTK_WIDGET (combo_box));
-}
-
-static void
-gtk_combo_box_cell_layout_reorder (GtkCellLayout   *layout,
-                                   GtkCellRenderer *cell,
-                                   gint             position)
-{
-  ComboCellInfo *info;
-  GtkComboBox *combo_box;
-  GtkWidget *menu;
-  GSList *link;
-
-  g_return_if_fail (GTK_IS_COMBO_BOX (layout));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
-
-  combo_box = GTK_COMBO_BOX (layout);
-
-  info = gtk_combo_box_get_cell_info (combo_box, cell);
-
-  g_return_if_fail (info != NULL);
-  g_return_if_fail (position >= 0);
-
-  link = g_slist_find (combo_box->priv->cells, info);
-
-  g_return_if_fail (link != NULL);
-
-  combo_box->priv->cells = g_slist_delete_link (combo_box->priv->cells, link);
-  combo_box->priv->cells = g_slist_insert (combo_box->priv->cells, info,
-                                           position);
-
-  if (combo_box->priv->cell_view)
-    gtk_cell_layout_reorder (GTK_CELL_LAYOUT (combo_box->priv->cell_view),
-                             cell, position);
-
-  if (combo_box->priv->column)
-    gtk_cell_layout_reorder (GTK_CELL_LAYOUT (combo_box->priv->column),
-                             cell, position);
-
-  menu = combo_box->priv->popup_widget;
-  if (GTK_IS_MENU (menu))
-    {
-      GList *i, *list;
-
-      list = gtk_container_get_children (GTK_CONTAINER (menu));
-      for (i = list; i; i = i->next)
-        {
-          GtkCellView *view;
-
-          if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data))
-            view = GTK_CELL_VIEW (GTK_BIN (i->data)->child);
-          else
-            view = GTK_CELL_VIEW (i->data);
-
-          gtk_cell_layout_reorder (GTK_CELL_LAYOUT (view), cell, position);
-        }
-      g_list_free (list);
-    }
-
-  gtk_widget_queue_draw (GTK_WIDGET (combo_box));
-}
-
-/*
- * public API
- */
-
-/**
- * gtk_combo_box_new:
- *
- * Creates a new empty #GtkComboBox.
- *
- * Return value: A new #GtkComboBox.
- *
- * Since: 2.4
- */
-GtkWidget *
-gtk_combo_box_new (void)
-{
-  return GTK_WIDGET (g_object_new (GTK_TYPE_COMBO_BOX, NULL));
-}
-
-/**
- * gtk_combo_box_new_with_model:
- * @model: A #GtkTreeModel.
- *
- * Creates a new #GtkComboBox with the model initialized to @model.
- *
- * Return value: A new #GtkComboBox.
- *
- * Since: 2.4
- */
-GtkWidget *
-gtk_combo_box_new_with_model (GtkTreeModel *model)
-{
-  GtkComboBox *combo_box;
-
-  g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);
-
-  combo_box = GTK_COMBO_BOX (g_object_new (GTK_TYPE_COMBO_BOX,
-                                           "model", model,
-                                           NULL));
-
-  return GTK_WIDGET (combo_box);
-}
-
-/**
- * gtk_combo_box_set_wrap_width:
- * @combo_box: A #GtkComboBox.
- * @width: Preferred number of columns.
- *
- * Sets the wrap width of @combo_box to be @width. The wrap width is basically
- * the preferred number of columns when you want to the popup to be layed out
- * in a table.
- *
- * Since: 2.4
- */
-void
-gtk_combo_box_set_wrap_width (GtkComboBox *combo_box,
-                              gint         width)
-{
-  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
-  g_return_if_fail (width >= 0);
-
-  if (width != combo_box->priv->wrap_width)
-    {
-      combo_box->priv->wrap_width = width;
-
-      gtk_combo_box_check_appearance (combo_box);
-      gtk_combo_box_relayout (combo_box);
-
-      g_object_notify (G_OBJECT (combo_box), "wrap_width");
-    }
-}
-
-/**
- * gtk_combo_box_set_row_span_column:
- * @combo_box: A #GtkComboBox.
- * @row_span: A column in the model passed during construction.
- *
- * Sets the column with row span information for @combo_box to be @row_span.
- * The row span column contains integers which indicate how many rows
- * an item should span.
- *
- * Since: 2.4
- */
-void
-gtk_combo_box_set_row_span_column (GtkComboBox *combo_box,
-                                   gint         row_span)
-{
-  gint col;
-
-  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
-
-  col = gtk_tree_model_get_n_columns (combo_box->priv->model);
-  g_return_if_fail (row_span >= 0 && row_span < col);
-
-  if (row_span != combo_box->priv->row_column)
-    {
-      combo_box->priv->row_column = row_span;
-
-      gtk_combo_box_relayout (combo_box);
-
-      g_object_notify (G_OBJECT (combo_box), "row_span_column");
-    }
-}
-
-/**
- * gtk_combo_box_set_column_span_column:
- * @combo_box: A #GtkComboBox.
- * @column_span: A column in the model passed during construction.
- *
- * Sets the column with column span information for @combo_box to be
- * @column_span. The column span column contains integers which indicate
- * how many columns an item should span.
- *
- * Since: 2.4
- */
-void
-gtk_combo_box_set_column_span_column (GtkComboBox *combo_box,
-                                      gint         column_span)
-{
-  gint col;
-
-  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
-
-  col = gtk_tree_model_get_n_columns (combo_box->priv->model);
-  g_return_if_fail (column_span >= 0 && column_span < col);
-
-  if (column_span != combo_box->priv->col_column)
-    {
-      combo_box->priv->col_column = column_span;
-
-      gtk_combo_box_relayout (combo_box);
-
-      g_object_notify (G_OBJECT (combo_box), "column_span_column");
-    }
-}
-
-/**
- * gtk_combo_box_get_active:
- * @combo_box: A #GtkComboBox.
- *
- * Returns the index of the currently active item, or -1 if there's no
- * active item.
- *
- * Return value: An integer which is the index of the currently active item, or
- * -1 if there's no active item.
- *
- * Since: 2.4
- */
-gint
-gtk_combo_box_get_active (GtkComboBox *combo_box)
-{
-  g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), 0);
-
-  return combo_box->priv->active_item;
-}
-
-/**
- * gtk_combo_box_set_active:
- * @combo_box: A #GtkComboBox.
- * @index_: An index in the model passed during construction, or -1 to have
- * no active item.
- *
- * Sets the active item of @combo_box to be the item at @index.
- *
- * Since: 2.4
- */
-void
-gtk_combo_box_set_active (GtkComboBox *combo_box,
-                          gint         index_)
-{
-  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
-  /* -1 means "no item selected" */
-  g_return_if_fail (index_ >= -1);
-
-  if (combo_box->priv->active_item == index_)
-    return;
-
-  gtk_combo_box_set_active_internal (combo_box, index_);
-}
-
-static void
-gtk_combo_box_set_active_internal (GtkComboBox *combo_box,
-				   gint         index)
-{
-  GtkTreePath *path;
-
-  combo_box->priv->active_item = index;
-
-  if (index == -1)
-    {
-      if (combo_box->priv->tree_view)
-        gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view)));
-      else
-        {
-          GtkMenu *menu = GTK_MENU (combo_box->priv->popup_widget);
-
-          if (GTK_IS_MENU (menu))
-            gtk_menu_set_active (menu, -1);
-        }
-
-      if (combo_box->priv->cell_view)
-        gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->cell_view), NULL);
-    }
-  else
-    {
-#if GTK_CHECK_VERSION(2,2,0)
-      path = gtk_tree_path_new_from_indices (index, -1);
-#else
-      char buf[32];
-      g_snprintf(buf, sizeof(buf), "%d", index);
-      path = gtk_tree_path_new_from_string(buf);
-#endif
-
-      if (combo_box->priv->tree_view)
-	gtk_tree_view_set_cursor (GTK_TREE_VIEW (combo_box->priv->tree_view), path, NULL, FALSE);
-      else
-        {
-          GtkMenu *menu = GTK_MENU (combo_box->priv->popup_widget);
-
-          if (GTK_IS_MENU (menu))
-            gtk_menu_set_active (GTK_MENU (menu), index);
-        }
-
-      if (combo_box->priv->cell_view)
-	gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->cell_view), path);
-
-      gtk_tree_path_free (path);
-    }
-
-  g_signal_emit_by_name (combo_box, "changed", NULL, NULL);
-}
-
-
-/**
- * gtk_combo_box_get_active_iter:
- * @combo_box: A #GtkComboBox
- * @iter: The uninitialized #GtkTreeIter.
- *
- * Sets @iter to point to the current active item, if it exists.
- *
- * Return value: %TRUE, if @iter was set
- *
- * Since: 2.4
- **/
-gboolean
-gtk_combo_box_get_active_iter (GtkComboBox     *combo_box,
-                               GtkTreeIter     *iter)
-{
-  GtkTreePath *path;
-  gint active;
-  gboolean retval;
-#if !GTK_CHECK_VERSION(2,2,0)
-  char buf[32];
-#endif
-
-  g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), FALSE);
-
-  active = gtk_combo_box_get_active (combo_box);
-  if (active < 0)
-    return FALSE;
-
-#if GTK_CHECK_VERSION(2,2,0)
-  path = gtk_tree_path_new_from_indices (active, -1);
-#else
-  g_snprintf(buf, sizeof(buf), "%d", active);
-  path = gtk_tree_path_new_from_string(buf);
-#endif
-  retval = gtk_tree_model_get_iter (gtk_combo_box_get_model (combo_box),
-                                    iter, path);
-  gtk_tree_path_free (path);
-
-  return retval;
-}
-
-/**
- * gtk_combo_box_set_active_iter:
- * @combo_box: A #GtkComboBox
- * @iter: The #GtkTreeIter.
- *
- * Sets the current active item to be the one referenced by @iter.
- * @iter must correspond to a path of depth one.
- *
- * Since: 2.4
- **/
-void
-gtk_combo_box_set_active_iter (GtkComboBox     *combo_box,
-                               GtkTreeIter     *iter)
-{
-  GtkTreePath *path;
-
-  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
-
-  path = gtk_tree_model_get_path (gtk_combo_box_get_model (combo_box), iter);
-  g_return_if_fail (path != NULL);
-  g_return_if_fail (gtk_tree_path_get_depth (path) == 1);
-
-  gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]);
-  gtk_tree_path_free (path);
-}
-
-/**
- * gtk_combo_box_set_model:
- * @combo_box: A #GtkComboBox.
- * @model: A #GtkTreeModel.
- *
- * Sets the model used by @combo_box to be @model. Will unset a previously set
- * model (if applicable). If @model is %NULL, then it will unset the model.
- *
- * Note that this function does not clear the cell renderers, you have to
- * call gtk_combo_box_cell_layout_clear() yourself if you need to set up
- * different cell renderers for the new model.
- *
- * Since: 2.4
- */
-void
-gtk_combo_box_set_model (GtkComboBox  *combo_box,
-                         GtkTreeModel *model)
-{
-  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
-
-  if (!model)
-    {
-      gtk_combo_box_unset_model (combo_box);
-      return;
-    }
-
-  g_return_if_fail (GTK_IS_TREE_MODEL (model));
-
-  if (model == combo_box->priv->model)
-    return;
-
-  if (combo_box->priv->model)
-    gtk_combo_box_unset_model (combo_box);
-
-  combo_box->priv->model = model;
-  g_object_ref (G_OBJECT (combo_box->priv->model));
-
-  combo_box->priv->inserted_id =
-    g_signal_connect (combo_box->priv->model, "row_inserted",
-		      G_CALLBACK (gtk_combo_box_model_row_inserted),
-		      combo_box);
-  combo_box->priv->deleted_id =
-    g_signal_connect (combo_box->priv->model, "row_deleted",
-		      G_CALLBACK (gtk_combo_box_model_row_deleted),
-		      combo_box);
-  combo_box->priv->reordered_id =
-    g_signal_connect (combo_box->priv->model, "rows_reordered",
-		      G_CALLBACK (gtk_combo_box_model_rows_reordered),
-		      combo_box);
-  combo_box->priv->changed_id =
-    g_signal_connect (combo_box->priv->model, "row_changed",
-		      G_CALLBACK (gtk_combo_box_model_row_changed),
-		      combo_box);
-
-  if (combo_box->priv->tree_view)
-    {
-      /* list mode */
-      gtk_tree_view_set_model (GTK_TREE_VIEW (combo_box->priv->tree_view),
-                               combo_box->priv->model);
-    }
-  else
-    {
-      /* menu mode */
-      if (combo_box->priv->popup_widget)
-	gtk_combo_box_menu_fill (combo_box);
-
-    }
-
-  if (combo_box->priv->cell_view)
-    gtk_cell_view_set_model (GTK_CELL_VIEW (combo_box->priv->cell_view),
-                             combo_box->priv->model);
-}
-
-/**
- * gtk_combo_box_get_model
- * @combo_box: A #GtkComboBox.
- *
- * Returns the #GtkTreeModel which is acting as data source for @combo_box.
- *
- * Return value: A #GtkTreeModel which was passed during construction.
- *
- * Since: 2.4
- */
-GtkTreeModel *
-gtk_combo_box_get_model (GtkComboBox *combo_box)
-{
-  g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL);
-
-  return combo_box->priv->model;
-}
-
-
-/* convenience API for simple text combos */
-
-/**
- * gtk_combo_box_new_text:
- *
- * Convenience function which constructs a new text combo box, which is a
- * #GtkComboBox just displaying strings. If you use this function to create
- * a text combo box, you should only manipulate its data source with the
- * following convenience functions: gtk_combo_box_append_text(),
- * gtk_combo_box_insert_text(), gtk_combo_box_prepend_text() and
- * gtk_combo_box_remove_text().
- *
- * Return value: A new text combo box.
- *
- * Since: 2.4
- */
-GtkWidget *
-gtk_combo_box_new_text (void)
-{
-  GtkWidget *combo_box;
-  GtkCellRenderer *cell;
-  GtkListStore *store;
-
-  store = gtk_list_store_new (1, G_TYPE_STRING);
-  combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
-  g_object_unref (store);
-
-  cell = gtk_cell_renderer_text_new ();
-  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, TRUE);
-  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell,
-                                  "text", 0,
-                                  NULL);
-
-  return combo_box;
-}
-
-/**
- * gtk_combo_box_append_text:
- * @combo_box: A #GtkComboBox constructed using gtk_combo_box_new_text().
- * @text: A string.
- *
- * Appends @string to the list of strings stored in @combo_box. Note that
- * you can only use this function with combo boxes constructed with
- * gtk_combo_box_new_text().
- *
- * Since: 2.4
- */
-void
-gtk_combo_box_append_text (GtkComboBox *combo_box,
-                           const gchar *text)
-{
-  GtkTreeIter iter;
-  GtkListStore *store;
-
-  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
-  g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
-  g_return_if_fail (text != NULL);
-
-  store = GTK_LIST_STORE (combo_box->priv->model);
-
-  gtk_list_store_append (store, &iter);
-  gtk_list_store_set (store, &iter, 0, text, -1);
-}
-
-/**
- * gtk_combo_box_insert_text:
- * @combo_box: A #GtkComboBox constructed using gtk_combo_box_new_text().
- * @position: An index to insert @text.
- * @text: A string.
- *
- * Inserts @string at @position in the list of strings stored in @combo_box.
- * Note that you can only use this function with combo boxes constructed
- * with gtk_combo_box_new_text().
- *
- * Since: 2.4
- */
-void
-gtk_combo_box_insert_text (GtkComboBox *combo_box,
-                           gint         position,
-                           const gchar *text)
-{
-  GtkTreeIter iter;
-  GtkListStore *store;
-
-  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
-  g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
-  g_return_if_fail (position >= 0);
-  g_return_if_fail (text != NULL);
-
-  store = GTK_LIST_STORE (combo_box->priv->model);
-
-  gtk_list_store_insert (store, &iter, position);
-  gtk_list_store_set (store, &iter, 0, text, -1);
-}
-
-/**
- * gtk_combo_box_prepend_text:
- * @combo_box: A #GtkComboBox constructed with gtk_combo_box_new_text().
- * @text: A string.
- *
- * Prepends @string to the list of strings stored in @combo_box. Note that
- * you can only use this function with combo boxes constructed with
- * gtk_combo_box_new_text().
- *
- * Since: 2.4
- */
-void
-gtk_combo_box_prepend_text (GtkComboBox *combo_box,
-                            const gchar *text)
-{
-  GtkTreeIter iter;
-  GtkListStore *store;
-
-  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
-  g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
-  g_return_if_fail (text != NULL);
-
-  store = GTK_LIST_STORE (combo_box->priv->model);
-
-  gtk_list_store_prepend (store, &iter);
-  gtk_list_store_set (store, &iter, 0, text, -1);
-}
-
-/**
- * gtk_combo_box_remove_text:
- * @combo_box: A #GtkComboBox constructed with gtk_combo_box_new_text().
- * @position: Index of the item to remove.
- *
- * Removes the string at @position from @combo_box. Note that you can only use
- * this function with combo boxes constructed with gtk_combo_box_new_text().
- *
- * Since: 2.4
- */
-void
-gtk_combo_box_remove_text (GtkComboBox *combo_box,
-                           gint         position)
-{
-  GtkTreeIter iter;
-  GtkListStore *store;
-
-  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
-  g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model));
-  g_return_if_fail (position >= 0);
-
-  store = GTK_LIST_STORE (combo_box->priv->model);
-
-  if (gtk_tree_model_iter_nth_child (combo_box->priv->model, &iter,
-                                     NULL, position))
-    gtk_list_store_remove (store, &iter);
-}
-
-static gboolean
-gtk_combo_box_mnemonic_activate (GtkWidget *widget,
-				 gboolean   group_cycling)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
-
-  gtk_widget_grab_focus (combo_box->priv->button);
-
-  return TRUE;
-}
-
-static void
-gtk_combo_box_destroy (GtkObject *object)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (object);
-
-  gtk_combo_box_popdown (combo_box);
-
-  combo_box->priv->destroying = 1;
-
-  GTK_OBJECT_CLASS (parent_class)->destroy (object);
-  combo_box->priv->cell_view = NULL;
-
-  combo_box->priv->destroying = 0;
-}
-
-static void
-gtk_combo_box_finalize (GObject *object)
-{
-  GtkComboBox *combo_box = GTK_COMBO_BOX (object);
-  GSList *i;
-
-  if (GTK_IS_MENU (combo_box->priv->popup_widget))
-    {
-      gtk_combo_box_menu_destroy (combo_box);
-      gtk_menu_detach (GTK_MENU (combo_box->priv->popup_widget));
-      combo_box->priv->popup_widget = NULL;
-    }
-
-  if (GTK_IS_TREE_VIEW (combo_box->priv->tree_view))
-    gtk_combo_box_list_destroy (combo_box);
-
-  if (combo_box->priv->popup_window)
-    gtk_widget_destroy (combo_box->priv->popup_window);
-
-  gtk_combo_box_unset_model (combo_box);
-
-  for (i = combo_box->priv->cells; i; i = i->next)
-    {
-      ComboCellInfo *info = (ComboCellInfo *)i->data;
-      GSList *list = info->attributes;
-
-      if (info->destroy)
-	info->destroy (info->func_data);
-
-      while (list && list->next)
-	{
-	  g_free (list->data);
-	  list = list->next->next;
-	}
-      g_slist_free (info->attributes);
-
-      g_object_unref (G_OBJECT (info->cell));
-      g_free (info);
-    }
-   g_slist_free (combo_box->priv->cells);
-
-   g_free (combo_box->priv);
-
-   G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-
-/**
- * Code below this point has been pulled in from gtkmenu.c in 2.4.14
- * and is needed to provide gtk_menu_attach()
- */
-
-typedef struct
-{
-  gint left_attach;
-  gint right_attach;
-  gint top_attach;
-  gint bottom_attach;
-  gint effective_left_attach;
-  gint effective_right_attach;
-  gint effective_top_attach;
-  gint effective_bottom_attach;
-} AttachInfo;
-
-#define ATTACH_INFO_KEY "gtk-menu-child-attach-info-key"
-
-static AttachInfo *
-get_attach_info (GtkWidget *child)
-{
-  GObject *object = G_OBJECT (child);
-  AttachInfo *ai = g_object_get_data (object, ATTACH_INFO_KEY);
-
-  if (!ai)
-    {
-      ai = g_new0 (AttachInfo, 1);
-      g_object_set_data_full (object, ATTACH_INFO_KEY, ai, g_free);
-    }
-
-  return ai;
-}
-
-/**
- * gtk_menu_attach:
- * @menu: a #GtkMenu.
- * @child: a #GtkMenuItem.
- * @left_attach: The column number to attach the left side of the item to.
- * @right_attach: The column number to attach the right side of the item to.
- * @top_attach: The row number to attach the top of the item to.
- * @bottom_attach: The row number to attach the bottom of the item to.
- *
- * Adds a new #GtkMenuItem to a (table) menu. The number of 'cells' that
- * an item will occupy is specified by @left_attach, @right_attach,
- * @top_attach and @bottom_attach. These each represent the leftmost,
- * rightmost, uppermost and lower column and row numbers of the table.
- * (Columns and rows are indexed from zero).
- *
- * Note that this function is not related to gtk_menu_detach().
- *
- * Since: 2.4
- **/
-static void
-gtk_menu_attach (GtkMenu   *menu,
-                 GtkWidget *child,
-                 guint      left_attach,
-                 guint      right_attach,
-                 guint      top_attach,
-                 guint      bottom_attach)
-{
-  GtkMenuShell *menu_shell;
-
-  g_return_if_fail (GTK_IS_MENU (menu));
-  g_return_if_fail (GTK_IS_MENU_ITEM (child));
-  g_return_if_fail (child->parent == NULL ||
-		    child->parent == GTK_WIDGET (menu));
-  g_return_if_fail (left_attach < right_attach);
-  g_return_if_fail (top_attach < bottom_attach);
-
-  menu_shell = GTK_MENU_SHELL (menu);
-
-  if (!child->parent)
-    {
-      AttachInfo *ai = get_attach_info (child);
-
-      ai->left_attach = left_attach;
-      ai->right_attach = right_attach;
-      ai->top_attach = top_attach;
-      ai->bottom_attach = bottom_attach;
-
-      menu_shell->children = g_list_append (menu_shell->children, child);
-
-      gtk_widget_set_parent (child, GTK_WIDGET (menu));
-
-      /*
-      menu_queue_resize (menu);
-      */
-    }
-  else
-    {
-      gtk_container_child_set (GTK_CONTAINER (child->parent), child,
-			       "left_attach",   left_attach,
-			       "right_attach",  right_attach,
-			       "top_attach",    top_attach,
-			       "bottom_attach", bottom_attach,
-			       NULL);
-    }
-}
-#endif /* Gtk 2.4 */
-
-gchar *
-gtk_combo_box_get_active_text (GtkComboBox *combo_box)
-{
-  GtkTreeIter iter;
-  gchar *text = NULL;
-
-  /* g_return_val_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model), NULL); */
-
-  if (gtk_combo_box_get_active_iter (combo_box, &iter))
-    gtk_tree_model_get (gtk_combo_box_get_model(combo_box), &iter,
-    			0, &text, -1);
-  return text;
-}
-
-#endif
--- a/pidgin/pidgincombobox.h	Thu Feb 04 02:18:37 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-/* gtkcombobox.h
- * Copyright (C) 2002, 2003  Kristian Rietveld <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02111-1301, USA.
- */
-
-#ifndef __PIDGIN_COMBO_BOX_H__
-#define __PIDGIN_COMBO_BOX_H__
-
-#ifndef __GTK_COMBO_BOX_H__
-#define __GTK_COMBO_BOX_H__
-
-#include <gtk/gtkbin.h>
-#include <gtk/gtktreemodel.h>
-#include <gtk/gtktreeview.h>
-
-G_BEGIN_DECLS
-
-#define GTK_TYPE_COMBO_BOX             (gtk_combo_box_get_type ())
-#define GTK_COMBO_BOX(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COMBO_BOX, GtkComboBox))
-#define GTK_COMBO_BOX_CLASS(vtable)    (G_TYPE_CHECK_CLASS_CAST ((vtable), GTK_TYPE_COMBO_BOX, GtkComboBoxClass))
-#define GTK_IS_COMBO_BOX(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COMBO_BOX))
-#define GTK_IS_COMBO_BOX_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), GTK_TYPE_COMBO_BOX))
-#define GTK_COMBO_BOX_GET_CLASS(inst)  (G_TYPE_INSTANCE_GET_CLASS ((inst), GTK_TYPE_COMBO_BOX, GtkComboBoxClass))
-
-typedef struct _GtkComboBox        GtkComboBox;
-typedef struct _GtkComboBoxClass   GtkComboBoxClass;
-typedef struct _GtkComboBoxPrivate GtkComboBoxPrivate;
-
-struct _GtkComboBox
-{
-  GtkBin parent_instance;
-
-  /*< private >*/
-  GtkComboBoxPrivate *priv;
-};
-
-struct _GtkComboBoxClass
-{
-  GtkBinClass parent_class;
-
-  /* signals */
-  void     (* changed)          (GtkComboBox *combo_box);
-
-  /* Padding for future expansion */
-  void (*_gtk_reserved0) (void);
-  void (*_gtk_reserved1) (void);
-  void (*_gtk_reserved2) (void);
-  void (*_gtk_reserved3) (void);
-};
-
-
-/* construction */
-GType         gtk_combo_box_get_type         (void);
-GtkWidget    *gtk_combo_box_new              (void);
-GtkWidget    *gtk_combo_box_new_with_model   (GtkTreeModel    *model);
-
-/* grids */
-void          gtk_combo_box_set_wrap_width         (GtkComboBox *combo_box,
-                                                    gint         width);
-void          gtk_combo_box_set_row_span_column    (GtkComboBox *combo_box,
-                                                    gint         row_span);
-void          gtk_combo_box_set_column_span_column (GtkComboBox *combo_box,
-                                                    gint         column_span);
-
-/* get/set active item */
-gint          gtk_combo_box_get_active       (GtkComboBox     *combo_box);
-void          gtk_combo_box_set_active       (GtkComboBox     *combo_box,
-                                              gint             index_);
-gboolean      gtk_combo_box_get_active_iter  (GtkComboBox     *combo_box,
-                                              GtkTreeIter     *iter);
-void          gtk_combo_box_set_active_iter  (GtkComboBox     *combo_box,
-                                              GtkTreeIter     *iter);
-
-/* getters and setters */
-void          gtk_combo_box_set_model        (GtkComboBox     *combo_box,
-                                              GtkTreeModel    *model);
-GtkTreeModel *gtk_combo_box_get_model        (GtkComboBox     *combo_box);
-
-/* convenience -- text */
-GtkWidget    *gtk_combo_box_new_text         (void);
-void          gtk_combo_box_append_text      (GtkComboBox     *combo_box,
-                                              const gchar     *text);
-void          gtk_combo_box_insert_text      (GtkComboBox     *combo_box,
-                                              gint             position,
-                                              const gchar     *text);
-void          gtk_combo_box_prepend_text     (GtkComboBox     *combo_box,
-                                              const gchar     *text);
-void          gtk_combo_box_remove_text      (GtkComboBox     *combo_box,
-                                              gint             position);
-/* programmatic control */
-void          gtk_combo_box_popup            (GtkComboBox     *combo_box);
-void          gtk_combo_box_popdown          (GtkComboBox     *combo_box);
-
-G_END_DECLS
-
-#endif /* __GTK_COMBO_BOX_H__ */
-
-gchar        *gtk_combo_box_get_active_text  (GtkComboBox     *combo_box);
-
-#endif /* __PIDGIN_COMBOX_BOX_H__ */
--- a/pidgin/pidginstock.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/pidginstock.c	Thu Feb 04 05:30:35 2010 +0000
@@ -53,49 +53,29 @@
 } const stock_icons[] = {
 
 	{ PIDGIN_STOCK_ACTION,          NULL,      GTK_STOCK_EXECUTE          },
-#if GTK_CHECK_VERSION(2,6,0)
 	{ PIDGIN_STOCK_ALIAS,           NULL,      GTK_STOCK_EDIT             },
-#else
-	{ PIDGIN_STOCK_ALIAS,           "buttons", "edit.png"                 },
-#endif
 	{ PIDGIN_STOCK_CHAT,            NULL,      GTK_STOCK_JUMP_TO          },
 	{ PIDGIN_STOCK_CLEAR,           NULL,      GTK_STOCK_CLEAR            },
 	{ PIDGIN_STOCK_CLOSE_TABS,      NULL,      GTK_STOCK_CLOSE            },
 	{ PIDGIN_STOCK_DEBUG,           NULL,      GTK_STOCK_PROPERTIES       },
 	{ PIDGIN_STOCK_DOWNLOAD,        NULL,      GTK_STOCK_GO_DOWN          },
-#if GTK_CHECK_VERSION(2,6,0)
 	{ PIDGIN_STOCK_DISCONNECT,      NULL,      GTK_STOCK_DISCONNECT       },
-#else
-	{ PIDGIN_STOCK_DISCONNECT,      "icons",   "stock_disconnect_16.png"  },
-#endif
 	{ PIDGIN_STOCK_FGCOLOR,         "buttons", "change-fgcolor-small.png" },
-#if GTK_CHECK_VERSION(2,6,0)
 	{ PIDGIN_STOCK_EDIT,            NULL,      GTK_STOCK_EDIT             },
-#else
-	{ PIDGIN_STOCK_EDIT,            "buttons", "edit.png"                 },
-#endif
 	{ PIDGIN_STOCK_FILE_CANCELED,   NULL,      GTK_STOCK_CANCEL           },
 	{ PIDGIN_STOCK_FILE_DONE,       NULL,      GTK_STOCK_APPLY            },
 	{ PIDGIN_STOCK_IGNORE,          NULL,      GTK_STOCK_DIALOG_ERROR     },
 	{ PIDGIN_STOCK_INVITE,          NULL,      GTK_STOCK_JUMP_TO          },
 	{ PIDGIN_STOCK_MODIFY,          NULL,      GTK_STOCK_PREFERENCES      },
 	{ PIDGIN_STOCK_ADD,             NULL,	   GTK_STOCK_ADD			  },
-#if GTK_CHECK_VERSION(2,6,0)
 	{ PIDGIN_STOCK_PAUSE,           NULL,      GTK_STOCK_MEDIA_PAUSE      },
-#else
-	{ PIDGIN_STOCK_PAUSE,           "buttons", "pause.png"                },
-#endif
 	{ PIDGIN_STOCK_POUNCE,          NULL,      GTK_STOCK_REDO             },
 	{ PIDGIN_STOCK_OPEN_MAIL,       NULL,      GTK_STOCK_JUMP_TO          },
 	{ PIDGIN_STOCK_SIGN_ON,         NULL,      GTK_STOCK_EXECUTE          },
 	{ PIDGIN_STOCK_SIGN_OFF,        NULL,      GTK_STOCK_CLOSE            },
 	{ PIDGIN_STOCK_TYPED,           "pidgin",  "typed.png"                },
 	{ PIDGIN_STOCK_UPLOAD,          NULL,      GTK_STOCK_GO_UP            },
-#if GTK_CHECK_VERSION(2,8,0)
 	{ PIDGIN_STOCK_INFO,            NULL,      GTK_STOCK_INFO             },
-#else
-	{ PIDGIN_STOCK_INFO,            "buttons", "info.png"                 },
-#endif
 };
 
 static const GtkStockItem stock_items[] =
@@ -204,6 +184,7 @@
 	{ PIDGIN_STOCK_TOOLBAR_VIDEO_CALL,       "toolbar", "video-call.png",       FALSE, TRUE,  TRUE,  TRUE,  TRUE,  FALSE, FALSE, NULL },
 	{ PIDGIN_STOCK_TOOLBAR_AUDIO_VIDEO_CALL, "toolbar", "audio-video-call.png", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
 #endif
+	{ PIDGIN_STOCK_TOOLBAR_SEND_ATTENTION, "toolbar", "get-attention.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL  }
 };
 
 const SizedStockIcon sized_status_icons [] = {
@@ -218,7 +199,10 @@
 	{ PIDGIN_STOCK_STATUS_LOGOUT,    "status",  "log-out.png",       TRUE, TRUE, TRUE,  TRUE,  TRUE,  FALSE, TRUE,  NULL },
 	{ PIDGIN_STOCK_STATUS_OFFLINE,   "status",  "offline.png",       TRUE, TRUE, TRUE,  TRUE,  TRUE,  FALSE, FALSE, PIDGIN_STOCK_STATUS_OFFLINE_I  },
 	{ PIDGIN_STOCK_STATUS_PERSON,    "status",  "person.png",        TRUE, TRUE, TRUE,  TRUE,  TRUE,  FALSE, FALSE, NULL },
-	{ PIDGIN_STOCK_STATUS_MESSAGE,   "toolbar", "message-new.png",   TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
+	{ PIDGIN_STOCK_STATUS_MESSAGE,   "toolbar", "message-new.png",   TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }
+};
+
+const SizedStockIcon sized_tray_icons [] = {
 
 	{ PIDGIN_STOCK_TRAY_AVAILABLE, "tray", "tray-online.png",        FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL },
 	{ PIDGIN_STOCK_TRAY_INVISIBLE, "tray", "tray-invisible.png",     FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL },
@@ -239,7 +223,6 @@
 find_file_common(const char *name)
 {
 	gchar *filename;
-#if GLIB_CHECK_VERSION(2,6,0)
 	const gchar *userdir;
 	const gchar * const *sysdirs;
 
@@ -256,7 +239,6 @@
 			return filename;
 		g_free(filename);
 	}
-#endif
 	filename = g_build_filename(DATADIR, name, NULL);
 	if (g_file_test(filename, G_FILE_TEST_EXISTS))
 		return filename;
@@ -354,7 +336,8 @@
 
 static void
 add_sized_icon(GtkIconSet *iconset, GtkIconSize sizeid, PidginIconTheme *theme,
-		const char *size, SizedStockIcon sized_icon, gboolean translucent)
+		const char *size, SizedStockIcon sized_icon, gboolean translucent,
+		gboolean size_wildcarded)
 {
 	char *filename;
 	GtkIconSource *source;
@@ -371,7 +354,7 @@
 	gtk_icon_source_set_direction(source, GTK_TEXT_DIR_LTR);
 	gtk_icon_source_set_direction_wildcarded(source, !sized_icon.rtl);
 	gtk_icon_source_set_size(source, sizeid);
-	gtk_icon_source_set_size_wildcarded(source, FALSE);
+	gtk_icon_source_set_size_wildcarded(source, size_wildcarded);
 	gtk_icon_source_set_state_wildcarded(source, TRUE);
 	gtk_icon_set_add_source(iconset, source);
 	gtk_icon_source_free(source);
@@ -381,7 +364,7 @@
 		gtk_icon_source_set_pixbuf(source, pixbuf);
 		gtk_icon_source_set_direction_wildcarded(source, TRUE);
 		gtk_icon_source_set_size(source, GTK_ICON_SIZE_MENU);
-		gtk_icon_source_set_size_wildcarded(source, FALSE);
+		gtk_icon_source_set_size_wildcarded(source, size_wildcarded);
 		gtk_icon_source_set_state_wildcarded(source, TRUE);
 		gtk_icon_set_add_source(iconset, source);
 		gtk_icon_source_free(source);
@@ -401,7 +384,7 @@
 		gtk_icon_source_set_filename(source, filename);
 		gtk_icon_source_set_direction(source, GTK_TEXT_DIR_RTL);
 		gtk_icon_source_set_size(source, sizeid);
-		gtk_icon_source_set_size_wildcarded(source, FALSE);
+		gtk_icon_source_set_size_wildcarded(source, size_wildcarded);
 		gtk_icon_source_set_state_wildcarded(source, TRUE);
 		gtk_icon_set_add_source(iconset, source);
 		g_free(filename);
@@ -413,11 +396,9 @@
 static void
 reload_settings(void)
 {
-#if GTK_CHECK_VERSION(2,4,0)
 	GtkSettings *setting = NULL;
 	setting = gtk_settings_get_default();
 	gtk_rc_reset_styles(setting);
-#endif
 }
 
 /*****************************************************************************
@@ -459,9 +440,9 @@
 
 #define ADD_SIZED_ICON(name, size) \
 		if (sized_status_icons[i].name) { \
-			add_sized_icon(normal, name, PIDGIN_ICON_THEME(theme), size, sized_status_icons[i], FALSE); \
+			add_sized_icon(normal, name, PIDGIN_ICON_THEME(theme), size, sized_status_icons[i], FALSE, FALSE); \
 			if (sized_status_icons[i].translucent_name) \
-				add_sized_icon(translucent, name, PIDGIN_ICON_THEME(theme), size, sized_status_icons[i], TRUE); \
+				add_sized_icon(translucent, name, PIDGIN_ICON_THEME(theme), size, sized_status_icons[i], TRUE, FALSE); \
 		}
 		ADD_SIZED_ICON(microscopic, "11");
 		ADD_SIZED_ICON(extra_small, "16");
@@ -480,6 +461,35 @@
 		}
 	}
 
+	for (i = 0; i < G_N_ELEMENTS(sized_tray_icons); i++)
+	{
+		normal = gtk_icon_set_new();
+		if (sized_tray_icons[i].translucent_name)
+			translucent = gtk_icon_set_new();
+
+#define ADD_SIZED_ICON(name, size) \
+		if (sized_tray_icons[i].name) { \
+			add_sized_icon(normal, name, PIDGIN_ICON_THEME(theme), size, sized_tray_icons[i], FALSE, TRUE); \
+			if (sized_tray_icons[i].translucent_name) \
+				add_sized_icon(translucent, name, PIDGIN_ICON_THEME(theme), size, sized_tray_icons[i], TRUE, TRUE); \
+		}
+		ADD_SIZED_ICON(microscopic, "11");
+		ADD_SIZED_ICON(extra_small, "16");
+		ADD_SIZED_ICON(small, "22");
+		ADD_SIZED_ICON(medium, "32");
+		ADD_SIZED_ICON(large, "48");
+		ADD_SIZED_ICON(huge, "64");
+#undef ADD_SIZED_ICON
+
+		gtk_icon_factory_add(icon_factory, sized_tray_icons[i].name, normal);
+		gtk_icon_set_unref(normal);
+
+		if (sized_tray_icons[i].translucent_name) {
+			gtk_icon_factory_add(icon_factory, sized_tray_icons[i].translucent_name, translucent);
+			gtk_icon_set_unref(translucent);
+		}
+	}
+
 	gtk_widget_destroy(win);
 	g_object_unref(G_OBJECT(icon_factory));
 	reload_settings();
@@ -551,7 +561,7 @@
 
 #define ADD_SIZED_ICON(name, size) \
 		if (sized_stock_icons[i].name) \
-			add_sized_icon(iconset, name, PIDGIN_ICON_THEME(theme), size, sized_stock_icons[i], FALSE);
+			add_sized_icon(iconset, name, PIDGIN_ICON_THEME(theme), size, sized_stock_icons[i], FALSE, FALSE);
 		ADD_SIZED_ICON(microscopic, "11");
 		ADD_SIZED_ICON(extra_small, "16");
 		ADD_SIZED_ICON(small, "22");
--- a/pidgin/pidginstock.h	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/pidginstock.h	Thu Feb 04 05:30:35 2010 +0000
@@ -159,9 +159,10 @@
 #define PIDGIN_STOCK_TOOLBAR_VIDEO_CALL   "pidgin-video-call"
 #define PIDGIN_STOCK_TOOLBAR_AUDIO_VIDEO_CALL "pidgin-audio-video-call"
 #endif
+#define PIDGIN_STOCK_TOOLBAR_SEND_ATTENTION	"pidgin-send-attention"
 
 /* Tray icons */
-#define PIDGIN_STOCK_TRAY_AVAILABLE       "pidgin-tray-available"
+#define PIDGIN_STOCK_TRAY_AVAILABLE       "pidgin-tray-online"
 #define PIDGIN_STOCK_TRAY_INVISIBLE	  "pidgin-tray-invisible"
 #define PIDGIN_STOCK_TRAY_AWAY	  	  "pidgin-tray-away"
 #define PIDGIN_STOCK_TRAY_BUSY            "pidgin-tray-busy"
--- a/pidgin/pidgintooltip.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/pidgintooltip.c	Thu Feb 04 05:30:35 2010 +0000
@@ -119,9 +119,7 @@
 
 	tipwindow = gtk_window_new(GTK_WINDOW_POPUP);
 	name = gtk_window_get_title(GTK_WINDOW(pidgin_tooltip.widget));
-#if GTK_CHECK_VERSION(2,10,0)
 	gtk_window_set_type_hint(GTK_WINDOW(tipwindow), GDK_WINDOW_TYPE_HINT_TOOLTIP);
-#endif
 	gtk_widget_set_app_paintable(tipwindow, TRUE);
 	gtk_window_set_title(GTK_WINDOW(tipwindow), name ? name : _("Pidgin Tooltip"));
 	gtk_window_set_resizable(GTK_WINDOW(tipwindow), FALSE);
@@ -136,41 +134,26 @@
 {
 	int sig;
 	int scr_w, scr_h, x, y, dy;
-#if GTK_CHECK_VERSION(2,2,0)
 	int mon_num;
 	GdkScreen *screen = NULL;
-#endif
 	GdkRectangle mon_size;
 	GtkWidget *tipwindow = pidgin_tooltip.tipwindow;
 	
-#if GTK_CHECK_VERSION(2,2,0)
 	gdk_display_get_pointer(gdk_display_get_default(), &screen, &x, &y, NULL);
 	mon_num = gdk_screen_get_monitor_at_point(screen, x, y);
 	gdk_screen_get_monitor_geometry(screen, mon_num, &mon_size);
 
 	scr_w = mon_size.width + mon_size.x;
 	scr_h = mon_size.height + mon_size.y;
-#else
-	scr_w = gdk_screen_width();
-	scr_h = gdk_screen_height();
-	gdk_window_get_pointer(NULL, &x, &y, NULL);
-	mon_size.x = 0;
-	mon_size.y = 0;
-#endif
 
-#if GTK_CHECK_VERSION(2,4,0)
 	dy = gdk_display_get_default_cursor_size(gdk_display_get_default()) / 2;
-#else
-	dy = 0;
-#endif
 
-#if GTK_CHECK_VERSION(2,2,0)
 	if (w > mon_size.width)
 		w = mon_size.width - 10;
 
 	if (h > mon_size.height)
 		h = mon_size.height - 10;
-#endif
+
 	x -= ((w >> 1) + 4);
 
 	if ((y + h + 4) > scr_h)
--- a/pidgin/pixmaps/Makefile.am	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/pixmaps/Makefile.am	Thu Feb 04 05:30:35 2010 +0000
@@ -446,7 +446,8 @@
 		toolbar/16/send-file.png \
 		toolbar/16/transfer.png \
 		toolbar/16/unblock.png \
-		toolbar/16/video-call.png
+		toolbar/16/video-call.png \
+		toolbar/16/get-attention.png
 
 TOOLBAR_22_SCALABLE = \
 		toolbar/22/scalable/select-avatar.svg \
@@ -485,48 +486,48 @@
 		tray/16/offline_4bit.ico
 
 TRAY_16 = \
-		tray/16/tray-away.png \
-		tray/16/tray-busy.png \
-		tray/16/tray-invisible.png \
-		tray/16/tray-connecting.png \
-		tray/16/tray-extended-away.png \
-		tray/16/tray-message.png \
-		tray/16/tray-new-im.png \
-		tray/16/tray-offline.png \
-		tray/16/tray-online.png
+		tray/hicolor/16x16/status/pidgin-tray-away.png \
+		tray/hicolor/16x16/status/pidgin-tray-busy.png \
+		tray/hicolor/16x16/status/pidgin-tray-invisible.png \
+		tray/hicolor/16x16/status/pidgin-tray-connecting.png \
+		tray/hicolor/16x16/status/pidgin-tray-extended-away.png \
+		tray/hicolor/16x16/status/pidgin-tray-message.png \
+		tray/hicolor/16x16/status/pidgin-tray-new-im.png \
+		tray/hicolor/16x16/status/pidgin-tray-offline.png \
+		tray/hicolor/16x16/status/pidgin-tray-online.png
 
 TRAY_22 = \
-		tray/22/tray-away.png \
-		tray/22/tray-busy.png \
-		tray/22/tray-connecting.png \
-		tray/22/tray-extended-away.png \
-		tray/22/tray-invisible.png \
-		tray/22/tray-message.png \
-		tray/22/tray-new-im.png \
-		tray/22/tray-offline.png \
-		tray/22/tray-online.png
+		tray/hicolor/22x22/status/pidgin-tray-away.png \
+		tray/hicolor/22x22/status/pidgin-tray-busy.png \
+		tray/hicolor/22x22/status/pidgin-tray-connecting.png \
+		tray/hicolor/22x22/status/pidgin-tray-extended-away.png \
+		tray/hicolor/22x22/status/pidgin-tray-invisible.png \
+		tray/hicolor/22x22/status/pidgin-tray-message.png \
+		tray/hicolor/22x22/status/pidgin-tray-new-im.png \
+		tray/hicolor/22x22/status/pidgin-tray-offline.png \
+		tray/hicolor/22x22/status/pidgin-tray-online.png
 
 TRAY_32 = \
-		tray/32/tray-away.png \
-		tray/32/tray-busy.png \
-		tray/32/tray-connecting.png \
-		tray/32/tray-extended-away.png \
-		tray/32/tray-invisible.png \
-		tray/32/tray-message.png \
-		tray/32/tray-new-im.png \
-		tray/32/tray-offline.png \
-		tray/32/tray-online.png
+		tray/hicolor/32x32/status/pidgin-tray-away.png \
+		tray/hicolor/32x32/status/pidgin-tray-busy.png \
+		tray/hicolor/32x32/status/pidgin-tray-connecting.png \
+		tray/hicolor/32x32/status/pidgin-tray-extended-away.png \
+		tray/hicolor/32x32/status/pidgin-tray-invisible.png \
+		tray/hicolor/32x32/status/pidgin-tray-message.png \
+		tray/hicolor/32x32/status/pidgin-tray-new-im.png \
+		tray/hicolor/32x32/status/pidgin-tray-offline.png \
+		tray/hicolor/32x32/status/pidgin-tray-online.png
 
 TRAY_48 = \
-		tray/48/tray-away.png \
-		tray/48/tray-busy.png \
-		tray/48/tray-connecting.png \
-		tray/48/tray-extended-away.png \
-		tray/48/tray-invisible.png \
-		tray/48/tray-message.png \
-		tray/48/tray-new-im.png \
-		tray/48/tray-offline.png \
-		tray/48/tray-online.png
+		tray/hicolor/48x48/status/pidgin-tray-away.png \
+		tray/hicolor/48x48/status/pidgin-tray-busy.png \
+		tray/hicolor/48x48/status/pidgin-tray-connecting.png \
+		tray/hicolor/48x48/status/pidgin-tray-extended-away.png \
+		tray/hicolor/48x48/status/pidgin-tray-invisible.png \
+		tray/hicolor/48x48/status/pidgin-tray-message.png \
+		tray/hicolor/48x48/status/pidgin-tray-new-im.png \
+		tray/hicolor/48x48/status/pidgin-tray-offline.png \
+		tray/hicolor/48x48/status/pidgin-tray-online.png
 
 EXTRA_DIST = \
 		edit.png			\
Binary file pidgin/pixmaps/tray/16/tray-away.png has changed
Binary file pidgin/pixmaps/tray/16/tray-busy.png has changed
Binary file pidgin/pixmaps/tray/16/tray-connecting.png has changed
Binary file pidgin/pixmaps/tray/16/tray-extended-away.png has changed
Binary file pidgin/pixmaps/tray/16/tray-invisible.png has changed
Binary file pidgin/pixmaps/tray/16/tray-message.png has changed
Binary file pidgin/pixmaps/tray/16/tray-new-im.png has changed
Binary file pidgin/pixmaps/tray/16/tray-offline.png has changed
Binary file pidgin/pixmaps/tray/16/tray-online.png has changed
Binary file pidgin/pixmaps/tray/22/tray-away.png has changed
Binary file pidgin/pixmaps/tray/22/tray-busy.png has changed
Binary file pidgin/pixmaps/tray/22/tray-connecting.png has changed
Binary file pidgin/pixmaps/tray/22/tray-extended-away.png has changed
Binary file pidgin/pixmaps/tray/22/tray-invisible.png has changed
Binary file pidgin/pixmaps/tray/22/tray-message.png has changed
Binary file pidgin/pixmaps/tray/22/tray-new-im.png has changed
Binary file pidgin/pixmaps/tray/22/tray-offline.png has changed
Binary file pidgin/pixmaps/tray/22/tray-online.png has changed
Binary file pidgin/pixmaps/tray/32/tray-away.png has changed
Binary file pidgin/pixmaps/tray/32/tray-busy.png has changed
Binary file pidgin/pixmaps/tray/32/tray-connecting.png has changed
Binary file pidgin/pixmaps/tray/32/tray-extended-away.png has changed
Binary file pidgin/pixmaps/tray/32/tray-invisible.png has changed
Binary file pidgin/pixmaps/tray/32/tray-message.png has changed
Binary file pidgin/pixmaps/tray/32/tray-new-im.png has changed
Binary file pidgin/pixmaps/tray/32/tray-offline.png has changed
Binary file pidgin/pixmaps/tray/32/tray-online.png has changed
Binary file pidgin/pixmaps/tray/48/tray-away.png has changed
Binary file pidgin/pixmaps/tray/48/tray-busy.png has changed
Binary file pidgin/pixmaps/tray/48/tray-connecting.png has changed
Binary file pidgin/pixmaps/tray/48/tray-extended-away.png has changed
Binary file pidgin/pixmaps/tray/48/tray-invisible.png has changed
Binary file pidgin/pixmaps/tray/48/tray-message.png has changed
Binary file pidgin/pixmaps/tray/48/tray-new-im.png has changed
Binary file pidgin/pixmaps/tray/48/tray-offline.png has changed
Binary file pidgin/pixmaps/tray/48/tray-online.png has changed
Binary file pidgin/pixmaps/tray/hicolor/16x16/status/pidgin-tray-away.png has changed
Binary file pidgin/pixmaps/tray/hicolor/16x16/status/pidgin-tray-busy.png has changed
Binary file pidgin/pixmaps/tray/hicolor/16x16/status/pidgin-tray-connecting.png has changed
Binary file pidgin/pixmaps/tray/hicolor/16x16/status/pidgin-tray-extended-away.png has changed
Binary file pidgin/pixmaps/tray/hicolor/16x16/status/pidgin-tray-invisible.png has changed
Binary file pidgin/pixmaps/tray/hicolor/16x16/status/pidgin-tray-message.png has changed
Binary file pidgin/pixmaps/tray/hicolor/16x16/status/pidgin-tray-new-im.png has changed
Binary file pidgin/pixmaps/tray/hicolor/16x16/status/pidgin-tray-offline.png has changed
Binary file pidgin/pixmaps/tray/hicolor/16x16/status/pidgin-tray-online.png has changed
Binary file pidgin/pixmaps/tray/hicolor/22x22/status/pidgin-tray-away.png has changed
Binary file pidgin/pixmaps/tray/hicolor/22x22/status/pidgin-tray-busy.png has changed
Binary file pidgin/pixmaps/tray/hicolor/22x22/status/pidgin-tray-connecting.png has changed
Binary file pidgin/pixmaps/tray/hicolor/22x22/status/pidgin-tray-extended-away.png has changed
Binary file pidgin/pixmaps/tray/hicolor/22x22/status/pidgin-tray-invisible.png has changed
Binary file pidgin/pixmaps/tray/hicolor/22x22/status/pidgin-tray-message.png has changed
Binary file pidgin/pixmaps/tray/hicolor/22x22/status/pidgin-tray-new-im.png has changed
Binary file pidgin/pixmaps/tray/hicolor/22x22/status/pidgin-tray-offline.png has changed
Binary file pidgin/pixmaps/tray/hicolor/22x22/status/pidgin-tray-online.png has changed
Binary file pidgin/pixmaps/tray/hicolor/32x32/status/pidgin-tray-away.png has changed
Binary file pidgin/pixmaps/tray/hicolor/32x32/status/pidgin-tray-busy.png has changed
Binary file pidgin/pixmaps/tray/hicolor/32x32/status/pidgin-tray-connecting.png has changed
Binary file pidgin/pixmaps/tray/hicolor/32x32/status/pidgin-tray-extended-away.png has changed
Binary file pidgin/pixmaps/tray/hicolor/32x32/status/pidgin-tray-invisible.png has changed
Binary file pidgin/pixmaps/tray/hicolor/32x32/status/pidgin-tray-message.png has changed
Binary file pidgin/pixmaps/tray/hicolor/32x32/status/pidgin-tray-new-im.png has changed
Binary file pidgin/pixmaps/tray/hicolor/32x32/status/pidgin-tray-offline.png has changed
Binary file pidgin/pixmaps/tray/hicolor/32x32/status/pidgin-tray-online.png has changed
Binary file pidgin/pixmaps/tray/hicolor/48x48/status/pidgin-tray-away.png has changed
Binary file pidgin/pixmaps/tray/hicolor/48x48/status/pidgin-tray-busy.png has changed
Binary file pidgin/pixmaps/tray/hicolor/48x48/status/pidgin-tray-connecting.png has changed
Binary file pidgin/pixmaps/tray/hicolor/48x48/status/pidgin-tray-extended-away.png has changed
Binary file pidgin/pixmaps/tray/hicolor/48x48/status/pidgin-tray-invisible.png has changed
Binary file pidgin/pixmaps/tray/hicolor/48x48/status/pidgin-tray-message.png has changed
Binary file pidgin/pixmaps/tray/hicolor/48x48/status/pidgin-tray-new-im.png has changed
Binary file pidgin/pixmaps/tray/hicolor/48x48/status/pidgin-tray-offline.png has changed
Binary file pidgin/pixmaps/tray/hicolor/48x48/status/pidgin-tray-online.png has changed
--- a/pidgin/plugins/gestures/gestures.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/plugins/gestures/gestures.c	Thu Feb 04 05:30:35 2010 +0000
@@ -57,11 +57,7 @@
 {
 	int count, current;
 
-#if GTK_CHECK_VERSION(2,2,0)
 	count = gtk_notebook_get_n_pages(GTK_NOTEBOOK(win->notebook));
-#else
-	count = g_list_length(GTK_NOTEBOOK(win->notebook)->children);
-#endif
 	current = gtk_notebook_get_current_page(GTK_NOTEBOOK(win->notebook));
 
 	if (dir == GTK_DIR_LEFT)
--- a/pidgin/plugins/perl/common/Makefile.mingw	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/plugins/perl/common/Makefile.mingw	Thu Feb 04 05:30:35 2010 +0000
@@ -25,6 +25,7 @@
 			-I$(PIDGIN_TOP)/win32 \
 			-I$(GTK_TOP)/include \
 			-I$(GTK_TOP)/include/atk-1.0 \
+			-I$(GTK_TOP)/include/cairo \
 			-I$(GTK_TOP)/include/glib-2.0 \
 			-I$(GTK_TOP)/include/gtk-2.0 \
 			-I$(GTK_TOP)/include/pango-1.0 \
--- a/pidgin/plugins/pidginrc.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/plugins/pidginrc.c	Thu Feb 04 05:30:35 2010 +0000
@@ -201,17 +201,13 @@
 purplerc_make_changes(void)
 {
 	GString *str = make_gtkrc_string();
-#if GTK_CHECK_VERSION(2,4,0)
 	GtkSettings *setting = NULL;
-#endif
 
 	gtk_rc_parse_string(str->str);
 	g_string_free(str, TRUE);
 
-#if GTK_CHECK_VERSION(2,4,0)
 	setting = gtk_settings_get_default();
 	gtk_rc_reset_styles(setting);
-#endif
 }
 
 static void
--- a/pidgin/plugins/spellchk.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/plugins/spellchk.c	Thu Feb 04 05:30:35 2010 +0000
@@ -2081,24 +2081,11 @@
 	g_string_free(data, TRUE);
 }
 
-#if !GTK_CHECK_VERSION(2,2,0)
-static void
-count_selected_helper(GtkTreeModel *model, GtkTreePath *path,
-					GtkTreeIter *iter, gpointer user_data)
-{
-	(*(gint *)user_data)++;
-}
-#endif
-
 static void on_selection_changed(GtkTreeSelection *sel,
 	gpointer data)
 {
 	gint num_selected;
-#if GTK_CHECK_VERSION(2,2,0)
 	num_selected = gtk_tree_selection_count_selected_rows(sel);
-#else
-	gtk_tree_selection_selected_foreach(sel, count_selected_helper, &num_selected);
-#endif
 	gtk_widget_set_sensitive((GtkWidget*)data, (num_selected > 0));
 }
 
--- a/pidgin/plugins/xmppconsole.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/plugins/xmppconsole.c	Thu Feb 04 05:30:35 2010 +0000
@@ -26,9 +26,6 @@
 #include "xmlnode.h"
 
 #include "gtkimhtml.h"
-#if !GTK_CHECK_VERSION(2,4,0)
-#include "pidgincombobox.h"
-#endif
 #include "gtkutils.h"
 
 typedef struct {
@@ -733,9 +730,7 @@
 	GtkTextBuffer *buffer;
 	GtkWidget *toolbar;
 	GList *connections;
-#if GTK_CHECK_VERSION(2,4,0)
 	GtkToolItem *button;
-#endif
 
 	if (console) {
 		gtk_window_present(GTK_WINDOW(console->window));
@@ -782,32 +777,17 @@
 	gtk_container_add(GTK_CONTAINER(sw), console->imhtml);
 
 	toolbar = gtk_toolbar_new();
-#if GTK_CHECK_VERSION(2,4,0)
 	button = gtk_tool_button_new(NULL, "<iq/>");
 	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(iq_clicked_cb), NULL);
 	gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(button));
-#else
-	gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "<iq/>",
-			           _("Insert an <iq/> stanza."), "foo", NULL, GTK_SIGNAL_FUNC(iq_clicked_cb), NULL);
-#endif
 
-#if GTK_CHECK_VERSION(2,4,0)
 	button = gtk_tool_button_new(NULL, "<presence/>");
 	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(presence_clicked_cb), NULL);
 	gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(button));
-#else
-	gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "<presence/>",
-			           _("Insert a <presence/> stanza."), NULL, gtk_label_new(NULL), GTK_SIGNAL_FUNC(presence_clicked_cb), NULL);
-#endif
 
-#if GTK_CHECK_VERSION(2,4,0)
 	button = gtk_tool_button_new(NULL, "<message/>");
 	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(message_clicked_cb), NULL);
 	gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(button));
-#else
-	gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), "<message/>",
-			           _("Insert a <message/> stanza."), "foo", gtk_label_new(NULL), GTK_SIGNAL_FUNC(message_clicked_cb), NULL);
-#endif
 
 	gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
 
--- a/pidgin/win32/gtkdocklet-win32.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/win32/gtkdocklet-win32.c	Thu Feb 04 05:30:35 2010 +0000
@@ -585,12 +585,7 @@
 			 G_CALLBACK(dummy_button_cb), NULL);
 
 	image = gtk_image_new();
-#if GLIB_CHECK_VERSION(2,10,0)
 	g_object_ref_sink(image);
-#else
-	g_object_ref(image);
-	gtk_object_sink(GTK_OBJECT(image));
-#endif
 
 	osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
 	GetVersionEx(&osinfo);
--- a/pidgin/win32/gtkwin32dep.c	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/win32/gtkwin32dep.c	Thu Feb 04 05:30:35 2010 +0000
@@ -142,56 +142,33 @@
 
 void winpidgin_shell_execute(const char *target, const char *verb, const char *clazz) {
 
+	SHELLEXECUTEINFOW wsinfo;
+	wchar_t *w_uri, *w_verb, *w_clazz = NULL;
+
 	g_return_if_fail(target != NULL);
 	g_return_if_fail(verb != NULL);
 
-	if (G_WIN32_HAVE_WIDECHAR_API()) {
-		SHELLEXECUTEINFOW wsinfo;
-		wchar_t *w_uri, *w_verb, *w_clazz = NULL;
-
-		w_uri = g_utf8_to_utf16(target, -1, NULL, NULL, NULL);
-		w_verb = g_utf8_to_utf16(verb, -1, NULL, NULL, NULL);
-
-		memset(&wsinfo, 0, sizeof(wsinfo));
-		wsinfo.cbSize = sizeof(wsinfo);
-		wsinfo.lpVerb = w_verb;
-		wsinfo.lpFile = w_uri;
-		wsinfo.nShow = SW_SHOWNORMAL;
-		if (clazz != NULL) {
-			w_clazz = g_utf8_to_utf16(clazz, -1, NULL, NULL, NULL);
-			wsinfo.fMask |= SEE_MASK_CLASSNAME;
-			wsinfo.lpClass = w_clazz;
-		}
-
-		if(!ShellExecuteExW(&wsinfo))
-			purple_debug_error("winpidgin", "Error opening URI: %s error: %d\n",
-				target, (int) wsinfo.hInstApp);
+	w_uri = g_utf8_to_utf16(target, -1, NULL, NULL, NULL);
+	w_verb = g_utf8_to_utf16(verb, -1, NULL, NULL, NULL);
 
-		g_free(w_uri);
-		g_free(w_verb);
-		g_free(w_clazz);
-	} else {
-		SHELLEXECUTEINFOA sinfo;
-		gchar *locale_uri;
-
-		locale_uri = g_locale_from_utf8(target, -1, NULL, NULL, NULL);
+	memset(&wsinfo, 0, sizeof(wsinfo));
+	wsinfo.cbSize = sizeof(wsinfo);
+	wsinfo.lpVerb = w_verb;
+	wsinfo.lpFile = w_uri;
+	wsinfo.nShow = SW_SHOWNORMAL;
+	if (clazz != NULL) {
+		w_clazz = g_utf8_to_utf16(clazz, -1, NULL, NULL, NULL);
+		wsinfo.fMask |= SEE_MASK_CLASSNAME;
+		wsinfo.lpClass = w_clazz;
+	}
 
-		memset(&sinfo, 0, sizeof(sinfo));
-		sinfo.cbSize = sizeof(sinfo);
-		sinfo.lpVerb = verb;
-		sinfo.lpFile = locale_uri;
-		sinfo.nShow = SW_SHOWNORMAL;
-		if (clazz != NULL) {
-			sinfo.fMask |= SEE_MASK_CLASSNAME;
-			sinfo.lpClass = clazz;
-		}
+	if(!ShellExecuteExW(&wsinfo))
+		purple_debug_error("winpidgin", "Error opening URI: %s error: %d\n",
+			target, (int) wsinfo.hInstApp);
 
-		if(!ShellExecuteExA(&sinfo))
-			purple_debug_error("winpidgin", "Error opening URI: %s error: %d\n",
-				target, (int) sinfo.hInstApp);
-
-		g_free(locale_uri);
-	}
+	g_free(w_uri);
+	g_free(w_verb);
+	g_free(w_clazz);
 
 }
 
@@ -406,6 +383,7 @@
 }
 
 void winpidgin_init(HINSTANCE hint) {
+	FARPROC exchndl_SetLogFile;
 
 	purple_debug_info("winpidgin", "winpidgin_init start\n");
 
@@ -423,6 +401,16 @@
 
 	MyFlashWindowEx = (LPFNFLASHWINDOWEX) wpurple_find_and_loadproc("user32.dll", "FlashWindowEx");
 
+	exchndl_SetLogFile = wpurple_find_and_loadproc("exchndl.dll", "SetLogFile");
+	if (exchndl_SetLogFile) {
+		gchar *filename = g_build_filename(purple_user_dir(),
+			"pidgin.RPT", NULL);
+		purple_debug_info("winpidgin", "Setting exchndl.dll LogFile to %s\n",
+			filename);
+		(exchndl_SetLogFile)(filename);
+		g_free(filename);
+	}
+
 	purple_debug_info("winpidgin", "winpidgin_init end\n");
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/win32/nsis/available.lst	Thu Feb 04 05:30:35 2010 +0000
@@ -0,0 +1,127 @@
+#This file is from ftp://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/available.lst
+af,ZA,af_ZA,Afrikaans (South Africa),af_ZA.zip
+ak,GH,ak_GH,Akan (Ghana),ak_GH.zip
+sq,AL,sq_AL,Albanian (Albania),sq_AL.zip
+bg,BG,bg_BG,Bulgarian (Bulgaria),bg_BG.zip
+ca,ES,ca_ES,Catalan (Spain),ca_ES.zip
+hr,HR,hr_HR,Croatian (Croatia),hr_HR.zip
+cs,CZ,cs_CZ,Czech (Czech Republic),cs_CZ.zip
+da,DK,da_DK,Danish (Denmark),da_DK.zip
+nl,NL,nl_NL,Dutch (Netherlands),nl_NL.zip
+nl,NL,nl_med,Dutch Medical (Netherlands),nl_med.zip
+nl,BE,nl_NL,Dutch (Belgium),nl_NL.zip
+nl,BE,nl_NL,Dutch Medical (Belgium),nl_NL.zip
+en,AU,en_AU,English (Australia),en_AU.zip
+en,CA,en_CA,English (Canada),en_CA.zip
+en,NZ,en_NZ,English (New Zealand),en_NZ.zip
+en,ZA,en_ZA,English (South Africa),en_ZA.zip
+en,GB,en_GB,English (United Kingdom),en_GB.zip
+en,US,en_US,English (United States),en_US.zip
+cop,EG,cop_EG,Coptic (Egypt),cop_EG.zip
+eo,ANY,eo_l3,Esperanto,eo.zip
+et,EE,et_EE,Estonian (Estonia),et_EE.zip
+fo,FO,fo_FO,Faroese (Faroe Islands),fo_FO.zip
+fr,BE,fr_FR,Français Réforme 1990 & Classique (Belgium),fr_FR_1-3-2.zip
+fr,CA,fr_FR,Français Réforme 1990 & Classique (Canada),fr_FR_1-3-2.zip
+fr,FR,fr_FR,Français Réforme 1990 & Classique (France),fr_FR_1-3-2.zip
+fr,LU,fr_FR,Français Réforme 1990 & Classique (Luxembourg),fr_FR_1-3-2.zip
+fr,MC,fr_FR,Français Réforme 1990 & Classique (Monaco),fr_FR_1-3-2.zip
+fr,CH,fr_FR,Français Réforme 1990 & Classique (Switzerland),fr_FR_1-3-2.zip
+fr,BE,fr_FR-classique,Français Classique (Belgium),fr_FR-classique_1-3-2.zip
+fr,CA,fr_FR-classique,Français Classique (Canada),fr_FR-classique_1-3-2.zip
+fr,FR,fr_FR-classique,Français Classique (France),fr_FR-classique_1-3-2.zip
+fr,LU,fr_FR-classique,Français Classique (Luxembourg),fr_FR-classique_1-3-2.zip
+fr,MC,fr_FR-classique,Français Classique (Monaco),fr_FR-classique_1-3-2.zip
+fr,CH,fr_FR-classique,Français Classique  (Switzerland),fr_FR-classique_1-3-2.zip
+fr,BE,fr_FR-1990,Français Réforme 1990 (Belgium),fr_FR-1990_1-3-2.zip
+fr,CA,fr_FR-1990,Français Réforme 1990 (Canada),fr_FR-1990_1-3-2.zip
+fr,FR,fr_FR-1990,Français Réforme 1990 (France),fr_FR-1990_1-3-2.zip
+fr,LU,fr_FR-1990,Français Réforme 1990 (Luxembourg),fr_FR-1990_1-3-2.zip
+fr,MC,fr_FR-1990,Français Réforme 1990 (Monaco),fr_FR-1990_1-3-2.zip
+fr,CH,fr_FR-1990,Français Réforme 1990 (Switzerland),fr_FR-1990_1-3-2.zip
+fy,NL,fy_NL,Frisian (Netherlands),fy_NL.zip
+gl,ES,gl_ES,Galician (Spain),gl_ES.zip
+gsc,FR,gsc_FR,Gascon (France),gsc_FR.zip
+de,AT,de_DE,German (Austria Base),de_DE.zip
+de,AT,de_AT,German (Austria Extension),de_AT.zip
+de,AT,de_AT_frami,German (Austria) neu 08/2006 (frami),de_AT_frami.zip
+de,DE,de_DE,German (Germany),de_DE.zip
+de,DE,de_DE_frami,German (Germany) neu 08/2006 (frami),de_DE_frami.zip
+de,LI,de_CH,German (Liechtenstein),de_CH.zip
+de,LI,de_CH_frami,German (Liechtenstein) neu 08/2006 (frami),de_CH_frami.zip
+de,LU,de_DE,German (Luxembourg),de_DE.zip
+de,LU,de_DE_frami,German (Luxembourg) neu 08/2006 (frami),de_DE_frami.zip
+de,CH,de_CH,German (Switzerland),de_CH.zip
+de,CT,de_CH_frami,German (Switzerland) neu 08/2006 (frami),de_CH_frami.zip
+el,GR,el_GR,Greek (Greece),el_GR.zip
+gu,IN,gu_IN,Gujarati (India),gu_IN.zip
+gd,GB,gd_GB,Scots Gaelic (Scotland),gd_GB.zip
+he,IL,he_IL,Hebrew (Israel),he_IL.zip
+hil,PH,hil_PH,Hiligaynon (Philippines),hil_PH.zip
+hu,HU,hu_HU,Hungarian (Hungary),hu_HU.zip
+hu,HU,hu_HU_comb,Hungarian (Hungary) collected compounds,hu_HU_comb.zip
+id,ID,id_ID,Indonesian (Indonesia),id_ID.zip
+ia,ANY,ia_ANY,Interlingua (ANY locale),ia_ANY.zip
+ga,IE,ga_IE,Irish (Ireland),ga_IE.zip
+it,IT,it_IT,Italian (Italy),it_IT.zip
+it,CH,it_IT,Italian (Switzerland),it_IT.zip
+sw,KE,sw_KE,Kiswahili (Africa),sw_KE.zip
+lv,LV,lv_LV,Latvian (Latvia),lv_LV.zip
+ku,TR,ku_TR,Kurdish (Turkey),ku_TR.zip
+ku,TR,ku_TR,Kurdish (Syria),ku_TR.zip
+it,IT,la,Latin (for x-register),la.zip
+lt,LT,lt_LT,Lithuanian (Lithuania),lt_LT.zip
+mk,MK,mk_MK,Macedonian (Macedonia),mk_MK.zip
+ms,MY,ms_MY,Malay (Malaysia),ms_MY.zip
+mi,NZ,mi_NZ,Maori (New Zealand),mi_NZ.zip
+mr,IN,mr_IN,Marathi (India),mr_IN.zip
+mos,BF,mos_BF,Moore,ms_BF.zip
+nr,ZA,nr_ZA,Ndebele (South Africa),nr_ZA.zip
+ne,NP,ne_NP,Nepali (Nepal),ne_NP.zip
+ns,ZA,ns_ZA,Northern Sotho (South Africa),ns_ZA.zip
+nb,NO,nb_NO,Norwegian Bokmaal (Norway),nb_NO.zip
+nn,NO,nn_NO,Norwegian Nynorsk (Norway),nn_NO.zip
+oc,FR,oc_FR,Occitan (Languedoc),oc_FR.zip
+pl,PL,pl_PL,Polish (Poland),pl_PL.zip
+pt,BR,pt_BR,Portuguese (Brazil),pt_BR.zip
+pt,PT,pt_PT,Portuguese (Portugal),pt_PT.zip
+ro,RO,ro_RO,Romanian (Romania),ro_RO.zip
+ru,RU,ru_RU,Russian (Russia),ru_RU.zip
+ru,RU,ru_RU_ye,Russian_ye (Russia),ru_RU_ye.zip
+ru,RU,ru_RU_yo,Russian_yo (Russia),ru_RU_yo.zip
+tn,ZA,tn_ZA,Setswana (Africa),tn_ZA.zip
+sk,SK,sk_SK,Slovak (Slovakia),sk_SK.zip
+sl,SI,sl_SI,Slovenian (Slovenia),sl_SI.zip
+st,ZA,st_ZA,Southern Sotho (South Africa),st_ZA.zip
+es,AR,es_AR,Spanish (Argentina),es_AR.zip
+es,BZ,es_HN,Spanish (Belize),es_HN.zip
+es,BO,es_BO,Spanish (Bolivia),es_BO.zip
+es,CL,es_CL,Spanish (Chile),es_CL.zip
+es,CO,es_CO,Spanish (Colombia),es_CO.zip
+es,CR,es_CR,Spanish (Costa Rica),es_CR.zip
+es,CU,es_CU,Spanish (Cuba),es_CU.zip
+es,DO,es_DO,Spanish (Dominican Republic),es_DO.zip
+es,EC,es_EC,Spanish (Ecuador),es_EC.zip
+es,SV,es_SV,Spanish (El Salvador),es_SV.zip
+es,GT,es_GT,Spanish (Guatemala),es_GT.zip
+es,HN,es_HN,Spanish (Honduras),es_HN.zip
+es,MX,es_MX,Spanish (Mexico),es_MX.zip
+es,NI,es_NI,Spanish (Nicaragua),es_NI.zip
+es,PA,es_PA,Spanish (Panama),es_PA.zip
+es,PY,es_PY,Spanish (Paraguay),es_PY.zip
+es,PE,es_PE,Spanish (Peru),es_PE.zip
+es,PR,es_PR,Spanish (Puerto Rico),es_PR.zip
+es,ES,es_ES,Spanish (Spain),es_ES.zip
+es,UY,es_UY,Spanish (Uruguay),es_UY.zip
+es,VE,es_VE,Spanish (Venezuela),es_VE.zip
+ss,ZA,ss_ZA,Swati (South Africa),ss_ZA.zip
+sv,SE,sv_SE,Swedish (Sweden),sv_SE.zip
+ts,ZA,ts_ZA,Tsonga (South Africa),ts_ZA.zip
+uk,UA,uk_UA,Ukrainian (Ukraine),uk_UA.zip
+ur,IN,ur_PK,Urdu (India),ur_PK.zip
+ur,PK,ur_PK,Urdu (Pakistan),ur_PK.zip
+ve,ZA,ve_ZA,Venda (South Africa),ve_ZA.zip
+vi,VN,vi_VN,Vietnamese (Viet-Nam),vi_VN.zip
+cy,GB,cy_GB,Welsh (Wales),cy_GB.zip
+xh,ZA,xh_ZA,Xhosa (South Africa),xh_ZA.zip
+zu,ZA,zu_ZA,Zulu (South Africa),zu_ZA.zip
--- a/pidgin/win32/nsis/langmacros.nsh	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/win32/nsis/langmacros.nsh	Thu Feb 04 05:30:35 2010 +0000
@@ -31,7 +31,6 @@
   ; Startup checks
   !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT INSTALLER_IS_RUNNING		${CUR_LANG}
   !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT PIDGIN_IS_RUNNING			${CUR_LANG}
-  !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT GTK_INSTALLER_NEEDED		${CUR_LANG}
 
   ; License Page
   !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT PIDGIN_LICENSE_BUTTON			${CUR_LANG}
@@ -48,10 +47,7 @@
   !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT PIDGIN_SHORTCUTS_SECTION_DESCRIPTION	${CUR_LANG}
   !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT PIDGIN_DESKTOP_SHORTCUT_DESC		${CUR_LANG}
   !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT PIDGIN_STARTMENU_SHORTCUT_DESC	${CUR_LANG}
-
-  ; GTK+ Directory Page
-  !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT GTK_UPGRADE_PROMPT			${CUR_LANG}
-  !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT GTK_WINDOWS_INCOMPATIBLE		${CUR_LANG}
+  !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT DEBUG_SYMBOLS_SECTION_TITLE ${CUR_LANG}
 
   ; Installer Finish Page
   !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT PIDGIN_FINISH_VISIT_WEB_SITE		${CUR_LANG}
@@ -59,10 +55,6 @@
   ; Pidgin Section Prompts and Texts
   !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT PIDGIN_PROMPT_CONTINUE_WITHOUT_UNINSTALL	${CUR_LANG}
 
-  ; GTK+ Section Prompts
-  !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT GTK_INSTALL_ERROR			${CUR_LANG}
-  !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT GTK_BAD_INSTALL_PATH		${CUR_LANG}
-
   ; URI Handler section
   !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT URI_HANDLERS_SECTION_TITLE		${CUR_LANG}
 
@@ -99,6 +91,9 @@
   !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT PIDGIN_SPELLCHECK_SWEDISH		${CUR_LANG}
   !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT PIDGIN_SPELLCHECK_UKRAINIAN		${CUR_LANG}
 
+  !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT PIDGIN_DEBUGSYMBOLS_ERROR ${CUR_LANG}
+  !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT PIDGIN_GTK_DOWNLOAD_ERROR ${CUR_LANG}
+
   !undef CUR_LANG
 !macroend
 
--- a/pidgin/win32/nsis/pidgin-installer.nsi	Thu Feb 04 02:18:37 2010 +0000
+++ b/pidgin/win32/nsis/pidgin-installer.nsi	Thu Feb 04 05:30:35 2010 +0000
@@ -8,11 +8,9 @@
 ;--------------------------------
 ;Global Variables
 Var name
-Var GTK_FOLDER
 Var ISSILENT
 Var STARTUP_RUN_KEY
 Var SPELLCHECK_SEL
-Var LANGUAGE_SET
 
 ;--------------------------------
 ;Configuration
@@ -20,14 +18,10 @@
 ;The name var is set in .onInit
 Name $name
 
-!ifdef WITH_GTK
-OutFile "pidgin-${PIDGIN_VERSION}.exe"
+!ifdef OFFLINE_INSTALLER
+OutFile "pidgin-${PIDGIN_VERSION}-offline.exe"
 !else
-!ifdef DEBUG
-OutFile "pidgin-${PIDGIN_VERSION}-debug.exe"
-!else
-OutFile "pidgin-${PIDGIN_VERSION}-no-gtk.exe"
-!endif
+OutFile "pidgin-${PIDGIN_VERSION}.exe"
 !endif
 
 SetCompressor /SOLID lzma
@@ -41,6 +35,7 @@
 !include "Sections.nsh"
 !include "WinVer.nsh"
 !include "LogicLib.nsh"
+!include "Memento.nsh"
 
 !include "FileFunc.nsh"
 !insertmacro GetParameters
@@ -52,11 +47,13 @@
 !insertmacro WordFind
 !insertmacro un.WordFind
 
+!include "TextFunc.nsh"
+
 ;--------------------------------
 ;Defines
 
 !define PIDGIN_NSIS_INCLUDE_PATH		"."
-!define PIDGIN_INSTALLER_DEPS			"..\..\..\..\win32-dev\pidgin-inst-deps"
+!define PIDGIN_INSTALLER_DEPS			"..\..\..\..\win32-dev\pidgin-inst-deps-0.2"
 
 ; Remove these and the stuff that uses them at some point
 !define OLD_GAIM_REG_KEY			"SOFTWARE\gaim"
@@ -70,16 +67,16 @@
 !define STARTUP_RUN_KEY				"SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
 !define PIDGIN_UNINST_EXE			"pidgin-uninst.exe"
 
-!define GTK_MIN_VERSION				"2.6.10"
-!define GTK_REG_KEY				"SOFTWARE\GTK\2.0"
+!define GTK_MIN_VERSION				"2.14.0"
 !define PERL_REG_KEY				"SOFTWARE\Perl"
 !define PERL_DLL				"perl510.dll"
-!define GTK_DEFAULT_INSTALL_PATH		"$COMMONFILES\GTK\2.0"
-!define GTK_RUNTIME_INSTALLER			"..\..\..\..\gtk_installer\gtk-runtime-${GTK_INSTALL_VERSION}*.exe"
 
 !define ASPELL_REG_KEY				"SOFTWARE\Aspell"
 !define DOWNLOADER_URL				"http://pidgin.im/win32/download_redir.php"
 
+!define MEMENTO_REGISTRY_ROOT			HKLM
+!define MEMENTO_REGISTRY_KEY			"${PIDGIN_UNINSTALL_KEY}"
+
 ;--------------------------------
 ;Version resource
 VIProductVersion "${PIDGIN_PRODUCT_VERSION}"
@@ -87,14 +84,10 @@
 VIAddVersionKey "FileVersion" "${PIDGIN_VERSION}"
 VIAddVersionKey "ProductVersion" "${PIDGIN_VERSION}"
 VIAddVersionKey "LegalCopyright" ""
-!ifdef WITH_GTK
-VIAddVersionKey "FileDescription" "Pidgin Installer (w/ GTK+ Installer)"
+!ifdef OFFLINE_INSTALLER
+VIAddVersionKey "FileDescription" "Pidgin Installer (Offline)"
 !else
-!ifdef DEBUG
-VIAddVersionKey "FileDescription" "Pidgin Installer (Debug Version)"
-!else
-VIAddVersionKey "FileDescription" "Pidgin Installer (w/o GTK+ Installer)"
-!endif
+VIAddVersionKey "FileDescription" "Pidgin Installer"
 !endif
 
 ;--------------------------------
@@ -139,14 +132,6 @@
   !insertmacro MUI_PAGE_LICENSE			"../../../COPYING"
   !insertmacro MUI_PAGE_COMPONENTS
 
-!ifdef WITH_GTK
-  ; GTK+ install dir page
-  !define MUI_PAGE_CUSTOMFUNCTION_PRE		preGtkDirPage
-  !define MUI_PAGE_CUSTOMFUNCTION_LEAVE		postGtkDirPage
-  !define MUI_DIRECTORYPAGE_VARIABLE		$GTK_FOLDER
-  !insertmacro MUI_PAGE_DIRECTORY
-!endif
-
   ; Pidgin install dir page
   !insertmacro MUI_PAGE_DIRECTORY
 
@@ -317,7 +302,7 @@
           IfErrors uninstall_problem
             ; Ready to uninstall..
             ClearErrors
-            ExecWait '"$TEMP\$R6" /S _?=$R1'
+            ExecWait '"$TEMP\$R6" /S /KEEPGTK=1 _?=$R1'
             IfErrors exec_error
               Delete "$TEMP\$R6"
             Goto done
@@ -348,77 +333,38 @@
 ;--------------------------------
 ;GTK+ Runtime Install Section
 
-!ifdef WITH_GTK
 Section $(GTK_SECTION_TITLE) SecGtk
 
-  Call CheckUserInstallRights
-  Pop $R1
-
-  SetOutPath $TEMP
-  SetOverwrite on
-  File /oname=gtk-runtime.exe ${GTK_RUNTIME_INSTALLER}
-  SetOverwrite off
-
-  Call DoWeNeedGtk
-  Pop $R0
-  Pop $R6
+  InitPluginsDir
+  StrCpy $R1 "$PLUGINSDIR\gtk.zip"
+!ifdef OFFLINE_INSTALLER
 
-  StrCmp $R0 "0" have_gtk
-  StrCmp $R0 "1" upgrade_gtk
-  StrCmp $R0 "2" upgrade_gtk
-  ;StrCmp $R0 "3" no_gtk no_gtk
+  SetOutPath $PLUGINSDIR
+  File /oname=gtk.zip "..\..\..\..\gtk_installer\gtk-runtime-${GTK_INSTALL_VERSION}.zip"
 
-  ;no_gtk:
-    StrCmp $R1 "NONE" gtk_no_install_rights
-    ClearErrors
-    ExecWait '"$TEMP\gtk-runtime.exe" /L=$LANGUAGE $ISSILENT /D=$GTK_FOLDER'
-    IfErrors gtk_install_error done
-
-  upgrade_gtk:
-    StrCpy $GTK_FOLDER $R6
-    StrCmp $R0 "2" +2 ; Upgrade isn't optional
-    MessageBox MB_YESNO $(GTK_UPGRADE_PROMPT) /SD IDYES IDNO done
-    ClearErrors
-    ExecWait '"$TEMP\gtk-runtime.exe" /L=$LANGUAGE $ISSILENT /D=$GTK_FOLDER'
-    IfErrors gtk_install_error done
+!else
 
-    gtk_install_error:
-      Delete "$TEMP\gtk-runtime.exe"
-      MessageBox MB_OK $(GTK_INSTALL_ERROR) /SD IDOK
-      Quit
-
-  have_gtk:
-    StrCpy $GTK_FOLDER $R6
-    StrCmp $R1 "NONE" done ; If we have no rights, we can't re-install
-    ; Even if we have a sufficient version of GTK+, we give user choice to re-install.
-    ClearErrors
-    ExecWait '"$TEMP\gtk-runtime.exe" /L=$LANGUAGE $ISSILENT'
-    IfErrors gtk_install_error
-    Goto done
+  ; We need to download the GTK+ runtime
+  retry:
+  StrCpy $R2 "${DOWNLOADER_URL}?version=${PIDGIN_VERSION}&gtk_version=${GTK_INSTALL_VERSION}&dl_pkg=gtk"
+  DetailPrint "Downloading GTK+ Runtime ... ($R2)"
+  NSISdl::download /TIMEOUT=10000 $R2 $R1
+  Pop $R0
+  StrCmp $R0 "cancel" done
+  StrCmp $R0 "success" +2
+    MessageBox MB_RETRYCANCEL "$(PIDGIN_GTK_DOWNLOAD_ERROR) : $R1" /SD IDCANCEL IDRETRY retry IDCANCEL done
 
-  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-  ; end got_install rights
+!endif
+
+  SetOutPath "$INSTDIR"
 
-  gtk_no_install_rights:
-    ; Install GTK+ to Pidgin install dir
-    StrCpy $GTK_FOLDER $INSTDIR
-    ClearErrors
-    ExecWait '"$TEMP\gtk-runtime.exe" /L=$LANGUAGE $ISSILENT /D=$GTK_FOLDER'
-    IfErrors gtk_install_error
-      SetOverwrite on
-      ClearErrors
-      CopyFiles /FILESONLY "$GTK_FOLDER\bin\*.dll" $GTK_FOLDER
-      SetOverwrite off
-      IfErrors gtk_install_error
-        Delete "$GTK_FOLDER\bin\*.dll"
-        Goto done
-  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-  ; end gtk_no_install_rights
+  nsisunz::UnzipToLog $R1 "$INSTDIR"
+  Pop $R0
+  StrCmp $R0 "success" +2
+    DetailPrint "$R0" ;print error message to log
 
   done:
-    Delete "$TEMP\gtk-runtime.exe"
 SectionEnd ; end of GTK+ section
-!endif
 
 ;--------------------------------
 ;Pidgin Install Section
@@ -430,15 +376,12 @@
   Call CheckUserInstallRights
   Pop $R0
 
-  ; Get GTK+ lib dir if we have it..
-
-  StrCmp $R0 "NONE" pidgin_none
+  StrCmp $R0 "NONE" pidgin_install_files
   StrCmp $R0 "HKLM" pidgin_hklm pidgin_hkcu
 
   pidgin_hklm:
-    ReadRegStr $R1 HKLM ${GTK_REG_KEY} "Path"
     WriteRegStr HKLM "${HKLM_APP_PATHS_KEY}" "" "$INSTDIR\pidgin.exe"
-    WriteRegStr HKLM "${HKLM_APP_PATHS_KEY}" "Path" "$R1\bin"
+    WriteRegStr HKLM "${HKLM_APP_PATHS_KEY}" "Path" "$INSTDIR\Gtk\bin"
     WriteRegStr HKLM ${PIDGIN_REG_KEY} "" "$INSTDIR"
     WriteRegStr HKLM ${PIDGIN_REG_KEY} "Version" "${PIDGIN_VERSION}"
     WriteRegStr HKLM "${PIDGIN_UNINSTALL_KEY}" "DisplayName" "Pidgin"
@@ -452,10 +395,6 @@
     Goto pidgin_install_files
 
   pidgin_hkcu:
-    ReadRegStr $R1 HKCU ${GTK_REG_KEY} "Path"
-    StrCmp $R1 "" 0 +2
-      ReadRegStr $R1 HKLM ${GTK_REG_KEY} "Path"
-
     WriteRegStr HKCU ${PIDGIN_REG_KEY} "" "$INSTDIR"
     WriteRegStr HKCU ${PIDGIN_REG_KEY} "Version" "${PIDGIN_VERSION}"
     WriteRegStr HKCU "${PIDGIN_UNINSTALL_KEY}" "DisplayName" "Pidgin"
@@ -466,9 +405,6 @@
     WriteRegStr HKCU "${PIDGIN_UNINSTALL_KEY}" "UninstallString" "$INSTDIR\${PIDGIN_UNINST_EXE}"
     Goto pidgin_install_files
 
-  pidgin_none:
-    ReadRegStr $R1 HKLM ${GTK_REG_KEY} "Path"
-
   pidgin_install_files:
     SetOutPath "$INSTDIR"
     ; Pidgin files
@@ -478,18 +414,8 @@
     Delete "$INSTDIR\plugins\liboscar.dll"
     Delete "$INSTDIR\plugins\libjabber.dll"
 
-    File /r ..\..\..\${PIDGIN_INSTALL_DIR}\*.*
-    !ifdef DEBUG
+    File /r /x locale ..\..\..\${PIDGIN_INSTALL_DIR}\*.*
     File "${PIDGIN_INSTALLER_DEPS}\exchndl.dll"
-    !endif
-
-    ; Install shfolder.dll if need be..
-    SearchPath $R4 "shfolder.dll"
-    StrCmp $R4 "" 0 got_shfolder
-      SetOutPath "$SYSDIR"
-      File "${PIDGIN_INSTALLER_DEPS}\shfolder.dll"
-      SetOutPath "$INSTDIR"
-    got_shfolder:
 
     ; Check if Perl is installed, if so add it to the AppPaths
     ReadRegStr $R2 HKLM ${PERL_REG_KEY} ""
@@ -574,6 +500,22 @@
 SectionGroupEnd
 
 ;--------------------------------
+;Translations
+
+!macro LANG_SECTION lang
+  ${MementoUnselectedSection} "${lang}" SecLang_${lang}
+    SetOutPath "$INSTDIR\locale\${lang}\LC_MESSAGES"
+    File /oname=pidgin.mo "..\..\..\${PIDGIN_INSTALL_DIR}\locale\${lang}\LC_MESSAGES\pidgin.mo"
+    SetOutPath "$INSTDIR"
+  ${MementoSectionEnd}
+!macroend
+SectionGroup $(TRANSLATIONS_SECTION_TITLE) SecTranslations
+  # pidgin-translations is generated based on the contents of the locale directory
+  !include "pidgin-translations.nsh"
+SectionGroupEnd
+${MementoSectionDone}
+
+;--------------------------------
 ;Spell Checking
 
 SectionGroup /e $(PIDGIN_SPELLCHECK_SECTION_TITLE) SecSpellCheck
@@ -667,6 +609,37 @@
   SectionEnd
 SectionGroupEnd
 
+Section /o $(DEBUG_SYMBOLS_SECTION_TITLE) SecDebugSymbols
+  InitPluginsDir
+
+  ; We need to download and extract the debug symbols
+  StrCpy $R1 "$PLUGINSDIR\pidgin-${PIDGIN_VERSION}-dbgsym.zip"
+!ifdef OFFLINE_INSTALLER
+
+  SetOutPath $PLUGINSDIR
+  File /oname=pidgin-${PIDGIN_VERSION}-dbgsym.zip "..\..\..\..\gtk_installer\gtk-runtime-${GTK_INSTALL_VERSION}.zip"
+
+!else
+
+  retry:
+  StrCpy $R2 "${DOWNLOADER_URL}?version=${PIDGIN_VERSION}&dl_pkg=dbgsym"
+  DetailPrint "Downloading Debug Symbols... ($R2)"
+  NSISdl::download /TIMEOUT=10000 $R2 $R1
+  Pop $R0
+  StrCmp $R0 "cancel" done
+  StrCmp $R0 "success" +2
+    MessageBox MB_RETRYCANCEL "$(PIDGIN_DEBUGSYMBOLS_ERROR) : $R2" /SD IDCANCEL IDRETRY retry IDCANCEL done
+
+!endif
+
+  nsisunz::UnzipToLog $R1 "$INSTDIR"
+  Pop $R0
+  StrCmp $R0 "success" +2
+    DetailPrint "$R0" ;print error message to log
+
+  done:
+SectionEnd
+
 ;--------------------------------
 ;Uninstaller Section
 
@@ -819,11 +792,20 @@
     Delete "$INSTDIR\softokn3.dll"
     Delete "$INSTDIR\ssl3.dll"
     Delete "$INSTDIR\${PIDGIN_UNINST_EXE}"
-    !ifdef DEBUG
     Delete "$INSTDIR\exchndl.dll"
-    !endif
     Delete "$INSTDIR\install.log"