]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
nternal branch sync. Included in this change:
authorVMware, Inc <>
Wed, 18 Sep 2013 03:29:34 +0000 (20:29 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Mon, 23 Sep 2013 05:10:49 +0000 (22:10 -0700)
. Tools,DND,X11: Constrain detection window to desktop work area
. dndcpx11: Adjust style to match Hosted UI guidelines
. changes in shared code that don't affect open-vm-tools functionality

Signed-off-by: Dmitry Torokhov <dtor@vmware.com>
open-vm-tools/lib/include/mutexRankLib.h
open-vm-tools/lib/include/vm_atomic.h
open-vm-tools/services/plugins/dndcp/Makefile.am
open-vm-tools/services/plugins/dndcp/dndUIX11.cpp
open-vm-tools/services/plugins/dndcp/dndUIX11.h
open-vm-tools/services/plugins/dndcp/xutils/xutils.cc [new file with mode: 0644]
open-vm-tools/services/plugins/dndcp/xutils/xutils.hh [new file with mode: 0644]

index 44f6875e2c3bc4313509f7baff3c0ea90e58d08c..b3e1e2eca36b6b3dde8435da9816d00f0a32c9b5 100644 (file)
@@ -86,9 +86,9 @@
 #define RANK_nfcLibLock              (RANK_libLockBase + 0x4505)
 
 /*
- * policy ops pending list lock
+ * Policy lib lock
  */
-#define RANK_popPendingListLock      (RANK_libLockBase + 0x4605)
+#define RANK_policyLibLock           (RANK_libLockBase + 0x4605)
 
 /*
  * disklib and I/O related locks
 #define RANK_licenseCheckLock        (RANK_libLockBase + 0x7090)
 #define RANK_preferenceLock          (RANK_libLockBase + 0x7100)
 
+
 #endif /* _LIBMUTEXRANK_H */
index 36d9a6898dbacd4f4a6e263f783c2f2c917b175b..af2f578cf5f69733cc833b437d2bf1b629a5ed5a 100644 (file)
@@ -37,8 +37,6 @@
 #ifndef _ATOMIC_H_
 #define _ATOMIC_H_
 
-//#define FAKE_ATOMIC /* defined if true atomic not needed */
-
 #define INCLUDE_ALLOW_USERLEVEL
 
 #define INCLUDE_ALLOW_MODULE
 #include "vm_basic_types.h"
 
 
-/* Basic atomic type: 32 bits */
+/* Basic atomic types: 32 and 64 bits */
 typedef struct Atomic_uint32 {
    volatile uint32 value;
-} Atomic_uint32;
-
+} Atomic_uint32 ALIGNED(4);
 
-/* Basic atomic type: 64 bits */
 typedef struct  Atomic_uint64 {
    volatile uint64 value;
 } Atomic_uint64 ALIGNED(8);
 
-
 /*
  * Prototypes for msft atomics.  These are defined & inlined by the
  * compiler so no function definition is needed.  The prototypes are
@@ -122,7 +117,7 @@ __int64  _InterlockedCompareExchange64(__int64 volatile*, __int64, __int64);
 #endif
 #endif /* _MSC_VER */
 
-#if defined(__arm__) && !defined(FAKE_ATOMIC)
+#if defined(__arm__)
 /*
  * LDREX without STREX or CLREX may cause problems in environments where the
  * context switch may not clear the reference monitor - according ARM manual
@@ -342,34 +337,47 @@ AtomicEpilogue(void)
 static INLINE uint32
 Atomic_Read(Atomic_uint32 const *var) // IN
 {
-   return var->value;
-}
-#define Atomic_Read32 Atomic_Read
+   uint32 value;
 
+#if defined(VMM)
+   ASSERT(((uintptr_t)var % 4) == 0);
+#endif
 
-/*
- *-----------------------------------------------------------------------------
- *
- * Atomic_Write --
- *
- *      Write
- *
- * Results:
- *      None.
- *
- * Side effects:
- *      None.
- *
- *-----------------------------------------------------------------------------
- */
+#if defined(__GNUC__)
+   /*
+    * Use inline assembler to force using a single load instruction to
+    * ensure that the compiler doesn't split a transfer operation into multiple
+    * instructions.
+    */
 
-static INLINE void
-Atomic_Write(Atomic_uint32 *var, // IN
-             uint32 val)         // IN
-{
-   var->value = val;
+#if defined(VM_ARM_V7)
+   __asm__ __volatile__(
+      "ldr %0, [%1]"
+      : "=r" (value)
+      : "r" (var->value)
+   );
+#else
+   __asm__ __volatile__(
+      "mov %1, %0"
+      : "=r" (value)
+      : "m" (var->value)
+   );
+#endif
+#elif defined(_MSC_VER)
+   /*
+    * Microsoft docs guarantee simple reads and writes to properly
+    * aligned 32-bit variables use only a single instruction.
+    * http://msdn.microsoft.com/en-us/library/ms684122%28VS.85%29.aspx
+    */
+
+   value = var->value;
+#else
+#error No compiler defined for Atomic_Read
+#endif
+
+   return value;
 }
