]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
[Wayland DnD] Part3: Update the Drag Detection Window and Use UInput in DnDUIX11
authorOliver Kurth <okurth@vmware.com>
Tue, 5 Jun 2018 22:47:35 +0000 (15:47 -0700)
committerOliver Kurth <okurth@vmware.com>
Tue, 5 Jun 2018 22:47:35 +0000 (15:47 -0700)
Two changes in this patch:
1. Changes the class DragDetWnd to template class.

   Currently the DragDetWnd inherits from Gtk::Invisible, but Gtk::Invisible
   doesn't work for Wayland, it seems this is a bug for Wayland and maybe it
   will be fixed sometime.

   So, changes the DragDetWnd to template class, and it will inherit from
   Gtk::Invisible for X11 and inherit from Gtk::Window for Wayland.

2. Uses UInput to simulate mouse motion in class DuDUIX11.

This patch is part of the new feature 'Wayland support in Linux guest'.

open-vm-tools/services/plugins/dndcp/dndUIX11.cpp
open-vm-tools/services/plugins/dndcp/dndUIX11.h
open-vm-tools/services/plugins/dndcp/dragDetWndX11.cpp
open-vm-tools/services/plugins/dndcp/dragDetWndX11.h
open-vm-tools/services/plugins/dndcp/fakeMouseWayland/fakeMouseWayland.cpp

index 21387b85d642a27992e90b34f3f8be4d29834eab..d7409245940e147a25d3de3b3ecad832685b8109 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * Copyright (C) 2009-2017 VMware, Inc. All rights reserved.
+ * Copyright (C) 2009-2018 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
@@ -47,6 +47,7 @@ extern "C" {
 #include "rpcout.h"
 }
 
+#include "fakeMouseWayland/fakeMouseWayland.h"
 #include "dnd.h"
 #include "dndMsg.h"
 #include "hostinfo.h"
@@ -89,7 +90,8 @@ DnDUIX11::DnDUIX11(ToolsAppCtx *ctx)
       mNumPendingRequest(0),
       mDestDropTime(0),
       mTotalFileSize(0),
-      mOrigin(0, 0)
+      mOrigin(0, 0),
+      mUseUInput(false)
 {
    TRACE_CALL();
 
@@ -103,6 +105,17 @@ DnDUIX11::DnDUIX11(ToolsAppCtx *ctx)
     * corners for now.
     */
    OnWorkAreaChanged(Gdk::Screen::get_default());
+
+   //Initialize the uinput device if available
+   if (ctx->uinputFD != -1) {
+      Screen * scrn = DefaultScreenOfDisplay(XOpenDisplay(NULL));
+      if (FakeMouse_Init(ctx->uinputFD, scrn->width, scrn->height)) {
+         mUseUInput = true;
+         mScreenWidth = scrn->width;
+         mScreenHeight = scrn->height;
+      }
+   }
+   g_debug("%s: Use UInput? %d.\n", __FUNCTION__, mUseUInput);
 }
 
 
@@ -202,19 +215,19 @@ DnDUIX11::Init()
    CONNECT_SIGNAL(mDnD, updateUnityDetWndChanged, OnUpdateUnityDetWnd);
 
    /* Set Gtk+ callbacks for source. */
-   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);
+   CONNECT_SIGNAL(mDetWnd->GetWnd(), signal_drag_begin(),        OnGtkDragBegin);
+   CONNECT_SIGNAL(mDetWnd->GetWnd(), signal_drag_data_get(),     OnGtkDragDataGet);
+   CONNECT_SIGNAL(mDetWnd->GetWnd(), signal_drag_end(),          OnGtkDragEnd);
+   CONNECT_SIGNAL(mDetWnd->GetWnd(), signal_enter_notify_event(), GtkEnterEventCB);
+   CONNECT_SIGNAL(mDetWnd->GetWnd(), signal_leave_notify_event(), GtkLeaveEventCB);
+   CONNECT_SIGNAL(mDetWnd->GetWnd(), signal_map_event(),         GtkMapEventCB);
+   CONNECT_SIGNAL(mDetWnd->GetWnd(), signal_unmap_event(),       GtkUnmapEventCB);
+   CONNECT_SIGNAL(mDetWnd->GetWnd(), signal_realize(),           GtkRealizeEventCB);
+   CONNECT_SIGNAL(mDetWnd->GetWnd(), signal_unrealize(),         GtkUnrealizeEventCB);
+   CONNECT_SIGNAL(mDetWnd->GetWnd(), signal_motion_notify_event(), GtkMotionNotifyEventCB);
+   CONNECT_SIGNAL(mDetWnd->GetWnd(), signal_configure_event(),   GtkConfigureEventCB);
+   CONNECT_SIGNAL(mDetWnd->GetWnd(), signal_button_press_event(), GtkButtonPressEventCB);
+   CONNECT_SIGNAL(mDetWnd->GetWnd(), signal_button_release_event(), GtkButtonReleaseEventCB);
 
 #undef CONNECT_SIGNAL
 
