Index: trunk/src/VBox/Additions/x11/xclient/clipboard.cpp
===================================================================
--- trunk/src/VBox/Additions/x11/xclient/clipboard.cpp	(revision 7261)
+++ trunk/src/VBox/Additions/x11/xclient/clipboard.cpp	(revision 7264)
@@ -48,4 +48,6 @@
 # define LogFlow(a) do {} while (0)
 #endif
+
+#define TRACE printf("%s: %d\n", __PRETTY_FUNCTION__, __LINE__); Log(("%s: %d\n", __PRETTY_FUNCTION__, __LINE__))
 
 /** The formats which we support in the guest. These can be deactivated in order to test specific code paths. */
@@ -1357,15 +1359,5 @@
 
     AssertReturn(g_ctx.client != 0, (void) 0);
-#if 0
-    /* Currently, disconnecting is not needed, as the new "connect clipboard" ioctl in the Guest Additions kernel
-     * module disconnects the last connection made automatically.  The reason for this change was that currently
-     * only one clipboard connection is allowed, and that if the client holding that connection was terminated
-     * too abruptly, the information needed to disconnect that connection was lost.  If the subsystem is ever
-     * changed to allow several connections, this will have to be rethought.
-     */
-    vmmdevInitRequest((VMMDevRequestHeader*)&request, VMMDevReq_HGCMDisconnect);
-    request.u32ClientID = g_ctx.client;
-    ioctl(g_ctx.sendDevice, IOCTL_VBOXGUEST_VMMREQUEST, (void*)&request);
-#endif
+    VbglR3ClipboardDisconnect(g_ctx.client);
     LogFlowFunc(("returning\n"));
 }
@@ -1476,20 +1468,27 @@
     LogFlowFunc(("\n"));
 
+    TRACE;
     rc = vboxClipboardCreateWindow();
     if (VBOX_FAILURE(rc))
         return rc;
 
+    TRACE;
     rc = RTThreadCreate(&g_ctx.thread, vboxClipboardThread, 0, 0, RTTHREADTYPE_IO,
                         RTTHREADFLAGS_WAITABLE, "SHCLIP");
     AssertRCReturn(rc, rc);
     /* Set up a timer to poll the host clipboard */
+    TRACE;
     XtAppAddTimeOut(g_ctx.appContext, 200 /* ms */, vboxClipboardTimerProc, 0);
 
+    TRACE;
     XtAppMainLoop(g_ctx.appContext);
+    TRACE;
     g_ctx.formatList.clear();
+    TRACE;
     XtDestroyApplicationContext(g_ctx.appContext);
     /* Set the termination signal. */
     RTSemEventSignal(g_ctx.terminating);
     LogFlowFunc(("returning %d\n", rc));
+    TRACE;
     return rc;
 }
Index: trunk/src/VBox/Additions/x11/xclient/clipboard.h
===================================================================
--- trunk/src/VBox/Additions/x11/xclient/clipboard.h	(revision 7261)
+++ trunk/src/VBox/Additions/x11/xclient/clipboard.h	(revision 7264)
@@ -20,7 +20,102 @@
 # define __Additions_linux_clipboard_h
 
+#include "thread.h"                 /* for VBoxGuestThread */
+
 extern void vboxClipboardDisconnect (void);
 extern int vboxClipboardConnect (void);
 extern int vboxClipboardMain (void);
 
