diff --git a/debian/patches/0001-nvidia-settings-Remove-STAMP_C.patch b/debian/patches/0001-nvidia-settings-Remove-STAMP_C.patch
new file mode 100644
index 0000000..52038c5
diff --git a/debian/patches/0002-nvidia-settings-Remove-__DATE__-from-the-man-page.patch b/debian/patches/0002-nvidia-settings-Remove-__DATE__-from-the-man-page.patch
new file mode 100644
index 0000000..eb2d900
diff --git a/debian/upstream/metadata b/debian/upstream/metadata
new file mode 100644
index 0000000..c75dbce
diff --git a/doc/version.mk b/doc/version.mk
index f4a6a7c..54ad7ff 100644
--- a/doc/version.mk
+++ b/doc/version.mk
@@ -1 +1 @@
-NVIDIA_VERSION = 384.111
+NVIDIA_VERSION = 390.87
diff --git a/samples/nv-control-warpblend.c b/samples/nv-control-warpblend.c
index d15c956..abe186f 100644
--- a/samples/nv-control-warpblend.c
+++ b/samples/nv-control-warpblend.c
@@ -70,6 +70,7 @@ int main(int ac, char **av)
     Pixmap blendPixmap;
     vertexDataRec warpData[6];
     int nvDpyId;
+    Bool blendAfterWarp = False;
 
     if (!xDpy) {
         fprintf (stderr, "Could not open X Display %s!\n", XDisplayName(NULL));
@@ -78,12 +79,16 @@ int main(int ac, char **av)
 
     screenId = XDefaultScreen(xDpy);
 
-    if (ac != 2) {
-        fprintf (stderr, "Usage: ./nv-control-warpblend nvDpyId\n");
+    if ((ac != 2) && (ac != 3)) {
+        fprintf (stderr, "Usage: ./nv-control-warpblend nvDpyId [--blend-after-warp]\n");
         fprintf (stderr, "See 'nvidia-settings -q CurrentMetaMode' for currently connected DPYs.\n");
         return 1;
     }
 
+    if (ac == 3) {
+        blendAfterWarp = (strcmp("--blend-after-warp", av[2]) == 0);
+    }
+
     nvDpyId = atoi(av[1]);
 
     // Start with two screen-aligned triangles, and warp them using the sample
@@ -166,7 +171,7 @@ int main(int ac, char **av)
                                screenId,
                                nvDpyId,
                                blendPixmap,
-                               False);
+                               blendAfterWarp);
 
     return 0;
 }
diff --git a/samples/version.mk b/samples/version.mk
index f4a6a7c..54ad7ff 100644
--- a/samples/version.mk
+++ b/samples/version.mk
@@ -1 +1 @@
-NVIDIA_VERSION = 384.111
+NVIDIA_VERSION = 390.87
diff --git a/src/Makefile b/src/Makefile
index 4155799..af7d209 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -219,6 +219,8 @@ XCP_OBJS    = $(call BUILD_OBJECT_LIST,$(XCP_SRC))
 
 GTK2_OBJS    = $(call BUILD_OBJECT_LIST_WITH_DIR,$(GTK_SRC),$(GTK2LIB_DIR))
 GTK3_OBJS    = $(call BUILD_OBJECT_LIST_WITH_DIR,$(GTK_SRC),$(GTK3LIB_DIR))
+IMAGE_OBJS    = $(addprefix $(OUTPUTDIR)/,$(addsuffix .o,$(notdir $(IMAGE_FILES))))
+IMAGE_HEADERS = $(addprefix $(OUTPUTDIR)/,$(addsuffix .h,$(notdir $(IMAGE_FILES))))
 
 CFLAGS     += -I .
 CFLAGS     += -I image_data
@@ -252,6 +254,13 @@ ifneq ($(NV_USE_BUNDLED_LIBJANSSON),0)
   $(call BUILD_OBJECT_LIST,$(JANSSON_SRC)): CFLAGS += $(JANSSON_CFLAGS)
 endif
 
+define BINARY_DATA_HEADER_RULE
+  $$(OUTPUTDIR)/$(notdir $(1)).h:
+	$(at_if_quiet){ \
+	  $$(PRINTF) "extern const char _binary_$(subst .,_,$(notdir $(1)))_start[];\n"; \
+	  $$(PRINTF) "extern const char _binary_$(subst .,_,$(notdir $(1)))_end[];\n"; \
+	} > $$@
+endef
 
 ##############################################################################
 # build rules
@@ -282,21 +291,21 @@ $(NVIDIA_SETTINGS).unstripped: $(OBJS) $(XNVCTRL_ARCHIVE)
 	    -rdynamic -o $@ $(OBJS) $(XNVCTRL_ARCHIVE) $(LIBS)
 
 $(eval $(call DEBUG_INFO_RULES, $(GTK2LIB)))
-$(GTK2LIB).unstripped: $(GTK2_OBJS) $(XCP_OBJS) $(VERSION_MK)
+$(GTK2LIB).unstripped: $(GTK2_OBJS) $(XCP_OBJS) $(IMAGE_OBJS) $(VERSION_MK)
 	$(call quiet_cmd,LINK) -shared $(CFLAGS) $(LDFLAGS) $(BIN_LDFLAGS) \
 	    $(XNVCTRL_ARCHIVE) $(LIBS) $(GTK2_LIBS) \
 	    -Wl,--unresolved-symbols=ignore-all -o $@ \
 	    -Wl,-soname -Wl,$(GTK2LIB_SONAME) \
-	    $(GTK2_OBJS) $(XCP_OBJS)
+	    $(GTK2_OBJS) $(IMAGE_OBJS) $(XCP_OBJS)
 
 ifdef BUILD_GTK3LIB
 $(eval $(call DEBUG_INFO_RULES, $(GTK3LIB)))
-$(GTK3LIB).unstripped: $(GTK3_OBJS) $(XCP_OBJS) $(VERSION_MK)
+$(GTK3LIB).unstripped: $(GTK3_OBJS) $(XCP_OBJS) $(IMAGE_OBJS) $(VERSION_MK)
 	$(call quiet_cmd,LINK) -shared $(CFLAGS) $(LDFLAGS)  $(BIN_LDFLAGS) \
 	    $(XNVCTRL_ARCHIVE) $(LIBS) $(GTK3_LIBS) \
 	    -Wl,--unresolved-symbols=ignore-all -o $@ \
 	    -Wl,-soname -Wl,$(GTK3LIB_SONAME) \
-	    $(GTK3_OBJS) $(XCP_OBJS)
+	    $(GTK3_OBJS) $(XCP_OBJS) $(IMAGE_OBJS)
 endif
 
 # define the rule to build each object file
@@ -315,7 +324,8 @@ build-xnvctrl:
 clean clobber:
 	rm -rf $(NVIDIA_SETTINGS) *~ $(STAMP_C) \
 		$(OUTPUTDIR)/*.o $(OUTPUTDIR)/*.d \
-		$(GTK2LIB) $(GTK3LIB) $(GTK2LIB_DIR) $(GTK3LIB_DIR)
+		$(GTK2LIB) $(GTK3LIB) $(GTK2LIB_DIR) $(GTK3LIB_DIR) \
+		$(IMAGE_HEADERS)
 	@$(MAKE) -C $(XNVCTRL_DIR) -f $(XNVCTRL_MAKEFILE) clean
 
 $(foreach src,$(GTK_SRC), \
@@ -326,3 +336,14 @@ $(foreach src,$(GTK_SRC), \
     $(eval $(call DEFINE_OBJECT_RULE_WITH_DIR,TARGET,$(src),$(GTK3LIB_DIR))))
 endif
 
+# Build $(IMAGE_OBJS)
+$(foreach png,$(IMAGE_FILES), \
+  $(eval $(call READ_ONLY_OBJECT_FROM_FILE_RULE,$(png))))
+
+# Build $(IMAGE_HEADERS)
+$(foreach png,$(IMAGE_FILES), \
+  $(eval $(call BINARY_DATA_HEADER_RULE,$(png))))
+$(GTK2_OBJS): $(IMAGE_HEADERS)
+ifdef BUILD_GTK3LIB
+  $(GTK3_OBJS): $(IMAGE_HEADERS)
+endif
diff --git a/src/gtk+-2.x/ctkbanner.c b/src/gtk+-2.x/ctkbanner.c
index 6b51d61..034783a 100644
--- a/src/gtk+-2.x/ctkbanner.c
+++ b/src/gtk+-2.x/ctkbanner.c
@@ -21,46 +21,45 @@
  */
 
 #include <gtk/gtk.h>
-#include <gdk-pixbuf/gdk-pixdata.h>
 #include <stdio.h>
 
 #include "ctkbanner.h"
 #include "common-utils.h"
 #include "ctkutils.h"
 
-/* pixdata headers */
-
-#include "background_pixdata.h"
-#include "background_tall_pixdata.h"
-#include "logo_pixdata.h"
-#include "logo_tall_pixdata.h"
-
-#include "antialias_pixdata.h"
-#include "bsd_pixdata.h"
-#include "clock_pixdata.h"
-#include "color_pixdata.h"
-#include "config_pixdata.h"
-#include "crt_pixdata.h"
-#include "dfp_pixdata.h"
-#include "display_config_pixdata.h"
-#include "framelock_pixdata.h"
-#include "glx_pixdata.h"
-#include "gpu_pixdata.h"
-#include "help_pixdata.h"
-#include "opengl_pixdata.h"
-#include "penguin_pixdata.h"
-#include "gvi_pixdata.h"
-#include "sdi_pixdata.h"
-#include "sdi_shared_sync_bnc_pixdata.h"
-#include "server_licensing_pixdata.h"
-#include "slimm_pixdata.h"
-#include "solaris_pixdata.h"
-#include "thermal_pixdata.h"
-#include "vcs_pixdata.h"
-#include "vdpau_pixdata.h"
-#include "x_pixdata.h"
-#include "xvideo_pixdata.h"
-#include "svp_3dvp_pixdata.h"
+/* PNG headers */
+
+#include "background.png.h"
+#include "background_tall.png.h"
+#include "logo.png.h"
+#include "logo_tall.png.h"
+
+#include "antialias.png.h"
+#include "bsd.png.h"
+#include "clock.png.h"
+#include "color.png.h"
+#include "config.png.h"
+#include "crt.png.h"
+#include "dfp.png.h"
+#include "display_config.png.h"
+#include "framelock.png.h"
+#include "glx.png.h"
+#include "gpu.png.h"
+#include "help.png.h"
+#include "opengl.png.h"
+#include "penguin.png.h"
+#include "gvi.png.h"
+#include "sdi.png.h"
+#include "sdi_shared_sync_bnc.png.h"
+#include "server_licensing.png.h"
+#include "slimm.png.h"
+#include "solaris.png.h"
+#include "thermal.png.h"
+#include "vcs.png.h"
+#include "vdpau.png.h"
+#include "x.png.h"
+#include "xvideo.png.h"
+#include "svp_3dvp.png.h"
 
 
 static void
@@ -395,49 +394,51 @@ static void ctk_banner_get_preferred_height(
 
 
 /*
- * select_artwork() - given a BannerArtworkType, lookup the pixdata
- * and other related data
+ * select_artwork() - given a BannerArtworkType, lookup the pixbuf and other
+ * related data
  */
 
-static gboolean select_artwork(BannerArtworkType artwork,
-                               gboolean *tall,
-                               int *pad_x,
-                               const GdkPixdata **pixdata)
+static GdkPixbuf* select_artwork(BannerArtworkType artwork,
+                                 gboolean *tall,
+                                 int *pad_x)
 {
     static const struct {
         BannerArtworkType artwork;
         gboolean tall;
         int pad_x;
-        const GdkPixdata *pixdata;
+        const char *png_start;
+        const char *png_end;
     } ArtworkTable[] = {
-        /* artwork                       tall  pad_x pixdata */
-        { BANNER_ARTWORK_ANTIALIAS,      FALSE, 16, &antialias_pixdata      },
-        { BANNER_ARTWORK_BSD,            TRUE,  16, &bsd_pixdata            },
-        { BANNER_ARTWORK_CLOCK,          FALSE, 16, &clock_pixdata          },
-        { BANNER_ARTWORK_COLOR,          FALSE, 16, &color_pixdata          },
-        { BANNER_ARTWORK_CONFIG,         FALSE, 16, &config_pixdata         },
-        { BANNER_ARTWORK_CRT,            FALSE, 16, &crt_pixdata            },
-        { BANNER_ARTWORK_DFP,            FALSE, 16, &dfp_pixdata            },
-        { BANNER_ARTWORK_DISPLAY_CONFIG, FALSE, 16, &display_config_pixdata },
-        { BANNER_ARTWORK_FRAMELOCK,      FALSE, 16, &framelock_pixdata      },
-        { BANNER_ARTWORK_GLX,            FALSE, 16, &glx_pixdata            },
-        { BANNER_ARTWORK_GPU,            FALSE, 16, &gpu_pixdata            },
-        { BANNER_ARTWORK_GVI,            FALSE, 16, &gvi_pixdata            },
-        { BANNER_ARTWORK_HELP,           FALSE, 16, &help_pixdata           },
-        { BANNER_ARTWORK_OPENGL,         FALSE, 16, &opengl_pixdata         },
-        { BANNER_ARTWORK_PENGUIN,        TRUE,  16, &penguin_pixdata        },
-        { BANNER_ARTWORK_SDI,            FALSE, 16, &sdi_pixdata            },
-        { BANNER_ARTWORK_SDI_SHARED_SYNC_BNC, FALSE, 16, &sdi_shared_sync_bnc_pixdata },
-        { BANNER_ARTWORK_SERVER_LICENSING, FALSE, 16, &server_licensing_pixdata },
-        { BANNER_ARTWORK_SLIMM,          FALSE, 16, &slimm_pixdata          },
-        { BANNER_ARTWORK_SOLARIS,        TRUE,  16, &solaris_pixdata        },
-        { BANNER_ARTWORK_THERMAL,        FALSE, 16, &thermal_pixdata        },
-        { BANNER_ARTWORK_VCS,            FALSE, 16, &vcs_pixdata            },
-        { BANNER_ARTWORK_VDPAU,          FALSE, 16, &vdpau_pixdata          },
-        { BANNER_ARTWORK_X,              FALSE, 16, &x_pixdata              },
-        { BANNER_ARTWORK_XVIDEO,         FALSE, 16, &xvideo_pixdata         },
-        { BANNER_ARTWORK_SVP,            FALSE, 16, &svp_3dvp_pixdata       },
-        { BANNER_ARTWORK_INVALID,        FALSE, 16, NULL                    },
+#define PNG(s) _binary_##s##_png_start, _binary_##s##_png_end
+        /* artwork                       tall  pad_x     png_start, png_end       }, */
+        { BANNER_ARTWORK_ANTIALIAS,      FALSE, 16,      PNG(antialias)           },
+        { BANNER_ARTWORK_BSD,            TRUE,  16,      PNG(bsd)                 },
+        { BANNER_ARTWORK_CLOCK,          FALSE, 16,      PNG(clock)               },
+        { BANNER_ARTWORK_COLOR,          FALSE, 16,      PNG(color)               },
+        { BANNER_ARTWORK_CONFIG,         FALSE, 16,      PNG(config)              },
+        { BANNER_ARTWORK_CRT,            FALSE, 16,      PNG(crt)                 },
+        { BANNER_ARTWORK_DFP,            FALSE, 16,      PNG(dfp)                 },
+        { BANNER_ARTWORK_DISPLAY_CONFIG, FALSE, 16,      PNG(display_config)      },
+        { BANNER_ARTWORK_FRAMELOCK,      FALSE, 16,      PNG(framelock)           },
+        { BANNER_ARTWORK_GLX,            FALSE, 16,      PNG(glx)                 },
+        { BANNER_ARTWORK_GPU,            FALSE, 16,      PNG(gpu)                 },
+        { BANNER_ARTWORK_GVI,            FALSE, 16,      PNG(gvi)                 },
+        { BANNER_ARTWORK_HELP,           FALSE, 16,      PNG(help)                },
+        { BANNER_ARTWORK_OPENGL,         FALSE, 16,      PNG(opengl)              },
+        { BANNER_ARTWORK_PENGUIN,        TRUE,  16,      PNG(penguin)             },
+        { BANNER_ARTWORK_SDI,            FALSE, 16,      PNG(sdi)                 },
+        { BANNER_ARTWORK_SDI_SHARED_SYNC_BNC, FALSE, 16, PNG(sdi_shared_sync_bnc) },
+        { BANNER_ARTWORK_SERVER_LICENSING, FALSE, 16,    PNG(server_licensing)    },
+        { BANNER_ARTWORK_SLIMM,          FALSE, 16,      PNG(slimm)               },
+        { BANNER_ARTWORK_SOLARIS,        TRUE,  16,      PNG(solaris)             },
+        { BANNER_ARTWORK_THERMAL,        FALSE, 16,      PNG(thermal)             },
+        { BANNER_ARTWORK_VCS,            FALSE, 16,      PNG(vcs)                 },
+        { BANNER_ARTWORK_VDPAU,          FALSE, 16,      PNG(vdpau)               },
+        { BANNER_ARTWORK_X,              FALSE, 16,      PNG(x)                   },
+        { BANNER_ARTWORK_XVIDEO,         FALSE, 16,      PNG(xvideo)              },
+        { BANNER_ARTWORK_SVP,            FALSE, 16,      PNG(svp_3dvp)            },
+        { BANNER_ARTWORK_INVALID,        FALSE, 16,      NULL, NULL               },
+#undef PNG
     };
 
     int i;
@@ -446,12 +447,13 @@ static gboolean select_artwork(BannerArtworkType artwork,
         if (ArtworkTable[i].artwork == artwork) {
             *tall = ArtworkTable[i].tall;
             *pad_x = ArtworkTable[i].pad_x;
-            *pixdata = ArtworkTable[i].pixdata;
-            return TRUE;
+
+            return ctk_pixbuf_from_data(ArtworkTable[i].png_start,
+                                        ArtworkTable[i].png_end);
         }
     }
-    
-    return FALSE;
+
+    return NULL;
 }
 
 
@@ -465,10 +467,10 @@ GtkWidget* ctk_banner_new(BannerArtworkType artwork)
 {
     GObject *object;
     CtkBanner *ctk_banner;
-    const GdkPixdata *pixdata;
     int tall, pad_x;
+    GdkPixbuf *pixbuf = select_artwork(artwork, &tall, &pad_x);
 
-    if (!select_artwork(artwork, &tall, &pad_x, &pixdata)) {
+    if (!pixbuf) {
         return NULL;
     }
     
@@ -484,31 +486,28 @@ GtkWidget* ctk_banner_new(BannerArtworkType artwork)
     /* load the global images */
 
     if (!Background.pixbuf) {
-        Background.pixbuf =
-            gdk_pixbuf_from_pixdata(&background_pixdata, TRUE, NULL);
+        Background.pixbuf = CTK_LOAD_PIXBUF(background);
         Background.w = gdk_pixbuf_get_width(Background.pixbuf);
         Background.h = gdk_pixbuf_get_height(Background.pixbuf);
     }
     g_object_ref(Background.pixbuf);
 
     if (!TallBackground.pixbuf) {
-        TallBackground.pixbuf =
-            gdk_pixbuf_from_pixdata(&background_tall_pixdata, TRUE, NULL);
+        TallBackground.pixbuf = CTK_LOAD_PIXBUF(background_tall);
         TallBackground.w = gdk_pixbuf_get_width(TallBackground.pixbuf);
         TallBackground.h = gdk_pixbuf_get_height(TallBackground.pixbuf);
     }
     g_object_ref(TallBackground.pixbuf);
     
     if (!Logo.pixbuf) {
-        Logo.pixbuf = gdk_pixbuf_from_pixdata(&logo_pixdata, TRUE, NULL);
+        Logo.pixbuf = CTK_LOAD_PIXBUF(logo);
         Logo.w = gdk_pixbuf_get_width(Logo.pixbuf);
         Logo.h = gdk_pixbuf_get_height(Logo.pixbuf);
     }
     g_object_ref(Logo.pixbuf);
     
     if (!TallLogo.pixbuf) {
-        TallLogo.pixbuf =
-            gdk_pixbuf_from_pixdata(&logo_tall_pixdata, TRUE, NULL);
+        TallLogo.pixbuf = CTK_LOAD_PIXBUF(logo_tall);
         TallLogo.w = gdk_pixbuf_get_width(TallLogo.pixbuf);
         TallLogo.h = gdk_pixbuf_get_height(TallLogo.pixbuf);
     }
@@ -533,13 +532,11 @@ GtkWidget* ctk_banner_new(BannerArtworkType artwork)
     
     
     /* load the artwork pixbuf */
-    
-    ctk_banner->artwork.pixbuf = gdk_pixbuf_from_pixdata(pixdata, TRUE, NULL);
-    ctk_banner->artwork.w =
-        gdk_pixbuf_get_width(ctk_banner->artwork.pixbuf);
-    ctk_banner->artwork.h =
-        gdk_pixbuf_get_height(ctk_banner->artwork.pixbuf);
-    
+
+    ctk_banner->artwork.pixbuf = pixbuf;
+    ctk_banner->artwork.w = gdk_pixbuf_get_width(pixbuf);
+    ctk_banner->artwork.h = gdk_pixbuf_get_height(pixbuf);
+
     return GTK_WIDGET(object);
 }
 
diff --git a/src/gtk+-2.x/ctkconfig.c b/src/gtk+-2.x/ctkconfig.c
index d82b37a..e5ca3e4 100644
--- a/src/gtk+-2.x/ctkconfig.c
+++ b/src/gtk+-2.x/ctkconfig.c
@@ -544,6 +544,9 @@ GtkTextBuffer *ctk_config_create_help(CtkConfig *ctk_config, GtkTextTagTable *ta
                   "consecutive polls (in milliseconds).  The Active "
                   "Timers table is only visible when timers are active.");
 
+    ctk_help_heading(b, &i, "Save Current Configuration");
+    ctk_help_para(b, &i, "%s", __save_current_config_help);
+
     ctk_help_finish(b);
 
     return b;
diff --git a/src/gtk+-2.x/ctkdisplayconfig-utils.c b/src/gtk+-2.x/ctkdisplayconfig-utils.c
index 9ba8875..40c9c7c 100644
--- a/src/gtk+-2.x/ctkdisplayconfig-utils.c
+++ b/src/gtk+-2.x/ctkdisplayconfig-utils.c
@@ -587,10 +587,9 @@ Bool mode_set_rotation(nvModePtr mode, Rotation rotation)
 /** apply_mode_attribute_token() *************************************
  *
  * Modifies the nvMode structure (pointed to by data) with
- * information from the token-value pair given.  Currently accepts
- * stereo (mode) data.
+ * information from the token-value pair given.
  *
- * Unknown token and/or values are silently ignored.
+ * Unknown tokens and/or values are silently ignored.
  *
  **/
 static void apply_mode_attribute_token(char *token, char *value, void *data)
@@ -674,6 +673,12 @@ static void apply_mode_attribute_token(char *token, char *value, void *data)
         if (!strcasecmp("on", value)) {
             mode->forceFullCompositionPipeline = True;
         }
+
+    /* AllowGSYNC */
+    } else if (!strcasecmp("allowgsync", token)) {
+        if (!strcasecmp("off", value)) {
+            mode->allowGSYNC = False;
+        }
     }
 
 }
