diff --git a/Makefile.common b/Makefile.common
index 7c56d336d0..d091566bfe 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -816,6 +816,10 @@ ifeq ($(HAVE_SDL2), 1)
HAVE_SDL = 0
endif
+ifeq ($(HAVE_XSHM), 1)
+ OBJ += gfx/drivers/xshm_gfx.o
+endif
+
ifeq ($(HAVE_VULKAN), 1)
ifneq ($(findstring Win32,$(OS)),)
GLSLANG_PLATFORM := Windows
diff --git a/gfx/drivers/xshm_gfx.c b/gfx/drivers/xshm_gfx.c
new file mode 100644
index 0000000000..06bacc6196
--- /dev/null
+++ b/gfx/drivers/xshm_gfx.c
@@ -0,0 +1,274 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
+ * Copyright (C) 2016-2016 - Alfred Agrell
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch 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 RetroArch.
+ * If not, see .
+ */
+
+#include
+#include
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+#include
+
+#include "../../configuration.h"
+#include "../../driver.h"
+#include "../../retroarch.h"
+#include "../../runloop.h"
+#include "../../performance_counters.h"
+#include "../../verbosity.h"
+#include "../video_context_driver.h"
+#include "../font_driver.h"
+
+#include "../common/x11_common.h"
+
+#ifdef HAVE_MENU
+#include "../../menu/menu_driver.h"
+#endif
+
+#include
+#include
+#include
+#include
+
+
+typedef struct xshm
+{
+ Display* display;
+ Window wndw;
+
+ int width;
+ int height;
+
+ XShmSegmentInfo shmInfo;
+ XImage* image;
+ GC gc;
+} xshm_t;
+
+static void *xshm_gfx_init(const video_info_t *video,
+ const input_driver_t **input, void **input_data)
+{
+ xshm_t* xshm = (xshm_t*)malloc(sizeof(xshm_t));
+
+ XInitThreads();
+
+ xshm->display = XOpenDisplay(NULL);
+
+ XSetWindowAttributes attributes;
+ attributes.border_pixel=0;
+ xshm->wndw = XCreateWindow(xshm->display, DefaultRootWindow(xshm->display)/*xshm->parentwindow*/,
+ 0, 0, video->width, video->height,
+ 0, 24, CopyFromParent, NULL, CWBorderPixel, &attributes);
+ XSetWindowBackground(xshm->display, xshm->wndw, 0);
+ XMapWindow(xshm->display, xshm->wndw);
+
+ xshm->shmInfo.shmid = shmget(IPC_PRIVATE, sizeof(uint32_t) * video->width * video->height,
+ IPC_CREAT|0600);
+ if (xshm->shmInfo.shmid<0) abort();//seems like an out of memory situation... let's just blow up
+
+ xshm->shmInfo.shmaddr = (char*)shmat(xshm->shmInfo.shmid, 0, 0);
+ xshm->shmInfo.readOnly = False;
+ XShmAttach(xshm->display, &xshm->shmInfo);
+ XSync(xshm->display, False);//no idea why this is required, but I get weird errors without it
+ xshm->image = XShmCreateImage(xshm->display, NULL, 24, ZPixmap,
+ xshm->shmInfo.shmaddr, &xshm->shmInfo, video->width, video->height);
+
+ xshm->gc = XCreateGC(xshm->display, xshm->wndw, 0, NULL);
+
+ xshm->width = video->width;
+ xshm->height = video->height;
+
+ *input = NULL;
+ *input_data = NULL;
+
+ return xshm;
+}
+
+static bool xshm_gfx_frame(void *data, const void *frame, unsigned width,
+ unsigned height, uint64_t frame_count,
+ unsigned pitch, const char *msg)
+{
+ xshm_t* xshm = (xshm_t*)data;
+ int x, y;
+
+ for (y=0;yshmInfo.shmaddr + sizeof(uint32_t)*xshm->width*y, (uint8_t*)frame + pitch*y, pitch);
+ }
+
+ XShmPutImage(xshm->display, xshm->wndw, xshm->gc, xshm->image,
+ 0, 0, 0, 0, xshm->width, xshm->height, False);
+ XFlush(xshm->display);
+
+ return true;
+}
+
+static void xshm_gfx_set_nonblock_state(void *data, bool toggle)
+{
+
+}
+
+static bool xshm_gfx_alive(void *data)
+{
+ return true;
+}
+
+static bool xshm_gfx_focus(void *data)
+{
+ return true;
+}
+
+static bool xshm_gfx_suppress_screensaver(void *data, bool enable)
+{
+ return false;
+}
+
+static bool xshm_gfx_has_windowed(void *data)
+{
+ return true;
+}
+
+static void xshm_gfx_free(void *data)
+{
+
+}
+
+static void xshm_gfx_set_rotation(void *data, unsigned rotation)
+{
+
+}
+
+static void xshm_gfx_viewport_info(void *data, struct video_viewport *vp)
+{
+
+}
+
+static bool xshm_gfx_read_viewport(void *data, uint8_t *buffer)
+{
+ return false;
+}
+
+static void xshm_poke_set_filtering(void *data, unsigned index, bool smooth)
+{
+
+}
+
+static void xshm_poke_set_aspect_ratio(void *data, unsigned aspect_ratio_idx)
+{
+
+}
+
+static void xshm_poke_apply_state_changes(void *data)
+{
+
+}
+
+#ifdef HAVE_MENU
+static void xshm_poke_set_texture_frame(void *data, const void *frame, bool rgb32,
+ unsigned width, unsigned height, float alpha)
+{
+
+}
+
+static void xshm_poke_texture_enable(void *data, bool enable, bool full_screen)
+{
+
+}
+
+static void xshm_poke_set_osd_msg(void *data, const char *msg,
+ const struct font_params *params, void *font)
+{
+
+}
+
+static void xshm_show_mouse(void *data, bool state)
+{
+
+}
+
+static void xshm_grab_mouse_toggle(void *data)
+{
+
+}
+#endif
+
+static video_poke_interface_t xshm_video_poke_interface = {
+ NULL,
+ NULL,
+ NULL,
+ xshm_poke_set_filtering,
+ NULL, /* get_video_output_size */
+ NULL, /* get_video_output_prev */
+ NULL, /* get_video_output_next */
+ NULL, /* get_current_framebuffer */
+ NULL, /* get_proc_address */
+ xshm_poke_set_aspect_ratio,
+ xshm_poke_apply_state_changes,
+#ifdef HAVE_MENU
+ xshm_poke_set_texture_frame,
+ xshm_poke_texture_enable,
+ xshm_poke_set_osd_msg,
+ xshm_show_mouse,
+ xshm_grab_mouse_toggle,
+#else
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+#endif
+ NULL,
+};
+
+static void xshm_gfx_poke_interface(void *data, const video_poke_interface_t **iface)
+{
+ (void)data;
+ *iface = &xshm_video_poke_interface;
+}
+
+static bool xshm_gfx_set_shader(void *data,
+ enum rarch_shader_type type, const char *path)
+{
+ (void)data;
+ (void)type;
+ (void)path;
+
+ return false;
+}
+
+video_driver_t video_xshm = {
+ xshm_gfx_init,
+ xshm_gfx_frame,
+ xshm_gfx_set_nonblock_state,
+ xshm_gfx_alive,
+ xshm_gfx_focus,
+ xshm_gfx_suppress_screensaver,
+ xshm_gfx_has_windowed,
+ xshm_gfx_set_shader,
+ xshm_gfx_free,
+ "xshm",
+
+ NULL,
+ xshm_gfx_set_rotation,
+ xshm_gfx_viewport_info,
+ xshm_gfx_read_viewport,
+ NULL, /* read_frame_raw */
+#ifdef HAVE_OVERLAY
+ NULL,
+#endif
+ xshm_gfx_poke_interface
+};
+
diff --git a/gfx/video_driver.c b/gfx/video_driver.c
index 54e513367a..4860ed25ab 100644
--- a/gfx/video_driver.c
+++ b/gfx/video_driver.c
@@ -203,6 +203,9 @@ static const video_driver_t *video_drivers[] = {
#endif
#ifdef HAVE_PLAIN_DRM
&video_drm,
+#endif
+#ifdef HAVE_XSHM
+ &video_xshm,
#endif
&video_null,
NULL,
diff --git a/qb/config.params.sh b/qb/config.params.sh
index 84ae7c17a0..91fbb8d517 100644
--- a/qb/config.params.sh
+++ b/qb/config.params.sh
@@ -79,7 +79,7 @@ HAVE_PARPORT=auto # Parallel port joypad support
HAVE_IMAGEVIEWER=yes # Built-in image viewer support.
HAVE_MMAP=auto # MMAP support
HAVE_QT=no # QT companion support
-HAVE_XSHM=no # XShm video driver support (disabled because it's just a dummied out stub)
+HAVE_XSHM=auto # XShm video driver support
HAVE_CHEEVOS=yes # Retro Achievements
HAVE_SHADERPIPELINE=yes # Additional shader-based pipelines
C89_SHADERPIPELINE=no