diff -Naur sushi-3.18.0/configure.ac sushi-3.18.0-gst3/configure.ac
--- sushi-3.18.0/configure.ac	2015-09-23 01:04:59.000000000 +0200
+++ sushi-3.18.0-gst3/configure.ac	2016-01-20 04:31:56.590327121 +0100
@@ -62,7 +62,7 @@
                   clutter-x11-1.0 >= $CLUTTER_MIN_VERSION
                   gtk+-3.0 >= $GTK_MIN_VERSION
                   clutter-gtk-1.0 >= $CLUTTER_GTK_MIN_VERSION
-                  clutter-gst-2.0
+                  clutter-gst-3.0
                   gstreamer-1.0
                   gstreamer-pbutils-1.0
                   gstreamer-tag-1.0
diff -Naur sushi-3.18.0/src/js/viewers/audio.js sushi-3.18.0-gst3/src/js/viewers/audio.js
--- sushi-3.18.0/src/js/viewers/audio.js	2015-07-22 21:26:54.000000000 +0200
+++ sushi-3.18.0-gst3/src/js/viewers/audio.js	2016-01-20 04:32:12.657744887 +0100
@@ -23,6 +23,7 @@
  *
  */
 
+const GdkPixbuf = imports.gi.GdkPixbuf;
 const Gio = imports.gi.Gio;
 const Gst = imports.gi.Gst;
 const Gtk = imports.gi.Gtk;
@@ -254,7 +255,8 @@
     },
 
     createToolbar : function () {
-        this._mainToolbar = new Gtk.Toolbar();
+        this._mainToolbar = new Gtk.Toolbar({ margin_start: Constants.TOOLBAR_SPACING,
+                                              margin_end: Constants.TOOLBAR_SPACING });
         this._mainToolbar.get_style_context().add_class('osd');
         this._mainToolbar.set_icon_size(Gtk.IconSize.MENU);
         this._mainToolbar.show();
diff -Naur sushi-3.18.0/src/js/viewers/gst.js sushi-3.18.0-gst3/src/js/viewers/gst.js
--- sushi-3.18.0/src/js/viewers/gst.js	2015-07-22 21:26:54.000000000 +0200
+++ sushi-3.18.0-gst3/src/js/viewers/gst.js	2016-01-20 04:31:56.590327121 +0100
@@ -23,7 +23,7 @@
  *
  */
 
-imports.gi.versions.ClutterGst = '2.0';
+imports.gi.versions.ClutterGst = '3.0';
 const ClutterGst = imports.gi.ClutterGst;
 const Clutter = imports.gi.Clutter;
 const Gdk = imports.gi.Gdk;
@@ -60,29 +60,33 @@
     },
 
     clear : function() {
-        this._video.playing = false;
+        this._player.playing = false;
     },
 
     _createVideo : function(file) {
-        this._video =
-            new ClutterGst.VideoTexture({ sync_size: false });
+        this._player = new ClutterGst.Playback();
+        this._video = new Clutter.Actor({
+            content: new ClutterGst.Aspectratio({
+                player: this._player
+            })
+        });
 
-        this._video.set_uri(file.get_uri());
-        this._video.playing = true;
+        this._player.set_uri(file.get_uri());
+        this._player.playing = true;
 
         this._videoSizeChangeId =
-            this._video.connect('size-change',
-                                Lang.bind(this,
-                                          this._onVideoSizeChange));
-        this._video.connect('notify::playing',
-                            Lang.bind(this,
-                                      this._onVideoPlayingChange));
-        this._video.connect('notify::progress',
-                            Lang.bind(this,
-                                      this._onVideoProgressChange));
-        this._video.connect('notify::duration',
-                            Lang.bind(this,
-                                      this._onVideoDurationChange));
+            this._player.connect('size-change',
+                                 Lang.bind(this,
+                                           this._onVideoSizeChange));
+        this._player.connect('notify::playing',
+                             Lang.bind(this,
+                                       this._onVideoPlayingChange));
+        this._player.connect('notify::progress',
+                             Lang.bind(this,
+                                       this._onVideoProgressChange));
+        this._player.connect('notify::duration',
+                             Lang.bind(this,
+                                       this._onVideoDurationChange));
     },
 
     _updateProgressBar : function() {
@@ -90,7 +94,7 @@
             return;
 
         this._isSettingValue = true;
-        this._progressBar.set_value(this._video.progress * 1000);
+        this._progressBar.set_value(this._player.progress * 1000);
         this._isSettingValue = false;
     },
 
