diff --git a/pidgin/gtkblist.c b/pidgin/gtkblist.c
--- a/pidgin/gtkblist.c
+++ b/pidgin/gtkblist.c
@@ -3904,7 +3904,7 @@
 	theme = pidgin_blist_get_theme();
 	name_color = NULL;
 
-	dim_grey = pidgin_style_context_is_dark(NULL) ? "light slate grey" : "dim grey";
+	dim_grey = pidgin_style_context_is_dark() ? "light slate grey" : "dim grey";
 
 	if (theme) {
 		if (purple_presence_is_idle(presence)) {
@@ -5909,7 +5909,7 @@
 				textcolor = pidgin_theme_font_get_color_describe(pair);
 			else
 				/* If no theme them default to making idle buddy names grey */
-				textcolor = pidgin_style_context_is_dark(NULL) ? "light slate grey" : "dim grey";
+				textcolor = pidgin_style_context_is_dark() ? "light slate grey" : "dim grey";
 
 			if (textcolor) {
 				idle = g_strdup_printf("<span color='%s' font_desc='%s'>%d:%02d</span>",
diff --git a/pidgin/gtkconv.h b/pidgin/gtkconv.h
--- a/pidgin/gtkconv.h
+++ b/pidgin/gtkconv.h
@@ -100,7 +100,6 @@
 	GtkWidget *tabby;
 	GtkWidget *menu_tabby;
 
-	GArray *nick_colors;
 	PurpleMessageFlags last_flags;
 	GtkWidget *history_sw;
 	GtkWidget *history;
diff --git a/pidgin/gtkconv.c b/pidgin/gtkconv.c
--- a/pidgin/gtkconv.c
+++ b/pidgin/gtkconv.c
@@ -63,8 +63,6 @@
 #include "pidgintooltip.h"
 #include "pidginwindow.h"
 
-#include "gtknickcolors.h"
-
 #define GTK_TOOLTIPS_VAR gtkconv->tooltips
 
 #define ADD_MESSAGE_HISTORY_AT_ONCE 100
@@ -135,11 +133,6 @@
 #define BUDDYICON_SIZE_MIN    32
 #define BUDDYICON_SIZE_MAX    96
 
-#define MIN_LUMINANCE_CONTRAST_RATIO 4.5
-
-#define NICK_COLOR_GENERATE_COUNT 220
-static GArray *generated_nick_colors = NULL;
-
 /* These probably won't conflict with any WebKit values. */
 #define PIDGIN_DRAG_BLIST_NODE (1337)
 #define PIDGIN_DRAG_IM_CONTACT (31337)
@@ -172,9 +165,6 @@
 static void update_typing_icon(PidginConversation *gtkconv);
 static void update_typing_message(PidginConversation *gtkconv, const char *message);
 gboolean pidgin_conv_has_focus(PurpleConversation *conv);
-static GArray* generate_nick_colors(guint numcolors, GdkRGBA background);
-gdouble luminance(GdkRGBA color);
-static gboolean color_is_visible(GdkRGBA foreground, GdkRGBA background, gdouble min_contrast_ratio);
 static GtkTextTag *get_buddy_tag(PurpleChatConversation *chat, const char *who, PurpleMessageFlags flag, gboolean create);
 static void pidgin_conv_update_fields(PurpleConversation *conv, PidginConvFields fields);
 static void focus_out_from_menubar(GtkWidget *wid, PidginConvWindow *win);
@@ -186,21 +176,52 @@
 		int width, int height);
 static gboolean pidgin_conv_xy_to_right_infopane(PidginConvWindow *win, int x, int y);
 
-static const GdkRGBA *
-get_nick_color(PidginConversation *gtkconv, const gchar *name)
-{
-	static GdkRGBA col;
-
-	if (name == NULL) {
-		col.red = col.green = col.blue = 0;
-		col.alpha = 1;
-		return &col;
-	}
-
-	col = g_array_index(gtkconv->nick_colors, GdkRGBA,
-		g_str_hash(name) % gtkconv->nick_colors->len);
-
-	return &col;
+/*<private>
+ * get_nick_color:
+ * @name: The name or text to get a color for.
+ * @color: (out): The return address for a #GdkRGBA that will recieve the
+ *         color.
+ *
+ * This function is based heavily on the implementation that gajim uses from
+ * python-nbxmpp in nbxmpp.util.text_to_color.  However, we don't have an
+ * implementation of HSL let alone HSLuv, so we're using HSV which is why
+ * the value is 1.0 instead of a luminance of 0.5.
+ *
+ * Currently there is no caching as GCache is deprecated and writing a fast LRU
+ * in glib is going to take a bit of finese.  Also we'll need to figure out how
+ * to scale to ginormous Twitch channels which will constantly break the cache.
+ */
+static void
+get_nick_color(const gchar *name, GdkRGBA *color) {
+	GdkRGBA background;
+	GChecksum *checksum = NULL;
+	guchar digest[20];
+	gsize digest_len = sizeof(digest);
+	gdouble hue = 0, red = 0, green = 0, blue = 0;
+
+	pidgin_style_context_get_background_color(&background);
+
+	/* hash the string and get the first 2 bytes of the digest */
+	checksum = g_checksum_new(G_CHECKSUM_SHA1);
+	g_checksum_update(checksum, (const guchar *)name, -1);
+	g_checksum_get_digest(checksum, digest, &digest_len);
+	g_checksum_free(checksum);
+
+	/* Calculate the hue based on the digest.  We need a value between 0 and 1
+	 * so we divide the value by 65535 which is the maximum value for 2 bytes.
+	 */
+	hue = (digest[0] << 8 | digest[1]) / 65535.0;
+
+	/* Get the rgb values for the hue at full saturation and value. */
+	gtk_hsv_to_rgb(hue, 1.0, 1.0, &red, &green, &blue);
+
+	/* Finally calculate the color summing 20% of the inverted background color
+	 * with 80% of the color.
+	 */
+	color->red = (0.2 * (1 - background.red)) + (0.8 * red);
+	color->green = (0.2 * (1 - background.green)) + (0.8 * green);
+	color->blue = (0.2 * (1 - background.blue)) + (0.8 * blue);
+	color->alpha = 1.0;
 }
 
 static PurpleBlistNode *
@@ -3310,7 +3331,7 @@
 	const gchar *name, *alias;
 	gchar *tmp, *alias_key;
 	PurpleChatUserFlags flags;
-	GdkRGBA *color = NULL;
+	GdkRGBA color;
 
 	alias = purple_chat_user_get_alias(cb);
 	name  = purple_chat_user_get_name(cb);
@@ -3352,7 +3373,8 @@
 			g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_NORMAL, NULL);
 		if ((tag = get_buddy_tag(chat, name, PURPLE_MESSAGE_NICK, FALSE)))
 			g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_NORMAL, NULL);
-		color = (GdkRGBA*)get_nick_color(gtkconv, name);
+
+		get_nick_color(name, &color);
 	}
 
 	gtk_list_store_insert_with_values(ls, &iter,
@@ -3369,7 +3391,7 @@
 			CHAT_USERS_ALIAS_KEY_COLUMN, alias_key,
 			CHAT_USERS_NAME_COLUMN,  name,
 			CHAT_USERS_FLAGS_COLUMN, flags,
-			CHAT_USERS_COLOR_COLUMN, color,
+			CHAT_USERS_COLOR_COLUMN, &color,
 			CHAT_USERS_WEIGHT_COLUMN, is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
 			-1);
 
@@ -3379,10 +3401,6 @@
 	                       (GDestroyNotify)gtk_tree_row_reference_free);
 	gtk_tree_path_free(newpath);
 
