--- /dev/null
+--- a/configure.ac
++++ b/configure.ac
+@@ -631,6 +631,7 @@
+ AC_ARG_ENABLE(libdrm, AS_HELP_STRING([--enable-libdrm], [Build Xorg with libdrm support (default: enabled)]), [DRM=$enableval],[DRM=yes])
+ AC_ARG_ENABLE(clientids, AS_HELP_STRING([--disable-clientids], [Build Xorg with client ID tracking (default: enabled)]), [CLIENTIDS=$enableval], [CLIENTIDS=yes])
+ AC_ARG_ENABLE(pciaccess, AS_HELP_STRING([--enable-pciaccess], [Build Xorg with pciaccess library (default: enabled)]), [PCI=$enableval], [PCI=yes])
++AC_ARG_ENABLE(xmir, AS_HELP_STRING([--enable-xmir], [Build support for nesting in Mir (default: auto)]), [XMIR=$enableval], [XMIR=auto])
+ AC_ARG_ENABLE(linux_acpi, AC_HELP_STRING([--disable-linux-acpi], [Disable building ACPI support on Linux (if available).]), [enable_linux_acpi=$enableval], [enable_linux_acpi=yes])
+ AC_ARG_ENABLE(linux_apm, AC_HELP_STRING([--disable-linux-apm], [Disable building APM support on Linux (if available).]), [enable_linux_apm=$enableval], [enable_linux_apm=yes])
+
+@@ -1275,6 +1276,15 @@
+ SDK_REQUIRED_MODULES="$SDK_REQUIRED_MODULES $XINERAMAPROTO"
+ fi
+
++if test "x$XMIR" != xno; then
++ PKG_CHECK_MODULES([XMIR], [mirclient], [XMIR=yes], [XMIR=no])
++ AC_SUBST([XMIR_LIBS])
++ AC_SUBST([XMIR_CFLAGS])
++ AC_DEFINE(XMIR, 1, [Support Mir nested mode])
++ SDK_REQUIRED_MODULES="$SDK_REQUIRED_MODULES mirclient"
++fi
++AM_CONDITIONAL(XMIR, [test "x$XMIR" = xyes])
++
+ AM_CONDITIONAL(XACE, [test "x$XACE" = xyes])
+ if test "x$XACE" = xyes; then
+ AC_DEFINE(XACE, 1, [Build X-ACE extension])
+@@ -2439,6 +2449,7 @@
+ hw/xfree86/utils/man/Makefile
+ hw/xfree86/utils/cvt/Makefile
+ hw/xfree86/utils/gtf/Makefile
++hw/xfree86/xmir/Makefile
+ hw/dmx/config/Makefile
+ hw/dmx/config/man/Makefile
+ hw/dmx/doc/Makefile
+--- a/hw/xfree86/Makefile.am
++++ b/hw/xfree86/Makefile.am
+@@ -30,15 +30,20 @@
+ INT10_SUBDIR = int10
+ endif
+
++if XMIR
++XMIR_SUBDIR = xmir
++endif
++
+ SUBDIRS = common ddc x86emu $(INT10_SUBDIR) os-support parser \
+ ramdac $(VGAHW_SUBDIR) loader modes $(DRI_SUBDIR) \
+ $(DRI2_SUBDIR) . $(VBE_SUBDIR) i2c dixmods \
+- fbdevhw shadowfb exa $(XF86UTILS_SUBDIR) doc man
++ fbdevhw shadowfb exa $(XF86UTILS_SUBDIR) doc man \
++ $(XMIR_SUBDIR)
+
+ DIST_SUBDIRS = common ddc i2c x86emu int10 fbdevhw os-support \
+ parser ramdac shadowfb vbe vgahw \
+ loader dixmods dri dri2 exa modes \
+- utils doc man
++ utils doc man xmir
+
+ bin_PROGRAMS = Xorg
+ nodist_Xorg_SOURCES = sdksyms.c
+--- a/hw/xfree86/common/xf86Config.c
++++ b/hw/xfree86/common/xf86Config.c
+@@ -118,6 +118,7 @@
+ {.name = "fb",.toLoad = TRUE,.load_opt = NULL},
+ {.name = "shadow",.toLoad = TRUE,.load_opt = NULL},
+ #endif
++ {.name = "xmir", .toLoad = FALSE, .load_opt = NULL},
+ {.name = NULL,.toLoad = FALSE,.load_opt = NULL}
+ };
+
+@@ -260,6 +261,17 @@
+ return NULL;
+ }
+
++ /*
++ * Set the xmir module to autoload if requested.
++ */
++ if (xorgMir) {
++ for (i=0 ; ModuleDefaults[i].name != NULL ; i++) {
++ if (strcmp(ModuleDefaults[i].name, "xmir") == 0) {
++ ModuleDefaults[i].toLoad = TRUE;
++ }
++ }
++ }
++
+ if (xf86configptr->conf_modules) {
+ /* Walk the disable list and let people know what we've parsed to
+ * not be loaded
+--- a/hw/xfree86/common/xf86Events.c
++++ b/hw/xfree86/common/xf86Events.c
+@@ -105,8 +105,6 @@
+ extern void (*xf86OSPMClose) (void);
+ #endif
+
+-static void xf86VTSwitch(void);
+-
+ /*
+ * Allow arbitrary drivers or other XFree86 code to register with our main
+ * Wakeup handler.
+@@ -411,7 +409,7 @@
+ * xf86VTSwitch --
+ * Handle requests for switching the vt.
+ */
+-static void
++_X_EXPORT void
+ xf86VTSwitch(void)
+ {
+ int i;
+@@ -471,7 +469,7 @@
+
+ xf86AccessLeave(); /* We need this here, otherwise */
+
+- if (!xf86VTSwitchAway()) {
++ if (!xorgMir && !xf86VTSwitchAway()) {
+ /*
+ * switch failed
+ */
+@@ -530,7 +528,7 @@
+ }
+ else {
+ DebugF("xf86VTSwitch: Entering\n");
+- if (!xf86VTSwitchTo())
++ if (!xorgMir && !xf86VTSwitchTo())
+ return;
+
+ #ifdef XF86PM
+--- a/hw/xfree86/common/xf86Globals.c
++++ b/hw/xfree86/common/xf86Globals.c
+@@ -206,3 +206,6 @@
+ #endif
+ RootWinPropPtr *xf86RegisteredPropertiesTable = NULL;
+ Bool xorgHWAccess = FALSE;
++Bool xorgMir = FALSE;
++const char *mirID = NULL;
++const char *mirSocket = NULL;
+--- a/hw/xfree86/common/xf86Helper.c
++++ b/hw/xfree86/common/xf86Helper.c
+@@ -100,7 +100,14 @@
+ if (xf86DriverList[drvIndex]->module)
+ UnloadModule(xf86DriverList[drvIndex]->module);
+ free(xf86DriverList[drvIndex]);
+- xf86DriverList[drvIndex] = NULL;
++
++ /* Compact xf86DriverList array, update xf86NumDrivers */
++ xf86NumDrivers--;
++ if(drvIndex != xf86NumDrivers)
++ memmove(xf86DriverList + drvIndex,
++ xf86DriverList + drvIndex + 1,
++ sizeof(DriverPtr) * (xf86NumDrivers - drvIndex));
++ xf86DriverList = realloc(xf86DriverList, xf86NumDrivers * sizeof(DriverPtr));
+ }
+ }
+
+--- a/hw/xfree86/common/xf86Init.c
++++ b/hw/xfree86/common/xf86Init.c
+@@ -554,7 +554,7 @@
+ * needed at this early stage.
+ */
+
+- for (i = 0; i < xf86NumDrivers; i++) {
++ for (i = 0; i < xf86NumDrivers; ) {
+ xorgHWFlags flags = HW_IO;
+
+ if (xf86DriverList[i]->Identify != NULL)
+@@ -565,11 +565,20 @@
+ GET_REQUIRED_HW_INTERFACES,
+ &flags);
+
++ if (xorgMir &&
++ (NEED_IO_ENABLED(flags) || !(flags & HW_SKIP_CONSOLE))) {
++ ErrorF("Driver needs flags %lu, incompatible with nested, deleting.\n", flags);
++ xf86DeleteDriver(i);
++ continue;
++ }
++
+ if (NEED_IO_ENABLED(flags))
+ want_hw_access = TRUE;
+
+ if (!(flags & HW_SKIP_CONSOLE))
+ xorgHWOpenConsole = TRUE;
++
++ i++;
+ }
+
+ if (xorgHWOpenConsole)
+@@ -662,9 +671,13 @@
+ }
+
+ /* Remove (unload) drivers that are not required */
+- for (i = 0; i < xf86NumDrivers; i++)
+- if (xf86DriverList[i] && xf86DriverList[i]->refCount <= 0)
++ for (i = 0; i < xf86NumDrivers; )
++ if (xf86DriverList[i] &&
++ !xf86DriverHasEntities(xf86DriverList[i]) &&
++ xf86DriverList[i]->refCount <= 0)
+ xf86DeleteDriver(i);
++ else
++ i++;
+
+ /*
+ * At this stage we know how many screens there are.
+@@ -1490,6 +1503,17 @@
+ xf86Info.ShareVTs = TRUE;
+ return 1;
+ }
++ if (!strcmp(argv[i], "-mir")) {
++ CHECK_FOR_REQUIRED_ARGUMENT();
++ mirID = argv[++i];
++ xorgMir = TRUE;
++ return 2;
++ }
++ if (!strcmp(argv[i], "-mirSocket")) {
++ CHECK_FOR_REQUIRED_ARGUMENT();
++ mirSocket = argv[++i];
++ return 2;
++ }
+
+ /* OS-specific processing */
+ return xf86ProcessArgument(argc, argv, i);
+@@ -1563,6 +1587,8 @@
+ ErrorF
+ ("-novtswitch don't automatically switch VT at reset & exit\n");
+ ErrorF("-sharevts share VTs with another X server\n");
++ ErrorF
++ ("-mir MirID run nested in a Mir compositor with app id MirID\n");
+ /* OS-specific usage */
+ xf86UseMsg();
+ ErrorF("\n");
+--- a/hw/xfree86/common/xf86Priv.h
++++ b/hw/xfree86/common/xf86Priv.h
+@@ -93,6 +93,9 @@
+ extern _X_EXPORT const char *xf86VisualNames[];
+ extern _X_EXPORT int xf86Verbose; /* verbosity level */
+ extern _X_EXPORT int xf86LogVerbose; /* log file verbosity level */
++extern _X_EXPORT Bool xorgMir;
++extern _X_EXPORT const char *mirID;
++extern _X_EXPORT const char *mirSocket;
+
+ extern _X_EXPORT RootWinPropPtr *xf86RegisteredPropertiesTable;
+
+@@ -149,6 +152,9 @@
+ extern _X_EXPORT int (*xf86PMGetEventFromOs) (int fd, pmEvent * events,
+ int num);
+ extern _X_EXPORT pmWait (*xf86PMConfirmEventToOs) (int fd, pmEvent event);
++extern _X_EXPORT void
++xf86VTSwitch(void);
++
+
+ /* xf86Helper.c */
+ extern _X_EXPORT void
+--- a/hw/xfree86/ramdac/xf86Cursor.c
++++ b/hw/xfree86/ramdac/xf86Cursor.c
+@@ -58,7 +58,12 @@
+ xf86CursorScreenPtr ScreenPriv;
+ miPointerScreenPtr PointPriv;
+
+- if (!xf86InitHardwareCursor(pScreen, infoPtr))
++ infoPtr->pScrn = xf86ScreenToScrn(pScreen);
++
++ /* If we can't create a hardware cursor don't bother initialising HW cursor support */
++ if (infoPtr->MaxWidth != 0 &&
++ infoPtr->MaxHeight != 0 &&
++ !xf86InitHardwareCursor(pScreen, infoPtr))
+ return FALSE;
+
+ if (!dixRegisterPrivateKey(&xf86CursorScreenKeyRec, PRIVATE_SCREEN, 0))
+--- a/hw/xfree86/ramdac/xf86HWCurs.c
++++ b/hw/xfree86/ramdac/xf86HWCurs.c
+@@ -114,8 +114,6 @@
+ infoPtr->RealizeCursor = RealizeCursorInterleave0;
+ }
+
+- infoPtr->pScrn = xf86ScreenToScrn(pScreen);
+-
+ return TRUE;
+ }
+
+--- /dev/null
++++ b/hw/xfree86/xmir/Makefile.am
+@@ -0,0 +1,26 @@
++INCLUDES = \
++ $(XORG_INCS) \
++ -I$(srcdir)/../ddc \
++ -I$(srcdir)/../ramdac \
++ -I$(srcdir)/../i2c \
++ -I$(srcdir)/../parser \
++ -I$(srcdir)/../modes
++
++libxmir_la_LTLIBRARIES = libxmir.la
++libxmir_la_CFLAGS = \
++ -DHAVE_XORG_CONFIG_H \
++ $(DRI_CFLAGS) \
++ $(DIX_CFLAGS) $(XORG_CFLAGS) $(LIBDRM_CFLAGS) \
++ $(XMIR_CFLAGS)
++
++libxmir_la_LDFLAGS = -module -avoid-version $(LIBDRM_LIBS) $(XMIR_LIBS)
++libxmir_ladir = $(moduledir)/extensions
++libxmir_la_SOURCES = \
++ xmir.c \
++ xmir-window.c \
++ xmir-output.c \
++ xmir-thread-proxy.c \
++ xmir.h \
++ xmir-private.h
++
++sdk_HEADERS = xmir.h
+--- /dev/null
++++ b/hw/xfree86/xmir/xmir-output.c
+@@ -0,0 +1,678 @@
++/*
++ * Copyright © 2012 Canonical, Inc
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Soft-
++ * ware"), to deal in the Software without restriction, including without
++ * limitation the rights to use, copy, modify, merge, publish, distribute,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, provided that the above copyright
++ * notice(s) and this permission notice appear in all copies of the Soft-
++ * ware and that both the above copyright notice(s) and this permission
++ * notice appear in supporting documentation.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
++ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
++ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
++ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
++ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
++ * MANCE OF THIS SOFTWARE.
++ *
++ * Except as contained in this notice, the name of a copyright holder shall
++ * not be used in advertising or otherwise to promote the sale, use or
++ * other dealings in this Software without prior written authorization of
++ * the copyright holder.
++ *
++ * Authors:
++ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com)
++ */
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <math.h>
++
++#include <xorg-config.h>
++#include "xmir.h"
++#include "xmir-private.h"
++#include "xf86Crtc.h"
++#include "xf86Priv.h"
++
++struct xmir_crtc {
++ xmir_screen *xmir;
++ xmir_window *root_fragment;
++ MirDisplayConfiguration *config;
++};
++
++static const char *
++xmir_mir_dpms_mode_description(MirPowerMode mode)
++{
++ switch (mode)
++ {
++ case mir_power_mode_on:
++ return "mir_power_mode_on";
++ case mir_power_mode_standby:
++ return "mir_power_mode_standby";
++ case mir_power_mode_suspend:
++ return "mir_power_mode_suspend";
++ case mir_power_mode_off:
++ return "mir_power_mode_off";
++ default:
++ return "OMGUNKNOWN!";
++ }
++}
++
++static void
++xmir_crtc_dpms(xf86CrtcPtr crtc, int mode)
++{
++ xf86CrtcConfigPtr crtc_cfg = XF86_CRTC_CONFIG_PTR(crtc->scrn);
++ struct xmir_crtc *xmir_crtc = crtc->driver_private;
++
++ for (int i = 0; i < crtc_cfg->num_output; i++) {
++ /* If this output should be driven by our "CRTC", set DPMS mode */
++ MirDisplayOutput *output = crtc_cfg->output[i]->driver_private;
++ if (crtc_cfg->output[i]->crtc == crtc) {
++ xf86Msg(X_INFO, "Setting DPMS mode for output %d to %d\n", i, mode);
++ switch (mode) {
++ case DPMSModeOn:
++ output->power_mode = mir_power_mode_on;
++ xmir_crtc->xmir->dpms_on = TRUE;
++ break;
++ case DPMSModeStandby:
++ output->power_mode = mir_power_mode_standby;
++ xmir_crtc->xmir->dpms_on = FALSE;
++ break;
++ case DPMSModeSuspend:
++ output->power_mode = mir_power_mode_suspend;
++ xmir_crtc->xmir->dpms_on = FALSE;
++ break;
++ case DPMSModeOff:
++ output->power_mode = mir_power_mode_off;
++ xmir_crtc->xmir->dpms_on = FALSE;
++ break;
++ }
++ }
++ }
++ mir_wait_for(mir_connection_apply_display_config(xmir_connection_get(),
++ xmir_crtc->config));
++}
++
++static const char*
++xmir_get_output_type_str(MirDisplayOutput *mir_output)
++{
++ const char *str = "Invalid";
++
++ switch(mir_output->type)
++ {
++ case mir_display_output_type_vga: str = "VGA"; break;
++ case mir_display_output_type_dvii: str = "DVI"; break;
++ case mir_display_output_type_dvid: str = "DVI"; break;
++ case mir_display_output_type_dvia: str = "DVI"; break;
++ case mir_display_output_type_composite: str = "Composite"; break;
++ case mir_display_output_type_svideo: str = "TV"; break;
++ case mir_display_output_type_lvds: str = "LVDS"; break;
++ case mir_display_output_type_component: str = "CTV"; break;
++ case mir_display_output_type_ninepindin: str = "DIN"; break;
++ case mir_display_output_type_displayport: str = "DP"; break;
++ case mir_display_output_type_hdmia: str = "HDMI"; break;
++ case mir_display_output_type_hdmib: str = "HDMI"; break;
++ case mir_display_output_type_tv: str = "TV"; break;
++ case mir_display_output_type_edp: str = "eDP"; break;
++
++ case mir_display_output_type_unknown: str = "None"; break;
++ default: break;
++ }
++
++ return str;
++}
++
++static void
++xmir_output_populate(xf86OutputPtr xf86output, MirDisplayOutput *output)
++{
++ /* We can always arbitrarily clone and output */
++ xf86output->possible_crtcs = 0xffffffff;
++ xf86output->possible_clones = 0xffffffff;
++
++ xf86output->driver_private = output;
++
++ xf86output->interlaceAllowed = FALSE;
++ xf86output->doubleScanAllowed = FALSE;
++ xf86output->mm_width = output->physical_width_mm;
++ xf86output->mm_height = output->physical_height_mm;
++ /* TODO: Subpixel order from Mir */
++ xf86output->subpixel_order = SubPixelUnknown;
++}
++
++static DisplayModePtr
++xmir_create_xf86mode(const struct MirDisplayMode *mir_mode)
++{
++ DisplayModePtr mode;
++
++ mode = xf86CVTMode(mir_mode->horizontal_resolution,
++ mir_mode->vertical_resolution,
++ mir_mode->refresh_rate,
++ FALSE, FALSE);
++
++ /*
++ * And now, because the CVT standard doesn't support such common
++ * resolutions as 1366x768...
++ */
++ mode->VDisplay = mir_mode->vertical_resolution;
++ mode->HDisplay = mir_mode->horizontal_resolution;
++
++ xf86SetModeDefaultName(mode);
++
++ return mode;
++}
++
++static void
++xmir_free_xf86mode(DisplayModePtr mode)
++{
++ free(mode->name);
++ free(mode);
++}
++
++static Bool
++xmir_set_mode_for_output(MirDisplayOutput *output,
++ DisplayModePtr mode)
++{
++ for (int i = 0; i < output->num_modes; i++) {
++ Bool modes_equal = FALSE;
++ DisplayModePtr mir_mode = NULL;
++ xf86Msg(X_INFO, "Checking against mode (%dx%d)@%.2f\n",
++ output->modes[i].horizontal_resolution,
++ output->modes[i].vertical_resolution,
++ output->modes[i].refresh_rate);
++
++ mir_mode = xmir_create_xf86mode(&output->modes[i]);
++ modes_equal = xf86ModesEqual(mode, mir_mode);
++ xmir_free_xf86mode(mir_mode);
++
++ if (modes_equal) {
++ output->current_mode = i;
++ output->used = 1;
++ xf86Msg(X_INFO, "Matched mode %d\n", i);
++ return TRUE;
++ }
++ }
++ return FALSE;
++}
++
++static uint32_t
++xmir_update_outputs_for_crtc(xf86CrtcPtr crtc, DisplayModePtr mode, int x, int y)
++{
++ xf86CrtcConfigPtr crtc_cfg = XF86_CRTC_CONFIG_PTR(crtc->scrn);
++ uint32_t representative_output_id = mir_display_output_id_invalid;
++
++ for (int i = 0; i < crtc_cfg->num_output; i++) {
++ /* If this output should be driven by our "CRTC", set its mode */
++ if (crtc_cfg->output[i]->crtc == crtc) {
++ MirDisplayOutput *output = crtc_cfg->output[i]->driver_private;
++ xmir_set_mode_for_output(output, mode);
++ output->position_x = x;
++ output->position_y = y;
++ representative_output_id = output->output_id;
++ }
++ }
++ return representative_output_id;
++}
++
++static void
++xmir_disable_unused_outputs(xf86CrtcPtr crtc)
++{
++ xf86CrtcConfigPtr crtc_cfg = XF86_CRTC_CONFIG_PTR(crtc->scrn);
++
++ for (int i = 0; i < crtc_cfg->num_output; i++)
++ /* If any outputs are no longer associated with a CRTC, disable them */
++ if (crtc_cfg->output[i]->crtc == NULL)
++ ((MirDisplayOutput*)crtc_cfg->output[i]->driver_private)->used = 0;
++}
++
++static void
++xmir_stupid_callback(MirSurface *surf, void *ctx)
++{
++}
++
++static void
++xmir_dump_config(MirDisplayConfiguration *config)
++{
++ for (int i = 0; i < config->num_outputs; i++)
++ {
++ xf86Msg(X_INFO, "Output %d (%s, %s) has mode %d (%d x %d @ %.2f), position (%d,%d), dpms: %s\n",
++ config->outputs[i].output_id,
++ config->outputs[i].connected ? "connected" : "disconnected",
++ config->outputs[i].used ? "enabled" : "disabled",
++ config->outputs[i].current_mode,
++ config->outputs[i].used ? config->outputs[i].modes[config->outputs[i].current_mode].horizontal_resolution : 0,
++ config->outputs[i].used ? config->outputs[i].modes[config->outputs[i].current_mode].vertical_resolution : 0,
++ config->outputs[i].used ? config->outputs[i].modes[config->outputs[i].current_mode].refresh_rate : 0,
++ config->outputs[i].position_x,
++ config->outputs[i].position_y,
++ xmir_mir_dpms_mode_description(config->outputs[i].power_mode));
++ for (int m = 0; m < config->outputs[i].num_modes; m++)
++ {
++ xf86Msg(X_INFO, " mode %d: (%d x %d @ %.2f)\n",
++ m,
++ config->outputs[i].modes[m].horizontal_resolution,
++
++ config->outputs[i].modes[m].vertical_resolution,
++ config->outputs[i].modes[m].refresh_rate);
++ }
++ }
++}
++
++static void
++xmir_update_config(xf86CrtcConfigPtr crtc_cfg)
++{
++ MirDisplayConfiguration *new_config;
++ struct xmir_crtc *xmir_crtc = crtc_cfg->crtc[0]->driver_private;
++
++ mir_display_config_destroy(xmir_crtc->config);
++
++ new_config = mir_connection_create_display_config(xmir_connection_get());
++ for (int i = 0; i < crtc_cfg->num_crtc; i++) {
++ xmir_crtc = crtc_cfg->crtc[i]->driver_private;
++ xmir_crtc-> config = new_config;
++ }
++
++ if (crtc_cfg->num_output != new_config->num_outputs)
++ FatalError("[xmir] New Mir config has different number of outputs?");
++
++ for (int i = 0; i < crtc_cfg->num_output ; i++) {
++ /* TODO: Ensure that the order actually matches up */
++ xmir_output_populate(crtc_cfg->output[i], new_config->outputs + i);
++ }
++ xf86Msg(X_INFO, "Recieved updated config from Mir:\n");
++ xmir_dump_config(new_config);
++}
++
++static void
++xmir_crtc_surface_created(MirSurface *surface, void *ctx)
++{
++ xf86CrtcPtr crtc = ctx;
++ struct xmir_crtc *xmir_crtc = crtc->driver_private;
++
++ if (xmir_crtc->root_fragment->surface != NULL)
++ mir_surface_release(xmir_crtc->root_fragment->surface, xmir_stupid_callback, NULL);
++
++ xmir_crtc->root_fragment->surface = surface;
++}
++
++static Bool
++xmir_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
++ Rotation rotation, int x, int y)
++{
++ MirSurfaceParameters params = {
++ .name = "Xorg",
++ .width = mode->HDisplay,
++ .height = mode->VDisplay,
++ .pixel_format = mir_pixel_format_xrgb_8888,
++ .buffer_usage = mir_buffer_usage_hardware,
++ .output_id = mir_display_output_id_invalid
++ };
++ BoxRec output_bounds = {
++ .x1 = x,
++ .y1 = y,
++ .x2 = x + mode->HDisplay,
++ .y2 = y + mode->VDisplay
++ };
++ struct xmir_crtc *xmir_crtc = crtc->driver_private;
++ uint32_t output_id = mir_display_output_id_invalid;
++ const char *error_msg;
++
++ if (mode->HDisplay == 0 || mode->VDisplay == 0)
++ return FALSE;
++
++ xf86Msg(X_INFO, "Initial configuration for crtc %p:\n", crtc);
++ xmir_dump_config(xmir_crtc->config);
++
++ xf86Msg(X_INFO, "Setting mode to %dx%d (%.2f)\n", mode->HDisplay, mode->VDisplay, mode->VRefresh);
++ output_id = xmir_update_outputs_for_crtc(crtc, mode, x, y);
++ xmir_disable_unused_outputs(crtc);
++
++ xf86Msg(X_INFO, "Updated configuration:\n");
++
++ xmir_dump_config(xmir_crtc->config);
++ mir_wait_for(mir_connection_apply_display_config(xmir_connection_get(),
++ xmir_crtc->config));
++ error_msg = mir_connection_get_error_message(xmir_connection_get());
++ if (*error_msg != '\0') {
++ xf86Msg(X_ERROR, "[xmir] Failed to set new display config: %s\n",
++ error_msg);
++ return FALSE;
++ /* TODO: Restore correct config cache */
++ }
++
++ xf86Msg(X_INFO, "Post-modeset config:\n");
++ xmir_update_config(XF86_CRTC_CONFIG_PTR(crtc->scrn));
++
++ if (output_id == mir_display_output_id_invalid) {
++ if (xmir_crtc->root_fragment->surface != NULL)
++ mir_wait_for(mir_surface_release(xmir_crtc->root_fragment->surface, xmir_stupid_callback, NULL));
++ xmir_crtc->root_fragment->surface = NULL;
++ return TRUE;
++ }
++
++ params.output_id = output_id;
++ xf86Msg(X_INFO, "Putting surface on output %d\n", output_id);
++ mir_wait_for(mir_connection_create_surface(xmir_connection_get(),
++ ¶ms,
++ xmir_crtc_surface_created,
++ crtc));
++ if (!mir_surface_is_valid(xmir_crtc->root_fragment->surface)) {
++ xf86Msg(X_ERROR,
++ "[xmir] Failed to create surface for %dx%d mode: %s\n",
++ mode->HDisplay, mode->VDisplay,
++ mir_surface_get_error_message(xmir_crtc->root_fragment->surface));
++ return FALSE;
++ }
++
++
++ /* During X server init this will be NULL.
++ This is fixed up in xmir_window_create */
++ xmir_crtc->root_fragment->win = xf86ScrnToScreen(crtc->scrn)->root;
++
++ RegionInit(&xmir_crtc->root_fragment->region, &output_bounds, 0);
++ xmir_crtc->root_fragment->has_free_buffer = TRUE;
++
++ return TRUE;
++}
++
++static void
++crtc_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
++{
++}
++
++static void
++crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
++{
++}
++
++static void
++crtc_show_cursor (xf86CrtcPtr crtc)
++{
++}
++
++static void
++crtc_hide_cursor (xf86CrtcPtr crtc)
++{
++}
++
++static void
++crtc_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
++{
++}
++
++static PixmapPtr
++crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
++{
++ return NULL;
++}
++
++static void *
++crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
++{
++ return NULL;
++}
++
++static void
++crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
++{
++}
++
++static void
++xmir_crtc_destroy(xf86CrtcPtr crtc)
++{
++ struct xmir_crtc *xmir_crtc = crtc->driver_private;
++
++ if (xmir_crtc->root_fragment->surface != NULL)
++ mir_surface_release(xmir_crtc->root_fragment->surface, NULL, NULL);
++
++ free(xmir_crtc);
++}
++
++static const xf86CrtcFuncsRec crtc_funcs = {
++ .dpms = xmir_crtc_dpms,
++ .set_mode_major = xmir_crtc_set_mode_major,
++ .set_cursor_colors = crtc_set_cursor_colors,
++ .set_cursor_position = crtc_set_cursor_position,
++ .show_cursor = crtc_show_cursor,
++ .hide_cursor = crtc_hide_cursor,
++ .load_cursor_argb = crtc_load_cursor_argb,
++ .shadow_create = crtc_shadow_create,
++ .shadow_allocate = crtc_shadow_allocate,
++ .shadow_destroy = crtc_shadow_destroy,
++ .destroy = xmir_crtc_destroy,
++};
++
++static void
++xmir_output_dpms(xf86OutputPtr output, int mode)
++{
++ return;
++}
++
++static xf86OutputStatus
++xmir_output_detect(xf86OutputPtr output)
++{
++ MirDisplayOutput *mir_output = output->driver_private;
++ return mir_output->connected ? XF86OutputStatusConnected : XF86OutputStatusDisconnected;
++}
++
++static Bool
++xmir_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
++{
++ return MODE_OK;
++}
++
++static DisplayModePtr
++xmir_output_get_modes(xf86OutputPtr xf86output)
++{
++ MirDisplayOutput *mir_output = xf86output->driver_private;
++ DisplayModePtr modes = NULL;
++
++ for (int i = 0; i < mir_output->num_modes; i++) {
++ DisplayModePtr mode = xmir_create_xf86mode(&mir_output->modes[i]);
++
++ mode->type = M_T_DRIVER;
++ if (i == mir_output->preferred_mode)
++ mode->type |= M_T_PREFERRED;
++
++ modes = xf86ModesAdd(modes, mode);
++ }
++ /* TODO: Get Mir to send us the EDID blob and add that */
++
++ return modes;
++}
++
++static void
++xmir_output_destroy(xf86OutputPtr xf86output)
++{
++ /* The MirDisplayOutput* in driver_private gets cleaned up by
++ mir_display_config_destroy() */
++}
++
++static const xf86OutputFuncsRec xmir_output_funcs = {
++ .dpms = xmir_output_dpms,
++ .detect = xmir_output_detect,
++ .mode_valid = xmir_output_mode_valid,
++ .get_modes = xmir_output_get_modes,
++ .destroy = xmir_output_destroy
++};
++
++
++struct xmir_visit_set_pixmap_window {
++ PixmapPtr old, new;
++};
++
++static int
++xmir_visit_set_window_pixmap(WindowPtr window, pointer data)
++{
++ struct xmir_visit_set_pixmap_window *visit = data;
++
++ if (window->drawable.pScreen->GetWindowPixmap(window) == visit->old) {
++ window->drawable.pScreen->SetWindowPixmap(window, visit->new);
++ return WT_WALKCHILDREN;
++ }
++
++ return WT_DONTWALKCHILDREN;
++}
++
++static void
++xmir_set_screen_pixmap(PixmapPtr old_front, PixmapPtr new_front)
++{
++ struct xmir_visit_set_pixmap_window visit = {
++ .old = old_front,
++ .new = new_front
++ };
++ (old_front->drawable.pScreen->SetScreenPixmap)(new_front);
++
++ TraverseTree(old_front->drawable.pScreen->root, &xmir_visit_set_window_pixmap, &visit);
++}
++
++static Bool
++xmir_resize(ScrnInfoPtr scrn, int width, int height)
++{
++ xf86CrtcConfigPtr crtc_cfg = XF86_CRTC_CONFIG_PTR(scrn);
++ ScreenPtr screen = xf86ScrnToScreen(scrn);
++ PixmapPtr old_screen_pixmap, new_screen_pixmap;
++
++ if (scrn->virtualX == width && scrn->virtualY == height)
++ return TRUE;
++
++ old_screen_pixmap = screen->GetScreenPixmap(screen);
++ new_screen_pixmap = screen->CreatePixmap(screen, width, height, scrn->depth,
++ CREATE_PIXMAP_USAGE_BACKING_PIXMAP);
++
++ if (!new_screen_pixmap)
++ return FALSE;
++
++ scrn->virtualX = width;
++ scrn->virtualY = height;
++ scrn->displayWidth = width;
++
++ for (int i = 0; i < crtc_cfg->num_crtc; i++) {
++ xf86CrtcPtr crtc = crtc_cfg->crtc[i];
++
++ if (!crtc->enabled)
++ continue;
++
++ xmir_crtc_set_mode_major(crtc, &crtc->mode,
++ crtc->rotation, crtc->x, crtc->y);
++ }
++
++ xmir_set_screen_pixmap(old_screen_pixmap, new_screen_pixmap);
++ screen->DestroyPixmap(old_screen_pixmap);
++
++ xf86_reload_cursors(screen);
++
++ return TRUE;
++}
++
++static const xf86CrtcConfigFuncsRec config_funcs = {
++ xmir_resize
++};
++
++static void
++xmir_handle_hotplug(void *ctx)
++{
++ ScrnInfoPtr scrn = *(ScrnInfoPtr *)ctx;
++ xf86CrtcConfigPtr crtc_config = XF86_CRTC_CONFIG_PTR(scrn);
++
++ if (crtc_config->num_crtc == 0)
++ FatalError("[xmir] Received hotplug event, but have no CRTCs?\n");
++
++ xmir_update_config(crtc_config);
++
++ /* Trigger RANDR refresh */
++ RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
++}
++
++static void
++xmir_display_config_callback(MirConnection *unused, void *ctx)
++{
++ xmir_screen *xmir = ctx;
++
++ xmir_post_to_eventloop(xmir->hotplug_event_handler, &xmir->scrn);
++}
++
++Bool
++xmir_mode_pre_init(ScrnInfoPtr scrn, xmir_screen *xmir)
++{
++ int i;
++ MirDisplayConfiguration *display_config;
++ xf86CrtcPtr xf86crtc;
++ int output_type_count[mir_display_output_type_edp + 1];
++
++ memset(output_type_count, 0, sizeof output_type_count);
++
++ /* Set up CRTC config functions */
++ xf86CrtcConfigInit(scrn, &config_funcs);
++
++ /* We don't scanout of a single surface, so we don't have a scanout limit */
++ xf86CrtcSetSizeRange(scrn,
++ 320, 320,
++ INT16_MAX, INT16_MAX);
++
++ /* Hook up hotplug notification */
++ xmir->hotplug_event_handler =
++ xmir_register_handler(&xmir_handle_hotplug,
++ sizeof (ScreenPtr));
++
++ mir_connection_set_display_config_change_callback(
++ xmir_connection_get(),
++ &xmir_display_config_callback, xmir);
++
++ display_config =
++ mir_connection_create_display_config(xmir_connection_get());
++
++ xmir->root_window_fragments = malloc((display_config->cards[0].max_simultaneous_outputs + 1) *
++ sizeof(xmir_window *));
++ xmir->root_window_fragments[display_config->cards[0].max_simultaneous_outputs] = NULL;
++
++ if (xmir->root_window_fragments == NULL)
++ return FALSE;
++
++ for (i = 0; i < display_config->num_outputs; i++) {
++ xf86OutputPtr xf86output;
++ char name[32];
++ MirDisplayOutput *mir_output = &display_config->outputs[i];
++ const char* output_type_str = xmir_get_output_type_str(mir_output);
++ int type_count = i;
++
++ if (mir_output->type >= 0 && mir_output->type <= mir_display_output_type_edp)
++ type_count = output_type_count[mir_output->type]++;
++
++ snprintf(name, sizeof name, "%s-%d", output_type_str, type_count);
++ xf86output = xf86OutputCreate(scrn, &xmir_output_funcs, name);
++
++ xmir_output_populate(xf86output, mir_output);
++ }
++
++ for (i = 0; i < display_config->cards[0].max_simultaneous_outputs; i++) {
++ struct xmir_crtc *xmir_crtc = malloc(sizeof *xmir_crtc);
++ if (xmir_crtc == NULL)
++ return FALSE;
++
++ xmir_crtc->xmir = xmir;
++ xmir_crtc->root_fragment = calloc(1, sizeof *xmir_crtc->root_fragment);
++ xmir_crtc->config = display_config;
++
++ if (xmir_crtc->root_fragment == NULL)
++ return FALSE;
++
++ xmir->root_window_fragments[i] = xmir_crtc->root_fragment;
++ RegionNull(&xmir_crtc->root_fragment->region);
++
++ xf86crtc = xf86CrtcCreate(scrn, &crtc_funcs);
++ xf86crtc->driver_private = xmir_crtc;
++ }
++
++ xf86SetScrnInfoModes(scrn);
++
++ /* TODO: Use initial Mir state rather than setting up our own */
++ xf86InitialConfiguration(scrn, TRUE);
++
++ return TRUE;
++}
+--- /dev/null
++++ b/hw/xfree86/xmir/xmir-private.h
+@@ -0,0 +1,106 @@
++/*
++ * Copyright © 2012 Canonical, Inc
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Soft-
++ * ware"), to deal in the Software without restriction, including without
++ * limitation the rights to use, copy, modify, merge, publish, distribute,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, provided that the above copyright
++ * notice(s) and this permission notice appear in all copies of the Soft-
++ * ware and that both the above copyright notice(s) and this permission
++ * notice appear in supporting documentation.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
++ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
++ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
++ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
++ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
++ * MANCE OF THIS SOFTWARE.
++ *
++ * Except as contained in this notice, the name of a copyright holder shall
++ * not be used in advertising or otherwise to promote the sale, use or
++ * other dealings in this Software without prior written authorization of
++ * the copyright holder.
++ *
++ * Authors:
++ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com)
++ */
++
++#ifndef _XMIR_PRIVATE_H
++#define _XMIR_PRIVATE_H
++
++#include <mir_toolkit/mir_client_library.h>
++#include "xmir.h"
++#include "xf86str.h"
++#include "list.h"
++#include "scrnintstr.h"
++#include "regionstr.h"
++
++#define MIR_MAX_BUFFER_AGE 3
++
++typedef struct xmir_marshall_handler xmir_marshall_handler;
++
++struct xmir_screen {
++ ScrnInfoPtr scrn;
++ CreateWindowProcPtr CreateWindow;
++ DestroyWindowProcPtr DestroyWindow;
++ xmir_driver * driver;
++ xmir_marshall_handler *submit_rendering_handler;
++ xmir_marshall_handler *hotplug_event_handler;
++ xmir_marshall_handler *focus_event_handler;
++ struct xorg_list damage_list;
++ struct xmir_window **root_window_fragments; /* NULL terminated array of xmir_window * */
++ unsigned int dpms_on:1; /* Until Mir is less stupid about DPMS */
++};
++
++struct xmir_window {
++ WindowPtr win;
++ MirSurface *surface;
++ RegionRec region;
++ RegionRec past_damage[MIR_MAX_BUFFER_AGE];
++ DamagePtr damage;
++ int damage_index;
++ struct xorg_list link_damage;
++ unsigned int has_free_buffer:1;
++ unsigned int damaged:1;
++};
++
++MirConnection *
++xmir_connection_get(void);
++
++xmir_screen *
++xmir_screen_get(ScreenPtr screen);
++
++xmir_window *
++xmir_window_get(WindowPtr win);
++
++void
++xmir_window_enable_damage_tracking(xmir_window *xmir_win);
++
++void
++xmir_window_disable_damage_tracking(xmir_window *xmir_win);
++
++
++Bool
++xmir_screen_init_window(ScreenPtr screen, xmir_screen *xmir);
++
++Bool
++xmir_mode_pre_init(ScrnInfoPtr scrn, xmir_screen *xmir);
++
++void
++xmir_init_thread_to_eventloop(void);
++
++xmir_marshall_handler *
++xmir_register_handler(void (*msg_handler)(void *msg), size_t msg_size);
++
++void
++xmir_post_to_eventloop(xmir_marshall_handler *handler, void *msg);
++
++void
++xmir_process_from_eventloop(void);
++
++ #endif /* _MIR_PRIVATE_H */
+--- /dev/null
++++ b/hw/xfree86/xmir/xmir-thread-proxy.c
+@@ -0,0 +1,124 @@
++/*
++ * Copyright © 2012 Canonical, Inc
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Soft-
++ * ware"), to deal in the Software without restriction, including without
++ * limitation the rights to use, copy, modify, merge, publish, distribute,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, provided that the above copyright
++ * notice(s) and this permission notice appear in all copies of the Soft-
++ * ware and that both the above copyright notice(s) and this permission
++ * notice appear in supporting documentation.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
++ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
++ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
++ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
++ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
++ * MANCE OF THIS SOFTWARE.
++ *
++ * Except as contained in this notice, the name of a copyright holder shall
++ * not be used in advertising or otherwise to promote the sale, use or
++ * other dealings in this Software without prior written authorization of
++ * the copyright holder.
++ *
++ * Authors:
++ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com)
++ */
++
++#include <stdint.h>
++#include <string.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <errno.h>
++
++#include "xf86.h"
++#include "xmir-private.h"
++
++struct xmir_marshall_handler {
++ void (*msg_handler)(void *msg);
++ size_t msg_size;
++ char msg[];
++};
++
++static int pipefds[2];
++
++static void
++xmir_wakeup_handler(pointer data, int err, pointer read_mask)
++{
++ if (err >= 0 && FD_ISSET(pipefds[0], (fd_set *)read_mask))
++ xmir_process_from_eventloop();
++}
++
++void
++xmir_init_thread_to_eventloop(void)
++{
++ int err = pipe(pipefds);
++ if (err == -1)
++ FatalError("[XMIR] Failed to create thread-proxy pipes: %s\n", strerror(errno));
++
++ /* Set the read end to not block; we'll pull from this in the event loop
++ * We don't need to care about the write end, as that'll be written to
++ * from its own thread
++ */
++ fcntl(pipefds[0], F_SETFL, O_NONBLOCK);
++
++ AddGeneralSocket(pipefds[0]);
++ RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
++ xmir_wakeup_handler,
++ NULL);
++}
++
++xmir_marshall_handler *
++xmir_register_handler(void (*msg_handler)(void *msg), size_t msg_size)
++{
++ xmir_marshall_handler *handler;
++
++ if (msg_size + sizeof *handler > PIPE_BUF)
++ return NULL;
++
++ handler = malloc(sizeof *handler + msg_size);
++ if (!handler)
++ return NULL;
++
++ handler->msg_handler = msg_handler;
++ handler->msg_size = msg_size;
++ return handler;
++}
++
++void
++xmir_post_to_eventloop(xmir_marshall_handler *handler, void *msg)
++{
++ ssize_t written;
++ const int total_size = sizeof *handler + handler->msg_size;
++ /* We require the total size to be less than PIPE_BUF to ensure an atomic write */
++ assert(total_size < PIPE_BUF);
++
++ memcpy(handler->msg, msg, handler->msg_size);
++ written = write(pipefds[1], handler, total_size);
++ if (written != total_size)
++ xf86Msg(X_ERROR, "[XMIR] Failed to proxy message to mainloop\n");
++}
++
++void
++xmir_process_from_eventloop(void)
++{
++ xmir_marshall_handler handler;
++ void *msg;
++
++ for (;;) {
++ if (read(pipefds[0], &handler, sizeof handler) < 0) {
++ return;
++ }
++
++ msg = malloc(handler.msg_size);
++ if(read(pipefds[0], msg, handler.msg_size) == handler.msg_size)
++ (*handler.msg_handler)(msg);
++ free(msg);
++ }
++}
++
+--- /dev/null
++++ b/hw/xfree86/xmir/xmir-window.c
+@@ -0,0 +1,343 @@
++/*
++ * Copyright © 2012 Canonical, Inc
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Soft-
++ * ware"), to deal in the Software without restriction, including without
++ * limitation the rights to use, copy, modify, merge, publish, distribute,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, provided that the above copyright
++ * notice(s) and this permission notice appear in all copies of the Soft-
++ * ware and that both the above copyright notice(s) and this permission
++ * notice appear in supporting documentation.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
++ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
++ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
++ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
++ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
++ * MANCE OF THIS SOFTWARE.
++ *
++ * Except as contained in this notice, the name of a copyright holder shall
++ * not be used in advertising or otherwise to promote the sale, use or
++ * other dealings in this Software without prior written authorization of
++ * the copyright holder.
++ *
++ * Authors:
++ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com)
++ */
++
++#ifdef HAVE_XORG_CONFIG_H
++#include "xorg-config.h"
++#endif
++#include <xorg-server.h>
++#include "windowstr.h"
++#include "regionstr.h"
++#include "damagestr.h"
++
++#include "xmir.h"
++#include "xmir-private.h"
++
++#include "xf86.h"
++
++#include <stdlib.h>
++#include <unistd.h>
++
++static DevPrivateKeyRec xmir_window_private_key;
++static const RegionRec xmir_empty_region = { {0, 0, 0, 0}, &RegionBrokenData };
++
++xmir_window *
++xmir_window_get(WindowPtr win)
++{
++ /* The root window is handled specially */
++ assert(win->parent != NULL);
++
++ return dixGetPrivate(&win->devPrivates, &xmir_window_private_key);
++}
++
++_X_EXPORT int
++xmir_window_get_fd(xmir_window *xmir_win)
++{
++ MirBufferPackage *package;
++
++ if (mir_platform_type_gbm != mir_surface_get_platform_type(xmir_win->surface))
++ FatalError("[xmir] Only supported on DRM Mir platform\n");
++
++ mir_surface_get_current_buffer(xmir_win->surface, &package);
++ if (package->fd_items != 1)
++ FatalError("[xmir] Unexpected buffer contents from Mir; this is a programming error\n");
++
++ return package->fd[0];
++}
++
++static void
++xmir_handle_buffer_available(void *ctx)
++{
++ xmir_screen *xmir;
++ xmir_window *mir_win = *(xmir_window **)ctx;
++
++ if (mir_win->surface == NULL)
++ return;
++
++ xmir = xmir_screen_get(xmir_window_to_windowptr(mir_win)->drawable.pScreen);
++
++ mir_win->has_free_buffer = TRUE;
++ mir_win->damage_index = (mir_win->damage_index + 1) % MIR_MAX_BUFFER_AGE;
++
++ if (xmir_window_is_dirty(mir_win))
++ (*xmir->driver->BufferAvailableForWindow)(mir_win,
++ xmir_window_get_dirty(mir_win));
++}
++
++static inline int
++index_in_damage_buffer(int current_index, int age)
++{
++ int index = (current_index - age) % MIR_MAX_BUFFER_AGE;
++
++ return index < 0 ? MIR_MAX_BUFFER_AGE + index : index;
++}
++
++static void
++handle_buffer_received(MirSurface *surf, void *ctx)
++{
++ xmir_window *xmir_win = ctx;
++
++ xmir_screen *xmir =
++ xmir_screen_get(xmir_window_to_windowptr(xmir_win)->drawable.pScreen);
++
++ xmir_post_to_eventloop(xmir->submit_rendering_handler, &xmir_win);
++}
++
++static RegionPtr
++damage_region_for_current_buffer(xmir_window *xmir_win)
++{
++ MirBufferPackage *package;
++ RegionPtr region;
++ int age;
++
++ mir_surface_get_current_buffer(xmir_win->surface, &package);
++ age = package->age;
++
++ region = &xmir_win->past_damage[index_in_damage_buffer(xmir_win->damage_index, age)];
++
++ /* As per EGL_EXT_buffer_age, contents are undefined for age == 0 */
++ if (age == 0)
++ RegionCopy(region, &xmir_win->region);
++
++ return region;
++}
++
++/* Submit rendering for @window to Mir
++ * @region is an (optional) damage region, to hint the compositor as to what
++ * region has changed. It can be NULL to indicate the whole window should be
++ * considered dirty.
++ */
++_X_EXPORT int
++xmir_submit_rendering_for_window(xmir_window *xmir_win,
++ RegionPtr region)
++{
++ RegionPtr tracking;
++
++ if (!xmir_screen_get(xmir_win->win->drawable.pScreen)->dpms_on)
++ return Success;
++
++ xmir_win->has_free_buffer = FALSE;
++ tracking = damage_region_for_current_buffer(xmir_win);
++ mir_surface_swap_buffers(xmir_win->surface, &handle_buffer_received, xmir_win);
++
++ if (region == NULL)
++ RegionEmpty(tracking);
++ else
++ RegionSubtract(tracking, tracking, region);
++
++ if (RegionNil(tracking))
++ xorg_list_del(&xmir_win->link_damage);
++
++ return Success;
++}
++
++_X_EXPORT Bool
++xmir_window_has_free_buffer(xmir_window *xmir_win)
++{
++ return xmir_win->has_free_buffer;
++}
++
++_X_EXPORT RegionPtr
++xmir_window_get_dirty(xmir_window *xmir_win)
++{
++ if (xorg_list_is_empty(&xmir_win->link_damage))
++ return (RegionPtr)&xmir_empty_region;
++
++ if (xmir_win->damaged) {
++ int i;
++ RegionPtr damage = DamageRegion(xmir_win->damage);
++ RegionIntersect(damage, damage, &xmir_win->region);
++
++ for (i = 0; i < MIR_MAX_BUFFER_AGE; i++) {
++ RegionUnion(&xmir_win->past_damage[i],
++ &xmir_win->past_damage[i],
++ damage);
++ }
++
++ DamageEmpty(xmir_win->damage);
++ xmir_win->damaged = 0;
++ }
++
++ return damage_region_for_current_buffer(xmir_win);
++}
++
++_X_EXPORT Bool
++xmir_window_is_dirty(xmir_window *xmir_win)
++{
++ return RegionNotEmpty(xmir_window_get_dirty(xmir_win));
++}
++
++_X_EXPORT WindowPtr
++xmir_window_to_windowptr(xmir_window *xmir_win)
++{
++ return xmir_win->win;
++}
++
++_X_EXPORT BoxPtr
++xmir_window_get_drawable_region(xmir_window *xmir_win)
++{
++ return RegionExtents(&xmir_win->region);
++}
++
++_X_EXPORT int32_t
++xmir_window_get_stride(xmir_window *xmir_win)
++{
++ MirBufferPackage *package;
++
++ mir_surface_get_current_buffer(xmir_win->surface, &package);
++
++ return package->stride;
++}
++
++static void
++damage_report(DamagePtr damage, RegionPtr region, void *ctx)
++{
++ xmir_window *xmir_win = ctx;
++
++ xmir_win->damaged = 1;
++ xorg_list_move(&xmir_win->link_damage,
++ &xmir_screen_get(damage->pScreen)->damage_list);
++}
++
++static void
++damage_destroy(DamagePtr damage, void *ctx)
++{
++ xmir_window *xmir_win = ctx;
++ xorg_list_del(&xmir_win->link_damage);
++}
++
++void
++xmir_window_enable_damage_tracking(xmir_window *xmir_win)
++{
++ WindowPtr win = xmir_win->win;
++
++ if (xmir_win->damage != NULL)
++ return;
++
++ xorg_list_init(&xmir_win->link_damage);
++ xmir_win->damage = DamageCreate(damage_report, damage_destroy,
++ DamageReportNonEmpty, TRUE,
++ win->drawable.pScreen, xmir_win);
++ DamageRegister(&win->drawable, xmir_win->damage);
++
++ for (int i = 0; i < MIR_MAX_BUFFER_AGE; i++) {
++ RegionNull(&xmir_win->past_damage[i]);
++ }
++ xmir_win->damage_index = 0;
++ xmir_win->damaged = 0;
++}
++
++void
++xmir_window_disable_damage_tracking(xmir_window *xmir_win)
++{
++ if (xmir_win->damage != NULL) {
++ DamageUnregister(xmir_win->damage);
++ DamageDestroy(xmir_win->damage);
++ xmir_win->damage = NULL;
++ }
++}
++
++static Bool
++xmir_create_window(WindowPtr win)
++{
++ ScreenPtr screen = win->drawable.pScreen;
++ xmir_screen *xmir = xmir_screen_get(screen);
++ Bool ret;
++
++ screen->CreateWindow = xmir->CreateWindow;
++ ret = (*screen->CreateWindow)(win);
++ screen->CreateWindow = xmir_create_window;
++
++ /* Until we support rootless operation, we care only for the root
++ * window, which has no parent.
++ */
++ if (win->parent == NULL) {
++ /* The CRTC setup has already created the root_window_fragments
++ array. We need to hook the root window into it */
++ for (int i = 0; xmir->root_window_fragments[i] != NULL; i++) {
++ xmir->root_window_fragments[i]->win = win;
++
++ /* TODO: This creates one Damage tracker per fragment; we only
++ really need one, though */
++ xmir_window_enable_damage_tracking(xmir->root_window_fragments[i]);
++ }
++ }
++ return ret;
++}
++
++static Bool
++xmir_destroy_window(WindowPtr win)
++{
++ ScreenPtr screen = win->drawable.pScreen;
++ xmir_screen *xmir = xmir_screen_get(screen);
++ Bool ret;
++
++ screen->DestroyWindow = xmir->DestroyWindow;
++ ret = (*screen->DestroyWindow)(win);
++ screen->DestroyWindow = xmir_destroy_window;
++
++ /* Until we support rootless operation, we care only for the root
++ * window, which has no parent.
++ */
++ if (win->parent == NULL) {
++ /* Break the link with the root_window_fragments */
++ for (int i = 0; xmir->root_window_fragments[i] != NULL; i++) {
++ xmir->root_window_fragments[i]->win = NULL;
++
++ /* We cannot use xmir_window_disable_damage_tracking here because
++ * the Damage extension will also clean it up on window destruction
++ */
++ xorg_list_del(&xmir->root_window_fragments[i]->link_damage);
++ }
++ }
++
++ return ret;
++}
++
++Bool
++xmir_screen_init_window(ScreenPtr screen, xmir_screen *xmir)
++{
++ if (!dixRegisterPrivateKey(&xmir_window_private_key, PRIVATE_WINDOW, 0))
++ return FALSE;
++
++ xmir->CreateWindow = screen->CreateWindow;
++ screen->CreateWindow = xmir_create_window;
++ xmir->DestroyWindow = screen->DestroyWindow;
++ screen->DestroyWindow = xmir_destroy_window;
++
++ xmir->submit_rendering_handler =
++ xmir_register_handler(&xmir_handle_buffer_available,
++ sizeof (xmir_window *));
++ if (xmir->submit_rendering_handler == NULL)
++ return FALSE;
++
++ return TRUE;
++}
+--- /dev/null
++++ b/hw/xfree86/xmir/xmir.c
+@@ -0,0 +1,263 @@
++/*
++ * Copyright © 2012 Canonical, Inc
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Soft-
++ * ware"), to deal in the Software without restriction, including without
++ * limitation the rights to use, copy, modify, merge, publish, distribute,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, provided that the above copyright
++ * notice(s) and this permission notice appear in all copies of the Soft-
++ * ware and that both the above copyright notice(s) and this permission
++ * notice appear in supporting documentation.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
++ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
++ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
++ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
++ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
++ * MANCE OF THIS SOFTWARE.
++ *
++ * Except as contained in this notice, the name of a copyright holder shall
++ * not be used in advertising or otherwise to promote the sale, use or
++ * other dealings in this Software without prior written authorization of
++ * the copyright holder.
++ *
++ * Authors:
++ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com)
++ */
++
++#ifdef HAVE_XORG_CONFIG_H
++#include <xorg-config.h>
++#endif
++
++#include "xmir.h"
++#include "xmir-private.h"
++
++#include "list.h"
++#include "xf86.h"
++#include "xf86Crtc.h"
++#include "xf86Priv.h"
++
++#include <xf86drm.h>
++#include <string.h>
++
++#include <mir_toolkit/mir_client_library.h>
++#include <mir_toolkit/mir_client_library_drm.h>
++
++static DevPrivateKeyRec xmir_screen_private_key;
++/*
++ * We have only a single Mir connection, regardless of how many
++ * drivers load.
++ */
++static MirConnection *conn;
++
++MirConnection *
++xmir_connection_get(void)
++{
++ return conn;
++}
++
++xmir_screen *
++xmir_screen_get(ScreenPtr screen)
++{
++ return dixGetPrivate(&screen->devPrivates, &xmir_screen_private_key);
++}
++
++_X_EXPORT int
++xmir_get_drm_fd(const char *busid)
++{
++ MirPlatformPackage platform;
++ int i, fd = -1;
++
++ mir_connection_get_platform(conn, &platform);
++
++ for (i = 0; i < platform.fd_items; ++i) {
++ char *fd_busid = drmGetBusid(platform.fd[i]);
++ if (!strcasecmp(busid, fd_busid))
++ fd = platform.fd[i];
++ drmFreeBusid(fd_busid);
++ }
++ return fd;
++}
++
++static void
++handle_auth_magic(int status, void *ctx)
++{
++ int *retVal = ctx;
++ *retVal = status;
++}
++
++_X_EXPORT int
++xmir_auth_drm_magic(xmir_screen *xmir, uint32_t magic)
++{
++ int status;
++ mir_wait_for(mir_connection_drm_auth_magic(xmir_connection_get(),
++ magic,
++ &handle_auth_magic,
++ &status));
++ return status;
++}
++
++_X_EXPORT xmir_screen *
++xmir_screen_create(ScrnInfoPtr scrn)
++{
++ xmir_screen *xmir = calloc (1, sizeof *xmir);
++ if (xmir == NULL)
++ return NULL;
++
++ xmir->scrn = scrn;
++ xmir->dpms_on = TRUE;
++
++ return xmir;
++}
++
++_X_EXPORT Bool
++xmir_screen_pre_init(ScrnInfoPtr scrn, xmir_screen *xmir, xmir_driver *driver)
++{
++ xmir->driver = driver;
++ xorg_list_init(&xmir->damage_list);
++
++ if (!xmir_mode_pre_init(scrn, xmir))
++ return FALSE;
++
++ return TRUE;
++}
++
++static void xmir_handle_focus_event(void *ctx)
++{
++ Bool new_focus = *(Bool *)ctx;
++ xf86Msg(X_INFO, "[XMir] Handling focus event, new_focus = %s\n", new_focus ? "TRUE" : "FALSE");
++
++ /* TODO: Split xf86VTSwitch out so that we don't need to check xf86VTOwner*/
++ /* TODO: Disable input on startup until we receive a usc ACK */
++ if (new_focus && !xf86VTOwner())
++ xf86VTSwitch();
++
++ if (!new_focus && xf86VTOwner())
++ xf86VTSwitch();
++}
++
++static void xmir_handle_lifecycle_event(MirConnection *unused, MirLifecycleState state, void *ctx)
++{
++ (void)unused;
++ xmir_screen *xmir = ctx;
++ Bool new_focus;
++ switch(state)
++ {
++ case mir_lifecycle_state_will_suspend:
++ new_focus = FALSE;
++ break;
++ case mir_lifecycle_state_resumed:
++ new_focus = TRUE;
++ break;
++ default:
++ xf86Msg(X_ERROR, "Received unknown Mir lifetime event\n");
++ return;
++ }
++ xmir_post_to_eventloop(xmir->focus_event_handler, &new_focus);
++}
++
++_X_EXPORT Bool
++xmir_screen_init(ScreenPtr screen, xmir_screen *xmir)
++{
++ if (!dixRegisterPrivateKey(&xmir_screen_private_key, PRIVATE_SCREEN, 0))
++ return FALSE;
++ dixSetPrivate(&screen->devPrivates, &xmir_screen_private_key, xmir);
++
++ if (!xmir_screen_init_window(screen, xmir))
++ return FALSE;
++
++ if (!xf86_cursors_init(screen, 0,0,0))
++ xf86Msg(X_WARNING, "xf86Cursor initialisation failed\n");
++
++ /* Hook up focus -> VT switch proxy */
++ xmir->focus_event_handler =
++ xmir_register_handler(&xmir_handle_focus_event,
++ sizeof(Bool));
++ if (xmir->focus_event_handler == NULL)
++ return FALSE;
++
++ mir_connection_set_lifecycle_event_callback(xmir_connection_get(),
++ &xmir_handle_lifecycle_event,
++ xmir);
++
++ return TRUE;
++}
++
++_X_EXPORT void
++xmir_screen_close(ScreenPtr screen, xmir_screen *xmir)
++{
++
++}
++
++_X_EXPORT void
++xmir_screen_destroy(xmir_screen *xmir)
++{
++
++}
++
++_X_EXPORT void
++xmir_screen_for_each_damaged_window(xmir_screen *xmir, xmir_window_proc callback)
++{
++ xmir_window *xmir_win, *tmp_win;
++ xorg_list_for_each_entry_safe(xmir_win, tmp_win, &xmir->damage_list, link_damage) {
++ if (xmir_window_has_free_buffer(xmir_win) &&
++ xmir_window_is_dirty(xmir_win))
++ (*callback)(xmir_win, xmir_window_get_dirty(xmir_win));
++ }
++}
++
++static MODULESETUPPROTO(xMirSetup);
++static MODULETEARDOWNPROTO(xMirTeardown);
++
++static XF86ModuleVersionInfo VersRec = {
++ "xmir",
++ MODULEVENDORSTRING,
++ MODINFOSTRING1,
++ MODINFOSTRING2,
++ XORG_VERSION_CURRENT,
++ 1, 0, 0,
++ ABI_CLASS_EXTENSION,
++ ABI_EXTENSION_VERSION,
++ MOD_CLASS_NONE,
++ {0, 0, 0, 0}
++};
++
++_X_EXPORT XF86ModuleData xmirModuleData = { &VersRec, xMirSetup, xMirTeardown };
++
++static pointer
++xMirSetup(pointer module, pointer opts, int *errmaj, int *errmin)
++{
++ static Bool setupDone = FALSE;
++
++ if (setupDone) {
++ if (errmaj)
++ *errmaj = LDR_ONCEONLY;
++ return NULL;
++ }
++
++ conn = mir_connect_sync(mirSocket, mirID);
++
++ if (!mir_connection_is_valid(conn)) {
++ if (errmaj)
++ *errmaj = LDR_MODSPECIFIC;
++ FatalError("Failed to connect to Mir: %s\n",
++ mir_connection_get_error_message(conn));
++ return NULL;
++ }
++
++ xmir_init_thread_to_eventloop();
++
++ setupDone = TRUE;
++
++ return module;
++}
++
++static void
++xMirTeardown(pointer module)
++{
++}
+--- /dev/null
++++ b/hw/xfree86/xmir/xmir.h
+@@ -0,0 +1,103 @@
++/*
++ * Copyright © 2012 Canonical, Inc
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Soft-
++ * ware"), to deal in the Software without restriction, including without
++ * limitation the rights to use, copy, modify, merge, publish, distribute,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, provided that the above copyright
++ * notice(s) and this permission notice appear in all copies of the Soft-
++ * ware and that both the above copyright notice(s) and this permission
++ * notice appear in supporting documentation.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
++ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
++ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
++ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
++ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
++ * MANCE OF THIS SOFTWARE.
++ *
++ * Except as contained in this notice, the name of a copyright holder shall
++ * not be used in advertising or otherwise to promote the sale, use or
++ * other dealings in this Software without prior written authorization of
++ * the copyright holder.
++ *
++ * Authors:
++ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com)
++ */
++
++#ifndef _XMIR_H
++#define _XMIR_H
++
++#include <stdint.h>
++#include <mir_toolkit/mir_client_library.h>
++
++#include "xf86str.h"
++#include "scrnintstr.h"
++#include "window.h"
++
++typedef struct xmir_screen xmir_screen;
++typedef struct xmir_window xmir_window;
++
++typedef void (*xmir_window_proc)(xmir_window *xmir_win, RegionPtr damaged_region);
++
++#define XMIR_DRIVER_VERSION 1
++typedef struct {
++ int version;
++ xmir_window_proc BufferAvailableForWindow;
++} xmir_driver;
++
++_X_EXPORT int
++xmir_get_drm_fd(const char *busid);
++
++_X_EXPORT int
++xmir_auth_drm_magic(xmir_screen *xmir, uint32_t magic);
++
++_X_EXPORT xmir_screen *
++xmir_screen_create(ScrnInfoPtr scrn);
++
++_X_EXPORT Bool
++xmir_screen_pre_init(ScrnInfoPtr scrn, xmir_screen *xmir, xmir_driver *driver);
++
++_X_EXPORT Bool
++xmir_screen_init(ScreenPtr screen, xmir_screen *xmir);
++
++_X_EXPORT void
++xmir_screen_close(ScreenPtr screen, xmir_screen *xmir);
++
++_X_EXPORT void
++xmir_screen_destroy(xmir_screen *xmir);
++
++_X_EXPORT WindowPtr
++xmir_window_to_windowptr(xmir_window *xmir_win);
++
++_X_EXPORT int
++xmir_window_get_fd(xmir_window *xmir_win);
++
++_X_EXPORT int
++xmir_submit_rendering_for_window(xmir_window *xmir_win,
++ RegionPtr region);
++
++_X_EXPORT Bool
++xmir_window_has_free_buffer(xmir_window *xmir_win);
++
++_X_EXPORT RegionPtr
++xmir_window_get_dirty(xmir_window *xmir_win);
++
++_X_EXPORT Bool
++xmir_window_is_dirty(xmir_window *xmir_win);
++
++_X_EXPORT BoxPtr
++xmir_window_get_drawable_region(xmir_window *xmir_win);
++
++_X_EXPORT int32_t
++xmir_window_get_stride(xmir_window *xmir_win);
++
++_X_EXPORT void
++xmir_screen_for_each_damaged_window(xmir_screen *xmir, xmir_window_proc callback);
++
++#endif /* _XMIR_H */
+--- a/include/list.h
++++ b/include/list.h
+@@ -184,6 +184,14 @@
+ prev->next = next;
+ }
+
++static inline void
++xorg_list_move(struct xorg_list *entry, struct xorg_list *head)
++{
++ __xorg_list_del(entry->prev, entry->next);
++ __xorg_list_add(entry, head->prev, head);
++}
++
++
+ /**
+ * Remove the element from the list it is in. Using this function will reset
+ * the pointers to/from this element so it is removed from the list. It does
+--- a/include/xorg-server.h.in
++++ b/include/xorg-server.h.in
+@@ -224,4 +224,7 @@
+ /* Use XTrans FD passing support */
+ #undef XTRANS_SEND_FDS
+
++/* Build XMIR nested server */
++#undef XMIR
++
+ #endif /* _XORG_SERVER_H_ */
+--- a/test/Makefile.am
++++ b/test/Makefile.am
+@@ -6,6 +6,9 @@
+ # For now, requires xf86 ddx, could be adjusted to use another
+ SUBDIRS += xi2
+ noinst_PROGRAMS += xkb input xtest misc fixes xfree86 hashtabletest os signal-logging touch
++if XMIR
++noinst_PROGRAMS += xmir-thread-proxy
++endif #XMIR
+ endif
+ check_LTLIBRARIES = libxservertest.la
+
+@@ -38,6 +41,8 @@
+ signal_logging_LDADD=$(TEST_LDADD)
+ hashtabletest_LDADD=$(TEST_LDADD) $(top_srcdir)/Xext/hashtable.c
+ os_LDADD=$(TEST_LDADD)
++xmir_thread_proxy_LDADD=$(TEST_LDADD) $(top_srcdir)/hw/xfree86/xmir/xmir-thread-proxy.c -lpthread
++xmir_thread_proxy_CFLAGS=$(AM_CFLAGS) $(XMIR_CFLAGS) -I$(top_srcdir)/hw/xfree86/xmir -I$(top_srcdir)/hw/xfree86/common
+
+ libxservertest_la_LIBADD = $(XSERVER_LIBS)
+ if XORG
+--- /dev/null
++++ b/test/xmir-thread-proxy.c
+@@ -0,0 +1,154 @@
++/*
++ * Copyright © 2012 Canonical, Inc
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Soft-
++ * ware"), to deal in the Software without restriction, including without
++ * limitation the rights to use, copy, modify, merge, publish, distribute,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, provided that the above copyright
++ * notice(s) and this permission notice appear in all copies of the Soft-
++ * ware and that both the above copyright notice(s) and this permission
++ * notice appear in supporting documentation.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
++ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
++ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
++ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
++ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
++ * MANCE OF THIS SOFTWARE.
++ *
++ * Except as contained in this notice, the name of a copyright holder shall
++ * not be used in advertising or otherwise to promote the sale, use or
++ * other dealings in this Software without prior written authorization of
++ * the copyright holder.
++ *
++ * Authors:
++ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com)
++ */
++
++#ifdef HAVE_DIX_CONFIG_H
++#include <dix-config.h>
++#endif
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <pthread.h>
++#include <unistd.h>
++
++#include "xmir-private.h"
++
++struct test_content {
++ int *variable;
++ int value;
++};
++
++static void
++_test_callback(void *msg_content)
++{
++ struct test_content *content = msg_content;
++ *content->variable = content->value;
++}
++
++static void
++xmir_test_marshall_to_eventloop(void)
++{
++ xmir_marshall_handler *test_marshaller;
++ struct test_content msg;
++ int check = 0;
++
++ xmir_init_thread_to_eventloop();
++
++ test_marshaller = xmir_register_handler(&_test_callback, sizeof msg);
++
++ msg.variable = ✓
++ msg.value = 1;
++
++ xmir_post_to_eventloop(test_marshaller, &msg);
++ xmir_process_from_eventloop();
++
++ assert(check == 1);
++}
++
++static void
++_racy_test_callback(void *msg_content)
++{
++ struct test_content *content = msg_content;
++ int new_value = *content->variable + 1;
++ /* Ensure the other threads get to run and see the old value of content->variable */
++ usleep(100);
++ *content->variable = new_value;
++}
++
++struct thread_context {
++ xmir_marshall_handler *marshaller;
++ struct test_content *msg;
++};
++
++static void *
++_post_racy_msg(void *thread_ctx)
++{
++ struct thread_context *ctx = thread_ctx;
++
++ xmir_post_to_eventloop(ctx->marshaller, ctx->msg);
++
++ return NULL;
++}
++
++#define NUM_THREADS 10
++
++static void
++xmir_test_many_threads_to_eventloop(void)
++{
++ pthread_t threads[NUM_THREADS];
++ pthread_attr_t attr;
++ xmir_marshall_handler *test_marshaller;
++ struct thread_context ctx;
++ struct test_content msg;
++ int check = 0, i;
++
++ pthread_attr_init(&attr);
++ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
++
++ xmir_init_thread_to_eventloop();
++
++ test_marshaller = xmir_register_handler(&_racy_test_callback, sizeof msg);
++
++ msg.variable = ✓
++
++ ctx.marshaller = test_marshaller;
++ ctx.msg = &msg;
++
++ for (i = 0; i < NUM_THREADS; i++) {
++ pthread_create(&threads[i], &attr, _post_racy_msg, (void *)&ctx);
++ }
++
++ pthread_attr_destroy(&attr);
++
++ for (i = 0; i < NUM_THREADS; i++) {
++ pthread_join(threads[i], NULL);
++ }
++
++ xmir_process_from_eventloop();
++
++ assert(check == NUM_THREADS);
++}
++
++static void
++xmir_test_refuses_to_marshall_too_large_msg(void)
++{
++ xmir_init_thread_to_eventloop();
++
++ assert(xmir_register_handler(&_test_callback, PIPE_BUF) == NULL);
++}
++
++int
++main(int argc, char **argv)
++{
++ xmir_test_marshall_to_eventloop();
++ xmir_test_many_threads_to_eventloop();
++ xmir_test_refuses_to_marshall_too_large_msg();
++}