[gnome-builder/wip/chergert/326redesign: 16/21] import recent panel-gtk updates



commit f5f83458855dd2fcbe93e31c696335f6b30b46b1
Author: Christian Hergert <chergert redhat com>
Date:   Fri May 5 00:40:12 2017 -0700

    import recent panel-gtk updates

 contrib/pnl/Makefile.am                            |   38 +-
 contrib/pnl/pnl-bin.c                              |  190 ++++
 contrib/pnl/{pnl-dock-tab-strip.c => pnl-bin.h}    |   40 +-
 contrib/pnl/pnl-child-property-action.c            |  558 ++++++++++++
 ...ock-tab-strip.h => pnl-child-property-action.h} |   22 +-
 contrib/pnl/pnl-dock-bin-edge-private.h            |    8 +-
 contrib/pnl/pnl-dock-bin-edge.c                    |   34 +-
 contrib/pnl/pnl-dock-bin-edge.h                    |   10 +-
 contrib/pnl/pnl-dock-bin.c                         |  741 +++++++++++-----
 contrib/pnl/pnl-dock-bin.h                         |   24 +-
 contrib/pnl/pnl-dock-item.c                        |  231 +++++-
 contrib/pnl/pnl-dock-item.h                        |   85 ++-
 contrib/pnl/pnl-dock-manager.h                     |   16 +-
 contrib/pnl/pnl-dock-overlay-edge.c                |   25 +-
 contrib/pnl/pnl-dock-overlay-edge.h                |   10 +-
 contrib/pnl/pnl-dock-overlay.c                     |    2 +-
 contrib/pnl/pnl-dock-overlay.h                     |   16 +-
 contrib/pnl/pnl-dock-paned-private.h               |    4 +
 contrib/pnl/pnl-dock-paned.c                       |    2 +-
 contrib/pnl/pnl-dock-paned.h                       |   16 +-
 contrib/pnl/pnl-dock-revealer.c                    |  175 +++-
 contrib/pnl/pnl-dock-revealer.h                    |   25 +-
 contrib/pnl/pnl-dock-stack.c                       |  170 ++++-
 contrib/pnl/pnl-dock-stack.h                       |   19 +-
 contrib/pnl/pnl-dock-transient-grab.h              |    4 +
 contrib/pnl/pnl-dock-types.h                       |   63 +-
 contrib/pnl/pnl-dock-widget.c                      |  135 +++-
 contrib/pnl/pnl-dock-widget.h                      |   29 +-
 contrib/pnl/pnl-dock-window.c                      |    2 +-
 contrib/pnl/pnl-dock-window.h                      |    9 +
 contrib/pnl/pnl-multi-paned.c                      |  188 +++--
 contrib/pnl/pnl-multi-paned.h                      |   16 +-
 .../{pnl-dock-tab-strip.h => pnl-tab-private.h}    |   18 +-
 contrib/pnl/pnl-tab-strip.c                        |  188 ++++-
 contrib/pnl/pnl-tab-strip.h                        |   20 +-
 contrib/pnl/pnl-tab.c                              |  944 +++++++++++++++++++-
 contrib/pnl/pnl-tab.h                              |   36 +-
 contrib/pnl/pnl-util-private.h                     |   20 +-
 contrib/pnl/pnl-util.c                             |  281 +++++--
 contrib/pnl/pnl-version.h.in                       |    2 +-
 contrib/pnl/pnl.h                                  |   10 +-
 data/theme/Adwaita-panels.css                      |   90 ++-
 data/theme/Adwaita.css                             |   13 -
 43 files changed, 3826 insertions(+), 703 deletions(-)
---
diff --git a/contrib/pnl/Makefile.am b/contrib/pnl/Makefile.am
index a31bb5c..a82e056 100644
--- a/contrib/pnl/Makefile.am
+++ b/contrib/pnl/Makefile.am
@@ -8,7 +8,7 @@ pkglib_LTLIBRARIES = libpanel-gtk.la
 
 headersdir = $(includedir)/gnome-builder-@VERSION@/pnl
 headers_DATA =                      \
-       pnl-animation.h             \
+       pnl-bin.h                   \
        pnl-dock-bin.h              \
        pnl-dock-bin-edge.h         \
        pnl-dock-item.h             \
@@ -22,7 +22,6 @@ headers_DATA =                      \
        pnl-dock-widget.h           \
        pnl-dock-window.h           \
        pnl-dock.h                  \
-       pnl-frame-source.h          \
        pnl-multi-paned.h           \
        pnl-tab-strip.h             \
        pnl-tab.h                   \
@@ -30,31 +29,39 @@ headers_DATA =                      \
        pnl.h                       \
        $(NULL)
 
-libpanel_gtk_la_SOURCES =           \
-       $(headers_DATA)             \
-       pnl-animation.c             \
+public_sources =                    \
+       pnl-bin.c                   \
        pnl-dock-bin-edge.c         \
-       pnl-dock-bin-edge-private.h \
        pnl-dock-bin.c              \
        pnl-dock-item.c             \
        pnl-dock-manager.c          \
-       pnl-dock-overlay-edge.c     \
        pnl-dock-overlay.c          \
-       pnl-dock-paned-private.h    \
+       pnl-dock-overlay-edge.c     \
        pnl-dock-paned.c            \
        pnl-dock-revealer.c         \
        pnl-dock-stack.c            \
-       pnl-dock-tab-strip.c        \
-       pnl-dock-tab-strip.h        \
-       pnl-dock-transient-grab.c   \
-       pnl-dock-transient-grab.h   \
        pnl-dock-widget.c           \
        pnl-dock-window.c           \
        pnl-dock.c                  \
-       pnl-frame-source.c          \
        pnl-multi-paned.c           \
        pnl-tab-strip.c             \
        pnl-tab.c                   \
+       $(NULL)
+
+libpanel_gtk_la_SOURCES =           \
+       $(headers_DATA)             \
+       $(public_sources)           \
+       pnl-animation.c             \
+       pnl-animation.h             \
+       pnl-child-property-action.c \
+       pnl-child-property-action.h \
+       pnl-dock-bin-edge-private.h \
+       pnl-dock-paned-private.h    \
+       pnl-dock-transient-grab.c   \
+       pnl-dock-transient-grab.h   \
+       pnl-frame-source.c          \
+       pnl-frame-source.h          \
+       pnl-tab-private.h           \
        pnl-util-private.h          \
        pnl-util.c                  \
        $(NULL)
@@ -93,7 +100,10 @@ Pnl-1.0.gir: libpanel-gtk.la
 Pnl_1_0_gir_INCLUDES = Gio-2.0 Gdk-3.0 Gtk-3.0
 Pnl_1_0_gir_CFLAGS = $(libpanel_gtk_la_CFLAGS) -DPNL_COMPILATION
 Pnl_1_0_gir_LIBS = libpanel-gtk.la
-Pnl_1_0_gir_FILES = $(libpanel_gtk_la_SOURCES)
+Pnl_1_0_gir_FILES =                 \
+       $(public_sources)           \
+       $(headers_DATA)             \
+       $(NULL)
 Pnl_1_0_gir_SCANNERFLAGS =          \
        --c-include="pnl.h"         \
        -n Pnl                      \