@@ -714,6 +719,7 @@ nvModePtr mode_parse(nvDisplayPtr display, const char *mode_str)
     mode->reflection = REFLECTION_NONE;
     mode->passive_stereo_eye = PASSIVE_STEREO_EYE_NONE;
     mode->position_type = CONF_ADJ_ABSOLUTE;
+    mode->allowGSYNC = True;
 
 
     /* Read the mode name */
@@ -1186,6 +1192,14 @@ static gchar *mode_get_str(nvLayoutPtr layout,
         flags_str = tmp;
     }
 
+    /* AllowGSYNC */
+    if (!mode->allowGSYNC) {
+        tmp = g_strdup_printf("%s, AllowGSYNC=Off",
+                              (flags_str ? flags_str : ""));
+        g_free(flags_str);
+        flags_str = tmp;
+    }
+
     if (flags_str) {
         tmp = g_strdup_printf("%s {%s}",
                               mode_str,
@@ -1637,31 +1651,6 @@ void display_remove_modes(nvDisplayPtr display)
 
 
 
-/*!
- * Sets all the modes on the display to the specified rotation
- *
- * \param[in]  mode      The display who's modes are to be modified
- * \param[in]  rotation  The rotation to set
- *
- * \return  TRUE if a new rotation was set for at least one mode, FALSE if all
- *          of the modes on the display were already set to the rotation given.
- */
-Bool display_set_modes_rotation(nvDisplayPtr display, Rotation rotation)
-{
-    nvModePtr mode;
-    Bool modified = FALSE;
-
-    for (mode = display->modes; mode; mode = mode->next) {
-        if (mode_set_rotation(mode, rotation)) {
-            modified = TRUE;
-        }
-    }
-
-    return modified;
-}
-
-
-
 /** display_free() ***************************************************
  *
  * Frees memory used by a display
diff --git a/src/gtk+-2.x/ctkdisplayconfig-utils.h b/src/gtk+-2.x/ctkdisplayconfig-utils.h
index f59696a..1bc4f31 100644
--- a/src/gtk+-2.x/ctkdisplayconfig-utils.h
+++ b/src/gtk+-2.x/ctkdisplayconfig-utils.h
@@ -82,7 +82,6 @@ Bool display_has_modeline(nvDisplayPtr display, nvModeLinePtr modeline);
 Bool display_add_modelines_from_server(nvDisplayPtr display, nvGpuPtr gpu,
                                        gchar **err_str);
 void display_remove_modes(nvDisplayPtr display);
-Bool display_set_modes_rotation(nvDisplayPtr display, Rotation rotation);
 
 
 /* Metamode functions */
diff --git a/src/gtk+-2.x/ctkdisplayconfig.c b/src/gtk+-2.x/ctkdisplayconfig.c
index 8db3c98..3a9450d 100644
--- a/src/gtk+-2.x/ctkdisplayconfig.c
+++ b/src/gtk+-2.x/ctkdisplayconfig.c
@@ -2541,19 +2541,30 @@ static void setup_mosaic_config(CtkDisplayConfig *ctk_object)
 {
     nvDisplayPtr display = ctk_display_layout_get_selected_display
         (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout));
+    nvScreenPtr screen = ctk_display_layout_get_selected_screen
+        (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout));
     nvGpuPtr gpu;
     const char *tooltip;
     const gchar *label;
+    gboolean display_gpu_support_mosaic = (display && display->gpu &&
+        display->gpu->mosaic_type != MOSAIC_TYPE_UNSUPPORTED);
+    gboolean screen_gpu_support_mosaic = (screen && screen->display_owner_gpu &&
+        screen->display_owner_gpu->mosaic_type != MOSAIC_TYPE_UNSUPPORTED);
 
 
-    if (!display || !display->gpu || !ctk_object->advanced_mode ||
-        display->gpu->mosaic_type == MOSAIC_TYPE_UNSUPPORTED) {
+    if (!ctk_object->advanced_mode ||
+        (!display_gpu_support_mosaic && !screen_gpu_support_mosaic)) {
         gtk_widget_hide(ctk_object->chk_mosaic_enabled);
         return;
     }
+
     gtk_widget_show(ctk_object->chk_mosaic_enabled);
 
-    gpu = display->gpu;
+    if (display_gpu_support_mosaic) {
+        gpu = display->gpu;
+    } else {
+        gpu = screen->display_owner_gpu;
+    }
 
     switch (gpu->mosaic_type) {
     case MOSAIC_TYPE_SLI_MOSAIC:
@@ -6182,6 +6193,8 @@ static void display_refresh_changed(GtkWidget *widget, gpointer user_data)
     gint idx;
     nvModeLinePtr modeline;
     nvDisplayPtr display;
+    Rotation old_rotation;
+    Reflection old_reflection;
 
 
     /* Get the modeline and display to set */
@@ -6190,6 +6203,9 @@ static void display_refresh_changed(GtkWidget *widget, gpointer user_data)
     display = ctk_display_layout_get_selected_display
         (CTK_DISPLAY_LAYOUT(ctk_object->obj_layout));
 
+    /* Save the current rotation and reflection settings */
+    old_rotation = display->cur_mode->rotation;
+    old_reflection = display->cur_mode->reflection;
 
     /* In Basic view, we assume the user most likely wants
      * to change which metamode is being used.
@@ -6214,6 +6230,24 @@ static void display_refresh_changed(GtkWidget *widget, gpointer user_data)
          &display->cur_mode->viewPortIn,
          &display->cur_mode->viewPortOut);
 
+    /* If we are in Basic mode, apply the rotation and reflection settings from
+     * the previous mode to the new mode.
+     */
+    if (!ctk_object->advanced_mode) {
+
+        if (display->cur_mode->rotation != old_rotation) {
+            ctk_display_layout_set_display_rotation(
+                CTK_DISPLAY_LAYOUT(ctk_object->obj_layout),
+                display, old_rotation);
+        }
+
+        if (display->cur_mode->reflection != old_reflection) {
+            ctk_display_layout_set_display_reflection(
+                CTK_DISPLAY_LAYOUT(ctk_object->obj_layout),
+                display, old_reflection);
+        }
+    }
+
     /* Update the modename */
     setup_display_modename(ctk_object);
 
@@ -6236,6 +6270,8 @@ static void display_resolution_changed(GtkWidget *widget, gpointer user_data)
     gint last_idx;
     nvSelectedModePtr selected_mode;
     nvDisplayPtr display;
+    Rotation old_rotation;
+    Reflection old_reflection;
 
 
     /* Get the modeline and display to set */
@@ -6254,6 +6290,9 @@ static void display_resolution_changed(GtkWidget *widget, gpointer user_data)
         return;
     }
 
+    /* Save the current rotation and reflection settings */
+    old_rotation = display->cur_mode->rotation;
+    old_reflection = display->cur_mode->reflection;
 
     /* In Basic view, we assume the user most likely wants
      * to change which metamode is being used.
@@ -6289,6 +6328,24 @@ static void display_resolution_changed(GtkWidget *widget, gpointer user_data)
              NULL /* viewPortOut */);
     }
 
+    /* If we are in Basic mode, apply the rotation and reflection settings from
+     * the previous mode to the new mode.
+     */
+    if (!ctk_object->advanced_mode) {
+
+        if (display->cur_mode->rotation != old_rotation) {
+            ctk_display_layout_set_display_rotation(
+                CTK_DISPLAY_LAYOUT(ctk_object->obj_layout),
+                display, old_rotation);
+        }
+
+        if (display->cur_mode->reflection != old_reflection) {
+            ctk_display_layout_set_display_reflection(
+                CTK_DISPLAY_LAYOUT(ctk_object->obj_layout),
+                display, old_reflection);
+        }
+    }
+
     /* Update the UI */
     setup_display_page(ctk_object);
 
diff --git a/src/gtk+-2.x/ctkdisplaylayout.c b/src/gtk+-2.x/ctkdisplaylayout.c
index 71de178..93a4ddd 100644
--- a/src/gtk+-2.x/ctkdisplaylayout.c
+++ b/src/gtk+-2.x/ctkdisplaylayout.c
@@ -1965,6 +1965,8 @@ static int move_selected(CtkDisplayLayout *ctk_object, int x, int y, int snap)
         sdim = get_screen_rect(info->screen, 1);
 
         /* Prevent moving out of the max layout bounds */
+
+        /* Restrict movement in the positive direction */
         x = MAX_LAYOUT_WIDTH - dim->width;
         if (info->dst_dim.x > x) {
             info->modify_dim.x += x - info->dst_dim.x;
@@ -1975,12 +1977,18 @@ static int move_selected(CtkDisplayLayout *ctk_object, int x, int y, int snap)
             info->modify_dim.y += y - info->dst_dim.y;
             info->dst_dim.y = y;
         }
-        x = layout->dim.width - MAX_LAYOUT_WIDTH;
+
+        /* Restrict movement in the negative direction. As long as the total
+         * distance does not exceed our maximum value, we can recalculate the
+         * layout origin. We should also make sure that the current origin (0,0)
+         * is accessible to the user.
+         */
+        x = NV_MIN(layout->dim.width - MAX_LAYOUT_WIDTH, 0);
         if (info->dst_dim.x < x) {
             info->modify_dim.x += x - info->dst_dim.x;
             info->dst_dim.x = x;
         }