-#if 0
-	if (is_me && color)
-		gdk_rgba_free(color);
-#endif
 	g_free(alias_key);
 }
 
@@ -4156,19 +4174,6 @@
 		pidgin_conv_window_add_gtkconv(hidden_convwin, gtkconv);
 	else
 		pidgin_conv_placement_place(gtkconv);
-
-	if (generated_nick_colors == NULL) {
-		GdkColor color;
-		GdkRGBA rgba;
-		color = gtk_widget_get_style(gtkconv->history)->base[GTK_STATE_NORMAL];
-		rgba.red = color.red / 65535.0;
-		rgba.green = color.green / 65535.0;
-		rgba.blue = color.blue / 65535.0;
-		rgba.alpha = 1.0;
-		generated_nick_colors = generate_nick_colors(NICK_COLOR_GENERATE_COUNT, rgba);
-	}
-
-	gtkconv->nick_colors = g_array_ref(generated_nick_colors);
 }
 
 static void
@@ -4275,8 +4280,6 @@
 		g_source_remove(gtkconv->attach_timer);
 	}
 
-	g_array_unref(gtkconv->nick_colors);
-
 	g_free(gtkconv);
 }
 
@@ -7793,51 +7796,6 @@
 	return (gtkconv->win == hidden_convwin);
 }
 