+/**
+ * Display change request monitor thread function
+ */
+class VBoxGuestClipboardThread : public VBoxGuestThreadFunction
+{
+private:
+    // Copying or assigning a thread object is not sensible
+    VBoxGuestClipboardThread(const VBoxGuestClipboardThread&);
+    VBoxGuestClipboardThread& operator=(const VBoxGuestClipboardThread&);
+
+    // Private member variables
+    /** Have we been initialised yet? */
+    bool mInit;
+    /** The thread object running us. */
+    VBoxGuestThread *mThread;
+public:
+    VBoxGuestClipboardThread() { mInit = false; }
+    /**
+     * Initialise the class and check that the guest supports dynamic resizing.
+     * @returns iprt status value
+     */
+    int init(void)
+    {
+        if (mInit)
+            return true;
+        return vboxClipboardConnect();
+    }
+    /**
+     * The actual thread function.
+     *
+     * @returns iprt status code as thread return value
+     * @param pParent the VBoxGuestThread running this thread function
+     */
+    virtual int threadFunction(VBoxGuestThread *pThread)
+    {
+        vboxClipboardMain();
+        return VINF_SUCCESS;
+    }
+    /**
+     * Send a signal to the thread function that it should exit
+     */
+    virtual void stop(void) { vboxClipboardDisconnect(); }
+};
+
+class VBoxGuestClipboard
+{
+private:
+    /** No copying or assignment. */
+    VBoxGuestClipboard(const VBoxGuestClipboard &);
+    VBoxGuestClipboard& operator=(const VBoxGuestClipboard &);
+
+    /** Our monitor thread function */
+    VBoxGuestClipboardThread mThreadFunction;
+    /** And the thread for the thread function */
+    VBoxGuestThread mThread;
+    /** Are we initialised? */
+    bool mInit;
+public:
+    /**
+     * Initialise the class.
+     * @returns iprt status value
+     */
+    int init(void)
+    {
+        int rc = mThreadFunction.init();
+        if (RT_SUCCESS(rc))
+            rc = mThread.start();
+        if (RT_SUCCESS(rc))
+            mInit = true;
+        return rc;
+    }
+    /**
+     * Uninitialise the class.
+     * @param cMillies how long to wait for the thread to stop
+     */
+    void uninit(unsigned cMillies = RT_INDEFINITE_WAIT)
+    {
+        if (mInit)
+            mThread.stop(cMillies, NULL);
+    }
+
+    VBoxGuestClipboard() : mThread(&mThreadFunction, 0, RTTHREADTYPE_MSG_PUMP,
+                                   RTTHREADFLAGS_WAITABLE, "SHCLIP MAIN")
+    { mInit = false; }
+    ~VBoxGuestClipboard()
+    {
+        if (mInit)
+            try {
+                uninit(2000);
+            } catch (...) { }
+    }
+};
+
 #endif /* __Additions_linux_clipboard_h not defined */
Index: trunk/src/VBox/Additions/x11/xclient/main.cpp
===================================================================
--- trunk/src/VBox/Additions/x11/xclient/main.cpp	(revision 7261)
+++ trunk/src/VBox/Additions/x11/xclient/main.cpp	(revision 7264)
@@ -22,12 +22,14 @@
 #include <VBox/log.h>
 #include <iprt/initterm.h>
+#include <iprt/path.h>
 
 #include <iostream>
+#include <cstdio>
 
 #include <sys/types.h>
 #include <stdlib.h>       /* For exit */
 #include <unistd.h>
-#include <getopt.h>
 #include <errno.h>
+#include <signal.h>
 
 #include <X11/Xlib.h>
@@ -43,6 +45,21 @@
 #endif
 
-static bool gbDaemonise = true;
+#define TRACE printf("%s: %d\n", __PRETTY_FUNCTION__, __LINE__); Log(("%s: %d\n", __PRETTY_FUNCTION__, __LINE__))
+
 static int (*gpfnOldIOErrorHandler)(Display *) = NULL;
