diff --git a/hw/xwayland/man/Xwayland.man b/hw/xwayland/man/Xwayland.man
index b9202160c8dd62d12f1eefa1b583cfe69c9d6944..97e3c6957b7a91d4dce4e87f93375041d605c04e 100644
--- a/hw/xwayland/man/Xwayland.man
+++ b/hw/xwayland/man/Xwayland.man
@@ -53,6 +53,11 @@ backend first, then fallback to the GBM backend if EGLStream is not supported
 by the Wayland server. Without this option, \fIXwayland\fP tries the GBM
 backend first, and fallback to EGLStream if GBM is not usable.
 .TP 8
+.B \-fullscreen
+Set the Xwayland window fullscreen when running rootful.
+
+This option is not compatible with rootless mode (\fI-rootless\fP).
+.TP 8
 .B \-geometry \fIWxH\fP
 Sets the geometry of the \fIXwayland\fP window to \fIWxH\fP when running rootful.
 
diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c
index 771f262b07c2e1f9e750a76f37a54fc858ebe50b..5261125143d25194cf2782ee1edc8b5fa7344cfc 100644
--- a/hw/xwayland/xwayland-screen.c
+++ b/hw/xwayland/xwayland-screen.c
@@ -676,6 +676,9 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
             }
             use_fixed_size = 1;
         }
+        else if (strcmp(argv[i], "-fullscreen") == 0) {
+            xwl_screen->fullscreen = 1;
+        }
     }
 
     if (use_fixed_size) {
@@ -732,6 +735,16 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
                              &registry_listener, xwl_screen);
     xwl_screen_roundtrip(xwl_screen);
 