-
-gdouble luminance(GdkRGBA color)
-{
-	gdouble r, g, b;
-	gdouble rr, gg, bb;
-	gdouble cutoff = 0.03928, scale = 12.92;
-	gdouble a = 0.055, d = 1.055, p = 2.2;
-
-	rr = color.red;
-	gg = color.green;
-	bb = color.blue;
-
-	r = (rr  > cutoff) ? pow((rr+a)/d, p) : rr/scale;
-	g = (gg  > cutoff) ? pow((gg+a)/d, p) : gg/scale;
-	b = (bb  > cutoff) ? pow((bb+a)/d, p) : bb/scale;
-
-	return (r*0.2126 + g*0.7152 + b*0.0722);
-}
-
-/* Algorithm from https://www.w3.org/TR/2008/REC-WCAG20-20081211/relative-luminance.xml */
-static gboolean
-color_is_visible(GdkRGBA foreground, GdkRGBA background, gdouble min_contrast_ratio)
-{
-	gdouble lfg, lbg, lmin, lmax;
-	gdouble luminosity_ratio;
-	gdouble nr, dr;
-
-	lfg = luminance(foreground); 
-	lbg = luminance(background);
-
-	if (lfg > lbg)
-		lmax = lfg, lmin = lbg;
-	else
-		lmax = lbg, lmin = lfg;
-
-	nr = lmax + 0.05, dr = lmin - 0.05;
-	if (dr < 0.005 && dr > -0.005)
-		dr += 0.01;
-
-	luminosity_ratio = nr/dr;
-	if ( luminosity_ratio < 0) 
-		luminosity_ratio *= -1.0;
-	return (luminosity_ratio > min_contrast_ratio);
-}
-
 void
 pidgin_conv_placement_place(PidginConversation *conv) {
        PidginConvWindow *win;
@@ -7857,71 +7815,3 @@
                pidgin_conv_window_add_gtkconv(win, conv);
        }
 }
