[gtk/gtk-3-24: 1/2] Use WindowFromPoint to find DND target window




commit c71dca236c9f20f8316fe439ff1bfa2d7e38ba2d
Author: Luca Bacci <luca bacci982 gmail com>
Date:   Wed Aug 25 17:06:47 2021 +0200

    Use WindowFromPoint to find DND target window

 gdk/win32/gdkdnd-win32.c    | 99 +++++++++++++--------------------------------
 gdk/win32/gdkwindow-win32.c | 50 +++++++++++++++++------
 2 files changed, 66 insertions(+), 83 deletions(-)
---
diff --git a/gdk/win32/gdkdnd-win32.c b/gdk/win32/gdkdnd-win32.c
index 762e5c3023..ff8abc6cbd 100644
--- a/gdk/win32/gdkdnd-win32.c
+++ b/gdk/win32/gdkdnd-win32.c
@@ -2204,43 +2204,6 @@ _gdk_win32_window_get_drag_protocol (GdkWindow *window,
   return protocol;
 }
 
-typedef struct {
-  gint x;
-  gint y;
-  HWND ignore;
-  HWND result;
-} find_window_enum_arg;
-
-static BOOL CALLBACK
-find_window_enum_proc (HWND   hwnd,
-                       LPARAM lparam)
-{
-  RECT rect;
-  POINT tl, br;
-  find_window_enum_arg *a = (find_window_enum_arg *) lparam;
-
-  if (hwnd == a->ignore)
-    return TRUE;
-
-  if (!IsWindowVisible (hwnd))
-    return TRUE;
-
-  tl.x = tl.y = 0;
-  ClientToScreen (hwnd, &tl);
-  GetClientRect (hwnd, &rect);
-  br.x = rect.right;
-  br.y = rect.bottom;
-  ClientToScreen (hwnd, &br);
-
-  if (a->x >= tl.x && a->y >= tl.y && a->x < br.x && a->y < br.y)
-    {
-      a->result = hwnd;
-      return FALSE;
-    }
-  else
-    return TRUE;
-}
-
 static GdkWindow *
 gdk_win32_drag_context_find_window (GdkDragContext  *context,
                                    GdkWindow       *drag_window,
@@ -2250,51 +2213,47 @@ gdk_win32_drag_context_find_window (GdkDragContext  *context,
                                    GdkDragProtocol *protocol)
 {
   GdkWin32DragContext *context_win32 = GDK_WIN32_DRAG_CONTEXT (context);
-  GdkWindow *dest_window, *dw;
-  find_window_enum_arg a;
+  GdkWindow *toplevel = NULL;
+  HWND hwnd = NULL;
+  POINT pt;
 
-  a.x = x_root * context_win32->scale - _gdk_offset_x;
-  a.y = y_root * context_win32->scale - _gdk_offset_y;
-  a.ignore = drag_window ? GDK_WINDOW_HWND (drag_window) : NULL;
-  a.result = NULL;
+  pt.x = x_root * context_win32->scale - _gdk_offset_x;
+  pt.y = y_root * context_win32->scale - _gdk_offset_y;
 
   GDK_NOTE (DND,
-           g_print ("gdk_drag_find_window_real: %p %+d%+d\n",
-                    (drag_window ? GDK_WINDOW_HWND (drag_window) : NULL),
-                    a.x, a.y));
+            g_print ("gdk_drag_find_window_real: %+d%+d\n",
+            (int) pt.x, (int) pt.y));
 
-  EnumWindows (find_window_enum_proc, (LPARAM) &a);
+  hwnd = WindowFromPoint (pt);
 
-  if (a.result == NULL)
-    dest_window = NULL;
-  else
+  if (hwnd)
     {
-      dw = gdk_win32_handle_table_lookup (a.result);
-      if (dw)
+      GdkWindow *window = gdk_win32_handle_table_lookup (hwnd);
+
+      if (window)
         {
-          dest_window = gdk_window_get_toplevel (dw);
-          g_object_ref (dest_window);
+          toplevel = gdk_window_get_toplevel (window);
+          g_object_ref (toplevel);
         }
       else
-        dest_window = gdk_win32_window_foreign_new_for_display (gdk_screen_get_display (screen), a.result);
-
-      if (use_ole2_dnd)
-        *protocol = GDK_DRAG_PROTO_OLE2;
-      else if (context->source_window)
-        *protocol = GDK_DRAG_PROTO_LOCAL;
-      else
-        *protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
+        toplevel = gdk_win32_window_foreign_new_for_display (gdk_screen_get_display (screen), hwnd);
     }
 
+  if (use_ole2_dnd)
+    *protocol = GDK_DRAG_PROTO_OLE2;
+  else if (context->source_window)
+    *protocol = GDK_DRAG_PROTO_LOCAL;
+  else
+    *protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
+
   GDK_NOTE (DND,
-           g_print ("gdk_drag_find_window: %p %+d%+d: %p: %p %s\n",
-                    (drag_window ? GDK_WINDOW_HWND (drag_window) : NULL),
-                    x_root, y_root,
-                    a.result,
-                    (dest_window ? GDK_WINDOW_HWND (dest_window) : NULL),
-                    _gdk_win32_drag_protocol_to_string (*protocol)));
-
-  return dest_window;
+            g_print ("gdk_drag_find_window: %+d%+d: %p: %p %s\n",
+                     x_root, y_root,
+                     hwnd,
+                     (toplevel ? GDK_WINDOW_HWND (toplevel) : NULL),
+                     _gdk_win32_drag_protocol_to_string (*protocol)));
+
+  return toplevel;
 }
 
 static gboolean
diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c
index 2d0faaca3e..29004669ab 100644
--- a/gdk/win32/gdkwindow-win32.c
+++ b/gdk/win32/gdkwindow-win32.c
@@ -885,13 +885,13 @@ _gdk_win32_display_create_window_impl (GdkDisplay    *display,
   if (impl->type_hint == GDK_WINDOW_TYPE_HINT_UTILITY)
     dwExStyle |= WS_EX_TOOLWINDOW;
 
-  /* WS_EX_TRANSPARENT means "try draw this window last, and ignore input".
-   * It's the last part we're after. We don't want DND indicator to accept
-   * input, because that will make it a potential drop target, and if it's
-   * under the mouse cursor, this will kill any DND.
+  /* WS_EX_LAYERED | WS_EX_TRANSPARENT makes the window transparent w.r.t.
+   * pointer input: the system will direct all pointer input to the window
+   * below. We don't want a DND indicator to accept pointer input, because
+   * that will make it a potential drop target.
    */
   if (impl->type_hint == GDK_WINDOW_TYPE_HINT_DND)
-    dwExStyle |= WS_EX_TRANSPARENT;
+    dwExStyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT;
 
   klass = RegisterGdkClass (window->window_type, impl->type_hint);
 
@@ -1277,10 +1277,10 @@ show_window_internal (GdkWindow *window,
 
   exstyle = GetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE);
 
-  /* Use SetWindowPos to show transparent windows so automatic redraws
-   * in other windows can be suppressed.
+  /* If we have to show an input-only window,
+   * redraws can be safely skipped.
    */
-  if (exstyle & WS_EX_TRANSPARENT)
+  if (window->input_only)
     {
       UINT flags = SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER;
 
@@ -1416,7 +1416,6 @@ show_window_internal (GdkWindow *window,
        }
     }
 
-
   if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
     {
       gdk_window_fullscreen (window);
@@ -1489,10 +1488,10 @@ gdk_win32_window_hide (GdkWindow *window)
   if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TOPLEVEL)
     ShowOwnedPopups (GDK_WINDOW_HWND (window), FALSE);
 
-  /* Use SetWindowPos to hide transparent windows so automatic redraws
-   * in other windows can be suppressed.
+  /* If we have to hide an input-only window,
+   * readraws can be safely skipped.
    */
-  if (GetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE) & WS_EX_TRANSPARENT)
+  if (window->input_only)
     {
       SetWindowPos (GDK_WINDOW_HWND (window), SWP_NOZORDER_SPECIFIED,
                    0, 0, 0, 0,
@@ -2787,6 +2786,7 @@ _gdk_win32_window_update_style_bits (GdkWindow *window)
   GdkWindowImplWin32 *impl = (GdkWindowImplWin32 *)window->impl;
   GdkWMDecoration decorations;
   LONG old_style, new_style, old_exstyle, new_exstyle;
+  gboolean needs_basic_layering = FALSE;
   gboolean all;
   RECT rect, before, after;
   gboolean was_topmost;
@@ -2842,7 +2842,18 @@ _gdk_win32_window_update_style_bits (GdkWindow *window)
   else
     impl->layered = FALSE;
 
-  if (impl->layered)
+  /* DND windows need to have the WS_EX_TRANSPARENT | WS_EX_LAYERED styles
+   * set so to behave in input passthrough mode. That's essential for DND
+   * indicators.
+   */
+  if (!impl->layered &&
+      GDK_WINDOW_HWND (window) != NULL &&
+      impl->type_hint == GDK_WINDOW_TYPE_HINT_DND)
+    {
+      needs_basic_layering = TRUE;
+    }
+
+  if (impl->layered || needs_basic_layering)
     new_exstyle |= WS_EX_LAYERED;
   else
     new_exstyle &= ~WS_EX_LAYERED;
@@ -2859,6 +2870,19 @@ _gdk_win32_window_update_style_bits (GdkWindow *window)
       update_single_bit (&new_style, all, decorations & GDK_DECOR_MAXIMIZE, WS_MAXIMIZEBOX);
     }
 
+  if (needs_basic_layering)
+    {
+      /* SetLayeredWindowAttributes may have been already called, e.g. to set an opacity level.
+       * We only have to call the API in case it has never been called before on the window.
+       */
+      if (SetLastError(0),
+          !GetLayeredWindowAttributes (GDK_WINDOW_HWND (window), NULL, NULL, NULL) &&
+          GetLastError() == 0)
+        {
+          API_CALL (SetLayeredWindowAttributes, (GDK_WINDOW_HWND (window), 0, 255, LWA_ALPHA));
+        }
+    }
+
   if (old_style == new_style && old_exstyle == new_exstyle )
     {
       GDK_NOTE (MISC, g_print ("_gdk_win32_window_update_style_bits: %p: no change\n",


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]