diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h
index 6945055..533d33d 100644
--- a/gdk/gdkevents.h
+++ b/gdk/gdkevents.h
@@ -460,6 +460,8 @@ typedef enum
  * @GDK_WINDOW_STATE_ABOVE: the window is kept above other windows.
  * @GDK_WINDOW_STATE_BELOW: the window is kept below other windows.
  * @GDK_WINDOW_STATE_FOCUSED: the window is presented as focused (with active decorations).
+ * @GDK_WINDOW_TILED: the window is in a tiled state, see
+ *   gdk_window_get_tiled_edges() for more details. Since 3.10
  *
  * Specifies the state of a toplevel window.
  */
@@ -472,7 +474,8 @@ typedef enum
   GDK_WINDOW_STATE_FULLSCREEN = 1 << 4,
   GDK_WINDOW_STATE_ABOVE      = 1 << 5,
   GDK_WINDOW_STATE_BELOW      = 1 << 6,
-  GDK_WINDOW_STATE_FOCUSED    = 1 << 7
+  GDK_WINDOW_STATE_FOCUSED    = 1 << 7,
+  GDK_WINDOW_STATE_TILED      = 1 << 8
 } GdkWindowState;
 
 /**
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index 3f0a58f..dbab420 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -11712,3 +11712,26 @@ gdk_window_get_frame_clock (GdkWindow *window)
 
   return toplevel->frame_clock;
 }
+
+/**
+ * gdk_window_get_tiled_edges:
+ * @window: a #GdkWindow
+ *
+ * Returns information about window tiling.
+ *
+ * Depending on the platform, windows may be 'glued' or tiled
+ * together on one or more edges. This information can be useful
+ * when the drawing window decorations.
+ *
+ * Since: 3.10
+ */
+GdkWindowEdges
+gdk_window_get_tiled_edges (GdkWindow *window)
+{
+  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
+
+  if (GDK_WINDOW_IMPL_GET_CLASS (window->impl)->get_tiled_edges)
+    GDK_WINDOW_IMPL_GET_CLASS (window->impl)->get_tiled_edges (window);
+
+  return 0;
+}
diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h
index d2ee972..76d1f95 100644
--- a/gdk/gdkwindow.h
+++ b/gdk/gdkwindow.h
@@ -318,6 +318,26 @@ typedef enum
 } GdkWindowEdge;
 
 /**
+ * GdkWindowEdges:
+ * @GDK_EDGE_TOP: the top edge
+ * @GDK_EDGE_LEFT: the left edge
+ * @GDK_EDGE_RIGHT: the right edge
+ * @GDK_EDGE_BOTTOM: the bottom edge
+ *
+ * This enumeration is used in
+ * gdk_window_get_tiled_edges().
+ *
+ * Since: 3.10
+ */
+typedef enum
+{
+  GDK_EDGE_TOP    = 1 << 0,
+  GDK_EDGE_LEFT   = 1 << 1,
+  GDK_EDGE_RIGHT  = 1 << 2,
+  GDK_EDGE_BOTTOM = 1 << 3
+} GdkWindowEdges;
+
+/**
  * GdkFullscreenMode:
  * @GDK_FULLSCREEN_ON_CURRENT_MONITOR: Fullscreen on current monitor only.
  * @GDK_FULLSCREEN_ON_ALL_MONITORS: Span across all monitors when fullscreen.
@@ -908,6 +928,9 @@ gboolean   gdk_window_get_support_multidevice (GdkWindow *window);
 GDK_AVAILABLE_IN_3_8
 GdkFrameClock* gdk_window_get_frame_clock      (GdkWindow     *window);
 
+GDK_AVAILABLE_IN_3_10
+GdkWindowEdges gdk_window_get_tiled_edges      (GdkWindow     *window);
+
 G_END_DECLS
 
 #endif /* __GDK_WINDOW_H__ */
diff --git a/gdk/gdkwindowimpl.h b/gdk/gdkwindowimpl.h
index 65149e8..90aa9a9 100644
--- a/gdk/gdkwindowimpl.h
+++ b/gdk/gdkwindowimpl.h
@@ -292,6 +292,7 @@ struct _GdkWindowImplClass
                                            gint            n_elements);
   void         (*delete_property)         (GdkWindow      *window,
                                            GdkAtom         property);
+  GdkWindowEdges (*get_tiled_edges)       (GdkWindow      *window);
 };
 
 /* Interface Functions */
diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c
index 9463f34..af2c5bd 100644
--- a/gdk/x11/gdkdisplay-x11.c
+++ b/gdk/x11/gdkdisplay-x11.c
@@ -239,6 +249,34 @@ do_net_wm_state_changes (GdkWindow *window)
                                      GDK_WINDOW_STATE_MAXIMIZED);
     }
 