diff --git a/contrib/pnl/pnl-bin.c b/contrib/pnl/pnl-bin.c
new file mode 100644
index 0000000..82421d4
--- /dev/null
+++ b/contrib/pnl/pnl-bin.c
@@ -0,0 +1,190 @@
+/* pnl-bin.c
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program 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 Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/>.
+ */
+
+#define G_LOG_DOMAIN "pnl-bin"
+
+/**
+ * SECTION:pnl-bin
+ * @title: PnlBin
+ *
+ * This is just a #GtkBin class that also allows for various styling with
+ * CSS over what can be done in GtkBin directly.
+ */
+
+#include <string.h>
+
+#include "pnl-bin.h"
+#include "pnl-util-private.h"
+
+G_DEFINE_TYPE (PnlBin, pnl_bin, GTK_TYPE_BIN)
+
+static gboolean
+pnl_bin_draw (GtkWidget *widget,
+              cairo_t   *cr)
+{
+  GtkStyleContext *style_context;
+  GtkWidget *child;
+  GtkAllocation alloc;
+  GtkStateFlags state;
+  GtkBorder margin;
+
+  g_assert (PNL_IS_BIN (widget));
+
+  gtk_widget_get_allocation (widget, &alloc);
+  alloc.x = 0;
+  alloc.y = 0;
+
+  style_context = gtk_widget_get_style_context (widget);
+  state = gtk_widget_get_state_flags (widget);
+
+  gtk_style_context_get_margin (style_context, state, &margin);
+  pnl_gtk_allocation_subtract_border (&alloc, &margin);
+
+  gtk_render_background (style_context, cr, alloc.x, alloc.y, alloc.width, alloc.height);
+
+  child = gtk_bin_get_child (GTK_BIN (widget));
+  if (child != NULL)
+    gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
+
+  gtk_render_frame (style_context, cr, alloc.x, alloc.y, alloc.width, alloc.height);
+
+  return FALSE;
+}
+
+static inline void
+add_border (GtkBorder       *lsv,
+            const GtkBorder *rsv)
+{
+  lsv->left += rsv->left;
+  lsv->right += rsv->right;
+  lsv->top += rsv->top;
+  lsv->bottom += rsv->bottom;
+}
+
+static void
+pnl_bin_size_allocate (GtkWidget     *widget,
+                       GtkAllocation *alloc)
+{
+  PnlBin *self = (PnlBin *)widget;
+  GtkAllocation child_alloc = { 0 };
+  GtkWidget *child;
+
+  g_assert (PNL_IS_BIN (self));
+  g_assert (alloc != NULL);
+
+  child = gtk_bin_get_child (GTK_BIN (self));
+
+  if (child != NULL)
+    {
+      GtkStyleContext *style_context;
+      GtkBorder borders;
+
+      style_context = gtk_widget_get_style_context (widget);
+      child_alloc = *alloc;
+
+      if (gtk_widget_get_has_window (widget))
+        {
+          child_alloc.x = 0;
+          child_alloc.y = 0;
+        }
+
+      pnl_gtk_style_context_get_borders (style_context, &borders);
+      pnl_gtk_allocation_subtract_border (&child_alloc, &borders);
+    }
+
+  GTK_WIDGET_CLASS (pnl_bin_parent_class)->size_allocate (widget, alloc);
+
+  if (child != NULL)
+    gtk_widget_size_allocate (child, &child_alloc);
+}
+
+static void
+pnl_bin_get_preferred_width (GtkWidget *widget,
+                             gint      *min_width,
+                             gint      *nat_width)
+{
+  PnlBin *self = (PnlBin *)widget;
+  GtkStyleContext *style_context;
+  GtkWidget *child;
+  GtkBorder borders;
+
+  g_assert (PNL_IS_BIN (widget));
+
+  *min_width = 0;
+  *nat_width = 0;
+
+  child = gtk_bin_get_child (GTK_BIN (self));
+  if (child != NULL)
+    gtk_widget_get_preferred_width (child, min_width, nat_width);
+
+  style_context = gtk_widget_get_style_context (widget);
+  pnl_gtk_style_context_get_borders (style_context, &borders);
+
+  *min_width += (borders.left + borders.right);
+  *nat_width += (borders.left + borders.right);
+}
+
+static void
+pnl_bin_get_preferred_height (GtkWidget *widget,
+                              gint      *min_height,
+                              gint      *nat_height)
+{
+  PnlBin *self = (PnlBin *)widget;
+  GtkStyleContext *style_context;
+  GtkWidget *child;
+  GtkBorder borders;
+
+  g_assert (PNL_IS_BIN (widget));
+
+  *min_height = 0;
+  *nat_height = 0;
+
+  child = gtk_bin_get_child (GTK_BIN (self));
+  if (child != NULL)
+    gtk_widget_get_preferred_height (child, min_height, nat_height);
+
+  style_context = gtk_widget_get_style_context (widget);
+  pnl_gtk_style_context_get_borders (style_context, &borders);
+
+  *min_height += (borders.top + borders.bottom);
+  *nat_height += (borders.top + borders.bottom);
+}
+
+static void
+pnl_bin_class_init (PnlBinClass *klass)
+{
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  widget_class->draw = pnl_bin_draw;
+  widget_class->get_preferred_width = pnl_bin_get_preferred_width;
+  widget_class->get_preferred_height = pnl_bin_get_preferred_height;
+  widget_class->size_allocate = pnl_bin_size_allocate;
+
+  gtk_widget_class_set_css_name (widget_class, "pnlbin");
+}
+
+static void
+pnl_bin_init (PnlBin *self)
+{
+}
+
+GtkWidget *
+pnl_bin_new (void)
+{
+  return g_object_new (PNL_TYPE_BIN, NULL);
+}
diff --git a/contrib/pnl/pnl-dock-tab-strip.c b/contrib/pnl/pnl-bin.h
similarity index 58%
rename from contrib/pnl/pnl-dock-tab-strip.c
rename to contrib/pnl/pnl-bin.h
index 3f0b9a6..125ea09 100644
--- a/contrib/pnl/pnl-dock-tab-strip.c
+++ b/contrib/pnl/pnl-bin.h
@@ -1,6 +1,6 @@
-/* pnl-dock-tab-strip.c
+/* pnl-bin.h
  *
- * Copyright (C) 2016 Christian Hergert <christian hergert me>
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,26 +16,28 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "pnl-dock-tab-strip.h"
+#if !defined(PNL_INSIDE) && !defined(PNL_COMPILATION)
+# error "Only <pnl.h> can be included directly."
+#endif
 
-struct _PnlDockTabStrip
-{
-  PnlTabStrip parent;
-};
+#ifndef PNL_BIN_H
+#define PNL_BIN_H
 
-enum {
-  PROP_0,
-  N_PROPS
-};
+#include <gtk/gtk.h>
 
-G_DEFINE_TYPE (PnlDockTabStrip, pnl_dock_tab_strip, PNL_TYPE_TAB_STRIP)
+G_BEGIN_DECLS
 
-static void
-pnl_dock_tab_strip_class_init (PnlDockTabStripClass *klass)
-{
-}
+#define PNL_TYPE_BIN (pnl_bin_get_type())
+
+G_DECLARE_DERIVABLE_TYPE (PnlBin, pnl_bin, PNL, BIN, GtkBin)
 
-static void
-pnl_dock_tab_strip_init (PnlDockTabStrip *strip)
+struct _PnlBinClass
 {
-}
+  GtkBinClass parent_class;
+};
+
+GtkWidget *pnl_bin_new (void);
+
+G_END_DECLS
+
+#endif /* PNL_BIN_H */
diff --git a/contrib/pnl/pnl-child-property-action.c b/contrib/pnl/pnl-child-property-action.c
new file mode 100644
index 0000000..e276099
--- /dev/null
+++ b/contrib/pnl/pnl-child-property-action.c
@@ -0,0 +1,558 @@
+/* pnl-child-property-action.c
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program 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 Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/>.
+ */
+
+#define G_LOG_DOMAIN "pnl-child-property-action"
+
+#include "pnl-child-property-action.h"
+#include "pnl-util-private.h"
+
+struct _PnlChildPropertyAction
+{
+  GObject       parent_instance;
+
+  GtkContainer *container;
+  GtkWidget    *child;
+
+  const gchar  *child_property_name;
+  const gchar  *name;
+
+  guint         enabled : 1;
+};
+
+enum {
+  PROP_0,
+  PROP_CHILD,
+  PROP_CHILD_PROPERTY_NAME,
+  PROP_CONTAINER,
+  PROP_ENABLED,
+  PROP_NAME,
+  PROP_PARAMETER_TYPE,
+  PROP_STATE,
+  PROP_STATE_TYPE,
+  N_PROPS
+};
+
+static void action_iface_init (GActionInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (PnlChildPropertyAction, pnl_child_property_action, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_ACTION, action_iface_init))
+
+static GParamSpec *properties [N_PROPS];
+
+static const gchar *
+pnl_child_property_action_get_name (GAction *action)
+{
+  return PNL_CHILD_PROPERTY_ACTION (action)->name;
+}
+
+static const GVariantType *
+pnl_child_property_action_get_state_type (GAction *action)
+{
+  PnlChildPropertyAction *self = PNL_CHILD_PROPERTY_ACTION (action);
+
+  if (self->container != NULL &&
+      self->child != NULL &&
+      self->child_property_name != NULL)
+    {
+      GParamSpec *pspec;
+
+      pspec = gtk_container_class_find_child_property (G_OBJECT_GET_CLASS (self->container),
+                                                       self->child_property_name);
+
+      if (pspec != NULL)
+        {
+          if (G_IS_PARAM_SPEC_BOOLEAN (pspec))
+            return G_VARIANT_TYPE ("b");
+          else if (G_IS_PARAM_SPEC_INT (pspec))
+            return G_VARIANT_TYPE ("i");
+          else if (G_IS_PARAM_SPEC_UINT (pspec))
+            return G_VARIANT_TYPE ("u");
+          else if (G_IS_PARAM_SPEC_STRING (pspec))
+            return G_VARIANT_TYPE ("s");
+          else if (G_IS_PARAM_SPEC_DOUBLE (pspec))
+            return G_VARIANT_TYPE ("d");
+          else if (G_IS_PARAM_SPEC_FLOAT (pspec))
+            return G_VARIANT_TYPE ("d");
+        }
+    }
+
+  g_warning ("Failed to discover state type for child property %s",
+             self->child_property_name);
+
+  return NULL;
+}
+
+static const GVariantType *
+pnl_child_property_action_get_parameter_type (GAction *action)
+{
+  const GVariantType *state_type = g_action_get_state_type (action);
+
+  if (g_variant_type_equal (state_type, G_VARIANT_TYPE ("b")))
+    return NULL;
+
+  return state_type;
+}
+
+
+static GVariant *
+pnl_child_property_action_get_state_hint (GAction *action)
+{
+  return NULL;
+}
+
+static gboolean
+pnl_child_property_action_get_enabled (GAction *action)
+{
+  return PNL_CHILD_PROPERTY_ACTION (action)->enabled;
+}
+
+static GVariant *
+pnl_child_property_action_get_state (GAction *action)
+{
+  PnlChildPropertyAction *self = PNL_CHILD_PROPERTY_ACTION (action);
+
+  g_assert (PNL_IS_CHILD_PROPERTY_ACTION (self));
+
+  if (self->container != NULL &&
+      self->child != NULL &&
+      self->child_property_name != NULL)
+    {
+      GParamSpec *pspec;
+
+      pspec = gtk_container_class_find_child_property (G_OBJECT_GET_CLASS (self->container),
+                                                       self->child_property_name);
+
+      if (pspec != NULL)
+        {
+          g_auto(GValue) value = G_VALUE_INIT;
+          GVariant *ret = NULL;
+
+          g_value_init (&value, pspec->value_type);
+          gtk_container_child_get_property (self->container,
+                                            self->child,
+                                            self->child_property_name,
+                                            &value);
+
+          if (G_IS_PARAM_SPEC_BOOLEAN (pspec))
+            ret = g_variant_new_boolean (g_value_get_boolean (&value));
+          else if (G_IS_PARAM_SPEC_INT (pspec))
+            ret = g_variant_new_int32 (g_value_get_int (&value));
+          else if (G_IS_PARAM_SPEC_UINT (pspec))
+            ret = g_variant_new_uint32 (g_value_get_uint (&value));
+          else if (G_IS_PARAM_SPEC_STRING (pspec))
+            ret = g_variant_new_string (g_value_get_string (&value));
+          else if (G_IS_PARAM_SPEC_DOUBLE (pspec))
+            ret = g_variant_new_double (g_value_get_double (&value));
+          else if (G_IS_PARAM_SPEC_FLOAT (pspec))
+            ret = g_variant_new_double (g_value_get_double (&value));
+
+          if (ret)
+            return g_variant_ref_sink (ret);
+        }
+    }
+
+  g_warning ("Failed to determine default state");
+
+  return NULL;
+}
+
+static void
+pnl_child_property_action_change_state (GAction  *action,
+                                        GVariant *state)
+{
+  PnlChildPropertyAction *self = PNL_CHILD_PROPERTY_ACTION (action);
+
+  if (self->container != NULL &&
+      self->child != NULL &&
+      self->child_property_name != NULL)
+    {
+      GParamSpec *pspec;
+
+      pspec = gtk_container_class_find_child_property (G_OBJECT_GET_CLASS (self->container),
+                                                       self->child_property_name);
+
+      if (pspec != NULL)
+        {
+          g_auto(GValue) value = G_VALUE_INIT;
+
+          g_value_init (&value, pspec->value_type);
+
+          if (G_IS_PARAM_SPEC_BOOLEAN (pspec))
+            {
+              if (!g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN))
+                {
+                  g_warning ("Expected 'b', got %s", g_variant_get_type_string (state));
+                  return;
+                }
+
+              g_value_set_boolean (&value, g_variant_get_boolean (state));
+            }
+          else if (G_IS_PARAM_SPEC_INT (pspec))
+            {
+              if (!g_variant_is_of_type (state, G_VARIANT_TYPE_INT32))
+                {
+                  g_warning ("Expected 'i', got %s", g_variant_get_type_string (state));
+                  return;
+                }
+
+              g_value_set_int (&value, g_variant_get_int32 (state));
+            }
+          else if (G_IS_PARAM_SPEC_UINT (pspec))
+            {
+              if (!g_variant_is_of_type (state, G_VARIANT_TYPE_UINT32))
+                {
+                  g_warning ("Expected 'u', got %s", g_variant_get_type_string (state));
+                  return;
+                }
+
+              g_value_set_uint (&value, g_variant_get_uint32 (state));
+            }
+          else if (G_IS_PARAM_SPEC_STRING (pspec))
+            {
+              if (!g_variant_is_of_type (state, G_VARIANT_TYPE_STRING))
+                {
+                  g_warning ("Expected 's', got %s", g_variant_get_type_string (state));
+                  return;
+                }
+
+              g_value_set_string (&value, g_variant_get_string (state, NULL));
+            }
+          else if (G_IS_PARAM_SPEC_DOUBLE (pspec) || G_IS_PARAM_SPEC_FLOAT (pspec))
+            {
+              if (!g_variant_is_of_type (state, G_VARIANT_TYPE_STRING))
+                {
+                  g_warning ("Expected 'd', got %s", g_variant_get_type_string (state));
+                  return;
+                }
+
+              if (G_IS_PARAM_SPEC_DOUBLE (pspec))
+                g_value_set_double (&value, g_variant_get_double (state));
+              else
+                g_value_set_float (&value, g_variant_get_double (state));
+            }
+          else
+            {
+              g_warning ("I don't know how to handle %s property types.",
+                         g_type_name (pspec->value_type));
+              return;
+            }
+
+          gtk_container_child_set_property (self->container,
+                                            self->child,
+                                            self->child_property_name,
+                                            &value);
+          g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_STATE]);
+
+          return;
+        }
+    }
+
+  g_warning ("Attempt to change state on incapable child property action");
+}
+
+static void
+pnl_child_property_action_activate (GAction  *action,
+                                    GVariant *parameter)
+{
+  PnlChildPropertyAction *self = (PnlChildPropertyAction *)action;
+
+  g_assert (PNL_IS_CHILD_PROPERTY_ACTION (self));
+
+  if (parameter == NULL &&
+      self->container != NULL &&
+      self->child != NULL &&
+      self->child_property_name != NULL)
+    {
+      GParamSpec *pspec;
+
+      pspec = gtk_container_class_find_child_property (G_OBJECT_GET_CLASS (self->container),
+                                                       self->child_property_name);
+
+      if (pspec != NULL)
+        {
+          g_auto(GValue) value = G_VALUE_INIT;
+
+          if (G_IS_PARAM_SPEC_BOOLEAN (pspec))
+            {
+              g_value_init (&value, G_TYPE_BOOLEAN);
+
+              if (parameter != NULL)
+                g_value_set_boolean (&value, g_variant_get_boolean (parameter));
+              else
+                {
+                  g_auto(GValue) previous = G_VALUE_INIT;
+
+                  g_value_init (&previous, G_TYPE_BOOLEAN);
+                  gtk_container_child_get_property (self->container,
+                                                    self->child,
+                                                    self->child_property_name,
+                                                    &previous);
+                  g_value_set_boolean (&value, !g_value_get_boolean (&previous));
+                }
+            }
+          else if (G_IS_PARAM_SPEC_INT (pspec))
+            {
+              g_value_init (&value, G_TYPE_INT);
+              g_value_set_int (&value, g_variant_get_int32 (parameter));
+            }
+          else if (G_IS_PARAM_SPEC_UINT (pspec))
+            {
+              g_value_init (&value, G_TYPE_UINT);
+              g_value_set_uint (&value, g_variant_get_uint32 (parameter));
+            }
+          else if (G_IS_PARAM_SPEC_STRING (pspec))
+            {
+              g_value_init (&value, G_TYPE_STRING);
+              g_value_set_string (&value, g_variant_get_string (parameter, NULL));
+            }
+          else if (G_IS_PARAM_SPEC_DOUBLE (pspec) || G_IS_PARAM_SPEC_FLOAT (pspec))
+            {
+              g_value_init (&value, G_TYPE_DOUBLE);
+              g_value_set_double (&value, g_variant_get_double (parameter));
+            }
+          else
+            {
+              g_warning ("Failed to transform state type");
+              return;
+            }
+
+          gtk_container_child_set_property (self->container, self->child, pspec->name, &value);
+
+          return;
+        }
+    }
+
+  g_warning ("I don't know how to activate %s", self->name);
+}
+
+static void
+action_iface_init (GActionInterface *iface)
+{
+  iface->get_name = pnl_child_property_action_get_name;
+  iface->get_parameter_type = pnl_child_property_action_get_parameter_type;
+  iface->get_state_type = pnl_child_property_action_get_state_type;
+  iface->get_state_hint = pnl_child_property_action_get_state_hint;
+  iface->get_enabled = pnl_child_property_action_get_enabled;
+  iface->get_state = pnl_child_property_action_get_state;
+  iface->change_state = pnl_child_property_action_change_state;
+  iface->activate = pnl_child_property_action_activate;
+}
+
+static void
+child_notify_cb (PnlChildPropertyAction *self,
+                 GParamSpec             *pspec,
+                 GtkWidget              *child)
+{
+  g_assert (PNL_IS_CHILD_PROPERTY_ACTION (self));
+  g_assert (pspec != NULL);
+  g_assert (GTK_IS_WIDGET (child));
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_STATE]);
+}
+
+static void
+pnl_child_property_action_constructed (GObject *object)
+{
+  PnlChildPropertyAction *self = (PnlChildPropertyAction *)object;
+  g_autofree gchar *signal_detail = NULL;
+
+  G_OBJECT_CLASS (pnl_child_property_action_parent_class)->constructed (object);
+
+  if (!self->child || !self->container || !self->child_property_name)
+    {
+      g_warning ("Child property action not setup correctly.");
+      return;
+    }
+
+  signal_detail = g_strdup_printf ("child-notify::%s", self->child_property_name);
+
+  g_signal_connect_object (self->child,
+                           signal_detail,
+                           G_CALLBACK (child_notify_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+}
+
+static void
+pnl_child_property_action_dispose (GObject *object)
+{
+  PnlChildPropertyAction *self = (PnlChildPropertyAction *)object;
+
+  pnl_clear_weak_pointer (&self->container);
+  pnl_clear_weak_pointer (&self->child);
+
+  G_OBJECT_CLASS (pnl_child_property_action_parent_class)->dispose (object);
+}
+
+static void
+pnl_child_property_action_get_property (GObject    *object,
+                                        guint       prop_id,
+                                        GValue     *value,
+                                        GParamSpec *pspec)
+{
+  PnlChildPropertyAction *self = PNL_CHILD_PROPERTY_ACTION (object);
+
+  switch (prop_id)
+    {
+    case PROP_CONTAINER:
+      g_value_set_object (value, self->container);
+      break;
+
+    case PROP_CHILD:
+      g_value_set_object (value, self->child);
+      break;
+
+    case PROP_CHILD_PROPERTY_NAME:
+      g_value_set_static_string (value, self->child_property_name);
+      break;
+
+    case PROP_ENABLED:
+      g_value_set_boolean (value, self->enabled);
+      break;
+
+    case PROP_PARAMETER_TYPE:
+      g_value_set_boxed (value, pnl_child_property_action_get_parameter_type (G_ACTION (self)));
+      break;
+
+    case PROP_STATE:
+      g_value_take_variant (value, pnl_child_property_action_get_state (G_ACTION (self)));
+      break;
+
+    case PROP_STATE_TYPE:
+      g_value_set_boxed (value, pnl_child_property_action_get_state_type (G_ACTION (self)));
+      break;
+
+    case PROP_NAME:
+      g_value_set_static_string (value, self->name);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+pnl_child_property_action_set_property (GObject      *object,
+                                        guint         prop_id,
+                                        const GValue *value,
+                                        GParamSpec   *pspec)
+{
+  PnlChildPropertyAction *self = PNL_CHILD_PROPERTY_ACTION (object);
+
+  switch (prop_id)
+    {
+    case PROP_CONTAINER:
+      pnl_set_weak_pointer (&self->container, g_value_get_object (value));
+      break;
+
+    case PROP_CHILD:
+      pnl_set_weak_pointer (&self->child, g_value_get_object (value));
+      break;
+
+    case PROP_CHILD_PROPERTY_NAME:
+      self->child_property_name = g_intern_string (g_value_get_string (value));
+      break;
+
+    case PROP_ENABLED:
+      self->enabled = g_value_get_boolean (value);
+      break;
+
+    case PROP_NAME:
+      self->name = g_intern_string (g_value_get_string (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+pnl_child_property_action_class_init (PnlChildPropertyActionClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = pnl_child_property_action_dispose;
+  object_class->get_property = pnl_child_property_action_get_property;
+  object_class->set_property = pnl_child_property_action_set_property;
+  object_class->constructed = pnl_child_property_action_constructed;
+
+  properties [PROP_CHILD] =
+    g_param_spec_object ("child",
+                         "Child",
+                         "The child widget",
+                         GTK_TYPE_WIDGET,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_CHILD_PROPERTY_NAME] =
+    g_param_spec_string ("child-property-name",
+                         "Child Property Name",
+                         "The name of the child property",
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_CONTAINER] =
+    g_param_spec_object ("container",
+                         "Container",
+                         "The container widget",
+                         GTK_TYPE_CONTAINER,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_ENABLED] =
+    g_param_spec_boolean ("enabled",
+                          "Enabled",
+                          "Enabled",
+                          TRUE,
+                          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_PARAMETER_TYPE] =
+    g_param_spec_boxed ("parameter-type",
+                        "Parameter Type",
+                        "The parameter type",
+                        G_TYPE_VARIANT_TYPE,
+                        (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_STATE] =
+    g_param_spec_variant ("state",
+                          "State",
+                          "State for the action",
+                          G_VARIANT_TYPE_ANY,
+                          NULL,
+                          (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_STATE_TYPE] =
+    g_param_spec_boxed ("state-type",
+                        "State Type",
+                        "The state type",
+                        G_TYPE_VARIANT_TYPE,
+                        (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_NAME] =
+    g_param_spec_string ("name",
+                         "Action Name",
+                         "The name of the action",
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+pnl_child_property_action_init (PnlChildPropertyAction *self)
+{
+  self->enabled = TRUE;
+}
diff --git a/contrib/pnl/pnl-dock-tab-strip.h b/contrib/pnl/pnl-child-property-action.h
similarity index 56%
copy from contrib/pnl/pnl-dock-tab-strip.h
copy to contrib/pnl/pnl-child-property-action.h
index 6cf04d6..f8319de 100644
--- a/contrib/pnl/pnl-dock-tab-strip.h
+++ b/contrib/pnl/pnl-child-property-action.h
@@ -1,6 +1,6 @@
-/* pnl-dock-tab-strip.h
+/* pnl-child-property-action.h
  *
- * Copyright (C) 2016 Christian Hergert <christian hergert me>
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,19 +16,21 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef PNL_DOCK_TAB_STRIP_H
-#define PNL_DOCK_TAB_STRIP_H
+#if !defined(PNL_INSIDE) && !defined(PNL_COMPILATION)
+# error "Only <pnl.h> can be included directly."
+#endif
 
-#include "pnl-tab-strip.h"
+#ifndef PNL_CHILD_PROPERTY_ACTION_H
+#define PNL_CHILD_PROPERTY_ACTION_H
 
-G_BEGIN_DECLS
+#include "pnl-dock-types.h"
 
-#define PNL_TYPE_DOCK_TAB_STRIP (pnl_dock_tab_strip_get_type())
+G_BEGIN_DECLS
 
-G_DECLARE_FINAL_TYPE (PnlDockTabStrip, pnl_dock_tab_strip, PNL, DOCK_TAB_STRIP, PnlTabStrip)
+#define PNL_TYPE_CHILD_PROPERTY_ACTION  (pnl_child_property_action_get_type())
 
-GtkWidget *pnl_dock_tab_strip_new (void);
+G_DECLARE_FINAL_TYPE (PnlChildPropertyAction, pnl_child_property_action,  PNL, CHILD_PROPERTY_ACTION, 
GObject)
 
 G_END_DECLS
 
-#endif /* PNL_DOCK_TAB_STRIP_H */
+#endif /* PNL_CHILD_PROPERTY_ACTION_H */
diff --git a/contrib/pnl/pnl-dock-bin-edge-private.h b/contrib/pnl/pnl-dock-bin-edge-private.h
index e45e4e2..ea3956d 100644
--- a/contrib/pnl/pnl-dock-bin-edge-private.h
+++ b/contrib/pnl/pnl-dock-bin-edge-private.h
@@ -16,6 +16,10 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#if !defined(PNL_INSIDE) && !defined(PNL_COMPILATION)
+# error "Only <pnl.h> can be included directly."
+#endif
+
 #ifndef PNL_DOCK_BIN_EDGE_PRIVATE_H
 #define PNL_DOCK_BIN_EDGE_PRIVATE_H
 
@@ -23,8 +27,8 @@
 
 G_BEGIN_DECLS
 
-void            pnl_dock_bin_edge_set_edge (PnlDockBinEdge  *self,
-                                            GtkPositionType  bin_edge);
+void pnl_dock_bin_edge_set_edge (PnlDockBinEdge  *self,
+                                 GtkPositionType  bin_edge);
 
 G_END_DECLS
 
diff --git a/contrib/pnl/pnl-dock-bin-edge.c b/contrib/pnl/pnl-dock-bin-edge.c
index 408ceb2..d4f0b6e 100644
--- a/contrib/pnl/pnl-dock-bin-edge.c
+++ b/contrib/pnl/pnl-dock-bin-edge.c
@@ -19,6 +19,7 @@
 #include "pnl-dock-bin.h"
 #include "pnl-dock-bin-edge.h"
 #include "pnl-dock-bin-edge-private.h"
+#include "pnl-dock-item.h"
 #include "pnl-dock-revealer.h"
 
 typedef struct
@@ -26,9 +27,11 @@ typedef struct
   GtkPositionType edge : 3;
 } PnlDockBinEdgePrivate;
 
+static void dock_item_iface_init (PnlDockItemInterface *iface);
+
 G_DEFINE_TYPE_EXTENDED (PnlDockBinEdge, pnl_dock_bin_edge, PNL_TYPE_DOCK_REVEALER, 0,
                         G_ADD_PRIVATE (PnlDockBinEdge)
-                        G_IMPLEMENT_INTERFACE (PNL_TYPE_DOCK_ITEM, NULL))
+                        G_IMPLEMENT_INTERFACE (PNL_TYPE_DOCK_ITEM, dock_item_iface_init))
 
 enum {
   PROP_0,
@@ -139,6 +142,11 @@ pnl_dock_bin_edge_add (GtkContainer *container,
 
   child = gtk_bin_get_child (GTK_BIN (container));
   gtk_container_add (GTK_CONTAINER (child), widget);
+
+  if (PNL_IS_DOCK_ITEM (child))
+    pnl_dock_item_adopt (PNL_DOCK_ITEM (container), PNL_DOCK_ITEM (child));
+
+  gtk_widget_show (child);
 }
 
 static void
@@ -238,7 +246,7 @@ pnl_dock_bin_edge_class_init (PnlDockBinEdgeClass *klass)
   binding_set = gtk_binding_set_by_class (klass);
   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0, "move-to-bin-child", 0);
 
-  gtk_widget_class_set_css_name (widget_class, "dockbinedge");
+  gtk_widget_class_set_css_name (widget_class, "pnldockbinedge");
 }
 
 static void
@@ -250,6 +258,26 @@ pnl_dock_bin_edge_init (PnlDockBinEdge *self)
                         "visible", TRUE,
                         NULL);
   GTK_CONTAINER_CLASS (pnl_dock_bin_edge_parent_class)->add (GTK_CONTAINER (self), child);
+}
 
-  pnl_dock_bin_edge_update_edge (self);
+static void
+pnl_dock_bin_edge_update_visibility (PnlDockItem *item)
+{
+  PnlDockBinEdge *self = (PnlDockBinEdge *)item;
+  GtkWidget *child;
+  gboolean visible = FALSE;
+
+  g_assert (PNL_IS_DOCK_BIN_EDGE (self));
+
+  if (NULL != (child = gtk_bin_get_child (GTK_BIN (self))))
+    visible = pnl_dock_item_has_widgets (PNL_DOCK_ITEM (child));
+
+  if (visible != pnl_dock_revealer_get_reveal_child (PNL_DOCK_REVEALER (self)))
+    pnl_dock_revealer_set_reveal_child (PNL_DOCK_REVEALER (self), visible);
+}
+
+static void
+dock_item_iface_init (PnlDockItemInterface *iface)
+{
+  iface->update_visibility = pnl_dock_bin_edge_update_visibility;
 }
diff --git a/contrib/pnl/pnl-dock-bin-edge.h b/contrib/pnl/pnl-dock-bin-edge.h
index c5496fa..3c2421d 100644
--- a/contrib/pnl/pnl-dock-bin-edge.h
+++ b/contrib/pnl/pnl-dock-bin-edge.h
@@ -16,17 +16,17 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#if !defined(PNL_INSIDE) && !defined(PNL_COMPILATION)
+# error "Only <pnl.h> can be included directly."
+#endif
+
 #ifndef PNL_DOCK_BIN_EDGE_H
 #define PNL_DOCK_BIN_EDGE_H
 
-#include "pnl-dock-revealer.h"
+#include "pnl-dock-types.h"
 
 G_BEGIN_DECLS
 
-#define PNL_TYPE_DOCK_BIN_EDGE (pnl_dock_bin_edge_get_type())
-
-G_DECLARE_DERIVABLE_TYPE (PnlDockBinEdge, pnl_dock_bin_edge, PNL, DOCK_BIN_EDGE, PnlDockRevealer)
-
 struct _PnlDockBinEdgeClass
 {
   PnlDockRevealerClass parent;
diff --git a/contrib/pnl/pnl-dock-bin.c b/contrib/pnl/pnl-dock-bin.c
index c3fb51d..91e8945 100644
--- a/contrib/pnl/pnl-dock-bin.c
+++ b/contrib/pnl/pnl-dock-bin.c
@@ -18,12 +18,13 @@
 
 #include <stdlib.h>
 
+#include "pnl-child-property-action.h"
 #include "pnl-dock-bin.h"
 #include "pnl-dock-bin-edge-private.h"
 #include "pnl-dock-item.h"
 
-#define HANDLE_WIDTH  10
-#define HANDLE_HEIGHT 10
+#define HANDLE_WIDTH  3
+#define HANDLE_HEIGHT 3
 
 typedef enum
 {
@@ -83,6 +84,13 @@ typedef struct
    * the last child, and our sort function ensures that.
    */
   PnlDockBinChildType type : 3;
+
+  /*
+   * If the panel is pinned, this will be set to TRUE. A pinned panel
+   * means that it is displayed juxtapose the center child, where as
+   * an unpinned child is floating above teh center child.
+   */
+  guint pinned : 1;
 } PnlDockBinChild;
 
 typedef struct
@@ -122,34 +130,184 @@ static void pnl_dock_bin_init_dock_item_iface (PnlDockItemInterface *iface);
 
 G_DEFINE_TYPE_EXTENDED (PnlDockBin, pnl_dock_bin, GTK_TYPE_CONTAINER, 0,
                         G_ADD_PRIVATE (PnlDockBin)
-                        G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
-                                               pnl_dock_bin_init_buildable_iface)
-                        G_IMPLEMENT_INTERFACE (PNL_TYPE_DOCK_ITEM,
-                                               pnl_dock_bin_init_dock_item_iface)
-                        G_IMPLEMENT_INTERFACE (PNL_TYPE_DOCK,
-                                               pnl_dock_bin_init_dock_iface))
+                        G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, pnl_dock_bin_init_buildable_iface)
+                        G_IMPLEMENT_INTERFACE (PNL_TYPE_DOCK_ITEM, pnl_dock_bin_init_dock_item_iface)
+                        G_IMPLEMENT_INTERFACE (PNL_TYPE_DOCK, pnl_dock_bin_init_dock_iface))
 
 enum {
   PROP_0,
+  PROP_LEFT_VISIBLE,
+  PROP_RIGHT_VISIBLE,
+  PROP_TOP_VISIBLE,
+  PROP_BOTTOM_VISIBLE,
+  N_PROPS,
+
   PROP_MANAGER,
-  N_PROPS
 };
 
 enum {
   CHILD_PROP_0,
+  CHILD_PROP_PINNED,
   CHILD_PROP_POSITION,
   CHILD_PROP_PRIORITY,
   N_CHILD_PROPS
 };
 
-enum {
-  STYLE_PROP_0,
-  STYLE_PROP_HANDLE_SIZE,
-  N_STYLE_PROPS
-};
-
+static GParamSpec *properties [N_PROPS];
 static GParamSpec *child_properties [N_CHILD_PROPS];
-static GParamSpec *style_properties [N_STYLE_PROPS];
+
+static gint
+pnl_dock_bin_child_compare (gconstpointer a,
+                            gconstpointer b)
+{
+  const PnlDockBinChild *child_a = a;
+  const PnlDockBinChild *child_b = b;
+
+  if (child_a->type == PNL_DOCK_BIN_CHILD_CENTER)
+    return 1;
+  else if (child_b->type == PNL_DOCK_BIN_CHILD_CENTER)
+    return -1;
+
+  if ((child_a->pinned ^ child_b->pinned) != 0)
+    return child_a->pinned - child_b->pinned;
+
+  return child_a->priority - child_b->priority;
+}
+
+static void
+pnl_dock_bin_resort_children (PnlDockBin *self)
+{
+  PnlDockBinPrivate *priv = pnl_dock_bin_get_instance_private (self);
+
+  g_assert (PNL_IS_DOCK_BIN (self));
+
+  /*
+   * Sort the children by priority/pinned status, but do not change
+   * the position of the PNL_DOCK_BIN_CHILD_CENTER child. It should
+   * always be at the last position.
+   */
+
+  g_qsort_with_data (&priv->children[0],
+                     PNL_DOCK_BIN_CHILD_CENTER,
+                     sizeof (PnlDockBinChild),
+                     (GCompareDataFunc)pnl_dock_bin_child_compare,
+                     NULL);
+
+  gtk_widget_queue_allocate (GTK_WIDGET (self));
+}
+
+static GAction *
+pnl_dock_bin_get_visible_action_for_type (PnlDockBin          *self,
+                                          PnlDockBinChildType  type)
+{
+  PnlDockBinPrivate *priv = pnl_dock_bin_get_instance_private (self);
+  const gchar *name = NULL;
+
+  g_assert (PNL_IS_DOCK_BIN (self));
+
+  switch (type)
+    {
+    case PNL_DOCK_BIN_CHILD_LEFT:
+      name = "left-visible";
+      break;
+
+    case PNL_DOCK_BIN_CHILD_RIGHT:
+      name = "right-visible";
+      break;
+
+    case PNL_DOCK_BIN_CHILD_TOP:
+      name = "top-visible";
+      break;
+
+    case PNL_DOCK_BIN_CHILD_BOTTOM:
+      name = "bottom-visible";
+      break;
+
+    case PNL_DOCK_BIN_CHILD_CENTER:
+    case LAST_PNL_DOCK_BIN_CHILD:
+    default:
+      g_assert_not_reached ();
+    }
+
+  return g_action_map_lookup_action (G_ACTION_MAP (priv->actions), name);
+}
+
+static gboolean
+get_visible (PnlDockBin  *self,
+             const gchar *action_name)
+{
+  PnlDockBinPrivate *priv = pnl_dock_bin_get_instance_private (self);
+  GAction *action;
+
+  g_assert (PNL_IS_DOCK_BIN (self));
+  g_assert (action_name != NULL);
+
+  action = g_action_map_lookup_action (G_ACTION_MAP (priv->actions), action_name);
+
+  if (action != NULL)
+    {
+      GVariant *v = g_action_get_state (action);
+      gboolean ret = v ? g_variant_get_boolean (v) : FALSE;
+
+      g_clear_pointer (&v, g_variant_unref);
+
+      return ret;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+set_visible (PnlDockBin  *self,
+             const gchar *action_name,
+             gboolean     value)
+{
+  PnlDockBinPrivate *priv = pnl_dock_bin_get_instance_private (self);
+  GAction *action;
+
+  g_assert (PNL_IS_DOCK_BIN (self));
+  g_assert (action_name != NULL);
+
+  action = g_action_map_lookup_action (G_ACTION_MAP (priv->actions), action_name);
+
+  if (action != NULL)
+    g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (value));
+
+  return FALSE;
+}
+
+static void
+pnl_dock_bin_update_actions (PnlDockBin *self)
+{
+  PnlDockBinPrivate *priv = pnl_dock_bin_get_instance_private (self);
+  guint i;
+
+  g_assert (PNL_IS_DOCK_BIN (self));
+
+  /*
+   * We need to walk each of the children edges looking for widgets
+   * that are visible. If so, we need to keep the edge action enabled.
+   * Otherwise disable it, so any buttons representing the action get
+   * properly desensitized.
+   */
+
+  for (i = 0; i < G_N_ELEMENTS (priv->children); i++)
+    {
+      PnlDockBinChild *child = &priv->children [i];
+      GAction *action;
+      gboolean enabled = FALSE;
+
+      if (child->type == PNL_DOCK_BIN_CHILD_CENTER)
+        continue;
+
+      action = pnl_dock_bin_get_visible_action_for_type (self, child->type);
+
+      if (child->widget != NULL)
+        enabled = pnl_dock_item_has_widgets (PNL_DOCK_ITEM (child->widget));
+
+      g_simple_action_set_enabled (G_SIMPLE_ACTION (action), enabled);
+    }
+}
 
 static gboolean
 map_boolean_to_variant (GBinding     *binding,
@@ -245,29 +403,6 @@ pnl_dock_bin_update_focus_chain (PnlDockBin *self)
     }
 }
 
-static GAction *
-pnl_dock_bin_get_action_for_type (PnlDockBin          *self,
-                                  PnlDockBinChildType  type)
-{
-  PnlDockBinPrivate *priv = pnl_dock_bin_get_instance_private (self);
-  const gchar *name = NULL;
-
-  g_assert (PNL_IS_DOCK_BIN (self));
-
-  if (type == PNL_DOCK_BIN_CHILD_LEFT)
-    name = "left-visible";
-  else if (type == PNL_DOCK_BIN_CHILD_RIGHT)
-    name = "right-visible";
-  else if (type == PNL_DOCK_BIN_CHILD_TOP)
-    name = "top-visible";
-  else if (type == PNL_DOCK_BIN_CHILD_BOTTOM)
-    name = "bottom-visible";
-  else
-    g_assert_not_reached ();
-
-  return g_action_map_lookup_action (G_ACTION_MAP (priv->actions), name);
-}
-
 static void
 pnl_dock_bin_add (GtkContainer *container,
                   GtkWidget    *widget)
@@ -330,14 +465,33 @@ pnl_dock_bin_forall (GtkContainer *container,
 {
   PnlDockBin *self = (PnlDockBin *)container;
   PnlDockBinPrivate *priv = pnl_dock_bin_get_instance_private (self);
+  PnlDockBinChild *child;
   guint i;
 
   g_assert (PNL_IS_DOCK_BIN (self));
   g_assert (callback != NULL);
 
-  for (i = G_N_ELEMENTS (priv->children); i > 0; i--)
+  /*
+   * Always call the "center" child callback first. This helps ensure that
+   * it is the first child to be rendered. We need that to ensure that panels
+   * are drawn *above* the center, even when floating. Note that the center
+   * child is always the last child in the array.
+   */
+  child = &priv->children [G_N_ELEMENTS (priv->children) - 1];
+  if (child->widget != NULL)
+    callback (child->widget, user_data);
+
+  /*
+   * Normally, we would iterate the array backwards so that we can ensure that
+   * the list is safe against widget destruction. However, since we have a
+   * fixed size array, we can walk forwards safely.  This helps ensure we
+   * preserve draw ordering for the various panels when we chain up to the
+   * container draw vfunc.
+   */
+
+  for (i = 0; i < G_N_ELEMENTS (priv->children) - 1; i++)
     {
-      PnlDockBinChild *child = &priv->children [i - 1];
+      child = &priv->children[i];
 
       if (child->widget != NULL)
         callback (GTK_WIDGET (child->widget), user_data);
@@ -357,7 +511,6 @@ pnl_dock_bin_get_children_preferred_width (PnlDockBin      *self,
   gint child_nat_width = 0;
   gint neighbor_min_width = 0;
   gint neighbor_nat_width = 0;
-  gint handle_size = 0;
 
   g_assert (PNL_IS_DOCK_BIN (self));
   g_assert (children != NULL);
@@ -368,10 +521,6 @@ pnl_dock_bin_get_children_preferred_width (PnlDockBin      *self,
   *min_width = 0;
   *nat_width = 0;
 
-  gtk_widget_style_get (GTK_WIDGET (self),
-                        "handle-size", &handle_size,
-                        NULL);
-
   /*
    * We have a fairly simple rule for deducing the size request of
    * the children layout. Since children edges can have any priority,
@@ -432,14 +581,22 @@ pnl_dock_bin_get_children_preferred_width (PnlDockBin      *self,
     {
     case PNL_DOCK_BIN_CHILD_LEFT:
     case PNL_DOCK_BIN_CHILD_RIGHT:
-      *min_width = (child_min_width + neighbor_min_width + handle_size);
-      *nat_width = (child_nat_width + neighbor_nat_width + handle_size);
+      if (child->pinned)
+        {
+          *min_width = (child_min_width + neighbor_min_width);
+          *nat_width = (child_nat_width + neighbor_nat_width);
+        }
+      else
+        {
+          *min_width = MAX (child_min_width, neighbor_min_width);
+          *nat_width = MAX (child_nat_width, neighbor_nat_width);
+        }
       break;
 
     case PNL_DOCK_BIN_CHILD_TOP:
     case PNL_DOCK_BIN_CHILD_BOTTOM:
-      *min_width = MAX (child_min_width, neighbor_min_width + handle_size);
-      *nat_width = MAX (child_nat_width, neighbor_nat_width + handle_size);
+      *min_width = MAX (child_min_width, neighbor_min_width);
+      *nat_width = MAX (child_nat_width, neighbor_nat_width);
       break;
 
     case PNL_DOCK_BIN_CHILD_CENTER:
@@ -488,7 +645,6 @@ pnl_dock_bin_get_children_preferred_height (PnlDockBin      *self,
   gint child_nat_height = 0;
   gint neighbor_min_height = 0;
   gint neighbor_nat_height = 0;
-  gint handle_size = 0;
 
   g_assert (PNL_IS_DOCK_BIN (self));
   g_assert (children != NULL);
@@ -499,10 +655,6 @@ pnl_dock_bin_get_children_preferred_height (PnlDockBin      *self,
   *min_height = 0;
   *nat_height = 0;
 
-  gtk_widget_style_get (GTK_WIDGET (self),
-                        "handle-size", &handle_size,
-                        NULL);
-
   /*
    * See pnl_dock_bin_get_children_preferred_width() for more information on
    * how this works. This works just like that but the negotiated/additive
@@ -527,14 +679,22 @@ pnl_dock_bin_get_children_preferred_height (PnlDockBin      *self,
     {
     case PNL_DOCK_BIN_CHILD_LEFT:
     case PNL_DOCK_BIN_CHILD_RIGHT:
-      *min_height = MAX (child_min_height, neighbor_min_height + handle_size);
-      *nat_height = MAX (child_nat_height, neighbor_nat_height + handle_size);
+      *min_height = MAX (child_min_height, neighbor_min_height);
+      *nat_height = MAX (child_nat_height, neighbor_nat_height);
       break;
 
     case PNL_DOCK_BIN_CHILD_TOP:
     case PNL_DOCK_BIN_CHILD_BOTTOM:
-      *min_height = (child_min_height + neighbor_min_height + handle_size);
-      *nat_height = (child_nat_height + neighbor_nat_height + handle_size);
+      if (child->pinned)
+        {
+          *min_height = (child_min_height + neighbor_min_height);
+          *nat_height = (child_nat_height + neighbor_nat_height);
+        }
+      else
+        {
+          *min_height = MAX (child_min_height, neighbor_min_height);
+          *nat_height = MAX (child_nat_height, neighbor_nat_height);
+        }
       break;
 
     case PNL_DOCK_BIN_CHILD_CENTER:
@@ -605,7 +765,6 @@ pnl_dock_bin_child_size_allocate (PnlDockBin      *self,
                                   GtkAllocation   *allocation)
 {
   PnlDockBinChild *child = children;
-  gint handle_size = 0;
 
   g_assert (PNL_IS_DOCK_BIN (self));
   g_assert (children != NULL);
@@ -622,10 +781,6 @@ pnl_dock_bin_child_size_allocate (PnlDockBin      *self,
       return;
     }
 
-  gtk_widget_style_get (GTK_WIDGET (self),
-                        "handle-size", &handle_size,
-                        NULL);
-
   if (child->widget != NULL &&
       gtk_widget_get_visible (child->widget) &&
       gtk_widget_get_child_visible (child->widget))
@@ -634,6 +789,11 @@ pnl_dock_bin_child_size_allocate (PnlDockBin      *self,
       GtkAllocation handle_alloc = { 0 };
       GtkRequisition neighbor_min = { 0 };
       GtkRequisition neighbor_nat = { 0 };
+      GtkStyleContext *style_context = gtk_widget_get_style_context (child->widget);
+      GtkStateType state = gtk_style_context_get_state (style_context);
+      GtkBorder margin;
+
+      gtk_style_context_get_margin (style_context, state, &margin);
 
       pnl_dock_bin_get_children_preferred_height (self, child, 1,
                                                   &child->min_req.height,
@@ -643,17 +803,20 @@ pnl_dock_bin_child_size_allocate (PnlDockBin      *self,
                                                  &child->min_req.width,
                                                  &child->nat_req.width);
 
-      pnl_dock_bin_get_children_preferred_height (self,
-                                                  &children [1],
-                                                  n_children - 1,
-                                                  &neighbor_min.height,
-                                                  &neighbor_nat.height);
-
-      pnl_dock_bin_get_children_preferred_width (self,
-                                                 &children [1],
-                                                 n_children - 1,
-                                                 &neighbor_min.width,
-                                                 &neighbor_nat.width);
+      if (child->pinned)
+        {
+          pnl_dock_bin_get_children_preferred_height (self,
+                                                      &children [1],
+                                                      n_children - 1,
+                                                      &neighbor_min.height,
+                                                      &neighbor_nat.height);
+
+          pnl_dock_bin_get_children_preferred_width (self,
+                                                     &children [1],
+                                                     n_children - 1,
+                                                     &neighbor_min.width,
+                                                     &neighbor_nat.width);
+        }
 
       pnl_dock_bin_negotiate_size (self,
                                    allocation,
@@ -669,36 +832,52 @@ pnl_dock_bin_child_size_allocate (PnlDockBin      *self,
           child_alloc.x = allocation->x;
           child_alloc.y = allocation->y;
           child_alloc.height = allocation->height;
-          child_alloc.width -= handle_size;
-          allocation->x += child_alloc.width + handle_size;
-          allocation->width -= child_alloc.width + handle_size;
+
+          if (child->pinned)
+            {
+              allocation->x += child_alloc.width;
+              allocation->width -= child_alloc.width;
+            }
+
           break;
 
+
         case PNL_DOCK_BIN_CHILD_RIGHT:
-          child_alloc.width -= handle_size;
           child_alloc.x = allocation->x + allocation->width - child_alloc.width;
           child_alloc.y = allocation->y;
           child_alloc.height = allocation->height;
-          allocation->width -= child_alloc.width + handle_size;
+
+          if (child->pinned)
+            allocation->width -= child_alloc.width;
+
           break;
 
+
         case PNL_DOCK_BIN_CHILD_TOP:
           child_alloc.x = allocation->x;
           child_alloc.y = allocation->y;
           child_alloc.width = allocation->width;
-          child_alloc.height -= handle_size;
-          allocation->y += child_alloc.height + handle_size;
-          allocation->height -= child_alloc.height + handle_size;
+
+          if (child->pinned)
+            {
+              allocation->y += child_alloc.height;
+              allocation->height -= child_alloc.height;
+            }
+
           break;
 
+
         case PNL_DOCK_BIN_CHILD_BOTTOM:
-          child_alloc.height -= handle_size;
           child_alloc.x = allocation->x;
           child_alloc.y = allocation->y + allocation->height - child_alloc.height;
           child_alloc.width = allocation->width;
-          allocation->height -= child_alloc.height + handle_size;
+
+          if (child->pinned)
+            allocation->height -= child_alloc.height;
+
           break;
 
+
         case PNL_DOCK_BIN_CHILD_CENTER:
         case LAST_PNL_DOCK_BIN_CHILD:
         default:
@@ -711,6 +890,7 @@ pnl_dock_bin_child_size_allocate (PnlDockBin      *self,
       switch (child->type)
         {
         case PNL_DOCK_BIN_CHILD_LEFT:
+
           /*
            * When left-to-right, we often have a scrollbar to deal
            * with right here. So fudge the allocation position a bit
@@ -727,20 +907,29 @@ pnl_dock_bin_child_size_allocate (PnlDockBin      *self,
               handle_alloc.x += handle_alloc.width - HANDLE_WIDTH;
               handle_alloc.width = HANDLE_WIDTH;
             }
+
+          handle_alloc.x -= margin.right;
+
           break;
 
         case PNL_DOCK_BIN_CHILD_RIGHT:
           handle_alloc.width = HANDLE_WIDTH;
+
           if (gtk_widget_get_direction (child->widget) == GTK_TEXT_DIR_RTL)
             handle_alloc.x -= (HANDLE_WIDTH / 2);
+
+          handle_alloc.x += margin.left;
+
           break;
 
         case PNL_DOCK_BIN_CHILD_BOTTOM:
           handle_alloc.height = HANDLE_HEIGHT;
+          handle_alloc.y += margin.top;
           break;
 
         case PNL_DOCK_BIN_CHILD_TOP:
           handle_alloc.y += handle_alloc.height - HANDLE_HEIGHT;
+          handle_alloc.y -= margin.bottom;
           handle_alloc.height = HANDLE_HEIGHT;
           break;
 
@@ -799,15 +988,20 @@ pnl_dock_bin_size_allocate (GtkWidget     *widget,
    * because the child has an empty allocation.
    */
 
-  for (i = 0; i < PNL_DOCK_BIN_CHILD_CENTER; i++)
+  for (i = PNL_DOCK_BIN_CHILD_CENTER; i > 0; i--)
     {
-      PnlDockBinChild *child = &priv->children [i];
+      PnlDockBinChild *child = &priv->children [i - 1];
 
       if (child->handle != NULL)
         {
-          if (PNL_IS_DOCK_BIN_EDGE (child->widget) &&
-              pnl_dock_revealer_get_reveal_child (PNL_DOCK_REVEALER (child->widget)))
-            gdk_window_show (child->handle);
+          if (PNL_IS_DOCK_BIN_EDGE (child->widget))
+            {
+              if (gtk_widget_get_realized (child->widget))
+                gdk_window_raise (gtk_widget_get_window (child->widget));
+
+              if (pnl_dock_revealer_get_reveal_child (PNL_DOCK_REVEALER (child->widget)))
+                gdk_window_show (child->handle);
+            }
           else
             gdk_window_hide (child->handle);
         }
@@ -815,9 +1009,9 @@ pnl_dock_bin_size_allocate (GtkWidget     *widget,
 }
 
 static void
-pnl_dock_bin_visible_action (GSimpleAction *action,
-                             GVariant      *state,
-                             gpointer       user_data)
+pnl_dock_bin_visible_change_state (GSimpleAction *action,
+                                   GVariant      *state,
+                                   gpointer       user_data)
 {
   PnlDockBin *self = user_data;
   PnlDockBinChild *child;
@@ -849,19 +1043,38 @@ pnl_dock_bin_visible_action (GSimpleAction *action,
   pnl_dock_revealer_set_reveal_child (PNL_DOCK_REVEALER (child->widget), reveal_child);
 }
 
-static gint
-pnl_dock_bin_child_compare (gconstpointer a,
-                            gconstpointer b)
+static void
+pnl_dock_bin_set_child_pinned (PnlDockBin *self,
+                               GtkWidget  *widget,
+                               gboolean    pinned)
 {
-  const PnlDockBinChild *child_a = a;
-  const PnlDockBinChild *child_b = b;
+  PnlDockBinChild *child;
+  GtkStyleContext *style_context;
 
-  if (child_a->type == PNL_DOCK_BIN_CHILD_CENTER)
-    return 1;
-  else if (child_b->type == PNL_DOCK_BIN_CHILD_CENTER)
-    return -1;
+  g_assert (PNL_IS_DOCK_BIN (self));
+  g_assert (GTK_IS_WIDGET (widget));
 
-  return child_a->priority - child_b->priority;
+  child = pnl_dock_bin_get_child (self, widget);
+
+  if (child->type == PNL_DOCK_BIN_CHILD_CENTER)
+    return;
+
+  child->pinned = !!pinned;
+
+  style_context = gtk_widget_get_style_context (widget);
+
+  if (child->pinned)
+    gtk_style_context_add_class (style_context, PNL_DOCK_BIN_STYLE_CLASS_PINNED);
+  else
+    gtk_style_context_remove_class (style_context, PNL_DOCK_BIN_STYLE_CLASS_PINNED);
+
+  pnl_dock_bin_resort_children (self);
+
+  gtk_widget_queue_resize (GTK_WIDGET (self));
+
+  if (child->widget != NULL)
+    gtk_container_child_notify_by_pspec (GTK_CONTAINER (self), child->widget,
+                                         child_properties [CHILD_PROP_PINNED]);
 }
 
 static void
@@ -870,7 +1083,6 @@ pnl_dock_bin_set_child_priority (PnlDockBin *self,
                                  gint        priority)
 {
   PnlDockBinChild *child;
-  PnlDockBinPrivate *priv = pnl_dock_bin_get_instance_private (self);
 
   g_assert (PNL_IS_DOCK_BIN (self));
   g_assert (GTK_IS_WIDGET (widget));
@@ -878,13 +1090,13 @@ pnl_dock_bin_set_child_priority (PnlDockBin *self,
   child = pnl_dock_bin_get_child (self, widget);
   child->priority = priority;
 
-  g_qsort_with_data (&priv->children[0],
-                     PNL_DOCK_BIN_CHILD_CENTER,
-                     sizeof (PnlDockBinChild),
-                     (GCompareDataFunc)pnl_dock_bin_child_compare,
-                     NULL);
+  pnl_dock_bin_resort_children (self);
 
   gtk_widget_queue_resize (GTK_WIDGET (self));
+
+  if (child->widget != NULL)
+    gtk_container_child_notify_by_pspec (GTK_CONTAINER (self), child->widget,
+                                         child_properties [CHILD_PROP_PRIORITY]);
 }
 
 static void
@@ -1335,7 +1547,12 @@ pnl_dock_bin_create_edge (PnlDockBin          *self,
                           PnlDockBinChild     *child,
                           PnlDockBinChildType  type)
 {
+  PnlDockBinPrivate *priv = pnl_dock_bin_get_instance_private (self);
+  g_autoptr(GSimpleActionGroup) map = NULL;
+  g_autoptr(GAction) pinned = NULL;
+  const gchar *name = NULL;
   GAction *action;
+  gboolean reveal_child = FALSE;
 
   g_assert (PNL_IS_DOCK_BIN (self));
   g_assert (child != NULL);
@@ -1358,101 +1575,73 @@ pnl_dock_bin_create_edge (PnlDockBin          *self,
       return;
     }
 
-  g_object_set (child->widget, "edge", (GtkPositionType)type, NULL);
+  /*
+   * If the user set the initial state for the edge before we created the
+   * edge, the value for it will be the state to the action. We need to
+   * grab that and apply it for our initial state.
+   */
+  switch (type)
+    {
+    case PNL_DOCK_BIN_CHILD_LEFT:   reveal_child = get_visible (self, "left-visible");   break;
+    case PNL_DOCK_BIN_CHILD_RIGHT:  reveal_child = get_visible (self, "right-visible");  break;
+    case PNL_DOCK_BIN_CHILD_TOP:    reveal_child = get_visible (self, "top-visible");    break;
+    case PNL_DOCK_BIN_CHILD_BOTTOM: reveal_child = get_visible (self, "bottom-visible"); break;
+    case PNL_DOCK_BIN_CHILD_CENTER:
+    case LAST_PNL_DOCK_BIN_CHILD:
+    default:
+      break;
+    }
+
+  g_object_set (child->widget,
+                "edge", (GtkPositionType)type,
+                "reveal-child", reveal_child,
+                NULL);
+
   gtk_widget_set_parent (g_object_ref_sink (child->widget), GTK_WIDGET (self));
 
-  action = pnl_dock_bin_get_action_for_type (self, type);
+  action = pnl_dock_bin_get_visible_action_for_type (self, type);
   g_object_bind_property_full (child->widget, "reveal-child",
                                action, "state",
                                G_BINDING_SYNC_CREATE,
                                map_boolean_to_variant,
                                NULL, NULL, NULL);
-}
-
-static gboolean
-pnl_dock_bin_draw (GtkWidget *widget,
-                   cairo_t   *cr)
-{
-  PnlDockBin *self = (PnlDockBin *)widget;
-  PnlDockBinPrivate *priv = pnl_dock_bin_get_instance_private (self);
-  GtkStyleContext *style_context;
-  gboolean ret;
-  guint i;
-  gint handle_size = 0;
 
-  g_assert (PNL_IS_DOCK_BIN (self));
-  g_assert (cr != NULL);
-
-  ret = GTK_WIDGET_CLASS (pnl_dock_bin_parent_class)->draw (widget, cr);
-
-  if (ret == GDK_EVENT_STOP)
-    return ret;
-
-  gtk_widget_style_get (widget,
-                        "handle-size", &handle_size,
-                        NULL);
-
-  if (handle_size == 0)
-    return ret;
-
-  style_context = gtk_widget_get_style_context (widget);
-
-  for (i = 0; i < PNL_DOCK_BIN_CHILD_CENTER; i++)
-    {
-      PnlDockBinChild *child = &priv->children [i];
-
-      if ((child->widget != NULL) &&
-          gtk_widget_get_visible (child->widget) &&
-          gtk_widget_get_child_visible (child->widget))
-        {
-          GtkAllocation handle;
-
-          gtk_widget_get_allocation (child->widget, &handle);
-
-          if (((child->type == PNL_DOCK_BIN_CHILD_LEFT) ||
-               (child->type == PNL_DOCK_BIN_CHILD_RIGHT)) &&
-              (handle.width <= handle_size))
-            continue;
-
-          if (((child->type == PNL_DOCK_BIN_CHILD_TOP) ||
-               (child->type == PNL_DOCK_BIN_CHILD_BOTTOM)) &&
-              (handle.height <= handle_size))
-            continue;
-
-          switch (child->type)
-            {
-            case PNL_DOCK_BIN_CHILD_LEFT:
-              handle.x += handle.width;
-              handle.width = handle_size;
-              break;
-
-            case PNL_DOCK_BIN_CHILD_RIGHT:
-              handle.x -= handle_size;
-              handle.width = handle_size;
-              break;
-
-            case PNL_DOCK_BIN_CHILD_TOP:
-              handle.y += handle.height;
-              handle.height = handle_size;
-              break;
-
-            case PNL_DOCK_BIN_CHILD_BOTTOM:
-              handle.y -= handle_size;
-              handle.height = handle_size;
-              break;
-
-            case PNL_DOCK_BIN_CHILD_CENTER:
-            case LAST_PNL_DOCK_BIN_CHILD:
-            default:
-              g_assert_not_reached ();
-              break;
-            }
-
-          gtk_render_handle (style_context, cr, handle.x, handle.y, handle.width, handle.height);
-        }
-    }
-
-  return ret;
+  pnl_dock_item_adopt (PNL_DOCK_ITEM (self), PNL_DOCK_ITEM (child->widget));
+
+  /* Action for panel children to easily activate */
+  map = g_simple_action_group_new ();
+  pinned = g_object_new (PNL_TYPE_CHILD_PROPERTY_ACTION,
+                         "enabled", TRUE,
+                         "container", self,
+                         "child", child->widget,
+                         "child-property-name", "pinned",
+                         "name", "pinned",
+                         NULL);
+  g_action_map_add_action (G_ACTION_MAP (map), pinned);
+  gtk_widget_insert_action_group (child->widget, "panel", G_ACTION_GROUP (map));
+  g_clear_object (&pinned);
+
+  /* Action for global widgetry to activate */
+  if (child->type == PNL_DOCK_BIN_CHILD_LEFT)
+    name = "left-pinned";
+  else if (child->type == PNL_DOCK_BIN_CHILD_RIGHT)
+    name = "right-pinned";
+  else if (child->type == PNL_DOCK_BIN_CHILD_TOP)
+    name = "top-pinned";
+  else if (child->type == PNL_DOCK_BIN_CHILD_BOTTOM)
+    name = "bottom-pinned";
+  pinned = g_object_new (PNL_TYPE_CHILD_PROPERTY_ACTION,
+                         "enabled", TRUE,
+                         "container", self,
+                         "child", child->widget,
+                         "child-property-name", "pinned",
+                         "name", name,
+                         NULL);
+  g_action_map_add_action (G_ACTION_MAP (priv->actions), pinned);
+
+  if (child->pinned)
+    gtk_style_context_add_class (gtk_widget_get_style_context (child->widget),
+                                 PNL_DOCK_BIN_STYLE_CLASS_PINNED);
 }
 
 static void
@@ -1467,6 +1656,7 @@ pnl_dock_bin_init_child (PnlDockBin          *self,
 
   child->type = type;
   child->priority = (int)type * 100;
+  child->pinned = TRUE;
 }
 
 static void
@@ -1501,6 +1691,10 @@ pnl_dock_bin_get_child_property (GtkContainer *container,
       g_value_set_enum (value, (GtkPositionType)child->type);
       break;
 
+    case CHILD_PROP_PINNED:
+      g_value_set_boolean (value, child->pinned);
+      break;
+
     default:
       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, prop_id, pspec);
     }
@@ -1517,6 +1711,10 @@ pnl_dock_bin_set_child_property (GtkContainer *container,
 
   switch (prop_id)
     {
+    case CHILD_PROP_PINNED:
+      pnl_dock_bin_set_child_pinned (self, widget, g_value_get_boolean (value));
+      break;
+
     case CHILD_PROP_PRIORITY:
       pnl_dock_bin_set_child_priority (self, widget, g_value_get_int (value));
       break;
@@ -1536,6 +1734,22 @@ pnl_dock_bin_get_property (GObject    *object,
 
   switch (prop_id)
     {
+    case PROP_LEFT_VISIBLE:
+      g_value_set_boolean (value, get_visible (self, "left-visible"));
+      break;
+
+    case PROP_RIGHT_VISIBLE:
+      g_value_set_boolean (value, get_visible (self, "right-visible"));
+      break;
+
+    case PROP_TOP_VISIBLE:
+      g_value_set_boolean (value, get_visible (self, "top-visible"));
+      break;
+
+    case PROP_BOTTOM_VISIBLE:
+      g_value_set_boolean (value, get_visible (self, "bottom-visible"));
+      break;
+
     case PROP_MANAGER:
       g_value_set_object (value, pnl_dock_item_get_manager (PNL_DOCK_ITEM (self)));
       break;
@@ -1555,6 +1769,22 @@ pnl_dock_bin_set_property (GObject      *object,
 
   switch (prop_id)
     {
+    case PROP_LEFT_VISIBLE:
+      set_visible (self, "left-visible", g_value_get_boolean (value));
+      break;
+
+    case PROP_RIGHT_VISIBLE:
+      set_visible (self, "right-visible", g_value_get_boolean (value));
+      break;
+
+    case PROP_TOP_VISIBLE:
+      set_visible (self, "top-visible", g_value_get_boolean (value));
+      break;
+
+    case PROP_BOTTOM_VISIBLE:
+      set_visible (self, "bottom-visible", g_value_get_boolean (value));
+      break;
+
     case PROP_MANAGER:
       pnl_dock_item_set_manager (PNL_DOCK_ITEM (self), g_value_get_object (value));
       break;
@@ -1574,7 +1804,6 @@ pnl_dock_bin_class_init (PnlDockBinClass *klass)
   object_class->get_property = pnl_dock_bin_get_property;
   object_class->set_property = pnl_dock_bin_set_property;
 
-  widget_class->draw = pnl_dock_bin_draw;
   widget_class->destroy = pnl_dock_bin_destroy;
   widget_class->drag_leave = pnl_dock_bin_drag_leave;
   widget_class->drag_motion = pnl_dock_bin_drag_motion;
@@ -1597,6 +1826,43 @@ pnl_dock_bin_class_init (PnlDockBinClass *klass)
 
   g_object_class_override_property (object_class, PROP_MANAGER, "manager");
 
+  properties [PROP_LEFT_VISIBLE] =
+    g_param_spec_boolean ("left-visible",
+                          "Left Visible",
+                          "If the left panel is visible.",
+                          FALSE,
+                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_RIGHT_VISIBLE] =
+    g_param_spec_boolean ("right-visible",
+                          "Right Visible",
+                          "If the right panel is visible.",
+                          FALSE,
+                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_TOP_VISIBLE] =
+    g_param_spec_boolean ("top-visible",
+                          "Top Visible",
+                          "If the top panel is visible.",
+                          FALSE,
+                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_BOTTOM_VISIBLE] =
+    g_param_spec_boolean ("bottom-visible",
+                          "Bottom Visible",
+                          "If the bottom panel is visible.",
+                          FALSE,
+                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+
+  child_properties [CHILD_PROP_PINNED] =
+    g_param_spec_boolean ("pinned",
+                          "Pinned",
+                          "If the child panel is pinned",
+                          FALSE,
+                          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   child_properties [CHILD_PROP_POSITION] =
     g_param_spec_enum ("position",
                        "Position",
@@ -1616,17 +1882,7 @@ pnl_dock_bin_class_init (PnlDockBinClass *klass)
 
   gtk_container_class_install_child_properties (container_class, N_CHILD_PROPS, child_properties);
 
-  style_properties [STYLE_PROP_HANDLE_SIZE] =
-    g_param_spec_int ("handle-size",
-                      "Handle Size",
-                      "Width of the resize handle",
-                      0,
-                      G_MAXINT,
-                      1,
-                      (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-  gtk_widget_class_install_style_property (widget_class, style_properties [STYLE_PROP_HANDLE_SIZE]);
-
-  gtk_widget_class_set_css_name (widget_class, "dockbin");
+  gtk_widget_class_set_css_name (widget_class, "pnldockbin");
 }
 
 static void
@@ -1637,10 +1893,10 @@ pnl_dock_bin_init (PnlDockBin *self)
     { (gchar *)"PNL_DOCK_BIN_WIDGET", GTK_TARGET_SAME_APP, 0 },
   };
   static const GActionEntry entries[] = {
-    { "left-visible", NULL, NULL, "false", pnl_dock_bin_visible_action },
-    { "right-visible", NULL, NULL, "false", pnl_dock_bin_visible_action },
-    { "top-visible", NULL, NULL, "false", pnl_dock_bin_visible_action },
-    { "bottom-visible", NULL, NULL, "false", pnl_dock_bin_visible_action },
+    { "left-visible", NULL, NULL, "false", pnl_dock_bin_visible_change_state },
+    { "right-visible", NULL, NULL, "false", pnl_dock_bin_visible_change_state },
+    { "top-visible", NULL, NULL, "false", pnl_dock_bin_visible_change_state },
+    { "bottom-visible", NULL, NULL, "false", pnl_dock_bin_visible_change_state },
   };
 
   gtk_widget_set_has_window (GTK_WIDGET (self), TRUE);
@@ -1898,7 +2154,7 @@ pnl_dock_bin_get_child_visible (PnlDockItem *item,
       (ancestor == priv->children [1].widget) ||
       (ancestor == priv->children [2].widget) ||
       (ancestor == priv->children [3].widget))
-    return pnl_dock_revealer_get_reveal_child (PNL_DOCK_REVEALER (ancestor));
+    return pnl_dock_revealer_get_child_revealed (PNL_DOCK_REVEALER (ancestor));
 
   return FALSE;
 }
@@ -1920,10 +2176,69 @@ pnl_dock_bin_set_child_visible (PnlDockItem *item,
     pnl_dock_revealer_set_reveal_child (PNL_DOCK_REVEALER (ancestor), child_visible);
 }
 
+static gboolean
+pnl_dock_bin_minimize (PnlDockItem     *item,
+                       PnlDockItem     *child,
+                       GtkPositionType *position)
+{
+  PnlDockBin *self = (PnlDockBin *)item;
+  PnlDockBinPrivate *priv = pnl_dock_bin_get_instance_private (self);
+
+  g_assert (PNL_IS_DOCK_BIN (self));
+  g_assert (PNL_IS_DOCK_ITEM (child));
+  g_assert (position != NULL);
+
+  for (guint i = 0; i < LAST_PNL_DOCK_BIN_CHILD; i++)
+    {
+      const PnlDockBinChild *info = &priv->children [i];
+
+      if (info->widget != NULL && gtk_widget_is_ancestor (GTK_WIDGET (child), info->widget))
+        {
+          switch (info->type)
+            {
+            case PNL_DOCK_BIN_CHILD_LEFT:
+            case PNL_DOCK_BIN_CHILD_CENTER:
+            case LAST_PNL_DOCK_BIN_CHILD:
+            default:
+              *position = GTK_POS_LEFT;
+              break;
+
+            case PNL_DOCK_BIN_CHILD_RIGHT:
+              *position = GTK_POS_RIGHT;
+              break;
+
+            case PNL_DOCK_BIN_CHILD_TOP:
+              *position = GTK_POS_TOP;
+              break;
+
+            case PNL_DOCK_BIN_CHILD_BOTTOM:
+              *position = GTK_POS_BOTTOM;
+              break;
+            }
+
+          break;
+        }
+    }
+
+  return FALSE;
+}
+
+static void
+pnl_dock_bin_update_visibility (PnlDockItem *item)
+{
+  PnlDockBin *self = (PnlDockBin *)item;
+
+  g_assert (PNL_IS_DOCK_BIN (self));
+
+  pnl_dock_bin_update_actions (self);
+}
+
 static void
 pnl_dock_bin_init_dock_item_iface (PnlDockItemInterface *iface)
 {
   iface->present_child = pnl_dock_bin_present_child;
   iface->get_child_visible = pnl_dock_bin_get_child_visible;
   iface->set_child_visible = pnl_dock_bin_set_child_visible;
+  iface->minimize = pnl_dock_bin_minimize;
+  iface->update_visibility = pnl_dock_bin_update_visibility;
 }
diff --git a/contrib/pnl/pnl-dock-bin.h b/contrib/pnl/pnl-dock-bin.h
index 9ba8ec8..08d3d7f 100644
--- a/contrib/pnl/pnl-dock-bin.h
+++ b/contrib/pnl/pnl-dock-bin.h
@@ -20,27 +20,29 @@
 # error "Only <pnl.h> can be included directly."
 #endif
 
-#ifndef PNL_DOCK_BIN_BIN_H
-#define PNL_DOCK_BIN_BIN_H
+#ifndef PNL_DOCK_BIN_H
+#define PNL_DOCK_BIN_H
 
 #include "pnl-dock-types.h"
 
 G_BEGIN_DECLS
 
+#define PNL_DOCK_BIN_STYLE_CLASS_PINNED "pinned"
+
 struct _PnlDockBinClass
 {
   GtkContainerClass parent;
 
   GtkWidget *(*create_edge) (PnlDockBin *self);
 
-  void (*padding1) (void);
-  void (*padding2) (void);
-  void (*padding3) (void);
-  void (*padding4) (void);
-  void (*padding5) (void);
-  void (*padding6) (void);
-  void (*padding7) (void);
-  void (*padding8) (void);
+  gpointer _reserved1;
+  gpointer _reserved2;
+  gpointer _reserved3;
+  gpointer _reserved4;
+  gpointer _reserved5;
+  gpointer _reserved6;
+  gpointer _reserved7;
+  gpointer _reserved8;
 };
 
 GtkWidget *pnl_dock_bin_new               (void);
@@ -52,4 +54,4 @@ GtkWidget *pnl_dock_bin_get_right_edge    (PnlDockBin   *self);
 
 G_END_DECLS
 
-#endif /* PNL_DOCK_BIN_BIN_H */
+#endif /* PNL_DOCK_BIN_H */
diff --git a/contrib/pnl/pnl-dock-item.c b/contrib/pnl/pnl-dock-item.c
index 60e335e..cdca76b 100644
--- a/contrib/pnl/pnl-dock-item.c
+++ b/contrib/pnl/pnl-dock-item.c
@@ -76,20 +76,6 @@ pnl_dock_item_real_get_manager (PnlDockItem *self)
 static void
 pnl_dock_item_real_update_visibility (PnlDockItem *self)
 {
-  GtkWidget *parent;
-
-  g_assert (PNL_IS_DOCK_ITEM (self));
-
-  for (parent = gtk_widget_get_parent (GTK_WIDGET (self));
-       parent != NULL;
-       parent = gtk_widget_get_parent (parent))
-    {
-      if (PNL_IS_DOCK_ITEM (parent))
-        {
-          pnl_dock_item_update_visibility (PNL_DOCK_ITEM (parent));
-          break;
-        }
-    }
 }
 
 static void
@@ -129,12 +115,40 @@ pnl_dock_item_real_manager_set (PnlDockItem    *self,
 }
 
 static void
+pnl_dock_item_real_release (PnlDockItem *self,
+                            PnlDockItem *child)
+{
+  g_assert (PNL_IS_DOCK_ITEM (self));
+  g_assert (PNL_IS_DOCK_ITEM (child));
+
+  g_warning ("%s does not know how to release child %s",
+             G_OBJECT_TYPE_NAME (self),
+             G_OBJECT_TYPE_NAME (child));
+}
+
+static gboolean
+pnl_dock_item_real_can_minimize (PnlDockItem *self,
+                                 PnlDockItem *descendant)
+{
+  return FALSE;
+}
+
+static gboolean
+pnl_dock_item_real_get_can_close (PnlDockItem *self)
+{
+  return FALSE;
+}
+
+static void
 pnl_dock_item_default_init (PnlDockItemInterface *iface)
 {
   iface->get_manager = pnl_dock_item_real_get_manager;
   iface->set_manager = pnl_dock_item_real_set_manager;
   iface->manager_set = pnl_dock_item_real_manager_set;
   iface->update_visibility = pnl_dock_item_real_update_visibility;
+  iface->release = pnl_dock_item_real_release;
+  iface->get_can_close = pnl_dock_item_real_get_can_close;
+  iface->can_minimize = pnl_dock_item_real_can_minimize;
 
   signals [MANAGER_SET] =
     g_signal_new ("manager-set",
@@ -181,9 +195,19 @@ pnl_dock_item_set_manager (PnlDockItem    *self,
 void
 pnl_dock_item_update_visibility (PnlDockItem *self)
 {
+  GtkWidget *parent;
+
   g_return_if_fail (PNL_IS_DOCK_ITEM (self));
 
   PNL_DOCK_ITEM_GET_IFACE (self)->update_visibility (self);
+
+  for (parent = gtk_widget_get_parent (GTK_WIDGET (self));
+       parent != NULL;
+       parent = gtk_widget_get_parent (parent))
+    {
+      if (PNL_IS_DOCK_ITEM (parent))
+        PNL_DOCK_ITEM_GET_IFACE (parent)->update_visibility (PNL_DOCK_ITEM (parent));
+    }
 }
 
 static void
@@ -454,3 +478,182 @@ pnl_dock_item_set_child_visible (PnlDockItem *self,
   if (PNL_DOCK_ITEM_GET_IFACE (self)->set_child_visible)
     PNL_DOCK_ITEM_GET_IFACE (self)->set_child_visible (self, child, child_visible);
 }
+
+/**
+ * pnl_dock_item_get_can_close:
+ * @self: a #PnlDockItem
+ *
+ * If this dock item can be closed by the user, this virtual function should be
+ * implemented by the panel and return %TRUE.
+ *
+ * Returns: %TRUE if the dock item can be closed by the user, otherwise %FALSE.
+ */
+gboolean
+pnl_dock_item_get_can_close (PnlDockItem *self)
+{
+  g_return_val_if_fail (PNL_IS_DOCK_ITEM (self), FALSE);
+
+  if (PNL_DOCK_ITEM_GET_IFACE (self)->get_can_close)
+    return PNL_DOCK_ITEM_GET_IFACE (self)->get_can_close (self);
+
+  return FALSE;
+}
+
+/**
+ * pnl_dock_item_close:
+ * @self: a #PnlDockItem
+ *
+ * This function will request that the dock item close itself.
+ *
+ * Returns: %TRUE if the dock item was closed
+ */
+gboolean
+pnl_dock_item_close (PnlDockItem *self)
+{
+  g_return_val_if_fail (PNL_IS_DOCK_ITEM (self), FALSE);
+
+  if (pnl_dock_item_get_can_close (self))
+    {
+      if (PNL_DOCK_ITEM_GET_IFACE (self)->close)
+        return PNL_DOCK_ITEM_GET_IFACE (self)->close (self);
+
+      gtk_widget_destroy (GTK_WIDGET (self));
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/**
+ * pnl_dock_item_minimize:
+ * @self: a #PnlDockItem
+ * @child: A #PnlDockItem that is a child of @self
+ * @position: (inout): A location for a #GtkPositionType
+ *
+ * This requests that @self minimize @child if it knows how.
+ *
+ * If not, it should suggest the gravity for @child if it knows how to
+ * determine that. For example, a #PnlDockBin might know if the widget was part
+ * of the right panel and therefore may set @position to %GTK_POS_RIGHT.
+ *
+ * Returns: %TRUE if @child was minimized. Otherwise %FALSE and @position
+ *   may be updated to a suggested position.
+ */
+gboolean
+pnl_dock_item_minimize (PnlDockItem     *self,
+                        PnlDockItem     *child,
+                        GtkPositionType *position)
+{
+  GtkPositionType unused = GTK_POS_LEFT;
+
+  g_return_val_if_fail (PNL_IS_DOCK_ITEM (self), FALSE);
+  g_return_val_if_fail (PNL_IS_DOCK_ITEM (child), FALSE);
+  g_return_val_if_fail (self != child, FALSE);
+
+  if (position == NULL)
+    position = &unused;
+
+  if (PNL_DOCK_ITEM_GET_IFACE (self)->minimize)
+    return PNL_DOCK_ITEM_GET_IFACE (self)->minimize (self, child, position);
+
+  return FALSE;
+}
+
+/**
+ * pnl_dock_item_get_title:
+ * @self: A #PnlDockItem
+ *
+ * Gets the title for the #PnlDockItem.
+ *
+ * Generally, you want to use a #PnlDockWidget which has a "title" property you
+ * can set. But this can be helpful for integration of various container
+ * widgets.
+ *
+ * Returns: (transfer full) (nullable): A newly allocated string or %NULL.
+ */
+gchar *
+pnl_dock_item_get_title (PnlDockItem *self)
+{
+  g_return_val_if_fail (PNL_IS_DOCK_ITEM (self), NULL);
+
+  if (PNL_DOCK_ITEM_GET_IFACE (self)->get_title)
+    return PNL_DOCK_ITEM_GET_IFACE (self)->get_title (self);
+
+  return NULL;
+}
+
+/**
+ * pnl_dock_item_get_icon_name:
+ * @self: A #PnlDockItem
+ *
+ * Gets the icon_name for the #PnlDockItem.
+ *
+ * Generally, you want to use a #PnlDockWidget which has a "icon-name" property
+ * you can set. But this can be helpful for integration of various container
+ * widgets.
+ *
+ * Returns: (transfer full) (nullable): A newly allocated string or %NULL.
+ */
+gchar *
+pnl_dock_item_get_icon_name (PnlDockItem *self)
+{
+  g_return_val_if_fail (PNL_IS_DOCK_ITEM (self), NULL);
+
+  if (PNL_DOCK_ITEM_GET_IFACE (self)->get_icon_name)
+    return PNL_DOCK_ITEM_GET_IFACE (self)->get_icon_name (self);
+
+  return NULL;
+}
+
+/**
+ * pnl_dock_item_release:
+ * @self: A #PnlDockItem
+ *
+ * This virtual method should remove @child from @self if the
+ * dock item knows how to do so. For example, the #PnlDockStack
+ * will remove @child from it's internal #GtkStack.
+ *
+ * After the virtual function has been executed, child tracking
+ * will be removed so that #PnlDockItem implementations do not
+ * need to implement themselves.
+ */
+void
+pnl_dock_item_release (PnlDockItem     *self,
+                       PnlDockItem     *child)
+{
+  g_return_if_fail (PNL_IS_DOCK_ITEM (self));
+  g_return_if_fail (self == pnl_dock_item_get_parent (child));
+
+  PNL_DOCK_ITEM_GET_IFACE (self)->release (self, child);
+
+  g_object_weak_unref (G_OBJECT (child),
+                       pnl_dock_item_child_weak_notify,
+                       self);
+  pnl_dock_item_child_weak_notify (self, (GObject *)child);
+}
+
+/**
+ * pnl_dock_item_get_can_minimize: (virtual can_minimize)
+ * @self: a #PnlDockItem
+ *
+ * Returns: %TRUE if the widget can be minimized.
+ */
+gboolean
+pnl_dock_item_get_can_minimize (PnlDockItem *self)
+{
+  PnlDockItem *parent;
+
+  g_return_val_if_fail (PNL_IS_DOCK_ITEM (self), FALSE);
+
+  parent = pnl_dock_item_get_parent (self);
+
+  while (parent != NULL)
+    {
+      if (PNL_DOCK_ITEM_GET_IFACE (parent)->can_minimize (parent, self))
+        return TRUE;
+      parent = pnl_dock_item_get_parent (parent);
+    }
+
+  return FALSE;
+}
diff --git a/contrib/pnl/pnl-dock-item.h b/contrib/pnl/pnl-dock-item.h
index 2a067e1..86d24ce 100644
--- a/contrib/pnl/pnl-dock-item.h
+++ b/contrib/pnl/pnl-dock-item.h
@@ -16,6 +16,10 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#if !defined(PNL_INSIDE) && !defined(PNL_COMPILATION)
+# error "Only <pnl.h> can be included directly."
+#endif
+
 #ifndef PNL_DOCK_ITEM_H
 #define PNL_DOCK_ITEM_H
 
@@ -27,38 +31,59 @@ struct _PnlDockItemInterface
 {
   GTypeInterface parent;
 
-  void            (*set_manager)       (PnlDockItem    *self,
-                                        PnlDockManager *manager);
-  PnlDockManager *(*get_manager)       (PnlDockItem    *self);
-  void            (*manager_set)       (PnlDockItem    *self,
-                                        PnlDockManager *old_manager);
-  void            (*present_child)     (PnlDockItem    *self,
-                                        PnlDockItem    *child);
-  void            (*update_visibility) (PnlDockItem    *self);
-  gboolean        (*get_child_visible) (PnlDockItem    *self,
-                                        PnlDockItem    *child);
-  void            (*set_child_visible) (PnlDockItem    *self,
-                                        PnlDockItem    *child,
-                                        gboolean        child_visible);
+  void            (*set_manager)        (PnlDockItem     *self,
+                                         PnlDockManager  *manager);
+  PnlDockManager *(*get_manager)        (PnlDockItem     *self);
+  void            (*manager_set)        (PnlDockItem     *self,
+                                         PnlDockManager  *old_manager);
+  void            (*present_child)      (PnlDockItem     *self,
+                                         PnlDockItem     *child);
+  void            (*update_visibility)  (PnlDockItem     *self);
+  gboolean        (*get_child_visible)  (PnlDockItem     *self,
+                                         PnlDockItem     *child);
+  void            (*set_child_visible)  (PnlDockItem     *self,
+                                         PnlDockItem     *child,
+                                         gboolean         child_visible);
+  gchar          *(*get_title)          (PnlDockItem     *self);
+  gchar          *(*get_icon_name)      (PnlDockItem     *self);
+  gboolean        (*get_can_close)      (PnlDockItem     *self);
+  gboolean        (*can_minimize)       (PnlDockItem     *self,
+                                         PnlDockItem     *descendant);
+  gboolean        (*close)              (PnlDockItem     *self);
+  gboolean        (*minimize)           (PnlDockItem     *self,
+                                         PnlDockItem     *child,
+                                         GtkPositionType *position);
+  void            (*release)            (PnlDockItem     *self,
+                                         PnlDockItem     *child);
 };
 
-PnlDockManager *pnl_dock_item_get_manager       (PnlDockItem    *self);
-void            pnl_dock_item_set_manager       (PnlDockItem    *self,
-                                                 PnlDockManager *manager);
-gboolean        pnl_dock_item_adopt             (PnlDockItem    *self,
-                                                 PnlDockItem    *child);
-void            pnl_dock_item_present           (PnlDockItem    *self);
-void            pnl_dock_item_present_child     (PnlDockItem    *self,
-                                                 PnlDockItem    *child);
-void            pnl_dock_item_update_visibility (PnlDockItem    *self);
-gboolean        pnl_dock_item_has_widgets       (PnlDockItem    *self);
-gboolean        pnl_dock_item_get_child_visible (PnlDockItem    *self,
-                                                 PnlDockItem    *child);
-void            pnl_dock_item_set_child_visible (PnlDockItem    *self,
-                                                 PnlDockItem    *child,
-                                                 gboolean        child_visible);
-PnlDockItem    *pnl_dock_item_get_parent        (PnlDockItem    *self);
-void            _pnl_dock_item_printf           (PnlDockItem    *self);
+PnlDockManager *pnl_dock_item_get_manager       (PnlDockItem     *self);
+void            pnl_dock_item_set_manager       (PnlDockItem     *self,
+                                                 PnlDockManager  *manager);
+gboolean        pnl_dock_item_adopt             (PnlDockItem     *self,
+                                                 PnlDockItem     *child);
+void            pnl_dock_item_present           (PnlDockItem     *self);
+void            pnl_dock_item_present_child     (PnlDockItem     *self,
+                                                 PnlDockItem     *child);
+void            pnl_dock_item_update_visibility (PnlDockItem     *self);
+gboolean        pnl_dock_item_has_widgets       (PnlDockItem     *self);
+gboolean        pnl_dock_item_get_child_visible (PnlDockItem     *self,
+                                                 PnlDockItem     *child);
+void            pnl_dock_item_set_child_visible (PnlDockItem     *self,
+                                                 PnlDockItem     *child,
+                                                 gboolean         child_visible);
+PnlDockItem    *pnl_dock_item_get_parent        (PnlDockItem     *self);
+gchar          *pnl_dock_item_get_title         (PnlDockItem     *self);
+gchar          *pnl_dock_item_get_icon_name     (PnlDockItem     *self);
+gboolean        pnl_dock_item_get_can_close     (PnlDockItem     *self);
+gboolean        pnl_dock_item_get_can_minimize  (PnlDockItem     *self);
+gboolean        pnl_dock_item_close             (PnlDockItem     *self);
+gboolean        pnl_dock_item_minimize          (PnlDockItem     *self,
+                                                 PnlDockItem     *child,
+                                                 GtkPositionType *position);
+void            pnl_dock_item_release           (PnlDockItem     *self,
+                                                 PnlDockItem     *child);
+void            _pnl_dock_item_printf           (PnlDockItem     *self);
 
 G_END_DECLS
 
diff --git a/contrib/pnl/pnl-dock-manager.h b/contrib/pnl/pnl-dock-manager.h
index a6d022d..1690b70 100644
--- a/contrib/pnl/pnl-dock-manager.h
+++ b/contrib/pnl/pnl-dock-manager.h
@@ -36,14 +36,14 @@ struct _PnlDockManagerClass
   void (*unregister_dock) (PnlDockManager *self,
                            PnlDock        *dock);
 
-  void (*padding1) (void);
-  void (*padding2) (void);
-  void (*padding3) (void);
-  void (*padding4) (void);
-  void (*padding5) (void);
-  void (*padding6) (void);
-  void (*padding7) (void);
-  void (*padding8) (void);
+  gpointer _reserved1;
+  gpointer _reserved2;
+  gpointer _reserved3;
+  gpointer _reserved4;
+  gpointer _reserved5;
+  gpointer _reserved6;
+  gpointer _reserved7;
+  gpointer _reserved8;
 };
 
 PnlDockManager *pnl_dock_manager_new             (void);
diff --git a/contrib/pnl/pnl-dock-overlay-edge.c b/contrib/pnl/pnl-dock-overlay-edge.c
index 6a07fc1..aa22dc0 100644
--- a/contrib/pnl/pnl-dock-overlay-edge.c
+++ b/contrib/pnl/pnl-dock-overlay-edge.c
@@ -25,12 +25,12 @@
 
 struct _PnlDockOverlayEdge
 {
-  GtkBin          parent;
+  PnlBin          parent;
   GtkPositionType edge : 2;
   gint            position;
 };
 
-G_DEFINE_TYPE_EXTENDED (PnlDockOverlayEdge, pnl_dock_overlay_edge, GTK_TYPE_BIN, 0,
+G_DEFINE_TYPE_EXTENDED (PnlDockOverlayEdge, pnl_dock_overlay_edge, PNL_TYPE_BIN, 0,
                         G_IMPLEMENT_INTERFACE (PNL_TYPE_DOCK_ITEM, NULL))
 
 enum {
@@ -63,35 +63,35 @@ pnl_dock_overlay_edge_update_edge (PnlDockOverlayEdge *self)
 
   style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
 
-  gtk_style_context_remove_class (style_context, "left-edge");
-  gtk_style_context_remove_class (style_context, "right-edge");
-  gtk_style_context_remove_class (style_context, "top-edge");
-  gtk_style_context_remove_class (style_context, "bottom-edge");
+  gtk_style_context_remove_class (style_context, "left");
+  gtk_style_context_remove_class (style_context, "right");
+  gtk_style_context_remove_class (style_context, "top");
+  gtk_style_context_remove_class (style_context, "bottom");
 
   switch (self->edge)
     {
     case GTK_POS_TOP:
       edge = GTK_POS_BOTTOM;
       orientation = GTK_ORIENTATION_HORIZONTAL;
-      style_class = "top-edge";
+      style_class = "top";
       break;
 
     case GTK_POS_BOTTOM:
       edge = GTK_POS_TOP;
       orientation = GTK_ORIENTATION_HORIZONTAL;
-      style_class = "bottom-edge";
+      style_class = "bottom";
       break;
 
     case GTK_POS_LEFT:
       edge = GTK_POS_RIGHT;
       orientation = GTK_ORIENTATION_VERTICAL;
-      style_class = "left-edge";
+      style_class = "left";
       break;
 
     case GTK_POS_RIGHT:
       edge = GTK_POS_LEFT;
       orientation = GTK_ORIENTATION_VERTICAL;
-      style_class = "right-edge";
+      style_class = "right";
       break;
 
     default:
@@ -189,9 +189,6 @@ pnl_dock_overlay_edge_class_init (PnlDockOverlayEdgeClass *klass)
 
   container_class->add = pnl_dock_overlay_edge_add;
 
-  widget_class->draw = pnl_gtk_bin_draw;
-  widget_class->size_allocate = pnl_gtk_bin_size_allocate;
-
   properties [PROP_EDGE] =
     g_param_spec_enum ("edge",
                        "Edge",
@@ -235,7 +232,7 @@ pnl_dock_overlay_edge_class_init (PnlDockOverlayEdgeClass *klass)
   gtk_widget_class_install_style_property (widget_class,
                                            style_properties [STYLE_PROP_OVERLAP_SIZE]);
 
-  gtk_widget_class_set_css_name (widget_class, "dockoverlayedge");
+  gtk_widget_class_set_css_name (widget_class, "pnldockoverlayedge");
 }
 
 static void
diff --git a/contrib/pnl/pnl-dock-overlay-edge.h b/contrib/pnl/pnl-dock-overlay-edge.h
index 1a0d521..e9e4ede 100644
--- a/contrib/pnl/pnl-dock-overlay-edge.h
+++ b/contrib/pnl/pnl-dock-overlay-edge.h
@@ -16,17 +16,17 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#if !defined(PNL_INSIDE) && !defined(PNL_COMPILATION)
+# error "Only <pnl.h> can be included directly."
+#endif
+
 #ifndef PNL_DOCK_OVERLAY_EDGE_H
 #define PNL_DOCK_OVERLAY_EDGE_H
 
-#include <gtk/gtk.h>
+#include "pnl-dock-types.h"
 
 G_BEGIN_DECLS
 
-#define PNL_TYPE_DOCK_OVERLAY_EDGE (pnl_dock_overlay_edge_get_type())
-
-G_DECLARE_FINAL_TYPE (PnlDockOverlayEdge, pnl_dock_overlay_edge, PNL, DOCK_OVERLAY_EDGE, GtkBin)
-
 GtkPositionType pnl_dock_overlay_edge_get_edge     (PnlDockOverlayEdge *self);
 void            pnl_dock_overlay_edge_set_edge     (PnlDockOverlayEdge *self,
                                                     GtkPositionType     edge);
diff --git a/contrib/pnl/pnl-dock-overlay.c b/contrib/pnl/pnl-dock-overlay.c
index 88ea7b7..e9520b9 100644
--- a/contrib/pnl/pnl-dock-overlay.c
+++ b/contrib/pnl/pnl-dock-overlay.c
@@ -900,7 +900,7 @@ pnl_dock_overlay_class_init (PnlDockOverlayClass *klass)
 
   gtk_container_class_install_child_properties (container_class, N_CHILD_PROPS, child_properties);
 
-  gtk_widget_class_set_css_name (widget_class, "dockoverlay");
+  gtk_widget_class_set_css_name (widget_class, "pnldockoverlay");
 
   signals [HIDE_EDGES] =
     g_signal_new ("hide-edges",
diff --git a/contrib/pnl/pnl-dock-overlay.h b/contrib/pnl/pnl-dock-overlay.h
index e5c69b0..3e5c69f 100644
--- a/contrib/pnl/pnl-dock-overlay.h
+++ b/contrib/pnl/pnl-dock-overlay.h
@@ -34,14 +34,14 @@ struct _PnlDockOverlayClass
 
   void (*hide_edges) (PnlDockOverlay *self);
 
-  void (*padding1) (void);
-  void (*padding2) (void);
-  void (*padding3) (void);
-  void (*padding4) (void);
-  void (*padding5) (void);
-  void (*padding6) (void);
-  void (*padding7) (void);
-  void (*padding8) (void);
+  gpointer _reserved1;
+  gpointer _reserved2;
+  gpointer _reserved3;
+  gpointer _reserved4;
+  gpointer _reserved5;
+  gpointer _reserved6;
+  gpointer _reserved7;
+  gpointer _reserved8;
 };
 
 GtkWidget              *pnl_dock_overlay_new                   (void);
diff --git a/contrib/pnl/pnl-dock-paned-private.h b/contrib/pnl/pnl-dock-paned-private.h
index a120a0a..9f73223 100644
--- a/contrib/pnl/pnl-dock-paned-private.h
+++ b/contrib/pnl/pnl-dock-paned-private.h
@@ -16,6 +16,10 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#if !defined(PNL_INSIDE) && !defined(PNL_COMPILATION)
+# error "Only <pnl.h> can be included directly."
+#endif
+
 #ifndef PNL_DOCK_PANED_PRIVATE_H
 #define PNL_DOCK_PANED_PRIVATE_H
 
diff --git a/contrib/pnl/pnl-dock-paned.c b/contrib/pnl/pnl-dock-paned.c
index 36cd6ba..2536a1f 100644
--- a/contrib/pnl/pnl-dock-paned.c
+++ b/contrib/pnl/pnl-dock-paned.c
@@ -86,7 +86,7 @@ pnl_dock_paned_class_init (PnlDockPanedClass *klass)
 
   container_class->add = pnl_dock_paned_add;
 
-  gtk_widget_class_set_css_name (widget_class, "dockpaned");
+  gtk_widget_class_set_css_name (widget_class, "pnldockpaned");
 }
 
 static void
diff --git a/contrib/pnl/pnl-dock-paned.h b/contrib/pnl/pnl-dock-paned.h
index 4889e00..f345d42 100644
--- a/contrib/pnl/pnl-dock-paned.h
+++ b/contrib/pnl/pnl-dock-paned.h
@@ -31,14 +31,14 @@ struct _PnlDockPanedClass
 {
   PnlMultiPanedClass parent;
 
-  void (*padding1) (void);
-  void (*padding2) (void);
-  void (*padding3) (void);
-  void (*padding4) (void);
-  void (*padding5) (void);
-  void (*padding6) (void);
-  void (*padding7) (void);
-  void (*padding8) (void);
+  gpointer _reserved1;
+  gpointer _reserved2;
+  gpointer _reserved3;
+  gpointer _reserved4;
+  gpointer _reserved5;
+  gpointer _reserved6;
+  gpointer _reserved7;
+  gpointer _reserved8;
 };
 
 GtkWidget *pnl_dock_paned_new (void);
diff --git a/contrib/pnl/pnl-dock-revealer.c b/contrib/pnl/pnl-dock-revealer.c
index ee994b0..3f176ff 100644
--- a/contrib/pnl/pnl-dock-revealer.c
+++ b/contrib/pnl/pnl-dock-revealer.c
@@ -54,9 +54,10 @@ typedef struct
   guint                          position_set : 1;
   guint                          reveal_child : 1;
   guint                          child_revealed : 1;
+  GtkRequisition                 nat_req;
 } PnlDockRevealerPrivate;
 
-G_DEFINE_TYPE_WITH_PRIVATE (PnlDockRevealer, pnl_dock_revealer, GTK_TYPE_BIN)
+G_DEFINE_TYPE_WITH_PRIVATE (PnlDockRevealer, pnl_dock_revealer, PNL_TYPE_BIN)
 
 enum {
   PROP_0,
@@ -202,6 +203,9 @@ pnl_dock_revealer_calculate_duration (PnlDockRevealer *self)
 
   g_assert (PNL_IS_DOCK_REVEALER (self));
 
+  if (!gtk_widget_get_realized (GTK_WIDGET (self)))
+    return 0;
+
   child = gtk_bin_get_child (GTK_BIN (self));
 
   if (child == NULL)
@@ -285,7 +289,6 @@ pnl_dock_revealer_set_reveal_child (PnlDockRevealer *self,
                                                g_object_ref (self),
                                                "value", reveal_child ? 1.0 : 0.0,
                                                NULL);
-
           pnl_set_weak_pointer (&priv->animation, animation);
         }
 
@@ -394,25 +397,50 @@ pnl_dock_revealer_get_preferred_width (GtkWidget *widget,
 {
   PnlDockRevealer *self = (PnlDockRevealer *)widget;
   PnlDockRevealerPrivate *priv = pnl_dock_revealer_get_instance_private (self);
+  GtkStyleContext *style_context;
+  GtkWidget *child;
+  GtkBorder borders;
 
   g_assert (PNL_IS_DOCK_REVEALER (self));
   g_assert (min_width != NULL);
   g_assert (nat_width != NULL);
 
+  style_context = gtk_widget_get_style_context (widget);
+  pnl_gtk_style_context_get_borders (style_context, &borders);
+
+  child = gtk_bin_get_child (GTK_BIN (self));
+
   pnl_dock_revealer_get_child_preferred_width (self, min_width, nat_width);
 
-  if (IS_HORIZONTAL (priv->transition_type) && priv->animation != NULL)
-    {
-      /*
-       * We allow going smaller than the minimum size during animations
-       * and rely on clipping to hide the child.
-       */
-      *min_width = 0;
+  *min_width += borders.left + borders.right;
+  *nat_width += borders.left + borders.right;
 
-      /*
-       * Our natural width is adjusted for the in-progress animation.
-       */
-      *nat_width *= gtk_adjustment_get_value (priv->adjustment);
+  priv->nat_req.width = *nat_width;
+
+  if (IS_HORIZONTAL (priv->transition_type))
+    {
+      if (priv->animation != NULL)
+        {
+          /*
+           * We allow going smaller than the minimum size during animations
+           * and rely on clipping to hide the child.
+           */
+          *min_width = 0;
+
+          /*
+           * Our natural width is adjusted for the in-progress animation.
+           */
+          *nat_width *= gtk_adjustment_get_value (priv->adjustment);
+        }
+      else if (child != NULL && !gtk_widget_get_child_visible (child))
+        {
+          /*
+           * Make sure we are completely hidden if the child is not currently
+           * visible.
+           */
+          *min_width = 0;
+          *nat_width = 0;
+        }
     }
 }
 
@@ -455,25 +483,50 @@ pnl_dock_revealer_get_preferred_height (GtkWidget *widget,
 {
   PnlDockRevealer *self = (PnlDockRevealer *)widget;
   PnlDockRevealerPrivate *priv = pnl_dock_revealer_get_instance_private (self);
+  GtkStyleContext *style_context;
+  GtkWidget *child;
+  GtkBorder borders;
 
   g_assert (PNL_IS_DOCK_REVEALER (self));
   g_assert (min_height != NULL);
   g_assert (nat_height != NULL);
 
+  style_context = gtk_widget_get_style_context (widget);
+  pnl_gtk_style_context_get_borders (style_context, &borders);
+
+  child = gtk_bin_get_child (GTK_BIN (self));
+
   pnl_dock_revealer_get_child_preferred_height (self, min_height, nat_height);
 
-  if (IS_VERTICAL (priv->transition_type) && priv->animation != NULL)
-    {
-      /*
-       * We allow going smaller than the minimum size during animations
-       * and rely on clipping to hide the child.
-       */
-      *min_height = 0;
+  *min_height += borders.top + borders.bottom;
+  *nat_height += borders.top + borders.bottom;
 
-      /*
-       * Our natural height is adjusted for the in-progress animation.
-       */
-      *nat_height *= gtk_adjustment_get_value (priv->adjustment);
+  priv->nat_req.height = *nat_height;
+
+  if (IS_VERTICAL (priv->transition_type))
+    {
+      if (priv->animation != NULL)
+        {
+          /*
+           * We allow going smaller than the minimum size during animations
+           * and rely on clipping to hide the child.
+           */
+          *min_height = 0;
+
+          /*
+           * Our natural height is adjusted for the in-progress animation.
+           */
+          *nat_height *= gtk_adjustment_get_value (priv->adjustment);
+        }
+      else if (child != NULL && !gtk_widget_get_child_visible (child))
+        {
+          /*
+           * Make sure we are completely hidden if the child is not currently
+           * visible.
+           */
+          *min_height = 0;
+          *nat_height = 0;
+        }
     }
 }
 
@@ -486,7 +539,9 @@ pnl_dock_revealer_size_allocate (GtkWidget     *widget,
   GtkAllocation child_allocation;
   GtkRequisition min_req;
   GtkRequisition nat_req;
+  GtkStyleContext *style_context;
   GtkWidget *child;
+  GtkBorder borders;
 
   g_assert (PNL_IS_DOCK_REVEALER (self));
 
@@ -505,10 +560,13 @@ pnl_dock_revealer_size_allocate (GtkWidget     *widget,
   if (!gtk_widget_get_child_visible (child))
     return;
 
+  child_allocation = *allocation;
   child_allocation.x = 0;
   child_allocation.y = 0;
-  child_allocation.width = allocation->width;
-  child_allocation.height = allocation->height;
+
+  style_context = gtk_widget_get_style_context (widget);
+  pnl_gtk_style_context_get_borders (style_context, &borders);
+  pnl_gtk_allocation_subtract_border (&child_allocation, &borders);
 
   if (IS_HORIZONTAL (priv->transition_type))
     {
@@ -516,7 +574,7 @@ pnl_dock_revealer_size_allocate (GtkWidget     *widget,
       child_allocation.width = nat_req.width;
 
       if (priv->transition_type == PNL_DOCK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT)
-        child_allocation.x = allocation->width - child_allocation.width;
+        child_allocation.x = allocation->width - borders.right - child_allocation.width;
     }
   else if (IS_VERTICAL (priv->transition_type))
     {
@@ -524,7 +582,7 @@ pnl_dock_revealer_size_allocate (GtkWidget     *widget,
       child_allocation.height = nat_req.height;
 
       if (priv->transition_type == PNL_DOCK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN)
-        child_allocation.y = allocation->height - child_allocation.height;
+        child_allocation.y = allocation->height - borders.bottom - child_allocation.height;
     }
 
   gtk_widget_size_allocate (child, &child_allocation);
@@ -545,6 +603,66 @@ pnl_dock_revealer_add (GtkContainer *container,
   gtk_widget_set_child_visible (widget, priv->reveal_child);
 }
 
+static gboolean
+pnl_dock_revealer_draw (GtkWidget *widget,
+                        cairo_t   *cr)
+{
+  PnlDockRevealer *self = (PnlDockRevealer *)widget;
+  PnlDockRevealerPrivate *priv = pnl_dock_revealer_get_instance_private (self);
+  GtkAllocation alloc;
+  GtkStyleContext *style_context;
+  GtkWidget *child;
+  GtkBorder margin;
+  GtkStateFlags state;
+
+  g_assert (PNL_IS_DOCK_REVEALER (self));
+
+  gtk_widget_get_allocation (widget, &alloc);
+
+  if (gtk_widget_get_has_window (widget))
+    {
+      alloc.x = 0;
+      alloc.y = 0;
+    }
+
+  if (priv->animation != NULL)
+    {
+      /*
+       * If we are currently animating, we want to ensure that our background
+       * is drawn at the size of the natural allocation. Otherwise borders
+       * will be shown in improper locations.
+       */
+      if (IS_HORIZONTAL (priv->transition_type))
+        {
+          if (priv->transition_type == PNL_DOCK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT)
+            alloc.x -= (priv->nat_req.width - alloc.width);
+          alloc.width = priv->nat_req.width;
+        }
+      else
+        {
+          if (priv->transition_type == PNL_DOCK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN)
+            alloc.y -= (priv->nat_req.height - alloc.height);
+          alloc.height = priv->nat_req.height;
+        }
+    }
+
+  style_context = gtk_widget_get_style_context (widget);
+  state = gtk_style_context_get_state (style_context);
+
+  gtk_style_context_get_margin (style_context, state, &margin);
+  pnl_gtk_allocation_subtract_border (&alloc, &margin);
+
+  gtk_render_background (style_context, cr, alloc.x, alloc.y, alloc.width, alloc.height);
+
+  child = gtk_bin_get_child (GTK_BIN (widget));
+  if (child != NULL)
+    gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
+
+  gtk_render_frame (style_context, cr, alloc.x, alloc.y, alloc.width, alloc.height);
+
+  return FALSE;
+}
+
 static void
 pnl_dock_revealer_realize (GtkWidget *widget)
 {
@@ -680,6 +798,7 @@ pnl_dock_revealer_class_init (PnlDockRevealerClass *klass)
   widget_class->get_preferred_height = pnl_dock_revealer_get_preferred_height;
   widget_class->realize = pnl_dock_revealer_realize;
   widget_class->size_allocate = pnl_dock_revealer_size_allocate;
+  widget_class->draw = pnl_dock_revealer_draw;
 
   container_class->add = pnl_dock_revealer_add;
 
diff --git a/contrib/pnl/pnl-dock-revealer.h b/contrib/pnl/pnl-dock-revealer.h
index 7865e1b..7bbcdb3 100644
--- a/contrib/pnl/pnl-dock-revealer.h
+++ b/contrib/pnl/pnl-dock-revealer.h
@@ -23,11 +23,14 @@
 #ifndef PNL_DOCK_REVEALER_H
 #define PNL_DOCK_REVEALER_H
 
-#include "pnl-dock-types.h"
+#include "pnl-bin.h"
 
 G_BEGIN_DECLS
 
 #define PNL_TYPE_DOCK_REVEALER_TRANSITION_TYPE (pnl_dock_revealer_transition_type_get_type())
+#define PNL_TYPE_DOCK_REVEALER                 (pnl_dock_revealer_get_type())
+
+G_DECLARE_DERIVABLE_TYPE (PnlDockRevealer, pnl_dock_revealer, PNL, DOCK_REVEALER, PnlBin)
 
 typedef enum
 {
@@ -40,16 +43,16 @@ typedef enum
 
 struct _PnlDockRevealerClass
 {
-  GtkBinClass parent;
+  PnlBinClass parent;
 
-  void (*padding1) (void);
-  void (*padding2) (void);
-  void (*padding3) (void);
-  void (*padding4) (void);
-  void (*padding5) (void);
-  void (*padding6) (void);
-  void (*padding7) (void);
-  void (*padding8) (void);
+  gpointer _reserved1;
+  gpointer _reserved2;
+  gpointer _reserved3;
+  gpointer _reserved4;
+  gpointer _reserved5;
+  gpointer _reserved6;
+  gpointer _reserved7;
+  gpointer _reserved8;
 };
 
 GType                          pnl_dock_revealer_transition_type_get_type (void);
diff --git a/contrib/pnl/pnl-dock-stack.c b/contrib/pnl/pnl-dock-stack.c
index 6f9f64b..9cdf82f 100644
--- a/contrib/pnl/pnl-dock-stack.c
+++ b/contrib/pnl/pnl-dock-stack.c
@@ -16,16 +16,22 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#define G_LOG_DOMAIN "pnl-dock-stack"
+
 #include "pnl-dock-item.h"
 #include "pnl-dock-stack.h"
 #include "pnl-dock-widget.h"
-#include "pnl-dock-tab-strip.h"
+#include "pnl-tab-private.h"
+#include "pnl-tab-strip.h"
+#include "pnl-util-private.h"
 
 typedef struct
 {
   GtkStack         *stack;
   PnlTabStrip      *tab_strip;
+  GtkButton        *pinned_button;
   GtkPositionType   edge : 2;
+  PnlTabStyle       style : 2;
 } PnlDockStackPrivate;
 
 static void pnl_dock_stack_init_dock_item_iface (PnlDockItemInterface *iface);
@@ -38,6 +44,8 @@ G_DEFINE_TYPE_EXTENDED (PnlDockStack, pnl_dock_stack, GTK_TYPE_BOX, 0,
 enum {
   PROP_0,
   PROP_EDGE,
+  PROP_SHOW_PINNED_BUTTON,
+  PROP_STYLE,
   N_PROPS
 };
 
@@ -49,14 +57,19 @@ pnl_dock_stack_add (GtkContainer *container,
 {
   PnlDockStack *self = (PnlDockStack *)container;
   PnlDockStackPrivate *priv = pnl_dock_stack_get_instance_private (self);
-  const gchar *title = NULL;
+  g_autofree gchar *icon_name = NULL;
+  g_autofree gchar *title = NULL;
 
   g_assert (PNL_IS_DOCK_STACK (self));
 
-  if (PNL_IS_DOCK_WIDGET (widget))
-    title = pnl_dock_widget_get_title (PNL_DOCK_WIDGET (widget));
+  if (PNL_IS_DOCK_ITEM (widget))
+    {
+      title = pnl_dock_item_get_title (PNL_DOCK_ITEM (widget));
+      icon_name = pnl_dock_item_get_icon_name (PNL_DOCK_ITEM (widget));
+    }
 
   gtk_container_add_with_properties (GTK_CONTAINER (priv->stack), widget,
+                                     "icon-name", icon_name,
                                      "title", title,
                                      NULL);
 
@@ -95,6 +108,14 @@ pnl_dock_stack_get_property (GObject    *object,
       g_value_set_enum (value, pnl_dock_stack_get_edge (self));
       break;
 
+    case PROP_SHOW_PINNED_BUTTON:
+      g_value_set_boolean (value, pnl_dock_stack_get_show_pinned_button (self));
+      break;
+
+    case PROP_STYLE:
+      g_value_set_flags (value, pnl_dock_stack_get_style (self));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -114,6 +135,14 @@ pnl_dock_stack_set_property (GObject      *object,
       pnl_dock_stack_set_edge (self, g_value_get_enum (value));
       break;
 
+    case PROP_SHOW_PINNED_BUTTON:
+      pnl_dock_stack_set_show_pinned_button (self, g_value_get_boolean (value));
+      break;
+
+    case PROP_STYLE:
+      pnl_dock_stack_set_style (self, g_value_get_flags (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -141,9 +170,24 @@ pnl_dock_stack_class_init (PnlDockStackClass *klass)
                        GTK_POS_TOP,
                        (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
 
+  properties [PROP_SHOW_PINNED_BUTTON] =
+    g_param_spec_boolean ("show-pinned-button",
+                          "Show Pinned Button",
+                          "Show the pinned button to pin the dock edge",
+                          FALSE,
+                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_STYLE] =
+    g_param_spec_flags ("style",
+                        "Style",
+                        "Style",
+                        PNL_TYPE_TAB_STYLE,
+                        PNL_TAB_BOTH,
+                        (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
   g_object_class_install_properties (object_class, N_PROPS, properties);
 
-  gtk_widget_class_set_css_name (widget_class, "dockstack");
+  gtk_widget_class_set_css_name (widget_class, "pnldockstack");
 }
 
 static void
@@ -153,23 +197,41 @@ pnl_dock_stack_init (PnlDockStack *self)
 
   gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_VERTICAL);
 
+  priv->style = PNL_TAB_BOTH;
   priv->edge = GTK_POS_TOP;
 
+  /*
+   * NOTE: setting a transition for the stack seems to muck up
+   *       focus, causing the old-tab to get refocused. So we can't
+   *       switch to CROSSFADE just yet.
+   */
+
   priv->stack = g_object_new (GTK_TYPE_STACK,
                               "homogeneous", TRUE,
                               "visible", TRUE,
                               NULL);
 
-  priv->tab_strip = g_object_new (PNL_TYPE_DOCK_TAB_STRIP,
+  priv->tab_strip = g_object_new (PNL_TYPE_TAB_STRIP,
                                   "edge", GTK_POS_TOP,
                                   "stack", priv->stack,
                                   "visible", TRUE,
                                   NULL);
 
+  priv->pinned_button = g_object_new (GTK_TYPE_BUTTON,
+                                      "action-name", "panel.pinned",
+                                      "child", g_object_new (GTK_TYPE_IMAGE,
+                                                             "icon-name", "window-maximize-symbolic",
+                                                             "visible", TRUE,
+                                                             NULL),
+                                      "visible", FALSE,
+                                      NULL);
+
   GTK_CONTAINER_CLASS (pnl_dock_stack_parent_class)->add (GTK_CONTAINER (self),
                                                           GTK_WIDGET (priv->tab_strip));
   GTK_CONTAINER_CLASS (pnl_dock_stack_parent_class)->add (GTK_CONTAINER (self),
                                                           GTK_WIDGET (priv->stack));
+
+  pnl_tab_strip_add_control (priv->tab_strip, GTK_WIDGET (priv->pinned_button));
 }
 
 GtkWidget *
@@ -312,9 +374,105 @@ pnl_dock_stack_set_child_visible (PnlDockItem *item,
 }
 
 static void
+update_tab_controls (GtkWidget *widget,
+                     gpointer   unused)
+{
+  g_assert (GTK_IS_WIDGET (widget));
+
+  if (PNL_IS_TAB (widget))
+    _pnl_tab_update_controls (PNL_TAB (widget));
+}
+
+static void
+pnl_dock_stack_update_visibility (PnlDockItem *item)
+{
+  PnlDockStack *self = (PnlDockStack *)item;
+  PnlDockStackPrivate *priv = pnl_dock_stack_get_instance_private (self);
+
+  g_assert (PNL_IS_DOCK_STACK (self));
+
+  gtk_container_foreach (GTK_CONTAINER (priv->tab_strip),
+                         update_tab_controls,
+                         NULL);
+
+  if (!pnl_dock_item_has_widgets (item))
+    gtk_widget_hide (GTK_WIDGET (item));
+  else
+    gtk_widget_show (GTK_WIDGET (item));
+}
+
+static void
+pnl_dock_stack_release (PnlDockItem *item,
+                        PnlDockItem *child)
+{
+  PnlDockStack *self = (PnlDockStack *)item;
+  PnlDockStackPrivate *priv = pnl_dock_stack_get_instance_private (self);
+
+  g_assert (PNL_IS_DOCK_STACK (self));
+  g_assert (PNL_IS_DOCK_ITEM (child));
+
+  gtk_container_remove (GTK_CONTAINER (priv->stack), GTK_WIDGET (child));
+}
+
+static void
 pnl_dock_stack_init_dock_item_iface (PnlDockItemInterface *iface)
 {
   iface->present_child = pnl_dock_stack_present_child;
   iface->get_child_visible = pnl_dock_stack_get_child_visible;
   iface->set_child_visible = pnl_dock_stack_set_child_visible;
+  iface->update_visibility = pnl_dock_stack_update_visibility;
+  iface->release = pnl_dock_stack_release;
+}
+
+gboolean
+pnl_dock_stack_get_show_pinned_button (PnlDockStack *self)
+{
+  PnlDockStackPrivate *priv = pnl_dock_stack_get_instance_private (self);
+
+  g_return_val_if_fail (PNL_IS_DOCK_STACK (self), FALSE);
+
+  return gtk_widget_get_visible (GTK_WIDGET (priv->pinned_button));
+}
+
+void
+pnl_dock_stack_set_show_pinned_button (PnlDockStack *self,
+                                       gboolean      show_pinned_button)
+{
+  PnlDockStackPrivate *priv = pnl_dock_stack_get_instance_private (self);
+
+  g_return_if_fail (PNL_IS_DOCK_STACK (self));
+
+  show_pinned_button = !!show_pinned_button;
+
+  if (show_pinned_button != gtk_widget_get_visible (GTK_WIDGET (priv->pinned_button)))
+    {
+      gtk_widget_set_visible (GTK_WIDGET (priv->pinned_button), show_pinned_button);
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SHOW_PINNED_BUTTON]);
+    }
+}
+
+PnlTabStyle
+pnl_dock_stack_get_style (PnlDockStack *self)
+{
+  PnlDockStackPrivate *priv = pnl_dock_stack_get_instance_private (self);
+
+  g_return_val_if_fail (PNL_IS_DOCK_STACK (self), 0);
+
+  return priv->style;
+}
+
+void
+pnl_dock_stack_set_style (PnlDockStack *self,
+                          PnlTabStyle   style)
+{
+  PnlDockStackPrivate *priv = pnl_dock_stack_get_instance_private (self);
+
+  g_return_if_fail (PNL_IS_DOCK_STACK (self));
+
+  if (priv->style != style)
+    {
+      priv->style = style;
+      pnl_tab_strip_set_style (priv->tab_strip, style);
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_STYLE]);
+    }
 }
diff --git a/contrib/pnl/pnl-dock-stack.h b/contrib/pnl/pnl-dock-stack.h
index fb19286..edbb646 100644
--- a/contrib/pnl/pnl-dock-stack.h
+++ b/contrib/pnl/pnl-dock-stack.h
@@ -30,12 +30,23 @@ G_BEGIN_DECLS
 struct _PnlDockStackClass
 {
   GtkBoxClass parent;
+
+  gpointer _reserved1;
+  gpointer _reserved2;
+  gpointer _reserved3;
+  gpointer _reserved4;
 };
 
-GtkWidget       *pnl_dock_stack_new      (void);
-GtkPositionType  pnl_dock_stack_get_edge (PnlDockStack    *self);
-void             pnl_dock_stack_set_edge (PnlDockStack    *self,
-                                          GtkPositionType  edge);
+GtkWidget       *pnl_dock_stack_new                    (void);
+GtkPositionType  pnl_dock_stack_get_edge               (PnlDockStack    *self);
+void             pnl_dock_stack_set_edge               (PnlDockStack    *self,
+                                                        GtkPositionType  edge);
+PnlTabStyle      pnl_dock_stack_get_style              (PnlDockStack    *self);
+void             pnl_dock_stack_set_style              (PnlDockStack    *self,
+                                                        PnlTabStyle      style);
+gboolean         pnl_dock_stack_get_show_pinned_button (PnlDockStack    *self);
+void             pnl_dock_stack_set_show_pinned_button (PnlDockStack    *self,
+                                                        gboolean         show_pinned_button);
 
 G_END_DECLS
 
diff --git a/contrib/pnl/pnl-dock-transient-grab.h b/contrib/pnl/pnl-dock-transient-grab.h
index 1c603d1..3125a4b 100644
--- a/contrib/pnl/pnl-dock-transient-grab.h
+++ b/contrib/pnl/pnl-dock-transient-grab.h
@@ -16,6 +16,10 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#if !defined(PNL_INSIDE) && !defined(PNL_COMPILATION)
+# error "Only <pnl.h> can be included directly."
+#endif
+
 #ifndef PNL_DOCK_TRANSIENT_GRAB_H
 #define PNL_DOCK_TRANSIENT_GRAB_H
 
diff --git a/contrib/pnl/pnl-dock-types.h b/contrib/pnl/pnl-dock-types.h
index 33f9c7b..66803df 100644
--- a/contrib/pnl/pnl-dock-types.h
+++ b/contrib/pnl/pnl-dock-types.h
@@ -25,31 +25,52 @@
 
 #include <gtk/gtk.h>
 
+#include "pnl-bin.h"
+#include "pnl-dock-revealer.h"
 #include "pnl-multi-paned.h"
 
 G_BEGIN_DECLS
 
-#define PNL_TYPE_DOCK          (pnl_dock_get_type ())
-#define PNL_TYPE_DOCK_BIN      (pnl_dock_bin_get_type())
-#define PNL_TYPE_DOCK_ITEM     (pnl_dock_item_get_type())
-#define PNL_TYPE_DOCK_MANAGER  (pnl_dock_manager_get_type())
-#define PNL_TYPE_DOCK_OVERLAY  (pnl_dock_overlay_get_type())
-#define PNL_TYPE_DOCK_PANED    (pnl_dock_paned_get_type())
-#define PNL_TYPE_DOCK_REVEALER (pnl_dock_revealer_get_type())
-#define PNL_TYPE_DOCK_STACK    (pnl_dock_stack_get_type())
-#define PNL_TYPE_DOCK_WIDGET   (pnl_dock_widget_get_type())
-#define PNL_TYPE_DOCK_WINDOW   (pnl_dock_window_get_type())
-
-G_DECLARE_INTERFACE      (PnlDock,         pnl_dock,          PNL, DOCK,          GtkContainer)
-G_DECLARE_DERIVABLE_TYPE (PnlDockBin,      pnl_dock_bin,      PNL, DOCK_BIN,      GtkContainer)
-G_DECLARE_INTERFACE      (PnlDockItem,     pnl_dock_item,     PNL, DOCK_ITEM,     GtkWidget)
-G_DECLARE_DERIVABLE_TYPE (PnlDockManager,  pnl_dock_manager,  PNL, DOCK_MANAGER,  GObject)
-G_DECLARE_DERIVABLE_TYPE (PnlDockOverlay,  pnl_dock_overlay,  PNL, DOCK_OVERLAY,  GtkEventBox)
-G_DECLARE_DERIVABLE_TYPE (PnlDockPaned,    pnl_dock_paned,    PNL, DOCK_PANED,    PnlMultiPaned)
-G_DECLARE_DERIVABLE_TYPE (PnlDockRevealer, pnl_dock_revealer, PNL, DOCK_REVEALER, GtkBin)
-G_DECLARE_DERIVABLE_TYPE (PnlDockStack,    pnl_dock_stack,    PNL, DOCK_STACK,    GtkBox)
-G_DECLARE_DERIVABLE_TYPE (PnlDockWidget,   pnl_dock_widget,   PNL, DOCK_WIDGET,   GtkBin)
-G_DECLARE_DERIVABLE_TYPE (PnlDockWindow,   pnl_dock_window,   PNL, DOCK_WINDOW,   GtkWindow)
+#define PNL_TYPE_DOCK                   (pnl_dock_get_type ())
+#define PNL_TYPE_DOCK_BIN               (pnl_dock_bin_get_type())
+#define PNL_TYPE_DOCK_BIN_EDGE          (pnl_dock_bin_edge_get_type())
+#define PNL_TYPE_DOCK_ITEM              (pnl_dock_item_get_type())
+#define PNL_TYPE_DOCK_MANAGER           (pnl_dock_manager_get_type())
+#define PNL_TYPE_DOCK_OVERLAY           (pnl_dock_overlay_get_type())
+#define PNL_TYPE_DOCK_OVERLAY_EDGE      (pnl_dock_overlay_edge_get_type())
+#define PNL_TYPE_DOCK_PANED             (pnl_dock_paned_get_type())
+#define PNL_TYPE_DOCK_STACK             (pnl_dock_stack_get_type())
+#define PNL_TYPE_DOCK_TAB_STRIP         (pnl_dock_tab_strip_get_type())
+#define PNL_TYPE_DOCK_WIDGET            (pnl_dock_widget_get_type())
+#define PNL_TYPE_DOCK_WINDOW            (pnl_dock_window_get_type())
+#define PNL_TYPE_TAB                    (pnl_tab_get_type())
+#define PNL_TYPE_TAB_STRIP              (pnl_tab_strip_get_type())
+#define PNL_TYPE_TAB_STYLE              (pnl_tab_style_get_type())
+
+G_DECLARE_DERIVABLE_TYPE (PnlDockBin,             pnl_dock_bin,               PNL, DOCK_BIN,              
GtkContainer)
+G_DECLARE_DERIVABLE_TYPE (PnlDockBinEdge,         pnl_dock_bin_edge,          PNL, DOCK_BIN_EDGE,         
PnlDockRevealer)
+G_DECLARE_DERIVABLE_TYPE (PnlDockManager,         pnl_dock_manager,           PNL, DOCK_MANAGER,          
GObject)
+G_DECLARE_DERIVABLE_TYPE (PnlDockOverlay,         pnl_dock_overlay,           PNL, DOCK_OVERLAY,          
GtkEventBox)
+G_DECLARE_DERIVABLE_TYPE (PnlDockPaned,           pnl_dock_paned,             PNL, DOCK_PANED,            
PnlMultiPaned)
+G_DECLARE_DERIVABLE_TYPE (PnlDockStack,           pnl_dock_stack,             PNL, DOCK_STACK,            
GtkBox)
+G_DECLARE_DERIVABLE_TYPE (PnlDockWidget,          pnl_dock_widget,            PNL, DOCK_WIDGET,           
PnlBin)
+G_DECLARE_DERIVABLE_TYPE (PnlDockWindow,          pnl_dock_window,            PNL, DOCK_WINDOW,           
GtkWindow)
+G_DECLARE_DERIVABLE_TYPE (PnlTabStrip,            pnl_tab_strip,              PNL, TAB_STRIP,             
GtkBox)
+
+G_DECLARE_FINAL_TYPE     (PnlTab,                 pnl_tab,                    PNL, TAB,                   
PnlBin)
+G_DECLARE_FINAL_TYPE     (PnlDockOverlayEdge,     pnl_dock_overlay_edge,      PNL, DOCK_OVERLAY_EDGE,     
PnlBin)
+
+G_DECLARE_INTERFACE      (PnlDock,                pnl_dock,                   PNL, DOCK,                  
GtkContainer)
+G_DECLARE_INTERFACE      (PnlDockItem,            pnl_dock_item,              PNL, DOCK_ITEM,             
GtkWidget)
+
+typedef enum
+{
+  PNL_TAB_TEXT  = 1 << 0,
+  PNL_TAB_ICONS = 1 << 1,
+  PNL_TAB_BOTH  = (PNL_TAB_TEXT | PNL_TAB_ICONS),
+} PnlTabStyle;
+
+GType pnl_tab_style_get_type (void);
 
 G_END_DECLS
 
diff --git a/contrib/pnl/pnl-dock-widget.c b/contrib/pnl/pnl-dock-widget.c
index 0b54845..f115b29 100644
--- a/contrib/pnl/pnl-dock-widget.c
+++ b/contrib/pnl/pnl-dock-widget.c
@@ -23,14 +23,20 @@
 typedef struct
 {
   gchar *title;
+  gchar *icon_name;
+  guint can_close : 1;
 } PnlDockWidgetPrivate;
 
-G_DEFINE_TYPE_EXTENDED (PnlDockWidget, pnl_dock_widget, GTK_TYPE_BIN, 0,
+static void dock_item_iface_init (PnlDockItemInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (PnlDockWidget, pnl_dock_widget, PNL_TYPE_BIN, 0,
                         G_ADD_PRIVATE (PnlDockWidget)
-                        G_IMPLEMENT_INTERFACE (PNL_TYPE_DOCK_ITEM, NULL))
+                        G_IMPLEMENT_INTERFACE (PNL_TYPE_DOCK_ITEM, dock_item_iface_init))
 
 enum {
   PROP_0,
+  PROP_CAN_CLOSE,
+  PROP_ICON_NAME,
   PROP_MANAGER,
   PROP_TITLE,
   N_PROPS
@@ -38,6 +44,56 @@ enum {
 
 static GParamSpec *properties [N_PROPS];
 
+static gchar *
+pnl_dock_widget_item_get_title (PnlDockItem *item)
+{
+  PnlDockWidget *self = (PnlDockWidget *)item;
+  PnlDockWidgetPrivate *priv = pnl_dock_widget_get_instance_private (self);
+
+  g_return_val_if_fail (PNL_IS_DOCK_WIDGET (self), NULL);
+
+  return g_strdup (priv->title);
+}
+
+static gchar *
+pnl_dock_widget_item_get_icon_name (PnlDockItem *item)
+{
+  PnlDockWidget *self = (PnlDockWidget *)item;
+  PnlDockWidgetPrivate *priv = pnl_dock_widget_get_instance_private (self);
+
+  g_return_val_if_fail (PNL_IS_DOCK_WIDGET (self), NULL);
+
+  return g_strdup (priv->icon_name);
+}
+
+static gboolean
+pnl_dock_widget_get_can_close (PnlDockItem *item)
+{
+  PnlDockWidget *self = (PnlDockWidget *)item;
+  PnlDockWidgetPrivate *priv = pnl_dock_widget_get_instance_private (self);
+
+  g_return_val_if_fail (PNL_IS_DOCK_WIDGET (self), FALSE);
+
+  return priv->can_close;
+}
+
+static void
+pnl_dock_widget_set_can_close (PnlDockWidget *self,
+                               gboolean       can_close)
+{
+  PnlDockWidgetPrivate *priv = pnl_dock_widget_get_instance_private (self);
+
+  g_return_if_fail (PNL_IS_DOCK_WIDGET (self));
+
+  can_close = !!can_close;
+
+  if (can_close != priv->can_close)
+    {
+      priv->can_close = can_close;
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_CLOSE]);
+    }
+}
+
 static void
 pnl_dock_widget_grab_focus (GtkWidget *widget)
 {
@@ -61,6 +117,7 @@ pnl_dock_widget_finalize (GObject *object)
   PnlDockWidgetPrivate *priv = pnl_dock_widget_get_instance_private (self);
 
   g_clear_pointer (&priv->title, g_free);
+  g_clear_pointer (&priv->icon_name, g_free);
 
   G_OBJECT_CLASS (pnl_dock_widget_parent_class)->finalize (object);
 }
@@ -75,12 +132,20 @@ pnl_dock_widget_get_property (GObject    *object,
 
   switch (prop_id)
     {
+    case PROP_CAN_CLOSE:
+      g_value_set_boolean (value, pnl_dock_widget_get_can_close (PNL_DOCK_ITEM (self)));
+      break;
+
+    case PROP_ICON_NAME:
+      g_value_set_string (value, pnl_dock_widget_item_get_icon_name (PNL_DOCK_ITEM (self)));
+      break;
+
     case PROP_MANAGER:
       g_value_set_object (value, pnl_dock_item_get_manager (PNL_DOCK_ITEM (self)));
       break;
 
     case PROP_TITLE:
-      g_value_set_string (value, pnl_dock_widget_get_title (self));
+      g_value_set_string (value, pnl_dock_widget_item_get_title (PNL_DOCK_ITEM (self)));
       break;
 
     default:
@@ -98,6 +163,14 @@ pnl_dock_widget_set_property (GObject      *object,
 
   switch (prop_id)
     {
+    case PROP_CAN_CLOSE:
+      pnl_dock_widget_set_can_close (self, g_value_get_boolean (value));
+      break;
+
+    case PROP_ICON_NAME:
+      pnl_dock_widget_set_icon_name (self, g_value_get_string (value));
+      break;
+
     case PROP_MANAGER:
       pnl_dock_item_set_manager (PNL_DOCK_ITEM (self), g_value_get_object (value));
       break;
@@ -121,27 +194,39 @@ pnl_dock_widget_class_init (PnlDockWidgetClass *klass)
   object_class->get_property = pnl_dock_widget_get_property;
   object_class->set_property = pnl_dock_widget_set_property;
 
-  widget_class->draw = pnl_gtk_bin_draw;
   widget_class->grab_focus = pnl_dock_widget_grab_focus;
-  widget_class->size_allocate = pnl_gtk_bin_size_allocate;
+
+  properties [PROP_CAN_CLOSE] =
+    g_param_spec_boolean ("can-close",
+                          "Can Close",
+                          "If the dock widget can be closed by the user",
+                          FALSE,
+                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_ICON_NAME] =
+    g_param_spec_string ("icon-name",
+                         "Icon Name",
+                         "Icon Name",
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
 
   properties [PROP_MANAGER] =
     g_param_spec_object ("manager",
                          "Manager",
                          "The panel manager",
                          PNL_TYPE_DOCK_MANAGER,
-                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
 
   properties [PROP_TITLE] =
     g_param_spec_string ("title",
                          "Title",
                          "Title",
                          NULL,
-                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
 
   g_object_class_install_properties (object_class, N_PROPS, properties);
 
-  gtk_widget_class_set_css_name (widget_class, "dockwidget");
+  gtk_widget_class_set_css_name (widget_class, "pnldockwidget");
 }
 
 static void
@@ -157,16 +242,6 @@ pnl_dock_widget_new (void)
   return g_object_new (PNL_TYPE_DOCK_WIDGET, NULL);
 }
 
-const gchar *
-pnl_dock_widget_get_title (PnlDockWidget *self)
-{
-  PnlDockWidgetPrivate *priv = pnl_dock_widget_get_instance_private (self);
-
-  g_return_val_if_fail (PNL_IS_DOCK_WIDGET (self), NULL);
-
-  return priv->title;
-}
-
 void
 pnl_dock_widget_set_title (PnlDockWidget *self,
                            const gchar   *title)
@@ -182,3 +257,27 @@ pnl_dock_widget_set_title (PnlDockWidget *self,
       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TITLE]);
     }
 }
+
+void
+pnl_dock_widget_set_icon_name (PnlDockWidget *self,
+                               const gchar   *icon_name)
+{
+  PnlDockWidgetPrivate *priv = pnl_dock_widget_get_instance_private (self);
+
+  g_return_if_fail (PNL_IS_DOCK_WIDGET (self));
+
+  if (g_strcmp0 (icon_name, priv->icon_name) != 0)
+    {
+      g_free (priv->icon_name);
+      priv->icon_name = g_strdup (icon_name);
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ICON_NAME]);
+    }
+}
+
+static void
+dock_item_iface_init (PnlDockItemInterface *iface)
+{
+  iface->get_can_close = pnl_dock_widget_get_can_close;
+  iface->get_title = pnl_dock_widget_item_get_title;
+  iface->get_icon_name = pnl_dock_widget_item_get_icon_name;
+}
diff --git a/contrib/pnl/pnl-dock-widget.h b/contrib/pnl/pnl-dock-widget.h
index 7141ad4..d97daf2 100644
--- a/contrib/pnl/pnl-dock-widget.h
+++ b/contrib/pnl/pnl-dock-widget.h
@@ -29,22 +29,23 @@ G_BEGIN_DECLS
 
 struct _PnlDockWidgetClass
 {
-  GtkBinClass parent;
-
-  void (*padding1) (void);
-  void (*padding2) (void);
-  void (*padding3) (void);
-  void (*padding4) (void);
-  void (*padding5) (void);
-  void (*padding6) (void);
-  void (*padding7) (void);
-  void (*padding8) (void);
+  PnlBinClass parent;
+
+  gpointer _reserved1;
+  gpointer _reserved2;
+  gpointer _reserved3;
+  gpointer _reserved4;
+  gpointer _reserved5;
+  gpointer _reserved6;
+  gpointer _reserved7;
+  gpointer _reserved8;
 };
 
-GtkWidget   *pnl_dock_widget_new       (void);
-const gchar *pnl_dock_widget_get_title (PnlDockWidget *self);
-void         pnl_dock_widget_set_title (PnlDockWidget *self,
-                                        const gchar   *title);
+GtkWidget *pnl_dock_widget_new           (void);
+void       pnl_dock_widget_set_title     (PnlDockWidget *self,
+                                          const gchar   *title);
+void       pnl_dock_widget_set_icon_name (PnlDockWidget *self,
+                                          const gchar   *icon_name);
 
 G_END_DECLS
 
diff --git a/contrib/pnl/pnl-dock-window.c b/contrib/pnl/pnl-dock-window.c
index 4aa7d85..afaaefd 100644
--- a/contrib/pnl/pnl-dock-window.c
+++ b/contrib/pnl/pnl-dock-window.c
@@ -93,7 +93,7 @@ pnl_dock_window_class_init (PnlDockWindowClass *klass)
 
   g_object_class_override_property (object_class, PROP_MANAGER, "manager");
 
-  gtk_widget_class_set_css_name (widget_class, "dockwindow");
+  gtk_widget_class_set_css_name (widget_class, "pnldockwindow");
 }
 
 static void
diff --git a/contrib/pnl/pnl-dock-window.h b/contrib/pnl/pnl-dock-window.h
index b45fb2d..ae8ff43 100644
--- a/contrib/pnl/pnl-dock-window.h
+++ b/contrib/pnl/pnl-dock-window.h
@@ -30,6 +30,15 @@ G_BEGIN_DECLS
 struct _PnlDockWindowClass
 {
   GtkWindowClass parent;
+
+  gpointer _reserved1;
+  gpointer _reserved2;
+  gpointer _reserved3;
+  gpointer _reserved4;
+  gpointer _reserved5;
+  gpointer _reserved6;
+  gpointer _reserved7;
+  gpointer _reserved8;
 };
 
 GtkWidget *pnl_dock_window_new (void);
diff --git a/contrib/pnl/pnl-multi-paned.c b/contrib/pnl/pnl-multi-paned.c
index 0217136..7b0d5d2 100644
--- a/contrib/pnl/pnl-multi-paned.c
+++ b/contrib/pnl/pnl-multi-paned.c
@@ -17,7 +17,10 @@
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#define G_LOG_DOMAIN "pnl-multi-paned"
+
 #include "pnl-multi-paned.h"
+#include "pnl-util-private.h"
 
 #define HANDLE_WIDTH  10
 #define HANDLE_HEIGHT 10
@@ -573,6 +576,8 @@ pnl_multi_paned_get_preferred_height (GtkWidget *widget,
 {
   PnlMultiPaned *self = (PnlMultiPaned *)widget;
   PnlMultiPanedPrivate *priv = pnl_multi_paned_get_instance_private (self);
+  GtkStyleContext *style_context;
+  GtkBorder borders;
   guint i;
   gint real_min_height = 0;
   gint real_nat_height = 0;
@@ -614,6 +619,12 @@ pnl_multi_paned_get_preferred_height (GtkWidget *widget,
 
   *min_height = real_min_height;
   *nat_height = real_nat_height;
+
+  style_context = gtk_widget_get_style_context (widget);
+  pnl_gtk_style_context_get_borders (style_context, &borders);
+
+  *min_height += borders.top + borders.bottom;
+  *nat_height += borders.top + borders.bottom;
 }
 
 static void
@@ -675,6 +686,8 @@ pnl_multi_paned_get_preferred_height_for_width (GtkWidget *widget,
 {
   PnlMultiPaned *self = (PnlMultiPaned *)widget;
   PnlMultiPanedPrivate *priv = pnl_multi_paned_get_instance_private (self);
+  GtkStyleContext *style_context;
+  GtkBorder borders;
 
   g_assert (PNL_IS_MULTI_PANED (self));
   g_assert (min_height != NULL);
@@ -697,6 +710,12 @@ pnl_multi_paned_get_preferred_height_for_width (GtkWidget *widget,
       *min_height += handle_size;
       *nat_height += handle_size;
     }
+
+  style_context = gtk_widget_get_style_context (widget);
+  pnl_gtk_style_context_get_borders (style_context, &borders);
+
+  *min_height += borders.top + borders.bottom;
+  *nat_height += borders.top + borders.bottom;
 }
 
 static void
@@ -706,6 +725,8 @@ pnl_multi_paned_get_preferred_width (GtkWidget *widget,
 {
   PnlMultiPaned *self = (PnlMultiPaned *)widget;
   PnlMultiPanedPrivate *priv = pnl_multi_paned_get_instance_private (self);
+  GtkStyleContext *style_context;
+  GtkBorder borders;
   guint i;
   gint real_min_width = 0;
   gint real_nat_width = 0;
@@ -747,6 +768,12 @@ pnl_multi_paned_get_preferred_width (GtkWidget *widget,
 
   *min_width = real_min_width;
   *nat_width = real_nat_width;
+
+  style_context = gtk_widget_get_style_context (widget);
+  pnl_gtk_style_context_get_borders (style_context, &borders);
+
+  *min_width += borders.left + borders.right;
+  *nat_width += borders.left + borders.right;
 }
 
 static void
@@ -808,6 +835,8 @@ pnl_multi_paned_get_preferred_width_for_height (GtkWidget *widget,
 {
   PnlMultiPaned *self = (PnlMultiPaned *)widget;
   PnlMultiPanedPrivate *priv = pnl_multi_paned_get_instance_private (self);
+  GtkStyleContext *style_context;
+  GtkBorder borders;
 
   g_assert (PNL_IS_MULTI_PANED (self));
   g_assert (min_width != NULL);
@@ -827,6 +856,12 @@ pnl_multi_paned_get_preferred_width_for_height (GtkWidget *widget,
       *min_width += handle_size;
       *nat_width += handle_size;
     }
+
+  style_context = gtk_widget_get_style_context (widget);
+  pnl_gtk_style_context_get_borders (style_context, &borders);
+
+  *min_width += borders.left + borders.right;
+  *nat_width += borders.left + borders.right;
 }
 
 static void
@@ -958,19 +993,26 @@ static void
 allocation_stage_borders (PnlMultiPaned   *self,
                           AllocationState *state)
 {
-  gint border_width;
+  GtkStyleContext *style_context;
+  GtkBorder borders;
 
   g_assert (PNL_IS_MULTI_PANED (self));
   g_assert (state != NULL);
   g_assert (state->children != NULL);
   g_assert (state->n_children > 0);
 
-  border_width = gtk_container_get_border_width (GTK_CONTAINER (self));
+  /*
+   * This subtracts the border+padding from the allocation area so the
+   * children are guaranteed to fall within that area.
+   */
+
+  style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
+  pnl_gtk_style_context_get_borders (style_context, &borders);
 
-  state->top_alloc.x += border_width;
-  state->top_alloc.y += border_width;
-  state->top_alloc.width -= border_width * 2;
-  state->top_alloc.height -= border_width * 2;
+  state->top_alloc.x += borders.left;
+  state->top_alloc.y += borders.right;
+  state->top_alloc.width -= (borders.left + borders.right);
+  state->top_alloc.height -= (borders.top + borders.bottom);
 
   if (state->top_alloc.width < 0)
     state->top_alloc.width = 0;
@@ -1212,7 +1254,7 @@ allocation_stage_expand (PnlMultiPaned   *self,
     }
 
   if (n_expand == 0)
-    return;
+    goto fill_last;
 
   if (IS_HORIZONTAL (state->orientation))
     adjust = state->avail_width / n_expand;
@@ -1249,6 +1291,8 @@ allocation_stage_expand (PnlMultiPaned   *self,
         }
     }
 
+fill_last:
+
   if (IS_HORIZONTAL (state->orientation))
     {
       if (state->avail_width > 0)
@@ -1284,26 +1328,33 @@ allocation_stage_allocate (PnlMultiPaned   *self,
 
       gtk_widget_size_allocate (child->widget, &child->alloc);
 
-      if ((child->handle != NULL) && (state->n_children != (i + 1)))
+      if (child->handle != NULL)
         {
-          if (state->orientation == GTK_ORIENTATION_HORIZONTAL)
+          if (state->n_children != (i + 1))
             {
-              gdk_window_move_resize (child->handle,
-                                      child->alloc.x + child->alloc.width - (HANDLE_WIDTH / 2),
-                                      child->alloc.y,
-                                      HANDLE_WIDTH,
-                                      child->alloc.height);
+              if (state->orientation == GTK_ORIENTATION_HORIZONTAL)
+                {
+                  gdk_window_move_resize (child->handle,
+                                          child->alloc.x + child->alloc.width - (HANDLE_WIDTH / 2),
+                                          child->alloc.y,
+                                          HANDLE_WIDTH,
+                                          child->alloc.height);
+                }
+              else
+                {
+                  gdk_window_move_resize (child->handle,
+                                          child->alloc.x,
+                                          child->alloc.y + child->alloc.height - (HANDLE_HEIGHT / 2),
+                                          child->alloc.width,
+                                          HANDLE_HEIGHT);
+                }
+
+              gdk_window_show (child->handle);
             }
           else
             {
-              gdk_window_move_resize (child->handle,
-                                      child->alloc.x,
-                                      child->alloc.y + child->alloc.height - (HANDLE_HEIGHT / 2),
-                                      child->alloc.width,
-                                      HANDLE_HEIGHT);
+              gdk_window_hide (child->handle);
             }
-
-          gdk_window_show (child->handle);
         }
     }
 }
@@ -1451,55 +1502,88 @@ pnl_multi_paned_draw (GtkWidget *widget,
 {
   PnlMultiPaned *self = (PnlMultiPaned *)widget;
   PnlMultiPanedPrivate *priv = pnl_multi_paned_get_instance_private (self);
-  gboolean ret;
+  GtkStyleContext *style_context;
+  GtkAllocation alloc;
+  GtkBorder margin;
+  GtkBorder borders;
+  GtkStateFlags state;
+  gint handle_size = 1;
+  guint i;
 
   g_assert (PNL_IS_MULTI_PANED (self));
   g_assert (cr != NULL);
 
-  ret = GTK_WIDGET_CLASS (pnl_multi_paned_parent_class)->draw (widget, cr);
+  gtk_widget_get_allocation (widget, &alloc);
+
+  alloc.x = 0;
+  alloc.y = 0;
+
+  style_context = gtk_widget_get_style_context (widget);
+  state = gtk_style_context_get_state (style_context);
+
+  pnl_gtk_style_context_get_borders (style_context, &borders);
+
+  gtk_style_context_get_margin (style_context, state, &margin);
+  pnl_gtk_allocation_subtract_border (&alloc, &margin);
 
-  if (ret != GDK_EVENT_STOP)
+  gtk_render_background (style_context, cr, alloc.x, alloc.y, alloc.width, alloc.height);
+
+  gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
+
+  for (i = 0; i < priv->children->len; i++)
     {
-      GtkStyleContext *style_context;
-      gint handle_size = 1;
-      guint i;
+      PnlMultiPanedChild *child = &g_array_index (priv->children, PnlMultiPanedChild, i);
 
-      style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
+      if (!gtk_widget_get_realized (child->widget) ||
+          !gtk_widget_get_visible (child->widget))
+        continue;
 
-      gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
+      gtk_container_propagate_draw (GTK_CONTAINER (self), child->widget, cr);
+    }
+
+  if (priv->children->len > 0)
+    {
+      gtk_style_context_save (style_context);
+      gtk_style_context_add_class (style_context, "handle");
 
       for (i = 0; i < priv->children->len; i++)
         {
           PnlMultiPanedChild *child = &g_array_index (priv->children, PnlMultiPanedChild, i);
-          GtkAllocation alloc;
+          GtkAllocation child_alloc;
 
-          if (!gtk_widget_get_realized (child->widget) ||
-              !gtk_widget_get_visible (child->widget))
+          if (!gtk_widget_get_visible (child->widget) ||
+              !gtk_widget_get_child_visible (child->widget))
             continue;
 
-          gtk_widget_get_allocation (child->widget, &alloc);
+          if (pnl_multi_paned_is_last_visible_child (self, child))
+            break;
+
+          gtk_widget_get_allocation (child->widget, &child_alloc);
+          gtk_widget_translate_coordinates (child->widget, widget, 0, 0, &child_alloc.x, &child_alloc.y);
+
+          if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+            gtk_render_handle (style_context,
+                               cr,
+                               child_alloc.x + child_alloc.width,
+                               borders.top,
+                               handle_size,
+                               child_alloc.height);
+          else
+            gtk_render_handle (style_context,
+                               cr,
+                               borders.left,
+                               child_alloc.y + child_alloc.height,
+                               child_alloc.width,
+                               handle_size);
 
-          if (!pnl_multi_paned_is_last_visible_child (self, child))
-            {
-              if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
-                gtk_render_handle (style_context,
-                                   cr,
-                                   alloc.x + alloc.width,
-                                   0,
-                                   handle_size,
-                                   alloc.height);
-              else
-                gtk_render_handle (style_context,
-                                   cr,
-                                   0,
-                                   alloc.y + alloc.height,
-                                   alloc.width,
-                                   handle_size);
-            }
         }
+
+      gtk_style_context_restore (style_context);
     }
 
-  return ret;
+  gtk_render_frame (style_context, cr, alloc.x, alloc.y, alloc.width, alloc.height);
+
+  return FALSE;
 }
 
 static void
@@ -1834,7 +1918,7 @@ pnl_multi_paned_class_init (PnlMultiPanedClass *klass)
   klass->resize_drag_begin = pnl_multi_paned_resize_drag_begin;
   klass->resize_drag_end = pnl_multi_paned_resize_drag_end;
 
-  gtk_widget_class_set_css_name (widget_class, "multipaned");
+  gtk_widget_class_set_css_name (widget_class, "pnlmultipaned");
 
   properties [PROP_ORIENTATION] =
     g_param_spec_enum ("orientation",
diff --git a/contrib/pnl/pnl-multi-paned.h b/contrib/pnl/pnl-multi-paned.h
index 2dae9cd..9b6854c 100644
--- a/contrib/pnl/pnl-multi-paned.h
+++ b/contrib/pnl/pnl-multi-paned.h
@@ -41,14 +41,14 @@ struct _PnlMultiPanedClass
   void (*resize_drag_end)   (PnlMultiPaned *self,
                              GtkWidget     *child);
 
-  void (*padding1) (void);
-  void (*padding2) (void);
-  void (*padding3) (void);
-  void (*padding4) (void);
-  void (*padding5) (void);
-  void (*padding6) (void);
-  void (*padding7) (void);
-  void (*padding8) (void);
+  gpointer _reserved1;
+  gpointer _reserved2;
+  gpointer _reserved3;
+  gpointer _reserved4;
+  gpointer _reserved5;
+  gpointer _reserved6;
+  gpointer _reserved7;
+  gpointer _reserved8;
 };
 
 GtkWidget *pnl_multi_paned_new            (void);
diff --git a/contrib/pnl/pnl-dock-tab-strip.h b/contrib/pnl/pnl-tab-private.h
similarity index 62%
rename from contrib/pnl/pnl-dock-tab-strip.h
rename to contrib/pnl/pnl-tab-private.h
index 6cf04d6..bbca3b5 100644
--- a/contrib/pnl/pnl-dock-tab-strip.h
+++ b/contrib/pnl/pnl-tab-private.h
@@ -1,6 +1,6 @@
-/* pnl-dock-tab-strip.h
+/* pnl-tab-private.h
  *
- * Copyright (C) 2016 Christian Hergert <christian hergert me>
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,19 +16,15 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef PNL_DOCK_TAB_STRIP_H
-#define PNL_DOCK_TAB_STRIP_H
+#ifndef PNL_TAB_PRIVATE_H
+#define PNL_TAB_PRIVATE_H
 
-#include "pnl-tab-strip.h"
+#include "pnl-tab.h"
 
 G_BEGIN_DECLS
 
-#define PNL_TYPE_DOCK_TAB_STRIP (pnl_dock_tab_strip_get_type())
-
-G_DECLARE_FINAL_TYPE (PnlDockTabStrip, pnl_dock_tab_strip, PNL, DOCK_TAB_STRIP, PnlTabStrip)
-
-GtkWidget *pnl_dock_tab_strip_new (void);
+void _pnl_tab_update_controls (PnlTab *self);
 
 G_END_DECLS
 
-#endif /* PNL_DOCK_TAB_STRIP_H */
+#endif /* PNL_TAB_PRIVATE_H */
diff --git a/contrib/pnl/pnl-tab-strip.c b/contrib/pnl/pnl-tab-strip.c
index e50b1c4..d78d9b9 100644
--- a/contrib/pnl/pnl-tab-strip.c
+++ b/contrib/pnl/pnl-tab-strip.c
@@ -17,6 +17,10 @@
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#define G_LOG_DOMAIN "pnl-tab-strip"
+
+#include "pnl-dock-item.h"
+#include "pnl-dock-widget.h"
 #include "pnl-tab.h"
 #include "pnl-tab-strip.h"
 
@@ -25,14 +29,20 @@ typedef struct
   GAction         *action;
   GtkStack        *stack;
   GtkPositionType  edge : 2;
+  PnlTabStyle      style : 2;
 } PnlTabStripPrivate;
 
-G_DEFINE_TYPE_WITH_PRIVATE (PnlTabStrip, pnl_tab_strip, GTK_TYPE_BOX)
+static void buildable_iface_init (GtkBuildableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (PnlTabStrip, pnl_tab_strip, GTK_TYPE_BOX,
+                         G_ADD_PRIVATE (PnlTabStrip)
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, buildable_iface_init))
 
 enum {
   PROP_0,
   PROP_EDGE,
   PROP_STACK,
+  PROP_STYLE,
   N_PROPS
 };
 
@@ -73,7 +83,7 @@ set_tab_state (GSimpleAction *action,
        * manually setting the state.
        */
       if (PNL_IS_TAB (tab))
-        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (tab), TRUE);
+        pnl_tab_set_active (PNL_TAB (tab), TRUE);
     }
 }
 
@@ -90,8 +100,11 @@ pnl_tab_strip_update_action_targets (PnlTabStrip *self)
 
   for (i = 0, iter = list; iter != NULL; iter = iter->next, i++)
     {
-      PnlTab *tab = iter->data;
-      gtk_actionable_set_action_target (GTK_ACTIONABLE (tab), "i", i);
+      GtkWidget *widget = iter->data;
+
+      /* Ignore controls, and just update tabs */
+      if (PNL_IS_TAB (widget))
+        gtk_actionable_set_action_target (GTK_ACTIONABLE (widget), "i", i);
     }
 
   g_list_free (list);
@@ -165,6 +178,10 @@ pnl_tab_strip_get_property (GObject    *object,
       g_value_set_object (value, pnl_tab_strip_get_stack (self));
       break;
 
+    case PROP_STYLE:
+      g_value_set_flags (value, pnl_tab_strip_get_style (self));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -188,6 +205,10 @@ pnl_tab_strip_set_property (GObject      *object,
       pnl_tab_strip_set_stack (self, g_value_get_object (value));
       break;
 
+    case PROP_STYLE:
+      pnl_tab_strip_set_style (self, g_value_get_flags (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -216,6 +237,14 @@ pnl_tab_strip_class_init (PnlTabStripClass *klass)
                        GTK_POS_TOP,
                        (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
 
+  properties [PROP_STYLE] =
+    g_param_spec_flags ("style",
+                        "Style",
+                        "The tab style",
+                        PNL_TYPE_TAB_STYLE,
+                        PNL_TAB_BOTH,
+                        (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
   properties [PROP_STACK] =
     g_param_spec_object ("stack",
                          "Stack",
@@ -225,7 +254,7 @@ pnl_tab_strip_class_init (PnlTabStripClass *klass)
 
   g_object_class_install_properties (object_class, N_PROPS, properties);
 
-  gtk_widget_class_set_css_name (widget_class, "docktabstrip");
+  gtk_widget_class_set_css_name (widget_class, "pnltabstrip");
 }
 
 static void
@@ -237,6 +266,8 @@ pnl_tab_strip_init (PnlTabStrip *self)
     { "tab", NULL, "i", "0", set_tab_state },
   };
 
+  priv->style = PNL_TAB_BOTH;
+
   gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_HORIZONTAL);
 
   group = g_simple_action_group_new ();
@@ -299,7 +330,7 @@ pnl_tab_strip_child_title_changed (PnlTabStrip *self,
                                    GParamSpec  *pspec,
                                    GtkWidget   *child)
 {
-  g_autofree gchar *title = NULL;
+  gchar *title = NULL;
   GtkWidget *parent;
   PnlTab *tab;
 
@@ -320,6 +351,38 @@ pnl_tab_strip_child_title_changed (PnlTabStrip *self,
                            NULL);
 
   pnl_tab_set_title (tab, title);
+
+  g_free (title);
+}
+
+static void
+pnl_tab_strip_child_icon_name_changed (PnlTabStrip *self,
+                                       GParamSpec  *pspec,
+                                       GtkWidget   *child)
+{
+  gchar *icon_name = NULL;
+  GtkWidget *parent;
+  PnlTab *tab;
+
+  g_assert (PNL_IS_TAB_STRIP (self));
+  g_assert (GTK_IS_WIDGET (child));
+
+  tab = g_object_get_data (G_OBJECT (child), "PNL_TAB");
+
+  if (!PNL_IS_TAB (tab))
+    return;
+
+  parent = gtk_widget_get_parent (child);
+
+  g_assert (GTK_IS_STACK (parent));
+
+  gtk_container_child_get (GTK_CONTAINER (parent), child,
+                           "icon-name", &icon_name,
+                           NULL);
+
+  pnl_tab_set_icon_name (tab, icon_name);
+
+  g_free (icon_name);
 }
 
 static void
@@ -339,7 +402,7 @@ pnl_tab_strip_stack_notify_visible_child (PnlTabStrip *self,
       PnlTab *tab = g_object_get_data (G_OBJECT (visible), "PNL_TAB");
 
       if (PNL_IS_TAB (tab))
-        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (tab), TRUE);
+        pnl_tab_set_active (PNL_TAB (tab), TRUE);
     }
 }
 
@@ -354,7 +417,7 @@ pnl_tab_strip_tab_clicked (PnlTabStrip *self,
 
   if (NULL != (widget = pnl_tab_get_widget (tab)))
     {
-      if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (tab)))
+      if (pnl_tab_get_active (tab))
         gtk_widget_grab_focus (widget);
     }
 }
@@ -367,15 +430,21 @@ pnl_tab_strip_stack_add (PnlTabStrip *self,
   PnlTabStripPrivate *priv = pnl_tab_strip_get_instance_private (self);
   g_autoptr(GVariant) target = g_variant_ref_sink (g_variant_new_int32 (0));
   PnlTab *tab;
+  gboolean can_close = FALSE;
 
   g_assert (PNL_IS_TAB_STRIP (self));
   g_assert (GTK_IS_WIDGET (widget));
   g_assert (GTK_IS_STACK (stack));
 
+  if (PNL_IS_DOCK_ITEM (widget))
+    can_close = pnl_dock_item_get_can_close (PNL_DOCK_ITEM (widget));
+
   tab = g_object_new (PNL_TYPE_TAB,
                       "action-name", "tab-strip.tab",
                       "action-target", target,
+                      "can-close", can_close,
                       "edge", priv->edge,
+                      "style", priv->style,
                       "widget", widget,
                       NULL);
 
@@ -399,11 +468,25 @@ pnl_tab_strip_stack_add (PnlTabStrip *self,
                            self,
                            G_CONNECT_SWAPPED);
 
-  gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (tab));
+  g_signal_connect_object (widget,
+                           "child-notify::icon-name",
+                           G_CALLBACK (pnl_tab_strip_child_icon_name_changed),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  gtk_container_add_with_properties (GTK_CONTAINER (self), GTK_WIDGET (tab),
+                                     "pack-type", GTK_PACK_START,
+                                     "expand", TRUE,
+                                     "fill", TRUE,
+                                     NULL);
 
   g_object_bind_property (widget, "visible", tab, "visible", G_BINDING_SYNC_CREATE);
 
+  if (PNL_IS_DOCK_WIDGET (widget))
+    g_object_bind_property (widget, "can-close", tab, "can-close", 0);
+
   pnl_tab_strip_child_title_changed (self, NULL, widget);
+  pnl_tab_strip_child_icon_name_changed (self, NULL, widget);
   pnl_tab_strip_stack_notify_visible_child (self, NULL, stack);
 }
 
@@ -565,10 +648,10 @@ pnl_tab_strip_set_edge (PnlTabStrip     *self,
 
       style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
 
-      gtk_style_context_remove_class (style_context, "left-edge");
-      gtk_style_context_remove_class (style_context, "top-edge");
-      gtk_style_context_remove_class (style_context, "right-edge");
-      gtk_style_context_remove_class (style_context, "bottom-edge");
+      gtk_style_context_remove_class (style_context, "left");
+      gtk_style_context_remove_class (style_context, "top");
+      gtk_style_context_remove_class (style_context, "right");
+      gtk_style_context_remove_class (style_context, "bottom");
 
       switch (edge)
         {
@@ -597,3 +680,82 @@ pnl_tab_strip_set_edge (PnlTabStrip     *self,
       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_EDGE]);
     }
 }
+
+static void
+apply_style (GtkWidget *widget,
+             gpointer   user_data)
+{
+  PnlTabStyle style = GPOINTER_TO_UINT (user_data);
+
+  g_assert (GTK_IS_WIDGET (widget));
+
+  if (PNL_IS_TAB (widget))
+    pnl_tab_set_style (PNL_TAB (widget), style);
+}
+
+guint
+pnl_tab_strip_get_style (PnlTabStrip *self)
+{
+  PnlTabStripPrivate *priv = pnl_tab_strip_get_instance_private (self);
+
+  g_return_val_if_fail (PNL_IS_TAB_STRIP (self), 0);
+
+  return priv->style;
+}
+
+void
+pnl_tab_strip_set_style (PnlTabStrip *self,
+                         PnlTabStyle  style)
+{
+  PnlTabStripPrivate *priv = pnl_tab_strip_get_instance_private (self);
+
+  g_return_if_fail (PNL_IS_TAB_STRIP (self));
+
+  if (style != priv->style)
+    {
+      priv->style = style;
+      gtk_container_foreach (GTK_CONTAINER (self), apply_style, GUINT_TO_POINTER (style));
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_STYLE]);
+    }
+}
+
+void
+pnl_tab_strip_add_control (PnlTabStrip *self,
+                           GtkWidget   *widget)
+{
+  g_return_if_fail (PNL_IS_TAB_STRIP (self));
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+
+  gtk_container_add_with_properties (GTK_CONTAINER (self), widget,
+                                     "pack-type", GTK_PACK_END,
+                                     "expand", FALSE,
+                                     "fill", FALSE,
+                                     NULL);
+
+  gtk_style_context_add_class (gtk_widget_get_style_context (widget), "control");
+}
+
+static void
+pnl_tab_strip_add_child (GtkBuildable *buildable,
+                         GtkBuilder   *builder,
+                         GObject      *child,
+                         const gchar  *child_type)
+{
+  PnlTabStrip *self = (PnlTabStrip *)buildable;
+
+  g_assert (PNL_IS_TAB_STRIP (self));
+  g_assert (GTK_IS_BUILDER (builder));
+  g_assert (G_IS_OBJECT (child));
+
+  if (g_strcmp0 (child_type, "control") == 0 && GTK_IS_WIDGET (child))
+    pnl_tab_strip_add_control (self, GTK_WIDGET (child));
+  else
+    g_warning ("I do not know how to add %s of type %s",
+               G_OBJECT_TYPE_NAME (child), child_type ? child_type : "NULL");
+}
+
+static void
+buildable_iface_init (GtkBuildableIface *iface)
+{
+  iface->add_child = pnl_tab_strip_add_child;
+}
diff --git a/contrib/pnl/pnl-tab-strip.h b/contrib/pnl/pnl-tab-strip.h
index 1aba919..81b1138 100644
--- a/contrib/pnl/pnl-tab-strip.h
+++ b/contrib/pnl/pnl-tab-strip.h
@@ -24,17 +24,22 @@
 #ifndef PNL_TAB_STRIP_H
 #define PNL_TAB_STRIP_H
 
-#include <gtk/gtk.h>
+#include "pnl-dock-types.h"
 
 G_BEGIN_DECLS
 
-#define PNL_TYPE_TAB_STRIP (pnl_tab_strip_get_type())
-
-G_DECLARE_DERIVABLE_TYPE (PnlTabStrip, pnl_tab_strip, PNL, TAB_STRIP, GtkBox)
-
 struct _PnlTabStripClass
 {
   GtkBoxClass parent;
+
+  gpointer _reserved1;
+  gpointer _reserved2;
+  gpointer _reserved3;
+  gpointer _reserved4;
+  gpointer _reserved5;
+  gpointer _reserved6;
+  gpointer _reserved7;
+  gpointer _reserved8;
 };
 
 GtkWidget       *pnl_tab_strip_new             (void);
@@ -47,6 +52,11 @@ void             pnl_tab_strip_set_edge        (PnlTabStrip     *self,
 gboolean         pnl_tab_strip_get_show_labels (PnlTabStrip     *self);
 void             pnl_tab_strip_set_show_labels (PnlTabStrip     *self,
                                                 gboolean         show_labels);
+PnlTabStyle      pnl_tab_strip_get_style       (PnlTabStrip     *self);
+void             pnl_tab_strip_set_style       (PnlTabStrip     *self,
+                                                PnlTabStyle      style);
+void             pnl_tab_strip_add_control     (PnlTabStrip     *self,
+                                                GtkWidget       *widget);
 
 G_END_DECLS
 
diff --git a/contrib/pnl/pnl-tab.c b/contrib/pnl/pnl-tab.c
index 5199cf0..0b1c3a4 100644
--- a/contrib/pnl/pnl-tab.c
+++ b/contrib/pnl/pnl-tab.c
@@ -19,35 +19,187 @@
 
 #define G_LOG_DOMAIN "pnl-tab"
 
+#include "pnl-dock-item.h"
 #include "pnl-tab.h"
+#include "pnl-tab-private.h"
 #include "pnl-util-private.h"
 
-struct _PnlTab
+struct _PnlTab { GtkEventBox parent; };
+
+typedef struct
 {
-  GtkToggleButton  parent;
-  GtkPositionType  edge : 2;
-  GtkLabel        *title;
-  GtkWidget       *widget;
-};
+  /*
+   * The edge the tab is being displayed upon. We use this to rotate
+   * text or alter box orientation.
+   */
+  GtkPositionType edge : 2;
+
+  /* Can we be closed by the user */
+  guint can_close : 1;
+
+  /* Are we the active tab */
+  guint active : 1;
+
+  /* If we are currently pressed */
+  guint pressed : 1;
+
+  /* If the pointer is over the widget (prelight) */
+  guint pointer_in_widget : 1;
+
+  /* If we are currently activating */
+  guint in_activate : 1;
+
+  /* Our icon/text style */
+  PnlTabStyle style : 2;
+
+  /* The action name to change the current tab */
+  gchar *action_name;
+
+  /* The value for the current tab */
+  GVariant *action_target_value;
+
+  /*
+   * Because we don't have access to GtkActionMuxer or GtkActionHelper
+   * from inside of Gtk, we need to manually track the state of the
+   * action we are monitoring.
+   *
+   * We hold a pointer to the group so we can disconnect as necessary.
+   */
+  GActionGroup *action_group;
+  gulong action_state_changed_handler;
 
-G_DEFINE_TYPE (PnlTab, pnl_tab, GTK_TYPE_TOGGLE_BUTTON)
+  /*
+   * These are our control widgets. The box contains the title in the
+   * center with the minimize/close buttons to a side, depending on the
+   * orientation/edge of the tabs.
+   */
+  GtkBox *box;
+  GtkImage *image;
+  GtkLabel *title;
+  GtkWidget *close;
+  GtkWidget *minimize;
+
+  /*
+   * This is a weak pointer to the widget this tab represents.
+   * It's used by the stack to translate between the tab/widget
+   * as necessary.
+   */
+  GtkWidget *widget;
+} PnlTabPrivate;
+
+static void actionable_iface_init (GtkActionableInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (PnlTab, pnl_tab, PNL_TYPE_BIN,
+                         G_ADD_PRIVATE (PnlTab)
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIONABLE, actionable_iface_init))
 
 enum {
   PROP_0,
+  PROP_ACTIVE,
+  PROP_CAN_CLOSE,
   PROP_EDGE,
+  PROP_STYLE,
   PROP_TITLE,
   PROP_WIDGET,
-  N_PROPS
+  N_PROPS,
+
+  PROP_ACTION_NAME,
+  PROP_ACTION_TARGET,
+};
+
+enum {
+  CLICKED,
+  N_SIGNALS
 };
 
 static GParamSpec *properties [N_PROPS];
+static guint signals [N_SIGNALS];
+
+static void
+pnl_tab_get_inner_allocation (PnlTab        *self,
+                              GtkAllocation *alloc)
+{
+  GtkBorder margin;
+  GtkBorder border;
+  GtkStyleContext *style_context;
+  GtkStateFlags flags;
+
+  g_assert (PNL_IS_TAB (self));
+  g_assert (alloc != NULL);
+
+  gtk_widget_get_allocation (GTK_WIDGET (self), alloc);
+
+  style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
+  flags = gtk_widget_get_state_flags (GTK_WIDGET (self));
+
+  gtk_style_context_get_border (style_context, flags, &margin);
+  gtk_style_context_get_border (style_context, flags, &border);
+
+  alloc->x += border.left;
+  alloc->x += margin.left;
+
+  alloc->y += border.top;
+  alloc->y += margin.top;
+
+  alloc->width -= (border.right + border.left);
+  alloc->width -= (margin.right + margin.left);
+
+  alloc->height -= (border.bottom + border.top);
+  alloc->height -= (margin.bottom + margin.top);
+}
+
+static void
+pnl_tab_apply_state (PnlTab *self)
+{
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
+  g_assert (PNL_IS_TAB (self));
+
+  if (priv->active)
+    gtk_widget_set_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_CHECKED, FALSE);
+  else
+    gtk_widget_unset_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_CHECKED);
+}
+
+static void
+pnl_tab_activate (PnlTab *self)
+{
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+  g_autoptr(GVariant) value = NULL;
+
+  g_assert (PNL_IS_TAB (self));
+
+  if (priv->in_activate ||
+      priv->action_name == NULL ||
+      priv->action_target_value == NULL)
+    return;
+
+  priv->in_activate = TRUE;
+
+  value = pnl_gtk_widget_get_action_state (GTK_WIDGET (self), priv->action_name);
+  if (value != NULL && !g_variant_equal (value, priv->action_target_value))
+    pnl_gtk_widget_activate_action (GTK_WIDGET (self), priv->action_name, priv->action_target_value);
+
+  priv->in_activate = FALSE;
+}
 
 static void
 pnl_tab_destroy (GtkWidget *widget)
 {
   PnlTab *self = (PnlTab *)widget;
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
 
-  pnl_clear_weak_pointer (&self->widget);
+  if (priv->action_group != NULL)
+    {
+      g_signal_handler_disconnect (priv->action_group,
+                                   priv->action_state_changed_handler);
+      priv->action_state_changed_handler = 0;
+      pnl_clear_weak_pointer (&priv->action_group);
+    }
+
+  pnl_clear_weak_pointer (&priv->widget);
+  g_clear_pointer (&priv->action_name, g_free);
+  g_clear_pointer (&priv->action_target_value, g_variant_unref);
 
   GTK_WIDGET_CLASS (pnl_tab_parent_class)->destroy (widget);
 }
@@ -55,30 +207,44 @@ pnl_tab_destroy (GtkWidget *widget)
 static void
 pnl_tab_update_edge (PnlTab *self)
 {
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
   g_assert (PNL_IS_TAB (self));
 
-  switch (self->edge)
+  switch (priv->edge)
     {
     case GTK_POS_TOP:
-      gtk_label_set_angle (self->title, 0.0);
+      gtk_label_set_angle (priv->title, 0.0);
+      gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->box), GTK_ORIENTATION_HORIZONTAL);
+      gtk_box_set_child_packing (priv->box, GTK_WIDGET (priv->close), FALSE, FALSE, 0, GTK_PACK_END);
+      gtk_box_set_child_packing (priv->box, GTK_WIDGET (priv->minimize), FALSE, FALSE, 0, GTK_PACK_END);
       gtk_widget_set_hexpand (GTK_WIDGET (self), TRUE);
       gtk_widget_set_vexpand (GTK_WIDGET (self), FALSE);
       break;
 
     case GTK_POS_BOTTOM:
-      gtk_label_set_angle (self->title, 0.0);
+      gtk_label_set_angle (priv->title, 0.0);
+      gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->box), GTK_ORIENTATION_HORIZONTAL);
+      gtk_box_set_child_packing (priv->box, GTK_WIDGET (priv->close), FALSE, FALSE, 0, GTK_PACK_END);
+      gtk_box_set_child_packing (priv->box, GTK_WIDGET (priv->minimize), FALSE, FALSE, 0, GTK_PACK_END);
       gtk_widget_set_hexpand (GTK_WIDGET (self), TRUE);
       gtk_widget_set_vexpand (GTK_WIDGET (self), FALSE);
       break;
 
     case GTK_POS_LEFT:
-      gtk_label_set_angle (self->title, -90.0);
+      gtk_label_set_angle (priv->title, -90.0);
+      gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->box), GTK_ORIENTATION_VERTICAL);
+      gtk_box_set_child_packing (priv->box, GTK_WIDGET (priv->close), FALSE, FALSE, 0, GTK_PACK_END);
+      gtk_box_set_child_packing (priv->box, GTK_WIDGET (priv->minimize), FALSE, FALSE, 0, GTK_PACK_END);
       gtk_widget_set_hexpand (GTK_WIDGET (self), FALSE);
       gtk_widget_set_vexpand (GTK_WIDGET (self), TRUE);
       break;
 
     case GTK_POS_RIGHT:
-      gtk_label_set_angle (self->title, 90.0);
+      gtk_label_set_angle (priv->title, 90.0);
+      gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->box), GTK_ORIENTATION_VERTICAL);
+      gtk_box_set_child_packing (priv->box, GTK_WIDGET (priv->close), FALSE, FALSE, 0, GTK_PACK_START);
+      gtk_box_set_child_packing (priv->box, GTK_WIDGET (priv->minimize), FALSE, FALSE, 0, GTK_PACK_START);
       gtk_widget_set_hexpand (GTK_WIDGET (self), FALSE);
       gtk_widget_set_vexpand (GTK_WIDGET (self), TRUE);
       break;
@@ -88,6 +254,356 @@ pnl_tab_update_edge (PnlTab *self)
     }
 }
 
+static gboolean
+get_widget_coordinates (GtkWidget *widget,
+                        GdkEvent  *event,
+                        gdouble   *x,
+                        gdouble   *y)
+{
+  GdkWindow *window = ((GdkEventAny *)event)->window;
+  GdkWindow *target = gtk_widget_get_window (widget);
+  gdouble tx, ty;
+
+  if (!gdk_event_get_coords (event, &tx, &ty))
+    return FALSE;
+
+  while (window && window != target)
+    {
+      gint window_x, window_y;
+
+      gdk_window_get_position (window, &window_x, &window_y);
+      tx += window_x;
+      ty += window_y;
+
+      window = gdk_window_get_parent (window);
+    }
+
+  if (window)
+    {
+      *x = tx;
+      *y = ty;
+
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static void
+pnl_tab_update_prelight (PnlTab   *self,
+                         GdkEvent *event)
+{
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+  gdouble x, y;
+
+  g_assert (PNL_IS_TAB (self));
+  g_assert (event != NULL);
+
+  if (get_widget_coordinates (GTK_WIDGET (self), (GdkEvent *)event, &x, &y))
+    {
+      GtkAllocation alloc;
+
+      pnl_tab_get_inner_allocation (self, &alloc);
+
+      /*
+       * We've translated our x,y coords to be relative to the widget, so we
+       * can discard the x,y of the allocation.
+       */
+      alloc.x = 0;
+      alloc.y = 0;
+
+      if (x >= alloc.x &&
+          x <= (alloc.x + alloc.width) &&
+          y >= alloc.y &&
+          y <= (alloc.y + alloc.height))
+        {
+          priv->pointer_in_widget = TRUE;
+          gtk_widget_set_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_PRELIGHT, FALSE);
+          return;
+        }
+    }
+
+  priv->pointer_in_widget = FALSE;
+  gtk_widget_unset_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_PRELIGHT);
+}
+
+static gboolean
+pnl_tab_motion_notify_event (GtkWidget      *widget,
+                             GdkEventMotion *event)
+{
+  PnlTab *self = (PnlTab *)widget;
+
+  g_assert (PNL_IS_TAB (self));
+  g_assert (event != NULL);
+
+  pnl_tab_update_prelight (self, (GdkEvent *)event);
+
+  return GDK_EVENT_PROPAGATE;
+}
+
+static gboolean
+pnl_tab_enter_notify_event (GtkWidget        *widget,
+                            GdkEventCrossing *event)
+{
+  PnlTab *self = (PnlTab *)widget;
+
+  g_assert (PNL_IS_TAB (self));
+  g_assert (event != NULL);
+
+  pnl_tab_update_prelight (self, (GdkEvent *)event);
+
+  return GDK_EVENT_PROPAGATE;
+}
+
+static gboolean
+pnl_tab_leave_notify_event (GtkWidget        *widget,
+                            GdkEventCrossing *event)
+{
+  PnlTab *self = (PnlTab *)widget;
+
+  g_return_val_if_fail (PNL_IS_TAB (self), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  pnl_tab_update_prelight (self, (GdkEvent *)event);
+
+  return GDK_EVENT_PROPAGATE;
+}
+
+static gboolean
+pnl_tab_button_press_event (GtkWidget      *widget,
+                            GdkEventButton *event)
+{
+  PnlTab *self = (PnlTab *)widget;
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
+  g_return_val_if_fail (PNL_IS_TAB (self), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  if (event->button == GDK_BUTTON_PRIMARY)
+    {
+      priv->pressed = TRUE;
+      gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_ACTIVE, FALSE);
+      gtk_widget_grab_focus (GTK_WIDGET (self));
+      return GDK_EVENT_STOP;
+    }
+
+  return GDK_EVENT_PROPAGATE;
+}
+
+static gboolean
+pnl_tab_button_release_event (GtkWidget      *widget,
+                              GdkEventButton *event)
+{
+  PnlTab *self = (PnlTab *)widget;
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
+  g_return_val_if_fail (PNL_IS_TAB (self), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  if (event->button == GDK_BUTTON_PRIMARY)
+    {
+      priv->pressed = FALSE;
+      gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_ACTIVE);
+
+      if (priv->pointer_in_widget)
+        g_signal_emit (self, signals [CLICKED], 0);
+
+      return GDK_EVENT_STOP;
+    }
+
+  return GDK_EVENT_PROPAGATE;
+}
+
+static void
+pnl_tab_realize (GtkWidget *widget)
+{
+  PnlTab *self = (PnlTab *)widget;
+  GdkWindowAttr attributes = { 0 };
+  GdkWindow *parent;
+  GdkWindow *window;
+  GtkAllocation alloc;
+  gint attributes_mask = 0;
+
+  g_assert (PNL_IS_TAB (widget));
+
+  gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
+
+  gtk_widget_set_realized (GTK_WIDGET (self), TRUE);
+
+  parent = gtk_widget_get_parent_window (GTK_WIDGET (self));
+
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.x = alloc.x;
+  attributes.y = alloc.y;
+  attributes.width = alloc.width;
+  attributes.height = alloc.height;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.event_mask = gtk_widget_get_events (widget);
+  attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
+                            GDK_BUTTON_RELEASE_MASK |
+                            GDK_TOUCH_MASK |
+                            GDK_EXPOSURE_MASK |
+                            GDK_ENTER_NOTIFY_MASK |
+                            GDK_LEAVE_NOTIFY_MASK);
+
+  attributes_mask = (GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL);
+
+  window = gdk_window_new (parent, &attributes, attributes_mask);
+  gtk_widget_register_window (GTK_WIDGET (self), window);
+  gtk_widget_set_window (GTK_WIDGET (self), window);
+}
+
+static void
+pnl_tab_action_state_changed (PnlTab       *self,
+                              const gchar  *action_name,
+                              GVariant     *value,
+                              GActionGroup *group)
+{
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+  gboolean active;
+
+  g_assert (PNL_IS_TAB (self));
+  g_assert (action_name != NULL);
+  g_assert (G_IS_ACTION_GROUP (group));
+
+  active = (value != NULL &&
+            priv->action_target_value != NULL &&
+            g_variant_equal (value, priv->action_target_value));
+
+  if (active != priv->active)
+    {
+      priv->active = active;
+      pnl_tab_apply_state (self);
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIVE]);
+    }
+}
+
+static void
+pnl_tab_monitor_action_group (PnlTab       *self,
+                              GActionGroup *group)
+{
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
+  g_return_if_fail (PNL_IS_TAB (self));
+  g_return_if_fail (!group || G_IS_ACTION_GROUP (group));
+
+  if (group != priv->action_group)
+    {
+      if (priv->action_group != NULL)
+        {
+          g_signal_handler_disconnect (priv->action_group,
+                                       priv->action_state_changed_handler);
+          priv->action_state_changed_handler = 0;
+          pnl_clear_weak_pointer (&priv->action_group);
+        }
+
+      if (group != NULL)
+        {
+          gchar *prefix = NULL;
+          gchar *name = NULL;
+
+          pnl_g_action_name_parse (priv->action_name, &prefix, &name);
+
+          if (name != NULL)
+            {
+              gchar *detailed;
+
+              detailed = g_strdup_printf ("action-state-changed::%s", name);
+              pnl_set_weak_pointer (&priv->action_group, group);
+              priv->action_state_changed_handler =
+                g_signal_connect_object (priv->action_group,
+                                         detailed,
+                                         G_CALLBACK (pnl_tab_action_state_changed),
+                                         self,
+                                         G_CONNECT_SWAPPED);
+
+              g_free (detailed);
+            }
+
+          g_free (prefix);
+          g_free (name);
+        }
+    }
+}
+
+static void
+pnl_tab_hierarchy_changed (GtkWidget *widget,
+                           GtkWidget *old_toplevel)
+{
+  PnlTab *self = (PnlTab *)widget;
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+  GActionGroup *group;
+
+  g_assert (GTK_IS_WIDGET (widget));
+  g_assert (!old_toplevel || GTK_IS_WIDGET (old_toplevel));
+
+  group = pnl_gtk_widget_find_group_for_action (widget, priv->action_name);
+  pnl_tab_monitor_action_group (self, group);
+}
+
+static void
+pnl_tab_size_allocate (GtkWidget     *widget,
+                       GtkAllocation *allocation)
+{
+  g_assert (PNL_IS_TAB (widget));
+
+  GTK_WIDGET_CLASS (pnl_tab_parent_class)->size_allocate (widget, allocation);
+
+  if (gtk_widget_get_realized (widget))
+    gdk_window_move_resize (gtk_widget_get_window (widget),
+                            allocation->x,
+                            allocation->y,
+                            allocation->width,
+                            allocation->height);
+}
+
+static void
+pnl_tab_close_clicked (PnlTab    *self,
+                       GtkWidget *button)
+{
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
+  g_assert (PNL_IS_TAB (self));
+  g_assert (GTK_IS_BUTTON (button));
+
+  g_object_ref (self);
+
+  if (PNL_IS_DOCK_ITEM (priv->widget) &&
+      pnl_dock_item_get_can_close (PNL_DOCK_ITEM (priv->widget)))
+    pnl_dock_item_close (PNL_DOCK_ITEM (priv->widget));
+
+  g_object_unref (self);
+}
+
+static void
+pnl_tab_minimize_clicked (PnlTab    *self,
+                          GtkWidget *button)
+{
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+  GtkPositionType position = GTK_POS_LEFT;
+
+  g_assert (PNL_IS_TAB (self));
+  g_assert (GTK_IS_BUTTON (button));
+
+  g_object_ref (self);
+
+  if (PNL_IS_DOCK_ITEM (priv->widget))
+    {
+      PnlDockItem *item = PNL_DOCK_ITEM (priv->widget);
+
+      for (PnlDockItem *parent = pnl_dock_item_get_parent (item);
+           parent != NULL;
+           parent = pnl_dock_item_get_parent (parent))
+        {
+          if (pnl_dock_item_minimize (parent, item, &position))
+            break;
+        }
+    }
+
+  g_object_unref (self);
+}
+
 static void
 pnl_tab_get_property (GObject    *object,
                       guint       prop_id,
@@ -95,13 +611,34 @@ pnl_tab_get_property (GObject    *object,
                       GParamSpec *pspec)
 {
   PnlTab *self = PNL_TAB (object);
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
 
   switch (prop_id)
     {
+    case PROP_ACTIVE:
+      g_value_set_boolean (value, pnl_tab_get_active (self));
+      break;
+
+    case PROP_ACTION_NAME:
+      g_value_set_string (value, priv->action_name);
+      break;
+
+    case PROP_ACTION_TARGET:
+      g_value_set_boxed (value, priv->action_target_value);
+      break;
+
+    case PROP_CAN_CLOSE:
+      g_value_set_boolean (value, pnl_tab_get_can_close (self));
+      break;
+
     case PROP_EDGE:
       g_value_set_enum (value, pnl_tab_get_edge (self));
       break;
 
+    case PROP_STYLE:
+      g_value_set_flags (value, pnl_tab_get_style (self));
+      break;
+
     case PROP_TITLE:
       g_value_set_string (value, pnl_tab_get_title (self));
       break;
@@ -122,13 +659,38 @@ pnl_tab_set_property (GObject      *object,
                       GParamSpec   *pspec)
 {
   PnlTab *self = PNL_TAB (object);
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
 
   switch (prop_id)
     {
+    case PROP_ACTIVE:
+      pnl_tab_set_active (self, g_value_get_boolean (value));
+      break;
+
+    case PROP_ACTION_NAME:
+      g_free (priv->action_name);
+      priv->action_name = g_value_dup_string (value);
+      break;
+
+    case PROP_ACTION_TARGET:
+      g_clear_pointer (&priv->action_target_value, g_variant_unref);
+      priv->action_target_value = g_value_get_variant (value);
+      if (priv->action_target_value != NULL)
+        g_variant_ref_sink (priv->action_target_value);
+      break;
+
+    case PROP_CAN_CLOSE:
+      pnl_tab_set_can_close (self, g_value_get_boolean (value));
+      break;
+
     case PROP_EDGE:
       pnl_tab_set_edge (self, g_value_get_enum (value));
       break;
 
+    case PROP_STYLE:
+      pnl_tab_set_style (self, g_value_get_flags (value));
+      break;
+
     case PROP_TITLE:
       pnl_tab_set_title (self, g_value_get_string (value));
       break;
@@ -152,8 +714,33 @@ pnl_tab_class_init (PnlTabClass *klass)
   object_class->set_property = pnl_tab_set_property;
 
   widget_class->destroy = pnl_tab_destroy;
+  widget_class->button_press_event = pnl_tab_button_press_event;
+  widget_class->button_release_event = pnl_tab_button_release_event;
+  widget_class->motion_notify_event = pnl_tab_motion_notify_event;
+  widget_class->enter_notify_event = pnl_tab_enter_notify_event;
+  widget_class->leave_notify_event = pnl_tab_leave_notify_event;
+  widget_class->realize = pnl_tab_realize;
+  widget_class->size_allocate = pnl_tab_size_allocate;
+  widget_class->hierarchy_changed = pnl_tab_hierarchy_changed;
+
+  gtk_widget_class_set_css_name (widget_class, "pnltab");
+
+  g_object_class_override_property (object_class, PROP_ACTION_NAME, "action-name");
+  g_object_class_override_property (object_class, PROP_ACTION_TARGET, "action-target");
 
-  gtk_widget_class_set_css_name (widget_class, "docktab");
+  properties [PROP_ACTIVE] =
+    g_param_spec_boolean ("active",
+                          "Active",
+                          "If the tab is currently active",
+                          FALSE,
+                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_CAN_CLOSE] =
+    g_param_spec_boolean ("can-close",
+                          "Can Close",
+                          "If the tab widget can be closed",
+                          FALSE,
+                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
 
   properties [PROP_EDGE] =
     g_param_spec_enum ("edge",
@@ -163,6 +750,14 @@ pnl_tab_class_init (PnlTabClass *klass)
                        GTK_POS_TOP,
                        (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
 
+  properties [PROP_STYLE] =
+    g_param_spec_flags ("style",
+                        "Style",
+                        "The style for the tab",
+                        PNL_TYPE_TAB_STYLE,
+                        PNL_TAB_BOTH,
+                        (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
   properties [PROP_TITLE] =
     g_param_spec_string ("title",
                          "Title",
@@ -178,61 +773,164 @@ pnl_tab_class_init (PnlTabClass *klass)
                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
 
   g_object_class_install_properties (object_class, N_PROPS, properties);
+
+  signals [CLICKED] =
+    g_signal_new_class_handler ("clicked",
+                                G_TYPE_FROM_CLASS (klass),
+                                G_SIGNAL_RUN_LAST,
+                                G_CALLBACK (pnl_tab_activate),
+                                NULL, NULL, NULL, G_TYPE_NONE, 0);
 }
 
 static void
 pnl_tab_init (PnlTab *self)
 {
-  self->edge = GTK_POS_TOP;
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+  GtkBox *center;
+
+  priv->style = PNL_TAB_BOTH;
+  priv->edge = GTK_POS_TOP;
+
+  gtk_widget_set_has_window (GTK_WIDGET (self), TRUE);
 
+  gtk_widget_add_events (GTK_WIDGET (self),
+                         GDK_BUTTON_PRESS_MASK |
+                         GDK_BUTTON_RELEASE_MASK |
+                         GDK_POINTER_MOTION_MASK |
+                         GDK_ENTER_NOTIFY_MASK|
+                         GDK_LEAVE_NOTIFY_MASK);
   gtk_widget_set_hexpand (GTK_WIDGET (self), TRUE);
   gtk_widget_set_vexpand (GTK_WIDGET (self), FALSE);
 
-  self->title = g_object_new (GTK_TYPE_LABEL,
+  priv->box = g_object_new (GTK_TYPE_BOX,
+                            "orientation", GTK_ORIENTATION_HORIZONTAL,
+                            "visible", TRUE,
+                            NULL);
+  g_signal_connect (priv->box, "destroy", G_CALLBACK (gtk_widget_destroyed), &priv->box);
+  gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (priv->box));
+
+  center = g_object_new (GTK_TYPE_BOX,
+                         "spacing", 6,
+                         "visible", TRUE,
+                         NULL);
+  gtk_box_set_center_widget (priv->box, GTK_WIDGET (center));
+
+  priv->image = g_object_new (GTK_TYPE_IMAGE,
+                              "visible", TRUE,
+                              NULL);
+  g_signal_connect (priv->image, "destroy", G_CALLBACK (gtk_widget_destroyed), &priv->image);
+  gtk_box_pack_start (center, GTK_WIDGET (priv->image), FALSE, FALSE, 0);
+
+  priv->title = g_object_new (GTK_TYPE_LABEL,
                               "ellipsize", PANGO_ELLIPSIZE_END,
                               "use-underline", TRUE,
                               "visible", TRUE,
                               NULL);
+  g_signal_connect (priv->title, "destroy", G_CALLBACK (gtk_widget_destroyed), &priv->title);
+  gtk_box_pack_start (center, GTK_WIDGET (priv->title), FALSE, FALSE, 0);
+
+  priv->close = g_object_new (GTK_TYPE_BUTTON,
+                              "halign", GTK_ALIGN_END,
+                              "child", g_object_new (GTK_TYPE_IMAGE,
+                                                     "icon-name", "window-close-symbolic",
+                                                     "visible", TRUE,
+                                                     NULL),
+                              "visible", TRUE,
+                              NULL);
+  g_signal_connect_object (priv->close,
+                           "clicked",
+                           G_CALLBACK (pnl_tab_close_clicked),
+                           self,
+                           G_CONNECT_SWAPPED);
+  gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (priv->close)), "close");
+  gtk_box_pack_end (priv->box, GTK_WIDGET (priv->close), FALSE, FALSE, 0);
+  g_object_bind_property (self, "can-close", priv->close, "visible", G_BINDING_SYNC_CREATE);
 
-  gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->title));
+  priv->minimize = g_object_new (GTK_TYPE_BUTTON,
+                                 "halign", GTK_ALIGN_END,
+                                 "child", g_object_new (GTK_TYPE_IMAGE,
+                                                        "icon-name", "window-minimize-symbolic",
+                                                        "visible", TRUE,
+                                                        NULL),
+                                 "visible", TRUE,
+                                 NULL);
+  g_signal_connect_object (priv->minimize,
+                           "clicked",
+                           G_CALLBACK (pnl_tab_minimize_clicked),
+                           self,
+                           G_CONNECT_SWAPPED);
+  gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (priv->minimize)), "minimize");
+  gtk_box_pack_end (priv->box, GTK_WIDGET (priv->minimize), FALSE, FALSE, 0);
 }
 
 const gchar *
 pnl_tab_get_title (PnlTab *self)
 {
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
   g_return_val_if_fail (PNL_IS_TAB (self), NULL);
 
-  return gtk_label_get_label (self->title);
+  return gtk_label_get_label (priv->title);
 }
 
 void
 pnl_tab_set_title (PnlTab      *self,
                    const gchar *title)
 {
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
   g_return_if_fail (PNL_IS_TAB (self));
 
-  gtk_label_set_label (self->title, title);
+  gtk_label_set_label (priv->title, title);
+}
+
+const gchar *
+pnl_tab_get_icon_name (PnlTab *self)
+{
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+  const gchar *ret = NULL;
+
+  g_return_val_if_fail (PNL_IS_TAB (self), NULL);
+
+  gtk_image_get_icon_name (priv->image, &ret, NULL);
+
+  return ret;
+}
+
+void
+pnl_tab_set_icon_name (PnlTab      *self,
+                       const gchar *icon_name)
+{
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
+  g_return_if_fail (PNL_IS_TAB (self));
+
+  g_object_set (priv->image, "icon-name", icon_name, NULL);
 }
 
 GtkPositionType
 pnl_tab_get_edge (PnlTab *self)
 {
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
   g_return_val_if_fail (PNL_IS_TAB (self), 0);
 
-  return self->edge;
+  return priv->edge;
 }
 
 void
 pnl_tab_set_edge (PnlTab          *self,
                   GtkPositionType  edge)
 {
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
   g_return_if_fail (PNL_IS_TAB (self));
   g_return_if_fail (edge >= 0);
   g_return_if_fail (edge <= 3);
 
-  if (self->edge != edge)
+  if (priv->edge != edge)
     {
-      self->edge = edge;
+      priv->edge = edge;
       pnl_tab_update_edge (self);
       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_EDGE]);
     }
@@ -246,20 +944,214 @@ pnl_tab_set_edge (PnlTab          *self,
 GtkWidget *
 pnl_tab_get_widget (PnlTab *self)
 {
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
   g_return_val_if_fail (PNL_IS_TAB (self), NULL);
 
-  return self->widget;
+  return priv->widget;
 }
 
 void
 pnl_tab_set_widget (PnlTab    *self,
                     GtkWidget *widget)
 {
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
   g_return_if_fail (PNL_IS_TAB (self));
 
-  if (pnl_set_weak_pointer (&self->widget, widget))
+  if (pnl_set_weak_pointer (&priv->widget, widget))
     {
-      gtk_label_set_mnemonic_widget (self->title, widget);
+      gtk_label_set_mnemonic_widget (priv->title, widget);
       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_WIDGET]);
     }
 }
+
+gboolean
+pnl_tab_get_can_close (PnlTab *self)
+{
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
+  g_return_val_if_fail (PNL_IS_TAB (self), FALSE);
+
+  return priv->can_close;
+}
+
+void
+pnl_tab_set_can_close (PnlTab   *self,
+                       gboolean  can_close)
+{
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
+  g_return_if_fail (PNL_IS_TAB (self));
+
+  can_close = !!can_close;
+
+  if (can_close != priv->can_close)
+    {
+      priv->can_close = can_close;
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_CLOSE]);
+    }
+}
+
+gboolean
+pnl_tab_get_active (PnlTab *self)
+{
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
+  g_return_val_if_fail (PNL_IS_TAB (self), FALSE);
+
+  return priv->active;
+}
+
+void
+pnl_tab_set_active (PnlTab   *self,
+                    gboolean  active)
+{
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
+  g_return_if_fail (PNL_IS_TAB (self));
+
+  active = !!active;
+
+  if (priv->active != active)
+    {
+      priv->active = active;
+      pnl_tab_activate (self);
+      pnl_tab_apply_state (self);
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ACTIVE]);
+    }
+}
+
+static const gchar *
+pnl_tab_get_action_name (GtkActionable *actionable)
+{
+  PnlTab *self = (PnlTab *)actionable;
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
+  g_return_val_if_fail (PNL_IS_TAB (self), NULL);
+
+  return priv->action_name;
+}
+
+static void
+pnl_tab_set_action_name (GtkActionable *actionable,
+                         const gchar   *action_name)
+{
+  PnlTab *self = (PnlTab *)actionable;
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
+  g_return_if_fail (PNL_IS_TAB (self));
+
+  if (g_strcmp0 (priv->action_name, action_name) != 0)
+    {
+      g_free (priv->action_name);
+      priv->action_name = g_strdup (action_name);
+      g_object_notify (G_OBJECT (self), "action-name");
+    }
+}
+
+static GVariant *
+pnl_tab_get_action_target_value (GtkActionable *actionable)
+{
+  PnlTab *self = (PnlTab *)actionable;
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
+  g_return_val_if_fail (PNL_IS_TAB (self), NULL);
+
+  return priv->action_target_value;
+}
+
+static void
+pnl_tab_set_action_target_value (GtkActionable *actionable,
+                                 GVariant      *variant)
+{
+  PnlTab *self = (PnlTab *)actionable;
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
+  g_return_if_fail (PNL_IS_TAB (self));
+
+  if (priv->action_target_value != variant)
+    {
+      g_clear_pointer (&priv->action_target_value, g_variant_unref);
+      if (variant)
+        priv->action_target_value = g_variant_ref (variant);
+      g_object_notify (G_OBJECT (self), "action-target");
+    }
+}
+
+static void
+actionable_iface_init (GtkActionableInterface *iface)
+{
+  iface->get_action_name = pnl_tab_get_action_name;
+  iface->set_action_name = pnl_tab_set_action_name;
+  iface->get_action_target_value = pnl_tab_get_action_target_value;
+  iface->set_action_target_value = pnl_tab_set_action_target_value;
+}
+
+PnlTabStyle
+pnl_tab_get_style (PnlTab *self)
+{
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
+  g_return_val_if_fail (PNL_IS_TAB (self), 0);
+
+  return priv->style;
+}
+
+void
+pnl_tab_set_style (PnlTab      *self,
+                   PnlTabStyle  style)
+{
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+
+  g_return_if_fail (PNL_IS_TAB (self));
+
+  if (style != priv->style)
+    {
+      priv->style = style;
+      gtk_widget_set_visible (GTK_WIDGET (priv->image), !!(priv->style & PNL_TAB_ICONS));
+      gtk_widget_set_visible (GTK_WIDGET (priv->title), !!(priv->style & PNL_TAB_TEXT));
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_STYLE]);
+    }
+}
+
+void
+_pnl_tab_update_controls (PnlTab *self)
+{
+  PnlTabPrivate *priv = pnl_tab_get_instance_private (self);
+  gboolean can_close = FALSE;
+  gboolean can_minimize = FALSE;
+
+  g_return_if_fail (PNL_IS_TAB (self));
+
+  if (PNL_IS_DOCK_ITEM (priv->widget))
+    {
+      can_close = pnl_dock_item_get_can_close (PNL_DOCK_ITEM (priv->widget));
+      can_minimize = pnl_dock_item_get_can_minimize (PNL_DOCK_ITEM (priv->widget));
+    }
+
+  gtk_widget_set_visible (GTK_WIDGET (priv->close), can_close);
+  gtk_widget_set_visible (GTK_WIDGET (priv->minimize), can_minimize);
+}
+
+GType
+pnl_tab_style_get_type (void)
+{
+  static GType type_id;
+
+  if (g_once_init_enter (&type_id))
+    {
+      GType _type_id;
+      static const GFlagsValue values[] = {
+        { PNL_TAB_ICONS, "PNL_TAB_ICONS", "icons" },
+        { PNL_TAB_TEXT, "PNL_TAB_TEXT", "text" },
+        { PNL_TAB_BOTH, "PNL_TAB_BOTH", "both" },
+        { 0 }
+      };
+
+      _type_id = g_flags_register_static ("PnlTabStyle", values);
+      g_once_init_leave (&type_id, _type_id);
+    }
+
+  return type_id;
+}
diff --git a/contrib/pnl/pnl-tab.h b/contrib/pnl/pnl-tab.h
index a59bfd5..c1e2188 100644
--- a/contrib/pnl/pnl-tab.h
+++ b/contrib/pnl/pnl-tab.h
@@ -24,23 +24,31 @@
 #ifndef PNL_TAB_H
 #define PNL_TAB_H
 
-#include <gtk/gtk.h>
+#include "pnl-dock-types.h"
 
 G_BEGIN_DECLS
 
-#define PNL_TYPE_TAB (pnl_tab_get_type())
-
-G_DECLARE_FINAL_TYPE (PnlTab, pnl_tab, PNL, TAB, GtkToggleButton)
-
-const gchar     *pnl_tab_get_title  (PnlTab          *self);
-void             pnl_tab_set_title  (PnlTab          *self,
-                                     const gchar     *title);
-GtkPositionType  pnl_tab_get_edge   (PnlTab          *self);
-void             pnl_tab_set_edge   (PnlTab          *self,
-                                     GtkPositionType  edge);
-GtkWidget       *pnl_tab_get_widget (PnlTab          *self);
-void             pnl_tab_set_widget (PnlTab          *self,
-                                     GtkWidget       *widget);
+const gchar     *pnl_tab_get_icon_name  (PnlTab          *self);
+void             pnl_tab_set_icon_name  (PnlTab          *self,
+                                         const gchar     *icon_name);
+const gchar     *pnl_tab_get_title      (PnlTab          *self);
+void             pnl_tab_set_title      (PnlTab          *self,
+                                         const gchar     *title);
+GtkPositionType  pnl_tab_get_edge       (PnlTab          *self);
+void             pnl_tab_set_edge       (PnlTab          *self,
+                                         GtkPositionType  edge);
+GtkWidget       *pnl_tab_get_widget     (PnlTab          *self);
+void             pnl_tab_set_widget     (PnlTab          *self,
+                                         GtkWidget       *widget);
+gboolean         pnl_tab_get_active     (PnlTab          *self);
+void             pnl_tab_set_active     (PnlTab          *self,
+                                         gboolean         active);
+gboolean         pnl_tab_get_can_close  (PnlTab          *self);
+void             pnl_tab_set_can_close  (PnlTab          *self,
+                                         gboolean         can_close);
+PnlTabStyle      pnl_tab_get_style      (PnlTab          *self);
+void             pnl_tab_set_style      (PnlTab          *self,
+                                         PnlTabStyle      style);
 
 G_END_DECLS
 
diff --git a/contrib/pnl/pnl-util-private.h b/contrib/pnl/pnl-util-private.h
index 36e6845..8d1f1a9 100644
--- a/contrib/pnl/pnl-util-private.h
+++ b/contrib/pnl/pnl-util-private.h
@@ -29,10 +29,22 @@ G_BEGIN_DECLS
 #define pnl_set_weak_pointer(ptr,obj) \
   
((obj!=*(ptr))?(pnl_clear_weak_pointer(ptr),*(ptr)=obj,((obj)?g_object_add_weak_pointer((GObject*)obj,(gpointer*)ptr),NULL:NULL),1):0)
 
-gboolean pnl_gtk_bin_draw          (GtkWidget *widget,
-                                    cairo_t   *cr);
-void     pnl_gtk_bin_size_allocate (GtkWidget     *widget,
-                                    GtkAllocation *allocation);
+void          pnl_gtk_widget_add_class             (GtkWidget        *widget,
+                                                    const gchar      *class_name);
+gboolean      pnl_gtk_widget_activate_action       (GtkWidget        *widget,
+                                                    const gchar      *full_action_name,
+                                                    GVariant         *variant);
+GVariant     *pnl_gtk_widget_get_action_state      (GtkWidget        *widget,
+                                                    const gchar      *action_name);
+GActionGroup *pnl_gtk_widget_find_group_for_action (GtkWidget        *widget,
+                                                    const gchar      *action_name);
+void          pnl_g_action_name_parse              (const gchar      *action_name,
+                                                    gchar           **prefix,
+                                                    gchar           **name);
+void          pnl_gtk_style_context_get_borders    (GtkStyleContext  *style_context,
+                                                    GtkBorder        *borders);
+void          pnl_gtk_allocation_subtract_border   (GtkAllocation    *alloc,
+                                                    GtkBorder        *border);
 
 G_END_DECLS
 
diff --git a/contrib/pnl/pnl-util.c b/contrib/pnl/pnl-util.c
index 5105be3..4f35d4a 100644
--- a/contrib/pnl/pnl-util.c
+++ b/contrib/pnl/pnl-util.c
@@ -16,6 +16,10 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#define G_LOG_DOMAIN "pnl-util"
+
+#include <string.h>
+
 #include "pnl-util-private.h"
 
 static void
@@ -28,82 +32,255 @@ pnl_gtk_border_sum (GtkBorder       *one,
   one->left += two->left;
 }
 
-gboolean
-pnl_gtk_bin_draw (GtkWidget *widget,
-                  cairo_t   *cr)
+void
+pnl_gtk_style_context_get_borders (GtkStyleContext *style_context,
+                                   GtkBorder       *borders)
 {
-  GtkStyleContext *style_context;
+  GtkBorder border = { 0 };
+  GtkBorder padding = { 0 };
+  GtkBorder margin = { 0 };
   GtkStateFlags state;
-  GtkAllocation alloc;
-  GtkBorder border;
-  GtkBorder padding;
-  GtkWidget *child;
 
-  g_assert (GTK_IS_WIDGET (widget));
-  g_assert (cr != NULL);
+  g_return_if_fail (GTK_IS_STYLE_CONTEXT (style_context));
+  g_return_if_fail (borders != NULL);
 
-  gtk_widget_get_allocation (widget, &alloc);
+  memset (borders, 0, sizeof *borders);
 
-  style_context = gtk_widget_get_style_context (widget);
   state = gtk_style_context_get_state (style_context);
+
   gtk_style_context_get_border (style_context, state, &border);
   gtk_style_context_get_padding (style_context, state, &padding);
+  gtk_style_context_get_margin (style_context, state, &margin);
 
-  pnl_gtk_border_sum (&border, &padding);
+  pnl_gtk_border_sum (borders, &padding);
+  pnl_gtk_border_sum (borders, &border);
+  pnl_gtk_border_sum (borders, &margin);
+}
 
-  gtk_render_background (gtk_widget_get_style_context (widget), cr,
-                         border.left,
-                         border.top,
-                         alloc.width - border.left - border.right,
-                         alloc.height - border.top - border.bottom);
+static void
+split_action_name (const gchar  *action_name,
+                   gchar       **prefix,
+                   gchar       **name)
+{
+  const gchar *dot;
 
-  child = gtk_bin_get_child (GTK_BIN (widget));
+  g_assert (prefix != NULL);
+  g_assert (name != NULL);
 
-  if (child != NULL)
-    gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
+  *prefix = NULL;
+  *name = NULL;
 
-  return GDK_EVENT_PROPAGATE;
+  if (action_name == NULL)
+    return;
+
+  dot = strchr (action_name, '.');
+
+  if (dot == NULL)
+    *name = g_strdup (action_name);
+  else
+    {
+      *prefix = g_strndup (action_name, dot - action_name);
+      *name = g_strdup (dot + 1);
+    }
 }
 
-void
-pnl_gtk_bin_size_allocate (GtkWidget     *widget,
-                           GtkAllocation *allocation)
+gboolean
+pnl_gtk_widget_activate_action (GtkWidget   *widget,
+                                const gchar *full_action_name,
+                                GVariant    *parameter)
 {
-  GtkStyleContext *style_context;
-  GtkStateFlags state;
-  GtkBorder border;
-  GtkBorder padding;
-  gint border_width;
-  GtkWidget *child;
+  GtkWidget *toplevel;
+  GApplication *app;
+  GActionGroup *group = NULL;
+  gchar *prefix = NULL;
+  gchar *action_name = NULL;
+  const gchar *dot;
+  gboolean ret = FALSE;
 
-  g_return_if_fail (GTK_IS_BIN (widget));
-  g_return_if_fail (allocation != NULL);
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+  g_return_val_if_fail (full_action_name, FALSE);
 
-  gtk_widget_set_allocation (widget, allocation);
+  dot = strchr (full_action_name, '.');
 
-  child = gtk_bin_get_child (GTK_BIN (widget));
+  if (dot == NULL)
+    {
+      prefix = NULL;
+      action_name = g_strdup (full_action_name);
+    }
+  else
+    {
+      prefix = g_strndup (full_action_name, dot - full_action_name);
+      action_name = g_strdup (dot + 1);
+    }
 
-  if (child == NULL)
-    return;
+  /*
+   * TODO: Support non-grouped names. We need to walk
+   *       through all the groups at each level to do this.
+   */
+  if (prefix == NULL)
+    prefix = g_strdup ("win");
 
-  style_context = gtk_widget_get_style_context (widget);
-  state = gtk_style_context_get_state (style_context);
-  gtk_style_context_get_border (style_context, state, &border);
-  gtk_style_context_get_padding (style_context, state, &padding);
+  app = g_application_get_default ();
+  toplevel = gtk_widget_get_toplevel (widget);
+
+  while ((group == NULL) && (widget != NULL))
+    {
+      group = gtk_widget_get_action_group (widget, prefix);
+
+      if G_UNLIKELY (GTK_IS_POPOVER (widget))
+        {
+          GtkWidget *relative_to;
+
+          relative_to = gtk_popover_get_relative_to (GTK_POPOVER (widget));
+
+          if (relative_to != NULL)
+            widget = relative_to;
+          else
+            widget = gtk_widget_get_parent (widget);
+        }
+      else
+        {
+          widget = gtk_widget_get_parent (widget);
+        }
+    }
+
+  if (!group && g_str_equal (prefix, "win") && G_IS_ACTION_GROUP (toplevel))
+    group = G_ACTION_GROUP (toplevel);
+
+  if (!group && g_str_equal (prefix, "app") && G_IS_ACTION_GROUP (app))
+    group = G_ACTION_GROUP (app);
+
+  if (group && g_action_group_has_action (group, action_name))
+    {
+      g_action_group_activate_action (group, action_name, parameter);
+      ret = TRUE;
+      goto cleanup;
+    }
+
+  if (parameter && g_variant_is_floating (parameter))
+    {
+      parameter = g_variant_ref_sink (parameter);
+      g_variant_unref (parameter);
+    }
+
+  g_warning ("Failed to locate action %s.%s", prefix, action_name);
+
+cleanup:
+  g_free (prefix);
+  g_free (action_name);
+
+  return ret;
+}
+
+static GActionGroup *
+find_group_with_action (GtkWidget   *widget,
+                        const gchar *prefix,
+                        const gchar *name)
+{
+  GActionGroup *group;
 
-  pnl_gtk_border_sum (&border, &padding);
+  g_assert (GTK_IS_WIDGET (widget));
+  g_assert (name != NULL);
+
+  /*
+   * GtkWidget does not provide a way to get group names,
+   * so there is nothing more we can do if prefix is NULL.
+   */
+  if (prefix == NULL)
+    return NULL;
+
+  if (g_str_equal (prefix, "app"))
+    group = G_ACTION_GROUP (g_application_get_default ());
+  else
+    group = gtk_widget_get_action_group (widget, prefix);
+
+  if (group != NULL && g_action_group_has_action (group, name))
+    return group;
+
+  widget = gtk_widget_get_parent (widget);
 
-  allocation->x += border.left;
-  allocation->y += border.top;
-  allocation->width -= border.left + border.right;
-  allocation->height -= border.top + border.bottom;
+  if (widget != NULL)
+    return find_group_with_action (widget, prefix, name);
+
+  return NULL;
+}
+
+GVariant *
+pnl_gtk_widget_get_action_state (GtkWidget   *widget,
+                                 const gchar *action_name)
+{
+  GActionGroup *group;
+  gchar *prefix = NULL;
+  gchar *name = NULL;
+  GVariant *ret = NULL;
+
+  split_action_name (action_name, &prefix, &name);
+  if (name == NULL || prefix == NULL)
+    goto cleanup;
+
+  group = find_group_with_action (widget, prefix, name);
+  if (group == NULL)
+    goto cleanup;
+
+  ret = g_action_group_get_action_state (group, name);
+
+cleanup:
+  g_free (name);
+  g_free (prefix);
+
+  return ret;
+}
+
+GActionGroup *
+pnl_gtk_widget_find_group_for_action (GtkWidget   *widget,
+                                      const gchar *action_name)
+{
+  GActionGroup *group;
+  gchar *prefix = NULL;
+  gchar *name = NULL;
 
-  border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
 
-  allocation->x += border_width;
-  allocation->y += border_width;
-  allocation->width -= border_width * 2;
-  allocation->height -= border_width * 2;
+  if (action_name == NULL)
+    return NULL;
 
-  gtk_widget_size_allocate (child, allocation);
+  split_action_name (action_name, &prefix, &name);
+  if (name == NULL || prefix == NULL)
+    goto cleanup;
+
+  group = find_group_with_action (widget, prefix, name);
+
+cleanup:
+  g_free (name);
+  g_free (prefix);
+
+  return group;
+}
+
+void
+pnl_g_action_name_parse (const gchar  *action_name,
+                         gchar       **prefix,
+                         gchar       **name)
+{
+  split_action_name (action_name, prefix, name);
+}
+
+void
+pnl_gtk_allocation_subtract_border (GtkAllocation *alloc,
+                                    GtkBorder     *border)
+{
+  g_return_if_fail (alloc != NULL);
+  g_return_if_fail (border != NULL);
+
+  alloc->x += border->left;
+  alloc->y += border->top;
+  alloc->width -= (border->left + border->right);
+  alloc->height -= (border->top + border->bottom);
+}
+
+void
+pnl_gtk_widget_add_class (GtkWidget   *widget,
+                          const gchar *class_name)
+{
+  gtk_style_context_add_class (gtk_widget_get_style_context (widget), class_name);
 }
diff --git a/contrib/pnl/pnl-version.h.in b/contrib/pnl/pnl-version.h.in
index 54a637b..a11acaa 100644
--- a/contrib/pnl/pnl-version.h.in
+++ b/contrib/pnl/pnl-version.h.in
@@ -24,7 +24,7 @@
 #endif
 
 /**
- * SECTION:pnlversion
+ * SECTION:pnl-version
  * @short_description: pnl version checking
  *
  * pnl provides macros to check the version of the library
diff --git a/contrib/pnl/pnl.h b/contrib/pnl/pnl.h
index 500e654..87867e2 100644
--- a/contrib/pnl/pnl.h
+++ b/contrib/pnl/pnl.h
@@ -28,24 +28,24 @@ G_BEGIN_DECLS
 #include "pnl-dock.h"
 #include "pnl-dock-bin.h"
 #include "pnl-dock-bin-edge.h"
-#include "pnl-dock-item.h"
-#include "pnl-dock-manager.h"
 #include "pnl-dock-overlay.h"
 #include "pnl-dock-overlay-edge.h"
+#include "pnl-dock-item.h"
+#include "pnl-dock-manager.h"
 #include "pnl-dock-paned.h"
 #include "pnl-dock-revealer.h"
 #include "pnl-dock-stack.h"
-#include "pnl-dock-tab-strip.h"
 #include "pnl-dock-types.h"
 #include "pnl-dock-widget.h"
 #include "pnl-dock-window.h"
 
-#include "pnl-version.h"
-
+#include "pnl-bin.h"
 #include "pnl-tab.h"
 #include "pnl-tab-strip.h"
 #include "pnl-multi-paned.h"
 
+#include "pnl-version.h"
+
 #undef PNL_INSIDE
 
 G_END_DECLS
diff --git a/data/theme/Adwaita-panels.css b/data/theme/Adwaita-panels.css
index 34d6907..d630d65 100644
--- a/data/theme/Adwaita-panels.css
+++ b/data/theme/Adwaita-panels.css
@@ -1,50 +1,80 @@
-dockbin {
-  border: 1px solid alpha(@borders, 0.75);
-  -PnlDockBin-handle-size: 1;
+pnldockbinedge {
+  background-color: @content_view_bg;
+  border-color: @borders;
+  border-style: solid;
 }
 
-dockpaned {
-  border: 1px solid @borders;
+pnldockbinedge.right {
+  border-left-width: 1px;
 }
 
-docktabstrip {
-  padding: 0 6px 0 6px;
+pnldockbinedge.left {
+  border-right-width: 1px;
 }
 
-docktab {
-  background-image: none;
-  background-color: transparent;
-  border-color: transparent;
-  border-style: solid;
-  color: @theme_fg_color;
-  min-height: 39px;
-  outline-offset: -6px;
-  transition-duration: 200ms;
-  transition-timing-function: ease;
+pnldockbinedge.bottom {
+  border-top-width: 1px;
+}
+
+pnldockpaned .handle {
+  border: 1px solid @borders;
 }
 
-docktab > label {
-  font-size: 0.9em;
+pnldockstack pnltabstrip {
+  padding-top: 2px;
+  background-color: @content_view_bg;
+  color: @theme_fg_color;
+  border-bottom: 1px solid mix(@theme_bg_color, @borders, 0.25);
 }
 
-docktab > * {
-  padding: 0 6px 0 6px;
+pnldockstack pnltabstrip button.control,
+pnldockstack pnltabstrip pnltab {
+  background: transparent;
+  box-shadow: none;
+  border: none;
+  padding: 0;
+  margin: 0;
+
+  border-bottom: 3px;
+  border-bottom-style: solid;
+  border-bottom-color: transparent;
+
+  margin-left: 6px;
+  margin-right: 6px;
+
+  color: @theme_fg_color;
 }
 
-dockoverlayedge {
-  background-color: @theme_bg_color;
+pnldockstack pnltabstrip button.control,
+pnldockstack pnltabstrip pnltab button,
+pnldockstack pnltabstrip pnltab {
+  transition-duration: 200ms;
 }
 
-dockoverlayedge docktabstrip {
+pnldockstack pnltabstrip pnltab button {
   padding: 0;
+  margin: 0;
   border: none;
+  background: none;
+  box-shadow: none;
 }
 
-dockoverlayedge.left-edge docktab:checked {
-  border-right-color: @theme_selected_bg_color;
-  border-bottom-color: transparent;
+pnldockstack pnltabstrip pnltab:active {
+  border-bottom-color: @theme_selected_bg_color;
 }
-dockoverlayedge.right-edge docktab:checked {
-  border-left-color: @theme_selected_bg_color;
-  border-bottom-color: transparent;
+
+pnldockstack pnltabstrip button.control:last-child {
+  margin-right: 16px;
+}
+
+pnldockstack pnltabstrip button.control:hover,
+pnldockstack pnltabstrip pnltab:hover {
+  border-bottom-color: mix(@borders, @theme_bg_color, 0.25);
+}
+
+pnldockstack pnltabstrip button.control:hover:checked,
+pnldockstack pnltabstrip button.control:checked,
+pnldockstack pnltabstrip pnltab:hover:checked,
+pnldockstack pnltabstrip pnltab:checked {
+  border-bottom-color: @theme_selected_bg_color;
 }
diff --git a/data/theme/Adwaita.css b/data/theme/Adwaita.css
index 8b62802..168333c 100644
--- a/data/theme/Adwaita.css
+++ b/data/theme/Adwaita.css
@@ -34,19 +34,6 @@ layouttab:backdrop {
 }
 
 
-docktabstrip {
-  background-color: #d6d6d6;
-  box-shadow: 0 4px 3px -5px #aaa inset,
-              0 -1px 0 #a1a1a1 inset;
-}
-docktabstrip:backdrop {
-  box-shadow: 0 -1px 0 #a1a1a1 inset;
-}
-docktabstrip docktab:checked {
-  box-shadow: 0 -2px 0 #4a90d9 inset;
-}
-
-
 entry.search-missing {
   border-color: #aa0000;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]