@@ -99,7 +103,7 @@
             return;
 
         let currentTime =
-            Math.floor(this._video.duration * this._video.progress);
+            Math.floor(this._player.duration * this._player.progress);
 
         this._currentLabel.set_text(Utils.formatTimeString(currentTime));
     },
@@ -108,7 +112,7 @@
         if (!this._mainToolbar)
             return;
 
-        let totalTime = this._video.duration;
+        let totalTime = this._player.duration;
 
         this._durationLabel.set_text(Utils.formatTimeString(totalTime));
     },
@@ -123,7 +127,7 @@
     },
 
     _onVideoPlayingChange : function() {
-        if (this._video.playing)
+        if (this._player.playing)
             this._toolbarPlay.set_icon_name('media-playback-pause-symbolic');
         else
         {
@@ -166,8 +170,8 @@
 
         this._toolbarPlay.connect('clicked',
                                   Lang.bind(this, function () {
-                                      let playing = !this._video.playing;
-                                      this._video.playing = playing;
+                                      let playing = !this._player.playing;
+                                      this._player.playing = playing;
                                   }));
 
         this._progressBar =
@@ -178,7 +182,7 @@
         this._progressBar.connect('value-changed',
                                   Lang.bind(this, function() {
                                       if(!this._isSettingValue)
-                                          this._video.progress = this._progressBar.get_value() / 1000;
+                                          this._player.progress = this._progressBar.get_value() / 1000;
                                   }));
 
         item = new Gtk.ToolItem();
@@ -200,7 +204,7 @@
         return this._toolbarActor;
     },
 
-    _onVideoSizeChange : function(video, width, height) {
+    _onVideoSizeChange : function(player, width, height) {
         this._videoWidth = width;
         this._videoHeight = height;
 
diff -Naur sushi-3.18.0/src/libsushi/sushi-cover-art.c sushi-3.18.0-gst3/src/libsushi/sushi-cover-art.c
--- sushi-3.18.0/src/libsushi/sushi-cover-art.c	2014-11-20 18:17:19.000000000 +0100
+++ sushi-3.18.0-gst3/src/libsushi/sushi-cover-art.c	2016-01-20 04:32:06.798592077 +0100
@@ -155,61 +155,41 @@
 }
 
 typedef struct {
-  SushiCoverArtFetcher *self;
-  GSimpleAsyncResult *result;
   gchar *artist;
   gchar *album;
-} FetchUriJob;
+} FetchUriTaskData;
 
 static void
-fetch_uri_job_free (gpointer user_data)
+fetch_uri_task_data_free (gpointer user_data)
 {
-  FetchUriJob *data = user_data;
+  FetchUriTaskData *data = user_data;
 
-  g_clear_object (&data->self);
-  g_clear_object (&data->result);
   g_free (data->artist);
   g_free (data->album);
 
-  g_slice_free (FetchUriJob, data);
+  g_slice_free (FetchUriTaskData, data);
 }
 
-static FetchUriJob *
-fetch_uri_job_new (SushiCoverArtFetcher *self,
-                   const gchar *artist,
-                   const gchar *album,
-                   GAsyncReadyCallback callback,
-                   gpointer user_data)
+static FetchUriTaskData *
+fetch_uri_task_data_new (const gchar *artist,
+                         const gchar *album)
 {
-  FetchUriJob *retval;
+  FetchUriTaskData *retval;
 
-  retval = g_slice_new0 (FetchUriJob);
+  retval = g_slice_new0 (FetchUriTaskData);
   retval->artist = g_strdup (artist);
   retval->album = g_strdup (album);
-  retval->self = g_object_ref (self);
-  retval->result = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
-                                              sushi_cover_art_fetcher_get_uri_for_track_async);
 
   return retval;
 }
 