+
+/* Make these global so that the destructors are called if we make an "emergency exit",
+   i.e. a (handled) signal or an X11 error. */
+#ifdef DYNAMIC_RESIZE
+VBoxGuestDisplayChangeMonitor gDisplayChange;
+# ifdef SEAMLESS_GUEST
+    /** Our instance of the seamless class.  This only makes sense if dynamic resizing
+        is enabled. */
+    VBoxGuestSeamless gSeamless;
+# endif /* SEAMLESS_GUEST defined */
+#endif /* DYNAMIC_RESIZE */
+#ifdef VBOX_X11_CLIPBOARD
+    VBoxGuestClipboard gClipboard;
+#endif
 
 /**
@@ -90,7 +107,4 @@
         return 0;
     }
-#ifdef VBOX_X11_CLIPBOARD
-    vboxClipboardDisconnect();
-#endif
     XGetErrorText(pDisplay, pError->error_code, errorText, sizeof(errorText));
     LogRel(("VBoxClient: an X Window protocol error occurred: %s (error code %d).  Request code: %d, minor code: %d, serial number: %d\n", errorText, pError->error_code, pError->request_code, pError->minor_code, pError->serial));
@@ -110,48 +124,83 @@
 }
 
+/**
+ * A standard signal handler which cleans up and exits.  Our global static objects will
+ * be cleaned up properly as we exit using "exit".
+ */
+void vboxClientSignalHandler(int cSignal)
+{
+    Log(("VBoxClient: terminated with signal %d\n", cSignal));
+    /* Our pause() call will now return and exit. */
+}
+
+/**
+ * Reset all standard termination signals to call our signal handler, which cleans up
+ * and exits.
+ */
+void vboxClientSetSignalHandlers(void)
+{
+    struct sigaction sigAction = { { 0 } };
+
+    sigAction.sa_handler = vboxClientSignalHandler;
+    sigemptyset(&sigAction.sa_mask);
+    sigaction(SIGHUP, &sigAction, NULL);
+    sigaction(SIGINT, &sigAction, NULL);
+    sigaction(SIGQUIT, &sigAction, NULL);
+    sigaction(SIGABRT, &sigAction, NULL);
+    sigaction(SIGPIPE, &sigAction, NULL);
+    sigaction(SIGALRM, &sigAction, NULL);
+    sigaction(SIGTERM, &sigAction, NULL);
+    sigaction(SIGUSR1, &sigAction, NULL);
+    sigaction(SIGUSR2, &sigAction, NULL);
+}
+
+/**
+ * Print out a usage message and exit with success.
+ */
+void vboxClientUsage(const char *pcszFileName)
+{
+    /* printf is better for i18n than iostream. */
+    printf("Usage: %s [-d|--nodaemon]\n", pcszFileName);
+    printf("Start the VirtualBox X Window System guest services.\n\n");
+    printf("Options:\n");
+    printf("  -d, --nodaemon   do not lower privileges and continue running as a system\n");
+    printf("                   service\n");
+    exit(0);
+}
+
+/**
+ * The main loop for the VBoxClient daemon.
+ */
 int main(int argc, char *argv[])
 {
     int rcClipboard, rc = VINF_SUCCESS;
-#ifdef DYNAMIC_RESIZE
-    VBoxGuestDisplayChangeMonitor displayChange;
-# ifdef SEAMLESS_GUEST
-    /** Our instance of the seamless class.  This only makes sense if dynamic resizing
-        is enabled. */
-    VBoxGuestSeamless seamless;
-# endif /* SEAMLESS_GUEST defined */
-#endif /* DYNAMIC_RESIZE */
-
+    const char *pszFileName = RTPathFilename(argv[0]);
+    bool fDaemonise = true;
+
+    if (NULL == pszFileName)
+        pszFileName = "VBoxClient";
+
+    TRACE;
     /* Parse our option(s) */
-/** @todo r=bird: use RTGetOpt */
-    while (1)
-    {
-        static struct option sOpts[] =
-        {
-            {"nodaemon", 0, 0, 'd'},
-            {0, 0, 0, 0}
-        };
-        int cOpt = getopt_long(argc, argv, "", sOpts, 0);
-        if (cOpt == -1)
-        {
-            if (optind < argc)
-            {
-                std::cout << "Unrecognized command line argument: " << argv[argc] << std::endl;
-                exit(1);
-            }
-            break;
-        }
-        switch(cOpt)
-        {
-        case 'd':
-            gbDaemonise = false;
-            break;
-        default:
-            std::cout << "Unrecognized command line option: " << static_cast<char>(cOpt)
-                      << std::endl;
-        case '?':
+    /** @todo Use RTGetOpt() if the arguments become more complex. */
+    for (int i = 1; i < argc; ++i)
+    {
+        if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--nodaemon"))
+            fDaemonise = false;
+        else if (!strcmp(argv[i], "-h") || strcmp(argv[i], "--help"))
+        {
+            vboxClientUsage(pszFileName);
+            exit(0);
+        }
+        else
+        {
+            /* printf is better than iostream for i18n. */
+            printf("%s: unrecognized option `%s'\n", pszFileName, argv[i]);
+            printf("Try `%s --help' for more information\n", pszFileName);
             exit(1);
         }
     }
-    if (gbDaemonise)
+    TRACE;
+    if (fDaemonise)
     {
         rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */);
@@ -163,4 +212,5 @@
     }
     /* Initialise our runtime before all else. */
+    TRACE;
     RTR3Init(false);
     if (RT_FAILURE(VbglR3Init()))
@@ -169,5 +219,6 @@
         return 1;
     }
-    if (RT_FAILURE(vboxClientDropPrivileges()))
+    TRACE;
+    if (fDaemonise && RT_FAILURE(vboxClientDropPrivileges()))
         return 1;
     LogRel(("VBoxClient: starting...\n"));
@@ -182,18 +233,19 @@
     /* Set an X11 I/O error handler, so that we can shutdown properly on fatal errors. */
     gpfnOldIOErrorHandler = XSetIOErrorHandler(vboxClientXLibIOErrorHandler);
+    vboxClientSetSignalHandlers();
+    try
+    {
 #ifdef VBOX_X11_CLIPBOARD
-    /* Connect to the host clipboard. */
-    LogRel(("VBoxClient: starting clipboard Guest Additions...\n"));
-    rcClipboard = vboxClipboardConnect();
-    if (RT_FAILURE(rcClipboard))
-    {
-        LogRel(("VBoxClient: vboxClipboardConnect failed with rc = %Rrc\n", rc));
-    }
+        /* Connect to the host clipboard. */
+        LogRel(("VBoxClient: starting clipboard Guest Additions...\n"));
+        rcClipboard = gClipboard.init();
+        if (RT_FAILURE(rcClipboard))
+        {
+            LogRel(("VBoxClient: vboxClipboardConnect failed with rc = %Rrc\n", rc));
+        }
 #endif  /* VBOX_X11_CLIPBOARD defined */
-    try
-    {
 #ifdef DYNAMIC_RESIZE
         LogRel(("VBoxClient: starting dynamic guest resizing...\n"));
-        rc = displayChange.init();
+        rc = gDisplayChange.init();
         if (RT_FAILURE(rc))
         {
@@ -204,5 +256,5 @@
         {
             LogRel(("VBoxClient: starting seamless Guest Additions...\n"));
-            rc = seamless.init();
+            rc = gSeamless.init();
             if (RT_FAILURE(rc))
             {
@@ -215,41 +267,39 @@
     catch (std::exception e)
     {
-        LogRel(("VBoxClient: failed to initialise seamless Additions - caught exception: %s\n", e.what()));
+        LogRel(("VBoxClient: failed to initialise Guest Additions - caught exception: %s\n", e.what()));
         rc = VERR_UNRESOLVED_ERROR;
     }
     catch (...)
     {
-        LogRel(("VBoxClient: failed to initialise seamless Additions - caught unknown exception.\n"));
+        LogRel(("VBoxClient: failed to initialise Guest Additions - caught unknown exception.\n"));
         rc = VERR_UNRESOLVED_ERROR;
     }
-#ifdef VBOX_X11_CLIPBOARD
-    if (RT_SUCCESS(rcClipboard))
-    {
-        LogRel(("VBoxClient: connecting to the shared clipboard service.\n"));
-        vboxClipboardMain();
-        vboxClipboardDisconnect();
-    }
-#else  /* VBOX_X11_CLIPBOARD not defined */
     LogRel(("VBoxClient: sleeping...\n"));
     pause();
     LogRel(("VBoxClient: exiting...\n"));
-#endif  /* VBOX_X11_CLIPBOARD not defined */
     try
     {
 #ifdef DYNAMIC_RESIZE
-        displayChange.uninit();
 # ifdef SEAMLESS_GUEST
-        seamless.uninit();
+        LogRel(("VBoxClient: shutting down seamless Guest Additions...\n"));
+        gSeamless.uninit(2000);
 # endif /* SEAMLESS_GUEST defined */
+        LogRel(("VBoxClient: shutting down dynamic guest resizing...\n"));
+        gDisplayChange.uninit(2000);
 #endif /* DYNAMIC_RESIZE defined */
+#ifdef VBOX_X11_CLIPBOARD
+        /* Connect to the host clipboard. */
+        LogRel(("VBoxClient: shutting down clipboard Guest Additions...\n"));
+        gClipboard.uninit(2000);
+#endif  /* VBOX_X11_CLIPBOARD defined */
     }
     catch (std::exception e)
     {
-        LogRel(("VBoxClient: error shutting down seamless Additions - caught exception: %s\n", e.what()));
+        LogRel(("VBoxClient: failed to shut down Guest Additions - caught exception: %s\n", e.what()));
         rc = VERR_UNRESOLVED_ERROR;
     }
     catch (...)
     {
-        LogRel(("VBoxClient: error shutting down seamless Additions - caught unknown exception.\n"));
+        LogRel(("VBoxClient: failed to shut down Guest Additions - caught unknown exception.\n"));
         rc = VERR_UNRESOLVED_ERROR;
     }
Index: trunk/src/VBox/Additions/x11/xclient/seamless.h
===================================================================
--- trunk/src/VBox/Additions/x11/xclient/seamless.h	(revision 7261)
+++ trunk/src/VBox/Additions/x11/xclient/seamless.h	(revision 7264)
@@ -168,10 +168,10 @@
     }
 
-    void uninit(void)
+    void uninit(unsigned cMillies = RT_INDEFINITE_WAIT)
     {
         if (isInitialised)
         {
             mHost.stop();
-            mGuestThread.stop(RT_INDEFINITE_WAIT, 0);
+            mGuestThread.stop(cMillies, 0);
             mGuest.uninit();
             isInitialised = false;