+  /* FIXME: we rely on implementation details of mutter here:
+   * mutter only tiles horizontally, and sets maxvert when it does
+   * and if it tiles, it always affects all edges
+   */
+  if (old_state & GDK_WINDOW_STATE_TILED)
+    {
+      if (!toplevel->have_maxvert)
+        {
+          gdk_synthesize_window_state (window,
+                                       GDK_WINDOW_STATE_TILED,
+                                       0);
+          toplevel->tiled_edges = 0;
+        }
+    }
+  else
+    {
+      if (toplevel->have_maxvert)
+        {
+          gdk_synthesize_window_state (window,
+                                       0,
+                                       GDK_WINDOW_STATE_TILED);
+          toplevel->tiled_edges = GDK_EDGE_TOP |
+                                  GDK_EDGE_LEFT |
+                                  GDK_EDGE_RIGHT |
+                                  GDK_EDGE_BOTTOM;
+        }
+    }
+
   if (old_state & GDK_WINDOW_STATE_FOCUSED)
     {
       if (!toplevel->have_focused)
diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c
index 39298ad..182c40a 100644
--- a/gdk/x11/gdkwindow-x11.c
+++ b/gdk/x11/gdkwindow-x11.c
@@ -5305,6 +5305,17 @@ gdk_x11_window_get_xid (GdkWindow *window)
   return GDK_WINDOW_IMPL_X11 (window->impl)->xid;
 }
 
+static GdkWindowEdges
+gdk_x11_window_get_tiled_edges (GdkWindow *window)
+{
+  GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
+
+  if (toplevel)
+    return toplevel->tiled_edges;
+
+  return 0;
+}
+
 static void
 gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass)
 {
@@ -5393,4 +5404,5 @@ gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass)
   impl_class->get_property = _gdk_x11_window_get_property;
   impl_class->change_property = _gdk_x11_window_change_property;
   impl_class->delete_property = _gdk_x11_window_delete_property;
+  impl_class->get_tiled_edges = gdk_x11_window_get_tiled_edges;
 }
diff --git a/gdk/x11/gdkwindow-x11.h b/gdk/x11/gdkwindow-x11.h
index 5079b5d..b6d5234 100644
--- a/gdk/x11/gdkwindow-x11.h
+++ b/gdk/x11/gdkwindow-x11.h
@@ -165,6 +165,8 @@ struct _GdkToplevelX11
    * frame after will be presented */
   gint64 throttled_presentation_time;
 #endif
+
+  GdkWindowEdges tiled_edges;
 };
 
 GType gdk_window_impl_x11_get_type (void);
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index e10d536..a887cc5 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -203,6 +203,7 @@ struct _GtkWindowPrivate
   guint    client_decorated          : 1; /* Decorations drawn client-side */
   guint    custom_title              : 1; /* app-provided titlebar */
   guint    fullscreen                : 1;
+  guint    tiled                     : 1;
 
 };
 
@@ -6105,7 +6106,7 @@ get_decoration_borders (GtkWidget *widget,
 
   if (window_border != NULL)
     {
-      if (maximized)
+      if (maximized || GTK_WINDOW (widget)->priv->tiled)
         {
           *window_border = empty;
         }
@@ -6120,7 +6121,7 @@ get_decoration_borders (GtkWidget *widget,
 
   if (window_border != NULL || outer_border != NULL)
     {
-      if (maximized)
+      if (maximized || GTK_WINDOW (widget)->priv->tiled)
         {
           outer = empty;
         }
@@ -6370,7 +6371,15 @@ gtk_window_state_event (GtkWidget           *widget,
         (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) ? 1 : 0;
     }
 
-  if (event->changed_mask & (GDK_WINDOW_STATE_FULLSCREEN | GDK_WINDOW_STATE_MAXIMIZED))
+  if (event->changed_mask & GDK_WINDOW_STATE_TILED)
+    {
+      priv->tiled =
+        (event->new_window_state & GDK_WINDOW_STATE_TILED) ? 1 : 0;
+      g_print ("tiled state changed, now: %d\n", priv->tiled);
+    }
+
+
+  if (event->changed_mask & (GDK_WINDOW_STATE_FULLSCREEN | GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_TILED))
     {
       update_window_buttons (window);
       gtk_widget_queue_draw (GTK_WIDGET (window));
@@ -9033,6 +9042,7 @@ gtk_window_draw (GtkWidget *widget,
       if (priv->client_decorated &&
           priv->decorated &&
           !priv->fullscreen &&
+          !priv->tiled &&
           !(gdk_window_get_state (gtk_widget_get_window (widget)) & GDK_WINDOW_STATE_MAXIMIZED))
         {
           gtk_style_context_add_class (context, "window-border");