-static gboolean
-fetch_uri_job_callback (gpointer user_data)
-{
-  FetchUriJob *job = user_data;
-
-  g_simple_async_result_complete (job->result);
-  fetch_uri_job_free (job);
-
-  return FALSE;
-}
-
-static gboolean
-fetch_uri_job (GIOSchedulerJob *sched_job,
-               GCancellable *cancellable,
-               gpointer user_data)
+static void
+fetch_uri_job (GTask *task,
+               gpointer source_object,
+               gpointer task_data,
+               GCancellable *cancellable)
 {
-  FetchUriJob *job = user_data;
+  FetchUriTaskData *data = task_data;
   Mb5Metadata metadata;
   Mb5Query query;
   Mb5Release release;
@@ -224,7 +204,7 @@
   param_values = g_new (gchar*, 3);
 
   param_names[0] = g_strdup ("query");
-  param_values[0] = g_strdup_printf ("artist:\"%s\" AND release:\"%s\"", job->artist, job->album);
+  param_values[0] = g_strdup_printf ("artist:\"%s\" AND release:\"%s\"", data->artist, data->album);
 
   param_names[1] = g_strdup ("limit");
   param_values[1] = g_strdup ("10");
@@ -258,21 +238,16 @@
 
   if (retval == NULL) {
     /* FIXME: do we need a better error? */
-    g_simple_async_result_set_error (job->result,
-                                     G_IO_ERROR,
-                                     0, "%s",
-                                     "Error getting the ASIN from MusicBrainz");
+    g_task_return_new_error (task,
+                             G_IO_ERROR,
+                             0, "%s",
+                             "Error getting the ASIN from MusicBrainz");
   } else {
-    g_simple_async_result_set_op_res_gpointer (job->result,
-                                               retval, NULL);
+    g_task_return_pointer (task, retval, g_free);
   }
 
-  g_io_scheduler_job_send_to_mainloop_async (sched_job,
-                                             fetch_uri_job_callback,
-                                             job, NULL);
   g_strfreev (param_names);
   g_strfreev (param_values);
-  return FALSE;
 }
 
 static gchar *
@@ -280,15 +255,7 @@
                                                   GAsyncResult *result,
                                                   GError **error)
 {
-  gchar *retval;
-
-  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
-                                             error))
-    return NULL;
-
-  retval = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
-
-  return retval;
+  return g_task_propagate_pointer (G_TASK (result), error);
 }
 
 static void
@@ -298,12 +265,12 @@
                                                  GAsyncReadyCallback callback,
                                                  gpointer user_data)
 {
-  FetchUriJob *job;
+  FetchUriTaskData *data = fetch_uri_task_data_new (artist, album);
+  GTask *task = g_task_new (G_OBJECT (self), NULL, callback, user_data);
+  g_task_set_task_data (task, data, fetch_uri_task_data_free);
 
-  job = fetch_uri_job_new (self, artist, album, callback, user_data);
-  g_io_scheduler_push_job (fetch_uri_job,
-                           job, NULL,
-                           G_PRIORITY_DEFAULT, NULL);
+  g_task_run_in_thread (task, fetch_uri_job);
+  g_object_unref (task);
 }
 
 static GFile *
diff -Naur sushi-3.18.0/src/libsushi/sushi-file-loader.c sushi-3.18.0-gst3/src/libsushi/sushi-file-loader.c
--- sushi-3.18.0/src/libsushi/sushi-file-loader.c	2014-11-20 18:17:19.000000000 +0100
+++ sushi-3.18.0-gst3/src/libsushi/sushi-file-loader.c	2016-01-20 04:32:09.724668363 +0100
@@ -590,7 +590,7 @@
     return NULL;
 
   retval = gtk_icon_info_load_icon (info, &error);