@@ -281,16 +294,16 @@ DnDUIX11::InitGtk()
     * 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.
     */
-   mDetWnd->drag_dest_set(targets, Gtk::DEST_DEFAULT_MOTION,
-                          Gdk::ACTION_COPY | Gdk::ACTION_MOVE);
+   mDetWnd->GetWnd()->drag_dest_set(targets, Gtk::DEST_DEFAULT_MOTION,
+                                    Gdk::ACTION_COPY | Gdk::ACTION_MOVE);
 
-   mDetWnd->signal_drag_leave().connect(
+   mDetWnd->GetWnd()->signal_drag_leave().connect(
       sigc::mem_fun(this, &DnDUIX11::OnGtkDragLeave));
-   mDetWnd->signal_drag_motion().connect(
+   mDetWnd->GetWnd()->signal_drag_motion().connect(
       sigc::mem_fun(this, &DnDUIX11::OnGtkDragMotion));
-   mDetWnd->signal_drag_drop().connect(
+   mDetWnd->GetWnd()->signal_drag_drop().connect(
       sigc::mem_fun(this, &DnDUIX11::OnGtkDragDrop));
-   mDetWnd->signal_drag_data_received().connect(
+   mDetWnd->GetWnd()->signal_drag_data_received().connect(
       sigc::mem_fun(this, &DnDUIX11::OnGtkDragDataReceived));
 }
 
@@ -351,19 +364,42 @@ DnDUIX11::OnSrcDragBegin(const CPClipboard *clip,       // IN
    Glib::RefPtr<Gtk::TargetList> targets;
    Gdk::DragAction actions;
    GdkEventMotion event;
+   int mouseX = mOrigin.get_x() + DRAG_DET_WINDOW_WIDTH / 2;
+   int mouseY = mOrigin.get_y() + DRAG_DET_WINDOW_WIDTH / 2;
 
    TRACE_CALL();
 
    CPClipboard_Clear(&mClipboard);
    CPClipboard_Copy(&mClipboard, clip);
 
+   if (mUseUInput) {
+      /*
+       * Check if the screen size changes, if so then update the
+       * uinput device.
+       */
+      Screen * scrn = DefaultScreenOfDisplay(XOpenDisplay(NULL));
+      if (   (scrn->width != mScreenWidth)
+          || (scrn->height != mScreenHeight)) {
+         g_debug("%s: Update uinput device. prew:%d, preh:%d, w:%d, h:%d\n",
+                 __FUNCTION__,
+                 mScreenWidth,
+                 mScreenHeight,
+                 scrn->width,
+                 scrn->height);
+         mScreenWidth = scrn->width;
+         mScreenHeight = scrn->height;
+         FakeMouse_Update(mScreenWidth, mScreenHeight);
+      }
+   }
+
    /*
     * 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, true, true, mOrigin.get_x(), mOrigin.get_y());
+
+   SendFakeXEvents(true, true, false, true, true, mouseX, mouseY);
+   SendFakeXEvents(false, true, true, false, true, mouseX, mouseY);
 
    /*
     * Construct the target and action list, as well as a fake motion notify
@@ -409,7 +445,7 @@ DnDUIX11::OnSrcDragBegin(const CPClipboard *clip,       // IN
 
    /* TODO set the x/y coords to the actual drag initialization point. */
    event.type = GDK_MOTION_NOTIFY;
-   event.window = mDetWnd->get_window()->gobj();
+   event.window = mDetWnd->GetWnd()->get_window()->gobj();
    event.send_event = false;
    event.time = GDK_CURRENT_TIME;
    event.x = 10;
@@ -427,7 +463,7 @@ DnDUIX11::OnSrcDragBegin(const CPClipboard *clip,       // IN
    event.y_root = mOrigin.get_y();
 
    /* Tell Gtk that a drag should be started from this widget. */
-   mDetWnd->drag_begin(targets, actions, 1, (GdkEvent *)&event);
+   mDetWnd->GetWnd()->drag_begin(targets, actions, 1, (GdkEvent *)&event);
    mBlockAdded = false;
    mHGGetFileStatus = DND_FILE_TRANSFER_NOT_STARTED;
    SourceDragStartDone();
@@ -464,9 +500,14 @@ DnDUIX11::OnSrcCancel()
     * flybacks when we cancel as user moves mouse in and out of destination
     * window in a H->G DnD.
     */
-   OnUpdateDetWnd(true, 0, 0);
-   SendFakeXEvents(true, true, false, true, true, mOrigin.get_x(), mOrigin.get_y());
+   OnUpdateDetWnd(true, mOrigin.get_x(), mOrigin.get_y());
+   SendFakeXEvents(true, true, false, true, true,
+                   mOrigin.get_x() + DRAG_DET_WINDOW_WIDTH / 2,
+                   mOrigin.get_y() + DRAG_DET_WINDOW_WIDTH / 2);
    OnUpdateDetWnd(false, 0, 0);
+   SendFakeXEvents(false, false, false, false, true,
+                   mMousePosX,
+                   mMousePosY);
    mInHGDrag = false;
    mHGGetFileStatus = DND_FILE_TRANSFER_NOT_STARTED;
    mEffect = DROP_NONE;
@@ -636,12 +677,12 @@ DnDUIX11::OnUpdateDetWnd(bool show,     // IN: show (true) or hide (false)
 {
    g_debug("%s: enter 0x%lx show %d x %d y %d\n",
          __FUNCTION__,
-         (unsigned long) mDetWnd->get_window()->gobj(), show, x, y);
+         (unsigned long) mDetWnd->GetWnd()->get_window()->gobj(), show, x, y);
 
    /* If the window is being shown, move it to the right place. */
    if (show) {
-      x = MAX(x - DRAG_DET_WINDOW_WIDTH / 2, 0);
-      y = MAX(y - DRAG_DET_WINDOW_WIDTH / 2, 0);
+      x = MAX(x - DRAG_DET_WINDOW_WIDTH / 2, mOrigin.get_x());
+      y = MAX(y - DRAG_DET_WINDOW_WIDTH / 2, mOrigin.get_y());
 
       mDetWnd->Show();
       mDetWnd->Raise();
@@ -686,7 +727,7 @@ DnDUIX11::OnUpdateUnityDetWnd(bool show,         // IN: show (true) or hide (fal
 {
    g_debug("%s: enter 0x%lx unityID 0x%x\n",
          __FUNCTION__,
-         (unsigned long) mDetWnd->get_window()->gobj(),
+         (unsigned long) mDetWnd->GetWnd()->get_window()->gobj(),
          unityWndId);
 
    if (show && ((unityWndId > 0) || bottom)) {
@@ -848,7 +889,7 @@ DnDUIX11::OnGtkDragMotion(
    Gdk::DragAction srcActions;
    Gdk::DragAction suggestedAction;
    Gdk::DragAction dndAction = (Gdk::DragAction)0;
-   Glib::ustring target = mDetWnd->drag_dest_find_target(dc);
+   Glib::ustring target = mDetWnd->GetWnd()->drag_dest_find_target(dc);
 
    if (!mDnD->IsDnDAllowed()) {
       g_debug("%s: No dnd allowed!\n", __FUNCTION__);
@@ -1322,7 +1363,7 @@ DnDUIX11::OnGtkDragDrop(
 
    Glib::ustring target;
 
-   target = mDetWnd->drag_dest_find_target(dc);
+   target = mDetWnd->GetWnd()->drag_dest_find_target(dc);
    g_debug("%s: calling drag_finish\n", __FUNCTION__);
    dc->drag_finish(true, false, time);
 
@@ -1536,10 +1577,10 @@ DnDUIX11::RequestData(
     * be ignored.
     */
    targets->add(Glib::ustring(DRAG_TARGET_NAME_URI_LIST));
-   Glib::ustring target = mDetWnd->drag_dest_find_target(dc, targets);
+   Glib::ustring target = mDetWnd->GetWnd()->drag_dest_find_target(dc, targets);
    targets->remove(Glib::ustring(DRAG_TARGET_NAME_URI_LIST));
    if (target != "") {
-      mDetWnd->drag_get_data(dc, target, time);
+      mDetWnd->GetWnd()->drag_get_data(dc, target, time);
       mNumPendingRequest++;
       return true;
    }
@@ -1549,13 +1590,13 @@ DnDUIX11::RequestData(
    targets->add(Glib::ustring(TARGET_NAME_STRING));
    targets->add(Glib::ustring(TARGET_NAME_TEXT_PLAIN));
    targets->add(Glib::ustring(TARGET_NAME_COMPOUND_TEXT));
-   target = mDetWnd->drag_dest_find_target(dc, targets);
+   target = mDetWnd->GetWnd()->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 != "") {
-      mDetWnd->drag_get_data(dc, target, time);
+      mDetWnd->GetWnd()->drag_get_data(dc, target, time);
       mNumPendingRequest++;
    }
 
@@ -1563,12 +1604,12 @@ DnDUIX11::RequestData(
    targets->add(Glib::ustring(TARGET_NAME_APPLICATION_RTF));
    targets->add(Glib::ustring(TARGET_NAME_TEXT_RICHTEXT));
    targets->add(Glib::ustring(TARGET_NAME_TEXT_RTF));
-   target = mDetWnd->drag_dest_find_target(dc, targets);
+   target = mDetWnd->GetWnd()->drag_dest_find_target(dc, targets);
    targets->remove(Glib::ustring(TARGET_NAME_APPLICATION_RTF));
    targets->remove(Glib::ustring(TARGET_NAME_TEXT_RICHTEXT));
    targets->remove(Glib::ustring(TARGET_NAME_TEXT_RTF));
    if (target != "") {
-      mDetWnd->drag_get_data(dc, target, time);
+      mDetWnd->GetWnd()->drag_get_data(dc, target, time);
       mNumPendingRequest++;
    }
    return (mNumPendingRequest > 0);
@@ -1865,24 +1906,43 @@ DnDUIX11::SendFakeXEvents(
        * is okay since the window is invisible and hidden on cancels and DnD
        * finish.
        */
-      XMoveResizeWindow(dndXDisplay, dndXWindow, x - 5 , y - 5, 25, 25);
+      XMoveResizeWindow(dndXDisplay,
+                        dndXWindow,
+                        x - DRAG_DET_WINDOW_WIDTH / 2 ,
+                        y - DRAG_DET_WINDOW_WIDTH / 2,
+                        DRAG_DET_WINDOW_WIDTH,
+                        DRAG_DET_WINDOW_WIDTH);
       XRaiseWindow(dndXDisplay, dndXWindow);
-      g_debug("%s: move wnd to (%d, %d, %d, %d)\n", __FUNCTION__, x - 5, y - 5 , x + 25, y + 25);
+      g_debug("%s: move wnd to (%d, %d, %d, %d)\n",
+              __FUNCTION__,
+              x - DRAG_DET_WINDOW_WIDTH / 2 ,
+              y - DRAG_DET_WINDOW_WIDTH / 2,
+              DRAG_DET_WINDOW_WIDTH,
+              DRAG_DET_WINDOW_WIDTH);
    }
 
    /*
     * Generate mouse movements over the window.  The second one makes ungrabs
     * happen more reliably on KDE, but isn't necessary on GNOME.
     */
-   XTestFakeMotionEvent(dndXDisplay, -1, x, y, CurrentTime);
-   XTestFakeMotionEvent(dndXDisplay, -1, x + 1, y + 1, CurrentTime);
+   if (mUseUInput) {
+      FakeMouse_Move(x, y);
+      FakeMouse_Move(x + 1, y + 1);
+   } else {
+      XTestFakeMotionEvent(dndXDisplay, -1, x, y, CurrentTime);
+      XTestFakeMotionEvent(dndXDisplay, -1, x + 1, y + 1, CurrentTime);
+   }
    g_debug("%s: move mouse to (%d, %d) and (%d, %d)\n", __FUNCTION__, x, y, x + 1, y + 1);
 
    if (buttonEvent) {
       g_debug("%s: faking left mouse button %s\n", __FUNCTION__,
               buttonPress ? "press" : "release");
-      XTestFakeButtonEvent(dndXDisplay, 1, buttonPress, CurrentTime);
-      XSync(dndXDisplay, False);
+      if (mUseUInput) {
+         FakeMouse_Click(buttonPress);
+      } else {
+         XTestFakeButtonEvent(dndXDisplay, 1, buttonPress, CurrentTime);
+         XSync(dndXDisplay, False);
+      }
 
       if (!buttonPress) {
          /*
@@ -2039,15 +2099,14 @@ DnDUIX11::TryXTestFakeDeviceButtonEvent()
 GtkWidget *
 DnDUIX11::GetDetWndAsWidget()
 {
-   GtkInvisible *window;
    GtkWidget *widget = NULL;
 
    if (!mDetWnd) {
       return NULL;
    }
-   window = mDetWnd->gobj();
-   if (window) {
-      widget = GTK_WIDGET(window);
+
+   if (mDetWnd->GetWnd()->gobj()) {
+      widget = GTK_WIDGET(mDetWnd->GetWnd()->gobj());
    }
    return widget;
 }
index d4fda4c0ea77de6858f726fdba5dbdb14b3938e2..8740e1750306c8a55eb86ca8b1986ee5788c47b3 100644 (file)
@@ -231,6 +231,10 @@ private:
     * composite overlay window.
     */
    Gdk::Point mOrigin;
+
+   bool mUseUInput;
+   int mScreenWidth;
+   int mScreenHeight;
 };
 
 #endif // __DND_UI_X11_H__
index 11094ff3f9cf91c1b39a5337f9548d9d1c51bc7d..501e52ae53807c9ea9b57e9224a2edb09d6d2e54 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * Copyright (C) 2009-2016 VMware, Inc. All rights reserved.
+ * Copyright (C) 2009-2018 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
@@ -40,6 +40,32 @@ DragDetWnd::DragDetWnd() :
 #if defined(DETWNDDEBUG)
    DebugSetAttributes();
 #endif
+
+   bool useInvisible = true;
+
+#ifdef GTK3
+   char *xdgSessionType = getenv("XDG_SESSION_TYPE");
+   if (   (xdgSessionType != NULL)
+       && (strstr(xdgSessionType, "wayland") != NULL)) {
+      useInvisible = false;
+   }
+#endif
+
+   if (useInvisible) {
+      mWnd = new DragDetWndImpl<Gtk::Invisible>();
+   } else {
+      DragDetWndImpl<Gtk::Window> *win = new DragDetWndImpl<Gtk::Window>();
+      win->set_accept_focus(false);
+      win->set_decorated(false);
+      win->set_keep_above();
+      // Makes this window transparent because we don't want user to see it.
+      win->set_opacity(0.01);
+      // Calls 'Show' to create the Gtk::Window object.
+      win->show();
+      win->hide();
+
+      mWnd = win;
+   }
 }
 
 
@@ -53,6 +79,17 @@ DragDetWnd::~DragDetWnd()
 }
 
 
+/**
+ * Get the actual widget.
+ */
+
+Gtk::Widget *
+DragDetWnd::GetWnd()
+{
+   return mWnd;
+}
+
+
 /**
  * Flush the X connection.
  */
@@ -76,7 +113,7 @@ DragDetWnd::Flush()
 void
 DragDetWnd::Show(void)
 {
-   show();
+   GetWnd()->show_now();
    Flush();
 }
 
@@ -89,7 +126,7 @@ DragDetWnd::Show(void)
 void
 DragDetWnd::Hide(void)
 {
-   hide();
+   GetWnd()->hide();
    Flush();
 }
 
@@ -102,7 +139,7 @@ DragDetWnd::Hide(void)
 void
 DragDetWnd::Raise(void)
 {
-   Glib::RefPtr<Gdk::Window> gdkwin = get_window();
+   Glib::RefPtr<Gdk::Window> gdkwin = GetWnd()->get_window();
    if (gdkwin) {
       gdkwin->raise();
    }
@@ -118,7 +155,7 @@ DragDetWnd::Raise(void)
 void
 DragDetWnd::Lower(void)
 {
-   Glib::RefPtr<Gdk::Window> gdkwin = get_window();
+   Glib::RefPtr<Gdk::Window> gdkwin = GetWnd()->get_window();
    if (gdkwin) {
       gdkwin->lower();
    }
@@ -136,7 +173,7 @@ DragDetWnd::Lower(void)
 int
 DragDetWnd::GetScreenWidth(void)
 {
-   Glib::RefPtr<Gdk::Screen> gdkscreen = get_screen();
+   Glib::RefPtr<Gdk::Screen> gdkscreen = GetWnd()->get_screen();
    return gdkscreen->get_width();
 }
 
@@ -151,7 +188,7 @@ DragDetWnd::GetScreenWidth(void)
 int
 DragDetWnd::GetScreenHeight(void)
 {
-   Glib::RefPtr<Gdk::Screen> gdkscreen = get_screen();
+   Glib::RefPtr<Gdk::Screen> gdkscreen = GetWnd()->get_screen();
    return gdkscreen->get_height();
 }
 
@@ -168,10 +205,10 @@ DragDetWnd::GetScreenHeight(void)
 void
 DragDetWnd::DebugSetAttributes(void)
 {
-   set_default_size(1, 1);
-   set_resizable(true);
-   set_decorated(false);
-   set_type_hint(Gdk::WINDOW_TYPE_HINT_DOCK);
+   GetWnd()->set_default_size(1, 1);
+   GetWnd()->set_resizable(true);
+   GetWnd()->set_decorated(false);
+   GetWnd()->set_type_hint(Gdk::WINDOW_TYPE_HINT_DOCK);
 }
 #endif
 
@@ -192,7 +229,7 @@ DragDetWnd::SetGeometry(const int x,
                         const int width,
                         const int height)
 {
-   Glib::RefPtr<Gdk::Window> gdkwin = get_window();
+   Glib::RefPtr<Gdk::Window> gdkwin = GetWnd()->get_window();
 
    if (gdkwin) {
       gdkwin->move_resize(x, y, width, height);
@@ -219,7 +256,7 @@ DragDetWnd::SetGeometry(const int x,
 void
 DragDetWnd::GetGeometry(int &x, int &y, int &width, int &height)
 {
-   Glib::RefPtr<Gdk::Window> gdkwin = get_window();
+   Glib::RefPtr<Gdk::Window> gdkwin = GetWnd()->get_window();
    if (gdkwin) {
 #ifndef GTK3
       int dummy;
index afdcf33a85d1ad059eca432b4759a8148b028c4d..a35a17c032e74734670c58f80c3dfa42a5b0b68e 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * Copyright (C) 2009-2017 VMware, Inc. All rights reserved.
+ * Copyright (C) 2009-2018 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
 
 class DnDUI;
 
-class DragDetWnd : public Gtk::Invisible
+/*
+ * DragDetWnd is an invisible window, there are two ways to create an
+ * invisible window:
+ * 1. inherits from class Gtk::Invisible;
+ * 2. inherits from class Gtk::Window and set the opacity to 1%;
+ * Class Gtk::Invisible cannot be used for Wayland because
+ * the Gtk::Invisible cannot receive the mouse event with Wayland,
+ * it seems this is a bug of Wayland.
+ * So two drag detection windows are created, one inherits from
+ * Gtk::Invisible which is used for the X11, and another window
+ * inherits from Gtk::Window which is used for the Wayland.
+ * After Wayland fixes the bug of Gtk::Invisible, the window
+ * inherits from Gtk::Window will be removed.
+ */
+template<class TBase>
+class DragDetWndImpl : public TBase
+{
+public:
+   DragDetWndImpl() {}
+   virtual ~DragDetWndImpl() {}
+};
+
+class DragDetWnd
 {
 public:
    DragDetWnd();
    virtual ~DragDetWnd();
 
+   Gtk::Widget *GetWnd();
    void Show();
    void Hide();
    void Raise();
@@ -56,6 +79,7 @@ public:
 private:
    void Flush();
    bool m_isVisible;
+   Gtk::Widget *mWnd;
 };
 
 #if defined(DETWNDTEST)
index 2f30cd2ac0346da90c6e50328d184e9195971b00..ee675a9d70234f4bebd50fcd11fa3d88a77b5921 100644 (file)
@@ -219,6 +219,7 @@ FakeMouse_Destory()
    if (ioctl(uinput_fd, UI_DEV_DESTROY, 0) < 0) {
       g_debug("%s: Failed to destroy uinput device\n", __FUNCTION__);
    }
+   isInit = false;
 }
 
 
@@ -327,6 +328,6 @@ FakeMouse_Click(bool down)  // IN
     * Insert a pause here so that userspace has time to detect this event,
     * otherwise it will not notice the event we are about to send.
     */
-   usleep(10 * 1000);
+   usleep(100 * 1000);
    return retValue;
 }