diff --git a/protocol/idle.xml b/protocol/idle.xml
new file mode 100644
index 0000000000000000000000000000000000000000..92d9989c749746edd3ff276418690f693b7b3cc5
--- /dev/null
+++ b/protocol/idle.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="idle">
+  <copyright><![CDATA[
+    Copyright (C) 2015 Martin Gräßlin
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  ]]></copyright>
+  <interface  name="org_kde_kwin_idle" version="1">
+      <description summary="User idle time manager">
+        This interface allows to monitor user idle time on a given seat. The interface
+        allows to register timers which trigger after no user activity was registered
+        on the seat for a given interval. It notifies when user activity resumes.
+
+        This is useful for applications wanting to perform actions when the user is not
+        interacting with the system, e.g. chat applications setting the user as away, power
+        management features to dim screen, etc..
+      </description>
+      <request name="get_idle_timeout">
+        <arg name="id" type="new_id" interface="org_kde_kwin_idle_timeout"/>
+        <arg name="seat" type="object" interface="wl_seat"/>
+        <arg name="timeout" type="uint" summary="The idle timeout in msec"/>
+      </request>
+  </interface>
+  <interface name="org_kde_kwin_idle_timeout" version="1">
+      <request name="release" type="destructor">
+        <description summary="release the timeout object"/>
+      </request>
+      <request name="simulate_user_activity">
+          <description summary="Simulates user activity for this timeout, behaves just like real user activity on the seat"/>
+      </request>
+      <event name="idle">
+          <description summary="Triggered when there has not been any user activity in the requested idle time interval"/>
+      </event>
+      <event name="resumed">
+          <description summary="Triggered on the first user activity after an idle event"/>
+      </event>
+  </interface>
+</protocol>
diff --git a/src/meson.build b/src/meson.build
index f39de3e334425c85ed2ff6c559f4be6360e58570..18db65369d2b209255742cbe346c92b9266caeac 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -19,6 +19,7 @@ phosh_resources = gnome.compile_resources(
 
 wl_protos = [
   '/'.join([wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml']),
+  '../protocol/idle.xml',
   '../protocol/phosh-mobile-shell.xml',
   '../protocol/wlr-layer-shell-unstable-v1.xml',
 ]
diff --git a/src/phosh.c b/src/phosh.c
index fac7c2c3d5b984a46b97fbb4cecb86c28152d4e3..d150ed56908bd5555178b61c1ad5578c2d48cabb 100644
--- a/src/phosh.c
+++ b/src/phosh.c
@@ -18,6 +18,7 @@
 
 #include "config.h"
 
+#include "idle-client-protocol.h"
 #include "phosh-mobile-shell-client-protocol.h"
 #include "wlr-layer-shell-unstable-v1-client-protocol.h"
 
@@ -28,6 +29,9 @@
 #include "favorites.h"
 #include "settings.h"
 
+/* FIXME: use org.gnome.desktop.session.idle-delay */
+#define LOCKSCREEN_TIMEOUT 60 * 1000
+
 enum {
   PHOSH_SHELL_PROP_0,
   PHOSH_SHELL_PROP_ROTATION,
@@ -47,13 +51,12 @@ typedef struct
   struct wl_registry *registry;
   struct phosh_mobile_shell *mshell;
   struct zwlr_layer_shell_v1 *layer_shell;
+  struct org_kde_kwin_idle *idle_manager;
   struct wl_output *output;
 
-  struct wl_seat *seat;
-  struct wl_pointer *pointer;
-
   GdkDisplay *gdk_display;
   gint rotation;
+  struct wl_seat *seat;
 
   /* Top panel */
   struct elem *panel;
@@ -64,6 +67,7 @@ typedef struct
   /* Lockscreen */
   struct elem *lockscreen;
   gulong unlock_handler_id;
+  struct org_kde_kwin_idle_timeout *lock_timer;
 
   /* Favorites menu */
   struct elem *favorites;
@@ -116,6 +120,7 @@ lockscreen_unlock_cb (PhoshShell *self, PhoshLockscreen *window)
 
   g_signal_handler_disconnect (window, priv->unlock_handler_id);
   gtk_widget_destroy (GTK_WIDGET (window));
+  zwlr_layer_surface_v1_destroy(priv->lockscreen->layer_surface);
   g_free (priv->lockscreen);
   priv->lockscreen = NULL;
 #if 0
@@ -264,6 +269,49 @@ lockscreen_create (PhoshShell *self)
 }
 
 
+static void lock_idle_cb(void* data, struct org_kde_kwin_idle_timeout *timer)
+{
+  PhoshShell *self = data;
+  PhoshShellPrivate *priv = phosh_shell_get_instance_private (self);
+
+  g_return_if_fail (PHOSH_IS_SHELL (data));
+  if (!priv->lockscreen)
+    lockscreen_create(self);
+}
+
+
+static void lock_resume_cb(void* data, struct org_kde_kwin_idle_timeout *timer)
+{
+}
+
+
+static const struct org_kde_kwin_idle_timeout_listener idle_timer_listener = {
+  .idle = lock_idle_cb,
+  .resumed = lock_resume_cb,
+};
+
+
+static void
+lockscreen_prepare (PhoshShell *self)
+{
+  PhoshShellPrivate *priv = phosh_shell_get_instance_private (self);
+
+  g_return_if_fail(priv->seat);
+  g_return_if_fail(priv->idle_manager);
+
+  priv->lock_timer = org_kde_kwin_idle_get_idle_timeout(
+    priv->idle_manager,
+    priv->seat,
+    LOCKSCREEN_TIMEOUT);
+
+  g_return_if_fail (priv->lock_timer);
+
+  org_kde_kwin_idle_timeout_add_listener(priv->lock_timer,
+                                         &idle_timer_listener,
+                                         self);
+}
+
+
 static void
 panel_create (PhoshShell *self)
 {
@@ -368,18 +416,6 @@ env_setup ()
 }
 
 
-static void
-phosh_mobile_shell_prepare_lock_surface (void *data,
-    struct phosh_mobile_shell *phosh_mobile_shell)
-{
-  PhoshShell *self = data;
-  PhoshShellPrivate *priv = phosh_shell_get_instance_private (self);
-
-  if (!priv->lockscreen)
-    lockscreen_create(self);
-}
-
-
 static void
 registry_handle_global (void *data,
                         struct wl_registry *registry,
@@ -405,6 +441,12 @@ registry_handle_global (void *data,
       /* TODO: create multiple outputs */
       priv->output = wl_registry_bind (registry, name,
           &wl_output_interface, 1);
+  } else if (!strcmp (interface, "org_kde_kwin_idle")) {
+    priv->idle_manager = wl_registry_bind (registry,
+                                           name,
+                                           &org_kde_kwin_idle_interface, 1);
+  } else if (!strcmp(interface, "wl_seat")) {
+    priv->seat = wl_registry_bind(registry, name, &wl_seat_interface, 1);
   }
 }
 
@@ -414,6 +456,7 @@ registry_handle_global_remove (void *data,
     struct wl_registry *registry,
     uint32_t name)
 {
+  // TODO
 }
 
 
@@ -500,6 +543,7 @@ phosh_shell_constructed (GObject *object)
   panel_create (self);
   /* Create background after panel since it needs the panel's size */
   background_create (self);
+  lockscreen_prepare (self);
 }