-
-static GArray*
-generate_nick_colors(guint numcolors, GdkRGBA background)
-{
-	guint i = 0, j = 0;
-	GArray *colors = g_array_new(FALSE, FALSE, sizeof(GdkRGBA));
-	GdkRGBA nick_highlight;
-	GdkRGBA send_color;
-	time_t breakout_time;
-
-	gdk_rgba_parse(&nick_highlight, DEFAULT_HIGHLIGHT_COLOR);
-	gdk_rgba_parse(&send_color, DEFAULT_SEND_COLOR);
-
-	pidgin_style_context_adjust_contrast(NULL, &nick_highlight);
-	pidgin_style_context_adjust_contrast(NULL, &send_color);
-
-	srand(background.red * 65535 + background.green * 65535 + background.blue * 65535 + 1);
-
-	breakout_time = time(NULL) + 3;
-
-	/* first we look through the list of "good" colors: colors that differ from every other color in the
-	 * list.  only some of them will differ from the background color though. lets see if we can find
-	 * numcolors of them that do
-	 */
-	while (i < numcolors && j < PIDGIN_NUM_NICK_SEED_COLORS && time(NULL) < breakout_time)
-	{
-		GdkRGBA color = nick_seed_colors[j];
-
-		if (color_is_visible(color, background,     MIN_LUMINANCE_CONTRAST_RATIO) &&
-			color_is_visible(color, nick_highlight, MIN_LUMINANCE_CONTRAST_RATIO) &&
-			color_is_visible(color, send_color,     MIN_LUMINANCE_CONTRAST_RATIO))
-		{
-			g_array_append_val(colors, color);
-			i++;
-		}
-		j++;
-	}
-
-	/* we might not have found numcolors in the last loop.  if we did, we'll never enter this one.
-	 * if we did not, lets just find some colors that don't conflict with the background.  its
-	 * expensive to find colors that not only don't conflict with the background, but also do not
-	 * conflict with each other.
-	 */
-	while(i < numcolors && time(NULL) < breakout_time)
-	{
-		GdkRGBA color = {g_random_double_range(0, 1), g_random_double_range(0, 1), g_random_double_range(0, 1), 1};
-
-		if (color_is_visible(color, background,     MIN_LUMINANCE_CONTRAST_RATIO) &&
-			color_is_visible(color, nick_highlight, MIN_LUMINANCE_CONTRAST_RATIO) &&
-			color_is_visible(color, send_color,     MIN_LUMINANCE_CONTRAST_RATIO))
-		{
-			g_array_append_val(colors, color);
-			i++;
-		}
-	}
-
-	if (i < numcolors) {
-		purple_debug_warning("gtkconv", "Unable to generate enough random colors before timeout. %u colors found.\n", i);
-	}
-
-	if( i == 0 ) {
-		/* To remove errors caused by an empty array. */
-		GdkRGBA color = {0.5, 0.5, 0.5, 1.0};
-		g_array_append_val(colors, color);
-	}
-
-	return colors;
-}
diff --git a/pidgin/gtknickcolors.h b/pidgin/gtknickcolors.h
deleted file mode 100644
--- a/pidgin/gtknickcolors.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* 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
- */
-
-#if !defined(PIDGIN_GLOBAL_HEADER_INSIDE) && !defined(PIDGIN_COMPILATION)
-# error "only <pidgin.h> may be included directly"
-#endif
-
-#ifndef _PIDGINNICKCOLORS_H_
-#define _PIDGINNICKCOLORS_H_
-/**
- * SECTION:gtknickcolors
- * @section_id: pidgin-gtknickcolors
- * @short_description: <filename>gtknickcolors.h</filename>
- * @title: Conversation Nick Colors
- */
-
-static const GdkRGBA nick_seed_colors[] = {
-	{64764/65535.0, 59881/65535.0, 20303/65535.0, 1},   /* Butter #1 */
-	{60909/65535.0, 54484/65535.0,     0/65535.0, 1},   /* Butter #2 */
-	{50372/65535.0, 41120/65535.0,     0/65535.0, 1},   /* Butter #3 */
-	{64764/65535.0, 44975/65535.0, 15934/65535.0, 1},   /* Orange #1 */
-	{62965/65535.0, 31097/65535.0,     0/65535.0, 1},   /* Orange #2 */
-	{52942/65535.0, 23644/65535.0,     0/65535.0, 1},   /* Orange #3 */
-	{59811/65535.0, 47545/65535.0, 28270/65535.0, 1},   /* Chocolate #1 */
-	{49601/65535.0, 32125/65535.0,  4369/65535.0, 1},   /* Chocolate #2 */
-	{36751/65535.0, 22873/65535.0,   514/65535.0, 1},   /* Chocolate #3 */
-	{35466/65535.0, 58082/65535.0, 13364/65535.0, 1},   /* Chameleon #1 */
-	{29555/65535.0, 53970/65535.0,  5654/65535.0, 1},   /* Chameleon #2 */
-	{20046/65535.0, 39578/65535.0,  1542/65535.0, 1},   /* Chameleon #3 */
-	{29289/65535.0, 40863/65535.0, 53199/65535.0, 1},   /* Sky Blue #1 */
-	{13364/65535.0, 25957/65535.0, 42148/65535.0, 1},   /* Sky Blue #2 */
-	{ 8224/65535.0, 19018/65535.0, 34695/65535.0, 1},   /* Sky Blue #3 */
-	{44461/65535.0, 32639/65535.0, 43167/65535.0, 1},   /* Plum #1 */
-	{30069/65535.0, 20560/65535.0, 31611/65535.0, 1},   /* Plum #2 */
-	{23644/65535.0, 13621/65535.0, 26214/65535.0, 1},   /* Plum #3 */
-	{61423/65535.0, 10537/65535.0, 10537/65535.0, 1},   /* Scarlet Red #1 */
-	{52428/65535.0,     0/65535.0,     0/65535.0, 1},   /* Scarlet Red #2 */
-	{42148/65535.0,     0/65535.0,     0/65535.0, 1},   /* Scarlet Red #3 */
-	{34952/65535.0, 35466/65535.0, 34181/65535.0, 1},   /* Aluminium #4*/
-	{21845/65535.0, 22359/65535.0, 21331/65535.0, 1},   /* Aluminium #5*/
-	{11822/65535.0, 13364/65535.0, 13878/65535.0, 1}    /* Aluminium #6*/
-};
-
-#define PIDGIN_NUM_NICK_SEED_COLORS (sizeof(nick_seed_colors) / sizeof(nick_seed_colors[0]))
-
-#endif
diff --git a/pidgin/meson.build b/pidgin/meson.build
--- a/pidgin/meson.build
+++ b/pidgin/meson.build
@@ -80,7 +80,6 @@
 	'gtkicon-theme-loader.h',
 	'gtkidle.h',
 	'gtkmedia.h',
-	'gtknickcolors.h',
 	'gtknotify.h',
 	'gtkpluginpref.h',
 	'gtkprefs.h',
