diff --git a/Makefile.am b/Makefile.am
index 42803be..d6aed90 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,6 @@
 ACLOCAL_AMFLAGS = -I m4 -I libgd ${ACLOCAL_FLAGS}
 
-SUBDIRS = libgd po egg-list-box panels shell
+SUBDIRS = libgd po egg-list-box panels shell search-provider
 if BUILD_DOCUMENTATION
 SUBDIRS += man
 endif
diff --git a/configure.ac b/configure.ac
index a3d3fc7..98f8a33 100644
--- a/configure.ac
+++ b/configure.ac
@@ -514,6 +514,7 @@ panels/wacom/calibrator/Makefile
 panels/wacom/gnome-wacom-panel.desktop.in
 po/Makefile.in
 libgd/Makefile
+search-provider/Makefile
 shell/Makefile
 shell/gnome-control-center.desktop.in
 man/Makefile
diff --git a/egg-list-box b/egg-list-box
--- a/egg-list-box
+++ b/egg-list-box
@@ -1 +1 @@
-Subproject commit ebcc7ed3bd2782e29e56b5452a5d4080d4d87cc7
+Subproject commit ebcc7ed3bd2782e29e56b5452a5d4080d4d87cc7-dirty
diff --git a/panels/sound/gvc b/panels/sound/gvc
--- a/panels/sound/gvc
+++ b/panels/sound/gvc
@@ -1 +1 @@
-Subproject commit 03894efbcd010faf53bbc6e27256d27485f721b8
+Subproject commit 03894efbcd010faf53bbc6e27256d27485f721b8-dirty
diff --git a/search-provider/Makefile.am b/search-provider/Makefile.am
new file mode 100644
index 0000000..11c120a
--- /dev/null
+++ b/search-provider/Makefile.am
@@ -0,0 +1,54 @@
+dbus_shell_search_provider_built_sources =	\
+	cc-shell-search-provider-generated.c	\
+	cc-shell-search-provider-generated.h
+
+$(dbus_shell_search_provider_built_sources) : Makefile.am $(srcdir)/org.gnome.ShellSearchProvider2.xml
+	gdbus-codegen							\
+		--interface-prefix org.gnome.				\
+		--c-namespace Cc					\
+		--generate-c-code cc-shell-search-provider-generated	\
+		$(srcdir)/org.gnome.ShellSearchProvider2.xml		\
+		$(NULL)
+
+INCLUDES =					\
+	-I$(top_srcdir)				\
+	$(SHELL_CFLAGS)				\
+	$(CHEESE_CFLAGS)			\
+	-I$(top_srcdir)/libgd
+
+libexec_PROGRAMS = gnome-control-center-search-provider
+
+BUILT_SOURCES =	$(dbus_shell_search_provider_built_sources)
+
+gnome_control_center_search_provider_SOURCES =	\
+	$(BUILT_SOURCES)			\
+	control-center-search-provider.c	\
+	control-center-search-provider.h	\
+	cc-search-provider.c			\
+	cc-search-provider.h			\
+	$(MARSHAL_FILES)
+
+gnome_control_center_search_provider_LDADD =	\
+	$(top_builddir)/shell/libshell.la	\
+	$(SHELL_LIBS)
+
+AM_CPPFLAGS = -DGNOMELOCALEDIR="\"$(datadir)/locale\""
+
+EXTRA_DIST = org.gnome.ControlCenter.service.in
+
+CLEANFILES = $(BUILT_SOURCES)
+
+servicedir = $(datadir)/dbus-1/services
+service_DATA = $(service_in_files:.service.in=.service)
+service_in_files = 				\
+	org.gnome.ControlCenter.SearchProvider.service.in
+
+org.gnome.ControlCenter.SearchProvider.service: org.gnome.ControlCenter.SearchProvider.service.in Makefile
+	$(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@
+
+searchproviderdir = $(datadir)/gnome-shell/search-providers
+dist_searchprovider_DATA = gnome-control-center-search-provider.ini
+
+DISTCLEANFILES = org.gnome.ControlCenter.SearchProvider.service
+
+-include $(top_srcdir)/git.mk
diff --git a/search-provider/cc-search-provider.c b/search-provider/cc-search-provider.c
new file mode 100644
index 0000000..ac92b7d
--- /dev/null
+++ b/search-provider/cc-search-provider.c
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2012 Giovanni Campagna <scampa.giovanni@gmail.com>
+ *
+ * The Control Center 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 2 of the License, or (at your
+ * option) any later version.
+ *
+ * The Control Center 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 the Control Center; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <config.h>
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <gio/gdesktopappinfo.h>
+#include <gtk/gtk.h>
+#include <string.h>
+
+#include <shell/cc-panel.h>
+#include <shell/cc-shell-model.h>
+#include <shell/cc-panel-loader.h>
+#include <shell/cc-util.h>
+
+#include "control-center-search-provider.h"
+#include "cc-search-provider.h"
+
+struct _CcSearchProvider
+{
+  GObject parent;
+
+  CcShellSearchProvider2 *skeleton;
+};
+
+struct _CcSearchProviderClass
+{
+  GObjectClass parent_class;
+};
+
+typedef enum {
+  MATCH_NONE,
+  MATCH_PREFIX,
+  MATCH_SUBSTRING
+} PanelSearchMatch;
+
+G_DEFINE_TYPE (CcSearchProvider, cc_search_provider, G_TYPE_OBJECT)
+
+static char **
+get_casefolded_terms (char **terms)
+{
+  char **casefolded_terms;
+  int i, n;
+
+  n = g_strv_length ((char**) terms);
+  casefolded_terms = g_new (char*, n + 1);
+
+  for (i = 0; i < n; i++)
+    casefolded_terms[i] = cc_util_normalize_casefold_and_unaccent (terms[i]);
+  casefolded_terms[n] = NULL;
+
+  return casefolded_terms;
+}
+
+static gboolean
+matches_multiple_terms (GtkTreeModel  *model,
+                        GtkTreeIter   *iter,
+                        char         **terms)
+{
+  int i;
+
+  for (i = 0; terms[i]; i++)
+    {
+      if (cc_shell_model_iter_matches_search (CC_SHELL_MODEL (model),
+                                              iter,
+                                              terms[i]))
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+static GtkTreeModel *
+get_model (void)
+{
+  CcSearchProviderApp *app;
+
+  app = cc_search_provider_app_get ();
+  return GTK_TREE_MODEL (cc_search_provider_app_get_model (app));
+}
+
+static gboolean
+handle_get_initial_result_set (CcShellSearchProvider2  *skeleton,
+                               GDBusMethodInvocation   *invocation,
+                               char                   **terms,
+                               CcSearchProvider        *self)
+{
+  GtkTreeModel *model = get_model ();
+  GtkTreeIter iter;
+  GPtrArray *results;
+  gboolean ok;
+  char **casefolded_terms;
+  char **results_as_strings;
+
+  casefolded_terms = get_casefolded_terms (terms);
+  results = g_ptr_array_new ();
+
+  ok = gtk_tree_model_get_iter_first (model, &iter);
+  while (ok)
+    {
+      if (matches_multiple_terms (model, &iter,
+                                  casefolded_terms))
+        {
+          g_ptr_array_add (results,
+                           gtk_tree_model_get_string_from_iter (model,
+                                                                &iter));
+        }
+
+      ok = gtk_tree_model_iter_next (model, &iter);
+    }
+
+  g_ptr_array_add (results, NULL);
+  results_as_strings = (char**) g_ptr_array_free (results, FALSE);
+  cc_shell_search_provider2_complete_get_initial_result_set (skeleton,
+                                                             invocation,
+                                                             (const char* const*) results_as_strings);
+
+  g_strfreev (casefolded_terms);
+  g_strfreev (results_as_strings);
+  return TRUE;
+}
+
+static gboolean
+handle_get_subsearch_result_set (CcShellSearchProvider2  *skeleton,
+                                 GDBusMethodInvocation   *invocation,
+                                 char                   **previous_results,
+                                 char                   **terms,
+                                 CcSearchProvider        *self)
+{
+  GtkTreeModel *model = get_model ();
+  GtkTreeIter iter;
+  GPtrArray *results;
+  char **casefolded_terms;
+  char **results_as_strings;
+  int i;
+
+  casefolded_terms = get_casefolded_terms (terms);
+  results = g_ptr_array_new ();
+
+  for (i = 0; previous_results[i]; i++)
+    {
+      if (gtk_tree_model_get_iter_from_string (model, &iter,
+                                               previous_results[i]) &&
+          matches_multiple_terms (model, &iter, casefolded_terms))
+        {
+          g_ptr_array_add (results, g_strdup (previous_results[i]));
+        }
+    }
+
+  g_ptr_array_add (results, NULL);
+  results_as_strings = (char**) g_ptr_array_free (results, FALSE);
+  cc_shell_search_provider2_complete_get_subsearch_result_set (skeleton,
+                                                               invocation,
+                                                               (const char* const*) results_as_strings);
+
+  g_strfreev (casefolded_terms);
+  g_strfreev (results_as_strings);
+  return TRUE;
+}
+
+static gboolean
+handle_get_result_metas (CcShellSearchProvider2  *skeleton,
+                         GDBusMethodInvocation   *invocation,
+                         char                   **results,
+                         CcSearchProvider        *self)
+{
+  GtkTreeModel *model = get_model ();
+  GtkTreeIter iter;
+  int i;
+  GVariantBuilder builder;
+  GAppInfo *app;
+  const char *id;
+  char *name, *description, *icon_string;
+  GIcon *icon;
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
+
+  for (i = 0; results[i]; i++)
+    {
+      if (!gtk_tree_model_get_iter_from_string (model, &iter, results[i]))
+        continue;
+
+      gtk_tree_model_get (model, &iter,
+                          COL_APP, &app,
+                          COL_NAME, &name,
+                          COL_GICON, &icon,
+                          COL_DESCRIPTION, &description,
+                          -1);
+      id = g_app_info_get_id (app);
+      icon_string = g_icon_to_string (icon);
+
+      g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{sv}"));
+      g_variant_builder_add (&builder, "{sv}",
+                             "id", g_variant_new_string (id));
+      g_variant_builder_add (&builder, "{sv}",
+                             "name", g_variant_new_string (name));
+      g_variant_builder_add (&builder, "{sv}",
+                             "gicon", g_variant_new_string (icon_string));
+      g_variant_builder_add (&builder, "{sv}",
+                             "description", g_variant_new_string (description));
+      g_variant_builder_close (&builder);
+
+      g_free (name);
+      g_free (description);
+      g_free (icon_string);
+      g_object_unref (app);
+      g_object_unref (icon);
+    }
+
+  cc_shell_search_provider2_complete_get_result_metas (skeleton,
+                                                       invocation,
+                                                       g_variant_builder_end (&builder));
+  return TRUE;
+}
+
+static gboolean
+handle_activate_result (CcShellSearchProvider2  *skeleton,
+                        GDBusMethodInvocation   *invocation,
+                        char                    *identifier,
+                        char                   **results,
+                        guint                    timestamp,
+                        CcSearchProvider        *self)
+{
+  GdkAppLaunchContext *launch_context;
+  GAppInfo *app;
+  GError *error;
+
+  launch_context = gdk_display_get_app_launch_context (gdk_display_get_default ());
+  gdk_app_launch_context_set_timestamp (launch_context, timestamp);
+
+  app = G_APP_INFO (g_desktop_app_info_new (identifier));
+
+  error = NULL;
+  if (!g_app_info_launch (app, NULL, G_APP_LAUNCH_CONTEXT (launch_context), &error))
+    {
+      g_dbus_method_invocation_return_gerror (invocation, error);
+      g_error_free (error);
+    }
+  else
+    {
+      cc_shell_search_provider2_complete_activate_result (skeleton, invocation);
+    }
+  return TRUE;
+}
+
+static gboolean
+handle_launch_search (CcShellSearchProvider2  *skeleton,
+                      GDBusMethodInvocation   *invocation,
+                      char                   **terms,
+                      guint                    timestamp,
+                      CcSearchProvider        *self)
+{
+  GdkAppLaunchContext *launch_context;
+  char *joined_terms, *command_line;
+  GAppInfo *app;
+  GError *error;
+
+  launch_context = gdk_display_get_app_launch_context (gdk_display_get_default ());
+  gdk_app_launch_context_set_timestamp (launch_context, timestamp);
+
+  joined_terms = g_strjoinv (" ", terms);
+  command_line = g_strdup_printf ("gnome-control-center -s '%s'", joined_terms);
+
+  error = NULL;
+  app = g_app_info_create_from_commandline (command_line,
+                                            "gnome-control-center.desktop",
+                                            G_APP_INFO_CREATE_SUPPORTS_STARTUP_NOTIFICATION,
+                                            &error);
+  if (!app) {
+      g_dbus_method_invocation_return_gerror (invocation, error);
+      g_error_free (error);
+      return TRUE;
+  }
+
+  if (!g_app_info_launch (app, NULL, G_APP_LAUNCH_CONTEXT (launch_context), &error))
+    {
+      g_dbus_method_invocation_return_gerror (invocation, error);
+      g_error_free (error);
+    }
+  else
+    {
+      cc_shell_search_provider2_complete_launch_search (skeleton, invocation);
+    }
+  return TRUE;
+}
+
+static void
+cc_search_provider_init (CcSearchProvider *self)
+{
+  self->skeleton = cc_shell_search_provider2_skeleton_new ();
+
+  g_signal_connect (self->skeleton, "handle-get-initial-result-set",
+                    G_CALLBACK (handle_get_initial_result_set), self);
+  g_signal_connect (self->skeleton, "handle-get-subsearch-result-set",
+                    G_CALLBACK (handle_get_subsearch_result_set), self);
+  g_signal_connect (self->skeleton, "handle-get-result-metas",
+                    G_CALLBACK (handle_get_result_metas), self);
+  g_signal_connect (self->skeleton, "handle-activate-result",
+                    G_CALLBACK (handle_activate_result), self);
+  g_signal_connect (self->skeleton, "handle-launch-search",
+                    G_CALLBACK (handle_launch_search), self);
+}
+
+gboolean
+cc_search_provider_dbus_register (CcSearchProvider  *self,
+                                  GDBusConnection   *connection,
+                                  const gchar       *object_path,
+                                  GError           **error)
+{
+  GDBusInterfaceSkeleton *skeleton;
+
+  skeleton = G_DBUS_INTERFACE_SKELETON (self->skeleton);
+
+  return g_dbus_interface_skeleton_export (skeleton, connection, object_path, error);
+}
+
+void
+cc_search_provider_dbus_unregister (CcSearchProvider *self,
+                                    GDBusConnection  *connection,
+                                    const gchar      *object_path)
+{
+  GDBusInterfaceSkeleton *skeleton;
+
+  skeleton = G_DBUS_INTERFACE_SKELETON (self->skeleton);
+
+  if (g_dbus_interface_skeleton_has_connection (skeleton, connection))
+      g_dbus_interface_skeleton_unexport_from_connection (skeleton, connection);
+}
+
+static void
+cc_search_provider_dispose (GObject *object)
+{
+  CcSearchProvider *self;
+
+  self = CC_SEARCH_PROVIDER (object);
+
+  g_clear_object (&self->skeleton);
+
+  G_OBJECT_CLASS (cc_search_provider_parent_class)->dispose (object);
+}
+
+static void
+cc_search_provider_class_init (CcSearchProviderClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = cc_search_provider_dispose;
+}
+
+CcSearchProvider *
+cc_search_provider_new (void)
+{
+  return g_object_new (CC_TYPE_SEARCH_PROVIDER, NULL);
+}
+
diff --git a/search-provider/cc-search-provider.h b/search-provider/cc-search-provider.h
new file mode 100644
index 0000000..f3084ac
--- /dev/null
+++ b/search-provider/cc-search-provider.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2012 Giovanni Campagna <scampa.giovanni@gmail.com>
+ *
+ * The Control Center 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 2 of the License, or (at your
+ * option) any later version.
+ *
+ * The Control Center 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 the Control Center; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef _CC_SEARCH_PROVIDER_H
+#define _CC_SEARCH_PROVIDER_H
+
+#include <glib-object.h>
+#include <gio/gio.h>
+#include "cc-shell-search-provider-generated.h"
+#include <shell/cc-shell-model.h>
+
+G_BEGIN_DECLS
+
+#define CC_TYPE_SEARCH_PROVIDER cc_search_provider_get_type()
+
+#define CC_SEARCH_PROVIDER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  CC_TYPE_SEARCH_PROVIDER, CcSearchProvider))
+
+#define CC_SEARCH_PROVIDER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  CC_TYPE_SEARCH_PROVIDER, CcSearchProviderClass))
+
+#define CC_IS_SEARCH_PROVIDER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  CC_TYPE_SEARCH_PROVIDER))
+
+#define CC_IS_SEARCH_PROVIDER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  CC_TYPE_SEARCH_PROVIDER))
+
+#define CC_SEARCH_PROVIDER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  CC_TYPE_SEARCH_PROVIDER, CcSearchProviderClass))
+
+typedef struct _CcSearchProvider CcSearchProvider;
+typedef struct _CcSearchProviderClass CcSearchProviderClass;
+
+GType cc_search_provider_get_type (void) G_GNUC_CONST;
+
+CcSearchProvider *cc_search_provider_new (void);
+
+gboolean cc_search_provider_dbus_register   (CcSearchProvider  *provider,
+                                             GDBusConnection   *connection,
+                                             const char        *object_path,
+                                             GError           **error);
+void     cc_search_provider_dbus_unregister (CcSearchProvider  *provider,
+                                             GDBusConnection   *connection,
+                                             const char        *object_path);
+
+G_END_DECLS
+
+#endif /* _CC_SEARCH_PROVIDER_H */
diff --git a/search-provider/control-center-search-provider.c b/search-provider/control-center-search-provider.c
new file mode 100644
index 0000000..1e3f6d7
--- /dev/null
+++ b/search-provider/control-center-search-provider.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2012 Giovanni Campagna <scampa.giovanni@gmail.com>
+ *
+ * The Control Center 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 2 of the License, or (at your
+ * option) any later version.
+ *
+ * The Control Center 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 the Control Center; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <stdlib.h>
+
+#include <gio/gio.h>
+
+#include <shell/cc-panel-list.h>
+#include <shell/cc-shell-model.h>
+#include "cc-search-provider.h"
+#include "control-center-search-provider.h"
+
+G_DEFINE_TYPE (CcSearchProviderApp, cc_search_provider_app, GTK_TYPE_APPLICATION);
+
+static gboolean
+cc_search_provider_app_dbus_register (GApplication    *application,
+                                      GDBusConnection *connection,
+                                      const gchar     *object_path,
+                                      GError         **error)
+{
+  CcSearchProviderApp *self;
+
+  if (!G_APPLICATION_CLASS (cc_search_provider_app_parent_class)->dbus_register (application,
+                                                                                   connection,
+                                                                                   object_path,
+                                                                                   error))
+    return FALSE;
+
+  self = CC_SEARCH_PROVIDER_APP (application);
+
+  return cc_search_provider_dbus_register (self->search_provider, connection,
+                                           object_path, error);
+}
+
+static void
+cc_search_provider_app_dbus_unregister (GApplication    *application,
+                                        GDBusConnection *connection,
+                                        const gchar     *object_path)
+{
+  CcSearchProviderApp *self;
+
+  self = CC_SEARCH_PROVIDER_APP (application);
+  if (self->search_provider)
+    cc_search_provider_dbus_unregister (self->search_provider, connection, object_path);
+
+  G_APPLICATION_CLASS (cc_search_provider_app_parent_class)->dbus_unregister (application,
+                                                                              connection,
+                                                                              object_path);
+}
+
+static void
+cc_search_provider_app_dispose (GObject *object)
+{
+  CcSearchProviderApp *self;
+
+  self = CC_SEARCH_PROVIDER_APP (object);
+
+  g_clear_object (&self->model);
+  g_clear_object (&self->search_provider);
+
+  G_OBJECT_CLASS (cc_search_provider_app_parent_class)->dispose (object);
+}
+
+static void
+cc_search_provider_app_init (CcSearchProviderApp *self)
+{
+  self->model = cc_shell_model_new ();
+  cc_panel_list_fill_model (self->model);
+
+  self->search_provider = cc_search_provider_new ();
+
+  g_application_set_inactivity_timeout (G_APPLICATION (self),
+                                        60 * 1000);
+  g_application_hold (G_APPLICATION (self));
+}
+
+static void
+cc_search_provider_app_class_init (CcSearchProviderAppClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GApplicationClass *app_class = G_APPLICATION_CLASS (klass);
+
+  object_class->dispose = cc_search_provider_app_dispose;
+
+  app_class->dbus_register = cc_search_provider_app_dbus_register;
+  app_class->dbus_unregister = cc_search_provider_app_dbus_unregister;
+}
+
+CcShellModel *
+cc_search_provider_app_get_model (CcSearchProviderApp *application)
+{
+  return application->model;
+}
+
+CcSearchProviderApp *
+cc_search_provider_app_get ()
+{
+  static CcSearchProviderApp *singleton;
+
+  if (singleton)
+    return singleton;
+
+  singleton = g_object_new (CC_TYPE_SEARCH_PROVIDER_APP,
+                            "application-id", "org.gnome.ControlCenter.SearchProvider",
+                            "flags", G_APPLICATION_IS_SERVICE,
+                            NULL);
+
+  return singleton;
+}
+
+int main (int argc, char **argv)
+{
+  GApplication *app;
+
+  app = G_APPLICATION (cc_search_provider_app_get ());
+  return g_application_run (app, argc, argv);
+}
diff --git a/search-provider/control-center-search-provider.h b/search-provider/control-center-search-provider.h
new file mode 100644
index 0000000..9b97b0c
--- /dev/null
+++ b/search-provider/control-center-search-provider.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012 Giovanni Campagna <scampa.giovanni@gmail.com>
+ *
+ * The Control Center 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 2 of the License, or (at your
+ * option) any later version.
+ *
+ * The Control Center 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 the Control Center; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef _CONTROL_CENTER_SEARCH_PROVIDER_H
+#define _CONTROL_CENTER_SEARCH_PROVIDER_H
+
+#include <gtk/gtk.h>
+
+#include <shell/cc-shell-model.h>
+#include "cc-search-provider.h"
+
+typedef struct {
+  GtkApplication parent;
+
+  CcShellModel     *model;
+  CcSearchProvider *search_provider;
+} CcSearchProviderApp;
+
+typedef struct {
+  GtkApplicationClass parent_class;
+} CcSearchProviderAppClass;
+
+#define CC_TYPE_SEARCH_PROVIDER_APP cc_search_provider_app_get_type ()
+
+#define CC_SEARCH_PROVIDER_APP(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  GNOME_TYPE_CONTROL_CENTER_APP, CcSearchProviderApp))
+
+GType cc_search_provider_app_get_type (void) G_GNUC_CONST;
+
+CcSearchProviderApp *cc_search_provider_app_get (void);
+
+CcShellModel *cc_search_provider_app_get_model (CcSearchProviderApp *application);
+
+#endif
diff --git a/search-provider/gnome-control-center-search-provider.ini b/search-provider/gnome-control-center-search-provider.ini
new file mode 100644
index 0000000..7923033
--- /dev/null
+++ b/search-provider/gnome-control-center-search-provider.ini
@@ -0,0 +1,5 @@
+[Shell Search Provider]
+DesktopId=gnome-control-center.desktop
+BusName=org.gnome.ControlCenter.SearchProvider
+ObjectPath=/org/gnome/ControlCenter/SearchProvider
+Version=2
diff --git a/search-provider/org.gnome.ControlCenter.SearchProvider.service.in b/search-provider/org.gnome.ControlCenter.SearchProvider.service.in
new file mode 100644
index 0000000..81dd0c8
--- /dev/null
+++ b/search-provider/org.gnome.ControlCenter.SearchProvider.service.in
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.gnome.ControlCenter.SearchProvider
+Exec=@libexecdir@/gnome-control-center-search-provider
\ No newline at end of file
diff --git a/search-provider/org.gnome.ShellSearchProvider2.xml b/search-provider/org.gnome.ShellSearchProvider2.xml
new file mode 100644
index 0000000..26b213d
--- /dev/null
+++ b/search-provider/org.gnome.ShellSearchProvider2.xml
@@ -0,0 +1,87 @@
+<!DOCTYPE node PUBLIC
+'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
+'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
+<node>
+
+  <!--
+      org.gnome.Shell.SearchProvider2:
+      @short_description: Search provider interface
+
+      The interface used for integrating into GNOME Shell's search
+      interface (version 2).
+  -->
+  <interface name="org.gnome.Shell.SearchProvider2">
+
+    <!--
+        GetInitialResultSet:
+        @terms: Array of search terms, which the provider should treat as logical AND.
+        @results: An array of result identifier strings representing items which match the given search terms. Identifiers must be unique within the provider's domain, but other than that may be chosen freely by the provider.
+
+        Called when the user first begins a search.
+    -->
+    <method name="GetInitialResultSet">
+      <arg type="as" name="terms" direction="in" />
+      <arg type="as" name="results" direction="out" />
+    </method>
+
+    <!--
+        GetSubsearchResultSet:
+        @previous_results: Array of results previously returned by GetInitialResultSet().
+        @terms: Array of updated search terms, which the provider should treat as logical AND.
+        @results: An array of result identifier strings representing items which match the given search terms. Identifiers must be unique within the provider's domain, but other than that may be chosen freely by the provider.
+
+        Called when a search is performed which is a "subsearch" of
+        the previous search, e.g. the method may return less results, but
+        not more or different results.
+
+        This allows search providers to only search through the previous
+        result set, rather than possibly performing a full re-query.
+    -->
+    <method name="GetSubsearchResultSet">
+      <arg type="as" name="previous_results" direction="in" />
+      <arg type="as" name="terms" direction="in" />
+      <arg type="as" name="results" direction="out" />
+    </method>
+
+    <!--
+        GetResultMetas:
+        @identifiers: An array of result identifiers as returned by GetInitialResultSet() or GetSubsearchResultSet()
+        @metas: A dictionary describing the given search result, containing 'id' and 'name' (both strings). Optionally, either 'gicon' (a serialized GIcon) or 'icon-data' (raw image data as (iiibiiay) - width, height, rowstride, has-alpha, bits per sample, channels, data) can be specified if the result can be better served with a thumbnail of the content (such as with images). A 'description' field (string) may also be specified if more context would help the user find the desired result.
+
+        Return an array of meta data used to display each given result
+    -->
+    <method name="GetResultMetas">
+      <arg type="as" name="identifiers" direction="in" />
+      <arg type="aa{sv}" name="metas" direction="out" />
+    </method>
+
+    <!--
+        ActivateResult:
+        @identifier: A result identifier as returned by GetInitialResultSet() or GetSubsearchResultSet()
+        @terms: Array of search terms, which the provider should treat as logical AND.
+        @timestamp: A timestamp of the user interaction that triggered this call
+
+        Called when the users chooses a given result. The result should
+        be displayed in the application associated with the corresponding
+        provider. The provided search terms can be used to allow launching a full search in
+        the application.
+    -->
+    <method name="ActivateResult">
+      <arg type="s" name="identifier" direction="in" />
+      <arg type="as" name="terms" direction="in" />
+      <arg type="u" name="timestamp" direction="in" />
+    </method>
+
+    <!--
+        LaunchSearch:
+        @terms: Array of search terms, which the provider should treat as logical AND.
+        @timestamp: A timestamp of the user interaction that triggered this call
+
+        Asks the search provider to launch a full search in the application for the provided terms.
+    -->
+    <method name="LaunchSearch">
+      <arg type="as" name="terms" direction="in" />
+      <arg type="u" name="timestamp" direction="in" />
+    </method>
+  </interface>
+</node>
diff --git a/shell/Makefile.am b/shell/Makefile.am
index 024d671..cda64d7 100644
--- a/shell/Makefile.am
+++ b/shell/Makefile.am
@@ -6,6 +6,16 @@ INCLUDES =					\
 
 all-local: check-local
 
+noinst_LTLIBRARIES = libshell.la
+
+libshell_la_SOURCES = \
+	cc-shell-model.c			\
+	cc-shell-model.h			\
+	cc-panel-list.c				\
+	cc-panel-list.h				\
+	cc-util.c				\
+	cc-util.h
+
 bin_PROGRAMS = gnome-control-center
 
 BUILT_SOURCES =			\
@@ -23,8 +33,6 @@ gnome_control_center_SOURCES =			\
 	cc-shell-category-view.h		\
 	cc-shell-item-view.c			\
 	cc-shell-item-view.h			\
-	cc-shell-model.c			\
-	cc-shell-model.h			\
 	cc-editable-entry.c			\
 	cc-editable-entry.h			\
 	cc-panel-loader.c			\
@@ -33,8 +41,6 @@ gnome_control_center_SOURCES =			\
 	cc-panel.h				\
 	cc-shell.c				\
 	cc-shell.h				\
-	cc-util.c				\
-	cc-util.h				\
 	hostname-helper.c			\
 	hostname-helper.h			\
 	cc-hostname-entry.c			\
@@ -44,6 +50,7 @@ gnome_control_center_SOURCES =			\
 gnome_control_center_LDFLAGS = -export-dynamic
 
 gnome_control_center_LDADD =						\
+	libshell.la							\
 	$(SHELL_LIBS)							\
 	$(CHEESE_LIBS)							\
 	$(top_builddir)/libgd/libgd.la					\
@@ -132,5 +139,4 @@ EXTRA_DIST += hostnames-test.txt
 check-local: test-hostname
 	$(builddir)/test-hostname $(srcdir)/hostnames-test.txt > /dev/null
 
-
 -include $(top_srcdir)/git.mk
diff --git a/shell/cc-panel-list.c b/shell/cc-panel-list.c
new file mode 100644
index 0000000..6d73268
--- /dev/null
+++ b/shell/cc-panel-list.c
@@ -0,0 +1,134 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (c) 2012 Giovanni Campagna <scampa.giovanni@gmail.com>
+ *
+ * The Control Center 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 2 of the License, or (at your
+ * option) any later version.
+ *
+ * The Control Center 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 the Control Center; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <gio/gdesktopappinfo.h>
+
+#include "cc-panel-list.h"
+
+const char *all_panels[] = {
+  "background",
+#ifdef BUILD_BLUETOOTH
+  "bluetooth",
+#endif
+  "color",
+  "datetime",
+  "display",
+  "info",
+  "keyboard",
+  "mouse",
+#ifdef BUILD_NETWORK
+  "network",
+#endif
+  "notifications",
+  "online-accounts",
+  "power",
+#ifdef BUILD_PRINTERS
+  "printers",
+#endif
+  "privacy",
+  "region",
+  "search",
+  "sharing",
+  "sound",
+  "universal-access",
+  "user-accounts",
+#ifdef BUILD_WACOM
+  "wacom",
+#endif
+};
+
+GList *
+cc_panel_list_get_panels (void)
+{
+  GList *l = NULL;
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (all_panels); i++)
+    l = g_list_prepend (l, (gpointer) all_panels[i]);
+
+  return g_list_reverse (l);
+}
+
+static int
+parse_categories (GDesktopAppInfo *app)
+{
+  const char *categories;
+  char **split;
+  int retval;
+  int i;
+
+  categories = g_desktop_app_info_get_categories (app);
+  split = g_strsplit (categories, ";", -1);
+
+  retval = -1;
+
+  for (i = 0; split[i]; i++)
+    {
+      if (strcmp (split[i], "HardwareSettings") == 0)
+        retval = CC_CATEGORY_HARDWARE;
+      else if (strcmp (split[i], "X-GNOME-PersonalSettings") == 0)
+        retval = CC_CATEGORY_PERSONAL;
+      else if (strcmp (split[i], "X-GNOME-SystemSettings") == 0)
+        retval = CC_CATEGORY_SYSTEM;
+    }
+
+  if (retval < 0)
+    {
+      g_warning ("Invalid categories %s for panel %s",
+                 categories, g_app_info_get_id (G_APP_INFO (app)));
+    }
+
+  g_strfreev (split);
+  return retval;
+}
+
+void
+cc_panel_list_fill_model (CcShellModel *model)
+{
+  int i;
+
+  for (i = 0; i < G_N_ELEMENTS (all_panels); i++)
+    {
+      GDesktopAppInfo *app;
+      char *desktop_name;
+      int category;
+
+      desktop_name = g_strconcat ("gnome-", all_panels[i],
+                                  "-panel.desktop", NULL);
+      app = g_desktop_app_info_new (desktop_name);
+
+      if (app == NULL)
+        {
+          g_warning ("Ignoring broken panel %s (missing desktop file)",
+                     all_panels[i]);
+          continue;
+        }
+
+      category = parse_categories (app);
+      if (G_UNLIKELY (category < 0))
+        continue;
+
+      cc_shell_model_add_item (model, category, G_APP_INFO (app), all_panels[i]);
+      g_object_unref (app);
+    }
+}
diff --git a/shell/cc-panel-list.h b/shell/cc-panel-list.h
new file mode 100644
index 0000000..bafa74f
--- /dev/null
+++ b/shell/cc-panel-list.h
@@ -0,0 +1,34 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (c) 2012 Giovanni Campagna <scampa.giovanni@gmail.com>
+ *
+ * The Control Center 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 2 of the License, or (at your
+ * option) any later version.
+ *
+ * The Control Center 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 the Control Center; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef _CC_PANEL_LIST_H
+#define _CC_PANEL_LIST_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <shell/cc-panel.h>
+#include <shell/cc-shell-model.h>
+
+G_BEGIN_DECLS
+
+void     cc_panel_list_fill_model     (CcShellModel  *model);
+GList   *cc_panel_list_get_panels     (void);
+
+#endif
diff --git a/shell/cc-panel-loader.c b/shell/cc-panel-loader.c
index 1755072..e103356 100644
--- a/shell/cc-panel-loader.c
+++ b/shell/cc-panel-loader.c
@@ -94,82 +94,6 @@ static struct {
 
 static GHashTable *panel_types;
 
-GList *
-cc_panel_loader_get_panels (void)
-{
-  GList *l = NULL;
-  guint i;
-
-  for (i = 0; i < G_N_ELEMENTS (all_panels); i++)
-    l = g_list_prepend (l, (gpointer) all_panels[i].name);
-
-  return g_list_reverse (l);
-}
-
-static int
-parse_categories (GDesktopAppInfo *app)
-{
-  const char *categories;
-  char **split;
-  int retval;
-  int i;
-
-  categories = g_desktop_app_info_get_categories (app);
-  split = g_strsplit (categories, ";", -1);
-
-  retval = -1;
-
-  for (i = 0; split[i]; i++)
-    {
-      if (strcmp (split[i], "HardwareSettings") == 0)
-        retval = CC_CATEGORY_HARDWARE;
-      else if (strcmp (split[i], "X-GNOME-PersonalSettings") == 0)
-        retval = CC_CATEGORY_PERSONAL;
-      else if (strcmp (split[i], "X-GNOME-SystemSettings") == 0)
-        retval = CC_CATEGORY_SYSTEM;
-    }
-
-  if (retval < 0)
-    {
-      g_warning ("Invalid categories %s for panel %s",
-                 categories, g_app_info_get_id (G_APP_INFO (app)));
-    }
-
-  g_strfreev (split);
-  return retval;
-}
-
-void
-cc_panel_loader_fill_model (CcShellModel *model)
-{
-  int i;
-
-  for (i = 0; i < G_N_ELEMENTS (all_panels); i++)
-    {
-      GDesktopAppInfo *app;
-      char *desktop_name;
-      int category;
-
-      desktop_name = g_strconcat ("gnome-", all_panels[i].name,
-                                  "-panel.desktop", NULL);
-      app = g_desktop_app_info_new (desktop_name);
-
-      if (app == NULL)
-        {
-          g_warning ("Ignoring broken panel %s (missing desktop file)",
-                     all_panels[i].name);
-          continue;
-        }
-
-      category = parse_categories (app);
-      if (G_UNLIKELY (category < 0))
-        continue;
-
-      cc_shell_model_add_item (model, category, G_APP_INFO (app), all_panels[i].name);
-      g_object_unref (app);
-    }
-}
-
 static void
 ensure_panel_types (void)
 {
diff --git a/shell/cc-panel-loader.h b/shell/cc-panel-loader.h
index bee1657..8936e6c 100644
--- a/shell/cc-panel-loader.h
+++ b/shell/cc-panel-loader.h
@@ -28,8 +28,6 @@
 
 G_BEGIN_DECLS
 
-void     cc_panel_loader_fill_model     (CcShellModel  *model);
-GList   *cc_panel_loader_get_panels     (void);
 CcPanel *cc_panel_loader_load_by_name   (CcShell       *shell,
                                          const char    *name,
                                          const char   **argv);
diff --git a/shell/control-center.c b/shell/control-center.c
index c082aa9..7f3bb68 100644
--- a/shell/control-center.c
+++ b/shell/control-center.c
@@ -40,7 +40,11 @@
 #include <cheese-gtk.h>
 #endif /* HAVE_CHEESE */
 
+#include "control-center.h"
+#include "gnome-control-center.h"
 #include "cc-shell-log.h"
+#include "cc-panel-loader.h"
+#include "cc-panel-list.h"
 
 G_GNUC_NORETURN static gboolean
 option_version_cb (const gchar *option_name,
@@ -74,17 +78,42 @@ const GOptionEntry all_options[] = {
   { NULL, 0, 0, 0, NULL, NULL, NULL } /* end the list */
 };
 
+G_DEFINE_TYPE (CcApplication, cc_application, GTK_TYPE_APPLICATION)
+
+GnomeControlCenter *
+cc_application_get_view (CcApplication *app)
+{
+  if (!app->view)
+    app->view = gnome_control_center_new (app->model);
+
+  return app->view;
+}
+
+void
+cc_application_destroy_view (CcApplication *app)
+{
+  g_clear_object (&app->view);
+}
+
+CcShellModel *
+cc_application_get_model (CcApplication *app)
+{
+  return app->model;
+}
+
 static int
-application_command_line_cb (GApplication  *application,
-                             GApplicationCommandLine  *command_line,
-                             GnomeControlCenter      *shell)
+cc_application_command_line (GApplication             *application,
+                             GApplicationCommandLine  *command_line)
 {
+  CcApplication *self;
+  GnomeControlCenter *shell;
   int argc;
   char **argv;
   int retval = 0;
   GOptionContext *context;
   GError *error = NULL;
 
+  self = CC_APPLICATION (application);
   verbose = FALSE;
   show_overview = FALSE;
   show_help = FALSE;
@@ -118,7 +147,7 @@ application_command_line_cb (GApplication  *application,
         group = gtk_get_option_group (FALSE);
 
       help = g_option_context_get_help (context, FALSE, group);
-      g_print ("%s", help);
+      g_application_command_line_print (command_line, "%s", help);
       g_free (help);
       g_option_context_free (context);
       return 0;
@@ -128,7 +157,7 @@ application_command_line_cb (GApplication  *application,
     {
       GList *panels, *l;
 
-      panels = cc_panel_loader_get_panels ();
+      panels = cc_panel_list_get_panels ();
 
       g_print ("%s\n", _("Available panels:"));
       for (l = panels; l != NULL; l = l->next)
@@ -147,6 +176,7 @@ application_command_line_cb (GApplication  *application,
 
   cc_shell_log_set_debug (verbose);
 
+  shell = cc_application_get_view (self);
   gnome_control_center_show (shell, GTK_APPLICATION (application));
 
   if (search_str)
@@ -165,9 +195,9 @@ application_command_line_cb (GApplication  *application,
       start_id = start_panels[0];
 
       if (start_panels[1])
-	g_debug ("Extra argument: %s", start_panels[1]);
+        g_debug ("Extra argument: %s", start_panels[1]);
       else
-	g_debug ("No extra argument");
+        g_debug ("No extra argument");
 
       if (!cc_shell_set_active_panel_from_id (CC_SHELL (shell), start_id, (const gchar**)start_panels+1, &err))
         {
@@ -201,11 +231,17 @@ help_activated (GSimpleAction *action,
                 GVariant      *parameter,
                 gpointer       user_data)
 {
-  GnomeControlCenter *shell = user_data;
-  CcPanel *panel = cc_shell_get_active_panel (CC_SHELL (shell));
-  GtkWidget *window = cc_shell_get_toplevel (CC_SHELL (shell));
+  CcApplication *self;
+  GnomeControlCenter *shell;
+  CcPanel *panel;
+  GtkWidget *window;
   const char *uri = NULL;
 
+  self = CC_APPLICATION (user_data);
+  shell = cc_application_get_view (self);
+  panel = cc_shell_get_active_panel (CC_SHELL (shell));
+  window  = cc_shell_get_toplevel (CC_SHELL (shell));
+
   if (panel)
     uri = cc_panel_get_help_uri (panel);
 
@@ -219,24 +255,44 @@ quit_activated (GSimpleAction *action,
                 GVariant      *parameter,
                 gpointer       user_data)
 {
-  GnomeControlCenter *shell = user_data;
-  g_object_unref (shell);
+  cc_application_destroy_view (CC_APPLICATION (user_data));
 }
 
 static void
-application_startup_cb (GApplication       *application,
-                        GnomeControlCenter *shell)
+cc_application_startup (GApplication *application)
 {
+  CcApplication *self;
   GMenu *menu, *section;
   GAction *action;
 
+#ifdef GDK_WINDOWING_X11
+  XInitThreads ();
+#endif
+
+  G_APPLICATION_CLASS (cc_application_parent_class)->startup (application);
+
+  self = CC_APPLICATION (application);
+
+  /* Ensure that the timeout is started */
+  g_application_hold (application);
+  g_application_release (application);
+
+  /* register a symbolic icon size for use in sidebar lists */
+  gtk_icon_size_register ("cc-sidebar-list", 24, 24);
+  g_type_ensure (egg_list_box_get_type ());
+
+  notify_init ("gnome-control-center");
+
+  self->model = cc_shell_model_new ();
+  cc_panel_list_fill_model (self->model);
+
   action = G_ACTION (g_simple_action_new ("help", NULL));
   g_action_map_add_action (G_ACTION_MAP (application), action);
-  g_signal_connect (action, "activate", G_CALLBACK (help_activated), shell);
+  g_signal_connect (action, "activate", G_CALLBACK (help_activated), application);
 
   action = G_ACTION (g_simple_action_new ("quit", NULL));
   g_action_map_add_action (G_ACTION_MAP (application), action);
-  g_signal_connect (action, "activate", G_CALLBACK (quit_activated), shell);
+  g_signal_connect (action, "activate", G_CALLBACK (quit_activated), application);
 
   menu = g_menu_new ();
 
@@ -257,41 +313,67 @@ application_startup_cb (GApplication       *application,
    */
 }
 
+static void
+cc_application_dispose (GObject *object)
+{
+  CcApplication *self;
+
+  self = CC_APPLICATION (object);
+
+  g_clear_object (&self->model);
+  cc_application_destroy_view (self);
+
+  G_OBJECT_CLASS (cc_application_parent_class)->dispose (object);
+}
+
+static void
+cc_application_init (CcApplication *app)
+{
+}
+
+static void
+cc_application_class_init (CcApplicationClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GApplicationClass *app_class = G_APPLICATION_CLASS (klass);
+
+  object_class->dispose = cc_application_dispose;
+
+  app_class->command_line = cc_application_command_line;
+  app_class->startup = cc_application_startup;
+}
+
+CcApplication *
+cc_application_get ()
+{
+  static CcApplication *singleton;
+
+  if (singleton)
+    return singleton;
+
+  singleton = g_object_new (CC_TYPE_APPLICATION,
+                            "application-id", "org.gnome.ControlCenter",
+                            "flags", G_APPLICATION_HANDLES_COMMAND_LINE,
+                            NULL);
+  return singleton;
+}
+
 int
 main (int argc, char **argv)
 {
-  GnomeControlCenter *shell;
-  GtkApplication *application;
+  GApplication *application;
   int status;
 
   bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
   textdomain (GETTEXT_PACKAGE);
 
-#ifdef GDK_WINDOWING_X11
-  XInitThreads ();
-#endif
-
-  gtk_init (&argc, &argv);
+  setlocale (LC_ALL, "");
   cc_shell_log_init ();
 
-  g_type_ensure (egg_list_box_get_type ());
-
-  /* register a symbolic icon size for use in sidebar lists */
-  gtk_icon_size_register ("cc-sidebar-list", 24, 24);
-
-  notify_init ("gnome-control-center");
-
-  shell = gnome_control_center_new ();
-
   /* enforce single instance of this application */
-  application = gtk_application_new ("org.gnome.ControlCenter", G_APPLICATION_HANDLES_COMMAND_LINE);
-  g_signal_connect (application, "startup",
-                    G_CALLBACK (application_startup_cb), shell);
-  g_signal_connect (application, "command-line",
-                    G_CALLBACK (application_command_line_cb), shell);
-
-  status = g_application_run (G_APPLICATION (application), argc, argv);
+  application = G_APPLICATION (cc_application_get ());
+  status = g_application_run (application, argc, argv);
 
   g_object_unref (application);
 
diff --git a/shell/control-center.h b/shell/control-center.h
new file mode 100644
index 0000000..a08ad46
--- /dev/null
+++ b/shell/control-center.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2012 Giovanni Campagna <scampa.giovanni@gmail.com>
+ *
+ * The Control Center 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 2 of the License, or (at your
+ * option) any later version.
+ *
+ * The Control Center 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 the Control Center; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef _CONTROL_CENTER_H
+#define _CONTROL_CENTER_H
+
+#include <glib-object.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include "gnome-control-center.h"
+#include "cc-shell-model.h"
+
+G_BEGIN_DECLS
+
+typedef struct _CcApplication      CcApplication;
+typedef struct _CcApplicationClass CcApplicationClass;
+
+#define CC_TYPE_APPLICATION cc_application_get_type ()
+
+#define CC_APPLICATION(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  GNOME_TYPE_CONTROL_CENTER_APP, CcApplication))
+
+struct _CcApplication {
+  GtkApplication parent;
+
+  CcShellModel       *model;
+  GnomeControlCenter *view;
+};
+
+struct _CcApplicationClass {
+  GtkApplicationClass parent_class;
+};
+
+GType cc_application_get_type (void) G_GNUC_CONST;
+
+CcApplication *cc_application_get (void);
+
+GnomeControlCenter    *cc_application_get_view  (CcApplication *app);
+CcShellModel          *cc_application_get_model (CcApplication *app);
+
+void                   cc_application_destroy_view (CcApplication *app);
+
+G_END_DECLS
+
+#endif /* _CONTROL_CENTER_H */
diff --git a/shell/gnome-control-center.c b/shell/gnome-control-center.c
index 064776c..3652286 100644
--- a/shell/gnome-control-center.c
+++ b/shell/gnome-control-center.c
@@ -42,6 +42,7 @@
 #include "cc-shell-model.h"
 #include "cc-panel-loader.h"
 #include "cc-util.h"
+#include "control-center.h"
 
 G_DEFINE_TYPE (GnomeControlCenter, gnome_control_center, CC_TYPE_SHELL)
 
@@ -93,6 +94,14 @@ struct _GnomeControlCenterPrivate
   CcSmallScreen small_screen;
 };
 
+enum {
+  PROP_0,
+  PROP_MODEL,
+  PROP_LAST
+};
+
+static void gnome_control_center_constructed (GObject *object);
+
 /* Notebook helpers */
 static GtkWidget *
 notebook_get_selected_page (GtkWidget *notebook)
@@ -872,8 +881,6 @@ add_category_view (GnomeControlCenter *shell,
 static void
 setup_model (GnomeControlCenter *shell)
 {
-  GnomeControlCenterPrivate *priv = shell->priv;
-
   gtk_widget_set_margin_top (shell->priv->main_vbox, 8);
   gtk_widget_set_margin_bottom (shell->priv->main_vbox, 8);
   gtk_widget_set_margin_left (shell->priv->main_vbox, 12);
@@ -881,14 +888,10 @@ setup_model (GnomeControlCenter *shell)
   gtk_container_set_focus_vadjustment (GTK_CONTAINER (shell->priv->main_vbox),
                                        gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (shell->priv->scrolled_window)));
 
-  priv->store = (GtkListStore *) cc_shell_model_new ();
-
   /* Add categories */
   add_category_view (shell, CC_CATEGORY_PERSONAL, C_("category", "Personal"));
   add_category_view (shell, CC_CATEGORY_HARDWARE, C_("category", "Hardware"));
   add_category_view (shell, CC_CATEGORY_SYSTEM, C_("category", "System"));
-
-  cc_panel_loader_fill_model (CC_SHELL_MODEL (shell->priv->store));
 }
 
 static void
@@ -1064,8 +1067,14 @@ gnome_control_center_set_property (GObject      *object,
                                    const GValue *value,
                                    GParamSpec   *pspec)
 {
+  GnomeControlCenter *self = GNOME_CONTROL_CENTER (object);
+  GnomeControlCenterPrivate *priv = self->priv;
+
   switch (property_id)
     {
+    case PROP_MODEL:
+      priv->store = g_value_dup_object (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     }
@@ -1154,10 +1163,17 @@ gnome_control_center_class_init (GnomeControlCenterClass *klass)
   object_class->set_property = gnome_control_center_set_property;
   object_class->dispose = gnome_control_center_dispose;
   object_class->finalize = gnome_control_center_finalize;
+  object_class->constructed = gnome_control_center_constructed;
 
   shell_class->set_active_panel_from_id = _shell_set_active_panel_from_id;
   shell_class->embed_widget_in_header = _shell_embed_widget_in_header;
   shell_class->get_toplevel = _shell_get_toplevel;
+
+  g_object_class_install_property (object_class, PROP_MODEL,
+                                   g_param_spec_object ("model",
+                                                        "", "",
+                                                        CC_TYPE_SHELL_MODEL,
+                                                        G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
 }
 
 static gboolean
@@ -1347,10 +1363,7 @@ gdk_window_set_cb (GObject    *object,
 static void
 gnome_control_center_init (GnomeControlCenter *self)
 {
-  GError *err = NULL;
   GnomeControlCenterPrivate *priv;
-  GdkScreen *screen;
-  GtkWidget *frame;
 
   priv = self->priv = CONTROL_CENTER_PRIVATE (self);
 
@@ -1364,6 +1377,31 @@ gnome_control_center_init (GnomeControlCenter *self)
 
   priv->monitor_num = -1;
   self->priv->small_screen = SMALL_SCREEN_UNSET;
+}
+
+static gboolean
+on_window_delete (GtkWindow *window,
+                  GdkEvent  *event,
+                  gpointer   data)
+{
+  CcApplication *app;
+
+  app = cc_application_get ();
+  cc_application_destroy_view (app);
+  return TRUE;
+}
+
+static void
+gnome_control_center_constructed (GObject *object)
+{
+  GError *err = NULL;
+  GnomeControlCenter *self;
+  GnomeControlCenterPrivate *priv;
+  GdkScreen *screen;
+  GtkWidget *frame;
+
+  self = GNOME_CONTROL_CENTER (object);
+  priv = self->priv;
 
   /* load the user interface */
   priv->builder = gtk_builder_new ();
@@ -1383,7 +1421,7 @@ gnome_control_center_init (GnomeControlCenter *self)
   g_signal_connect (screen, "monitors-changed", G_CALLBACK (monitors_changed_cb), self);
   g_signal_connect (priv->window, "configure-event", G_CALLBACK (main_window_configure_cb), self);
   g_signal_connect (priv->window, "notify::application", G_CALLBACK (application_set_cb), self);
-  g_signal_connect_swapped (priv->window, "delete-event", G_CALLBACK (g_object_unref), self);
+  g_signal_connect (priv->window, "delete-event", G_CALLBACK (on_window_delete), self);
   g_signal_connect_after (priv->window, "key_press_event",
                           G_CALLBACK (window_key_press_event), self);
   g_signal_connect (priv->window, "notify::window", G_CALLBACK (gdk_window_set_cb), self);
@@ -1424,16 +1462,17 @@ gnome_control_center_init (GnomeControlCenter *self)
   notebook_page_notify_cb (GTK_NOTEBOOK (priv->notebook), NULL, priv);
 }
 
-GnomeControlCenter *
-gnome_control_center_new (void)
+void
+gnome_control_center_present (GnomeControlCenter *center)
 {
-  return g_object_new (GNOME_TYPE_CONTROL_CENTER, NULL);
+  gtk_window_present (GTK_WINDOW (center->priv->window));
 }
 
 void
-gnome_control_center_present (GnomeControlCenter *center)
+gnome_control_center_present_with_time (GnomeControlCenter *center,
+                                        int                 timestamp)
 {
-  gtk_window_present (GTK_WINDOW (center->priv->window));
+  gtk_window_present_with_time (GTK_WINDOW (center->priv->window), timestamp);
 }
 
 void
@@ -1443,3 +1482,11 @@ gnome_control_center_show (GnomeControlCenter *center,
   gtk_window_set_application (GTK_WINDOW (center->priv->window), app);
   gtk_widget_show (gtk_bin_get_child (GTK_BIN (center->priv->window)));
 }
+
+GnomeControlCenter *
+gnome_control_center_new (CcShellModel *model)
+{
+  return g_object_new (GNOME_TYPE_CONTROL_CENTER,
+                       "model", model,
+                       NULL);
+}
diff --git a/shell/gnome-control-center.h b/shell/gnome-control-center.h
index c3e1e23..43539b0 100644
--- a/shell/gnome-control-center.h
+++ b/shell/gnome-control-center.h
@@ -23,6 +23,7 @@
 
 #include <glib-object.h>
 #include "cc-shell.h"
+#include "cc-shell-model.h"
 
 G_BEGIN_DECLS
 
@@ -66,11 +67,14 @@ struct _GnomeControlCenterClass
 
 GType gnome_control_center_get_type (void) G_GNUC_CONST;
 
-GnomeControlCenter *gnome_control_center_new (void);
+GnomeControlCenter *gnome_control_center_new (CcShellModel *model);
 
-void gnome_control_center_present (GnomeControlCenter *center);
+void gnome_control_center_present           (GnomeControlCenter *center);
+void gnome_control_center_present_with_time (GnomeControlCenter *center,
+                                             int                 timestamp);
 
-void gnome_control_center_show (GnomeControlCenter *center, GtkApplication *app);
+void gnome_control_center_show              (GnomeControlCenter *center,
+                                             GtkApplication     *app);
 
 void gnome_control_center_set_overview_page (GnomeControlCenter *center);
 