-#define Atomic_Write32 Atomic_Write
+#define Atomic_Read32 Atomic_Read
 
 
 /*
@@ -392,11 +400,7 @@ static INLINE uint32
 Atomic_ReadWrite(Atomic_uint32 *var, // IN
                  uint32 val)         // IN
 {
-#ifdef FAKE_ATOMIC
-   uint32 retval = var->value;
-   var->value = val;
-   return retval;
-#elif defined(__GNUC__)
+#if defined(__GNUC__)
 #ifdef VM_ARM_V7
    register volatile uint32 retVal;
    register volatile uint32 res;
@@ -448,6 +452,83 @@ Atomic_ReadWrite(Atomic_uint32 *var, // IN
 #define Atomic_ReadWrite32 Atomic_ReadWrite
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Atomic_Write --
+ *
+ *      Write
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+Atomic_Write(Atomic_uint32 *var, // IN
+             uint32 val)         // IN
+{
+#if defined(VMM)
+   ASSERT(((uintptr_t)var % 4) == 0);
+#endif
+
+#if defined(__GNUC__)
+#if defined(VM_ARM_V7)
+   /*
+    * A3.4.1 ARM DDI 0406C:
+    *
+    * When a processor writes using any instruction other than a
+    * Store-Exclusive:
+    *
+    * - if the write is to a physical address that is not covered by its local
+    *   monitor the write does not affect the state of the local monitor
+    * - if the write is to a physical address that is covered by its local
+    *   monitor it is IMPLEMENTATION DEFINED whether the write affects the
+    *   state of the local monitor.
+    *
+    * A3.4.5 ARM DDI 0406C:
+    *
+    * If two STREX instructions are executed without an intervening LDREX the
+    * second STREX returns a status value of 1. This means that:
+    *
+    * — ARM recommends that, in a given thread of execution, every STREX has a
+    *   preceding LDREX associated with it
+    * — it is not necessary for every LDREX to have a subsequent STREX.
+    */
+
+   Atomic_ReadWrite(var, val);
+#else
+   /*
+    * Use inline assembler to force using a single store instruction to
+    * ensure that the compiler doesn't split a transfer operation into multiple
+    * instructions.
+    */
+
+   __asm__ __volatile__(
+      "mov %1, %0"
+      : "=m" (var->value)
+      : "r" (val)
+   );
+#endif
+#elif defined(_MSC_VER)
+   /*
+    * Microsoft docs guarantee simple reads and writes to properly
+    * aligned 32-bit variables use only a single instruction.
+    * http://msdn.microsoft.com/en-us/library/ms684122%28VS.85%29.aspx
+    */
+
+   var->value = val;
+#else
+#error No compiler defined for Atomic_Write
+#endif
+}
+#define Atomic_Write32 Atomic_Write
+
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -469,14 +550,7 @@ Atomic_ReadIfEqualWrite(Atomic_uint32 *var, // IN
                         uint32 oldVal,      // IN
                         uint32 newVal)      // IN
 {
-#ifdef FAKE_ATOMIC
-   uint32 readVal = var->value;
-
-   if (oldVal == readVal) {
-     var->value = newVal;
-   }
-   return oldVal;
-#elif defined(__GNUC__)
+#if defined(__GNUC__)
 #ifdef VM_ARM_V7
    register uint32 retVal;
    register uint32 res;
@@ -559,7 +633,7 @@ Atomic_ReadIfEqualWriteLockAcquire(Atomic_uint32 *var, // IN
                                   uint32 oldVal,      // IN
                                   uint32 newVal)      // IN
 {
-#if !defined(FAKE_ATOMIC) && defined(__GNUC__) && defined(__x86_64__)
+#if defined(__GNUC__) && defined(__x86_64__)
    uint32 val;
    __asm__ __volatile__(
       "repnz; lock; cmpxchgl %2, %1"
@@ -668,9 +742,7 @@ static INLINE void
 Atomic_And(Atomic_uint32 *var, // IN
            uint32 val)         // IN
 {
-#ifdef FAKE_ATOMIC
-   var->value &= val;
-#elif defined(__GNUC__)
+#if defined(__GNUC__)
 #ifdef VM_ARM_V7
    register volatile uint32 res;
    register volatile uint32 tmp;
@@ -734,9 +806,7 @@ static INLINE void
 Atomic_Or(Atomic_uint32 *var, // IN
           uint32 val)         // IN
 {
-#ifdef FAKE_ATOMIC
-   var->value |= val;
-#elif defined(__GNUC__)
+#if defined(__GNUC__)
 #ifdef VM_ARM_V7
    register volatile uint32 res;
    register volatile uint32 tmp;
@@ -800,9 +870,7 @@ static INLINE void
 Atomic_Xor(Atomic_uint32 *var, // IN
            uint32 val)         // IN
 {
-#ifdef FAKE_ATOMIC
-   var->value ^= val;
-#elif defined(__GNUC__)
+#if defined(__GNUC__)
 #ifdef VM_ARM_V7
    register volatile uint32 res;
    register volatile uint32 tmp;
@@ -905,9 +973,7 @@ static INLINE void
 Atomic_Add(Atomic_uint32 *var, // IN
            uint32 val)         // IN
 {
-#ifdef FAKE_ATOMIC
-   var->value += val;
-#elif defined(__GNUC__)
+#if defined(__GNUC__)
 #ifdef VM_ARM_V7
    register volatile uint32 res;
    register volatile uint32 tmp;
@@ -1010,9 +1076,7 @@ static INLINE void
 Atomic_Sub(Atomic_uint32 *var, // IN
            uint32 val)         // IN
 {
-#ifdef FAKE_ATOMIC
-   var->value -= val;
-#elif defined(__GNUC__)
+#if defined(__GNUC__)
 #ifdef VM_ARM_V7
    register volatile uint32 res;
    register volatile uint32 tmp;
@@ -1115,7 +1179,7 @@ static INLINE void
 Atomic_Inc(Atomic_uint32 *var) // IN
 {
 #ifdef __GNUC__
-#if defined(VM_ARM_V7) || defined(FAKE_ATOMIC)
+#if defined(VM_ARM_V7)
    Atomic_Add(var, 1);
 #else // VM_ARM_V7
    /* Checked against the Intel manual and GCC --walken */
@@ -1161,7 +1225,7 @@ static INLINE void
 Atomic_Dec(Atomic_uint32 *var) // IN
 {
 #ifdef __GNUC__
-#if defined(VM_ARM_V7) || defined(FAKE_ATOMIC)
+#if defined(VM_ARM_V7)
    Atomic_Sub(var, 1);
 #else // VM_ARM_V7
    /* Checked against the Intel manual and GCC --walken */
@@ -1343,11 +1407,7 @@ static INLINE uint32
 Atomic_FetchAndAddUnfenced(Atomic_uint32 *var, // IN
                            uint32 val)         // IN
 {
-#ifdef FAKE_ATOMIC
-   uint32 res = var->value;
-   var->value = res + val;
-   return res;
-#elif defined(__GNUC__)
+#if defined(__GNUC__)
 #ifdef VM_ARM_V7
    register volatile uint32 res;
    register volatile uint32 retVal;
@@ -1428,7 +1488,7 @@ static INLINE uint32
 Atomic_FetchAndAddLockReleaseUnfenced(Atomic_uint32 *var, // IN
                                      uint32 val)         // IN
 {
-#if !defined(FAKE_ATOMIC) && defined(__GNUC__) && defined(__x86_64__)
+#if defined(__GNUC__) && defined(__x86_64__)
    __asm__ __volatile__(
       "repz; lock; xaddl %0, %1"
       : "=r" (val),
@@ -1470,7 +1530,7 @@ static INLINE uint32
 Atomic_FetchAndAdd(Atomic_uint32 *var, // IN
                    uint32 val)         // IN
 {
-#if defined(__GNUC__) && !defined(VM_ARM_V7) && !defined(FAKE_ATOMIC)
+#if defined(__GNUC__) && !defined(VM_ARM_V7)
    val = Atomic_FetchAndAddUnfenced(var, val);
    AtomicEpilogue();
    return val;
@@ -1508,7 +1568,7 @@ static INLINE uint32
 Atomic_FetchAndAddLockRelease(Atomic_uint32 *var, // IN
                              uint32 val)         // IN
 {
-#if defined(__GNUC__) && !defined(VM_ARM_V7) && !defined(FAKE_ATOMIC)
+#if defined(__GNUC__) && !defined(VM_ARM_V7)
    val = Atomic_FetchAndAddLockReleaseUnfenced(var, val);
    AtomicEpilogue();
    return val;
@@ -1755,14 +1815,7 @@ Atomic_CMPXCHG64(Atomic_uint64 *var,   // IN/OUT
                  uint64 const *oldVal, // IN
                  uint64 const *newVal) // IN
 {
-#ifdef FAKE_ATOMIC
-   uint64 readVal = var->value;
-
-   if (*oldVal == readVal) {
-     var->value = *newVal;
-   }
-   return (*oldVal == readVal);
-#elif defined(__GNUC__)
+#if defined(__GNUC__)
 #if defined(VM_ARM_V7)
    return (Atomic_ReadIfEqualWrite64(var, *oldVal, *newVal) == *oldVal);
 
@@ -1925,14 +1978,7 @@ Atomic_CMPXCHG32(Atomic_uint32 *var,   // IN/OUT
                  uint32 oldVal, // IN
                  uint32 newVal) // IN
 {
-#ifdef FAKE_ATOMIC
-   uint32 readVal = var->value;
-
-   if (oldVal == readVal) {
-     var->value = newVal;
-   }
-   return (oldVal == readVal);
-#elif defined(__GNUC__)
+#if defined(__GNUC__)
 #ifdef VM_ARM_V7
    return (Atomic_ReadIfEqualWrite(var, oldVal, newVal) == oldVal);
 #else // VM_ARM_V7
@@ -1977,9 +2023,7 @@ Atomic_CMPXCHG32(Atomic_uint32 *var,   // IN/OUT
 static INLINE uint64
 Atomic_Read64(Atomic_uint64 const *var) // IN
 {
-#ifdef FAKE_ATOMIC
-   return var->value;
-#elif defined(__GNUC__) && defined(__x86_64__)
+#if defined(__GNUC__) && defined(__x86_64__)
    uint64 value;
 
 #ifdef VMM
index 04422c7b973e91d6531ff38c90c3a2a70c76ccf6..1e067e20a6fff9aa7c7c36bb3c95cda279fdde53 100644 (file)
@@ -18,8 +18,6 @@
 plugindir = @VMUSR_PLUGIN_INSTALLDIR@
 plugin_LTLIBRARIES = libdndcp.la
 
-CFLAGS += -Wno-unused
-
 libdndcp_la_CPPFLAGS =
 libdndcp_la_CPPFLAGS += @GTK_CPPFLAGS@
 libdndcp_la_CPPFLAGS += @GTKMM_CPPFLAGS@
@@ -27,6 +25,7 @@ libdndcp_la_CPPFLAGS += @PLUGIN_CPPFLAGS@
 libdndcp_la_CPPFLAGS += -I$(top_srcdir)/services/plugins/dndcp/dnd
 libdndcp_la_CPPFLAGS += -I$(top_srcdir)/services/plugins/dndcp/dndGuest
 libdndcp_la_CPPFLAGS += -I$(top_srcdir)/services/plugins/dndcp/stringxx
+libdndcp_la_CPPFLAGS += -I$(top_srcdir)/services/plugins/dndcp/xutils
 libdndcp_la_CPPFLAGS += -I$(top_builddir)/include
 
 libdndcp_la_LDFLAGS =
@@ -66,6 +65,7 @@ libdndcp_la_SOURCES += dndGuest/rpcV4Util.cpp
 libdndcp_la_SOURCES += dndGuest/dndCPTransportGuestRpc.cpp
 
 libdndcp_la_SOURCES += stringxx/string.cc
+libdndcp_la_SOURCES += xutils/xutils.cc
 
 libdndcp_la_SOURCES += copyPasteCompat.c
 libdndcp_la_SOURCES += copyPasteCompatX11.c
index 4548a502559c42bd3f8f8a4256b84feec375226d..051ea736e0bbc371e1a70f0220ac5c5f15f75984 100644 (file)
 
 #define G_LOG_DOMAIN "dndcp"
 
+#include "xutils/xutils.hh"
+
 #include "dndUIX11.h"
 #include "guestDnDCPMgr.hh"
 #include "tracer.hh"
 
 extern "C" {
-#include "vmblock.h"
-#include "file.h"
+#include <X11/extensions/XTest.h>       /* for XTest*() */
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <X11/Xatom.h>
+
+#include "vmware/guestrpc/tclodefs.h"
+
 #include "copyPasteCompat.h"
-#include "dnd.h"
-#include "dndMsg.h"
-#include "dndClipboard.h"
 #include "cpName.h"
 #include "cpNameUtil.h"
+#include "dnd.h"
+#include "dndClipboard.h"
+#include "dndMsg.h"
+#include "file.h"
 #include "hostinfo.h"
 #include "rpcout.h"
-#include <gtk/gtk.h>
-#include <gdk/gdkx.h>
-#include <X11/extensions/XTest.h>       /* for XTest*() */
-#include "vmware/guestrpc/tclodefs.h"
+#include "vmblock.h"
 }
 
 /* IsXExtensionPointer may be not defined with old Xorg. */
@@ -53,67 +58,99 @@ extern "C" {
 
 #include "copyPasteDnDWrapper.h"
 
-/**
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::DnDUIX11 --
  *
- * Constructor.
+ *      Constructor.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 DnDUIX11::DnDUIX11(ToolsAppCtx *ctx)
-    : m_ctx(ctx),
-      m_DnD(NULL),
-      m_detWnd(NULL),
-      m_blockCtrl(NULL),
-      m_HGGetFileStatus(DND_FILE_TRANSFER_NOT_STARTED),
-      m_blockAdded(false),
-      m_GHDnDInProgress(false),
-      m_GHDnDDataReceived(false),
-      m_unityMode(false),
-      m_inHGDrag(false),
-      m_effect(DROP_NONE),
-      m_mousePosX(0),
-      m_mousePosY(0),
-      m_dc(NULL),
-      m_numPendingRequest(0),
-      m_destDropTime(0),
-      mTotalFileSize(0)
+    : mCtx(ctx),
+      mDnD(NULL),
+      mDetWnd(NULL),
+      mBlockCtrl(NULL),
+      mHGGetFileStatus(DND_FILE_TRANSFER_NOT_STARTED),
+      mBlockAdded(false),
+      mGHDnDInProgress(false),
+      mGHDnDDataReceived(false),
+      mUnityMode(false),
+      mInHGDrag(false),
+      mEffect(DROP_NONE),
+      mMousePosX(0),
+      mMousePosY(0),
+      mDragCtx(NULL),
+      mNumPendingRequest(0),
+      mDestDropTime(0),
+      mTotalFileSize(0),
+      mOrigin(0, 0)
 {
    TRACE_CALL();
+
+   xutils::Init();
+   xutils::workAreaChanged.connect(sigc::mem_fun(this, &DnDUIX11::OnWorkAreaChanged));
+
+   /*
+    * XXX Hard coded use of default screen means this doesn't work in dual-
+    * headed setups (e.g. DISPLAY=:0.1).  However, the number of people running
+    * such setups in VMs is expected to be, like, hella small, so I'mma cut
+    * corners for now.
+    */
+   OnWorkAreaChanged(Gdk::Screen::get_default());
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::~DnDUIX11 --
+ *
+ *      Destructor.
  *
- * Destructor.
+ *-----------------------------------------------------------------------------
  */
 
 DnDUIX11::~DnDUIX11()
 {
    TRACE_CALL();
-   if (m_detWnd) {
-      delete m_detWnd;
+
+   if (mDetWnd) {
+      delete mDetWnd;
    }
-   CPClipboard_Destroy(&m_clipboard);
+   CPClipboard_Destroy(&mClipboard);
    /* Any files from last unfinished file transfer should be deleted. */
-   if (DND_FILE_TRANSFER_IN_PROGRESS == m_HGGetFileStatus &&
-       !m_HGStagingDir.empty()) {
-      uint64 totalSize = File_GetSizeEx(m_HGStagingDir.c_str());
+   if (   DND_FILE_TRANSFER_IN_PROGRESS == mHGGetFileStatus
+       && !mHGStagingDir.empty()) {
+      uint64 totalSize = File_GetSizeEx(mHGStagingDir.c_str());
       if (mTotalFileSize != totalSize) {
          g_debug("%s: deleting %s, expecting %"FMT64"d, finished %"FMT64"d\n",
-                 __FUNCTION__, m_HGStagingDir.c_str(),
+                 __FUNCTION__, mHGStagingDir.c_str(),
                  mTotalFileSize, totalSize);
-         DnD_DeleteStagingFiles(m_HGStagingDir.c_str(), FALSE);
+         DnD_DeleteStagingFiles(mHGStagingDir.c_str(), FALSE);
       } else {
          g_debug("%s: file size match %s\n",
-                 __FUNCTION__, m_HGStagingDir.c_str());
+                 __FUNCTION__, mHGStagingDir.c_str());
       }
    }
-   CommonResetCB();
+   ResetUI();
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::Init --
+ *
+ *      Initialize DnDUIX11 object.
+ *
+ * Results:
+ *      Returns true on success and false on failure.
  *
- * Initialize DnDUIX11 object.
+ *-----------------------------------------------------------------------------
  */
 
 bool
@@ -122,15 +159,15 @@ DnDUIX11::Init()
    TRACE_CALL();
    bool ret = true;
 
-   CPClipboard_Init(&m_clipboard);
+   CPClipboard_Init(&mClipboard);
 
    GuestDnDCPMgr *p = GuestDnDCPMgr::GetInstance();
    ASSERT(p);
-   m_DnD = p->GetDnDMgr();
-   ASSERT(m_DnD);
+   mDnD = p->GetDnDMgr();
+   ASSERT(mDnD);
 
-   m_detWnd = new DragDetWnd();
-   if (!m_detWnd) {
+   mDetWnd = new DragDetWnd();
+   if (!mDetWnd) {
       g_debug("%s: unable to allocate DragDetWnd object\n", __FUNCTION__);
       goto fail;
    }
@@ -142,70 +179,73 @@ DnDUIX11::Init()
     * Gtk::Invisible, which doesn't implement the methods that SetAttributes
     * relies upon.
     */
-   m_detWnd->SetAttributes();
+   mDetWnd->SetAttributes();
 #endif
 
-   SetTargetsAndCallbacks();
+   InitGtk();
 
 #define CONNECT_SIGNAL(_obj, _sig, _cb) \
    _obj->_sig.connect(sigc::mem_fun(this, &DnDUIX11::_cb))
 
    /* Set common layer callbacks. */
-   CONNECT_SIGNAL(m_DnD, srcDragBeginChanged,   CommonDragStartCB);
-   CONNECT_SIGNAL(m_DnD, srcDropChanged,        CommonSourceDropCB);
-   CONNECT_SIGNAL(m_DnD, srcCancelChanged,      CommonSourceCancelCB);
-   CONNECT_SIGNAL(m_DnD, destCancelChanged,     CommonDestCancelCB);
-   CONNECT_SIGNAL(m_DnD, destMoveDetWndToMousePosChanged, CommonMoveDetWndToMousePos);
-   CONNECT_SIGNAL(m_DnD, getFilesDoneChanged,   CommonSourceFileCopyDoneCB);
-   CONNECT_SIGNAL(m_DnD, moveMouseChanged,      CommonUpdateMouseCB);
-   CONNECT_SIGNAL(m_DnD, privDropChanged,       CommonDestPrivateDropCB);
-   CONNECT_SIGNAL(m_DnD, updateDetWndChanged,   CommonUpdateDetWndCB);
-   CONNECT_SIGNAL(m_DnD, updateUnityDetWndChanged, CommonUpdateUnityDetWndCB);
+   CONNECT_SIGNAL(mDnD, srcDragBeginChanged,   OnSrcDragBegin);
+   CONNECT_SIGNAL(mDnD, srcDropChanged,        OnSrcDrop);
+   CONNECT_SIGNAL(mDnD, srcCancelChanged,      OnSrcCancel);
+   CONNECT_SIGNAL(mDnD, destCancelChanged,     OnDestCancel);
+   CONNECT_SIGNAL(mDnD, destMoveDetWndToMousePosChanged, OnDestMoveDetWndToMousePos);
+   CONNECT_SIGNAL(mDnD, getFilesDoneChanged,   OnGetFilesDone);
+   CONNECT_SIGNAL(mDnD, moveMouseChanged,      OnMoveMouse);
+   CONNECT_SIGNAL(mDnD, privDropChanged,       OnPrivateDrop);
+   CONNECT_SIGNAL(mDnD, updateDetWndChanged,   OnUpdateDetWnd);
+   CONNECT_SIGNAL(mDnD, updateUnityDetWndChanged, OnUpdateUnityDetWnd);
 
    /* Set Gtk+ callbacks for source. */
-   CONNECT_SIGNAL(m_detWnd, signal_drag_begin(),        GtkSourceDragBeginCB);
-   CONNECT_SIGNAL(m_detWnd, signal_drag_data_get(),     GtkSourceDragDataGetCB);
-   CONNECT_SIGNAL(m_detWnd, signal_drag_end(),          GtkSourceDragEndCB);
-   CONNECT_SIGNAL(m_detWnd, signal_enter_notify_event(), GtkEnterEventCB);
-   CONNECT_SIGNAL(m_detWnd, signal_leave_notify_event(), GtkLeaveEventCB);
-   CONNECT_SIGNAL(m_detWnd, signal_map_event(),         GtkMapEventCB);
-   CONNECT_SIGNAL(m_detWnd, signal_unmap_event(),       GtkUnmapEventCB);
-   CONNECT_SIGNAL(m_detWnd, signal_realize(),           GtkRealizeEventCB);
-   CONNECT_SIGNAL(m_detWnd, signal_unrealize(),         GtkUnrealizeEventCB);
-   CONNECT_SIGNAL(m_detWnd, signal_motion_notify_event(), GtkMotionNotifyEventCB);
-   CONNECT_SIGNAL(m_detWnd, signal_configure_event(),   GtkConfigureEventCB);
-   CONNECT_SIGNAL(m_detWnd, signal_button_press_event(), GtkButtonPressEventCB);
-   CONNECT_SIGNAL(m_detWnd, signal_button_release_event(), GtkButtonReleaseEventCB);
+   CONNECT_SIGNAL(mDetWnd, signal_drag_begin(),        OnGtkDragBegin);
+   CONNECT_SIGNAL(mDetWnd, signal_drag_data_get(),     OnGtkDragDataGet);
+   CONNECT_SIGNAL(mDetWnd, signal_drag_end(),          OnGtkDragEnd);
+   CONNECT_SIGNAL(mDetWnd, signal_enter_notify_event(), GtkEnterEventCB);
+   CONNECT_SIGNAL(mDetWnd, signal_leave_notify_event(), GtkLeaveEventCB);
+   CONNECT_SIGNAL(mDetWnd, signal_map_event(),         GtkMapEventCB);
+   CONNECT_SIGNAL(mDetWnd, signal_unmap_event(),       GtkUnmapEventCB);
+   CONNECT_SIGNAL(mDetWnd, signal_realize(),           GtkRealizeEventCB);
+   CONNECT_SIGNAL(mDetWnd, signal_unrealize(),         GtkUnrealizeEventCB);
+   CONNECT_SIGNAL(mDetWnd, signal_motion_notify_event(), GtkMotionNotifyEventCB);
+   CONNECT_SIGNAL(mDetWnd, signal_configure_event(),   GtkConfigureEventCB);
+   CONNECT_SIGNAL(mDetWnd, signal_button_press_event(), GtkButtonPressEventCB);
+   CONNECT_SIGNAL(mDetWnd, signal_button_release_event(), GtkButtonReleaseEventCB);
 
 #undef CONNECT_SIGNAL
 
-   CommonUpdateDetWndCB(false, 0, 0);
-   CommonUpdateUnityDetWndCB(false, 0, false);
+   OnUpdateDetWnd(false, 0, 0);
+   OnUpdateUnityDetWnd(false, 0, false);
    goto out;
 fail:
    ret = false;
-   if (m_DnD) {
-      delete m_DnD;
-      m_DnD = NULL;
+   if (mDnD) {
+      delete mDnD;
+      mDnD = NULL;
    }
-   if (m_detWnd) {
-      delete m_detWnd;
-      m_detWnd = NULL;
+   if (mDetWnd) {
+      delete mDetWnd;
+      mDetWnd = NULL;
    }
 out:
    return ret;
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::InitGtk --
+ *
+ *      Register supported DND target types and signal handlers with GTK+.
  *
- * Setup targets we support, claim ourselves as a drag destination, and
- * register callbacks for Gtk+ drag and drop callbacks the platform will
- * send to us.
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::SetTargetsAndCallbacks()
+DnDUIX11::InitGtk()
 {
    TRACE_CALL();
 
@@ -238,64 +278,89 @@ DnDUIX11::SetTargetsAndCallbacks()
     * but in our case, we will call drag_get_data during DragMotion, and
     * will cause X dead with DEST_DEFAULT_ALL. The reason is unclear.
     */
-   m_detWnd->drag_dest_set(targets, Gtk::DEST_DEFAULT_MOTION,
-                           Gdk::ACTION_COPY | Gdk::ACTION_MOVE);
-   m_detWnd->signal_drag_leave().connect(sigc::mem_fun(this, &DnDUIX11::GtkDestDragLeaveCB));
-   m_detWnd->signal_drag_motion().connect(sigc::mem_fun(this, &DnDUIX11::GtkDestDragMotionCB));
-   m_detWnd->signal_drag_drop().connect(sigc::mem_fun(this, &DnDUIX11::GtkDestDragDropCB));
-   m_detWnd->signal_drag_data_received().connect(sigc::mem_fun(this, &DnDUIX11::GtkDestDragDataReceivedCB));
+   mDetWnd->drag_dest_set(targets, Gtk::DEST_DEFAULT_MOTION,
+                          Gdk::ACTION_COPY | Gdk::ACTION_MOVE);
+
+   mDetWnd->signal_drag_leave().connect(
+      sigc::mem_fun(this, &DnDUIX11::OnGtkDragLeave));
+   mDetWnd->signal_drag_motion().connect(
+      sigc::mem_fun(this, &DnDUIX11::OnGtkDragMotion));
+   mDetWnd->signal_drag_drop().connect(
+      sigc::mem_fun(this, &DnDUIX11::OnGtkDragDrop));
+   mDetWnd->signal_drag_data_received().connect(
+      sigc::mem_fun(this, &DnDUIX11::OnGtkDragDataReceived));
 }
 
-/* Begin of callbacks issued by common layer code */
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::ResetUI --
  *
- * Reset Callback to reset dnd ui state.
+ *      Reset UI state variables.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      May remove a vmblock blocking entry.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::CommonResetCB(void)
+DnDUIX11::ResetUI()
 {
    TRACE_CALL();
-   m_GHDnDDataReceived = false;
-   m_HGGetFileStatus = DND_FILE_TRANSFER_NOT_STARTED;
-   m_GHDnDInProgress = false;
-   m_effect = DROP_NONE;
-   m_inHGDrag = false;
-   m_dc = NULL;
+   mGHDnDDataReceived = false;
+   mHGGetFileStatus = DND_FILE_TRANSFER_NOT_STARTED;
+   mGHDnDInProgress = false;
+   mEffect = DROP_NONE;
+   mInHGDrag = false;
+   mDragCtx = NULL;
    RemoveBlock();
 }
 
 
 /* Source functions for HG DnD. */
 
-/**
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::OnSrcDragBegin --
+ *
+ *      Called when host successfully detected a pending HG drag.
+ *
+ * Results:
+ *      None.
  *
- * Called when host successfully detected a pending HG drag.
+ * Side effects:
+ *      Calls mDetWnd->drag_begin().
  *
- * param[in] clip cross-platform clipboard
- * param[in] stagingDir associated staging directory
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::CommonDragStartCB(const CPClipboard *clip, std::string stagingDir)
+DnDUIX11::OnSrcDragBegin(const CPClipboard *clip,       // IN
+                         const std::string stagingDir)  // IN
 {
    Glib::RefPtr<Gtk::TargetList> targets;
    Gdk::DragAction actions;
    GdkEventMotion event;
 
-   CPClipboard_Clear(&m_clipboard);
-   CPClipboard_Copy(&m_clipboard, clip);
-
    TRACE_CALL();
 
+   CPClipboard_Clear(&mClipboard);
+   CPClipboard_Copy(&mClipboard, clip);
+
    /*
     * Before the DnD, we should make sure that the mouse is released
     * otherwise it may be another DnD, not ours. Send a release, then
     * a press here to cover this case.
     */
    SendFakeXEvents(false, true, false, false, false, 0, 0);
-   SendFakeXEvents(true, true, true, false, true, 0, 0);
+   SendFakeXEvents(true, true, true, true, true, mOrigin.get_x(), mOrigin.get_y());
 
    /*
     * Construct the target and action list, as well as a fake motion notify
@@ -303,9 +368,9 @@ DnDUIX11::CommonDragStartCB(const CPClipboard *clip, std::string stagingDir)
     */
    targets = Gtk::TargetList::create(std::list<Gtk::TargetEntry>());
 
-   if (CPClipboard_ItemExists(&m_clipboard, CPFORMAT_FILELIST)) {
-      m_HGStagingDir = stagingDir;
-      if (!m_HGStagingDir.empty()) {
+   if (CPClipboard_ItemExists(&mClipboard, CPFORMAT_FILELIST)) {
+      mHGStagingDir = stagingDir;
+      if (!mHGStagingDir.empty()) {
          targets->add(Glib::ustring(DRAG_TARGET_NAME_URI_LIST));
          /* Add private data to tag dnd as originating from this vm. */
          char *pid;
@@ -318,20 +383,20 @@ DnDUIX11::CommonDragStartCB(const CPClipboard *clip, std::string stagingDir)
       }
    }
 
-   if (CPClipboard_ItemExists(&m_clipboard, CPFORMAT_FILECONTENTS)) {
+   if (CPClipboard_ItemExists(&mClipboard, CPFORMAT_FILECONTENTS)) {
       if (WriteFileContentsToStagingDir()) {
          targets->add(Glib::ustring(DRAG_TARGET_NAME_URI_LIST));
       }
    }
 
-   if (CPClipboard_ItemExists(&m_clipboard, CPFORMAT_TEXT)) {
+   if (CPClipboard_ItemExists(&mClipboard, CPFORMAT_TEXT)) {
       targets->add(Glib::ustring(TARGET_NAME_STRING));
       targets->add(Glib::ustring(TARGET_NAME_TEXT_PLAIN));
       targets->add(Glib::ustring(TARGET_NAME_UTF8_STRING));
       targets->add(Glib::ustring(TARGET_NAME_COMPOUND_TEXT));
    }
 
-   if (CPClipboard_ItemExists(&m_clipboard, CPFORMAT_RTF)) {
+   if (CPClipboard_ItemExists(&mClipboard, CPFORMAT_RTF)) {
       targets->add(Glib::ustring(TARGET_NAME_APPLICATION_RTF));
       targets->add(Glib::ustring(TARGET_NAME_TEXT_RICHTEXT));
    }
@@ -340,7 +405,7 @@ DnDUIX11::CommonDragStartCB(const CPClipboard *clip, std::string stagingDir)
 
    /* TODO set the x/y coords to the actual drag initialization point. */
    event.type = GDK_MOTION_NOTIFY;
-   event.window = m_detWnd->get_window()->gobj();
+   event.window = mDetWnd->get_window()->gobj();
    event.send_event = false;
    event.time = GDK_CURRENT_TIME;
    event.x = 10;
@@ -349,27 +414,38 @@ DnDUIX11::CommonDragStartCB(const CPClipboard *clip, std::string stagingDir)
    event.state = GDK_BUTTON1_MASK;
    event.is_hint = 0;
    event.device = gdk_device_get_core_pointer();
-   event.x_root = 0;
-   event.y_root = 5;
+   event.x_root = mOrigin.get_x();
+   event.y_root = mOrigin.get_y();
 
    /* Tell Gtk that a drag should be started from this widget. */
-   m_detWnd->drag_begin(targets, actions, 1, (GdkEvent *)&event);
-   m_blockAdded = false;
-   m_HGGetFileStatus = DND_FILE_TRANSFER_NOT_STARTED;
+   mDetWnd->drag_begin(targets, actions, 1, (GdkEvent *)&event);
+   mBlockAdded = false;
+   mHGGetFileStatus = DND_FILE_TRANSFER_NOT_STARTED;
    SourceDragStartDone();
    /* Initialize host hide feedback to DROP_NONE. */
-   m_effect = DROP_NONE;
-   SourceUpdateFeedback(m_effect);
+   mEffect = DROP_NONE;
+   SourceUpdateFeedback(mEffect);
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
  *
- * Cancel current HG DnD.
+ * DnDUIX11::OnSrcCancel --
+ *
+ *      Handler for when host cancels HG drag.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      Detection window and fake mouse events.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::CommonSourceCancelCB(void)
+DnDUIX11::OnSrcCancel()
 {
    TRACE_CALL();
 
@@ -379,142 +455,188 @@ DnDUIX11::CommonSourceCancelCB(void)
     * flybacks when we cancel as user moves mouse in and out of destination
     * window in a H->G DnD.
     */
-   CommonUpdateDetWndCB(true, 0, 0);
-   SendFakeXEvents(true, true, false, true, true, 0, 0);
-   CommonUpdateDetWndCB(false, 0, 0);
-   m_inHGDrag = false;
-   m_HGGetFileStatus = DND_FILE_TRANSFER_NOT_STARTED;
-   m_effect = DROP_NONE;
+   OnUpdateDetWnd(true, 0, 0);
+   SendFakeXEvents(true, true, false, true, true, mOrigin.get_x(), mOrigin.get_y());
+   OnUpdateDetWnd(false, 0, 0);
+   mInHGDrag = false;
+   mHGGetFileStatus = DND_FILE_TRANSFER_NOT_STARTED;
+   mEffect = DROP_NONE;
    RemoveBlock();
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
  *
- * Handle common layer private drop CB.
+ * DnDUIX11::OnPrivateDrop --
  *
- * @param[in] x position to release the mouse button (ignored).
- * @param[in] y position to release the mouse button (ignored).
+ *      Handler for private drop event.
  *
- * @note We ignore the coordinates, because we just need to release the mouse
- * in its current position.
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      Releases mouse button at current position.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::CommonDestPrivateDropCB(int32 x,
-                                  int32 y)
+DnDUIX11::OnPrivateDrop(int32 x,        // UNUSED
+                        int32 y)        // UNUSED
 {
    TRACE_CALL();
+
    /* Unity manager in host side may already send the drop into guest. */
-   if (m_GHDnDInProgress) {
+   if (mGHDnDInProgress) {
 
       /*
        * Release the mouse button.
        */
       SendFakeXEvents(false, true, false, false, false, 0, 0);
    }
-   CommonResetCB();
+   ResetUI();
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::OnDestCancel --
  *
- * Cancel current DnD (G->H only).
+ *      Handler for GH drag cancellation.
+ *
+ *      Note: This event fires as part of the complete guest-to-host sequence,
+ *      not just error or user cancellation.
+ *
+ * Results:
+ *      Uses detection window and fake mouse events to intercept drop.
+ *
+ * Side effects:
+ *      Reinitializes UI state.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::CommonDestCancelCB(void)
+DnDUIX11::OnDestCancel()
 {
    TRACE_CALL();
-   /* Unity manager in host side may already send the drop into guest. */
-   if (m_GHDnDInProgress) {
-      CommonUpdateDetWndCB(true, 0, 0);
 
+   /* Unity manager in host side may already send the drop into guest. */
+   if (mGHDnDInProgress) {
       /*
        * Show the window, move it to the mouse position, and release the
        * mouse button.
        */
-      SendFakeXEvents(true, true, false, true, false, 0, 0);
+      SendFakeXEvents(true, true, false, true, false, mOrigin.get_x(),
+                      mOrigin.get_y());
    }
-   m_destDropTime = GetTimeInMillis();
-   CommonResetCB();
+   mDestDropTime = GetTimeInMillis();
+   ResetUI();
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::OnSrcDrop --
+ *
+ *      Callback when host signals drop.
  *
- * Got drop from host side. Release the mouse button in the detection window
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      Release the mouse button in the detection window.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::CommonSourceDropCB(void)
+DnDUIX11::OnSrcDrop()
 {
    TRACE_CALL();
-   CommonUpdateDetWndCB(true, 0, 0);
+   OnUpdateDetWnd(true, mOrigin.get_x(), mOrigin.get_y());
 
    /*
     * Move the mouse to the saved coordinates, and release the mouse button.
     */
-   SendFakeXEvents(false, true, false, false, true, m_mousePosX, m_mousePosY);
-   CommonUpdateDetWndCB(false, 0, 0);
+   SendFakeXEvents(false, true, false, false, true, mMousePosX, mMousePosY);
+   OnUpdateDetWnd(false, 0, 0);
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
  *
- * Callback when file transfer is done, which finishes the file
- * copying from host to guest staging directory.
+ * DnDUIX11::OnGetFilesDone --
  *
- * @param[in] success if true, transfer was successful
+ *      Callback when HG file transfer completes.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      Releases vmblock blocking entry.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::CommonSourceFileCopyDoneCB(bool success)
+DnDUIX11::OnGetFilesDone(bool success)  // IN: true if transfer succeeded
 {
    g_debug("%s: %s\n", __FUNCTION__, success ? "success" : "failed");
 
    /*
-    * If hg drag is not done yet, only remove block. GtkSourceDragEndCB will
-    * call CommonResetCB(). Otherwise destination may miss the data because
+    * If hg drag is not done yet, only remove block. OnGtkDragEnd will
+    * call ResetUI(). Otherwise destination may miss the data because
      * we are already reset.
     */
 
-   m_HGGetFileStatus = DND_FILE_TRANSFER_FINISHED;
+   mHGGetFileStatus = DND_FILE_TRANSFER_FINISHED;
 
-   if (!m_inHGDrag) {
-      CommonResetCB();
+   if (!mInHGDrag) {
+      ResetUI();
    } else {
       RemoveBlock();
    }
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::OnUpdateDetWnd --
  *
- * Shows/hides drag detection windows based on the mask.
+ *      Callback to show/hide drag detection window.
  *
- * @param[in] bShow if true, show the window, else hide it.
- * @param[in] x x-coordinate to which the detection window needs to be moved
- * @param[in] y y-coordinate to which the detection window needs to be moved
+ * Results:
+ *      Shows/hides and moves detection window.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::CommonUpdateDetWndCB(bool bShow,
-                               int32 x,
-                               int32 y)
+DnDUIX11::OnUpdateDetWnd(bool show,     // IN: show (true) or hide (false)
+                         int32 x,       // IN: detection window's destination x-coord
+                         int32 y)       // IN: detection window's destination y-coord
 {
    g_debug("%s: enter 0x%lx show %d x %d y %d\n",
          __FUNCTION__,
-         (unsigned long) m_detWnd->get_window()->gobj(), bShow, x, y);
+         (unsigned long) mDetWnd->get_window()->gobj(), show, x, y);
 
    /* If the window is being shown, move it to the right place. */
-   if (bShow) {
+   if (show) {
       x = MAX(x - DRAG_DET_WINDOW_WIDTH / 2, 0);
       y = MAX(y - DRAG_DET_WINDOW_WIDTH / 2, 0);
 
-      m_detWnd->Show();
-      m_detWnd->Raise();
-      m_detWnd->SetGeometry(x, y, DRAG_DET_WINDOW_WIDTH * 2, DRAG_DET_WINDOW_WIDTH * 2);
+      mDetWnd->Show();
+      mDetWnd->Raise();
+      mDetWnd->SetGeometry(x, y, DRAG_DET_WINDOW_WIDTH * 2, DRAG_DET_WINDOW_WIDTH * 2);
       g_debug("%s: show at (%d, %d, %d, %d)\n", __FUNCTION__, x, y, DRAG_DET_WINDOW_WIDTH * 2, DRAG_DET_WINDOW_WIDTH * 2);
       /*
        * Wiggle the mouse here. Especially for G->H DnD, this improves
@@ -523,46 +645,54 @@ DnDUIX11::CommonUpdateDetWndCB(bool bShow,
        */
 
       SendFakeMouseMove(x + 2, y + 2);
-      m_detWnd->SetIsVisible(true);
+      mDetWnd->SetIsVisible(true);
    } else {
       g_debug("%s: hide\n", __FUNCTION__);
-      m_detWnd->Hide();
-      m_detWnd->SetIsVisible(false);
+      mDetWnd->Hide();
+      mDetWnd->SetIsVisible(false);
    }
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::OnUpdateUnityDetWnd --
+ *
+ *      Callback to show/hide fullscreen Unity drag detection window.
  *
- * Shows/hides full-screen Unity drag detection window.
+ * Results:
+ *      None.
  *
- * @param[in] bShow if true, show the window, else hide it.
- * @param[in] unityWndId active front window
- * @param[in] bottom if true, adjust the z-order to be bottom most.
+ * Side effects:
+ *      Detection window shown, hidden.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::CommonUpdateUnityDetWndCB(bool bShow,
-                                    uint32 unityWndId,
-                                    bool bottom)
+DnDUIX11::OnUpdateUnityDetWnd(bool show,         // IN: show (true) or hide (false)
+                              uint32 unityWndId, // IN: XXX ?
+                              bool bottom)       // IN: place window at bottom of stack?
 {
    g_debug("%s: enter 0x%lx unityID 0x%x\n",
          __FUNCTION__,
-         (unsigned long) m_detWnd->get_window()->gobj(),
+         (unsigned long) mDetWnd->get_window()->gobj(),
          unityWndId);
-   if (bShow && ((unityWndId > 0) || bottom)) {
-      int width = m_detWnd->GetScreenWidth();
-      int height = m_detWnd->GetScreenHeight();
-      m_detWnd->SetGeometry(0, 0, width, height);
-      m_detWnd->Show();
+
+   if (show && ((unityWndId > 0) || bottom)) {
+      int width = mDetWnd->GetScreenWidth();
+      int height = mDetWnd->GetScreenHeight();
+      mDetWnd->SetGeometry(0, 0, width, height);
+      mDetWnd->Show();
       if (bottom) {
-         m_detWnd->Lower();
+         mDetWnd->Lower();
       }
 
       g_debug("%s: show, (0, 0, %d, %d)\n", __FUNCTION__, width, height);
    } else {
-      if (m_detWnd->GetIsVisible() == true) {
-         if (m_unityMode) {
+      if (mDetWnd->GetIsVisible() == true) {
+         if (mUnityMode) {
 
             /*
              * Show and move detection window to current mouse position
@@ -571,110 +701,133 @@ DnDUIX11::CommonUpdateUnityDetWndCB(bool bShow,
             SendFakeXEvents(true, false, true, true, false, 0, 0);
          }
       } else {
-         m_detWnd->Hide();
+         mDetWnd->Hide();
          g_debug("%s: hide\n", __FUNCTION__);
       }
    }
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
  *
- * Move detection windows to current cursor position.
+ * DnDUIX11::OnDestMoveDetWndToMousePos --
+ *
+ *      Callback to move detection window to current moue position.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      Detection window is moved, shown.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::CommonMoveDetWndToMousePos(void)
+DnDUIX11::OnDestMoveDetWndToMousePos()
 {
    SendFakeXEvents(true, false, true, true, false, 0, 0);
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::OnMoveMouse --
+ *
+ *      Callback to update mouse position.
+ *
+ * Results:
+ *      None.
  *
- * Handle request from common layer to update mouse position.
+ * Side effects:
+ *      Moves mouse.  Duh.
  *
- * @param[in] x x coordinate of pointer
- * @param[in] y y coordinate of pointer
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::CommonUpdateMouseCB(int32 x,
-                              int32 y)
+DnDUIX11::OnMoveMouse(int32 x,  // IN: Pointer x-coord
+                      int32 y)  // IN: Pointer y-coord
 {
    // Position the pointer, and record its position.
 
    SendFakeXEvents(false, false, false, false, true, x, y);
-   m_mousePosX = x;
-   m_mousePosY = y;
+   mMousePosX = x;
+   mMousePosY = y;
 
-   if (m_dc && !m_GHDnDInProgress) {
+   if (mDragCtx && !mGHDnDInProgress) {
 
       // If we are the context of a DnD, send DnD feedback to the source.
 
       DND_DROPEFFECT effect;
-      effect = ToDropEffect((Gdk::DragAction)(m_dc->action));
-      if (effect != m_effect) {
-         m_effect = effect;
+      effect = ToDropEffect((Gdk::DragAction)(mDragCtx->action));
+      if (effect != mEffect) {
+         mEffect = effect;
          g_debug("%s: Updating feedback\n", __FUNCTION__);
-         SourceUpdateFeedback(m_effect);
+         SourceUpdateFeedback(mEffect);
       }
    }
 }
 
-/* Beginning of Gtk+ Callbacks */
 
 /*
- * Source callbacks from Gtk+. Most are seen only when we are acting as a
- * drag source.
+ ****************************************************************************
+ * BEGIN GTK+ Callbacks (dndcp as drag source: host-to-guest)
  */
 
-/**
+
+/*
+ *-----------------------------------------------------------------------------
  *
- * "drag_motion" signal handler for GTK. We should respond by setting drag
- * status. Note that there is no drag enter signal. We need to figure out
- * if a new drag is happening on our own. Also, we don't respond with a
- * "allowed" drag status right away, we start a new drag operation over VMDB
- * (which tries to notify the host of the new operation). Once the host has
- * responded), we respond with a proper drag status.
- *
- * @param[in] dc associated drag context
- * @param[in] x x coordinate of the drag motion
- * @param[in] y y coordinate of the drag motion
- * @param[in] time time of the drag motion
- *
- * @return returning false means we won't get notified of future motion. So,
- * we only return false if we don't recognize the types being offered. We
- * return true otherwise, even if we don't accept the drag right now for some
- * other reason.
- *
- * @note you may see this callback during DnD when detection window is acting
- * as a source. In that case it will be ignored. In a future refactoring,
- * we will try and avoid this.
+ * DnDUIX11::OnGtkDragMotion --
+ *
+ *      GTK "drag_motion" signal handler.
+ *
+ *      We should respond by setting drag status. Note that there is no drag
+ *      enter signal. We need to figure out if a new drag is happening on
+ *      our own. Also, we don't respond with a "allowed" drag status right
+ *      away, we start a new drag operation with the host (which tries to
+ *      notify the host of the new operation). Once the host has responded),
+ *      we respond with a proper drag status.
+ *
+ *      Note: You may see this callback during DnD when detection window
+ *      is acting as a source. In that case it will be ignored. In a future
+ *      refactoring, we will try and avoid this.
+ *
+ * Results:
+ *      Returns true unless we don't recognize the types offered.
+ *
+ * Side effects:
+ *      Via RequestData issues a Gtk::Widget::drag_get_data.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 bool
-DnDUIX11::GtkDestDragMotionCB(const Glib::RefPtr<Gdk::DragContext> &dc,
-                              int x,
-                              int y,
-                              guint timeValue)
+DnDUIX11::OnGtkDragMotion(
+   const Glib::RefPtr<Gdk::DragContext> &dc,    // IN: GTK drag context
+   int x,                                       // IN: drag motion x-coord
+   int y,                                       // IN: drag motion y-coord
+   guint timeValue)                             // IN: event timestamp
 {
    /*
     * If this is a Host to Guest drag, we are done here, so return.
     */
    unsigned long curTime = GetTimeInMillis();
-   g_debug("%s: enter dc %p, m_dc %p\n", __FUNCTION__,
-         dc ? dc->gobj() : NULL, m_dc ? m_dc : NULL);
-   if (curTime - m_destDropTime <= 1000) {
+   g_debug("%s: enter dc %p, mDragCtx %p\n", __FUNCTION__,
+         dc ? dc->gobj() : NULL, mDragCtx ? mDragCtx : NULL);
+   if (curTime - mDestDropTime <= 1000) {
       g_debug("%s: ignored %ld %ld %ld\n", __FUNCTION__,
-            curTime, m_destDropTime, curTime - m_destDropTime);
+            curTime, mDestDropTime, curTime - mDestDropTime);
       return true;
    }
 
    g_debug("%s: not ignored %ld %ld %ld\n", __FUNCTION__,
-         curTime, m_destDropTime, curTime - m_destDropTime);
+         curTime, mDestDropTime, curTime - mDestDropTime);
 
-   if (m_inHGDrag || (m_HGGetFileStatus != DND_FILE_TRANSFER_NOT_STARTED)) {
+   if (mInHGDrag || (mHGGetFileStatus != DND_FILE_TRANSFER_NOT_STARTED)) {
       g_debug("%s: ignored not in hg drag or not getting hg data\n", __FUNCTION__);
       return true;
    }
@@ -682,9 +835,9 @@ DnDUIX11::GtkDestDragMotionCB(const Glib::RefPtr<Gdk::DragContext> &dc,
    Gdk::DragAction srcActions;
    Gdk::DragAction suggestedAction;
    Gdk::DragAction dndAction = (Gdk::DragAction)0;
-   Glib::ustring target = m_detWnd->drag_dest_find_target(dc);
+   Glib::ustring target = mDetWnd->drag_dest_find_target(dc);
 
-   if (!m_DnD->IsDnDAllowed()) {
+   if (!mDnD->IsDnDAllowed()) {
       g_debug("%s: No dnd allowed!\n", __FUNCTION__);
       dc->drag_status(dndAction, timeValue);
       return true;
@@ -715,7 +868,7 @@ DnDUIX11::GtkDestDragMotionCB(const Glib::RefPtr<Gdk::DragContext> &dc,
       return true;
    }
 
-   m_dc = dc->gobj();
+   mDragCtx = dc->gobj();
 
    if (target != "") {
       /*
@@ -739,14 +892,14 @@ DnDUIX11::GtkDestDragMotionCB(const Glib::RefPtr<Gdk::DragContext> &dc,
 
    if (dndAction != (Gdk::DragAction)0) {
       dc->drag_status(dndAction, timeValue);
-      if (!m_GHDnDInProgress) {
+      if (!mGHDnDInProgress) {
          g_debug("%s: new drag, need to get data for host\n", __FUNCTION__);
          /*
           * This is a new drag operation. We need to start a drag thru the
           * backdoor, and to the host. Before we can tell the host, we have to
           * retrieve the drop data.
           */
-         m_GHDnDInProgress = true;
+         mGHDnDInProgress = true;
          /* only begin drag enter after we get the data */
          /* Need to grab all of the data. */
          if (!RequestData(dc, timeValue)) {
@@ -765,21 +918,32 @@ DnDUIX11::GtkDestDragMotionCB(const Glib::RefPtr<Gdk::DragContext> &dc,
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::OnGtkDragLeave --
  *
- * "drag_leave" signal handler for GTK. Log the reception of this signal,
- * but otherwise unhandled in our implementation.
+ *      GTK+ "drag_leave" signal handler.
  *
- *  @param[in] dc drag context
- *  @param[in] time time of the drag
+ *      Logs event.  Acknowledges, finishes outdated sequence if drag context
+ *      is not the same as we're currently interested in (i.e. != mDragCtx).
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      May cancel dnd associated with this drag context.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::GtkDestDragLeaveCB(const Glib::RefPtr<Gdk::DragContext> &dc,
-                             guint time)
+DnDUIX11::OnGtkDragLeave(
+   const Glib::RefPtr<Gdk::DragContext> &dc,    // IN: GTK drag context
+   guint time)                                  // IN: event timestamp
 {
-   g_debug("%s: enter dc %p, m_dc %p\n", __FUNCTION__,
-         dc ? dc->gobj() : NULL, m_dc ? m_dc : NULL);
+   g_debug("%s: enter dc %p, mDragCtx %p\n", __FUNCTION__,
+         dc ? dc->gobj() : NULL, mDragCtx ? mDragCtx : NULL);
 
    /*
     * If we reach here after reset DnD, or we are getting a late
@@ -789,7 +953,7 @@ DnDUIX11::GtkDestDragLeaveCB(const Glib::RefPtr<Gdk::DragContext> &dc,
     * be 5 minutes).
     * See http://bugzilla.eng.vmware.com/show_bug.cgi?id=528320
     */
-   if (!m_dc || dc->gobj() != m_dc) {
+   if (!mDragCtx || dc->gobj() != mDragCtx) {
       g_debug("%s: calling drag_finish\n", __FUNCTION__);
       dc->drag_finish(true, false, time);
    }
@@ -797,44 +961,57 @@ DnDUIX11::GtkDestDragLeaveCB(const Glib::RefPtr<Gdk::DragContext> &dc,
 
 
 /*
- * Gtk+ callbacks that are seen when we are a drag source.
- */
-
-/**
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::OnGtkDragBegin --
+ *
+ *      GTK+ "drag_begin" signal handler.
+ *
+ * Results:
+ *      None.
  *
- * "drag_begin" signal handler for GTK.
+ * Side effects:
+ *      Records drag context for later use.
  *
- * @param[in] context drag context
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::GtkSourceDragBeginCB(const Glib::RefPtr<Gdk::DragContext>& context)
+DnDUIX11::OnGtkDragBegin(
+   const Glib::RefPtr<Gdk::DragContext>& context)       // IN: GTK drag context
 {
-   g_debug("%s: enter dc %p, m_dc %p\n", __FUNCTION__,
-         context ? context->gobj() : NULL, m_dc ? m_dc : NULL);
-   m_dc = context->gobj();
+   g_debug("%s: enter dc %p, mDragCtx %p\n", __FUNCTION__,
+         context ? context->gobj() : NULL, mDragCtx ? mDragCtx : NULL);
+   mDragCtx = context->gobj();
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::OnGtkDragDataGet --
+ *
+ *      GTK+ "drag_data_get" signal handler.
  *
- * "drag_data_get" handler for GTK. We don't send drop until we are done.
+ * Results:
+ *      None.
  *
- * @param[in] dc drag state
- * @param[in] selection_data buffer for data
- * @param[in] info unused
- * @param[in] time timestamp
+ * Side effects:
+ *      May insert vmblock blocking entry and request host-to-guest file transfer from
+ *      host.
  *
- * @note if the drop has occurred, the files are copied from the guest.
+ *      If unable to obtain drag information, may instead cancel the DND
+ *      operation.
  *
  *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::GtkSourceDragDataGetCB(const Glib::RefPtr<Gdk::DragContext> &dc,
-                                 Gtk::SelectionData& selection_data,
-                                 guint info,
-                                 guint time)
+DnDUIX11::OnGtkDragDataGet(
+   const Glib::RefPtr<Gdk::DragContext> &dc,    // IN: GTK drag context
+   Gtk::SelectionData& selection_data,          // IN: drag details
+   guint info,                                  // UNUSED
+   guint time)                                  // IN: event timestamp
 {
    size_t index = 0;
    std::string str;
@@ -851,23 +1028,23 @@ DnDUIX11::GtkSourceDragDataGetCB(const Glib::RefPtr<Gdk::DragContext> &dc,
 
    selection_data.set(target.c_str(), "");
 
-   g_debug("%s: enter dc %p, m_dc %p with target %s\n", __FUNCTION__,
-         dc ? dc->gobj() : NULL, m_dc ? m_dc : NULL,
-         target.c_str());
+   g_debug("%s: enter dc %p, mDragCtx %p with target %s\n", __FUNCTION__,
+           dc ? dc->gobj() : NULL, mDragCtx ? mDragCtx : NULL,
+           target.c_str());
 
-   if (!m_inHGDrag) {
+   if (!mInHGDrag) {
       g_debug("%s: not in drag, return\n", __FUNCTION__);
       return;
    }
 
-   if (target == DRAG_TARGET_NAME_URI_LIST &&
-       CPClipboard_GetItem(&m_clipboard, CPFORMAT_FILELIST, &buf, &sz)) {
+   if (   target == DRAG_TARGET_NAME_URI_LIST
+       && CPClipboard_GetItem(&mClipboard, CPFORMAT_FILELIST, &buf, &sz)) {
 
       /* Provide path within vmblock file system instead of actual path. */
-      stagingDirName = GetLastDirName(m_HGStagingDir);
+      stagingDirName = GetLastDirName(mHGStagingDir);
       if (stagingDirName.length() == 0) {
          g_debug("%s: Cannot get staging directory name, stagingDir: %s\n",
-               __FUNCTION__, m_HGStagingDir.c_str());
+                 __FUNCTION__, mHGStagingDir.c_str());
          return;
       }
 
@@ -887,7 +1064,7 @@ DnDUIX11::GtkSourceDragDataGetCB(const Glib::RefPtr<Gdk::DragContext> &dc,
          post = DND_URI_LIST_POST;
       } else {
          g_debug("%s: Unknown request target: %s\n", __FUNCTION__,
-               selection_data.get_target().c_str());
+                 selection_data.get_target().c_str());
          return;
       }
 
@@ -897,11 +1074,11 @@ DnDUIX11::GtkSourceDragDataGetCB(const Glib::RefPtr<Gdk::DragContext> &dc,
       /* Provide URIs for each path in the guest's file list. */
       while ((str = GetNextPath(hgData, index).c_str()).length() != 0) {
          uriList += pre;
-         if (DnD_BlockIsReady(m_blockCtrl)) {
-            uriList += m_blockCtrl->blockRoot;
+         if (DnD_BlockIsReady(mBlockCtrl)) {
+            uriList += mBlockCtrl->blockRoot;
             uriList += DIRSEPS + stagingDirName + DIRSEPS + str + post;
          } else {
-            uriList += DIRSEPS + m_HGStagingDir + DIRSEPS + str + post;
+            uriList += DIRSEPS + mHGStagingDir + DIRSEPS + str + post;
          }
       }
 
@@ -922,10 +1099,10 @@ DnDUIX11::GtkSourceDragDataGetCB(const Glib::RefPtr<Gdk::DragContext> &dc,
        * Doing both of these addresses bug
        * http://bugzilla.eng.vmware.com/show_bug.cgi?id=391661.
        */
-      if (!m_blockAdded &&
-          m_inHGDrag &&
-          (m_HGGetFileStatus == DND_FILE_TRANSFER_NOT_STARTED)) {
-         m_HGGetFileStatus = DND_FILE_TRANSFER_IN_PROGRESS;
+      if (   !mBlockAdded
+          &&  mInHGDrag
+          && (mHGGetFileStatus == DND_FILE_TRANSFER_NOT_STARTED)) {
+         mHGGetFileStatus = DND_FILE_TRANSFER_IN_PROGRESS;
          AddBlock();
       } else {
          g_debug("%s: not calling AddBlock\n", __FUNCTION__);
@@ -935,29 +1112,25 @@ DnDUIX11::GtkSourceDragDataGetCB(const Glib::RefPtr<Gdk::DragContext> &dc,
       return;
    }
 
-   if (target == DRAG_TARGET_NAME_URI_LIST &&
-       CPClipboard_ItemExists(&m_clipboard, CPFORMAT_FILECONTENTS)) {
+   if (   target == DRAG_TARGET_NAME_URI_LIST
+       && CPClipboard_ItemExists(&mClipboard, CPFORMAT_FILECONTENTS)) {
       g_debug("%s: Providing uriList [%s] for file contents DnD\n",
-            __FUNCTION__, m_HGFileContentsUriList.c_str());
+            __FUNCTION__, mHGFileContentsUriList.c_str());
 
       selection_data.set(DRAG_TARGET_NAME_URI_LIST,
-                         m_HGFileContentsUriList.c_str());
+                         mHGFileContentsUriList.c_str());
       return;
    }
 
-   if ((target == TARGET_NAME_STRING ||
-        target == TARGET_NAME_TEXT_PLAIN ||
-        target == TARGET_NAME_UTF8_STRING ||
-        target == TARGET_NAME_COMPOUND_TEXT) &&
-       CPClipboard_GetItem(&m_clipboard, CPFORMAT_TEXT, &buf, &sz)) {
+   if (   TargetIsPlainText(target)
+       && CPClipboard_GetItem(&mClipboard, CPFORMAT_TEXT, &buf, &sz)) {
       g_debug("%s: providing plain text, size %"FMTSZ"u\n", __FUNCTION__, sz);
       selection_data.set(target.c_str(), (const char *)buf);
       return;
    }
 
-   if ((target == TARGET_NAME_APPLICATION_RTF ||
-        target == TARGET_NAME_TEXT_RICHTEXT) &&
-       CPClipboard_GetItem(&m_clipboard, CPFORMAT_RTF, &buf, &sz)) {
+   if (   TargetIsRichText(target)
+       && CPClipboard_GetItem(&mClipboard, CPFORMAT_RTF, &buf, &sz)) {
       g_debug("%s: providing rtf text, size %"FMTSZ"u\n", __FUNCTION__, sz);
       selection_data.set(target.c_str(), (const char *)buf);
       return;
@@ -965,73 +1138,95 @@ DnDUIX11::GtkSourceDragDataGetCB(const Glib::RefPtr<Gdk::DragContext> &dc,
 
    /* Can not get any valid data, cancel this HG DnD. */
    g_debug("%s: no valid data for HG DnD\n", __FUNCTION__);
-   CommonResetCB();
+   ResetUI();
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::OnGtkDragEnd --
+ *
+ *      GTK+ "drag_end" signal handler.
  *
- * "drag_end" handler for GTK. Received by drag source.
+ * Results:
+ *      None.
  *
- * @param[in] dc drag state
+ * Side effects:
+ *      May reset UI state.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::GtkSourceDragEndCB(const Glib::RefPtr<Gdk::DragContext> &dc)
+DnDUIX11::OnGtkDragEnd(
+   const Glib::RefPtr<Gdk::DragContext> &dc)    // IN: GTK drag context
 {
-   g_debug("%s: entering dc %p, m_dc %p\n", __FUNCTION__,
-         dc ? dc->gobj() : NULL, m_dc ? m_dc : NULL);
+   g_debug("%s: entering dc %p, mDragCtx %p\n", __FUNCTION__,
+         dc ? dc->gobj() : NULL, mDragCtx ? mDragCtx : NULL);
 
    /*
     * We may see a drag end for the previous DnD, but after a new
     * DnD has started. If so, ignore it.
     */
-   if (m_dc && dc && (m_dc != dc->gobj())) {
+   if (mDragCtx && dc && (mDragCtx != dc->gobj())) {
       g_debug("%s: got old dc (new DnD started), ignoring\n", __FUNCTION__);
       return;
    }
 
    /*
     * If we are a file DnD and file transfer is not done yet, don't call
-    * CommonResetCB() here, since we will do so in the fileCopyDoneChanged
+    * ResetUI() here, since we will do so in the fileCopyDoneChanged
     * callback.
     */
-   if (DND_FILE_TRANSFER_IN_PROGRESS != m_HGGetFileStatus) {
-      CommonResetCB();
+   if (DND_FILE_TRANSFER_IN_PROGRESS != mHGGetFileStatus) {
+      ResetUI();
    }
-   m_inHGDrag = false;
+   mInHGDrag = false;
 }
 
-/* Gtk+ callbacks seen when we are a drag destination. */
 
-/**
+/*
+ * END GTK+ Callbacks (dndcp as drag source: host-to-guest)
+ ****************************************************************************
+ */
+
+
+/*
+ ****************************************************************************
+ * BEGIN GTK+ Callbacks (dndcp as drag destination: guest-to-host)
+ */
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::OnGtkDragDataReceived --
+ *
+ *      GTK+ "drag_data_received" signal handler.
  *
- * "drag_data_received" signal handler for GTK. We requested the drag
- * data earlier from some drag source on the guest; this is the response.
+ * Results:
+ *      None.
  *
- * This is for G->H DnD.
+ * Side effects:
+ *      May signal to host beginning of guest-to-host DND.
  *
- * @param[in] dc drag context
- * @param[in] x where the drop happened
- * @param[in] y where the drop happened
- * @param[in] sd the received data
- * @param[in] info the info that has been registered with the target in the
- * target list.
- * @param[in] time the timestamp at which the data was received.
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::GtkDestDragDataReceivedCB(const Glib::RefPtr<Gdk::DragContext> &dc,
-                                    int x,
-                                    int y,
-                                    const Gtk::SelectionData& sd,
-                                    guint info,
-                                    guint time)
+DnDUIX11::OnGtkDragDataReceived(
+   const Glib::RefPtr<Gdk::DragContext> &dc,    // IN: GTK drag context
+   int x,                                       // IN: drop location x-coord
+   int y,                                       // IN: drop location y-coord
+   const Gtk::SelectionData& sd,                // IN: drag content details
+   guint info,                                  // UNUSED
+   guint time)                                  // IN: event timestamp
 {
-   g_debug("%s: enter dc %p, m_dc %p\n", __FUNCTION__,
-         dc ? dc->gobj() : NULL, m_dc ? m_dc : NULL);
+   g_debug("%s: enter dc %p, mDragCtx %p\n", __FUNCTION__,
+         dc ? dc->gobj() : NULL, mDragCtx ? mDragCtx : NULL);
    /* The GH DnD may already finish before we got response. */
-   if (!m_GHDnDInProgress) {
+   if (!mGHDnDInProgress) {
       g_debug("%s: not valid\n", __FUNCTION__);
       return;
    }
@@ -1044,18 +1239,18 @@ DnDUIX11::GtkDestDragDataReceivedCB(const Glib::RefPtr<Gdk::DragContext> &dc,
     */
    if (SetCPClipboardFromGtk(sd) == false) {
       g_debug("%s: Failed to set CP clipboard.\n", __FUNCTION__);
-      CommonResetCB();
+      ResetUI();
       return;
    }
 
-   m_numPendingRequest--;
-   if (m_numPendingRequest > 0) {
+   mNumPendingRequest--;
+   if (mNumPendingRequest > 0) {
       return;
    }
 
-   if (CPClipboard_IsEmpty(&m_clipboard)) {
+   if (CPClipboard_IsEmpty(&mClipboard)) {
       g_debug("%s: Failed getting item.\n", __FUNCTION__);
-      CommonResetCB();
+      ResetUI();
       return;
    }
 
@@ -1070,41 +1265,46 @@ DnDUIX11::GtkDestDragDataReceivedCB(const Glib::RefPtr<Gdk::DragContext> &dc,
     * Note that we prevent against sending multiple "dragStart"s or "drop"s for
     * each DnD.
     */
-   if (!m_GHDnDDataReceived) {
+   if (!mGHDnDDataReceived) {
       g_debug("%s: Drag entering.\n", __FUNCTION__);
-      m_GHDnDDataReceived = true;
+      mGHDnDDataReceived = true;
       TargetDragEnter();
    } else {
-      g_debug("%s: not !m_GHDnDDataReceived\n", __FUNCTION__);
+      g_debug("%s: not !mGHDnDDataReceived\n", __FUNCTION__);
    }
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::OnGtkDragDrop --
+ *
+ *      GTK+ "drag_drop" signal handler.
  *
- * "drag_drop" signal handler for GTK. Send the drop to the host (by
- * way of the backdoor), then tell the host to get the files.
+ * Results:
+ *      Returns true so long as drag target and data are (at one point)
+ *      provided (i.e. not a spurious event).
  *
- * @param[in] dc drag context
- * @param[in] x x location of the drop
- * @param[in] y y location of the drop
- * @param[in] time timestamp for the drop
+ * Side effects:
+ *      Signals to drag source that drop is finished.
  *
- * @return true on success, false otherwise.
+ *-----------------------------------------------------------------------------
  */
 
 bool
-DnDUIX11::GtkDestDragDropCB(const Glib::RefPtr<Gdk::DragContext> &dc,
-                            int x,
-                            int y,
-                            guint time)
+DnDUIX11::OnGtkDragDrop(
+   const Glib::RefPtr<Gdk::DragContext> &dc,    // IN: GTK drag context
+   int x,                                       // IN: drop location x-coord
+   int y,                                       // IN: drop location y-coord
+   guint time)                                  // IN: motion event timestamp
 {
-   g_debug("%s: enter dc %p, m_dc %p x %d y %d\n", __FUNCTION__,
-         (dc ? dc->gobj() : NULL), (m_dc ? m_dc : NULL), x, y);
+   g_debug("%s: enter dc %p, mDragCtx %p x %d y %d\n", __FUNCTION__,
+         (dc ? dc->gobj() : NULL), (mDragCtx ? mDragCtx : NULL), x, y);
 
    Glib::ustring target;
 
-   target = m_detWnd->drag_dest_find_target(dc);
+   target = mDetWnd->drag_dest_find_target(dc);
    g_debug("%s: calling drag_finish\n", __FUNCTION__);
    dc->drag_finish(true, false, time);
 
@@ -1113,24 +1313,35 @@ DnDUIX11::GtkDestDragDropCB(const Glib::RefPtr<Gdk::DragContext> &dc,
       return false;
    }
 
-   if (CPClipboard_IsEmpty(&m_clipboard)) {
-      g_debug("%s: No valid data on m_clipboard.\n", __FUNCTION__);
+   if (CPClipboard_IsEmpty(&mClipboard)) {
+      g_debug("%s: No valid data on mClipboard.\n", __FUNCTION__);
       return false;
    }
 
    return true;
 }
 
-/* General utility functions */
 
-/**
+/*
+ * END GTK+ Callbacks (dndcp as drag destination: guest-to-host)
+ ****************************************************************************
+ */
+
+
+/*
+ *-----------------------------------------------------------------------------
  *
- * Try to construct cross-platform clipboard data from selection data
- * provided to us by Gtk+.
+ * DnDUIX11::SetCPClipboardFromGtk --
  *
- * @param[in] sd Gtk selection data to convert to CP clipboard data
+ *      Construct cross-platform clipboard from GTK+ selection_data.
  *
- * @return false on failure, true on success
+ * Results:
+ *      Returns true if conversion succeeded, false otherwise.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 bool
@@ -1148,7 +1359,7 @@ DnDUIX11::SetCPClipboardFromGtk(const Gtk::SelectionData& sd) // IN
    const utf::string target = sd.get_target().c_str();
 
    /* Try to get file list. */
-   if (m_DnD->CheckCapability(DND_CP_CAP_FILE_DND) && target == DRAG_TARGET_NAME_URI_LIST) {
+   if (mDnD->CheckCapability(DND_CP_CAP_FILE_DND) && target == DRAG_TARGET_NAME_URI_LIST) {
       /*
        * Turn the uri list into two \0  delimited lists. One for full paths and
        * one for just the last path component.
@@ -1218,7 +1429,7 @@ DnDUIX11::SetCPClipboardFromGtk(const Gtk::SelectionData& sd) // IN
       DynBuf_Init(&buf);
       fileList.SetFileSize(totalSize);
       if (fileList.ToCPClipboard(&buf, false)) {
-          CPClipboard_SetItem(&m_clipboard, CPFORMAT_FILELIST, DynBuf_Get(&buf),
+          CPClipboard_SetItem(&mClipboard, CPFORMAT_FILELIST, DynBuf_Get(&buf),
                               DynBuf_GetSize(&buf));
       }
       DynBuf_Destroy(&buf);
@@ -1226,16 +1437,13 @@ DnDUIX11::SetCPClipboardFromGtk(const Gtk::SelectionData& sd) // IN
    }
 
    /* Try to get plain text. */
-   if (m_DnD->CheckCapability(DND_CP_CAP_PLAIN_TEXT_DND) && (
-       target == TARGET_NAME_STRING ||
-       target == TARGET_NAME_TEXT_PLAIN ||
-       target == TARGET_NAME_UTF8_STRING ||
-       target == TARGET_NAME_COMPOUND_TEXT)) {
+   if (   mDnD->CheckCapability(DND_CP_CAP_PLAIN_TEXT_DND)
+       && TargetIsPlainText(target)) {
       std::string source = sd.get_data_as_string();
-      if (source.size() > 0 &&
-          source.size() < DNDMSG_MAX_ARGSZ &&
-          CPClipboard_SetItem(&m_clipboard, CPFORMAT_TEXT, source.c_str(),
-                              source.size() + 1)) {
+      if (   source.size() > 0
+          && source.size() < DNDMSG_MAX_ARGSZ
+          && CPClipboard_SetItem(&mClipboard, CPFORMAT_TEXT, source.c_str(),
+                                 source.size() + 1)) {
          g_debug("%s: Got text, size %"FMTSZ"u\n", __FUNCTION__, source.size());
       } else {
          g_debug("%s: Failed to get text\n", __FUNCTION__);
@@ -1245,14 +1453,13 @@ DnDUIX11::SetCPClipboardFromGtk(const Gtk::SelectionData& sd) // IN
    }
 
    /* Try to get RTF string. */
-   if (m_DnD->CheckCapability(DND_CP_CAP_RTF_DND) && (
-       target == TARGET_NAME_APPLICATION_RTF ||
-       target == TARGET_NAME_TEXT_RICHTEXT)) {
+   if (   mDnD->CheckCapability(DND_CP_CAP_RTF_DND)
+       && TargetIsRichText(target)) {
       std::string source = sd.get_data_as_string();
-      if (source.size() > 0 &&
-          source.size() < DNDMSG_MAX_ARGSZ &&
-          CPClipboard_SetItem(&m_clipboard, CPFORMAT_RTF, source.c_str(),
-                              source.size() + 1)) {
+      if (   source.size() > 0
+          && source.size() < DNDMSG_MAX_ARGSZ
+          && CPClipboard_SetItem(&mClipboard, CPFORMAT_RTF, source.c_str(),
+                                 source.size() + 1)) {
          g_debug("%s: Got RTF, size %"FMTSZ"u\n", __FUNCTION__, source.size());
          return true;
       } else {
@@ -1264,36 +1471,46 @@ DnDUIX11::SetCPClipboardFromGtk(const Gtk::SelectionData& sd) // IN
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::RequestData --
+ *
+ *      Requests clipboard data from a drag source.
  *
- * Ask for clipboard data from drag source.
+ *      Evaluates targets (think MIME types) offered by the drag source, and
+ *      if we support any, requests the contents.
  *
- * @param[in] dc   Associated drag context
- * @param[in] time Time of the request
+ * Results:
+ *      Returns true if we found a supported type.
  *
- * @return true if there is any data request, false otherwise.
+ * Side effects:
+ *      May call drag_get_data.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 bool
-DnDUIX11::RequestData(const Glib::RefPtr<Gdk::DragContext> &dc,
-                      guint time)
+DnDUIX11::RequestData(
+   const Glib::RefPtr<Gdk::DragContext> &dc, // IN: GTK drag context
+   guint time)                               // IN: event timestamp
 {
    Glib::RefPtr<Gtk::TargetList> targets;
    targets = Gtk::TargetList::create(std::list<Gtk::TargetEntry>());
 
-   CPClipboard_Clear(&m_clipboard);
-   m_numPendingRequest = 0;
+   CPClipboard_Clear(&mClipboard);
+   mNumPendingRequest = 0;
 
    /*
     * First check file list. If file list is available, all other formats will
     * be ignored.
     */
    targets->add(Glib::ustring(DRAG_TARGET_NAME_URI_LIST));
-   Glib::ustring target = m_detWnd->drag_dest_find_target(dc, targets);
+   Glib::ustring target = mDetWnd->drag_dest_find_target(dc, targets);
    targets->remove(Glib::ustring(DRAG_TARGET_NAME_URI_LIST));
    if (target != "") {
-      m_detWnd->drag_get_data(dc, target, time);
-      m_numPendingRequest++;
+      mDetWnd->drag_get_data(dc, target, time);
+      mNumPendingRequest++;
       return true;
    }
 
@@ -1302,37 +1519,50 @@ DnDUIX11::RequestData(const Glib::RefPtr<Gdk::DragContext> &dc,
    targets->add(Glib::ustring(TARGET_NAME_STRING));
    targets->add(Glib::ustring(TARGET_NAME_TEXT_PLAIN));
    targets->add(Glib::ustring(TARGET_NAME_COMPOUND_TEXT));
-   target = m_detWnd->drag_dest_find_target(dc, targets);
+   target = mDetWnd->drag_dest_find_target(dc, targets);
    targets->remove(Glib::ustring(TARGET_NAME_STRING));
    targets->remove(Glib::ustring(TARGET_NAME_TEXT_PLAIN));
    targets->remove(Glib::ustring(TARGET_NAME_UTF8_STRING));
    targets->remove(Glib::ustring(TARGET_NAME_COMPOUND_TEXT));
    if (target != "") {
-      m_detWnd->drag_get_data(dc, target, time);
-      m_numPendingRequest++;
+      mDetWnd->drag_get_data(dc, target, time);
+      mNumPendingRequest++;
    }
 
    /* Then check RTF. */
    targets->add(Glib::ustring(TARGET_NAME_APPLICATION_RTF));
    targets->add(Glib::ustring(TARGET_NAME_TEXT_RICHTEXT));
-   target = m_detWnd->drag_dest_find_target(dc, targets);
+   target = mDetWnd->drag_dest_find_target(dc, targets);
    targets->remove(Glib::ustring(TARGET_NAME_APPLICATION_RTF));
    targets->remove(Glib::ustring(TARGET_NAME_TEXT_RICHTEXT));
    if (target != "") {
-      m_detWnd->drag_get_data(dc, target, time);
-      m_numPendingRequest++;
+      mDetWnd->drag_get_data(dc, target, time);
+      mNumPendingRequest++;
    }
-   return (m_numPendingRequest > 0);
+   return (mNumPendingRequest > 0);
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::GetLastDirName --
+ *
+ *      Try to get last directory name from a full path name.
+ *
+ *      What this really means is to get the basename of the parent's directory
+ *      name, intended to isolate an individual DND operation's staging directory
+ *      name.
  *
- * Try to get last directory name from a full path name.
+ *         E.g. /tmp/VMwareDnD/abcd137/foo → abcd137
  *
- * @param[in] str pathname to process
+ * Results:
+ *      Returns session directory name on success, empty string otherwise.
  *
- * @return last dir name in the full path name if sucess, empty str otherwise
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 std::string
@@ -1361,20 +1591,33 @@ DnDUIX11::GetLastDirName(const std::string &str)
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::GetNextPath --
  *
- * Provide a substring containing the next path from the provided
- * NUL-delimited string starting at the provided index.
+ *      Convoluted somethingerother.
  *
- * @param[in] str NUL-delimited path list
- * @param[in] index current index into string
+ *      XXX Something here involves URI parsing and encoding.  Get to the bottom
+ *      of this and use shared URI code.
  *
- * @return a string with the next path or "" if there are no more paths.
+ *      Original description:
+ *         Provide a substring containing the next path from the provided
+ *         NUL-delimited string starting at the provided index.
+ *
+ * Results:
+ *      Returns "a string with the next path or empty string if there are no
+ *      more paths".
+ *
+ * Side effects:
+ *      Updates index.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 utf::utf8string
-DnDUIX11::GetNextPath(utf::utf8string& str,
-                      size_t& index)
+DnDUIX11::GetNextPath(utf::utf8string& str,     // IN: NUL-delimited path list
+                      size_t& index)            // IN/OUT: index into string
 {
    utf::utf8string ret;
    size_t start;
@@ -1416,56 +1659,64 @@ DnDUIX11::GetNextPath(utf::utf8string& str,
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::SendFakeMouseMove --
  *
- * Issue a fake mouse move event to the detection window. Code stolen from
- * DnD V2 Linux guest implementation, where it was originally defined as a
- * macro.
+ *      Issue a fake mouse move event to the detection window.
  *
- * @param[in] x x-coordinate of location to move mouse to.
- * @param[in] y y-coordinate of location to move mouse to.
+ * Results:
+ *      Returns true on success, false on failure.
  *
- * @return true on success, false on failure.
+ * Side effects:
+ *      Generates mouse events.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 bool
-DnDUIX11::SendFakeMouseMove(const int x,
-                            const int y)
+DnDUIX11::SendFakeMouseMove(const int x,        // IN: x-coord
+                            const int y)        // IN: y-coord
 {
    return SendFakeXEvents(false, false, false, false, true, x, y);
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::SendFakeXEvents --
+ *
+ *      Fake X mouse events and window movement for the detection window.
+ *
+ *      This function shows the detection window and generates button
+ *      press/release and pointer motion events.
  *
- * Fake X mouse events and window movement for the provided Gtk widget.
+ *      XXX This code should be implemented using GDK APIs.
+ *          (gdk_display_warp_pointer?)
  *
- * This function will optionally show the widget, move the provided widget
- * to either the provided location or the current mouse position if no
- * coordinates are provided, and cause a button press or release event.
+ *      XXX This code should be moved into the detection window class
  *
- * @param[in] showWidget       whether to show Gtk widget
- * @param[in] buttonEvent      whether to send a button event
- * @param[in] buttonPress      whether to press or release mouse
- * @param[in] moveWindow:      whether to move our window too
- * @param[in] coordsProvided   whether coordinates provided
- * @param[in] xCoord           x coordinate
- * @param[in] yCoord           y coordinate
+ * Results:
+ *      Returns true if generated X events, false on failure.
  *
- * @note todo this code should be implemented using GDK APIs.
- * @note todo this code should be moved into the detection window class
+ * Side effects:
+ *      A ton of things.
  *
- * @return true on success, false on failure.
+ *-----------------------------------------------------------------------------
  */
 
 bool
-DnDUIX11::SendFakeXEvents(const bool showWidget,
-                          const bool buttonEvent,
-                          const bool buttonPress,
-                          const bool moveWindow,
-                          const bool coordsProvided,
-                          const int xCoord,
-                          const int yCoord)
+DnDUIX11::SendFakeXEvents(
+   const bool showWidget,       // IN: whether to show widget
+   const bool buttonEvent,      // IN: whether to send a button event
+   const bool buttonPress,      // IN: whether button event is press or release
+   const bool moveWindow,       // IN: whether to move detection window
+   const bool coordsProvided,   // IN: whether coords provided, else will
+                                //     query current mouse position
+   const int xCoord,            // IN: destination x-coord
+   const int yCoord)            // IN: destination y-coord
 {
    GtkWidget *widget;
    Window rootWnd;
@@ -1527,8 +1778,8 @@ DnDUIX11::SendFakeXEvents(const bool showWidget,
       /*
        * Position away from the edge of the window.
        */
-      int width = m_detWnd->GetScreenWidth();
-      int height = m_detWnd->GetScreenHeight();
+      int width = mDetWnd->GetScreenWidth();
+      int height = mDetWnd->GetScreenHeight();
       bool change = false;
 
       x = rootXReturn;
@@ -1608,11 +1859,11 @@ DnDUIX11::SendFakeXEvents(const bool showWidget,
             goto exit;
          }
 
-         if ((maskReturn & Button1Mask) ||
-             (maskReturn & Button2Mask) ||
-             (maskReturn & Button3Mask) ||
-             (maskReturn & Button4Mask) ||
-             (maskReturn & Button5Mask)) {
+         if (   (maskReturn & Button1Mask)
+             || (maskReturn & Button2Mask)
+             || (maskReturn & Button3Mask)
+             || (maskReturn & Button4Mask)
+             || (maskReturn & Button5Mask)) {
             Debug("%s: XTestFakeButtonEvent was not working for button "
                   "release, trying XTestFakeDeviceButtonEvent now.\n",
                   __FUNCTION__);
@@ -1633,18 +1884,28 @@ exit:
 }
 
 
-/**
- * Fake X mouse events in device level.
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::TryXTestFakeDeviceButtonEvent --
+ *
+ *      Fake X mouse events in device level.
  *
- * XXX The function will only be called if XTestFakeButtonEvent does not work
- * for mouse button release. Later on we may only call this one for mouse
- * button simulation if this is more reliable.
+ *      XXX The function will only be called if XTestFakeButtonEvent does
+ *      not work for mouse button release. Later on we may only call this
+ *      one for mouse button simulation if this is more reliable.
  *
- * @return true on success, false on failure.
+ * Results:
+ *      Returns true on success, false on failure.
+ *
+ * Side effects:
+ *      Generates mouse events.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 bool
-DnDUIX11::TryXTestFakeDeviceButtonEvent(void)
+DnDUIX11::TryXTestFakeDeviceButtonEvent()
 {
    XDeviceInfo *list = NULL;
    XDeviceInfo *list2 = NULL;
@@ -1709,16 +1970,27 @@ DnDUIX11::TryXTestFakeDeviceButtonEvent(void)
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::GetDetWndAsWidget --
+ *
+ *      Get the GtkWidget pointer for a DragDetWnd object.
+ *
+ *      The X11 Unity implementation requires access to the drag detection
+ *      window as a GtkWindow pointer, which it uses to show and hide the
+ *      detection window.
+ *
+ *      This function is also called by the code that issues fake X events
+ *      to the detection window.
+ *
+ * Results:
+ *      A GtkWidget* on success or NULL on failure.
  *
- * Get the GtkWidget pointer for a DragDetWnd object. The X11 Unity
- * implementation requires access to the drag detection window as
- * a GtkWindow pointer, which it uses to show and hide the detection
- * window. This function is also called by the code that issues fake
- * X events to the detection window.
+ * Side effects:
+ *      None.
  *
- * @return a pointer to the GtkWidget for the detection window, or NULL
- * on failure.
+ *-----------------------------------------------------------------------------
  */
 
 GtkWidget *
@@ -1727,10 +1999,10 @@ DnDUIX11::GetDetWndAsWidget()
    GtkInvisible *window;
    GtkWidget *widget = NULL;
 
-   if (!m_detWnd) {
+   if (!mDetWnd) {
       return NULL;
    }
-   window = m_detWnd->gobj();
+   window = mDetWnd->gobj();
    if (window) {
       widget = GTK_WIDGET(window);
    }
@@ -1738,72 +2010,102 @@ DnDUIX11::GetDetWndAsWidget()
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::AddBlock --
  *
- * Add a block for the current H->G file transfer. Must be paired with a
- * call to RemoveBlock() on finish or cancellation.
+ *      Insert a vmblock blocking entry.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      Caller must pair with RemoveBlock() upon dnd completion/cancellation.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 void
 DnDUIX11::AddBlock()
 {
    TRACE_CALL();
-   if (m_blockAdded) {
+
+   if (mBlockAdded) {
       g_debug("%s: block already added\n", __FUNCTION__);
       return;
    }
-   g_debug("%s: DnDBlockIsReady %d fd %d\n", __FUNCTION__, DnD_BlockIsReady(m_blockCtrl), m_blockCtrl->fd);
-   if (DnD_BlockIsReady(m_blockCtrl) && m_blockCtrl->AddBlock(m_blockCtrl->fd, m_HGStagingDir.c_str())) {
-      m_blockAdded = true;
-      g_debug("%s: add block for %s.\n", __FUNCTION__, m_HGStagingDir.c_str());
+
+   g_debug("%s: DnDBlockIsReady %d fd %d\n", __FUNCTION__,
+           DnD_BlockIsReady(mBlockCtrl), mBlockCtrl->fd);
+
+   if (   DnD_BlockIsReady(mBlockCtrl)
+       && mBlockCtrl->AddBlock(mBlockCtrl->fd, mHGStagingDir.c_str())) {
+      mBlockAdded = true;
+      g_debug("%s: add block for %s.\n", __FUNCTION__, mHGStagingDir.c_str());
    } else {
-      m_blockAdded = false;
-      g_debug("%s: unable to add block dir %s.\n", __FUNCTION__, m_HGStagingDir.c_str());
+      mBlockAdded = false;
+      g_debug("%s: unable to add block dir %s.\n", __FUNCTION__, mHGStagingDir.c_str());
    }
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::RemoveBlock --
  *
- * Remove block for the current H->G file transfer. Must be paired with a
- * call to AddBlock(), but it will only attempt to remove block if one is
- * currently in effect.
+ *      Remove a vmblock blocking entry.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 void
 DnDUIX11::RemoveBlock()
 {
    TRACE_CALL();
-   if (m_blockAdded && (DND_FILE_TRANSFER_IN_PROGRESS != m_HGGetFileStatus)) {
-      g_debug("%s: removing block for %s\n", __FUNCTION__, m_HGStagingDir.c_str());
+
+   if (mBlockAdded && (DND_FILE_TRANSFER_IN_PROGRESS != mHGGetFileStatus)) {
+      g_debug("%s: removing block for %s\n", __FUNCTION__, mHGStagingDir.c_str());
       /* We need to make sure block subsystem has not been shut off. */
-      if (DnD_BlockIsReady(m_blockCtrl)) {
-         m_blockCtrl->RemoveBlock(m_blockCtrl->fd, m_HGStagingDir.c_str());
+      if (DnD_BlockIsReady(mBlockCtrl)) {
+         mBlockCtrl->RemoveBlock(mBlockCtrl->fd, mHGStagingDir.c_str());
       }
-      m_blockAdded = false;
+      mBlockAdded = false;
    } else {
-      g_debug("%s: not removing block m_blockAdded %d m_HGGetFileStatus %d\n",
+      g_debug("%s: not removing block mBlockAdded %d mHGGetFileStatus %d\n",
             __FUNCTION__,
-            m_blockAdded,
-            m_HGGetFileStatus);
+            mBlockAdded,
+            mHGGetFileStatus);
    }
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::ToDropEffect --
  *
- * Convert a Gdk::DragAction value to its corresponding DND_DROPEFFECT.
+ *      Convert a Gdk::DragAction value to its corresponding DND_DROPEFFECT.
  *
- * @param[in] the Gdk::DragAction value to return.
+ * Results:
+ *      Returns corresponding DND_DROPEFFECT or DROP_UNKNOWN if a match isn't
+ *      found.
  *
- * @return the corresponding DND_DROPEFFECT, with DROP_UNKNOWN returned
- * if no mapping is supported.
+ * Side effects:
+ *      None.
  *
- * @note DROP_NONE is not mapped in this function.
+ *-----------------------------------------------------------------------------
  */
 
-DND_DROPEFFECT
-DnDUIX11::ToDropEffect(Gdk::DragAction action)
+/* static */ DND_DROPEFFECT
+DnDUIX11::ToDropEffect(const Gdk::DragAction action)
 {
    DND_DROPEFFECT effect;
 
@@ -1828,16 +2130,25 @@ DnDUIX11::ToDropEffect(Gdk::DragAction action)
 }
 
 
-/**
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::WriteFileContentsToStagingDir --
  *
- * Try to extract file contents from m_clipboard. Write all files to a
- * temporary staging directory. Construct uri list.
+ *      Try to extract file contents from mClipboard. Write all files to a
+ *      temporary staging directory. Construct uri list.
  *
- * @return true if success, false otherwise.
+ * Results:
+ *      Returns true on success, false on failure.
+ *
+ * Side effects:
+ *      Hm?
+ *
+ *-----------------------------------------------------------------------------
  */
 
 bool
-DnDUIX11::WriteFileContentsToStagingDir(void)
+DnDUIX11::WriteFileContentsToStagingDir()
 {
    void *buf = NULL;
    size_t sz = 0;
@@ -1850,7 +2161,7 @@ DnDUIX11::WriteFileContentsToStagingDir(void)
    size_t i = 0;
    bool ret = false;
 
-   if (!CPClipboard_GetItem(&m_clipboard, CPFORMAT_FILECONTENTS, &buf, &sz)) {
+   if (!CPClipboard_GetItem(&mClipboard, CPFORMAT_FILECONTENTS, &buf, &sz)) {
       return false;
    }
 
@@ -1893,7 +2204,7 @@ DnDUIX11::WriteFileContentsToStagingDir(void)
       goto exit;
    }
 
-   m_HGFileContentsUriList = "";
+   mHGFileContentsUriList = "";
 
    for (i = 0; i < nFiles; i++) {
       utf::string fileName;
@@ -1924,15 +2235,14 @@ DnDUIX11::WriteFileContentsToStagingDir(void)
       filePathName = tempDir;
       filePathName += DIRSEPS + fileName;
 
-      if (fileItem[i].validFlags & CP_FILE_VALID_TYPE &&
-          CP_FILE_TYPE_DIRECTORY == fileItem[i].type) {
+      if (   fileItem[i].validFlags & CP_FILE_VALID_TYPE
+          && CP_FILE_TYPE_DIRECTORY == fileItem[i].type) {
          if (!File_CreateDirectory(filePathName.c_str())) {
             goto exit;
          }
-         g_debug("%s: created directory [%s].\n",
-               __FUNCTION__, filePathName.c_str());
-      } else if (fileItem[i].validFlags & CP_FILE_VALID_TYPE &&
-                 CP_FILE_TYPE_REGULAR == fileItem[i].type) {
+         g_debug("%s: created directory [%s].\n", __FUNCTION__, filePathName.c_str());
+      } else if (   fileItem[i].validFlags & CP_FILE_VALID_TYPE
+                 && CP_FILE_TYPE_REGULAR == fileItem[i].type) {
          FileIODescriptor file;
          FileIOResult fileErr;
 
@@ -1952,8 +2262,7 @@ DnDUIX11::WriteFileContentsToStagingDir(void)
                                 NULL);
 
          FileIO_Close(&file);
-         g_debug("%s: created file [%s].\n",
-               __FUNCTION__, filePathName.c_str());
+         g_debug("%s: created file [%s].\n", __FUNCTION__, filePathName.c_str());
       } else {
          /*
           * Right now only Windows can provide CPFORMAT_FILECONTENTS data.
@@ -1979,17 +2288,16 @@ DnDUIX11::WriteFileContentsToStagingDir(void)
                          writeTime,
                          attrChangeTime)) {
          /* Not a critical error, only log it. */
-         g_debug("%s: File_SetTimes failed with file [%s].\n",
-               __FUNCTION__, filePathName.c_str());
+         g_debug("%s: File_SetTimes failed with file [%s].\n", __FUNCTION__,
+                 filePathName.c_str());
       }
 
       /* Update file permission attributes. */
       if (fileItem->validFlags & CP_FILE_VALID_PERMS) {
-         if (Posix_Chmod(filePathName.c_str(),
-                         fileItem->permissions) < 0) {
+         if (Posix_Chmod(filePathName.c_str(), fileItem->permissions) < 0) {
             /* Not a critical error, only log it. */
-            g_debug("%s: Posix_Chmod failed with file [%s].\n",
-                  __FUNCTION__, filePathName.c_str());
+            g_debug("%s: Posix_Chmod failed with file [%s].\n", __FUNCTION__,
+                    filePathName.c_str());
          }
       }
 
@@ -1998,11 +2306,10 @@ DnDUIX11::WriteFileContentsToStagingDir(void)
        * top level one. We only put top level name into uri list.
        */
       if (fileName.find(DIRSEPS, 0) == utf::string::npos) {
-         m_HGFileContentsUriList += "file://" + filePathName + "\r\n";
+         mHGFileContentsUriList += "file://" + filePathName + "\r\n";
       }
    }
-   g_debug("%s: created uri list [%s].\n",
-         __FUNCTION__, m_HGFileContentsUriList.c_str());
+   g_debug("%s: created uri list [%s].\n", __FUNCTION__, mHGFileContentsUriList.c_str());
    ret = true;
 
 exit:
@@ -2015,61 +2322,82 @@ exit:
 }
 
 
-/**
- * Tell host that we are done with HG DnD initialization.
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::SourceDragStartDone --
+ *
+ *      Tell host that we're done with host-to-guest drag-and-drop
+ *      initialization.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::SourceDragStartDone(void)
+DnDUIX11::SourceDragStartDone()
 {
    TRACE_CALL();
-   m_inHGDrag = true;
-   m_DnD->SrcUIDragBeginDone();
+   mInHGDrag = true;
+   mDnD->SrcUIDragBeginDone();
 }
 
 
-/**
- * Set block control member.
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::SetBlockControl --
  *
- * @param[in] block control as setup by vmware-user.
+ *      Set block control member.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::SetBlockControl(DnDBlockControl *blockCtrl)
+DnDUIX11::SetBlockControl(DnDBlockControl *blockCtrl)   // IN
 {
-   m_blockCtrl = blockCtrl;
+   mBlockCtrl = blockCtrl;
 }
 
 
-/**
- * Got feedback from our DropSource, send it over to host. Called by
- * drag motion callback.
+/*
+ *-----------------------------------------------------------------------------
  *
- * @param[in] effect feedback to send to the UI-independent DnD layer.
+ * DnDUIX11::SourceUpdateFeedback --
+ *
+ *      Forward feedback from our drop source to the host.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::SourceUpdateFeedback(DND_DROPEFFECT effect)
+DnDUIX11::SourceUpdateFeedback(
+   DND_DROPEFFECT effect) // IN: feedback to send to the UI-independent DnD layer.
 {
    TRACE_CALL();
-   m_DnD->SrcUIUpdateFeedback(effect);
+   mDnD->SrcUIUpdateFeedback(effect);
 }
 
 
-/**
- * This is triggered when user drags valid data from guest to host. Try to
- * get clip data and notify host to start GH DnD.
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::TargetDragEnter --
+ *
+ *      With the source's drag selection data on the clipboard, signal to
+ *      host to begin guest-to-host drag-and-drop.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::TargetDragEnter(void)
+DnDUIX11::TargetDragEnter()
 {
    TRACE_CALL();
 
    /* Check if there is valid data with current detection window. */
-   if (!CPClipboard_IsEmpty(&m_clipboard)) {
+   if (!CPClipboard_IsEmpty(&mClipboard)) {
       g_debug("%s: got valid data from detWnd.\n", __FUNCTION__);
-      m_DnD->DestUIDragEnter(&m_clipboard);
+      mDnD->DestUIDragEnter(&mClipboard);
    }
 
    /*
@@ -2080,14 +2408,18 @@ DnDUIX11::TargetDragEnter(void)
 }
 
 
-/**
- * Get Unix time in milliseconds. See man 2 gettimeofday for details.
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::GetTimeInMillis --
  *
- * @return unix time in milliseconds.
+ *      Get Unix time in milliseconds.
+ *
+ *-----------------------------------------------------------------------------
  */
 
-unsigned long
-DnDUIX11::GetTimeInMillis(void)
+/* static */ unsigned long
+DnDUIX11::GetTimeInMillis()
 {
    VmTimeType atime;
 
@@ -2096,18 +2428,22 @@ DnDUIX11::GetTimeInMillis(void)
 }
 
 
-/**
- * Update version information in m_DnD.
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::VmXDnDVersionChanged --
  *
- * @param[ignored] chan RpcChannel pointer
- * @param[in] version the version negotiated with host.
+ *      Update version information in mDnD.
+ *
+ *-----------------------------------------------------------------------------
  */
 
 void
-DnDUIX11::VmxDnDVersionChanged(RpcChannel *chan, uint32 version)
+DnDUIX11::VmxDnDVersionChanged(RpcChannel *chan,        // IN
+                               uint32 version)          // IN
 {
-   ASSERT(m_DnD);
-   m_DnD->VmxDnDVersionChanged(version);
+   ASSERT(mDnD);
+   mDnD->VmxDnDVersionChanged(version);
 }
 
 
@@ -2260,3 +2596,48 @@ DnDUIX11::GtkButtonReleaseEventCB(GdkEventButton *event)
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDUIX11::OnWorkAreaChanged --
+ *
+ *      Updates mOrigin in response to changes to _NET_workArea.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+DnDUIX11::OnWorkAreaChanged(Glib::RefPtr<Gdk::Screen> screen)    // IN
+{
+   TRACE_CALL();
+
+   std::vector<unsigned long> values;
+   if (   xutils::GetCardinalList(screen->get_root_window(), "_NET_WORKAREA", values)
+       && values.size() > 0
+       && values.size() % 4 == 0) {
+      /*
+       * wm-spec: _NET_WORKAREA, x, y, width, height CARDINAL[][4]/32
+       *
+       * For the purposes of drag-and-drop, we're okay with using the screen-
+       * agnostic _NET_WORKAREA atom, as the guest VM really deals with only
+       * one logical monitor.
+       */
+      unsigned long desktop = 0;
+      xutils::GetCardinal(screen->get_root_window(), "_NET_CURRENT_DESKTOP", desktop);
+
+      mOrigin.set_x(values[0 + 4 * desktop]);
+      mOrigin.set_y(values[1 + 4 * desktop]);
+   } else {
+      mOrigin.set_x(0);
+      mOrigin.set_y(0);
+   }
+
+   g_debug("%s: new origin at (%d, %d)\n", __FUNCTION__, mOrigin.get_x(),
+           mOrigin.get_y());
+}
index d0af46c4d9cc582bf2bb404f4484fff6869effb8..6a98def38298bd6d9a776f76de977c29ea0f248e 100644 (file)
@@ -64,90 +64,88 @@ public:
    bool Init();
    void VmxDnDVersionChanged(RpcChannel *chan, uint32 version);
    void SetDnDAllowed(bool isDnDAllowed)
-      {ASSERT(m_DnD); m_DnD->SetDnDAllowed(isDnDAllowed);}
+      {ASSERT(mDnD); mDnD->SetDnDAllowed(isDnDAllowed);}
    void SetBlockControl(DnDBlockControl *blockCtrl);
    void SetUnityMode(Bool mode)
-      {m_unityMode = mode;};
+      {mUnityMode = mode;};
 
-   DragDetWnd *GetFullDetWnd() {return m_detWnd;}
+   DragDetWnd *GetFullDetWnd() {return mDetWnd;}
    GtkWidget *GetDetWndAsWidget();
 
 private:
-
-   /**
+   /*
     * Blocking FS Helper Functions.
     */
    void AddBlock();
    void RemoveBlock();
 
-   bool TryXTestFakeDeviceButtonEvent(void);
+   bool TryXTestFakeDeviceButtonEvent();
 
-   /**
+   /*
     * Callbacks from Common DnD layer.
     */
-   void CommonResetCB();
-   void CommonUpdateMouseCB(int32 x, int32 y);
+   void ResetUI();
+   void OnMoveMouse(int32 x, int32 y);
 
-   /**
+   /*
     * Source functions for HG DnD.
     */
-   void CommonDragStartCB(const CPClipboard *clip, std::string stagingDir);
-   void CommonSourceDropCB(void);
+   void OnSrcDragBegin(const CPClipboard *clip, std::string stagingDir);
+   void OnSrcDrop();
 
-   /**
+   /*
     * Called when HG Dnd is completed.
     */
-   void CommonSourceCancelCB(void);
+   void OnSrcCancel();
 
-   /**
+   /*
     * Called when GH DnD is completed.
     */
-   void CommonDestPrivateDropCB(int32 x, int32 y);
-   void CommonDestCancelCB(void);
+   void OnPrivateDrop(int32 x, int32 y);
+   void OnDestCancel();
 
-   /**
+   /*
     * Source functions for file transfer.
     */
-   void CommonSourceFileCopyDoneCB(bool success);
+   void OnGetFilesDone(bool success);
 
-   /**
+   /*
     * Callbacks for showing/hiding detection window.
     */
-   void CommonUpdateDetWndCB(bool bShow, int32 x, int32 y);
-   void CommonUpdateUnityDetWndCB(bool bShow, uint32 unityWndId, bool bottom);
-   void CommonMoveDetWndToMousePos(void);
+   void OnUpdateDetWnd(bool bShow, int32 x, int32 y);
+   void OnUpdateUnityDetWnd(bool bShow, uint32 unityWndId, bool bottom);
+   void OnDestMoveDetWndToMousePos();
 
-   /**
+   /*
     * Gtk+ Callbacks: Drag Destination.
     */
-   void GtkDestDragDataReceivedCB(const Glib::RefPtr<Gdk::DragContext> &dc,
-                                  int x, int y, const Gtk::SelectionData &sd,
-                                  guint info, guint time);
-   bool GtkDestDragDropCB(const Glib::RefPtr<Gdk::DragContext> &dc,
-                          int x, int y, guint time);
-   void GtkDestDragLeaveCB(const Glib::RefPtr<Gdk::DragContext> &dc,
-                           guint time);
-   bool GtkDestDragMotionCB(const Glib::RefPtr<Gdk::DragContext> &dc, int x,
-                            int y, guint time);
-
-   /**
+   void OnGtkDragDataReceived(const Glib::RefPtr<Gdk::DragContext> &dc,
+                              int x, int y, const Gtk::SelectionData &sd,
+                              guint info, guint time);
+   bool OnGtkDragDrop(const Glib::RefPtr<Gdk::DragContext> &dc, int x, int y,
+                      guint time);
+   void OnGtkDragLeave(const Glib::RefPtr<Gdk::DragContext> &dc, guint time);
+   bool OnGtkDragMotion(const Glib::RefPtr<Gdk::DragContext> &dc, int x,
+                        int y, guint time);
+
+   /*
     * Gtk+ Callbacks: Drag Source.
     */
-   void GtkSourceDragBeginCB(const Glib::RefPtr<Gdk::DragContext>& context);
-   void GtkSourceDragDataGetCB(const Glib::RefPtr<Gdk::DragContext>& context,
-                               Gtk::SelectionData& selection_data, guint info,
-                               guint time);
-   void GtkSourceDragEndCB(const Glib::RefPtr<Gdk::DragContext>& context);
-   /**
+   void OnGtkDragBegin(const Glib::RefPtr<Gdk::DragContext>& context);
+   void OnGtkDragDataGet(const Glib::RefPtr<Gdk::DragContext>& context,
+                         Gtk::SelectionData& selection_data, guint info,
+                         guint time);
+   void OnGtkDragEnd(const Glib::RefPtr<Gdk::DragContext>& context);
+   /*
     * Source functions for HG DnD. Makes calls to common layer.
     */
-   void SourceDragStartDone(void);
+   void SourceDragStartDone();
    void SourceUpdateFeedback(DND_DROPEFFECT effect);
 
-   /**
+   /*
     * Target function for GH DnD. Makes call to common layer.
     */
-   void TargetDragEnter(void);
+   void TargetDragEnter();
 
    /*
     * Other signal handlers for tracing.
@@ -164,50 +162,74 @@ private:
    bool GtkButtonPressEventCB(GdkEventButton *event);
    bool GtkButtonReleaseEventCB(GdkEventButton *event);
 
-   /**
+   /*
     * Misc methods.
     */
+   void InitGtk();
+
    bool SetCPClipboardFromGtk(const Gtk::SelectionData& sd);
    bool RequestData(const Glib::RefPtr<Gdk::DragContext> &dc,
                     guint timeValue);
    std::string GetLastDirName(const std::string &str);
    utf::utf8string GetNextPath(utf::utf8string &str, size_t& index);
-   DND_DROPEFFECT ToDropEffect(Gdk::DragAction action);
-   void SetTargetsAndCallbacks();
+
+   static DND_DROPEFFECT ToDropEffect(const Gdk::DragAction action);
+   static unsigned long GetTimeInMillis();
+
    bool SendFakeXEvents(const bool showWidget, const bool buttonEvent,
                         const bool buttonPress, const bool moveWindow,
                         const bool coordsProvided,
                         const int xCoord, const int yCoord);
    bool SendFakeMouseMove(const int x, const int y);
    bool WriteFileContentsToStagingDir();
-   unsigned long GetTimeInMillis();
-
-   ToolsAppCtx *m_ctx;
-   GuestDnDMgr *m_DnD;
-   std::string m_HGStagingDir;
-   utf::string m_HGFileContentsUriList;
-   DragDetWnd *m_detWnd;
-   CPClipboard m_clipboard;
-   DnDBlockControl *m_blockCtrl;
-   DND_FILE_TRANSFER_STATUS m_HGGetFileStatus;
-   int m_HGEffect;
-   bool m_blockAdded;
+
+   static inline bool TargetIsPlainText(const utf::string& target) {
+      return    target == TARGET_NAME_STRING
+             || target == TARGET_NAME_TEXT_PLAIN
+             || target == TARGET_NAME_UTF8_STRING
+             || target == TARGET_NAME_COMPOUND_TEXT;
+   }
+
+   static inline bool TargetIsRichText(const utf::string& target) {
+      return    target == TARGET_NAME_APPLICATION_RTF
+             || target == TARGET_NAME_TEXT_RICHTEXT;
+   }
+
+   void OnWorkAreaChanged(Glib::RefPtr<Gdk::Screen> screen);
+
+   ToolsAppCtx *mCtx;
+   GuestDnDMgr *mDnD;
+   std::string mHGStagingDir;
+   utf::string mHGFileContentsUriList;
+   DragDetWnd *mDetWnd;
+   CPClipboard mClipboard;
+   DnDBlockControl *mBlockCtrl;
+   DND_FILE_TRANSFER_STATUS mHGGetFileStatus;
+   int mHGEffect;
+   bool mBlockAdded;
 
    /* State to determine if drag motion is a drag enter. */
-   bool m_GHDnDInProgress;
+   bool mGHDnDInProgress;
    /* Icon updates from the guest. */
    /* Only update mouse when we have clipboard contents from the host. */
-   bool m_GHDnDDataReceived;
-   bool m_GHDnDDropOccurred;
-   bool m_unityMode;
-   bool m_inHGDrag;
-   DND_DROPEFFECT m_effect;
-   int32 m_mousePosX;
-   int32 m_mousePosY;
-   GdkDragContext *m_dc;
-   int m_numPendingRequest;
-   unsigned long m_destDropTime;
+   bool mGHDnDDataReceived;
+   bool mGHDnDDropOccurred;
+   bool mUnityMode;
+   bool mInHGDrag;
+   DND_DROPEFFECT mEffect;
+   int32 mMousePosX;
+   int32 mMousePosY;
+   GdkDragContext *mDragCtx;
+   int mNumPendingRequest;
+   unsigned long mDestDropTime;
    uint64 mTotalFileSize;
+
+   /*
+    * Upper left corner of our work area, a safe place for us to place
+    * our detection window without clashing with a windows parented to the
+    * composite overlay window.
+    */
+   Gdk::Point mOrigin;
 };
 
 #endif // __DND_UI_X11_H__
diff --git a/open-vm-tools/services/plugins/dndcp/xutils/xutils.cc b/open-vm-tools/services/plugins/dndcp/xutils/xutils.cc
new file mode 100644 (file)
index 0000000..2ed7326
--- /dev/null
@@ -0,0 +1,1370 @@
+/*********************************************************
+ * Copyright (C) 2008-2013 VMware, Inc. All rights reserved.
+ *
+ * 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 version 2.1 and no 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 Lesser GNU 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+
+#include <cairomm/cairomm.h>
+#include <gdkmm.h>
+#if GTK_MAJOR_VERSION == 3
+#include <gdkmm/devicemanager.h>
+#endif
+
+#include "xutils/xutils.hh"
+
+/* These must be after the gtkmm includes, as gtkmm is quite picky. */
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <gdk/gdkx.h>
+
+extern "C" {
+#include "vm_assert.h"
+}
+
+
+namespace xutils {
+
+
+/* Actual definitions of the signals in this class. */
+sigc::signal<void, Glib::RefPtr<Gdk::Screen> > currentDesktopChanged;
+sigc::signal<void, Glib::RefPtr<Gdk::Screen> > desktopLayoutChanged;
+sigc::signal<void, Glib::RefPtr<Gdk::Screen> > desktopGeometryChanged;
+sigc::signal<void, Glib::RefPtr<Gdk::Screen> > desktopViewportChanged;
+sigc::signal<void, Glib::RefPtr<Gdk::Screen> > windowStackChanged;
+sigc::signal<void, Glib::RefPtr<Gdk::Screen> > windowManagerChanged;
+sigc::signal<void, Glib::RefPtr<Gdk::Screen> > activeWindowChanged;
+sigc::signal<void, Glib::RefPtr<Gdk::Screen> > workAreaChanged;
+
+/* Necessary for calculating per-monitor _NET_WORKAREA in GetMonitorWorkArea() */
+struct NETWMStrutPartial {
+   NETWMStrutPartial()
+      : left_width(0),
+        left_start(0),
+        left_end(0),
+        right_width(0),
+        right_start(0),
+        right_end(0),
+        top_height(0),
+        top_start(0),
+        top_end(0),
+        bottom_height(0),
+        bottom_start(0),
+        bottom_end(0) {}
+
+   int left_width, left_start, left_end;
+   int right_width, right_start, right_end;
+   int top_height, top_start, top_end;
+   int bottom_height, bottom_start, bottom_end;
+};
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * xutils::OnWindowFilter --
+ *
+ *      Window filter handler that listens for changes to the properties we
+ *      care about and emits the appropriate signals.
+ *
+ * Results:
+ *      GDK_FILTER_CONTINUE, always.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+GdkFilterReturn
+OnWindowFilter(XEvent* xevent,     // IN: Incoming event
+               GdkEvent* event,    // OUT/UNUSED
+               GdkScreen* _screen) // IN: The screen
+{
+   Glib::RefPtr<Gdk::Screen> screen = Glib::wrap(_screen, true);
+   ::Display* xdisplay = xevent->xany.display;
+   GdkDisplay* display = gdk_x11_lookup_xdisplay(xdisplay);
+   Window rootWin = GDK_WINDOW_XID(screen->get_root_window()->gobj());
+
+#define ATOM(name) gdk_x11_get_xatom_by_name_for_display(display, (name))
+
+   if (xevent->type == PropertyNotify &&
+       xevent->xproperty.window == rootWin) {
+      if (xevent->xproperty.atom == ATOM("_NET_CLIENT_LIST_STACKING")) {
+         windowStackChanged.emit(screen);
+      } else if (xevent->xproperty.atom == ATOM("_NET_DESKTOP_LAYOUT")) {
+         desktopLayoutChanged.emit(screen);
+      } else if (xevent->xproperty.atom == ATOM("_NET_NUMBER_OF_DESKTOPS")) {
+         desktopLayoutChanged.emit(screen);
+      } else if (xevent->xproperty.atom == ATOM("_NET_CURRENT_DESKTOP")) {
+         currentDesktopChanged.emit(screen);
+      } else if (xevent->xproperty.atom == ATOM("_NET_DESKTOP_GEOMETRY")) {
+         desktopGeometryChanged.emit(screen);
+      } else if (xevent->xproperty.atom == ATOM("_NET_DESKTOP_VIEWPORT")) {
+         desktopViewportChanged.emit(screen);
+      } else if (xevent->xproperty.atom == ATOM("_NET_SUPPORTING_WM_CHECK")) {
+         windowManagerChanged.emit(screen);
+      } else if (xevent->xproperty.atom == ATOM("_NET_ACTIVE_WINDOW")) {
+         activeWindowChanged.emit(screen);
+      } else if (xevent->xproperty.atom == ATOM("_NET_WORKAREA")) {
+         workAreaChanged.emit(screen);
+      }
+   }
+
+#undef ATOM
+
+   return GDK_FILTER_CONTINUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * xutils::Init --
+ *
+ *      Base initialization function that sets up the window filter. This
+ *      is required if any signals are to be used.
+ *
+ *      This can be called more than once.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Init()
+{
+   static bool initialized = false;
+
+   if (!initialized) {
+      initialized = true;
+
+      /*
+       * Select PropertyChange events on the root window so that we can
+       * listen for when the host window stack changes and update our
+       * copy.
+       */
+      Glib::RefPtr<Gdk::Display> display = Gdk::Display::get_default();
+      ::Display* xdisplay = GDK_DISPLAY_XDISPLAY(display->gobj());
+
+      for (int i = 0; i < display->get_n_screens(); i++) {
+         Glib::RefPtr<Gdk::Screen> screen = display->get_screen(i);
+         Glib::RefPtr<Gdk::Window> rootWin = screen->get_root_window();
+         Window xRootWin = GDK_WINDOW_XID(rootWin->gobj());
+
+         int mask = PropertyChangeMask;
+
+#if GTK_MAJOR_VERSION == 3
+         if (gdk_x11_window_lookup_for_display(
+                display->gobj(), xRootWin) != NULL) {
+#else
+         if (gdk_xid_table_lookup(xRootWin) != NULL) {
+#endif
+            /* Make sure we don't interfere with GDK. */
+            XWindowAttributes attrs;
+            XGetWindowAttributes(xdisplay, xRootWin, &attrs);
+            mask |= attrs.your_event_mask;
+         }
+
+         XSelectInput(xdisplay, xRootWin, mask);
+
+         gdk_window_add_filter(rootWin->gobj(), (GdkFilterFunc)OnWindowFilter,
+                               screen->gobj());
+      }
+   }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * xutils::GetCardinal --
+ *
+ *      Utility function to get a cardinal from a window property.
+ *
+ * Results:
+ *      true if the function succeeded, along with a value for retValue.
+ *      Otherwise false.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+bool
+GetCardinal(Glib::RefPtr<const Gdk::Window> window, // IN: Window
+            const utf::string& atomName,            // IN: Atom name
+            unsigned long& retValue)                        // OUT: Return value
+{
+   ASSERT(window);
+   ASSERT(!atomName.empty());
+
+   std::vector<unsigned long> retValues;
+   bool result = GetCardinalList(window, atomName, retValues);
+
+   if (result && retValues.size() == 1) {
+      retValue = retValues[0];
+      return true;
+   }
+
+   return false;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * xutils::GetCardinalList --
+ *
+ *      Utility function to get a cardinal list from a window property.
+ *
+ * Results:
+ *      true if the function succeeded, along with return values for retValue.
+ *      Otherwise false.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+bool
+GetCardinalList(Glib::RefPtr<const Gdk::Window> window, // IN: Window
+                const utf::string& atomName,            // IN: Atom name
+                std::vector<unsigned long>& retValues)         // IN: Return values
+{
+   ASSERT(window);
+   ASSERT(window->get_display());
+   ASSERT(!atomName.empty());
+
+   GdkDisplay* display = const_cast<GdkDisplay*>(window->get_display()->gobj());
+   GdkWindow* gdkwin = const_cast<GdkWindow*>(window->gobj());
+
+   Atom atom = gdk_x11_get_xatom_by_name_for_display(display, atomName.c_str());
+
+   Atom type;
+   int format;
+   unsigned long nitems;
+   unsigned long bytes_after;
+   uint8* values;
+
+   gdk_error_trap_push();
+   int ret = XGetWindowProperty(GDK_DISPLAY_XDISPLAY(display),
+                                GDK_WINDOW_XID(gdkwin),
+                                atom, 0, G_MAXLONG, False, XA_CARDINAL, &type,
+                                &format, &nitems, &bytes_after, &values);
+   int err = gdk_error_trap_pop();
+
+   if (ret == Success && !err) {
+      if (type == XA_CARDINAL && nitems > 0) {
+         retValues.resize(nitems);
+
+         if (format == 8) {
+            for (unsigned long i = 0; i < nitems; i++) {
+               retValues[i] = values[i];
+            }
+         } else if (format == 16) {
+            uint16* shortValues = (uint16*)values;
+            for (unsigned long i = 0; i < nitems; i++) {
+               retValues[i] = shortValues[i];
+            }
+         } else if (format == 32) {
+            unsigned long* longValues = (unsigned long*)values;
+            for (unsigned long i = 0; i < nitems; i++) {
+               retValues[i] = longValues[i];
+            }
+         } else {
+            NOT_IMPLEMENTED();
+         }
+
+         XFree(values);
+         return true;
+      }
+
+      XFree(values);
+   }
+
+   return false;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * xutils::SetDesktopForWindow --
+ *
+ *      Sets the virtual desktop that a window is on. This takes care of
+ *      the workspace part of the desktop. Viewports must be handled
+ *      separately by moving the window.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SetDesktopForWindow(Glib::RefPtr<Gdk::Window> window, // IN:
+                    uint32 desktop)                   // IN:
+{
+   GdkScreen* screen = window->get_screen()->gobj();
+   Atom tempDesktop = desktop; // Cast for 64-bit correctness.
+   Window win = GDK_WINDOW_XID(window->gobj());
+   Display* display = GDK_WINDOW_XDISPLAY(window->gobj());
+
+   Atom atom = gdk_x11_get_xatom_by_name_for_display(
+      window->get_display()->gobj(), "_NET_WM_DESKTOP");
+
+   gdk_error_trap_push();
+   XChangeProperty(display, win, atom,
+                   XA_CARDINAL, 32, PropModeReplace,
+                   (unsigned char*)&tempDesktop, 1);
+   gdk_flush();
+   int err = gdk_error_trap_pop();
+
+   if (err) {
+      Warning("Unable to move host window (XID %d) to desktop %d\n",
+          (int)GDK_WINDOW_XID(window->gobj()), desktop);
+   }
+
+   XEvent ev;
+   ev.xclient.type = ClientMessage;
+   ev.xclient.serial = 0;
+   ev.xclient.send_event = True;
+   ev.xclient.window = win;
+   ev.xclient.message_type = atom;
+   ev.xclient.format = 32;
+   ev.xclient.data.l[0] = desktop;
+   ev.xclient.data.l[1] = 2; // source (2 gives full control)
+   ev.xclient.data.l[2] = 0; // unused
+   ev.xclient.data.l[3] = 0; // unused
+   ev.xclient.data.l[4] = 0; // unused
+
+   gdk_error_trap_push();
+   XSendEvent(display,
+              GDK_WINDOW_XID(gdk_screen_get_root_window(screen)),
+              False, SubstructureRedirectMask | SubstructureNotifyMask,
+              &ev);
+   gdk_flush();
+   err = gdk_error_trap_pop();
+
+   if (err) {
+      Warning("Unable to move host window (XID %d) to desktop %d\n",
+          (int)GDK_WINDOW_XID(window->gobj()), desktop);
+   }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * xutils::SetFullscreenMonitorsHint --
+ *
+ *      Sets the _NET_WM_FULLSCREEN_MONITORS hint for the passed in window and
+ *      monitor indices.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SetFullscreenMonitorsHint(Glib::RefPtr<Gdk::Window> window, // IN:
+                          std::vector<long> monitors)       // IN:
+{
+   // monitors contains 4 monitor indices, per EWMH spec
+   ASSERT(monitors.size() == 4);
+
+   Display* display = GDK_WINDOW_XDISPLAY(window->gobj());
+
+   XClientMessageEvent xclient;
+   memset(&xclient, 0, sizeof xclient);
+   xclient.type = ClientMessage;
+   xclient.window = GDK_WINDOW_XID(window->gobj());
+   xclient.message_type = XInternAtom(display,
+                                      "_NET_WM_FULLSCREEN_MONITORS",
+                                      False);
+   xclient.format = 32;
+
+   for (int i = 0; i < 4; i++) {
+      xclient.data.l[i] = monitors[i];
+   }
+
+   xclient.data.l[4] = 1;
+
+   XSendEvent(display,
+              GDK_WINDOW_XID(gdk_get_default_root_window()),
+              False,
+              SubstructureRedirectMask | SubstructureNotifyMask,
+              (XEvent *) &xclient);
+
+   XSync(display, False);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * xutils::GetDesktopForWindow --
+ *
+ *      Retrieve the virtual desktop that a given window is shown on.
+ *
+ * Results:
+ *      The index of the virtual desktop.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+uint32
+GetDesktopForWindow(Glib::RefPtr<const Gdk::Window> window) // IN:
+{
+   unsigned long result = 0;
+   GetCardinal(window, "_NET_WM_DESKTOP", result);
+   return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * xutils::GetNumDesktops --
+ *
+ *      Returns the number of virtual desktops.
+ *
+ * Results:
+ *      The number of virtual desktops.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+uint32
+GetNumDesktops(Glib::RefPtr<Gdk::Screen> screen) // IN:
+{
+   unsigned long result = 0;
+   GetCardinal(screen->get_root_window(), "_NET_NUMBER_OF_DESKTOPS", result);
+   return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * xutils::GetCurrentDesktop --
+ *
+ *      Retrieve the current virtual desktop for the screen.
+ *
+ * Results:
+ *      The index of the virtual desktop.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+uint32
+GetCurrentDesktop(Glib::RefPtr<Gdk::Screen> screen) // IN
+{
+   unsigned long result = 0;
+   GetCardinal(screen->get_root_window(), "_NET_CURRENT_DESKTOP", result);
+   return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * xutils::GetDesktopLayout --
+ *
+ *      Retrieves the current virtual desktop layout for the screen.
+ *
+ * Results:
+ *      The virtual desktop layout information is set and the function
+ *      returns true if successful. Otherwise false is returned.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+bool
+GetDesktopLayout(Glib::RefPtr<Gdk::Screen> screen, // IN: Screen
+                 uint32& rows,                     // OUT: Rows
+                 uint32& columns,                  // OUT: Columns
+                 Gtk::CornerType& corner,          // OUT: Corner of the first
+                                                   //      desktop.
+                 Gtk::Orientation& orientation)    // OUT: Desktop orientation
+{
+   std::vector<unsigned long> values;
+
+   if (GetCardinalList(screen->get_root_window(),
+                       "_NET_DESKTOP_LAYOUT", values)) {
+      switch (values[0]) {
+      case 0:
+         orientation = Gtk::ORIENTATION_HORIZONTAL;
+         break;
+
+      case 1:
+         orientation = Gtk::ORIENTATION_VERTICAL;
+         break;
+
+      default:
+         Warning("Unsupported orientation in _NET_DESKTOP_LAYOUT\n");
+         return false;
+      }
+
+      columns = static_cast<uint32>(values[1]);
+      rows = static_cast<uint32>(values[2]);
+
+      if (columns == 0 && rows == 0) {
+         Warning("Invalid desktop configuration in _NET_DESKTOP_LAYOUT. "
+                 "Rows and columns are both 0!\n");
+         return false;
+      } else if (columns == 0 || rows == 0) {
+         uint32 numDesktops = GetNumDesktops(screen);
+
+         if (columns == 0) {
+            columns = numDesktops / rows +
+                      ((numDesktops % rows) > 0 ? 1 : 0);
+         } else if (rows == 0) {
+            rows = numDesktops / columns +
+                   ((numDesktops % columns) > 0 ? 1 : 0);
+         }
+      }
+
+      corner = Gtk::CORNER_TOP_LEFT;
+
+      if (values.size() == 4) {
+         switch (values[3]) {
+         case 0:
+            corner = Gtk::CORNER_TOP_LEFT;
+            break;
+
+         case 1:
+            corner = Gtk::CORNER_TOP_RIGHT;
+            break;
+
+         case 2:
+            corner = Gtk::CORNER_BOTTOM_RIGHT;
+            break;
+
+         case 3:
+            corner = Gtk::CORNER_BOTTOM_LEFT;
+            break;
+
+         default:
+            Warning("Unsupported corner in _NET_DESKTOP_LAYOUT\n");
+            return false;
+         }
+      }
+
+      return true;
+   }
+
+   return false;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * xutils::GetDesktopGeometry --
+ *
+ *      Retrieves the desktop geometry for this screen.
+ *
+ * Results:
+ *      The desktop geometry is set and the function returns true if
+ *      successful. Otherwise false is returned.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+bool
+GetDesktopGeometry(Glib::RefPtr<Gdk::Screen> screen, // IN: The screen
+                   uint32& width,                    // OUT: Width
+                   uint32& height)                   // OUT: Height
+{
+   std::vector<unsigned long> values;
+
+   if (GetCardinalList(screen->get_root_window(),
+                       "_NET_DESKTOP_GEOMETRY", values)) {
+      if (values.size() == 2) {
+         width = values[0];
+         height = values[1];
+         return true;
+      }
+   }
+
+   return false;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * xutils::GetDesktopViewport --
+ *
+ *      Retrieves the viewport of the specified virtual desktop.
+ *
+ * Results:
+ *      The viewport is set and the function returns true if successful.
+ *      Otherwise false is returned.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+bool
+GetDesktopViewport(Glib::RefPtr<Gdk::Screen> screen, // IN: The screen
+                   uint32 desktopIndex,              // IN: Desktop index
+                   VMPoint& viewport)                // OUT: Viewport
+{
+   std::vector<unsigned long> values;
+
+   if (GetCardinalList(screen->get_root_window(),
+                       "_NET_DESKTOP_VIEWPORT", values)) {
+      uint32 numDesktops = GetNumDesktops(screen);
+
+      if (values.size() == numDesktops * 2) {
+         viewport.x = values[desktopIndex * 2];
+         viewport.y = values[desktopIndex * 2 + 1];
+         return true;
+      }
+   }
+
+   return false;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * xutils::RaiseWindowInternal --
+ *
+ *      Internal function to handle the restack operation.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+RaiseWindowInternal(Glib::RefPtr<Gdk::Window> window,  // IN: Window to raise
+                    Glib::RefPtr<Gdk::Window> sibling, // IN: The sibling
+                    guint32 timestamp)                 // IN: Event timestamp
+{
+   GdkScreen* screen = window->get_screen()->gobj();
+
+   if (gdk_x11_screen_supports_net_wm_hint(screen,
+         gdk_atom_intern_static_string("_NET_RESTACK_WINDOW"))) {
+      XEvent ev;
+      ev.xclient.type = ClientMessage;
+      ev.xclient.serial = 0;
+      ev.xclient.send_event = True;
+      ev.xclient.window = GDK_WINDOW_XID(window->gobj());
+      ev.xclient.message_type =
+         gdk_x11_get_xatom_by_name_for_display(window->get_display()->gobj(),
+                                               "_NET_RESTACK_WINDOW");
+      ev.xclient.format = 32;
+      ev.xclient.data.l[0] = 2;        // source (2 gives full control)
+      ev.xclient.data.l[1] = (sibling
+                              ? GDK_WINDOW_XID(sibling->gobj())
+                              : None); // sibling
+      ev.xclient.data.l[2] = Above;    // direction
+      ev.xclient.data.l[3] = 0;        // unused
+      ev.xclient.data.l[4] = 0;        // unused
+
+      XSendEvent(GDK_WINDOW_XDISPLAY(window->gobj()),
+                 GDK_WINDOW_XID(gdk_screen_get_root_window(screen)),
+                 False, SubstructureRedirectMask | SubstructureNotifyMask,
+                 &ev);
+   } else {
+      /*
+       * As of writing (2011-03-08), Metacity doesn't support
+       * _NET_RESTACK_WINDOW and will block our attempt to raise a window unless
+       * it's active, so we activate the window first.
+       */
+      if (gdk_x11_screen_supports_net_wm_hint(
+             screen,
+             gdk_atom_intern_static_string("_NET_ACTIVE_WINDOW"))) {
+
+         XClientMessageEvent xclient;
+         memset (&xclient, 0, sizeof (xclient));
+         xclient.type = ClientMessage;
+         xclient.window = GDK_WINDOW_XID(window->gobj());
+         xclient.message_type =
+            gdk_x11_get_xatom_by_name_for_display(window->get_display()->gobj(),
+                                                  "_NET_ACTIVE_WINDOW");
+         xclient.format = 32;
+         xclient.data.l[0] = 2; // source (2 gives full control)
+         xclient.data.l[1] = timestamp;
+         xclient.data.l[2] = None; // currently active window
+         xclient.data.l[3] = 0;
+         xclient.data.l[4] = 0;
+
+         XSendEvent(GDK_WINDOW_XDISPLAY(window->gobj()),
+                    GDK_WINDOW_XID(gdk_screen_get_root_window(screen)),
+                    False, SubstructureRedirectMask | SubstructureNotifyMask,
+                    (XEvent*)&xclient);
+      }
+
+      int flags = CWStackMode;
+      XWindowChanges changes;
+      changes.stack_mode = Above;
+
+      if (sibling) {
+         changes.sibling = GDK_WINDOW_XID(sibling->gobj());
+         flags |= CWSibling;
+      }
+
+      XReconfigureWMWindow(GDK_WINDOW_XDISPLAY(window->gobj()),
+                           GDK_WINDOW_XID(window->gobj()),
+                           DefaultScreen(GDK_WINDOW_XDISPLAY(window->gobj())),
+                           flags, &changes);
+   }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * xutils::RaiseWindow --
+ *
+ *      Raises a window to the top of the window stack. This version
+ *      accepts a timestamp instead of fetching it, useful when being
+ *      called from an event handler or when using a common timestamp.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+RaiseWindow(Glib::RefPtr<Gdk::Window> window,  // IN: Window to raise
+            Glib::RefPtr<Gdk::Window> sibling, // IN/OPT: The sibling
+            guint32 timestamp)                 // IN/OPT: Event timestamp
+{
+   /*
+    * Fake an input event timestamp so that the window manager
+    * will allow a restacking of this window.
+    */
+   gdk_x11_window_set_user_time(window->gobj(),
+      timestamp == 0
+      ?  gdk_x11_display_get_user_time(gdk_display_get_default())
+      : timestamp);
+
+   gdk_error_trap_push();
+   RaiseWindowInternal(window, sibling, timestamp);
+   gdk_flush();
+   int err = gdk_error_trap_pop();
+
+   if (err && sibling) {
+      /*
+       * This could be due to sibling not being a sibling window.
+       * Apparently, this is possible in our case. Ignore the "sibling."
+       */
+      gdk_error_trap_push();
+      RaiseWindowInternal(window, Glib::RefPtr<Gdk::Window>(), timestamp);
+      err = gdk_error_trap_pop();
+   }
+
+   if (err) {
+      /* We still have an error. Log it and continue on. */
+      Glib::ustring method;
+
+      if (gdk_x11_screen_supports_net_wm_hint(
+            window->get_screen()->gobj(),
+            gdk_atom_intern_static_string("_NET_RESTACK_WINDOW"))) {
+         method = "_NET_RESTACK_WINDOW";
+      } else {
+         method = "XReconfigureWMWindow";
+      }
+
+      if (sibling) {
+         Log("Unable to raise window (XID %d) over sibling (XID %d) using %s. "
+             "Error code = %d\n",
+             (int)GDK_WINDOW_XID(window->gobj()),
+             (int)GDK_WINDOW_XID(sibling->gobj()), method.c_str(), err);
+      } else {
+         Log("Unable to raise window (XID %d) using %s. Error code = %d\n",
+             (int)GDK_WINDOW_XID(window->gobj()), method.c_str(), err);
+      }
+   }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * xutils::GetHostWindowStack --
+ *
+ *      Returns the window stack as recorded by the window manager.
+ *      This is the equivalent of gdk_screen_get_window_stack, except
+ *      that function is broken on 64-bit platforms, so for the time
+ *      being we need to provide our own.
+ *
+ * Results:
+ *      The host window stack.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+HostWindowList
+GetHostWindowStack()
+{
+   HostWindowList windows;
+   GdkScreen* screen = gdk_screen_get_default();
+
+   if (!gdk_x11_screen_supports_net_wm_hint(screen,
+          gdk_atom_intern_static_string("_NET_CLIENT_LIST_STACKING"))) {
+      /*
+       * This is bad. We don't really have an alternative. We might want to
+       * just disable Unity.
+       */
+      return windows;
+   }
+
+   GdkDisplay* display = gdk_display_get_default();
+   unsigned long numItems = 0;
+   unsigned long bytesAfter = 0;
+   gint format = 0;
+   Atom type = 0;
+   guchar* data = NULL;
+
+   GdkWindow* rootWin = gdk_screen_get_root_window(screen);
+
+   gdk_error_trap_push();
+   int ret = XGetWindowProperty(GDK_DISPLAY_XDISPLAY(display),
+                                GDK_WINDOW_XID(rootWin),
+                                gdk_x11_get_xatom_by_name_for_display(display,
+                                   "_NET_CLIENT_LIST_STACKING"),
+                                0, G_MAXLONG, False, XA_WINDOW,
+                                &type, &format, &numItems, &bytesAfter,
+                                &data);
+   int err = gdk_error_trap_pop();
+
+   if (ret == Success && !err &&
+       type == XA_WINDOW && format == 32 && data != NULL && numItems > 0) {
+      long* stack = (long*)data;
+
+      for (unsigned long i = 0; i < numItems; i++) {
+#if GTK_MAJOR_VERSION == 3
+         GdkWindow* win =
+            gdk_x11_window_foreign_new_for_display(display, stack[i]);
+#else
+         GdkWindow* win =
+            gdk_window_foreign_new_for_display(display, stack[i]);
+#endif
+
+         if (win != NULL) {
+#if GTK_MAJOR_VERSION == 3
+            windows.push_back(Glib::wrap(win));
+#else
+            windows.push_back(Glib::wrap((GdkWindowObject*)win));
+#endif
+         }
+      }
+   }
+
+   return windows;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * xutils::GetMonitorWorkArea --
+ *
+ *      Gets the work area on a monitor. This is the area excluding docks,
+ *      which a window would size to when maximized.
+ *
+ *      While the window manager typically provides a work area spanning all
+ *      monitors (_NET_WORKAREA), it does not provide per-monitor work areas, so
+ *      we must compute our own.
+ *
+ * Results:
+ *      The work area of the specified monitor.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+GetMonitorWorkArea(Glib::RefPtr<Gdk::Screen> screen,    // IN:
+                   int monitor,                         // IN:
+                   Gdk::Rectangle& workArea)            // OUT:
+{
+#if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1,10,0)
+   /*
+    * Relies on Cairo::Region support available in cairo 1.10+, which is
+    * not available in our FreeBSD and Solaris toolchains.  Not called by
+    * Tools code, so it's fine to just ifdef this out.
+    */
+   NOT_IMPLEMENTED();
+#else
+
+
+   /*
+    * Start off by getting the size of the monitor. We're going to subtract
+    * from this.
+    */
+   Gdk::Rectangle screenGeom;
+   screen->get_monitor_geometry(monitor, screenGeom);
+   Cairo::RectangleInt rect;
+   Cairo::RefPtr<Cairo::Region> workAreaRegion = Cairo::Region::create();
+
+   rect.x = screenGeom.get_x();
+   rect.y = screenGeom.get_y();
+   rect.width = screenGeom.get_width();
+   rect.height = screenGeom.get_height();
+   workAreaRegion->do_union(rect);
+
+   /*
+    * If we're dealing with a reparenting window manager, then using XQueryTree
+    * will _not_ give us client windows, so to get client windows reliably, we
+    * need to either use XQueryTree (get all top level windows) and iterate
+    * hierarchy (root -> frame -> client) to be able to test for application
+    * window properties, since these are only set on the client windows and not
+    * on reparenting frames, or just use _NET_CLIENT_LIST. In practice, WMs put
+    * docks and panels into _NET_CLIENT_LIST, so this should give us what we
+    * need.
+    */
+   HostWindowList windows = GetHostWindowStack();
+
+   for (HostWindowList::const_iterator iter = windows.begin();
+        iter != windows.end();
+        iter++) {
+
+      Glib::RefPtr<Gdk::Window> gdkWindow = *iter;
+      std::vector<unsigned long> values;
+      bool haveStrut = false;
+      NETWMStrutPartial strut = NETWMStrutPartial();
+
+      /*
+       * The EWMH spec says that the new _NET_WM_STRUT_PARTIAL takes precedence
+       * over the older _NET_WM_STRUT API.
+       */
+      if (   GetCardinalList(gdkWindow, "_NET_WM_STRUT_PARTIAL", values)
+          && values.size() == 12) {
+         haveStrut = true;
+         strut.left_width = values[0];
+         strut.right_width = values[1];
+         strut.top_height = values[2];
+         strut.bottom_height = values[3];
+         strut.left_start = values[4];
+         strut.left_end = values[5];
+         strut.right_start = values[6];
+         strut.right_end = values[7];
+         strut.top_start = values[8];
+         strut.top_end = values[9];
+         strut.bottom_start = values[10];
+         strut.bottom_end = values[11];
+      } else if (   GetCardinalList(gdkWindow, "_NET_WM_STRUT", values)
+                 && values.size() == 4) {
+         haveStrut = true;
+         strut.left_width = values[0];
+         strut.right_width = values[1];
+         strut.top_height = values[2];
+         strut.bottom_height = values[3];
+
+         /*
+          * Per EWMH spec: "This property (_NET_WM_STRUT) is equivalent to a
+          * _NET_WM_STRUT_PARTIAL property where all start values are 0 and all
+          * end values are the height or width of the logical screen."
+          */
+         strut.left_start = 0;
+         strut.left_end = screen->get_height();
+         strut.right_start = 0;
+         strut.right_end = screen->get_height();
+         strut.top_start = 0;
+         strut.top_end = screen->get_width();
+         strut.bottom_start = 0;
+         strut.bottom_end = screen->get_width();
+      } else {
+         continue;
+      }
+
+      ASSERT(haveStrut);
+
+      /*
+       * Struts can be defined on one or more of the screen edges, so we create
+       * 4 rectangles and subtract each from the work area.
+       *
+       * Per the EWMH spec: "Struts MUST be specified in root window
+       * coordinates, that is, they are not relative to the edges of any view
+       * port or Xinerama monitor.... Note that the strut is relative to the
+       * screen edge, and not the edge of the xinerama monitor."
+       */
+      Gdk::Rectangle top(strut.top_start,
+                         0,
+                         strut.top_end - strut.top_start,
+                         strut.top_height);
+      Gdk::Rectangle bottom(strut.bottom_start,
+                            screen->get_height() - strut.bottom_height,
+                            strut.bottom_end - strut.bottom_start,
+                            strut.bottom_height);
+      Gdk::Rectangle left(0,
+                          strut.left_start,
+                          strut.left_width,
+                          strut.left_end - strut.left_start);
+      Gdk::Rectangle right(screen->get_width() - strut.right_width,
+                           strut.right_start,
+                           strut.right_width,
+                           strut.right_end - strut.right_start);
+
+      /*
+       * We want each strut's rectangle to be used as if it was taking up the
+       * entire edge of the monitor, so artificially inflate height or width as
+       * need be. This means that instead of using the start and end strut
+       * values, we take the whole edge.
+       */
+      Gdk::Rectangle edge;
+      bool intersects = false;
+
+      edge = top.intersect(screenGeom, intersects);
+
+      if (top.get_height() > 0 && intersects && !edge.has_zero_area()) {
+         rect.x = screenGeom.get_x();
+         rect.y = screenGeom.get_y();
+         rect.width = screenGeom.get_width();
+         rect.height = edge.get_height();
+         workAreaRegion->subtract(rect);
+      }
+
+      edge = bottom.intersect(screenGeom, intersects);
+
+      if (bottom.get_height() > 0 && intersects && !edge.has_zero_area()) {
+         rect.x = screenGeom.get_x();
+         rect.y = edge.get_y();
+         rect.width = screenGeom.get_width();
+         rect.height = edge.get_height();
+         workAreaRegion->subtract(rect);
+      }
+
+      edge = left.intersect(screenGeom, intersects);
+
+      if (left.get_width() > 0 && intersects && !edge.has_zero_area()) {
+         rect.x = screenGeom.get_x();
+         rect.y = screenGeom.get_y();
+         rect.width = edge.get_width();
+         rect.height = screenGeom.get_height();
+         workAreaRegion->subtract(rect);
+      }
+
+      edge = right.intersect(screenGeom, intersects);
+
+      if (right.get_width() > 0 && intersects && !edge.has_zero_area()) {
+         rect.x = edge.get_x();
+         rect.y = screenGeom.get_y();
+         rect.width = edge.get_width();
+         rect.height = screenGeom.get_height();
+         workAreaRegion->subtract(rect);
+      }
+   }
+
+   rect = workAreaRegion->get_extents();
+   workArea.set_x(rect.x);
+   workArea.set_y(rect.y);
+   workArea.set_width(rect.width);
+   workArea.set_height(rect.height);
+#endif // if CAIRO_VERSION
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * xutils::GetWindowManagerName --
+ *
+ *      Retrieves the current Window Manager name, if we can find it. This
+ *      mimics the behavior of gdk_x11_screen_get_window_manager_name(), but
+ *      there seem to be issues with that method returning its cached window
+ *      manager name when it shouldn't
+ *      (http://bugzilla.redhat.com/show_bug.cgi?id=471927).
+ *
+ * Results:
+ *      If we can find the current window manager name, we'll return it. If we
+ *      can't, then we'll return "unknown" -- same behavior as
+ *      gdk_x11_screen_get_window_manager_name().
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+utf::string
+GetWindowManagerName(Glib::RefPtr<Gdk::Screen> screen) // IN: Screen
+{
+   utf::string wmName = "unknown";
+   GdkDisplay* display = gdk_display_get_default();
+   unsigned long numItems = 0;
+   unsigned long bytesAfter = 0;
+   gint format = 0;
+   Atom type = 0;
+   guchar* data = NULL;
+   ::Window* window;
+
+   GdkWindow* rootWin = gdk_screen_get_root_window(screen->gobj());
+
+   /*
+    * First, we need to get the window that our EWMH-compliant WM is using to
+    * communicate its properties with.
+    */
+   gdk_error_trap_push();
+   int ret = XGetWindowProperty(GDK_DISPLAY_XDISPLAY(display),
+                                GDK_WINDOW_XID(rootWin),
+                                gdk_x11_get_xatom_by_name_for_display(display,
+                                   "_NET_SUPPORTING_WM_CHECK"),
+                                0, G_MAXLONG, False, XA_WINDOW,
+                                &type, &format, &numItems, &bytesAfter,
+                                &data);
+   int err = gdk_error_trap_pop();
+
+   if (ret != Success || err || type != XA_WINDOW || data == NULL) {
+      if (data) {
+         XFree(data);
+      }
+      return wmName;
+   }
+
+   window = (::Window*)data;
+   gchar* name = NULL;
+
+   /*
+    * Now, using the window provided in _NET_SUPPORTING_WM_CHECK, look for the
+    * _NET_WM_NAME on it.
+    */
+   gdk_error_trap_push();
+   ret = XGetWindowProperty(GDK_DISPLAY_XDISPLAY(display),
+                            *window,
+                            gdk_x11_get_xatom_by_name_for_display(display,
+                                "_NET_WM_NAME"),
+                            0, G_MAXLONG, False,
+                            gdk_x11_get_xatom_by_name_for_display(display,
+                                "UTF8_STRING"),
+                            &type, &format, &numItems, &bytesAfter,
+                            (guchar**)&name);
+   err = gdk_error_trap_pop();
+
+   XFree(window);
+
+   if (ret != Success || err || name == NULL) {
+      if (name != NULL) {
+         XFree(name);
+      }
+      return wmName;
+   }
+
+   wmName = name;
+   XFree(name);
+
+   return wmName;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * xutils::ChangeEWMHWindowState --
+ *
+ *      Sends the requested _NET_WM_STATE change through to the root window for
+ *      the Window Manager to act on.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+ChangeEWMHWindowState(bool add,                         // IN
+                      Glib::RefPtr<Gdk::Window> window, // IN
+                      GdkAtom state1,                   // IN
+                      GdkAtom state2)                   // IN
+{
+   GdkScreen* screen = window->get_screen()->gobj();
+   GdkDisplay* display = const_cast<GdkDisplay*>(window->get_display()->gobj());
+   Window win = GDK_WINDOW_XID(window->gobj());
+
+   XClientMessageEvent xclient;
+
+/* Straight from http://standards.freedesktop.org/wm-spec/wm-spec-latest.html */
+#define _NET_WM_STATE_REMOVE        0    /* remove/unset property */
+#define _NET_WM_STATE_ADD           1    /* add/set property */
+#define _NET_WM_STATE_TOGGLE        2    /* toggle property  */
+
+   memset(&xclient, 0, sizeof xclient);
+   xclient.type = ClientMessage;
+   xclient.window = win;
+   xclient.message_type = gdk_x11_get_xatom_by_name_for_display(display,
+                                                                "_NET_WM_STATE");
+   xclient.format = 32;
+   xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+   xclient.data.l[1] = gdk_x11_atom_to_xatom_for_display(display, state1);
+   xclient.data.l[2] = gdk_x11_atom_to_xatom_for_display(display, state2);
+   xclient.data.l[3] = 0;
+   xclient.data.l[4] = 0;
+
+   XSendEvent(GDK_DISPLAY_XDISPLAY(display),
+              GDK_WINDOW_XID(gdk_screen_get_root_window(screen)),
+              False, SubstructureRedirectMask | SubstructureNotifyMask,
+              (XEvent*)&xclient);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * xutils::GetEWMHWindowState --
+ *
+ *      Queries _NET_WM_STATE on the provided window and returns a std::list of
+ *      utf::strings which contain the X Atom names that are set as
+ *      _NET_WM_STATE for the given window.
+ *
+ * Results:
+ *      An std::list containing the utf::string names of all _NET_WM_STATE atoms
+ *      that are set on the given window.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+std::list<utf::string>
+GetEWMHWindowState(Glib::RefPtr<Gdk::Window> window) // IN
+{
+   std::list<utf::string> atomStrings;
+
+   GdkDisplay* display = const_cast<GdkDisplay*>(window->get_display()->gobj());
+   GdkWindow* gdkwin = const_cast<GdkWindow*>(window->gobj());
+
+   Atom type = None;
+   gint format;
+   gulong nitems;
+   gulong bytes_after;
+   guchar* data;
+   Atom* atoms = NULL;
+
+   gdk_error_trap_push();
+   int ret = XGetWindowProperty(GDK_DISPLAY_XDISPLAY(display),
+                                GDK_WINDOW_XID(gdkwin),
+                                gdk_x11_get_xatom_by_name_for_display(
+                                   display, "_NET_WM_STATE"),
+                                0, G_MAXLONG, False, XA_ATOM, &type, &format,
+                                &nitems, &bytes_after, &data);
+   int err = gdk_error_trap_pop();
+
+   if (ret != Success || err) {
+      atomStrings.push_back("Error calling XGetWindowProperty");
+      return atomStrings;
+   }
+
+   if (type != XA_ATOM) {
+      XFree(data);
+      atomStrings.push_back("Error: type != XA_ATOM");
+      return atomStrings;
+   }
+
+   atoms = reinterpret_cast<Atom*>(data);
+
+   for (gulong i = 0; i < nitems; ++i) {
+      atomStrings.push_back(gdk_x11_get_xatom_name(atoms[i]));
+   }
+
+   XFree(atoms);
+
+   return atomStrings;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * xutils::GetPointerLocation --
+ *
+ *      Get the location of the pointer relative to the root window.
+ *
+ * Results:
+ *      OUT parameters are filled in.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+GetPointerLocation(const Glib::RefPtr<Gdk::Window>& window, // IN
+                   int& x,                                  // OUT
+                   int& y,                                  // OUT
+                   Gdk::ModifierType& mask)                 // OUT
+{
+#if GTK_MAJOR_VERSION == 3
+   Glib::RefPtr<Gdk::DeviceManager> deviceManager =
+      window->get_display()->get_device_manager();
+   Glib::RefPtr<Gdk::Device> device = deviceManager->get_client_pointer();
+
+   window->get_device_position(device, x, y, mask);
+   window->get_root_coords(x, y, x, y);
+#else
+   window->get_display()->get_pointer(x, y, mask);
+#endif
+}
+
+
+} // namespace xutils
diff --git a/open-vm-tools/services/plugins/dndcp/xutils/xutils.hh b/open-vm-tools/services/plugins/dndcp/xutils/xutils.hh
new file mode 100644 (file)
index 0000000..3635f8b
--- /dev/null
@@ -0,0 +1,117 @@
+/*********************************************************
+ * Copyright (C) 2008-2013 VMware, Inc. All rights reserved.
+ *
+ * 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 version 2.1 and no 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 Lesser GNU 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+
+#ifndef XUTILS_XUTILS_HH
+#define XUTILS_XUTILS_HH
+
+
+#include <gdkmm.h>
+#include <gtkmm.h>
+
+#include "stringxx/string.hh"
+
+
+namespace xutils {
+
+typedef std::list<Glib::RefPtr<Gdk::Window> > HostWindowList;
+
+/* General initialization */
+void Init();
+
+
+/* General property helpers */
+bool GetCardinal(Glib::RefPtr<const Gdk::Window> window,
+                 const utf::string& atomName, unsigned long& retValue);
+bool GetCardinalList(Glib::RefPtr<const Gdk::Window> window,
+                     const utf::string& atomName,
+                     std::vector<unsigned long>& retValues);
+
+/*
+ * Utility functions for virtual desktops.
+ *
+ * There are two components to virtual desktops: Workspaces and Viewports.
+ *
+ * Workspaces can contain one or more viewports. Workspace layouts have a
+ * corner origin and a direction in which the workspaces are ordered.
+ *
+ * Viewports exist inside a workspace and are essentially one large screen
+ * containing windows. The current viewport has an X, Y offset on this
+ * large screen containing the physical screen full of content to display.
+ *
+ * Some window managers (Metacity, for example) use workspaces exclusively to
+ * represent virtual desktops, while others (Enlightenment) may use workspaces
+ * and viewports combined. Compiz uses multiple viewports in a single
+ * workspace.
+ */
+void SetDesktopForWindow(Glib::RefPtr<Gdk::Window> window, uint32 desktop);
+uint32 GetDesktopForWindow(Glib::RefPtr<const Gdk::Window> window);
+
+uint32 GetNumDesktops(Glib::RefPtr<Gdk::Screen> screen);
+uint32 GetCurrentDesktop(Glib::RefPtr<Gdk::Screen> screen);
+extern sigc::signal<void, Glib::RefPtr<Gdk::Screen> > currentDesktopChanged;
+
+bool GetDesktopLayout(Glib::RefPtr<Gdk::Screen> screen,
+                      uint32& rows, uint32& columns, Gtk::CornerType& corner,
+                      Gtk::Orientation& orientation);
+extern sigc::signal<void, Glib::RefPtr<Gdk::Screen> > desktopLayoutChanged;
+
+bool GetDesktopGeometry(Glib::RefPtr<Gdk::Screen> screen,
+                        uint32& width, uint32& height);
+extern sigc::signal<void, Glib::RefPtr<Gdk::Screen> > desktopGeometryChanged;
+
+bool GetDesktopViewport(Glib::RefPtr<Gdk::Screen> screen,
+                        uint32 desktopIndex, VMPoint& viewport);
+extern sigc::signal<void, Glib::RefPtr<Gdk::Screen> > desktopViewportChanged;
+
+extern sigc::signal<void, Glib::RefPtr<Gdk::Screen> > activeWindowChanged;
+
+/* Window stacking */
+void RaiseWindow(Glib::RefPtr<Gdk::Window> window,
+                 Glib::RefPtr<Gdk::Window> sibling =
+                    Glib::RefPtr<Gdk::Window>(),
+                 guint32 timestamp = 0);
+HostWindowList GetHostWindowStack();
+extern sigc::signal<void, Glib::RefPtr<Gdk::Screen> > windowStackChanged;
+
+
+/* Multi-head */
+void GetMonitorWorkArea(Glib::RefPtr<Gdk::Screen> screen,
+                        int monitor, Gdk::Rectangle& rect);
+
+utf::string GetWindowManagerName(Glib::RefPtr<Gdk::Screen> screen);
+extern sigc::signal<void, Glib::RefPtr<Gdk::Screen> > windowManagerChanged;
+
+void SetFullscreenMonitorsHint(Glib::RefPtr<Gdk::Window> window,
+                               std::vector<long> topology);
+
+void ChangeEWMHWindowState(bool add, Glib::RefPtr<Gdk::Window> window,
+                           GdkAtom state1, GdkAtom state2);
+std::list<utf::string> GetEWMHWindowState(Glib::RefPtr<Gdk::Window> window);
+
+void GetPointerLocation(const Glib::RefPtr<Gdk::Window>& window,
+                        int& x, int& y, Gdk::ModifierType& mask);
+
+
+extern sigc::signal<void, Glib::RefPtr<Gdk::Screen> > workAreaChanged;
+
+
+} // namespace xutils
+
+
+#endif // XUTILS_XUTILS_HH