diff --git a/pidgin/pidginstylecontext.h b/pidgin/pidginstylecontext.h
--- a/pidgin/pidginstylecontext.h
+++ b/pidgin/pidginstylecontext.h
@@ -41,27 +41,27 @@
 G_BEGIN_DECLS
 
 /**
+ * pidgin_style_context_get_background_color:
+ * @color: (out): A return address of a #GdkRGBA for the background color.
+ *
+ * Get's the background color for #GtkWindow in the currently selected theme
+ * and sets @color to that value.
+ *
+ * Since: 3.0.0
+ */
+void pidgin_style_context_get_background_color(GdkRGBA *color);
+
+/**
  * pidgin_style_context_is_dark:
- * @context: The #GtkStyleContext to use, or %NULL to use a cached version.
  *
  * Gets whether or not dark mode is enabled.
  *
  * Returns: %TRUE if dark mode is enabled and foreground colours should be
  *          inverted.
+ *
+ * Since: 3.0.0
  */
-
-gboolean pidgin_style_context_is_dark(GtkStyleContext *context);
-
-/**
- * pidgin_style_context_adjust_contrast:
- * @context: The #GtkStyleContext in use.
- * @color: (inout): Color to be lightened. Transformed color will be written
- *         here.
- *
- * Lighten a color if dark mode is enabled.
- */
-
-void pidgin_style_context_adjust_contrast(GtkStyleContext *context, GdkRGBA *color);
+gboolean pidgin_style_context_is_dark(void);
 
 G_END_DECLS
 
diff --git a/pidgin/pidginstylecontext.c b/pidgin/pidginstylecontext.c
--- a/pidgin/pidginstylecontext.c
+++ b/pidgin/pidginstylecontext.c
@@ -29,48 +29,53 @@
 /******************************************************************************
  * Public API
  *****************************************************************************/
+void
+pidgin_style_context_get_background_color(GdkRGBA *color) {
+	/* This value will leak, we could put a shutdown function in but right now
+	 * that seems like a bit much for a few bytes.
+	 */
+	static GdkRGBA *background = NULL;
+
+	if(g_once_init_enter(&background)) {
+		GdkRGBA *bg = NULL;
+		GtkStyleContext *context = NULL;
+		GtkWidget *window = NULL;
+
+		/* We create a window to get its background color from its style
+		 * context.  This _is_ doable without creating a window, but you still
+		 * need the window class and about four times as much code, so that's
+		 * why we do it this way.
+		 */
+		window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+		context = gtk_widget_get_style_context(window);
+
+		gtk_style_context_get(context, GTK_STATE_FLAG_NORMAL,
+		                      GTK_STYLE_PROPERTY_BACKGROUND_COLOR, &bg,
+		                      NULL);
+		g_object_unref(G_OBJECT(window));
+
+		g_once_init_leave(&background, bg);
+	}
+
+	*color = *background;
+}
+
 gboolean
-pidgin_style_context_is_dark(GtkStyleContext *context) {
+pidgin_style_context_is_dark(void) {
 	GdkRGBA bg;
 	gdouble luminance = 0.0;
 
-	if(context == NULL) {
-		if(dark_mode_have_cache) {
-			return dark_mode_cached_value;
-		}
-
-		context = gtk_style_context_new();
-	} else {
-		g_object_ref(G_OBJECT(context));
+	if(dark_mode_have_cache) {
+		return dark_mode_cached_value;
 	}
 
-	gtk_style_context_get(context, GTK_STATE_FLAG_NORMAL,
-	                      GTK_STYLE_PROPERTY_BACKGROUND_COLOR, &bg,
-	                      NULL);
-	g_object_unref(G_OBJECT(context));
+	pidgin_style_context_get_background_color(&bg);
 
-	/* magic values are taken from https://en.wikipedia.org/wiki/Luma_(video)
-	 * Rec._601_luma_versus_Rec._709_luma_coefficients.
-	 */
-	luminance = (0.299 * bg.red) + (0.587 * bg.green) + (0.114 * bg.blue);
+	/* 709 coefficients from https://en.wikipedia.org/wiki/Luma_(video) */
+	luminance = (0.2126 * bg.red) + (0.7152 * bg.green) + (0.0722 * bg.blue);
 
-	dark_mode_cached_value = (luminance < 0x7FFF);
+	dark_mode_cached_value = (luminance < 0.5);
 	dark_mode_have_cache = TRUE;
 
 	return dark_mode_cached_value;
 }
-
-void
-pidgin_style_context_adjust_contrast(GtkStyleContext *context, GdkRGBA *rgba) {
-	if(pidgin_style_context_is_dark(context)) {
-		gdouble h, s, v;
-
-		gtk_rgb_to_hsv(rgba->red, rgba->green, rgba->blue, &h, &s, &v);
-
-		v += 0.3;
-		v = v > 1.0 ? 1.0 : v;
-		s = 0.7;
-
-		gtk_hsv_to_rgb(h, s, v, &rgba->red, &rgba->green, &rgba->blue);
-	}
-}