+    if (xwl_screen->fullscreen && xwl_screen->rootless) {
+        ErrorF("error, cannot set fullscreen when running rootless\n");
+        return FALSE;
+    }
+
+    if (xwl_screen->fullscreen && !xwl_screen_has_viewport_support(xwl_screen)) {
+        ErrorF("missing viewport support in the compositor, ignoring fullscreen\n");
+        xwl_screen->fullscreen = FALSE;
+    }
+
     if (!xwl_screen->rootless && !xwl_screen->xdg_wm_base) {
         ErrorF("missing XDG-WM-Base protocol\n");
         return FALSE;
diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h
index 5f2782d330fefb97514d8dcc03489995953b3a3d..360e2aa855891ba307fe47438e07cbf8f4b2bad0 100644
--- a/hw/xwayland/xwayland-screen.h
+++ b/hw/xwayland/xwayland-screen.h
@@ -58,6 +58,7 @@ struct xwl_screen {
     int glamor;
     int present;
     int force_xrandr_emulation;
+    int fullscreen;
 
     CreateScreenResourcesProcPtr CreateScreenResources;
     CloseScreenProcPtr CloseScreen;
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index 491ce223ec785d29b8f913638f3c0fdf6ab059c3..25c8f6cf7e47a9e6d777e53a9a2e914f2f293af5 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -267,6 +267,41 @@ window_get_client_toplevel(WindowPtr window)
     return window;
 }
 
+static struct xwl_output *
+xwl_window_get_output(struct xwl_window *xwl_window)
+{
+    struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
+    struct xwl_output *xwl_output;
+
+    xwl_output = xwl_output_from_wl_output(xwl_screen, xwl_window->wl_output);
+
+    if (xwl_output)
+        return xwl_output;
+
+    return xwl_screen_get_first_output(xwl_screen);
+}
+
+static Bool
+xwl_window_should_enable_viewport_fullscreen(struct xwl_window *xwl_window,
+                                             struct xwl_output **xwl_output_ret,
+                                             struct xwl_emulated_mode *emulated_mode_ret)
+{
+    struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
+    struct xwl_output *xwl_output;
+
+    xwl_output = xwl_window_get_output(xwl_window);
+    if (!xwl_output)
+        return FALSE;
+
+    *xwl_output_ret = xwl_output;
+    emulated_mode_ret->server_output_id = 0;
+    emulated_mode_ret->width = xwl_screen->width;
+    emulated_mode_ret->height = xwl_screen->height;
+    emulated_mode_ret->from_vidmode = FALSE;
+
+    return TRUE;
+}
+
 static Bool
 xwl_window_should_enable_viewport(struct xwl_window *xwl_window,
                                   struct xwl_output **xwl_output_ret,
@@ -279,7 +314,15 @@ xwl_window_should_enable_viewport(struct xwl_window *xwl_window,
     WindowPtr window;
     DrawablePtr drawable;
 
-    if (!xwl_screen_has_resolution_change_emulation(xwl_screen))
+    if (!xwl_screen_has_viewport_support(xwl_screen))
+        return FALSE;
+
+    if (xwl_screen->fullscreen)
+        return xwl_window_should_enable_viewport_fullscreen(xwl_window,
+                                                            xwl_output_ret,
+                                                            emulated_mode_ret);
+
+    if (!xwl_screen->rootless)
         return FALSE;
 
     window = window_get_client_toplevel(xwl_window->window);
@@ -401,12 +444,44 @@ send_surface_id_event(struct xwl_window *xwl_window)
                           &e, 1, SubstructureRedirectMask, NullGrab);
 }
 
+static Bool
+xwl_window_set_fullscreen(struct xwl_window *xwl_window)
+{
+    struct xwl_output *xwl_output;
+    struct wl_output *wl_output = NULL;
+
+    if (!xwl_window->xdg_toplevel)
+        return FALSE;
+
+    xwl_output = xwl_window_get_output(xwl_window);
+    if (xwl_output)
+        wl_output = xwl_output->output;
+
+    if (wl_output && xwl_window->wl_output_fullscreen == wl_output)
+        return FALSE;
+
+    xdg_toplevel_set_fullscreen(xwl_window->xdg_toplevel, wl_output);
+    xwl_window_check_resolution_change_emulation(xwl_window);
+    wl_surface_commit(xwl_window->surface);
+
+    xwl_window->wl_output_fullscreen = wl_output;
+
+    return TRUE;
+}
+
 static void
 xdg_surface_handle_configure(void *data,
                              struct xdg_surface *xdg_surface,
                              uint32_t serial)
 {
+    struct xwl_window *xwl_window = data;
+    struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
+
+    if (xwl_screen->fullscreen)
+        xwl_window_set_fullscreen(xwl_window);
+
     xdg_surface_ack_configure(xdg_surface, serial);
+    wl_surface_commit(xwl_window->surface);
 }
 
 static const struct xdg_surface_listener xdg_surface_listener = {
@@ -419,9 +494,14 @@ xwl_window_surface_enter(void *data,
                          struct wl_output *wl_output)
 {
     struct xwl_window *xwl_window = data;
+    struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
 
-    if (xwl_window->wl_output != wl_output)
+    if (xwl_window->wl_output != wl_output) {
         xwl_window->wl_output = wl_output;
+
+        if (xwl_screen->fullscreen)
+            xwl_window_set_fullscreen(xwl_window);
+    }
 }
 
 static void
@@ -533,7 +613,7 @@ ensure_surface_for_window(WindowPtr window)
     /* When a new window-manager window is realized, then the randr emulation
      * props may have not been set on the managed client window yet.
      */
-    if (window_is_wm_window(window)) {
+    if (!xwl_screen->fullscreen && window_is_wm_window(window)) {
         toplevel = window_get_client_toplevel(window);
         if (toplevel)
             xwl_output_set_window_randr_emu_props(xwl_screen, toplevel);
diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h
index 1975b749c0f6c41d652d2ae1178e623a75983164..24147e3fc70ad3be9db852d7ab33f7aa7b9cf669 100644
--- a/hw/xwayland/xwayland-window.h
+++ b/hw/xwayland/xwayland-window.h
@@ -53,6 +53,7 @@ struct xwl_window {
     struct xorg_list window_buffers_unavailable;
     OsTimerPtr window_buffers_timer;
     struct wl_output *wl_output;
+    struct wl_output *wl_output_fullscreen;
 #ifdef GLAMOR_HAS_GBM
     struct xorg_list frame_callback_list;
     Bool present_flipped;
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index d28d6f8e71e750d4ce49e492a2cfd699e297cc73..8fb929eeb6870d60092f8de8b7a4550b032131c5 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -91,6 +91,7 @@ void
 ddxUseMsg(void)
 {
     ErrorF("-rootless              run rootless, requires wm support\n");
+    ErrorF("-fullscreen            run fullscreen when rootful\n");
     ErrorF("-geometry WxH          set Xwayland window size when rootful\n");
     ErrorF("-wm fd                 create X client for wm on given fd\n");
     ErrorF("-initfd fd             add given fd as a listen socket for initialization clients\n");
@@ -229,6 +230,9 @@ ddxProcessArgument(int argc, char *argv[], int i)
         CHECK_FOR_REQUIRED_ARGUMENTS(1);
         return 2;
     }
+    else if (strcmp(argv[i], "-fullscreen") == 0) {
+        return 1;
+    }
 
     return 0;
 }
diff --git a/hw/xwayland/xwayland.pc.in b/hw/xwayland/xwayland.pc.in
index 0b21e7acc18f507a9e9fe0df3c33a343833f01fa..5976bd6b143b8e0a76538b75c903096ed3d481d9 100644
--- a/hw/xwayland/xwayland.pc.in
+++ b/hw/xwayland/xwayland.pc.in
@@ -14,3 +14,4 @@ have_terminate_delay=true
 have_no_touch_pointer_emulation=true
 have_force_xrandr_emulation=true
 have_geometry=true
+have_fullscreen=true