diff --git a/src/background.c b/src/background.c
index 7e46283..4b255ab 100644
--- a/src/background.c
+++ b/src/background.c
@@ -101,6 +101,8 @@ static gboolean
 handle_get_app_state (XdpImplBackground *object,
                       GDBusMethodInvocation *invocation)
 {
+  idle_timeout_inhibit ();
+
   g_debug ("background: handle GetAppState");
 
   if (app_state == NULL)
@@ -114,6 +116,8 @@ handle_get_app_state (XdpImplBackground *object,
   else
     xdp_impl_background_complete_get_app_state (object, invocation, app_state);
 
+  idle_timeout_release ();
+
   return TRUE;
 }
 
@@ -400,6 +404,8 @@ handle_enable_autostart (XdpImplBackground *object,
   g_autofree char *commandline = NULL;
   g_autoptr(GKeyFile) keyfile = NULL;
 
+  idle_timeout_inhibit ();
+
   g_debug ("background: handle EnableAutostart");
 
   file = g_strconcat (arg_app_id, ".desktop", NULL);
@@ -458,6 +464,7 @@ handle_enable_autostart (XdpImplBackground *object,
 out:
   xdp_impl_background_complete_enable_autostart (object, invocation, result);
 
+  idle_timeout_release ();
   return TRUE;
 }
 
diff --git a/src/idle-timeout.h b/src/idle-timeout.h
new file mode 100644
index 0000000..85c4297
--- /dev/null
+++ b/src/idle-timeout.h
@@ -0,0 +1,4 @@
+#pragma once
+
+void idle_timeout_inhibit (void);
+void idle_timeout_release (void);
diff --git a/src/inhibit.c b/src/inhibit.c
index 5202b93..e046211 100644
--- a/src/inhibit.c
+++ b/src/inhibit.c
@@ -14,6 +14,8 @@
 #include "inhibit.h"
 #include "request.h"
 
+#include "idle-timeout.h"
+
 enum {
   INHIBIT_LOGOUT  = 1,
   INHIBIT_SWITCH  = 2,
@@ -448,6 +450,8 @@ inhibit_session_close (Session *session)
   g_debug ("Closing inhibit session %s", ((Session *)inhibit_session)->id);
 
   active_sessions = g_list_remove (active_sessions, session);
+
+  idle_timeout_release ();
 }
 
 static void
@@ -480,6 +484,8 @@ inhibit_session_new (const char *app_id,
 {
   InhibitSession *inhibit_session;
 
+  idle_timeout_inhibit ();
+
   g_debug ("Creating inhibit session %s", session_handle);
 
   inhibit_session = g_object_new (inhibit_session_get_type (),
diff --git a/src/print.c b/src/print.c
index df6a357..7fb2dd2 100644
--- a/src/print.c
+++ b/src/print.c
@@ -42,6 +42,8 @@
 
 #include "gtkbackports.h"
 
+#include "idle-timeout.h"
+
 typedef struct {
   char *app_id;
   GtkPageSetup *page_setup;
@@ -265,6 +267,8 @@ print_file (int fd,
   // ensures the app_name won't be NULL even if the app_id.desktop file doesn't exist
   g_autofree char *app_name = g_strdup (app_id);
 
+  idle_timeout_inhibit ();
+
   if (!g_str_has_suffix (app_id, ".desktop"))
     {
       app_desktop_fullname = g_strconcat (app_id, ".desktop", NULL);
@@ -287,13 +291,19 @@ print_file (int fd,
 
 #if GTK_CHECK_VERSION (3, 22, 0)
   if (job && !gtk_print_job_set_source_fd (job, fd, error))
-    return FALSE;
+    {
+      idle_timeout_release ();
+      return FALSE;
+    }
 #endif
 
   istream = (GUnixInputStream *)g_unix_input_stream_new (fd, FALSE);
 
   if ((fd2 = g_file_open_tmp (PACKAGE_NAME "XXXXXX", &filename, error)) == -1)
-    return FALSE;
+    {
+      idle_timeout_release ();
+      return FALSE;
+    }
 
   ostream = (GUnixOutputStream *)g_unix_output_stream_new (fd2, TRUE);
 
@@ -302,21 +312,29 @@ print_file (int fd,
                               G_OUTPUT_STREAM_SPLICE_NONE,
                               NULL,
                               error) == -1)
-    return FALSE;
+    {
+      idle_timeout_release ();
+      return FALSE;
+    }
   if (job)
     {
       if (!gtk_print_job_set_source_file (job, filename, error))
-        return FALSE;
+        {
+          idle_timeout_release ();
+          return FALSE;
+        }
 
-      gtk_print_job_send (job, NULL, NULL, NULL);
+      idle_timeout_inhibit ();
+      gtk_print_job_send (job, (GtkPrintJobCompleteFunc) idle_timeout_release, NULL, NULL);
     }
   else
     {
       if (!launch_preview (filename, title, settings, page_setup, error))
-	{
-	  unlink (filename);
-	  return FALSE;
-	}
+        {
+          unlink (filename);
+          idle_timeout_release ();
+          return FALSE;
+        }
     }
 
   /* The file will be removed when the GtkPrintJob closes it (once the job is
@@ -325,6 +343,7 @@ print_file (int fd,
   if (!preview)
     unlink (filename);
 
+  idle_timeout_release ();
   return TRUE;
 }
 
diff --git a/src/request.c b/src/request.c
index de96932..902d249 100644
--- a/src/request.c
+++ b/src/request.c
@@ -21,6 +21,8 @@
 
 #include "request.h"
 
+#include "idle-timeout.h"
+
 #include <string.h>
 
 static void request_skeleton_iface_init (XdpImplRequestIface *iface);
@@ -52,6 +54,8 @@ request_skeleton_iface_init (XdpImplRequestIface *iface)
 static void
 request_init (Request *request)
 {
+  /* Prevent process from exiting as long as a request exists */
+  idle_timeout_inhibit ();
 }
 
 static void
@@ -64,6 +68,9 @@ request_finalize (GObject *object)
   g_free (request->id);
 
   G_OBJECT_CLASS (request_parent_class)->finalize (object);
+
+  /* Process can exit when there are no more outstanding requests */
+  idle_timeout_release ();
 }
 
 static void
diff --git a/src/session.c b/src/session.c
index 5ebe13f..cdafc30 100644
--- a/src/session.c
+++ b/src/session.c
@@ -19,6 +19,8 @@
 
 #include "session.h"
 
+#include "idle-timeout.h"
+
 enum
 {
   PROP_0,
@@ -148,6 +150,9 @@ session_finalize (GObject *object)
 {
   Session *session = (Session *)object;
 
+  /* Allow the process to exit when there are no active sessions left */
+  idle_timeout_release ();
+
   g_hash_table_remove (sessions, session->id);
 
   g_free (session->id);
@@ -162,6 +167,9 @@ session_constructed (GObject *object)
 
   g_hash_table_insert (sessions, g_strdup (session->id), session);
 
+  /* Prevent the process from exiting while there are active sessions */
+  idle_timeout_inhibit ();
+
   G_OBJECT_CLASS (session_parent_class)->constructed (object);
 }
 
diff --git a/src/xdg-desktop-portal-gtk.c b/src/xdg-desktop-portal-gtk.c
index 8cad9f2..70ad680 100644
--- a/src/xdg-desktop-portal-gtk.c
+++ b/src/xdg-desktop-portal-gtk.c
@@ -57,10 +57,17 @@
 #include "settings.h"
 #include "wallpaper.h"
 
+#include "idle-timeout.h"
+
+/* Process should go away this long after last request has been handled */
+#define IDLE_TIMEOUT_MS 1000
 
 static GMainLoop *loop = NULL;
 static GHashTable *outstanding_handles = NULL;
 
+static gint idle_timeout_id;
+static gint idle_timeout_inhibit_count;
+
 static gboolean opt_verbose;
 static gboolean opt_replace;
 static gboolean show_version;
@@ -213,6 +220,51 @@ on_name_lost (GDBusConnection *connection,
   g_main_loop_quit (loop);
 }
 
+static gboolean
+on_idle_timeout (void)
+{
+  g_main_loop_quit (loop);
+  return FALSE;
+}
+
+static void
+idle_timeout_stop (void)
+{
+  if (idle_timeout_id)
+  {
+    g_source_remove (idle_timeout_id);
+    idle_timeout_id = 0;
+  }
+}
+
+static void
+idle_timeout_restart (void)
+{
+  idle_timeout_stop ();
+  idle_timeout_id = g_timeout_add (IDLE_TIMEOUT_MS, (GSourceFunc) on_idle_timeout, NULL);
+}
+
+void
+idle_timeout_inhibit (void)
+{
+  idle_timeout_stop ();
+  idle_timeout_inhibit_count++;
+}
+
+void
+idle_timeout_release (void)
+{
+  if (idle_timeout_inhibit_count == 0)
+  {
+    g_warning ("Mismatched idle timeout inhibitor release");
+    return;
+  }
+
+  idle_timeout_inhibit_count--;
+  if (idle_timeout_inhibit_count == 0)
+    idle_timeout_restart ();
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -286,6 +338,7 @@ main (int argc, char *argv[])
                              NULL,
                              NULL);
 
+  idle_timeout_restart ();
   g_main_loop_run (loop);
 
   g_bus_unown_name (owner_id);