-  gtk_icon_info_free (info);
+  g_object_unref (info);
 
   if (error != NULL) {
     gchar *uri;
diff -Naur sushi-3.18.0/src/libsushi/sushi-font-widget.c sushi-3.18.0-gst3/src/libsushi/sushi-font-widget.c
--- sushi-3.18.0/src/libsushi/sushi-font-widget.c	2015-07-22 21:26:54.000000000 +0200
+++ sushi-3.18.0-gst3/src/libsushi/sushi-font-widget.c	2016-01-20 04:32:23.257021423 +0100
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2014 Khaled Hosny <khaledhosny@eglug.org>.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -26,6 +27,7 @@
 #include "sushi-font-widget.h"
 #include "sushi-font-loader.h"
 
+#include <hb-glib.h>
 #include <math.h>
 
 enum {
@@ -68,6 +70,112 @@
 static const gchar uppercase_text_stock[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 static const gchar punctuation_text_stock[] = "0123456789.:,;(*!?')";
 
+static void
+text_to_glyphs (cairo_t *cr,
+                const gchar *text,
+                cairo_glyph_t **glyphs,
+                int *num_glyphs)
+{
+  PangoAttribute *fallback_attr;
+  PangoAttrList *attr_list;
+  PangoContext *context;
+  PangoDirection base_dir;
+  GList *items;
+  GList *visual_items;
+  FT_Face ft_face;
+  hb_font_t *hb_font;
+  gdouble x = 0, y = 0;
+  gint i;
+  gdouble x_scale, y_scale;
+
+  *num_glyphs = 0;
+  *glyphs = NULL;
+
+  base_dir = pango_find_base_dir (text, -1);
+
+  cairo_scaled_font_t *cr_font = cairo_get_scaled_font (cr);
+  ft_face = cairo_ft_scaled_font_lock_face (cr_font);
+  hb_font = hb_ft_font_create (ft_face, NULL);
+
+  cairo_surface_t *target = cairo_get_target (cr);
+  cairo_surface_get_device_scale (target, &x_scale, &y_scale);
+
+  /* We abuse pango itemazation to split text into script and direction
+   * runs, since we use our fonts directly no through pango, we don't
+   * bother changing the default font, but we disable font fallback as
+   * pango will split runs at font change */
+  context = pango_cairo_create_context (cr);
+  attr_list = pango_attr_list_new ();
+  fallback_attr = pango_attr_fallback_new (FALSE);
+  pango_attr_list_insert (attr_list, fallback_attr);
+  items = pango_itemize_with_base_dir (context, base_dir,
+                                       text, 0, strlen (text),
+                                       attr_list, NULL);
+  g_object_unref (context);
+  pango_attr_list_unref (attr_list);
+
+  /* reorder the items in the visual order */
+  visual_items = pango_reorder_items (items);
+
+  while (visual_items) {
+    PangoItem *item;
+    PangoAnalysis analysis;
+    hb_buffer_t *hb_buffer;
+    hb_glyph_info_t *hb_glyphs;
+    hb_glyph_position_t *hb_positions;
+    gint n;
+
+    item = visual_items->data;
+    analysis = item->analysis;
+
+    hb_buffer = hb_buffer_create ();
+    hb_buffer_add_utf8 (hb_buffer, text, -1, item->offset, item->length);
+    hb_buffer_set_script (hb_buffer, hb_glib_script_to_script (analysis.script));
+    hb_buffer_set_language (hb_buffer, hb_language_from_string (pango_language_to_string (analysis.language), -1));
+    hb_buffer_set_direction (hb_buffer, analysis.level % 2 ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
+
+    hb_shape (hb_font, hb_buffer, NULL, 0);
+
+    n = hb_buffer_get_length (hb_buffer);
+    hb_glyphs = hb_buffer_get_glyph_infos (hb_buffer, NULL);
+    hb_positions = hb_buffer_get_glyph_positions (hb_buffer, NULL);
+
+    *glyphs = g_renew (cairo_glyph_t, *glyphs, *num_glyphs + n);
+
+    for (i = 0; i < n; i++) {
+      (*glyphs)[*num_glyphs + i].index = hb_glyphs[i].codepoint;
+      (*glyphs)[*num_glyphs + i].x = x + (hb_positions[i].x_offset / (64. * x_scale));
+      (*glyphs)[*num_glyphs + i].y = y - (hb_positions[i].y_offset / (64. * y_scale));
+      x += (hb_positions[i].x_advance / (64. * x_scale));
+      y -= (hb_positions[i].y_advance / (64. * y_scale));
+    }
+
+    *num_glyphs += n;
+
+    hb_buffer_destroy (hb_buffer);
+
+    visual_items = visual_items->next;
+  }
+
+  g_list_free_full (visual_items, (GDestroyNotify) pango_item_free);
+  g_list_free_full (items, (GDestroyNotify) pango_item_free);
+
+  hb_font_destroy (hb_font);
+  cairo_ft_scaled_font_unlock_face (cr_font);
+}
+
+static void
+text_extents (cairo_t *cr,
+              const char *text,
+              cairo_text_extents_t *extents)
+{
+  cairo_glyph_t *glyphs;
+  gint num_glyphs;
+  text_to_glyphs (cr, text, &glyphs, &num_glyphs);
+  cairo_glyph_extents (cr, glyphs, num_glyphs, extents);
+  g_free (glyphs);
+}
+
 /* adapted from gnome-utils:font-viewer/font-view.c
  *
  * Copyright (C) 2002-2003  James Henstridge <james@daa.com.au>
@@ -84,13 +192,18 @@
 {
   cairo_font_extents_t font_extents;
   cairo_text_extents_t extents;
+  cairo_glyph_t *glyphs;
   GtkTextDirection text_dir;
   gint pos_x;
+  gint num_glyphs;
+  gint i;
 
   text_dir = gtk_widget_get_direction (GTK_WIDGET (self));
 
+  text_to_glyphs (cr, text, &glyphs, &num_glyphs);
+
   cairo_font_extents (cr, &font_extents);
-  cairo_text_extents (cr, text, &extents);
+  cairo_glyph_extents (cr, glyphs, num_glyphs, &extents);
 
   if (pos_y != NULL)
     *pos_y += font_extents.ascent + font_extents.descent +
@@ -102,8 +215,15 @@
       extents.x_advance - padding.right;
   }
 
+  for (i = 0; i < num_glyphs; i++) {
+    glyphs[i].x += pos_x;
+    glyphs[i].y += *pos_y;
+  }
+
   cairo_move_to (cr, pos_x, *pos_y);
-  cairo_show_text (cr, text);
+  cairo_show_glyphs (cr, glyphs, num_glyphs);
+
+  g_free (glyphs);
 
   *pos_y += LINE_SPACING / 2;
 }
@@ -113,29 +233,20 @@
                          const gchar *text)
 {
   gunichar *string;
-  glong len, idx, map;
-  FT_CharMap charmap;
-  gboolean retval = FALSE;
+  glong len, idx;
+  gboolean retval = TRUE;
 
   string = g_utf8_to_ucs4_fast (text, -1, &len);
 
-  for (map = 0; map < face->num_charmaps; map++) {
-    charmap = face->charmaps[map];
-    FT_Set_Charmap (face, charmap);
-
-    retval = TRUE;
+  FT_Select_Charmap (face, FT_ENCODING_UNICODE);
 
-    for (idx = 0; idx < len; idx++) {
-      gunichar c = string[idx];
+  for (idx = 0; idx < len; idx++) {
+    gunichar c = string[idx];
 
-      if (!FT_Get_Char_Index (face, c)) {
-        retval = FALSE;
-        break;
-      }
-    }
-
-    if (retval)
+    if (!FT_Get_Char_Index (face, c)) {
+      retval = FALSE;
       break;
+    }
   }
 
   g_free (string);
@@ -371,7 +482,7 @@
   if (self->priv->font_name != NULL) {
       cairo_set_font_size (cr, title_size);
       cairo_font_extents (cr, &font_extents);
-      cairo_text_extents (cr, self->priv->font_name, &extents);
+      text_extents (cr, self->priv->font_name, &extents);
       pixmap_height += font_extents.ascent + font_extents.descent +
         extents.y_advance + LINE_SPACING;
       pixmap_width = MAX (pixmap_width, extents.width + padding.left + padding.right);
@@ -382,21 +493,21 @@
   cairo_font_extents (cr, &font_extents);
 
   if (self->priv->lowercase_text != NULL) {
-    cairo_text_extents (cr, self->priv->lowercase_text, &extents);
+    text_extents (cr, self->priv->lowercase_text, &extents);
     pixmap_height += font_extents.ascent + font_extents.descent + 
       extents.y_advance + LINE_SPACING;
     pixmap_width = MAX (pixmap_width, extents.width + padding.left + padding.right);
   }
 
   if (self->priv->uppercase_text != NULL) {
-    cairo_text_extents (cr, self->priv->uppercase_text, &extents);
+    text_extents (cr, self->priv->uppercase_text, &extents);
     pixmap_height += font_extents.ascent + font_extents.descent +
       extents.y_advance + LINE_SPACING;
     pixmap_width = MAX (pixmap_width, extents.width + padding.left + padding.right);
   }
 
   if (self->priv->punctuation_text != NULL) {
-    cairo_text_extents (cr, self->priv->punctuation_text, &extents);
+    text_extents (cr, self->priv->punctuation_text, &extents);
     pixmap_height += font_extents.ascent + font_extents.descent +
       extents.y_advance + LINE_SPACING;
     pixmap_width = MAX (pixmap_width, extents.width + padding.left + padding.right);
@@ -408,7 +519,7 @@
     for (i = 0; i < n_sizes; i++) {
       cairo_set_font_size (cr, sizes[i]);
       cairo_font_extents (cr, &font_extents);
-      cairo_text_extents (cr, self->priv->sample_string, &extents);
+      text_extents (cr, self->priv->sample_string, &extents);
       pixmap_height += font_extents.ascent + font_extents.descent +
         extents.y_advance + LINE_SPACING;
       pixmap_width = MAX (pixmap_width, extents.width + padding.left + padding.right);
@@ -529,7 +640,8 @@
 
   for (i = 0; i < n_sizes; i++) {
     cairo_set_font_size (cr, sizes[i]);
-    draw_string (self, cr, padding, self->priv->sample_string, &pos_y);
+    if (self->priv->sample_string !=  NULL)
+      draw_string (self, cr, padding, self->priv->sample_string, &pos_y);
     if (pos_y > allocated_height)
       break;
   }
diff -Naur sushi-3.18.0/src/libsushi/sushi-font-widget.h sushi-3.18.0-gst3/src/libsushi/sushi-font-widget.h
--- sushi-3.18.0/src/libsushi/sushi-font-widget.h	2014-11-20 18:17:19.000000000 +0100
+++ sushi-3.18.0-gst3/src/libsushi/sushi-font-widget.h	2016-01-20 04:32:15.922830073 +0100
@@ -29,6 +29,7 @@
 #include <glib-object.h>
 #include <gtk/gtk.h>
 #include <cairo/cairo-ft.h>
+#include <hb-ft.h>
 
 G_BEGIN_DECLS
 
diff -Naur sushi-3.18.0/src/libsushi/sushi-utils.c sushi-3.18.0-gst3/src/libsushi/sushi-utils.c
--- sushi-3.18.0/src/libsushi/sushi-utils.c	2015-07-19 19:41:51.000000000 +0200
+++ sushi-3.18.0-gst3/src/libsushi/sushi-utils.c	2016-01-20 04:31:59.474401978 +0100
@@ -25,7 +25,11 @@
 
 #include "sushi-utils.h"
 
+#include <gtk/gtk.h>
+
+#ifdef GDK_WINDOWING_X11
 #include <gdk/gdkx.h>
+#endif
 
 /**
  * sushi_create_foreign_window:
@@ -36,10 +40,12 @@
 GdkWindow *
 sushi_create_foreign_window (guint xid)
 {
-  GdkWindow *retval;
+  GdkWindow *retval = NULL;
 
-  retval = gdk_x11_window_foreign_new_for_display (gdk_display_get_default (),
-                                                   xid);
+#ifdef GDK_WINDOWING_X11
+  if (GDK_IS_X11_DISPLAY (gdk_display_get_default ()))
+    retval = gdk_x11_window_foreign_new_for_display (gdk_display_get_default (), xid);
+#endif
 
   return retval;
 }