-        y = layout->dim.height - MAX_LAYOUT_HEIGHT;
+        y = NV_MIN(layout->dim.height - MAX_LAYOUT_HEIGHT, 0);
         if (info->dst_dim.y < y) {
             info->modify_dim.y += y - info->dst_dim.y;
             info->dst_dim.y = y;
@@ -4452,9 +4460,7 @@ void ctk_display_layout_set_display_panning(CtkDisplayLayout *ctk_object,
 /*!
  * Sets the rotation orientation for the display.
  *
- * In basic mode, this function will make all modes on the display have the
- * same rotation.  In advanced mode, only the current mode will have its
- * rotation orientation modified.
+ * Only the current mode will have its rotation orientation modified.
  *
  * If a modification occurs, this function will call the modified_callback
  * handler registered, if any.
@@ -4467,23 +4473,13 @@ void ctk_display_layout_set_display_rotation(CtkDisplayLayout *ctk_object,
                                              nvDisplayPtr display,
                                              Rotation rotation)
 {
-    Bool modified;
-
-
     if (!display->cur_mode ||
         !display->cur_mode->modeline) {
         return;
     }
 
-    if (ctk_object->advanced_mode) {
-        /* In advanced mode, only set the rotation of the current mode */
-        modified = mode_set_rotation(display->cur_mode, rotation);
-    } else {
-        /* In basic mode, make all the modes have the same rotation */
-        modified = display_set_modes_rotation(display, rotation);
-    }
+    if (mode_set_rotation(display->cur_mode, rotation)) {
 
-    if (modified) {
         /* Update the layout */
         ctk_display_layout_update(ctk_object);
 
@@ -4500,9 +4496,7 @@ void ctk_display_layout_set_display_rotation(CtkDisplayLayout *ctk_object,
 /*!
  * Sets the reflection orientation for the display.
  *
- * In basic mode, this function will make all modes on the display have the
- * same reflection.  In advanced mode, only the current mode will have its
- * reflection orientation modified.
+ * Only the current mode will have its reflection orientation modified.
  *
  * If a modification occurs, this function will call the modified_callback
  * handler registered, if any.
@@ -4515,33 +4509,15 @@ void ctk_display_layout_set_display_reflection(CtkDisplayLayout *ctk_object,
                                                nvDisplayPtr display,
                                                Reflection reflection)
 {
-    Bool modified = FALSE;
-
-
     if (!display->cur_mode ||
         !display->cur_mode->modeline) {
         return;
     }
 
-    if (ctk_object->advanced_mode) {
-        /* In advanced mode, only set the reflection of the current mode */
-        if (display->cur_mode->reflection != reflection) {
-            modified = TRUE;
-        }
-        display->cur_mode->reflection = reflection;
-    } else {
-        nvModePtr mode;
+    if (display->cur_mode->reflection != reflection) {
 
-        /* In basic mode, make all the modes have the same reflection */
-        for (mode = display->modes; mode; mode = mode->next) {
-            if (mode->reflection != reflection) {
-                mode->reflection = reflection;
-                modified = TRUE;
-            }
-        }
-    }
+        display->cur_mode->reflection = reflection;
 
-    if (modified) {
         /* Update the layout */
         ctk_display_layout_update(ctk_object);
 
diff --git a/src/gtk+-2.x/ctkdisplaylayout.h b/src/gtk+-2.x/ctkdisplaylayout.h
index b09d2bc..0dd6e89 100644
--- a/src/gtk+-2.x/ctkdisplaylayout.h
+++ b/src/gtk+-2.x/ctkdisplaylayout.h
@@ -226,6 +226,7 @@ typedef struct nvModeRec {
 
     Bool forceCompositionPipeline;
     Bool forceFullCompositionPipeline;
+    Bool allowGSYNC;
 
 } nvMode, *nvModePtr;
 
diff --git a/src/gtk+-2.x/ctkecc.c b/src/gtk+-2.x/ctkecc.c
index 13a5f22..591d2aa 100644
--- a/src/gtk+-2.x/ctkecc.c
+++ b/src/gtk+-2.x/ctkecc.c
@@ -77,6 +77,7 @@ static void show_ecc_toggle_warning_dlg(CtkEcc *);
 static void ecc_set_config_status(CtkEcc *);
 static void ecc_configuration_update_received(GObject *, CtrlEvent *, gpointer);
 static void post_ecc_configuration_update(CtkEcc *);
+static void reset_default_config_button_clicked(GtkWidget *, gpointer);
 
 GType ctk_ecc_get_type(void)
 {
@@ -164,12 +165,40 @@ static gboolean update_ecc_info(gpointer user_data)
     CtkEcc *ctk_ecc = CTK_ECC(user_data);
     CtrlTarget *ctrl_target = ctk_ecc->ctrl_target;
     int64_t val;
+    gboolean status;
     ReturnStatus ret;
 
-    if (ctk_ecc->ecc_enabled == FALSE) {
+
+    if (!ctk_ecc->ecc_config_supported && !ctk_ecc->ecc_enabled ) {
         return FALSE;
     }
 
+    /*
+     * The ECC Configuration may be changed by non NV-CONTROL clients so we
+     * can't rely on an event to update the configuration state.
+     */
+
+    if (ctk_ecc->ecc_config_supported) {
+
+        ret = NvCtrlGetAttribute(ctrl_target, NV_CTRL_GPU_ECC_CONFIGURATION,
+                                 &status);
+
+        if (ret != NvCtrlSuccess ||
+            status == NV_CTRL_GPU_ECC_CONFIGURATION_DISABLED) {
+                ctk_ecc->ecc_configured = FALSE;
+        } else {
+                ctk_ecc->ecc_configured = TRUE;
+        }
+
+        ecc_set_config_status(ctk_ecc);
+    }
+
+    /* If ECC is not enabled, don't query ECC details but continue updating */
+
+    if (ctk_ecc->ecc_enabled == FALSE) {
+        return TRUE;
+    }
+
     /* Query ECC Errors */
 
     if (ctk_ecc->sbit_error) {
@@ -257,6 +286,20 @@ static void ecc_set_config_status(CtkEcc *ctk_ecc)
     g_signal_handlers_unblock_by_func(G_OBJECT(ctk_ecc->configuration_status),
                                       G_CALLBACK(ecc_config_button_toggled),
                                       (gpointer) ctk_ecc);
+
+    g_signal_handlers_block_by_func
+        (G_OBJECT(ctk_ecc->reset_default_config_button),
+         G_CALLBACK(reset_default_config_button_clicked),
+         (gpointer) ctk_ecc);
+    gtk_widget_set_sensitive
+        (ctk_ecc->reset_default_config_button,
+         ctk_ecc->ecc_config_supported &&
+         (ctk_ecc->ecc_configured != ctk_ecc->ecc_default_status));
+    g_signal_handlers_unblock_by_func
+        (G_OBJECT(ctk_ecc->reset_default_config_button),
+         G_CALLBACK(reset_default_config_button_clicked),
+         (gpointer) ctk_ecc);
+
 }
 
 
@@ -296,30 +339,21 @@ static void ecc_configuration_update_received(GObject *object,
 static void reset_default_config_button_clicked(GtkWidget *widget,
                                                 gpointer user_data)
 {
-    gboolean status;
     ReturnStatus ret;
     CtkEcc *ctk_ecc = CTK_ECC(user_data);
     CtrlTarget *ctrl_target = ctk_ecc->ctrl_target;
 
-    /* get default status and set it to ECC configuration */
-    ret = NvCtrlGetAttribute(ctrl_target,
-                             NV_CTRL_GPU_ECC_DEFAULT_CONFIGURATION,
-                             &status);
-    if (ret != NvCtrlSuccess) {
-        ctk_config_statusbar_message(ctk_ecc->ctk_config,
-                                     "Failed to get default configuration!");
-        return;
-    }
+    /* set default status to ECC configuration */
     ret =  NvCtrlSetAttribute(ctrl_target,
                               NV_CTRL_GPU_ECC_CONFIGURATION,
-                              status);
+                              ctk_ecc->ecc_default_status);
     if (ret != NvCtrlSuccess) {
         ctk_config_statusbar_message(ctk_ecc->ctk_config,
                                      "Failed to set default configuration!");
         return;
     }
 
-    ctk_ecc->ecc_configured = status;
+    ctk_ecc->ecc_configured = ctk_ecc->ecc_default_status;
 
     /* update ECC configuration button status */
     ecc_set_config_status(ctk_ecc);
@@ -385,6 +419,9 @@ static void show_ecc_toggle_warning_dlg(CtkEcc *ctk_ecc)
     if (ctk_ecc->ecc_toggle_warning_dlg_shown) {
         return;
     }
+
+    ctk_ecc_stop_timer(GTK_WIDGET(ctk_ecc));
+
     ctk_ecc->ecc_toggle_warning_dlg_shown = TRUE;
     parent = ctk_get_parent_window(GTK_WIDGET(ctk_ecc));
 
@@ -397,6 +434,8 @@ static void show_ecc_toggle_warning_dlg(CtkEcc *ctk_ecc)
                                   "taking effect.");
     gtk_dialog_run(GTK_DIALOG(dlg));
     gtk_widget_destroy (dlg);
+
+    ctk_ecc_start_timer(GTK_WIDGET(ctk_ecc));
 }
 
 
@@ -431,7 +470,9 @@ static void ecc_config_button_toggled(GtkWidget *widget,
 
     ctk_ecc->ecc_configured = enabled;
 
-    gtk_widget_set_sensitive(ctk_ecc->reset_default_config_button, TRUE);
+    gtk_widget_set_sensitive(ctk_ecc->reset_default_config_button,
+                             ctk_ecc->ecc_config_supported &&
+                             (enabled != ctk_ecc->ecc_default_status));
 
     /* Update status bar message */
     post_ecc_configuration_update(ctk_ecc);
@@ -458,7 +499,6 @@ GtkWidget* ctk_ecc_new(CtrlTarget *ctrl_target,
     gboolean dbit_error_available;
     gboolean aggregate_dbit_error_available;
     gboolean ecc_enabled;
-    gboolean ecc_default_status;
     ReturnStatus ret;
     gchar *ecc_enabled_string;
     gchar *str = NULL;
@@ -528,9 +568,9 @@ GtkWidget* ctk_ecc_new(CtrlTarget *ctrl_target,
                              &val);
     if (ret != NvCtrlSuccess ||
         val == NV_CTRL_GPU_ECC_DEFAULT_CONFIGURATION_DISABLED) {
-        ecc_default_status = FALSE;
+        ctk_ecc->ecc_default_status = FALSE;
     } else {
-        ecc_default_status = TRUE;
+        ctk_ecc->ecc_default_status = TRUE;
     }
 
     /* Query ECC errors */
@@ -572,6 +612,8 @@ GtkWidget* ctk_ecc_new(CtrlTarget *ctrl_target,
         ecc_config_supported = 0;
     }
 
+    ctk_ecc->ecc_config_supported = ecc_config_supported;
+
     /* set container properties for the CtkEcc widget */
 
     gtk_box_set_spacing(GTK_BOX(ctk_ecc), 5);
@@ -720,7 +762,7 @@ GtkWidget* ctk_ecc_new(CtrlTarget *ctrl_target,
                            __reset_default_config_button_help);
     gtk_widget_set_sensitive(ctk_ecc->reset_default_config_button,
                              ecc_config_supported &&
-                             (ecc_enabled != ecc_default_status));
+                             (ecc_enabled != ctk_ecc->ecc_default_status));
     g_signal_connect(G_OBJECT(ctk_ecc->reset_default_config_button),
                      "clicked",
                      G_CALLBACK(reset_default_config_button_clicked),
diff --git a/src/gtk+-2.x/ctkecc.h b/src/gtk+-2.x/ctkecc.h
index eb605e8..158cf16 100644
--- a/src/gtk+-2.x/ctkecc.h
+++ b/src/gtk+-2.x/ctkecc.h
@@ -58,7 +58,6 @@ struct _CtkEcc
     GtkWidget* dbit_error;
     GtkWidget* aggregate_sbit_error;
     GtkWidget* aggregate_dbit_error;
-    GtkWidget* ecc_config_supported;
     GtkWidget* clear_button;
     GtkWidget* clear_aggregate_button;
     GtkWidget* reset_default_config_button;
@@ -71,6 +70,8 @@ struct _CtkEcc
     gboolean dbit_error_available;
     gboolean aggregate_sbit_error_available;
     gboolean aggregate_dbit_error_available;
+    gboolean ecc_config_supported;
+    gboolean ecc_default_status;
 
 };
 
diff --git a/src/gtk+-2.x/ctkframelock.c b/src/gtk+-2.x/ctkframelock.c
index 79e3d95..1679cb4 100644
--- a/src/gtk+-2.x/ctkframelock.c
+++ b/src/gtk+-2.x/ctkframelock.c
@@ -18,7 +18,6 @@
  */
 
 #include <gtk/gtk.h>
-#include <gdk-pixbuf/gdk-pixdata.h>
 
 #include "NvCtrlAttributes.h"
 #include "NVCtrlLib.h"
@@ -34,15 +33,15 @@
 #include "ctkhelp.h"
 #include "ctkevent.h"
 
-#include "led_green_pixdata.h"
-#include "led_red_pixdata.h"
-#include "led_grey_pixdata.h"
+#include "led_green.png.h"
+#include "led_red.png.h"
+#include "led_grey.png.h"
 
-#include "rj45_input_pixdata.h"
-#include "rj45_output_pixdata.h"
-#include "rj45_unused_pixdata.h"
+#include "rj45_input.png.h"
+#include "rj45_output.png.h"
+#include "rj45_unused.png.h"
 
-#include "bnc_cable_pixdata.h"
+#include "bnc_cable.png.h"
 
 #include "parse.h"
 #include "msg.h"
@@ -4941,19 +4940,13 @@ GtkWidget* ctk_framelock_new(CtrlTarget *ctrl_target,
 
     /* Cache images */
 
-    ctk_framelock->led_grey_pixbuf =
-        gdk_pixbuf_from_pixdata(&led_grey_pixdata, TRUE, NULL);
-    ctk_framelock->led_green_pixbuf =
-        gdk_pixbuf_from_pixdata(&led_green_pixdata, TRUE, NULL);
-    ctk_framelock->led_red_pixbuf =
-        gdk_pixbuf_from_pixdata(&led_red_pixdata, TRUE, NULL);
+    ctk_framelock->led_grey_pixbuf = CTK_LOAD_PIXBUF(led_grey);
+    ctk_framelock->led_green_pixbuf = CTK_LOAD_PIXBUF(led_green);
+    ctk_framelock->led_red_pixbuf = CTK_LOAD_PIXBUF(led_red);
 
-    ctk_framelock->rj45_input_pixbuf =
-        gdk_pixbuf_from_pixdata(&rj45_input_pixdata, TRUE, NULL);
-    ctk_framelock->rj45_output_pixbuf =
-        gdk_pixbuf_from_pixdata(&rj45_output_pixdata, TRUE, NULL);
-    ctk_framelock->rj45_unused_pixbuf =
-        gdk_pixbuf_from_pixdata(&rj45_unused_pixdata, TRUE, NULL);
+    ctk_framelock->rj45_input_pixbuf = CTK_LOAD_PIXBUF(rj45_input);
+    ctk_framelock->rj45_output_pixbuf = CTK_LOAD_PIXBUF(rj45_output);
+    ctk_framelock->rj45_unused_pixbuf = CTK_LOAD_PIXBUF(rj45_unused);
 
     g_object_ref(ctk_framelock->led_grey_pixbuf);
     g_object_ref(ctk_framelock->led_green_pixbuf);
@@ -5035,8 +5028,7 @@ GtkWidget* ctk_framelock_new(CtrlTarget *ctrl_target,
     gtk_container_add(GTK_CONTAINER(frame), padding);
 
     /* add house sync BNC connector image */
-    image = gtk_image_new_from_pixbuf
-         (gdk_pixbuf_from_pixdata(&bnc_cable_pixdata, TRUE, NULL));
+    image = gtk_image_new_from_pixbuf(CTK_LOAD_PIXBUF(bnc_cable));
     hbox = gtk_hbox_new(FALSE, 0);
     gtk_box_pack_end(GTK_BOX(hbox), image, FALSE, FALSE, 0);
 
diff --git a/src/gtk+-2.x/ctkglstereo.c b/src/gtk+-2.x/ctkglstereo.c
new file mode 100644
index 0000000..135bb8c
--- /dev/null
+++ b/src/gtk+-2.x/ctkglstereo.c
@@ -0,0 +1,213 @@
+/*
+ * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix
+ * and Linux systems.
+ *
+ * Copyright (C) 2017 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses>.
+ */
+
+#include "ctkutils.h"
+#include "ctkglstereo.h"
+
+#ifdef CTK_GTK3
+#include <GL/gl.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "right.png.h"
+#include "left.png.h"
+#include "nvlogo.png.h"
+
+#include "matrix_utils.h"
+#include "opengl_loading.h"
+#include "ctkglwidget.h"
+#endif
+
+#ifdef CTK_GTK3
+const unsigned int animateDiv = 1000;
+static void animate(StereoAppData *appData, int eye)
+{
+    float x;
+    int op;
+    float delta = 0.2;
+
+    GLfloat tm[16];  // Temporary matrix
+    GLfloat *mvp;    // Model-View-Projection matrix
+    mvp = appData->cube->mvp;
+
+    if (eye == GL_LEFT) {
+        op = 1;
+    } else {
+        op = -1;
+    }
+
+    x = 2 * M_PI / animateDiv * appData->animationCounter;
+
+    genIdentityMatrix(mvp);
+
+    genRotateMatrixX(M_PI / 4, tm);
+    matrixMult(mvp, tm);
+
+    genRotateMatrixZ(M_PI / 4, tm);
+    matrixMult(mvp, tm);
+
+    // Apply the calculated rotation for this
+    // frame along axis X and Y to generate the
+    // animated effect
+    genRotateMatrixX(x, tm);
+    matrixMult(mvp, tm);
+    genRotateMatrixY(x, tm);
+    matrixMult(mvp, tm);
+
+    // Translates depending on eye
+    // and locates the object away from zero in the z-axis so
+    // that is viewable in the fov we define in the next step.
+    genTranslateMatrix(op * delta, 0, -1.5, tm);
+    matrixMult(mvp, tm);
+
+    genPerspectiveMatrix(M_PI / 2 , 1, 0.5, 5, tm);
+    matrixMult(mvp, tm);
+}
+
+static void produceFrameStereoTest(void *_appData)
+{
+    StereoAppData *appData = _appData;
+
+    dGL.glDrawBuffer(GL_BACK_LEFT);
+
+    dGL.glClearColor(206.0/255, 206.0/255, 206.0/255, 1);
+    dGL.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    animate(appData, GL_LEFT);
+    drawModel(appData->cube);
+    drawModel(appData->labelLeft);
+
+    dGL.glDrawBuffer(GL_BACK_RIGHT);
+    dGL.glClearColor(206.0/255, 206.0/255, 206.0/255, 1);
+    dGL.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    animate(appData, GL_RIGHT);
+    drawModel(appData->cube);
+    drawModel(appData->labelRight);
+
+    appData->animationCounter++;
+    appData->animationCounter %= animateDiv;
+}
+
+static int verifyOpenglForStereo(void)
+{
+    GLint majorVer = 0;
+
+    dGL.glGetIntegerv(GL_MAJOR_VERSION, &majorVer);
+
+    if (majorVer < 3) {
+        return -1;
+    }
+    return 0;
+}
+
+static int setupStereoTest(void *_appData)
+{
+    StereoAppData *appData = _appData;
+
+    GdkPixbuf *nvidiaLogo = CTK_LOAD_PIXBUF(nvlogo);
+    GdkPixbuf *imageLeft  = CTK_LOAD_PIXBUF(left);
+    GdkPixbuf *imageRight = CTK_LOAD_PIXBUF(right);
+
+    if (verifyOpenglForStereo() != 0) {
+        return -2;
+    }
+
+    dGL.glViewport(0, 0, 200, 200);
+
+    dGL.glEnable(GL_DEPTH_TEST);
+
+    dGL.glEnable(GL_BLEND);
+    dGL.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+    dGL.glEnable(GL_TEXTURE_2D);
+    dGL.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+    appData->animationCounter = 0;
+
+    appData->cube = cubeSetup(nvidiaLogo);
+
+    appData->labelLeft = labelSetup(-0.75, 0.90,      // x and y
+                                     0.5,  0.20,      // width and height
+                                       1, 0, 0,       // rgb
+                                     imageLeft        // GdkPixbuf *
+                                   );
+
+    appData->labelRight = labelSetup(0.70, 0.85,      // x and y
+                                     0.6,  0.20,      // width and height
+                                       0, 0, 1,       // rgb
+                                     imageRight       // GdkPixbuf *
+                                    );
+
+    g_object_unref(nvidiaLogo);
+    g_object_unref(imageLeft);
+    g_object_unref(imageRight);
+
+    if (appData->cube == NULL ||
+        appData->labelLeft == NULL ||
+        appData->labelRight == NULL) {
+
+        return -1;
+    }
+
+    return 0;
+}
+
+#endif
+
+GtkWidget *ctk_glstereo_new(void)
+{
+#ifdef CTK_GTK3
+    GtkWidget *gtk_widget;
+    CtkGLWidget *ctk_glwidget;
+    int glx_attributes[] = {
+        GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+        GLX_RENDER_TYPE,   GLX_RGBA_BIT,
+        GLX_DOUBLEBUFFER,  1,
+        GLX_RED_SIZE,      1,
+        GLX_GREEN_SIZE,    1,
+        GLX_BLUE_SIZE,     1,
+        GLX_ALPHA_SIZE,    1,
+        GLX_DEPTH_SIZE,    1,
+        GLX_STEREO,        1,
+        None
+    };
+
+    void *app_data;
+    app_data = malloc(sizeof(StereoAppData));
+    gtk_widget = ctk_glwidget_new(glx_attributes,
+                                  app_data,
+                                  setupStereoTest,
+                                  produceFrameStereoTest);
+
+    ctk_glwidget = CTK_GLWIDGET(gtk_widget);
+
+    if (ctk_glwidget) {
+        ctk_glwidget->timer_interval = 10;  // In milliseconds
+        gtk_widget_set_size_request(GTK_WIDGET(ctk_glwidget), 200, 200);
+        return GTK_WIDGET(ctk_glwidget);
+    }
+
+    free(app_data);
+
+#endif
+    return NULL;
+}
+
diff --git a/src/gtk+-2.x/ctkglstereo.h b/src/gtk+-2.x/ctkglstereo.h
new file mode 100644
index 0000000..c598839
--- /dev/null
+++ b/src/gtk+-2.x/ctkglstereo.h
@@ -0,0 +1,44 @@
+/*
+ * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix
+ * and Linux systems.
+ *
+ * Copyright (C) 2017 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses>.
+ */
+
+#ifndef __CTK_GLSTEREO_H__
+#define __CTK_GLSTEREO_H__
+
+#include "ctkutils.h"
+
+#ifdef CTK_GTK3
+#include "opengl_wrappers.h"
+#endif
+
+GtkWidget *ctk_glstereo_new(void);
+
+
+#ifdef CTK_GTK3
+typedef struct _StereoAppData StereoAppData;
+struct _StereoAppData
+{
+    OpenGLModelData *cube;
+    OpenGLModelData *labelLeft;
+    OpenGLModelData *labelRight;
+    unsigned int animationCounter;
+};
+
+#endif
+
+#endif
diff --git a/src/gtk+-2.x/ctkglwidget.c b/src/gtk+-2.x/ctkglwidget.c
new file mode 100644
index 0000000..bd47bcd
--- /dev/null
+++ b/src/gtk+-2.x/ctkglwidget.c
@@ -0,0 +1,282 @@
+/*
+ * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix
+ * and Linux systems.
+ *
+ * Copyright (C) 2017 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses>.
+ */
+
+#include "ctkutils.h"
+#include "ctkglwidget.h"
+
+#include <assert.h>
+#include <gtk/gtk.h>
+#include <GL/glx.h>
+#include <gdk/gdkx.h>
+#include <stdlib.h>
+#include "opengl_loading.h"
+
+GtkWidget *ctk_glwidget_new(int glx_attributes[],
+                            void *app_data,
+                            int (*app_setup_callback) (void *app_data),
+                            void (*draw_frame_callback) (void *app_data) )
+{
+#ifdef CTK_GTK3
+    GObject *object;
+    CtkGLWidget *ctk_glwidget;
+    GLXFBConfig *fb_configs;
+    int n_elements;
+    int x_visual_id;
+
+    GdkDisplay *gdk_display;
+    Display *display;
+    GLXContext glx_context;
+    GdkVisual *gdk_visual;
+
+    gdk_display = gdk_display_get_default();
+
+
+    display = gdk_x11_display_get_xdisplay(gdk_display);
+
+    if (!loadGL()) {
+        return NULL;
+    }
+
+    fb_configs = dGL.glXChooseFBConfig(display,
+                                       DefaultScreen(display),
+                                       glx_attributes, &n_elements);
+    if (n_elements == 0) {
+        return NULL;
+    }
+
+    dGL.glXGetFBConfigAttrib(display,
+                             fb_configs[0],
+                             GLX_VISUAL_ID,
+                             &x_visual_id);
+
+    gdk_visual = gdk_x11_screen_lookup_visual(gdk_screen_get_default(),
+                                              x_visual_id);
+
+    if (gdk_visual == NULL) {
+        XFree(fb_configs);
+        return NULL;
+    }
+
+    gdk_x11_display_error_trap_push(gdk_display);
+    glx_context = dGL.glXCreateNewContext(display,
+                                          fb_configs[0],
+                                          GLX_RGBA_TYPE,
+                                          NULL,
+                                          GL_TRUE);
+
+    if (gdk_x11_display_error_trap_pop(gdk_display) != 0) {
+        glx_context = NULL;
+    }
+
+    XFree(fb_configs);
+
+    if (glx_context == NULL) {
+        return NULL;
+    }
+
+    object = g_object_new(CTK_TYPE_GLWIDGET, NULL);
+    ctk_glwidget = CTK_GLWIDGET(object);
+
+    ctk_glwidget->app_data = app_data;
+    ctk_glwidget->app_setup_callback = app_setup_callback;
+    ctk_glwidget->draw_frame_callback = draw_frame_callback;
+
+    ctk_glwidget->gdk_display = gdk_display;
+    ctk_glwidget->gdk_window = NULL;
+    ctk_glwidget->display = display;
+
+    ctk_glwidget->is_error = FALSE;
+    ctk_glwidget->timer_interval = 100;
+
+    ctk_glwidget->glx_context = glx_context;
+    ctk_glwidget->gdk_visual = gdk_visual;
+
+    return GTK_WIDGET(ctk_glwidget);
+
+#else
+    return NULL;
+#endif
+}
+
+#ifdef CTK_GTK3
+static void on_error(CtkGLWidget *ctk_glwidget);
+static gboolean draw_frame_in_glwidget(gpointer p);
+
+static void ctk_glwidget_realize(GtkWidget *gtk_widget)
+{
+    CtkGLWidget *ctk_glwidget;
+    GdkWindowAttr gdk_attributes;
+    gint attributes_mask;
+    GtkAllocation allocation;
+
+    ctk_glwidget = CTK_GLWIDGET(gtk_widget);
+
+    gtk_widget_set_realized(gtk_widget, TRUE);
+    gtk_widget_set_has_window(gtk_widget, TRUE);
+
+    if (ctk_glwidget->is_error) {
+        return;
+    }
+
+    if (ctk_glwidget->gdk_window) {
+        gdk_window_set_user_data(ctk_glwidget->gdk_window,
+                                 gtk_widget);
+        return;
+    }
+
+    gtk_widget_get_allocation(gtk_widget, &allocation);
+
+    gdk_attributes.x = allocation.x;
+    gdk_attributes.y = allocation.y;
+    gdk_attributes.width = allocation.width;
+    gdk_attributes.height = allocation.height;
+    gdk_attributes.wclass = GDK_INPUT_OUTPUT;
+    gdk_attributes.window_type = GDK_WINDOW_CHILD;
+    gdk_attributes.event_mask = gtk_widget_get_events(gtk_widget);
+    gdk_attributes.visual = ctk_glwidget->gdk_visual;
+
+    attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
+
+    ctk_glwidget->gdk_window =
+        gdk_window_new(gtk_widget_get_parent_window(gtk_widget),
+                       &gdk_attributes, attributes_mask);
+
+    if (ctk_glwidget->gdk_window == NULL) {
+        on_error(ctk_glwidget);
+        return;
+    }
+
+    ctk_glwidget->window = gdk_x11_window_get_xid(ctk_glwidget->gdk_window);
+    gdk_window_set_user_data(ctk_glwidget->gdk_window, gtk_widget);
+    gtk_widget_set_window(gtk_widget, ctk_glwidget->gdk_window);
+
+    dGL.glXMakeContextCurrent(ctk_glwidget->display, ctk_glwidget->window,
+                              ctk_glwidget->window, ctk_glwidget->glx_context);
+
+    if (ctk_glwidget->app_setup_callback(ctk_glwidget->app_data) != 0) {
+        on_error(ctk_glwidget);
+        return;
+    }
+
+    g_timeout_add_full(G_PRIORITY_LOW,
+                       ctk_glwidget->timer_interval,
+                       draw_frame_in_glwidget,
+                       ctk_glwidget,
+                       0);
+
+}
+
+static void ctk_glwidget_unrealize(GtkWidget *gtk_widget)
+{
+
+    if (CTK_GLWIDGET(gtk_widget)->is_error) {
+        return;
+    }
+
+    if (gtk_widget_get_has_window(gtk_widget)) {
+        gdk_window_set_user_data(CTK_GLWIDGET(gtk_widget)->gdk_window, NULL);
+    }
+
+    gtk_selection_remove_all(gtk_widget);
+    gtk_widget_set_realized(gtk_widget, FALSE);
+}
+
+static void ctk_glwidget_finalize(GObject *gobject)
+{
+    assert(!"unimplemented");
+}
+
+static void ctk_glwidget_class_init(CtkGLWidgetClass *klass)
+{
+    GtkWidgetClass *widget_class;
+    GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+    widget_class = (GtkWidgetClass *) klass;
+
+    widget_class->realize = ctk_glwidget_realize;
+    widget_class->unrealize = ctk_glwidget_unrealize;
+    gobject_class->finalize = ctk_glwidget_finalize;
+}
+
+GType ctk_glwidget_get_type(void)
+{
+    static GType ctk_glwidget_type = 0;
+
+    if (!ctk_glwidget_type) {
+        static const GTypeInfo info_ctk_glwidget = {
+            sizeof (CtkGLWidgetClass),
+            NULL, /* base_init */
+            NULL, /* base_finalize */
+            (GClassInitFunc) ctk_glwidget_class_init, /* class_init */
+            NULL, /* class_finalize */
+            NULL, /* class_data */
+            sizeof (CtkGLWidget),
+            0, /* n_preallocs */
+            NULL, /* instance_init */
+            NULL  /* value_table */
+        };
+        ctk_glwidget_type = g_type_register_static(GTK_TYPE_WIDGET,
+                                "CtkGLWidget", &info_ctk_glwidget, 0);
+    }
+    return ctk_glwidget_type;
+}
+
+static gboolean draw_frame_in_glwidget(gpointer p)
+{
+    CtkGLWidget *ctk_glwidget = CTK_GLWIDGET(p);
+
+    if (ctk_glwidget->is_error) {
+        return FALSE;
+    }
+
+    if (!gtk_widget_get_realized(GTK_WIDGET(p))) {
+        return TRUE;
+    }
+
+    if (ctk_widget_is_drawable(GTK_WIDGET(ctk_glwidget))) {
+        ctk_glwidget_make_current(ctk_glwidget);
+        ctk_glwidget->draw_frame_callback(ctk_glwidget->app_data);
+        ctk_glwidget_swap(ctk_glwidget);
+    }
+    return TRUE;
+}
+
+static void on_error(CtkGLWidget *ctk_glwidget)
+{
+    ctk_glwidget->is_error = TRUE;
+    gtk_widget_set_size_request(GTK_WIDGET(ctk_glwidget), 0, 0);
+
+    if (ctk_glwidget->gdk_window) {
+        gdk_window_set_user_data(ctk_glwidget->gdk_window, NULL);
+    }
+}
+
+void ctk_glwidget_make_current(CtkGLWidget *ctk_glwidget)
+{
+    dGL.glXMakeContextCurrent(ctk_glwidget->display,
+                              ctk_glwidget->window,
+                              ctk_glwidget->window,
+                              ctk_glwidget->glx_context);
+}
+
+void ctk_glwidget_swap(CtkGLWidget *ctk_glwidget)
+{
+    dGL.glXSwapBuffers(ctk_glwidget->display, ctk_glwidget->window);
+}
+#endif
+
diff --git a/src/gtk+-2.x/ctkglwidget.h b/src/gtk+-2.x/ctkglwidget.h
new file mode 100644
index 0000000..f4154dd
--- /dev/null
+++ b/src/gtk+-2.x/ctkglwidget.h
@@ -0,0 +1,91 @@
+/*
+ * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix
+ * and Linux systems.
+ *
+ * Copyright (C) 2017 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses>.
+ */
+
+#ifndef __CTK_GLWIDGET_H__
+#define __CTK_GLWIDGET_H__
+
+#include <gtk/gtk.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <gdk/gdkx.h>
+
+#include "ctkconfig.h"
+
+G_BEGIN_DECLS
+
+#define CTK_TYPE_GLWIDGET (ctk_glwidget_get_type())
+
+#define CTK_GLWIDGET(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), CTK_TYPE_GLWIDGET, CtkGLWidget))
+
+#define CTK_GLWIDGET_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), CTK_TYPE_GLWIDGET, CtkGLWidgetClass))
+
+#define CTK_IS_GLWIDGET(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CTK_TYPE_GLWIDGET))
+
+#define CTK_IS_GLWIDGET_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE ((klass), CTK_TYPE_GLWIDGET))
+
+#define CTK_GLWIDGET_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), CTK_TYPE_GLWIDGET, CtkGLWidgetClass))
+
+
+typedef struct _CtkGLWidget      CtkGLWidget;
+typedef struct _CtkGLWidgetClass CtkGLWidgetClass;
+
+struct _CtkGLWidget
+{
+    GtkWidget parent;
+
+    GdkDisplay *gdk_display;
+    GdkWindow *gdk_window;
+    Display *display;
+    Window window;
+    GLXContext glx_context;
+    GdkVisual *gdk_visual;
+
+    gboolean is_error;
+    int timer_interval;
+    void *app_data;
+
+    int (*app_setup_callback) (void *app_data);
+    void (*draw_frame_callback) (void *app_data);
+};
+
+struct _CtkGLWidgetClass
+{
+    GtkWidgetClass parent_class;
+};
+
+GType ctk_glwidget_get_type (void);
+
+GtkWidget *ctk_glwidget_new(int glx_attributes[],
+                            void *app_data,
+                            int (*app_setup_callback) (void *app_data),
+                            void (*draw_frame_callback) (void *app_data));
+
+#ifdef CTK_GTK3
+void ctk_glwidget_make_current(CtkGLWidget *ctk_glwidget);
+void ctk_glwidget_swap(CtkGLWidget *ctk_glwidget);
+#endif
+
+G_END_DECLS
+
+#endif
diff --git a/src/gtk+-2.x/ctkgridlicense.c b/src/gtk+-2.x/ctkgridlicense.c
index f995d0a..ced1406 100644
--- a/src/gtk+-2.x/ctkgridlicense.c
+++ b/src/gtk+-2.x/ctkgridlicense.c
@@ -117,6 +117,12 @@ static gboolean checkConfigfile(gboolean *writable);
 static gboolean disallow_whitespace(GtkWidget *widget, GdkEvent *event, gpointer user_data);
 static gboolean allow_digits(GtkWidget *widget, GdkEvent *event, gpointer user_data);
 static gboolean enable_disable_ui_controls(GtkWidget *widget, GdkEvent *event, gpointer user_data);
+static void update_gui_from_griddconfig(gpointer user_data);
+static gboolean licenseStateQueryFailed = FALSE;
+static void get_licensed_feature_code(gpointer user_data);
+static gboolean is_restart_required(gpointer user_data);
+static gboolean queryLicensedFeatureCode = TRUE;
+int64_t licensedFeatureCode = NV_GRID_LICENSE_FEATURE_TYPE_VAPP;
 
 GType ctk_manage_grid_license_get_type(void)
 {
@@ -748,19 +754,60 @@ static gboolean update_manage_grid_license_state_info(gpointer user_data)
     int licenseState = NV_GRID_UNLICENSED;
     int griddFeatureType = ctk_manage_grid_license->feature_type;
 
-    /* Send license state request */
-    if (!(send_message_to_gridd(ctk_manage_grid_license, LICENSE_STATE_REQUEST,
-                                &licenseState))) {
-        ret = FALSE;
+    /* Send license state and feature type request */
+    if ((!(send_message_to_gridd(ctk_manage_grid_license, LICENSE_STATE_REQUEST,
+                                 &licenseState))) ||
+        (!(send_message_to_gridd(ctk_manage_grid_license, LICENSE_FEATURE_TYPE_REQUEST,
+                                 &griddFeatureType)))) {
+        licenseStatusMessage = "Unable to query license state information "
+                               "from the NVIDIA GRID "
+                               "licensing daemon.\n"
+                               "Please make sure nvidia-gridd and "
+                               "dbus-daemon are running.\n";
+        gtk_label_set_text(GTK_LABEL(ctk_manage_grid_license->label_license_state),
+                           licenseStatusMessage);
+        /* Disable text controls on UI. */
+        gtk_widget_set_sensitive(ctk_manage_grid_license->txt_server_address, FALSE);
+        gtk_widget_set_sensitive(ctk_manage_grid_license->txt_server_port, FALSE);
+        gtk_widget_set_sensitive(ctk_manage_grid_license->txt_secondary_server_address, FALSE);
+        gtk_widget_set_sensitive(ctk_manage_grid_license->txt_secondary_server_port, FALSE);
+        /* Disable Apply/Cancel button. */
+        gtk_widget_set_sensitive(ctk_manage_grid_license->btn_apply, FALSE);
+        gtk_widget_set_sensitive(ctk_manage_grid_license->btn_cancel, FALSE);
+        /* Disable toggle buttons */
+        if (ctk_manage_grid_license->radio_btn_qdws && ctk_manage_grid_license->radio_btn_vapp) {
+            gtk_widget_set_sensitive(ctk_manage_grid_license->radio_btn_qdws, FALSE);
+            gtk_widget_set_sensitive(ctk_manage_grid_license->radio_btn_vapp, FALSE);
+        }
+
+        licenseStateQueryFailed = TRUE;
+        return ret;
     }
 
+    if (licenseStateQueryFailed == TRUE) {
+        /*Failure to communicate with nvidia-gridd in previous attempt.
+         Refresh UI with parameters from the griddConfig.*/
+        update_gui_from_griddconfig(ctk_manage_grid_license);
+        licenseStateQueryFailed = FALSE;
+    }
+
+    /* Set the license feature type fetched from nvidia-gridd.*/
+    ctk_manage_grid_license->gridd_feature_type = griddFeatureType;
+
     if (licenseState == NV_GRID_UNLICENSED) {
+        queryLicensedFeatureCode = TRUE;
         switch (ctk_manage_grid_license->feature_type) {
             case NV_GRID_LICENSE_FEATURE_TYPE_VAPP:
                 licenseStatus = NV_GRID_UNLICENSED_VAPP;
+                if (is_restart_required(ctk_manage_grid_license)) {
+                    licenseStatus = NV_GRID_LICENSE_RESTART_REQUIRED_VAPP;
+                }
                 break;
             case NV_GRID_LICENSE_FEATURE_TYPE_QDWS:
                 licenseStatus = NV_GRID_UNLICENSED_QDWS_SELECTED;
+                if (licensedFeatureCode == NV_GRID_LICENSE_FEATURE_TYPE_QDWS) {
+                    licenseStatus = NV_GRID_UNLICENSED_REQUEST_DETAILS;
+                }
                 break;
             case NV_GRID_LICENSE_FEATURE_TYPE_VGPU:
                 licenseStatus = NV_GRID_UNLICENSED_VGPU;
@@ -770,14 +817,6 @@ static gboolean update_manage_grid_license_state_info(gpointer user_data)
         }
     }
     else {
-        /* Send license feature type request */
-        if (!(send_message_to_gridd(ctk_manage_grid_license, LICENSE_FEATURE_TYPE_REQUEST,
-                                    &griddFeatureType))) {
-            ret = FALSE;
-        }
-        /* Set the license feature type fetched from nvidia-gridd.*/
-        ctk_manage_grid_license->gridd_feature_type = griddFeatureType;
-
         if ((licenseState == NV_GRID_LICENSED) ||
             (licenseState == NV_GRID_LICENSE_RENEWING) ||
             (licenseState == NV_GRID_LICENSE_RENEW_FAILED)) {
@@ -804,6 +843,10 @@ static gboolean update_manage_grid_license_state_info(gpointer user_data)
                 default:
                     break;
             }
+            if (queryLicensedFeatureCode == TRUE) {
+                get_licensed_feature_code(ctk_manage_grid_license);
+                queryLicensedFeatureCode = FALSE;
+            }
         }
         else if (licenseState == NV_GRID_LICENSE_REQUESTING) {
             switch (ctk_manage_grid_license->feature_type) {
@@ -932,8 +975,12 @@ static gboolean update_manage_grid_license_state_info(gpointer user_data)
               "Your system is currently licensed for Quadro Virtual Datacenter "
               "Workstation.";
           break;
+    case NV_GRID_LICENSE_RESTART_REQUIRED_VAPP:
+          licenseStatusMessage = "Restart your system for GRID Virtual Apps.";
+          break;
+    case NV_GRID_UNLICENSED_REQUEST_DETAILS:
     default:
-          licenseStatusMessage = "Your system does not have a valid GPU license.\n"
+          licenseStatusMessage = "Your system does not have a valid GRID license.\n"
               "Enter license server details and apply.";
           break;
     }
@@ -943,7 +990,22 @@ static gboolean update_manage_grid_license_state_info(gpointer user_data)
     return ret;
 }
 
+/*
+ * is_restart_required() - Check if restart is required for new feature to be enabled.
+ */
+static gboolean is_restart_required(gpointer user_data)
+{
+    CtkManageGridLicense *ctk_manage_grid_license = CTK_MANAGE_GRID_LICENSE(user_data);
+    gboolean ret = FALSE;
 
+    /* Once licensed, system reboot required if there is mismatch between feature type
+        updated from UI/gridd.conf and feature code of the feature that is licensed on this system. */
+    if ((licensedFeatureCode) &&
+        (licensedFeatureCode != ctk_manage_grid_license->feature_type)) {
+        ret = TRUE;
+    }
+    return ret;
+}
 
 /*
  * apply_clicked() - Called when the user clicks on the "Apply" button.
@@ -1031,12 +1093,48 @@ static void apply_clicked(GtkWidget *widget, gpointer user_data)
 }
 
 /*
+ * get_licensed_feature_code() - Get the feature code of the feature that is licensed on this system.
+ */
+static void get_licensed_feature_code(gpointer user_data)
+{
+    CtkManageGridLicense *ctk_manage_grid_license = CTK_MANAGE_GRID_LICENSE(user_data);
+    nvmlGridLicensableFeatures_t *gridLicensableFeatures;
+    gint ret, i;
+
+    ret = NvCtrlNvmlGetGridLicenseAttributes(ctk_manage_grid_license->target,
+                                             NV_CTRL_ATTR_NVML_GPU_GRID_LICENSABLE_FEATURES,
+                                             &gridLicensableFeatures);
+    if (ret != NvCtrlSuccess) {
+        return;
+    }
+
+    for (i = 0; i < gridLicensableFeatures->licensableFeaturesCount; i++)
+    {
+        if (gridLicensableFeatures->gridLicensableFeatures[i].featureState != 0)
+        {
+            licensedFeatureCode = gridLicensableFeatures->gridLicensableFeatures[i].featureCode;
+            break;
+        }
+    }
+    nvfree(gridLicensableFeatures);
+}
+
+/*
  * cancel_clicked() - Called when the user clicks on the "Cancel" button.
  */
 
 static void cancel_clicked(GtkWidget *widget, gpointer user_data)
 {
     CtkManageGridLicense *ctk_manage_grid_license = CTK_MANAGE_GRID_LICENSE(user_data);
+
+    /* Discard user input and revert back to configuration from the nvidia-gridd config file */
+    update_gui_from_griddconfig(ctk_manage_grid_license);
+
+}
+
+static void update_gui_from_griddconfig(gpointer user_data)
+{
+    CtkManageGridLicense *ctk_manage_grid_license = CTK_MANAGE_GRID_LICENSE(user_data);
     NvGriddConfigParams *griddConfig = NULL;
     const char *textBoxServerStr;
 
@@ -1058,21 +1156,55 @@ static void cancel_clicked(GtkWidget *widget, gpointer user_data)
                            griddConfig->str[NV_GRIDD_BACKUP_SERVER_ADDRESS]);
         gtk_entry_set_text(GTK_ENTRY(ctk_manage_grid_license->txt_secondary_server_port),
                            griddConfig->str[NV_GRIDD_BACKUP_SERVER_PORT]);
-    }
+        /* set default value for feature type based on the user configured parameter or virtualization mode */
+        /* Check Feature type "2" for Quadro Virtual Datacenter Workstation. */
+        if (strcmp(griddConfig->str[NV_GRIDD_FEATURE_TYPE], "2") == 0) {
+            ctk_manage_grid_license->feature_type = NV_GRID_LICENSE_FEATURE_TYPE_QDWS;
+        }
+        else {
+            ctk_manage_grid_license->feature_type = NV_GRID_LICENSE_FEATURE_TYPE_VAPP;
+        }
 
-    textBoxServerStr = gtk_entry_get_text(GTK_ENTRY(ctk_manage_grid_license->txt_server_address));
-    /* Enable/Disable Secondary server address/port textboxes if Primary server address textbox string is empty. */
-    if (strcmp(textBoxServerStr, "") == 0) {
-        gtk_widget_set_sensitive(ctk_manage_grid_license->txt_secondary_server_address, FALSE);
-        gtk_widget_set_sensitive(ctk_manage_grid_license->txt_secondary_server_port, FALSE);
-    } else {
-        gtk_widget_set_sensitive(ctk_manage_grid_license->txt_secondary_server_address, TRUE);
-        gtk_widget_set_sensitive(ctk_manage_grid_license->txt_secondary_server_port, TRUE);
-    }
+        /* Override feature type when on vGPU */
+        if (ctk_manage_grid_license->license_edition_state == NV_CTRL_ATTR_NVML_GPU_VIRTUALIZATION_MODE_VGPU)
+        {
+            ctk_manage_grid_license->feature_type = NV_GRID_LICENSE_FEATURE_TYPE_VGPU;
+        }
 
-    /* Disable Apply/Cancel button. */
-    gtk_widget_set_sensitive(ctk_manage_grid_license->btn_apply, FALSE);
-    gtk_widget_set_sensitive(ctk_manage_grid_license->btn_cancel, FALSE);
+        /* Set license edition toggle button active */
+        if (ctk_manage_grid_license->radio_btn_qdws && ctk_manage_grid_license->radio_btn_vapp) {
+            if (ctk_manage_grid_license->feature_type == NV_GRID_LICENSE_FEATURE_TYPE_QDWS) {
+                /* Set 'Quadro Virtual Datacenter Workstation' toggle button active */
+                gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ctk_manage_grid_license->radio_btn_qdws), TRUE);
+            }
+            else {
+                /* Set 'GRID Virtual Apps' toggle button active */
+                gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ctk_manage_grid_license->radio_btn_vapp), TRUE);
+            }
+        }
+
+        /* Enable Primary server address/port textboxes. */
+        gtk_widget_set_sensitive(ctk_manage_grid_license->txt_server_address, TRUE);
+        gtk_widget_set_sensitive(ctk_manage_grid_license->txt_server_port, TRUE);
+        /* Enable toggle buttons. */
+        if (ctk_manage_grid_license->radio_btn_qdws && ctk_manage_grid_license->radio_btn_vapp) {
+            gtk_widget_set_sensitive(ctk_manage_grid_license->radio_btn_qdws, TRUE);
+            gtk_widget_set_sensitive(ctk_manage_grid_license->radio_btn_vapp, TRUE);
+        }
+
+        textBoxServerStr = gtk_entry_get_text(GTK_ENTRY(ctk_manage_grid_license->txt_server_address));
+        /* Enable/Disable Secondary server address/port textboxes if Primary server address textbox string is empty. */
+        if (strcmp(textBoxServerStr, "") == 0) {
+            gtk_widget_set_sensitive(ctk_manage_grid_license->txt_secondary_server_address, FALSE);
+            gtk_widget_set_sensitive(ctk_manage_grid_license->txt_secondary_server_port, FALSE);
+        } else {
+            gtk_widget_set_sensitive(ctk_manage_grid_license->txt_secondary_server_address, TRUE);
+            gtk_widget_set_sensitive(ctk_manage_grid_license->txt_secondary_server_port, TRUE);
+        }
+        /* Disable Apply/Cancel button. */
+        gtk_widget_set_sensitive(ctk_manage_grid_license->btn_apply, FALSE);
+        gtk_widget_set_sensitive(ctk_manage_grid_license->btn_cancel, FALSE);
+    }
 
     if(griddConfig)
         FreeNvGriddConfigParams(griddConfig);
@@ -1198,8 +1330,8 @@ static gboolean enable_disable_ui_controls(GtkWidget *widget, GdkEvent *event, g
         textBoxSecondaryServerPortStr = gtk_entry_get_text(GTK_ENTRY(ctk_manage_grid_license->txt_secondary_server_port));
 
         /* Enable apply/cancel button if either:
-            Primary server address/port textbox string doesn't match with the Primary server string from the gridd config file or
-            Secondary server address/port textbox string doesn't match with the Secondary server string from the gridd config file. */
+            Primary server address/port textbox string doesn't match with the Primary server string from the nvidia-gridd config file or
+            Secondary server address/port textbox string doesn't match with the Secondary server string from the nvidia-gridd config file. */
         if ((strcmp(griddConfig->str[NV_GRIDD_SERVER_ADDRESS], textBoxServerStr) != 0) ||
             ((strcmp(griddConfig->str[NV_GRIDD_BACKUP_SERVER_ADDRESS], textBoxSecondaryServerStr) != 0) ||
             (strcmp(griddConfig->str[NV_GRIDD_BACKUP_SERVER_PORT], textBoxSecondaryServerPortStr) != 0) ||
@@ -1336,7 +1468,6 @@ GtkWidget* ctk_manage_grid_license_new(CtrlTarget *target,
     GtkWidget *banner, *label, *frame;
     gchar *str = NULL;
     int64_t mode;
-    GtkWidget *button1 = NULL, *button2 = NULL;
     GSList *slist = NULL;
     gint ret;
     DBusError err;
@@ -1430,25 +1561,7 @@ GtkWidget* ctk_manage_grid_license_new(CtrlTarget *target,
     ctk_manage_grid_license->license_edition_state = mode;
     ctk_manage_grid_license->dbusData = dbusData;
     ctk_manage_grid_license->feature_type = 0;
-
-    /* set default value for feature type based on the user configured parameter or virtualization mode */
-    if (griddConfig) {
-        /* Check Feature type "2" for Quadro Virtual Datacenter Workstation. */
-        if (strcmp(griddConfig->str[NV_GRIDD_FEATURE_TYPE], "2") == 0) {
-            ctk_manage_grid_license->feature_type = NV_GRID_LICENSE_FEATURE_TYPE_QDWS;
-        }
-        else {
-            ctk_manage_grid_license->feature_type = NV_GRID_LICENSE_FEATURE_TYPE_VAPP;
-        }
-    }
-
-    /* Overwrite feature type in vGPU case */
-    if (ctk_manage_grid_license->license_edition_state == NV_CTRL_ATTR_NVML_GPU_VIRTUALIZATION_MODE_VGPU)
-    {
-        ctk_manage_grid_license->feature_type = NV_GRID_LICENSE_FEATURE_TYPE_VGPU;
-    }
-
-    ctk_manage_grid_license->gridd_feature_type = ctk_manage_grid_license->feature_type;
+    ctk_manage_grid_license->target = target;
 
     /* set container properties for the CtkManageGridLicense widget */
 
@@ -1481,22 +1594,22 @@ GtkWidget* ctk_manage_grid_license_new(CtrlTarget *target,
         gtk_container_add(GTK_CONTAINER(vbox1), vbox3);
         gtk_container_set_border_width(GTK_CONTAINER(vbox3), 5);
 
-        button1 = gtk_radio_button_new_with_label(NULL,
+        ctk_manage_grid_license->radio_btn_qdws = gtk_radio_button_new_with_label(NULL,
                                                   "Quadro Virtual Datacenter Workstation");
-        slist = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button1));
-        gtk_box_pack_start(GTK_BOX(vbox3), button1, FALSE, FALSE, 0);
-        g_object_set_data(G_OBJECT(button1), "button_id",
+        slist = gtk_radio_button_get_group(GTK_RADIO_BUTTON(ctk_manage_grid_license->radio_btn_qdws));
+        gtk_box_pack_start(GTK_BOX(vbox3), ctk_manage_grid_license->radio_btn_qdws, FALSE, FALSE, 0);
+        g_object_set_data(G_OBJECT(ctk_manage_grid_license->radio_btn_qdws), "button_id",
                 GINT_TO_POINTER(NV_GRID_LICENSE_FEATURE_TYPE_QDWS));
-        g_signal_connect(G_OBJECT(button1), "toggled",
+        g_signal_connect(G_OBJECT(ctk_manage_grid_license->radio_btn_qdws), "toggled",
                          G_CALLBACK(license_edition_toggled),
                          (gpointer) ctk_manage_grid_license);
 
-        button2 = gtk_radio_button_new_with_label(slist, "GRID Virtual Apps");
-        gtk_box_pack_start(GTK_BOX(vbox3), button2, FALSE, FALSE, 0);
-        g_object_set_data(G_OBJECT(button2), "button_id",
+        ctk_manage_grid_license->radio_btn_vapp = gtk_radio_button_new_with_label(slist, "GRID Virtual Apps");
+        gtk_box_pack_start(GTK_BOX(vbox3), ctk_manage_grid_license->radio_btn_vapp, FALSE, FALSE, 0);
+        g_object_set_data(G_OBJECT(ctk_manage_grid_license->radio_btn_vapp), "button_id",
                 GINT_TO_POINTER(NV_GRID_LICENSE_FEATURE_TYPE_VAPP));
 
-        g_signal_connect(G_OBJECT(button2), "toggled",
+        g_signal_connect(G_OBJECT(ctk_manage_grid_license->radio_btn_vapp), "toggled",
                          G_CALLBACK(license_edition_toggled),
                          (gpointer) ctk_manage_grid_license);
 
@@ -1540,8 +1653,6 @@ GtkWidget* ctk_manage_grid_license_new(CtrlTarget *target,
 
     label = gtk_label_new("Primary Server:");
     ctk_manage_grid_license->txt_server_address = gtk_entry_new();
-    gtk_entry_set_text(GTK_ENTRY(ctk_manage_grid_license->txt_server_address),
-                       griddConfig->str[NV_GRIDD_SERVER_ADDRESS]);
     hbox = gtk_hbox_new(FALSE, 0);
     eventbox = gtk_event_box_new();
     gtk_container_add(GTK_CONTAINER(eventbox), label);
@@ -1577,8 +1688,6 @@ GtkWidget* ctk_manage_grid_license_new(CtrlTarget *target,
 
     /* value */
     ctk_manage_grid_license->txt_server_port = gtk_entry_new();
-    gtk_entry_set_text(GTK_ENTRY(ctk_manage_grid_license->txt_server_port),
-                       griddConfig->str[NV_GRIDD_SERVER_PORT]);
     hbox = gtk_hbox_new(FALSE, 0);
     gtk_box_pack_start(GTK_BOX(hbox),
                        ctk_manage_grid_license->txt_server_port,
@@ -1596,13 +1705,6 @@ GtkWidget* ctk_manage_grid_license_new(CtrlTarget *target,
     label = gtk_label_new("Secondary Server:");
     ctk_manage_grid_license->txt_secondary_server_address = gtk_entry_new();
 
-    /* Disable Secondary server address textbox if Primary server address is empty. */
-    if (strcmp(griddConfig->str[NV_GRIDD_SERVER_ADDRESS], "") == 0) {
-        gtk_widget_set_sensitive(ctk_manage_grid_license->txt_secondary_server_address, FALSE);
-    }
-    gtk_entry_set_text(GTK_ENTRY(ctk_manage_grid_license->txt_secondary_server_address),
-                       griddConfig->str[NV_GRIDD_BACKUP_SERVER_ADDRESS]);
-
     hbox = gtk_hbox_new(FALSE, 0);
     eventbox = gtk_event_box_new();
     gtk_container_add(GTK_CONTAINER(eventbox), label);
@@ -1640,13 +1742,6 @@ GtkWidget* ctk_manage_grid_license_new(CtrlTarget *target,
     /* value */
     ctk_manage_grid_license->txt_secondary_server_port = gtk_entry_new();
 
-    /* Disable Secondary server port textbox if Primary server address is empty. */
-    if (strcmp(griddConfig->str[NV_GRIDD_SERVER_ADDRESS], "") == 0) {
-        gtk_widget_set_sensitive(ctk_manage_grid_license->txt_secondary_server_port, FALSE);
-    }
-    gtk_entry_set_text(GTK_ENTRY(ctk_manage_grid_license->txt_secondary_server_port),
-                       griddConfig->str[NV_GRIDD_BACKUP_SERVER_PORT]);
-
     hbox = gtk_hbox_new(FALSE, 0);
     gtk_box_pack_start(GTK_BOX(hbox),
                        ctk_manage_grid_license->txt_secondary_server_port,
@@ -1687,18 +1782,13 @@ GtkWidget* ctk_manage_grid_license_new(CtrlTarget *target,
                      G_CALLBACK(cancel_clicked),
                      (gpointer) ctk_manage_grid_license);
 
-    /* Set license edition toggle button active */
-    if (button2 && button1) {
-        if (ctk_manage_grid_license->feature_type == NV_GRID_LICENSE_FEATURE_TYPE_QDWS) {
-            /* Set 'Quadro Virtual Datacenter Workstation' toggle button active */
-            gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button1), TRUE);
-        }
-        else {
-            /* Set 'GRID Virtual Apps' toggle button active */
-            gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button2), TRUE);
-        }
-    }
+    /* Update GUI with information from the nvidia-gridd config file */
+    update_gui_from_griddconfig(ctk_manage_grid_license);
+
+    get_licensed_feature_code(ctk_manage_grid_license);
 
+    /* Set the license feature type fetched from nvidia-gridd */
+    ctk_manage_grid_license->gridd_feature_type = ctk_manage_grid_license->feature_type;
 
     /* Register a timer callback to update license status info */
     str = g_strdup_printf("Manage GRID License");
diff --git a/src/gtk+-2.x/ctkgridlicense.h b/src/gtk+-2.x/ctkgridlicense.h
index c72a8ef..42178dc 100644
--- a/src/gtk+-2.x/ctkgridlicense.h
+++ b/src/gtk+-2.x/ctkgridlicense.h
@@ -56,10 +56,13 @@ struct _CtkManageGridLicense
     GtkWidget* txt_server_address;
     GtkWidget* label_license_state;
     GtkWidget* btn_apply;
+    GtkWidget* radio_btn_vapp;
+    GtkWidget* radio_btn_qdws;
     GtkWidget* btn_cancel;
     GtkWidget* box_server_info;
 
     DbusData *dbusData;
+    CtrlTarget *target;
     gint license_edition_state;
     gint feature_type;                      // Feature type from UI/gridd.conf.
     int gridd_feature_type;                 // Feature type fetched from nvidia-gridd.
@@ -82,6 +85,8 @@ typedef enum
     NV_GRID_LICENSE_EXPIRED_VGPU,
     NV_GRID_LICENSE_EXPIRED_QDWS,
     NV_GRID_LICENSE_RESTART_REQUIRED,
+    NV_GRID_LICENSE_RESTART_REQUIRED_VAPP,
+    NV_GRID_UNLICENSED_REQUEST_DETAILS,     // Default case
 } licenseStatus;
 
 struct _CtkManageGridLicenseClass
diff --git a/src/gtk+-2.x/ctkopengl.c b/src/gtk+-2.x/ctkopengl.c
index 30321f1..eb71e29 100644
--- a/src/gtk+-2.x/ctkopengl.c
+++ b/src/gtk+-2.x/ctkopengl.c
@@ -283,20 +283,20 @@ GtkWidget* ctk_opengl_new(CtrlTarget *ctrl_target,
     GtkAdjustment *adjustment;
     GtkWidget *menu;
 
-    gint sync_to_vblank;
-    gint flipping_allowed;
-    gint gsync_allowed;
-    gint show_gsync_visual_indicator;
-    gint force_stereo;
-    gint xinerama_stereo;
-    gint stereo_eyes_exchange;
-    gint stereo_swap_mode;
+    gint sync_to_vblank = 0;
+    gint flipping_allowed = 0;
+    gint gsync_allowed = 0;
+    gint show_gsync_visual_indicator = 0;
+    gint force_stereo = 0;
+    gint xinerama_stereo = 0;
+    gint stereo_eyes_exchange = 0;
+    gint stereo_swap_mode = 0;
     CtrlAttributeValidValues image_settings_valid;
-    gint image_settings_value;
-    gint aa_line_gamma;
-    gint use_conformant_clamping;
-    gint show_sli_visual_indicator;
-    gint show_multigpu_visual_indicator;
+    gint image_settings_value = 0;
+    gint aa_line_gamma = 0;
+    gint use_conformant_clamping = 0;
+    gint show_sli_visual_indicator = 0;
+    gint show_multigpu_visual_indicator = 0;
 
     ReturnStatus ret_sync_to_vblank;
     ReturnStatus ret_flipping_allowed;
diff --git a/src/gtk+-2.x/ctkpowermizer.c b/src/gtk+-2.x/ctkpowermizer.c
index d6eced8..7a2d8b5 100644
--- a/src/gtk+-2.x/ctkpowermizer.c
+++ b/src/gtk+-2.x/ctkpowermizer.c
@@ -385,7 +385,10 @@ static void update_editable_perf_level_info(CtkPowermizer *ctk_powermizer)
                          GTK_FILL, GTK_FILL | GTK_EXPAND, 0, 0);
         col_idx += 2;
     }
-    if (ctk_powermizer->gpu_clock) {
+    
+    /* Show if graphics clock offset available */
+    if (ctk_powermizer->gpu_clock &&
+        ctk_powermizer->nvclock_attribute) {
         /* Graphics clock */
         label = gtk_label_new("Graphics Clock Offset");
         gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f);
@@ -410,7 +413,10 @@ static void update_editable_perf_level_info(CtkPowermizer *ctk_powermizer)
                          GTK_FILL, GTK_FILL | GTK_EXPAND, 0, 0);
         col_idx += 4;
     }
-    if (ctk_powermizer->memory_transfer_rate) {
+    
+    /* Show if memory transfer rate offset available */
+    if (ctk_powermizer->memory_transfer_rate &&
+        ctk_powermizer->mem_transfer_rate_attribute) {
         /* Memory transfer rate */
         label = gtk_label_new("Memory Transfer Rate Offset");
         gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f);
@@ -680,7 +686,7 @@ static void update_perf_mode_table(CtkPowermizer *ctk_powermizer,
                 /* Set hasEditablePerfLevel flag on if overclocking attributes
                  * are available
                  */
-                if (ctk_powermizer->nvclock_attribute &&
+                if (ctk_powermizer->nvclock_attribute ||
                     ctk_powermizer->mem_transfer_rate_attribute) {
                     ctk_powermizer->hasEditablePerfLevel = TRUE;
                 }
@@ -1307,7 +1313,7 @@ GtkWidget* ctk_powermizer_new(CtrlTarget *ctrl_target,
         }
     }
 
-    if ((nvclock_attribute == NV_CTRL_GPU_NVCLOCK_OFFSET_ALL_PERFORMANCE_LEVELS) &&
+    if ((nvclock_attribute == NV_CTRL_GPU_NVCLOCK_OFFSET_ALL_PERFORMANCE_LEVELS) ||
         (mem_transfer_rate_attribute ==
          NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET_ALL_PERFORMANCE_LEVELS)) {
         ctk_powermizer->editable_performance_levels_unified = TRUE;
diff --git a/src/gtk+-2.x/ctkscreen.c b/src/gtk+-2.x/ctkscreen.c
index b7e465d..a452849 100644
--- a/src/gtk+-2.x/ctkscreen.c
+++ b/src/gtk+-2.x/ctkscreen.c
@@ -34,6 +34,9 @@
 #include "ctkutils.h"
 #include "ctkbanner.h"
 
+#include "ctkglwidget.h"
+#include "ctkglstereo.h"
+
 void ctk_screen_event_handler(GtkWidget *widget,
                               CtrlEvent *event,
                               gpointer data);
@@ -131,6 +134,7 @@ GtkWidget* ctk_screen_new(CtrlTarget *ctrl_target, CtkEvent *ctk_event)
     GtkWidget *banner;
     GtkWidget *hseparator;
     GtkWidget *table;
+    GtkWidget *ctk_glstereo;
 
     ReturnStatus ret;
 
@@ -311,6 +315,16 @@ GtkWidget* ctk_screen_new(CtrlTarget *ctrl_target, CtkEvent *ctk_event)
     if (ctk_screen->stereo_available) {
         add_table_row(table, 20, 0, 0, "Stereo Mode:", 0, 0,
                       NvCtrlGetStereoModeName(stereo_mode));
+
+        if (stereo_mode != NV_CTRL_STEREO_OFF) {
+            ctk_glstereo = ctk_glstereo_new();
+            if (ctk_glstereo) {
+                hbox = gtk_hbox_new(FALSE, 0);
+                gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+                gtk_box_pack_start(GTK_BOX(hbox), ctk_glstereo,
+                                   FALSE, FALSE, 0);
+            }
+        }
     }
 
     g_free(screen_number);
diff --git a/src/gtk+-2.x/ctkslimm.c b/src/gtk+-2.x/ctkslimm.c
index 70b5fac..f3024b8 100644
--- a/src/gtk+-2.x/ctkslimm.c
+++ b/src/gtk+-2.x/ctkslimm.c
@@ -120,6 +120,10 @@ static GridConfig gridConfigs[] = {
     {1, 2,  FALSE},
     {4, 1,  FALSE},
     {1, 4,  FALSE},
+    {4, 8,  FALSE},
+    {8, 4,  FALSE},
+    {2, 16, FALSE},
+    {16, 2, FALSE},
 };
 
 GType ctk_slimm_get_type()
diff --git a/src/gtk+-2.x/ctkui.c b/src/gtk+-2.x/ctkui.c
index 9ee0a1c..ce5ef08 100644
--- a/src/gtk+-2.x/ctkui.c
+++ b/src/gtk+-2.x/ctkui.c
@@ -18,10 +18,10 @@
  */
 
 #include <gtk/gtk.h>
-#include <gdk-pixbuf/gdk-pixdata.h>
 #include "ctkui.h"
 #include "ctkwindow.h"
-#include "nvidia_icon_pixdata.h"
+#include "ctkutils.h"
+#include "nvidia_icon.png.h"
 /*
  * This source file provides thin wrappers over the gtk routines, so
  * that nvidia-settings.c doesn't need to include gtk+
@@ -47,7 +47,7 @@ void ctk_main(ParsedAttribute *p,
     GList *list = NULL;
     GtkWidget *window;
 
-    list = g_list_append (list, gdk_pixbuf_from_pixdata(&nvidia_icon_pixdata, TRUE, NULL));
+    list = g_list_append (list, CTK_LOAD_PIXBUF(nvidia_icon));
     gtk_window_set_default_icon_list(list);
     window = ctk_window_new(p, conf, system);
 
diff --git a/src/gtk+-2.x/ctkutils.c b/src/gtk+-2.x/ctkutils.c
index a05129d..65ee75a 100644
--- a/src/gtk+-2.x/ctkutils.c
+++ b/src/gtk+-2.x/ctkutils.c
@@ -19,6 +19,9 @@
 
 #include <stdlib.h>
 #include <gtk/gtk.h>
+#ifdef CTK_GTK3
+#include <gio/gio.h>
+#endif
 #include <NvCtrlAttributes.h>
 #include "NVCtrlLib.h"
 #include "ctkutils.h"
@@ -827,4 +830,34 @@ char *ctk_get_filename_from_dialog(const gchar* title,
     return filename;
 }
 
+GdkPixbuf *ctk_pixbuf_from_data(const char *start, const char *end)
+{
+    GdkPixbuf *pixbuf = NULL;
+    size_t size = end - start;
+
+#ifdef CTK_GTK3
+    GInputStream *stream =
+        g_memory_input_stream_new_from_data(start, size, NULL);
+
+    if (stream) {
+        pixbuf = gdk_pixbuf_new_from_stream(stream, NULL, NULL);
 
+        g_object_unref(stream);
+    }
+#else
+    GdkPixbufLoader *loader = gdk_pixbuf_loader_new();
+
+    if (loader) {
+        gdk_pixbuf_loader_write(loader, (const void*)start, size, NULL);
+        gdk_pixbuf_loader_close(loader, NULL);
+
+        pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
+        if (pixbuf) {
+            g_object_ref(pixbuf);
+        }
+
+        g_object_unref(loader);
+    }
+#endif
+    return pixbuf;
+}
diff --git a/src/gtk+-2.x/ctkutils.h b/src/gtk+-2.x/ctkutils.h
index bf3949d..a4d8fb9 100644
--- a/src/gtk+-2.x/ctkutils.h
+++ b/src/gtk+-2.x/ctkutils.h
@@ -125,6 +125,8 @@ void ctk_force_text_colors_on_widget(GtkWidget *widget);
 gchar *ctk_get_filename_from_dialog(const gchar* title,
                                     GtkWindow *parent,
                                     const gchar* initial_filename);
+GdkPixbuf *ctk_pixbuf_from_data(const char *start, const char *end);
+#define CTK_LOAD_PIXBUF(art) ctk_pixbuf_from_data(_binary_##art##_png_start, _binary_##art##_png_end)
 
 G_END_DECLS
 
diff --git a/src/gtk+-2.x/ctkwindow.c b/src/gtk+-2.x/ctkwindow.c
index bff0775..da06ddd 100644
--- a/src/gtk+-2.x/ctkwindow.c
+++ b/src/gtk+-2.x/ctkwindow.c
@@ -26,6 +26,7 @@
 
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
+#include <gdk/gdkx.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -72,6 +73,7 @@
 #include "common-utils.h"
 #include "query-assign.h"
 
+#include "opengl_loading.h"
 
 /* column enumeration */
 
@@ -1343,6 +1345,20 @@ static GtkWidget *create_quit_dialog(CtkWindow *ctk_window)
 
 static void save_settings_and_exit(CtkWindow *ctk_window)
 {
+#ifdef CTK_GTK3
+    GdkDisplay *gdk_display;
+    Display *display;
+    GdkScreen *gdk_screen;
+
+    if (dGL.glXMakeContextCurrent) {
+        gdk_screen = gtk_window_get_screen(GTK_WINDOW(ctk_window));
+        gdk_display = gdk_screen_get_display(gdk_screen);
+        display = gdk_x11_display_get_xdisplay(gdk_display);
+        dGL.glXMakeContextCurrent(display, 0, 0, 0);
+    }
+
+#endif
+
     add_special_config_file_attributes(ctk_window);
     gtk_main_quit();
 }
diff --git a/src/gtk+-2.x/ctkxvideo.c b/src/gtk+-2.x/ctkxvideo.c
index d48b6be..68ea0c3 100644
--- a/src/gtk+-2.x/ctkxvideo.c
+++ b/src/gtk+-2.x/ctkxvideo.c
@@ -229,9 +229,6 @@ static GtkWidget *xv_sync_to_display_radio_button_add(CtkXVideo *ctk_xvideo,
                      G_CALLBACK(xv_sync_to_display_id_toggled),
                      (gpointer) ctk_xvideo);
 
-    ctk_config_set_tooltip(ctk_xvideo->ctk_config, button,
-                           __xv_sync_to_display_help);
-
     return button;
 }
 
@@ -281,6 +278,8 @@ static void xv_sync_to_display_rebuild_buttons(CtkXVideo *ctk_xvideo,
     }
 
 
+    ctk_xvideo->active_attributes |= __XV_SYNC_TO_DISPLAY;
+
     /* Add a button for No Display Specified */
     last_button = NULL;
     button = xv_sync_to_display_radio_button_add(ctk_xvideo, NULL,
@@ -548,6 +547,10 @@ GtkWidget* ctk_xvideo_new(CtrlTarget *ctrl_target,
     gtk_container_add(GTK_CONTAINER(frame), vbox);
     ctk_xvideo->xv_sync_to_display_button_box = vbox;
 
+    ctk_config_set_tooltip(ctk_xvideo->ctk_config,
+                           ctk_xvideo->xv_sync_to_display_button_box,
+                           __xv_sync_to_display_help);
+
     xv_sync_to_display_rebuild_buttons(ctk_xvideo, FALSE);
 
     g_signal_connect(G_OBJECT(ctk_event),
diff --git a/src/gtk+-2.x/matrix_utils.c b/src/gtk+-2.x/matrix_utils.c
new file mode 100644
index 0000000..3667843
--- /dev/null
+++ b/src/gtk+-2.x/matrix_utils.c
@@ -0,0 +1,122 @@
+/*
+ * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix
+ * and Linux systems.
+ *
+ * Copyright (C) 2017 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses>.
+ */
+
+#include <math.h>
+#include <string.h>
+
+#include "matrix_utils.h"
+
+void matrixMult(float a[16], const float b[16])
+{
+    int i, j, k;
+    float aa[16];
+
+    memcpy(aa, a, sizeof(aa));
+    memset(a, 0, 16 * sizeof(float));
+
+    for (j = 0; j < 4; j++) {
+        for (i = 0; i < 4; i++) {
+            for (k = 0; k < 4; k++) {
+                a[4 * j + i] += aa[4 * j + k] * b[4 * k + i];
+            }
+        }
+    }
+}
+
+void matrixTranspose(float m[16])
+{
+    int i, j;
+    float tmp;
+
+    for (j = 0; j < 4; ++j) {
+        for (i = 0; i < j; ++i) {
+            tmp = m[4 * j + i];
+            m[4 * j + i] = m[4 * i + j];
+            m[4 * i + j] = tmp;
+        }
+    }
+}
+
+void genZeroMatrix(float matrix[16])
+{
+    memset(matrix, 0, 16 * sizeof(float));
+}
+
+void genIdentityMatrix(float matrix[16])
+{
+    genZeroMatrix(matrix);
+    matrix[0]  = 1;
+    matrix[5]  = 1;
+    matrix[10] = 1;
+    matrix[15] = 1;
+}
+
+void genTranslateMatrix(float x, float y, float z, float matrix[16])
+{
+    genIdentityMatrix(matrix);
+    matrix[12] = x;
+    matrix[13] = y;
+    matrix[14] = z;
+}
+
+void genRotateMatrixX(float radians, float matrix[16])
+{
+    genIdentityMatrix(matrix);
+    matrix[5]  = cosf(radians);
+    matrix[6]  = -1 * sinf(radians);
+    matrix[9]  = sinf(radians);
+    matrix[10] = cosf(radians);
+}
+
+void genRotateMatrixY(float radians, float matrix[16])
+{
+    genIdentityMatrix(matrix);
+    matrix[0]  = cosf(radians);
+    matrix[2]  = -1 * sinf(radians);
+    matrix[8]  = sinf(radians);
+    matrix[10] = cosf(radians);
+}
+
+void genRotateMatrixZ(float radians, float matrix[16])
+{
+    genIdentityMatrix(matrix);
+    matrix[0]  = cosf(radians);
+    matrix[1]  = sinf(radians);
+    matrix[4]  = -1 * sinf(radians);
+    matrix[5]  = cosf(radians);
+}
+
+void genPerspectiveMatrix(float fovY,
+                          float aspect,
+                          float zNear,
+                          float zFar,
+                          float matrix[16])
+{
+    float f;
+
+    f = 1 / tanf(fovY / 2);
+
+    genZeroMatrix(matrix);
+    matrix[0]  = f / aspect;
+    matrix[5]  = f;
+    matrix[10] = (zFar + zNear) / (zNear - zFar);
+    matrix[11] = 2 * zFar * zNear / (zNear - zFar);
+    matrix[14] = -1;
+}
+
diff --git a/src/gtk+-2.x/matrix_utils.h b/src/gtk+-2.x/matrix_utils.h
new file mode 100644
index 0000000..822702d
--- /dev/null
+++ b/src/gtk+-2.x/matrix_utils.h
@@ -0,0 +1,39 @@
+/*
+ * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix
+ * and Linux systems.
+ *
+ * Copyright (C) 2017 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses>.
+ */
+
+#ifndef __MATRIX_UTILS_H__
+#define __MATRIX_UTILS_H__
+
+void matrixMult(float a[16], const float b[16]);
+void matrixTranspose(float m[16]);
+
+void genZeroMatrix(float matrix[16]);
+void genIdentityMatrix(float matrix[16]);
+
+void genTranslateMatrix(float x, float y, float z, float matrix[16]);
+void genRotateMatrixX(float radians, float matrix[16]);
+void genRotateMatrixY(float radians, float matrix[16]);
+void genRotateMatrixZ(float radians, float matrix[16]);
+void genPerspectiveMatrix(float fovY,
+                          float aspect,
+                          float zNear,
+                          float zFar,
+                          float matrix[16]);
+
+#endif /*__MATRIX_UTILS_H__*/
diff --git a/src/gtk+-2.x/opengl_loading.c b/src/gtk+-2.x/opengl_loading.c
new file mode 100644
index 0000000..1e3454e
--- /dev/null
+++ b/src/gtk+-2.x/opengl_loading.c
@@ -0,0 +1,104 @@
+/*
+ * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix
+ * and Linux systems.
+ *
+ * Copyright (C) 2017 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses>.
+ */
+
+#include <stdio.h>
+#include <GL/glx.h>
+#include <dlfcn.h>
+#include "opengl_loading.h"
+
+libGLData dGL;
+
+#define LOAD_GL_FUNCTION(func) \
+    dGL.func = dGL.glXGetProcAddress((const GLubyte *) #func); \
+    if (dGL.func == NULL) { \
+        fprintf(stderr, "Failed to load " #func "\n"); \
+        return GL_FALSE; \
+    }
+
+GLboolean loadGL(void)
+{
+    dGL.handle = dlopen("libGL.so.1", RTLD_LAZY);
+    if (dGL.handle == NULL) {
+        return GL_FALSE;
+    }
+
+    dGL.glXGetProcAddress = dlsym(dGL.handle, "glXGetProcAddress");
+    if (dGL.glXGetProcAddress == NULL) {
+        return GL_FALSE;
+    }
+
+    LOAD_GL_FUNCTION(glGetString)
+    LOAD_GL_FUNCTION(glGetIntegerv)
+    LOAD_GL_FUNCTION(glGetStringi)
+
+    LOAD_GL_FUNCTION(glXCreateNewContext)
+    LOAD_GL_FUNCTION(glXDestroyContext)
+    LOAD_GL_FUNCTION(glXMakeContextCurrent)
+    LOAD_GL_FUNCTION(glXSwapBuffers)
+    LOAD_GL_FUNCTION(glXChooseFBConfig)
+    LOAD_GL_FUNCTION(glXGetFBConfigAttrib)
+    LOAD_GL_FUNCTION(glXGetProcAddress)
+    LOAD_GL_FUNCTION(glXCreateWindow)
+    LOAD_GL_FUNCTION(glXGetVisualFromFBConfig)
+
+    LOAD_GL_FUNCTION(glBindTexture)
+    LOAD_GL_FUNCTION(glBlendFunc)
+    LOAD_GL_FUNCTION(glClear)
+    LOAD_GL_FUNCTION(glClearColor)
+    LOAD_GL_FUNCTION(glClearDepth)
+    LOAD_GL_FUNCTION(glDepthFunc)
+    LOAD_GL_FUNCTION(glDepthMask)
+    LOAD_GL_FUNCTION(glDrawArrays)
+    LOAD_GL_FUNCTION(glDrawBuffer)
+    LOAD_GL_FUNCTION(glEnable)
+    LOAD_GL_FUNCTION(glGenTextures)
+    LOAD_GL_FUNCTION(glGetError)
+    LOAD_GL_FUNCTION(glPixelStorei)
+    LOAD_GL_FUNCTION(glTexImage2D)
+    LOAD_GL_FUNCTION(glTexParameteri)
+    LOAD_GL_FUNCTION(glViewport)
+    LOAD_GL_FUNCTION(glAttachShader)
+    LOAD_GL_FUNCTION(glBindBuffer)
+    LOAD_GL_FUNCTION(glBindVertexArray)
+    LOAD_GL_FUNCTION(glBufferData)
+    LOAD_GL_FUNCTION(glCompileShader)
+    LOAD_GL_FUNCTION(glCreateProgram)
+    LOAD_GL_FUNCTION(glCreateShader)
+    LOAD_GL_FUNCTION(glDeleteShader)
+    LOAD_GL_FUNCTION(glEnableVertexAttribArray)
+    LOAD_GL_FUNCTION(glGenBuffers)
+    LOAD_GL_FUNCTION(glGenVertexArrays)
+    LOAD_GL_FUNCTION(glGetProgramiv)
+    LOAD_GL_FUNCTION(glGetShaderInfoLog)
+    LOAD_GL_FUNCTION(glGetShaderiv)
+    LOAD_GL_FUNCTION(glLinkProgram)
+    LOAD_GL_FUNCTION(glShaderSource)
+    LOAD_GL_FUNCTION(glUniform4f)
+    LOAD_GL_FUNCTION(glUniformMatrix4fv)
+    LOAD_GL_FUNCTION(glUseProgram)
+    LOAD_GL_FUNCTION(glVertexAttribPointer)
+    LOAD_GL_FUNCTION(glGetUniformLocation)
+
+    return GL_TRUE;
+}
+
+void closeDynamicGL(void)
+{
+    dlclose(dGL.handle);
+}
diff --git a/src/gtk+-2.x/opengl_loading.h b/src/gtk+-2.x/opengl_loading.h
new file mode 100644
index 0000000..1afbc73
--- /dev/null
+++ b/src/gtk+-2.x/opengl_loading.h
@@ -0,0 +1,90 @@
+/*
+ * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix
+ * and Linux systems.
+ *
+ * Copyright (C) 2017 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses>.
+ */
+
+#ifndef __OPENGL_LOADING_H__
+#define __OPENGL_LOADING_H__
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+typedef struct _libGLData libGLData;
+struct _libGLData {
+
+    void *handle;
+
+    const GLubyte *(*glGetString)   (GLenum);
+    const GLubyte *(*glGetStringi)  (GLenum, GLuint);
+    void           (*glGetIntegerv) (GLenum, GLint *);
+
+    // GLX function pointers
+    GLXContext     (*glXCreateNewContext)       (Display *, GLXFBConfig, int, GLXContext,Bool);
+    void           (*glXDestroyContext)         (Display *, GLXContext);
+    Bool           (*glXMakeContextCurrent)     (Display *, GLXDrawable, GLXDrawable, GLXContext);
+    void           (*glXSwapBuffers)            (Display *, GLXDrawable);
+    GLXFBConfig   *(*glXChooseFBConfig)         (Display *, int, const int * , int *);
+    int            (*glXGetFBConfigAttrib)      (Display *, GLXFBConfig, int, int *);
+    void          *(*glXGetProcAddress)         (const GLubyte *);
+    GLXWindow      (*glXCreateWindow)           (Display *, GLXFBConfig, Window win, const int *);
+    XVisualInfo*   (*glXGetVisualFromFBConfig)  (Display *, GLXFBConfig);
+
+    void           (*glBindTexture)             (GLenum, GLuint);
+    void           (*glBlendFunc)               (GLenum, GLenum);
+    void           (*glClear)                   (GLbitfield);
+    void           (*glClearColor)              (GLclampf, GLclampf, GLclampf, GLclampf);
+    void           (*glClearDepth)              (GLdouble);
+    void           (*glDepthFunc)               (GLenum);
+    void           (*glDepthMask)               (GLboolean);
+    void           (*glDrawArrays)              (GLenum, GLint, GLsizei);
+    void           (*glDrawBuffer)              (GLenum);
+    void           (*glEnable)                  (GLenum);
+    void           (*glGenTextures)             (GLsizei, GLuint *);
+    GLenum         (*glGetError)                (void);
+    void           (*glPixelStorei)             (GLenum, GLint);
+    void           (*glTexImage2D)              (GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
+    void           (*glTexParameteri)           (GLenum, GLenum, GLint);
+    void           (*glViewport)                (GLint, GLint, GLsizei, GLsizei);
+    void           (*glAttachShader)            (GLuint, GLuint);
+    void           (*glBindBuffer)              (GLenum, GLuint);
+    void           (*glBindVertexArray)         (GLuint);
+    void           (*glBufferData)              (GLenum, GLsizeiptr, const GLvoid *, GLenum);
+    void           (*glCompileShader)           (GLuint);
+    GLuint         (*glCreateProgram)           (void);
+    GLuint         (*glCreateShader)            (GLenum);
+    void           (*glDeleteShader)            (GLuint);
+    void           (*glEnableVertexAttribArray) (GLuint);
+    void           (*glGenBuffers)              (GLsizei, GLuint *);
+    void           (*glGenVertexArrays)         (GLsizei, GLuint *);
+    void           (*glGetProgramiv)            (GLuint, GLenum, GLint *);
+    void           (*glGetShaderInfoLog)        (GLuint, GLsizei, GLsizei *, GLchar *);
+    void           (*glGetShaderiv)             (GLuint, GLenum, GLint *);
+    void           (*glLinkProgram)             (GLuint);
+    void           (*glShaderSource)            (GLuint, GLsizei, const GLchar* const *, const GLint *);
+    void           (*glUniform4f)               (GLint, GLfloat, GLfloat, GLfloat, GLfloat);
+    void           (*glUniformMatrix4fv)        (GLint, GLsizei, GLboolean, const GLfloat *);
+    void           (*glUseProgram)              (GLuint);
+    void           (*glVertexAttribPointer)     (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *);
+    GLint          (*glGetUniformLocation)      (GLuint, const GLchar *);
+
+};
+
+extern libGLData dGL;
+void closeDynamicGL(void);
+GLboolean loadGL(void);
+
+#endif /* __OPENGL_LOADING_H__ */
diff --git a/src/gtk+-2.x/opengl_wrappers.c b/src/gtk+-2.x/opengl_wrappers.c
new file mode 100644
index 0000000..7ce2323
--- /dev/null
+++ b/src/gtk+-2.x/opengl_wrappers.c
@@ -0,0 +1,410 @@
+/*
+ * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix
+ * and Linux systems.
+ *
+ * Copyright (C) 2017 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses>.
+ */
+
+#include "ctkutils.h"
+
+#ifdef CTK_GTK3
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "opengl_loading.h"
+#include "opengl_wrappers.h"
+#include "matrix_utils.h"
+
+GLchar const * const cubeVertexShaderSource[] =
+{
+    "#version 450 core\n"
+    "in  vec3 xyz;\n"
+    "in  vec2 uv;\n"
+    "out vec2 uvFromV;\n"
+    "uniform mat4 mvp;\n"
+    "void main(void)\n"
+    "{\n"
+    "    gl_Position =  vec4(xyz, 1) * mvp;\n"
+    "    uvFromV = uv;\n"
+    "}\n"
+};
+
+GLchar const * const cubeFragmentShaderSource[] =
+{
+    "#version 450 core\n"
+    "out vec4 color;\n"
+    "in vec2 uvFromV;\n"
+    "uniform sampler2D textureSampler;\n"
+    "void main(void)\n"
+    "{\n"
+    "    color = texture(textureSampler, uvFromV);\n"
+    "    if (color.a == 0) {\n"
+    "        color = vec4(0, 0, 0, 1);\n"
+    "    }\n"
+    "}\n"
+};
+
+GLchar const * const  textVertexShaderSource[] =
+{
+    "#version 450 core\n"
+    "in  vec3 xyz;\n"
+    "in  vec2 uv;\n"
+    "out vec2 uvFromV;\n"
+    "uniform vec4 textColor;\n"
+    "void main(void)\n"
+    "{\n"
+    "    gl_Position =  vec4(xyz, 1);\n"
+    "    uvFromV = uv;\n"
+    "}\n"
+};
+
+GLchar const * const textFragmentShaderSource[] =
+{
+    "#version 450 core\n"
+    "out vec4 color;\n"
+    "in vec2 uvFromV;\n"
+    "uniform sampler2D textureSampler;\n"
+    "uniform vec4 textColor;\n"
+    "void main(void)\n"
+    "{\n"
+    "    color = texture(textureSampler, uvFromV);\n"
+    "    color.rgb = textColor.rgb;\n"
+    "}\n"
+};
+
+void freeOglmd(OpenGLModelData *p)
+{
+    if (p) {
+            free(p->uniforms);
+            p->uniforms = NULL;
+            free(p->mvp);
+            p->mvp = NULL;
+    }
+    free(p);
+    p = NULL;
+}
+
+static GLboolean verifyShaderCompilation(GLuint shader)
+{
+    GLint status;
+    char compilationLog[2048];
+
+    dGL.glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+    if (!status) {
+        dGL.glGetShaderInfoLog(shader, 2000, NULL, compilationLog);
+        fprintf(stderr, "Shader compilation failed for shaderID=%i\n", shader);
+        fprintf(stderr, "Error message:\n");
+        fprintf(stderr, "%s\n", compilationLog);
+        return GL_FALSE;
+    }
+    return GL_TRUE;
+}
+
+static GLuint makeProgram(char const * const * vertexShaderSource,
+                          char const * const * fragmentShaderSource)
+{
+    GLuint program, vertexShader, fragmentShader;
+    GLint status;
+
+    vertexShader = dGL.glCreateShader(GL_VERTEX_SHADER);
+    dGL.glShaderSource(vertexShader, 1, vertexShaderSource, NULL);
+    dGL.glCompileShader(vertexShader);
+    if (!verifyShaderCompilation(vertexShader)) {
+        return 0;
+    }
+
+    fragmentShader = dGL.glCreateShader(GL_FRAGMENT_SHADER);
+    dGL.glShaderSource(fragmentShader, 1, fragmentShaderSource, NULL);
+    dGL.glCompileShader(fragmentShader);
+    if (!verifyShaderCompilation(fragmentShader)) {
+        return 0;
+    }
+
+    program = dGL.glCreateProgram();
+    dGL.glAttachShader(program, vertexShader);
+    dGL.glAttachShader(program, fragmentShader);
+
+    dGL.glDeleteShader(vertexShader);
+    dGL.glDeleteShader(fragmentShader);
+
+    dGL.glLinkProgram(program);
+
+    dGL.glGetProgramiv(program, GL_LINK_STATUS, &status);
+    if (!status) {
+        fprintf(stderr, "Link failed for programID=%i\n",program);
+        return 0;
+    }
+    return program;
+}
+
+void drawModel(OpenGLModelData *data)
+{
+    int i;
+
+    dGL.glBindVertexArray(data->vao);
+    dGL.glBindTexture(GL_TEXTURE_2D, data->tex);
+    dGL.glUseProgram(data->program);
+
+    for (i = 0; i < data->uniformCount; i++) {
+        dGL.glUniform4f(data->uniforms[i].index,
+                        data->uniforms[i].data[0],
+                        data->uniforms[i].data[1],
+                        data->uniforms[i].data[2],
+                        data->uniforms[i].data[3]);
+    }
+
+    if (data->mvp != NULL) {
+        // This functions expects the mvp to be row-major, openGL internally
+        // uses column major, so we set the transpose parameter to GL_TRUE
+        dGL.glUniformMatrix4fv(dGL.glGetUniformLocation(data->program, "mvp"),
+                               1, GL_TRUE, data->mvp);
+    }
+
+    dGL.glDrawArrays(GL_TRIANGLES, 0, data->vboLen / 3);
+}
+
+static GLuint drawModelSetup(float *modelData,
+                             unsigned int modelDataLen,
+                             float *textureCoordinates,
+                             unsigned int textureCoordinatesLen)
+{
+    GLuint vao;
+    GLuint vertexBuffer, uvBuffer;
+
+    dGL.glGenVertexArrays(1, &vao);
+    dGL.glBindVertexArray(vao);
+
+    dGL.glGenBuffers(1, &vertexBuffer);
+    dGL.glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
+    dGL.glBufferData(GL_ARRAY_BUFFER, modelDataLen * sizeof(float),
+                     modelData, GL_STATIC_DRAW);
+    dGL.glEnableVertexAttribArray(0);
+    dGL.glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
+
+    dGL.glGenBuffers(1, &uvBuffer);
+    dGL.glBindBuffer(GL_ARRAY_BUFFER, uvBuffer);
+    dGL.glBufferData(GL_ARRAY_BUFFER, textureCoordinatesLen * sizeof(float),
+                     textureCoordinates, GL_STATIC_DRAW);
+    dGL.glEnableVertexAttribArray(1);
+    dGL.glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
+
+    return vao;
+}
+
+static GLuint textureSetup(int textureWidth, int textureHeight,
+                           void *textureDataRaw32)
+{
+    GLuint texName;
+    dGL.glGenTextures(1, &texName);
+    dGL.glBindTexture(GL_TEXTURE_2D, texName);
+    dGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+    dGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+    dGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    dGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    dGL.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
+                     textureWidth, textureHeight,
+                     0, GL_RGBA, GL_UNSIGNED_BYTE, textureDataRaw32);
+
+    return texName;
+}
+
+OpenGLModelData *cubeSetup(GdkPixbuf *image)
+{
+    OpenGLModelData *cube;
+
+    float d = 1;
+    int tmp;
+
+    float modelData[] =  {
+        -d / 2,  d / 2, -d / 2, // 1
+         d / 2,  d / 2, -d / 2, // 2
+        -d / 2, -d / 2, -d / 2, // 3
+         d / 2, -d / 2, -d / 2, // 4
+        -d / 2, -d / 2, -d / 2, // 5
+         d / 2,  d / 2, -d / 2, // 6
+
+        -d / 2,  d / 2,  d / 2, // 7
+        -d / 2,  d / 2, -d / 2, // 8
+        -d / 2, -d / 2,  d / 2, // 9
+        -d / 2, -d / 2, -d / 2, // 10
+        -d / 2, -d / 2,  d / 2, // 11
+        -d / 2,  d / 2, -d / 2, // 12
+
+        -d / 2,  d / 2,  d / 2, // 13
+         d / 2,  d / 2,  d / 2, // 14
+        -d / 2,  d / 2, -d / 2, // 15
+         d / 2,  d / 2, -d / 2, // 16
+        -d / 2,  d / 2, -d / 2, // 17
+         d / 2,  d / 2,  d / 2, // 18
+
+         d / 2,  d / 2, -d / 2, // 19
+         d / 2,  d / 2,  d / 2, // 20
+         d / 2, -d / 2, -d / 2, // 21
+         d / 2, -d / 2,  d / 2, // 22
+         d / 2, -d / 2, -d / 2, // 23
+         d / 2,  d / 2,  d / 2, // 24
+
+        -d / 2, -d / 2, -d / 2, // 25
+         d / 2, -d / 2, -d / 2, // 26
+        -d / 2, -d / 2,  d / 2, // 27
+         d / 2, -d / 2,  d / 2, // 28
+        -d / 2, -d / 2,  d / 2, // 29
+         d / 2, -d / 2, -d / 2, // 30
+
+         d / 2,  d / 2,  d / 2, // 31
+        -d / 2,  d / 2,  d / 2, // 32
+         d / 2, -d / 2,  d / 2, // 33
+        -d / 2, -d / 2,  d / 2, // 34
+         d / 2, -d / 2,  d / 2, // 35
+        -d / 2,  d / 2,  d / 2, // 36
+
+    };
+
+    float textureCoordinates[] = {
+        0, 1,
+        1, 1,
+        0, 0,
+        1, 0,
+        0, 0,
+        1, 1,
+
+        0, 1,
+        1, 1,
+        0, 0,
+        1, 0,
+        0, 0,
+        1, 1,
+
+        0, 1,
+        1, 1,
+        0, 0,
+        1, 0,
+        0, 0,
+        1, 1,
+
+        0, 1,
+        1, 1,
+        0, 0,
+        1, 0,
+        0, 0,
+        1, 1,
+
+        0, 1,
+        1, 1,
+        0, 0,
+        1, 0,
+        0, 0,
+        1, 1,
+
+        0, 1,
+        1, 1,
+        0, 0,
+        1, 0,
+        0, 0,
+        1, 1,
+    };
+
+    tmp = makeProgram(cubeVertexShaderSource, cubeFragmentShaderSource);
+
+    if (tmp == 0) {
+        return NULL;
+    }
+
+    cube = malloc(sizeof(OpenGLModelData));
+    memset(cube, 0, sizeof(OpenGLModelData));
+
+    cube->program = (GLuint) tmp;
+
+    // 6 sides in a cube
+    // 2 triangles per side
+    // 3 vertices per triangle
+    // 3 vertex  coordinates per vertex
+    // 2 texture coordinates per vertex
+    cube->vboLen = 6 * 2 * 3 * 3;
+    cube->vao = drawModelSetup(modelData, cube->vboLen,
+                               textureCoordinates, cube->vboLen / 3 * 2);
+
+    cube->tex  = textureSetup(gdk_pixbuf_get_width(image),
+                              gdk_pixbuf_get_height(image),
+                              gdk_pixbuf_get_pixels(image));
+
+    cube->mvp = malloc(16 * sizeof(float));
+    genIdentityMatrix(cube->mvp);
+
+    return cube;
+}
+
+OpenGLModelData *labelSetup(float x, float y,
+                            float width, float height,
+                            float red, float green, float blue,
+                            GdkPixbuf *image)
+{
+    OpenGLModelData *label;
+    int tmp;
+
+    float modelData[] =  {
+        -width/2 + x,  height/2 + y, 0, // 1
+         width/2 + x,  height/2 + y, 0, // 2
+        -width/2 + x, -height/2 + y, 0, // 3
+         width/2 + x, -height/2 + y, 0, // 4
+        -width/2 + x, -height/2 + y, 0, // 5
+         width/2 + x,  height/2 + y, 0, // 6
+    };
+
+    float textureCoordinates[] = {
+        0, 0,
+        1, 0,
+        0, 1,
+        1, 1,
+        0, 1,
+        1, 0,
+    };
+
+    tmp = makeProgram(textVertexShaderSource, textFragmentShaderSource);
+    if (tmp == 0) {
+        return NULL;
+    }
+
+    label = malloc(sizeof(OpenGLModelData));
+    memset(label, 0, sizeof(OpenGLModelData));
+
+    label->program = (GLuint) tmp;
+
+    // 2 triangles
+    // 3 vertices per triangle
+    // 3 vertex coordinates per vertex
+    // 2 texture coordinates per vertex
+    label->vboLen = 2 * 3 * 3;
+    label->vao = drawModelSetup(modelData, label->vboLen,
+                 textureCoordinates, label->vboLen/3 * 2);
+
+    label->tex = textureSetup(gdk_pixbuf_get_width(image),
+                              gdk_pixbuf_get_height(image),
+                              gdk_pixbuf_get_pixels(image));
+
+    label->uniformCount = 1;
+    label->uniforms = malloc(label->uniformCount * sizeof(uniformVec4f));
+    label->uniforms[0].index = dGL.glGetUniformLocation(label->program, "textColor");
+    label->uniforms[0].data[0] = red;
+    label->uniforms[0].data[1] = green;
+    label->uniforms[0].data[2] = blue;
+    label->uniforms[0].data[3] = 0;
+
+    return label;
+}
+
+#endif
diff --git a/src/gtk+-2.x/opengl_wrappers.h b/src/gtk+-2.x/opengl_wrappers.h
new file mode 100644
index 0000000..17ecd18
--- /dev/null
+++ b/src/gtk+-2.x/opengl_wrappers.h
@@ -0,0 +1,68 @@
+/*
+ * nvidia-settings: A tool for configuring the NVIDIA X driver on Unix
+ * and Linux systems.
+ *
+ * Copyright (C) 2017 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses>.
+ */
+
+#ifndef __OPENGL_WRAPPERS_H__
+#define __OPENGL_WRAPPERS_H__
+
+#include "ctkutils.h"
+
+#ifdef CTK_GTK3
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <GL/gl.h>
+
+typedef struct _uniformVec4f uniformVec4f;
+struct _uniformVec4f
+{
+    GLuint index;
+    float data[4];
+};
+
+typedef struct _OpenGLModelData OpenGLModelData;
+struct _OpenGLModelData
+{
+    GLuint vao;
+    int vboLen;
+    GLuint tex;
+    GLuint program;
+    float *mvp;
+    uniformVec4f *uniforms;
+    int uniformCount;
+};
+
+void freeOglmd(OpenGLModelData *p);
+
+extern char const * const cubeVertexShaderSource[1];
+extern char const * const cubeFragmentShaderSource[1];
+extern char const * const textVertexShaderSource[1];
+extern char const * const textFragmentShaderSource[1];
+
+void drawModel(OpenGLModelData *data);
+
+OpenGLModelData *cubeSetup(GdkPixbuf *image);
+
+OpenGLModelData *labelSetup(float x, float y,
+                            float width, float height,
+                            float red, float green, float blue,
+                            GdkPixbuf *image);
+
+#endif
+
+#endif /*__OPENGL_WRAPPERS_H__*/
+
diff --git a/src/image_data/antialias.png b/src/image_data/antialias.png
index 401976a..7a90c10 100644
Binary files a/src/image_data/antialias.png and b/src/image_data/antialias.png differ
diff --git a/src/image_data/background.png b/src/image_data/background.png
index 4f6245f..5f7a295 100644
Binary files a/src/image_data/background.png and b/src/image_data/background.png differ
diff --git a/src/image_data/background_tall.png b/src/image_data/background_tall.png
index 93e1030..5b6cb12 100644
Binary files a/src/image_data/background_tall.png and b/src/image_data/background_tall.png differ
diff --git a/src/image_data/bnc_cable.png b/src/image_data/bnc_cable.png
index 8f7b9a2..74603f7 100644
Binary files a/src/image_data/bnc_cable.png and b/src/image_data/bnc_cable.png differ
diff --git a/src/image_data/bsd.png b/src/image_data/bsd.png
index 5a01458..5a0700a 100644
Binary files a/src/image_data/bsd.png and b/src/image_data/bsd.png differ
diff --git a/src/image_data/clock.png b/src/image_data/clock.png
index acf5265..de768e0 100644
Binary files a/src/image_data/clock.png and b/src/image_data/clock.png differ
diff --git a/src/image_data/color.png b/src/image_data/color.png
index b956adc..939ba3f 100644
Binary files a/src/image_data/color.png and b/src/image_data/color.png differ
diff --git a/src/image_data/config.png b/src/image_data/config.png
index 570efd8..0e24e0f 100644
Binary files a/src/image_data/config.png and b/src/image_data/config.png differ
diff --git a/src/image_data/crt.png b/src/image_data/crt.png
index 6b1e559..fc243bf 100644
Binary files a/src/image_data/crt.png and b/src/image_data/crt.png differ
diff --git a/src/image_data/dfp.png b/src/image_data/dfp.png
index 1a661a5..faa215b 100644
Binary files a/src/image_data/dfp.png and b/src/image_data/dfp.png differ
diff --git a/src/image_data/display_config.png b/src/image_data/display_config.png
index 6f36ea3..2a20a30 100644
Binary files a/src/image_data/display_config.png and b/src/image_data/display_config.png differ
diff --git a/src/image_data/framelock.png b/src/image_data/framelock.png
index 842cbd6..ebf1a4f 100644
Binary files a/src/image_data/framelock.png and b/src/image_data/framelock.png differ
diff --git a/src/image_data/glx.png b/src/image_data/glx.png
index 710a5ae..a2df4db 100644
Binary files a/src/image_data/glx.png and b/src/image_data/glx.png differ
diff --git a/src/image_data/gpu.png b/src/image_data/gpu.png
index adc3782..f160e60 100644
Binary files a/src/image_data/gpu.png and b/src/image_data/gpu.png differ
diff --git a/src/image_data/help.png b/src/image_data/help.png
index 05002cf..884a80b 100644
Binary files a/src/image_data/help.png and b/src/image_data/help.png differ
diff --git a/src/image_data/led_green.png b/src/image_data/led_green.png
index 4e1a204..9037edd 100644
Binary files a/src/image_data/led_green.png and b/src/image_data/led_green.png differ
diff --git a/src/image_data/led_grey.png b/src/image_data/led_grey.png
index f140b10..390ce48 100644
Binary files a/src/image_data/led_grey.png and b/src/image_data/led_grey.png differ
diff --git a/src/image_data/led_red.png b/src/image_data/led_red.png
index 2dec661..c51c992 100644
Binary files a/src/image_data/led_red.png and b/src/image_data/led_red.png differ
diff --git a/src/image_data/left.png b/src/image_data/left.png
new file mode 100644
index 0000000..a29f632
Binary files /dev/null and b/src/image_data/left.png differ
diff --git a/src/image_data/logo.png b/src/image_data/logo.png
index 1b073b1..cf6041c 100644
Binary files a/src/image_data/logo.png and b/src/image_data/logo.png differ
diff --git a/src/image_data/logo_tall.png b/src/image_data/logo_tall.png
index b27b470..8630fe2 100644
Binary files a/src/image_data/logo_tall.png and b/src/image_data/logo_tall.png differ
diff --git a/src/image_data/nvidia_icon.png b/src/image_data/nvidia_icon.png
old mode 100755
new mode 100644
Binary files a/src/image_data/nvidia_icon.png and b/src/image_data/nvidia_icon.png differ
diff --git a/src/image_data/nvlogo.png b/src/image_data/nvlogo.png
new file mode 100644
index 0000000..dcae1b7
Binary files /dev/null and b/src/image_data/nvlogo.png differ
diff --git a/src/image_data/opengl.png b/src/image_data/opengl.png
index e69fa24..6f3d0d4 100644
Binary files a/src/image_data/opengl.png and b/src/image_data/opengl.png differ
diff --git a/src/image_data/penguin.png b/src/image_data/penguin.png
index 6391c58..aa742ae 100644
Binary files a/src/image_data/penguin.png and b/src/image_data/penguin.png differ
diff --git a/src/image_data/right.png b/src/image_data/right.png
new file mode 100644
index 0000000..f25e16f
Binary files /dev/null and b/src/image_data/right.png differ
diff --git a/src/image_data/rj45_unused.png b/src/image_data/rj45_unused.png
index b41ac15..314ff29 100644
Binary files a/src/image_data/rj45_unused.png and b/src/image_data/rj45_unused.png differ
diff --git a/src/image_data/sdi.png b/src/image_data/sdi.png
index abf06ad..9c265d6 100644
Binary files a/src/image_data/sdi.png and b/src/image_data/sdi.png differ
diff --git a/src/image_data/sdi_shared_sync_bnc.png b/src/image_data/sdi_shared_sync_bnc.png
index f4b7455..894359d 100644
Binary files a/src/image_data/sdi_shared_sync_bnc.png and b/src/image_data/sdi_shared_sync_bnc.png differ
diff --git a/src/image_data/server_licensing.png b/src/image_data/server_licensing.png
index 6631971..ada413f 100644
Binary files a/src/image_data/server_licensing.png and b/src/image_data/server_licensing.png differ
diff --git a/src/image_data/slimm.png b/src/image_data/slimm.png
index 8c1e654..3c1e76d 100644
Binary files a/src/image_data/slimm.png and b/src/image_data/slimm.png differ
diff --git a/src/image_data/solaris.png b/src/image_data/solaris.png
index 59f4037..59b662c 100644
Binary files a/src/image_data/solaris.png and b/src/image_data/solaris.png differ
diff --git a/src/image_data/svp_3dvp.png b/src/image_data/svp_3dvp.png
index f21a16c..1869cee 100644
Binary files a/src/image_data/svp_3dvp.png and b/src/image_data/svp_3dvp.png differ
diff --git a/src/image_data/thermal.png b/src/image_data/thermal.png
index bb40385..8fa2610 100644
Binary files a/src/image_data/thermal.png and b/src/image_data/thermal.png differ
diff --git a/src/image_data/vcs.png b/src/image_data/vcs.png
index 8fe7289..5e96b0c 100644
Binary files a/src/image_data/vcs.png and b/src/image_data/vcs.png differ
diff --git a/src/image_data/vdpau.png b/src/image_data/vdpau.png
index 25aee50..e576e1f 100644
Binary files a/src/image_data/vdpau.png and b/src/image_data/vdpau.png differ
diff --git a/src/image_data/x.png b/src/image_data/x.png
index 2a94e42..121c8b7 100644
Binary files a/src/image_data/x.png and b/src/image_data/x.png differ
diff --git a/src/image_data/xvideo.png b/src/image_data/xvideo.png
index 9b79903..a02f65b 100644
Binary files a/src/image_data/xvideo.png and b/src/image_data/xvideo.png differ
diff --git a/src/libXNVCtrl/NVCtrl.h b/src/libXNVCtrl/NVCtrl.h
index cd63032..122f827 100644
--- a/src/libXNVCtrl/NVCtrl.h
+++ b/src/libXNVCtrl/NVCtrl.h
@@ -332,7 +332,8 @@
 #define NV_CTRL_STEREO_3D_VISION_PRO                            11
 #define NV_CTRL_STEREO_HDMI_3D                                  12
 #define NV_CTRL_STEREO_TRIDELITY_SL                             13
-#define NV_CTRL_STEREO_MAX NV_CTRL_STEREO_TRIDELITY_SL
+#define NV_CTRL_STEREO_INBAND_STEREO_SIGNALING                  14
+#define NV_CTRL_STEREO_MAX NV_CTRL_STEREO_INBAND_STEREO_SIGNALING
 
 /*
  * NV_CTRL_EMULATE - not supported
diff --git a/src/libXNVCtrl/utils.mk b/src/libXNVCtrl/utils.mk
index 31d40f9..66dbb16 100644
--- a/src/libXNVCtrl/utils.mk
+++ b/src/libXNVCtrl/utils.mk
@@ -80,6 +80,7 @@ HOSTNAME_CMD          ?= hostname
 DATE                  ?= date
 GZIP_CMD              ?= gzip
 CHMOD                 ?= chmod
+OBJCOPY               ?= objcopy
 
 NV_AUTO_DEPEND        ?= 1
 NV_VERBOSE            ?= 0
@@ -271,10 +272,14 @@ endif
 NV_MODULE_LOGGING_NAME ?=
 
 ifeq ($(NV_VERBOSE),0)
-  quiet_cmd = @$(PRINTF) \
+  at_if_quiet := @
+  quiet_cmd_no_at = $(PRINTF) \
     " $(if $(NV_MODULE_LOGGING_NAME),[ %-17.17s ],%s)  $(quiet_$(1))\n" \
     "$(NV_MODULE_LOGGING_NAME)" && $($(1))
+  quiet_cmd = @$(quiet_cmd_no_at)
 else
+  at_if_quiet :=
+  quiet_cmd_no_at = $($(1))
   quiet_cmd = $($(1))
 endif
 
@@ -295,6 +300,8 @@ quiet_HOST_LINK    = $(call define_quiet_cmd,HOST_LINK   ,$@)
 quiet_M4           = $(call define_quiet_cmd,M4          ,$<)
 quiet_STRIP_CMD    = $(call define_quiet_cmd,STRIP       ,$@)
 quiet_HARDLINK     = $(call define_quiet_cmd,HARDLINK    ,$@)
+quiet_LD           = $(call define_quiet_cmd,LD          ,$@)
+quiet_OBJCOPY      = $(call define_quiet_cmd,OBJCOPY     ,$@)
 
 ##############################################################################
 # Tell gmake to delete the target of a rule if it has changed and its
@@ -447,3 +454,30 @@ define DEFINE_STAMP_C_RULE
 	@ $$(PRINTF) "%s\n" "const char *pNV_ID = NV_ID + 11;"          >> $$@
 
 endef
+
+##############################################################################
+# Define rules that can be used for embedding a file into an ELF object that
+# contains the raw contents of that file and symbols pointing to the embedded
+# data.
+#
+# Note that objcopy will name the symbols in the resulting object file based on
+# the filename specified in $(1).  For example,
+#
+#   $(eval $(call $(READ_ONLY_OBJECT_FROM_FILE_RULE),a/b/c))
+#
+# will create an object named $(OUTPUTDIR)/c.o with the symbols _binary_c_start,
+# _binary_c_end, and _binary_c_size.
+#
+# Arguments:
+#  $(1): Path to the file to convert
+##############################################################################
+
+define READ_ONLY_OBJECT_FROM_FILE_RULE
+  $$(OUTPUTDIR)/$$(notdir $(1)).o: $(1)
+	$(at_if_quiet)cd $$(dir $(1)); \
+	$$(call quiet_cmd_no_at,LD) -r -z noexecstack --format=binary \
+	    $$(notdir $(1)) -o $$(OUTPUTDIR_ABSOLUTE)/$$(notdir $$@)
+	$$(call quiet_cmd,OBJCOPY) \
+	    --rename-section .data=.rodata,contents,alloc,load,data,readonly \
+	    $$@
+endef
diff --git a/src/libXNVCtrl/version.mk b/src/libXNVCtrl/version.mk
index f4a6a7c..54ad7ff 100644
--- a/src/libXNVCtrl/version.mk
+++ b/src/libXNVCtrl/version.mk
@@ -1 +1 @@
-NVIDIA_VERSION = 384.111
+NVIDIA_VERSION = 390.87
diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributes.c b/src/libXNVCtrlAttributes/NvCtrlAttributes.c
index dbb4d89..4216b11 100644
--- a/src/libXNVCtrlAttributes/NvCtrlAttributes.c
+++ b/src/libXNVCtrlAttributes/NvCtrlAttributes.c
@@ -1338,6 +1338,7 @@ const char *NvCtrlGetStereoModeNameIfExists(int stereo_mode)
         [NV_CTRL_STEREO_3D_VISION]                    = "NVIDIA 3D Vision",
         [NV_CTRL_STEREO_3D_VISION_PRO]                = "NVIDIA 3D Vision Pro",
         [NV_CTRL_STEREO_HDMI_3D]                      = "HDMI 3D",
+        [NV_CTRL_STEREO_INBAND_STEREO_SIGNALING]      = "Generic Active Stereo (in-band DP)",
     };
 
 
diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributes.h b/src/libXNVCtrlAttributes/NvCtrlAttributes.h
index 03c9a58..434aee8 100644
--- a/src/libXNVCtrlAttributes/NvCtrlAttributes.h
+++ b/src/libXNVCtrlAttributes/NvCtrlAttributes.h
@@ -272,7 +272,9 @@ typedef enum {
 #define NV_CTRL_ATTR_NVML_GPU_GRID_LICENSE_SUPPORTED_FALSE                                 0
 #define NV_CTRL_ATTR_NVML_GPU_GRID_LICENSE_SUPPORTED_TRUE                                  1
 
-#define NV_CTRL_ATTR_NVML_LAST_ATTRIBUTE (NV_CTRL_ATTR_NVML_GPU_GRID_LICENSE_SUPPORTED)
+#define NV_CTRL_ATTR_NVML_GPU_GRID_LICENSABLE_FEATURES          (NV_CTRL_ATTR_NVML_BASE + 2)
+
+#define NV_CTRL_ATTR_NVML_LAST_ATTRIBUTE (NV_CTRL_ATTR_NVML_GPU_GRID_LICENSABLE_FEATURES)
 
 #define NV_CTRL_ATTR_LAST_ATTRIBUTE \
         (NV_CTRL_ATTR_NVML_LAST_ATTRIBUTE)
diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributesNvml.c b/src/libXNVCtrlAttributes/NvCtrlAttributesNvml.c
index 9662d38..5eb40d2 100644
--- a/src/libXNVCtrlAttributes/NvCtrlAttributesNvml.c
+++ b/src/libXNVCtrlAttributes/NvCtrlAttributesNvml.c
@@ -895,6 +895,54 @@ static ReturnStatus NvCtrlNvmlGetGPUAttribute(const CtrlTarget *ctrl_target,
     return NvCtrlNotSupported;
 }
 
+static ReturnStatus NvCtrlNvmlGetGridLicensableFeatures(const CtrlTarget *ctrl_target,
+                                                    int attr, nvmlGridLicensableFeatures_t **val)
+{
+    const NvCtrlAttributePrivateHandle *h = getPrivateHandleConst(ctrl_target);
+    const NvCtrlNvmlAttributes *nvml;
+    nvmlDevice_t device;
+    nvmlReturn_t ret;
+
+    if ((h == NULL) || (h->nvml == NULL)) {
+        return NvCtrlBadHandle;
+    }
+
+    nvml = h->nvml;
+
+    ret = nvml->lib.deviceGetHandleByIndex(nvml->deviceIdx, &device);
+        if (ret == NVML_SUCCESS) {
+        switch (attr) {
+            case NV_CTRL_ATTR_NVML_GPU_GRID_LICENSABLE_FEATURES:
+                if (nvml->lib.deviceGetGridLicensableFeatures) {
+                    nvmlGridLicensableFeatures_t *gridLicensableFeatures;
+                    gridLicensableFeatures = (nvmlGridLicensableFeatures_t *)nvalloc(sizeof(nvmlGridLicensableFeatures_t));
+                    ret = nvml->lib.deviceGetGridLicensableFeatures(device,
+                                                                    gridLicensableFeatures);
+                    if (ret == NVML_SUCCESS) {
+                        *val = gridLicensableFeatures;
+                        return NvCtrlSuccess;
+                    }
+                } else {
+                    /* return NvCtrlNotSupported against older driver */
+                    ret = NVML_ERROR_FUNCTION_NOT_FOUND;
+                }
+
+                break;
+
+            default:
+                /* Did we forget to handle a GPU integer attribute? */
+                nv_warning_msg("Unhandled integer attribute %s (%d) of GPU "
+                               "(%d)", INT_ATTRIBUTE_NAME(attr), attr,
+                               NvCtrlGetTargetId(ctrl_target));
+                return NvCtrlNotSupported;
+        }
+    }
+
+    /* An NVML error occurred */
+    printNvmlError(ret);
+    return NvCtrlNotSupported;
+}
+
 #ifdef NVML_EXPERIMENTAL
 
 static int getThermalCoolerId(const NvCtrlAttributePrivateHandle *h,
@@ -1072,6 +1120,28 @@ ReturnStatus NvCtrlNvmlGetAttribute(const CtrlTarget *ctrl_target,
 }
 
 
+ReturnStatus NvCtrlNvmlGetGridLicenseAttributes(const CtrlTarget *ctrl_target,
+                                                int attr, nvmlGridLicensableFeatures_t **val)
+{
+    if (NvmlMissing(ctrl_target)) {
+        return NvCtrlMissingExtension;
+    }
+
+    /*
+     * This should't be reached for target types that are not handled through
+     * NVML (Keep TARGET_TYPE_IS_NVML_COMPATIBLE in NvCtrlAttributesPrivate.h up
+     * to date).
+     */
+    assert(TARGET_TYPE_IS_NVML_COMPATIBLE(NvCtrlGetTargetType(ctrl_target)));
+
+    if (NvCtrlGetTargetType(ctrl_target) == GPU_TARGET) {
+        return NvCtrlNvmlGetGridLicensableFeatures(ctrl_target, attr, val);
+    }
+    else {
+            return NvCtrlBadHandle;
+    }
+}
+
 
 /*
  * Set NVML Attribute Values
diff --git a/src/libXNVCtrlAttributes/NvCtrlAttributesPrivate.h b/src/libXNVCtrlAttributes/NvCtrlAttributesPrivate.h
index ec1101b..2a13861 100644
--- a/src/libXNVCtrlAttributes/NvCtrlAttributesPrivate.h
+++ b/src/libXNVCtrlAttributes/NvCtrlAttributesPrivate.h
@@ -427,6 +427,8 @@ ReturnStatus NvCtrlNvmlSetStringAttribute(CtrlTarget *ctrl_target,
                                           int attr, const char *ptr);
 ReturnStatus NvCtrlNvmlGetAttribute(const CtrlTarget *ctrl_target,
                                     int attr, int64_t *val);
+ReturnStatus NvCtrlNvmlGetGridLicenseAttributes(const CtrlTarget *ctrl_target,
+                                                int attr, nvmlGridLicensableFeatures_t **val);
 ReturnStatus NvCtrlNvmlSetAttribute(CtrlTarget *ctrl_target, int attr,
                                     int index, int val);
 ReturnStatus
diff --git a/src/nvml.h b/src/nvml.h
index 6febac2..9ec7642 100644
--- a/src/nvml.h
+++ b/src/nvml.h
@@ -1217,7 +1217,7 @@ typedef struct nvmlAccountingStats_st {
 
 #define NVML_VGPU_NAME_BUFFER_SIZE          64
 
-#define NVML_MAX_VGPU_TYPES_PER_PGPU        17
+#define NVML_MAX_VGPU_TYPES_PER_PGPU        18
 
 #define NVML_MAX_VGPU_INSTANCES_PER_PGPU    24
 
diff --git a/src/src.mk b/src/src.mk
index 0e56ca6..66ec238 100644
--- a/src/src.mk
+++ b/src/src.mk
@@ -41,88 +41,49 @@ NVIDIA_SETTINGS_EXTRA_DIST += $(SRC_EXTRA_DIST)
 # files in the src/image_data directory of nvidia-settings
 #
 
-IMAGE_DATA_SRC +=
+IMAGE_FILES += image_data/antialias.png
+IMAGE_FILES += image_data/background.png
+IMAGE_FILES += image_data/background_tall.png
+IMAGE_FILES += image_data/bnc_cable.png
+IMAGE_FILES += image_data/bsd.png
+IMAGE_FILES += image_data/clock.png
+IMAGE_FILES += image_data/color.png
+IMAGE_FILES += image_data/config.png
+IMAGE_FILES += image_data/crt.png
+IMAGE_FILES += image_data/dfp.png
+IMAGE_FILES += image_data/display_config.png
+IMAGE_FILES += image_data/framelock.png
+IMAGE_FILES += image_data/glx.png
+IMAGE_FILES += image_data/gpu.png
+IMAGE_FILES += image_data/gvi.png
+IMAGE_FILES += image_data/help.png
+IMAGE_FILES += image_data/led_green.png
+IMAGE_FILES += image_data/led_grey.png
+IMAGE_FILES += image_data/led_red.png
+IMAGE_FILES += image_data/left.png
+IMAGE_FILES += image_data/logo.png
+IMAGE_FILES += image_data/logo_tall.png
+IMAGE_FILES += image_data/nvidia_icon.png
+IMAGE_FILES += image_data/nvlogo.png
+IMAGE_FILES += image_data/opengl.png
+IMAGE_FILES += image_data/penguin.png
+IMAGE_FILES += image_data/right.png
+IMAGE_FILES += image_data/rj45_input.png
+IMAGE_FILES += image_data/rj45_output.png
+IMAGE_FILES += image_data/rj45_unused.png
+IMAGE_FILES += image_data/sdi.png
+IMAGE_FILES += image_data/sdi_shared_sync_bnc.png
+IMAGE_FILES += image_data/server_licensing.png
+IMAGE_FILES += image_data/slimm.png
+IMAGE_FILES += image_data/solaris.png
+IMAGE_FILES += image_data/svp_3dvp.png
+IMAGE_FILES += image_data/thermal.png
+IMAGE_FILES += image_data/vcs.png
+IMAGE_FILES += image_data/vdpau.png
+IMAGE_FILES += image_data/x.png
+IMAGE_FILES += image_data/xvideo.png
 
-IMAGE_DATA_EXTRA_DIST += image_data/HOWTO-ADD-IMAGES
-IMAGE_DATA_EXTRA_DIST += image_data/antialias.png
-IMAGE_DATA_EXTRA_DIST += image_data/antialias_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/background.png
-IMAGE_DATA_EXTRA_DIST += image_data/background_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/background_tall.png
-IMAGE_DATA_EXTRA_DIST += image_data/background_tall_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/bnc_cable.png
-IMAGE_DATA_EXTRA_DIST += image_data/bnc_cable_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/bsd.png
-IMAGE_DATA_EXTRA_DIST += image_data/bsd_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/clock.png
-IMAGE_DATA_EXTRA_DIST += image_data/clock_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/color.png
-IMAGE_DATA_EXTRA_DIST += image_data/color_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/config.png
-IMAGE_DATA_EXTRA_DIST += image_data/config_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/crt.png
-IMAGE_DATA_EXTRA_DIST += image_data/crt_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/dfp.png
-IMAGE_DATA_EXTRA_DIST += image_data/dfp_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/display_config.png
-IMAGE_DATA_EXTRA_DIST += image_data/display_config_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/framelock.png
-IMAGE_DATA_EXTRA_DIST += image_data/framelock_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/glx.png
-IMAGE_DATA_EXTRA_DIST += image_data/glx_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/gpu.png
-IMAGE_DATA_EXTRA_DIST += image_data/gpu_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/gvi.png
-IMAGE_DATA_EXTRA_DIST += image_data/gvi_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/help.png
-IMAGE_DATA_EXTRA_DIST += image_data/help_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/led_green.png
-IMAGE_DATA_EXTRA_DIST += image_data/led_green_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/led_grey.png
-IMAGE_DATA_EXTRA_DIST += image_data/led_grey_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/led_red.png
-IMAGE_DATA_EXTRA_DIST += image_data/led_red_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/logo.png
-IMAGE_DATA_EXTRA_DIST += image_data/logo_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/logo_tall.png
-IMAGE_DATA_EXTRA_DIST += image_data/logo_tall_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/nvidia_icon.png
-IMAGE_DATA_EXTRA_DIST += image_data/nvidia_icon_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/opengl.png
-IMAGE_DATA_EXTRA_DIST += image_data/opengl_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/penguin.png
-IMAGE_DATA_EXTRA_DIST += image_data/penguin_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/png_to_c_header.sh
-IMAGE_DATA_EXTRA_DIST += image_data/rj45_input.png
-IMAGE_DATA_EXTRA_DIST += image_data/rj45_input_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/rj45_output.png
-IMAGE_DATA_EXTRA_DIST += image_data/rj45_output_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/rj45_unused.png
-IMAGE_DATA_EXTRA_DIST += image_data/rj45_unused_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/sdi.png
-IMAGE_DATA_EXTRA_DIST += image_data/sdi_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/sdi_shared_sync_bnc.png
-IMAGE_DATA_EXTRA_DIST += image_data/sdi_shared_sync_bnc_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/server_licensing.png
-IMAGE_DATA_EXTRA_DIST += image_data/server_licensing_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/slimm.png
-IMAGE_DATA_EXTRA_DIST += image_data/slimm_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/solaris.png
-IMAGE_DATA_EXTRA_DIST += image_data/solaris_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/svp_3dvp.png
-IMAGE_DATA_EXTRA_DIST += image_data/svp_3dvp_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/thermal.png
-IMAGE_DATA_EXTRA_DIST += image_data/thermal_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/vcs.png
-IMAGE_DATA_EXTRA_DIST += image_data/vcs_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/vdpau.png
-IMAGE_DATA_EXTRA_DIST += image_data/vdpau_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/x.png
-IMAGE_DATA_EXTRA_DIST += image_data/x_pixdata.h
-IMAGE_DATA_EXTRA_DIST += image_data/xvideo.png
-IMAGE_DATA_EXTRA_DIST += image_data/xvideo_pixdata.h
-
-NVIDIA_SETTINGS_EXTRA_DIST += $(IMAGE_DATA_EXTRA_DIST)
+NVIDIA_SETTINGS_EXTRA_DIST += $(IMAGE_FILES)
 
 #
 # files in the src/libXNVCtrlAttributes directory of nvidia-settings
@@ -222,6 +183,11 @@ GTK_SRC += gtk+-2.x/ctkcolorcontrols.c
 GTK_SRC += gtk+-2.x/ctk3dvisionpro.c
 GTK_SRC += gtk+-2.x/ctkvdpau.c
 GTK_SRC += gtk+-2.x/ctkgridlicense.c
+GTK_SRC += gtk+-2.x/ctkglwidget.c
+GTK_SRC += gtk+-2.x/ctkglstereo.c
+GTK_SRC += gtk+-2.x/opengl_loading.c
+GTK_SRC += gtk+-2.x/opengl_wrappers.c
+GTK_SRC += gtk+-2.x/matrix_utils.c
 
 
 GTK_EXTRA_DIST += gtk+-2.x/ctkxvideo.h
@@ -270,6 +236,11 @@ GTK_EXTRA_DIST += gtk+-2.x/ctkcolorcontrols.h
 GTK_EXTRA_DIST += gtk+-2.x/ctk3dvisionpro.h
 GTK_EXTRA_DIST += gtk+-2.x/ctkvdpau.h
 GTK_EXTRA_DIST += gtk+-2.x/ctkgridlicense.h
+GTK_EXTRA_DIST += gtk+-2.x/ctkglwidget.h
+GTK_EXTRA_DIST += gtk+-2.x/ctkglstereo.h
+GTK_EXTRA_DIST += gtk+-2.x/opengl_loading.h
+GTK_EXTRA_DIST += gtk+-2.x/opengl_wrappers.h
+GTK_EXTRA_DIST += gtk+-2.x/matrix_utils.h
 
 NVIDIA_SETTINGS_EXTRA_DIST += $(GTK_EXTRA_DIST)
 
diff --git a/src/version.h b/src/version.h
index 147c91a..870e306 100644
--- a/src/version.h
+++ b/src/version.h
@@ -1 +1 @@
-#define NVIDIA_VERSION "384.111"
+#define NVIDIA_VERSION "390.87"
diff --git a/src/version.mk b/src/version.mk
index f4a6a7c..54ad7ff 100644
--- a/src/version.mk
+++ b/src/version.mk
@@ -1 +1 @@
-NVIDIA_VERSION = 384.111
+NVIDIA_VERSION = 390.87
diff --git a/utils.mk b/utils.mk
index 31d40f9..66dbb16 100644
--- a/utils.mk
+++ b/utils.mk
@@ -80,6 +80,7 @@ HOSTNAME_CMD          ?= hostname
 DATE                  ?= date
 GZIP_CMD              ?= gzip
 CHMOD                 ?= chmod
+OBJCOPY               ?= objcopy
 
 NV_AUTO_DEPEND        ?= 1
 NV_VERBOSE            ?= 0
@@ -271,10 +272,14 @@ endif
 NV_MODULE_LOGGING_NAME ?=
 
 ifeq ($(NV_VERBOSE),0)
-  quiet_cmd = @$(PRINTF) \
+  at_if_quiet := @
+  quiet_cmd_no_at = $(PRINTF) \
     " $(if $(NV_MODULE_LOGGING_NAME),[ %-17.17s ],%s)  $(quiet_$(1))\n" \
     "$(NV_MODULE_LOGGING_NAME)" && $($(1))
+  quiet_cmd = @$(quiet_cmd_no_at)
 else
+  at_if_quiet :=
+  quiet_cmd_no_at = $($(1))
   quiet_cmd = $($(1))
 endif
 
@@ -295,6 +300,8 @@ quiet_HOST_LINK    = $(call define_quiet_cmd,HOST_LINK   ,$@)
 quiet_M4           = $(call define_quiet_cmd,M4          ,$<)
 quiet_STRIP_CMD    = $(call define_quiet_cmd,STRIP       ,$@)
 quiet_HARDLINK     = $(call define_quiet_cmd,HARDLINK    ,$@)
+quiet_LD           = $(call define_quiet_cmd,LD          ,$@)
+quiet_OBJCOPY      = $(call define_quiet_cmd,OBJCOPY     ,$@)
 
 ##############################################################################
 # Tell gmake to delete the target of a rule if it has changed and its
@@ -447,3 +454,30 @@ define DEFINE_STAMP_C_RULE
 	@ $$(PRINTF) "%s\n" "const char *pNV_ID = NV_ID + 11;"          >> $$@
 
 endef
+
+##############################################################################
+# Define rules that can be used for embedding a file into an ELF object that
+# contains the raw contents of that file and symbols pointing to the embedded
+# data.
+#
+# Note that objcopy will name the symbols in the resulting object file based on
+# the filename specified in $(1).  For example,
+#
+#   $(eval $(call $(READ_ONLY_OBJECT_FROM_FILE_RULE),a/b/c))
+#
+# will create an object named $(OUTPUTDIR)/c.o with the symbols _binary_c_start,
+# _binary_c_end, and _binary_c_size.
+#
+# Arguments:
+#  $(1): Path to the file to convert
+##############################################################################
+
+define READ_ONLY_OBJECT_FROM_FILE_RULE
+  $$(OUTPUTDIR)/$$(notdir $(1)).o: $(1)
+	$(at_if_quiet)cd $$(dir $(1)); \
+	$$(call quiet_cmd_no_at,LD) -r -z noexecstack --format=binary \
+	    $$(notdir $(1)) -o $$(OUTPUTDIR_ABSOLUTE)/$$(notdir $$@)
+	$$(call quiet_cmd,OBJCOPY) \
+	    --rename-section .data=.rodata,contents,alloc,load,data,readonly \
+	    $$@
+endef
diff --git a/version.mk b/version.mk
index f4a6a7c..54ad7ff 100644
--- a/version.mk
+++ b/version.mk
@@ -1 +1 @@
-NVIDIA_VERSION = 384.111
+NVIDIA_VERSION = 390.87
