[gtk/gtk-3-24: 1/2] macos: Fix to offscreen window selections in Gimp 2.99




commit 16ded6835c9b4651635c6dc357b1d60b46710e0c
Author: Lukas Oberhuber <lukaso gmail com>
Date:   Fri May 27 21:26:50 2022 +0000

    macos: Fix to offscreen window selections in Gimp 2.99

 gdk/quartz/gdkdevice-core-quartz.c |  4 +-
 gdk/quartz/gdkevents-quartz.c      | 37 ++++++++++-------
 gdk/quartz/gdkglcontext-quartz.c   |  4 +-
 gdk/quartz/gdkwindow-quartz.c      | 82 +++++++++++++++++++++++++++++++-------
 gdk/quartz/gdkwindow-quartz.h      |  5 +++
 gtk/gtkdnd-quartz.c                |  4 +-
 gtk/gtkfilechoosernativequartz.c   |  4 +-
 modules/input/imquartz.c           | 17 ++++++--
 8 files changed, 114 insertions(+), 43 deletions(-)
---
diff --git a/gdk/quartz/gdkdevice-core-quartz.c b/gdk/quartz/gdkdevice-core-quartz.c
index a8fd34f224..4fd2ae940c 100644
--- a/gdk/quartz/gdkdevice-core-quartz.c
+++ b/gdk/quartz/gdkdevice-core-quartz.c
@@ -228,11 +228,9 @@ gdk_quartz_device_core_query_state_helper (GdkWindow       *window,
     }
   else
     {
-      GdkWindowImplQuartz *impl;
       NSWindow *nswindow;
 
-      impl = GDK_WINDOW_IMPL_QUARTZ (toplevel->impl);
-      nswindow = impl->toplevel;
+      nswindow = gdk_quartz_window_search_for_nearest_nswindow (window);
 
       point = [nswindow mouseLocationOutsideOfEventStream];
 
diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
index 1b43add865..891dfd4cea 100644
--- a/gdk/quartz/gdkevents-quartz.c
+++ b/gdk/quartz/gdkevents-quartz.c
@@ -387,7 +387,7 @@ get_window_point_from_screen_point (GdkWindow *window,
   NSPoint point;
   GdkQuartzNSWindow *nswindow;
 
-  nswindow = (GdkQuartzNSWindow*)(((GdkWindowImplQuartz *)window->impl)->toplevel);
+  nswindow = gdk_quartz_window_search_for_nearest_nswindow (window);
   point = [nswindow convertPointFromScreen:screen_point];
   *x = point.x;
   *y = window->height - point.y;
@@ -658,18 +658,25 @@ find_toplevel_under_pointer (GdkDisplay *display,
 
     }
 
-  if (toplevel)
-    {
-      get_window_point_from_screen_point (toplevel, screen_point, x, y);
-      /* If the coordinates are out of window bounds, this toplevel is not
-       * under the pointer and we thus return NULL. This can occur when
-       * toplevel under pointer has not yet been updated due to a very recent
-       * window resize. Alternatively, we should no longer be relying on
-       * the toplevel_under_pointer value which is maintained in gdkwindow.c.
-       */
-      if (*x < 0 || *y < 0 || *x >= toplevel->width || *y >= toplevel->height)
-        return NULL;
-    }
+  if (toplevel == NULL)
+    return NULL;
+
+  /*
+   * Root window type does not need translation, but also does not have
+   * an associated NSWindow and therefore can't translate screen points
+   */
+  if (toplevel == _gdk_root)
+    return toplevel;
+
+  get_window_point_from_screen_point (toplevel, screen_point, x, y);
+  /* If the coordinates are out of window bounds, this toplevel is not
+    * under the pointer and we thus return NULL. This can occur when
+    * toplevel under pointer has not yet been updated due to a very recent
+    * window resize. Alternatively, we should no longer be relying on
+    * the toplevel_under_pointer value which is maintained in gdkwindow.c.
+    */
+  if (*x < 0 || *y < 0 || *x >= toplevel->width || *y >= toplevel->height)
+    return NULL;
 
   return toplevel;
 }
@@ -793,7 +800,7 @@ find_toplevel_for_mouse_event (NSEvent    *nsevent,
 
           toplevel = toplevel_under_pointer;
 
-          toplevel_impl = (GdkWindowImplQuartz *)toplevel->impl;
+          toplevel_impl = GDK_WINDOW_IMPL_QUARTZ (toplevel->impl);
 
           *x = x_tmp;
           *y = y_tmp;
@@ -1405,7 +1412,7 @@ test_resize (NSEvent *event, GdkWindow *toplevel, gint x, gint y)
   /* Resizing from the resize indicator only begins if an GDK_QUARTZ_LEFT_MOUSE_BUTTON
    * event is received in the resizing area.
    */
-  toplevel_impl = (GdkWindowImplQuartz *)toplevel->impl;
+  toplevel_impl = GDK_WINDOW_IMPL_QUARTZ (toplevel->impl);
   if ([toplevel_impl->toplevel showsResizeIndicator])
   if ([event type] == GDK_QUARTZ_LEFT_MOUSE_DOWN &&
       [toplevel_impl->toplevel showsResizeIndicator])
diff --git a/gdk/quartz/gdkglcontext-quartz.c b/gdk/quartz/gdkglcontext-quartz.c
index a244d66e43..ddd18e1e7c 100644
--- a/gdk/quartz/gdkglcontext-quartz.c
+++ b/gdk/quartz/gdkglcontext-quartz.c
@@ -28,7 +28,7 @@
 #include "gdkquartzglcontext.h"
 #include "gdkquartzwindow.h"
 #include "gdkprivate-quartz.h"
-#include "gdkquartz-cocoa-access.h"
+#include "gdkinternal-quartz.h"
 
 #include "gdkinternals.h"
 
@@ -138,7 +138,7 @@ gdk_quartz_window_create_gl_context (GdkWindow     *window,
 
   if (attached)
     {
-      NSView *view = gdk_quartz_window_get_nsview (window);
+      NSView *view = gdk_quartz_window_search_for_nearest_nsview (window);
 
       if ([view respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)])
         [view setWantsBestResolutionOpenGLSurface:YES];
diff --git a/gdk/quartz/gdkwindow-quartz.c b/gdk/quartz/gdkwindow-quartz.c
index 4419975dc4..a9bc6c6504 100644
--- a/gdk/quartz/gdkwindow-quartz.c
+++ b/gdk/quartz/gdkwindow-quartz.c
@@ -125,22 +125,74 @@ gdk_quartz_window_init (GdkQuartzWindow *quartz_window)
  * GdkQuartzWindowImpl
  */
 
+static inline NSObject *
+gdk_quartz_window_search_for_nearest_nsobject (GdkWindow *window, bool get_nswindow_instead_of_nsview)
+{
+  GdkWindow *onscreen_window = window;
+  NSObject  *nsobject        = NULL;
+
+  if (GDK_WINDOW_DESTROYED (window))
+    return NULL;
+
+  /*
+   * if window is type GDK_WINDOW_OFFSCREEN
+   * you need to get the embedder in order to find the NSView
+   * see: gdkdevice.c:1461
+   */
+  while (1)
+    {
+      g_return_val_if_fail (onscreen_window != NULL, NULL);
+
+      if (GDK_IS_WINDOW_IMPL_QUARTZ (onscreen_window->impl))
+        {
+          if (get_nswindow_instead_of_nsview)
+            nsobject = GDK_WINDOW_IMPL_QUARTZ (onscreen_window->impl)->toplevel;
+          else
+            nsobject = GDK_WINDOW_IMPL_QUARTZ (onscreen_window->impl)->view;
+
+          if (nsobject != NULL)
+            break;
+        }
+
+      if (onscreen_window->window_type == GDK_WINDOW_OFFSCREEN)
+        onscreen_window = gdk_offscreen_window_get_embedder (onscreen_window);
+      else
+        onscreen_window = onscreen_window->parent;
+    }
+
+  g_return_val_if_fail (nsobject != NULL, NULL);
+
+  return nsobject;
+}
+
+NSView *
+gdk_quartz_window_search_for_nearest_nsview (GdkWindow *window)
+{
+  return (NSView *)gdk_quartz_window_search_for_nearest_nsobject (window, FALSE);
+}
+
+NSWindow *
+gdk_quartz_window_search_for_nearest_nswindow (GdkWindow *window)
+{
+  return (NSWindow *)gdk_quartz_window_search_for_nearest_nsobject (window, TRUE);
+}
+
 NSView *
 gdk_quartz_window_get_nsview (GdkWindow *window)
 {
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || !GDK_IS_WINDOW_IMPL_QUARTZ (window->impl))
     return NULL;
 
-  return ((GdkWindowImplQuartz *)window->impl)->view;
+  return GDK_WINDOW_IMPL_QUARTZ (window->impl)->view;
 }
 
 NSWindow *
 gdk_quartz_window_get_nswindow (GdkWindow *window)
 {
-  if (GDK_WINDOW_DESTROYED (window))
+  if (GDK_WINDOW_DESTROYED (window) || !GDK_IS_WINDOW_IMPL_QUARTZ (window->impl))
     return NULL;
 
-  return ((GdkWindowImplQuartz *)window->impl)->toplevel;
+  return GDK_WINDOW_IMPL_QUARTZ (window->impl)->toplevel;
 }
 
 static CGContextRef
@@ -220,9 +272,12 @@ gdk_window_impl_quartz_finalize (GObject *object)
     g_object_unref (impl->transient_for);
 
   if (impl->view)
-    [[NSNotificationCenter defaultCenter] removeObserver: impl->toplevel
-                                       name: @"NSViewFrameDidChangeNotification"
-                                     object: impl->view];
+    {
+      [[NSNotificationCenter defaultCenter] removeObserver: impl->toplevel
+                                        name: @"NSViewFrameDidChangeNotification"
+                                      object: impl->view];
+      [impl->view release];
+    }
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -319,6 +374,8 @@ static void
 gdk_window_impl_quartz_init (GdkWindowImplQuartz *impl)
 {
   impl->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
+  impl->view      = NULL;
+  impl->toplevel  = NULL;
 }
 
 static gboolean
@@ -369,7 +426,7 @@ _gdk_quartz_window_process_updates_recurse (GdkWindow *window,
           GdkWindowImplQuartz *toplevel_impl;
           NSWindow *nswindow;
 
-          toplevel_impl = (GdkWindowImplQuartz *)toplevel->impl;
+          toplevel_impl = GDK_WINDOW_IMPL_QUARTZ (toplevel->impl);
           nswindow = toplevel_impl->toplevel;
 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
           /* In theory, we could skip the flush disabling, since we only
@@ -877,9 +934,6 @@ _gdk_quartz_display_create_window_impl (GdkDisplay    *display,
                                  (attributes->cursor) :
                                  NULL));
 
-  impl->view = NULL;
-  impl->toplevel = NULL;
-
   if (attributes_mask & GDK_WA_TYPE_HINT)
     {
       type_hint = attributes->type_hint;
@@ -959,7 +1013,6 @@ _gdk_quartz_display_create_window_impl (GdkDisplay    *display,
                                       selector: @selector (windowDidResize:)
                                       name: @"NSViewFrameDidChangeNotification"
                                       object: impl->view];
-       [impl->view release];
       }
       break;
 
@@ -981,7 +1034,6 @@ _gdk_quartz_display_create_window_impl (GdkDisplay    *display,
            /* GdkWindows should be hidden by default */
            [impl->view setHidden:YES];
            [parent_impl->view addSubview:impl->view];
-           [impl->view release];
          }
       }
       break;
@@ -1580,7 +1632,7 @@ gdk_window_quartz_raise (GdkWindow *window)
         {
           GdkWindowImplQuartz *impl;
 
-          impl = (GdkWindowImplQuartz *)parent->impl;
+          impl = GDK_WINDOW_IMPL_QUARTZ (parent->impl);
 
           impl->sorted_children = g_list_remove (impl->sorted_children, window);
           impl->sorted_children = g_list_prepend (impl->sorted_children, window);
@@ -1611,7 +1663,7 @@ gdk_window_quartz_lower (GdkWindow *window)
         {
           GdkWindowImplQuartz *impl;
 
-          impl = (GdkWindowImplQuartz *)parent->impl;
+          impl = GDK_WINDOW_IMPL_QUARTZ (parent->impl);
 
           impl->sorted_children = g_list_remove (impl->sorted_children, window);
           impl->sorted_children = g_list_append (impl->sorted_children, window);
diff --git a/gdk/quartz/gdkwindow-quartz.h b/gdk/quartz/gdkwindow-quartz.h
index de9a5ebccf..34e64855a5 100644
--- a/gdk/quartz/gdkwindow-quartz.h
+++ b/gdk/quartz/gdkwindow-quartz.h
@@ -87,6 +87,11 @@ CGContextRef gdk_quartz_window_get_context     (GdkWindowImplQuartz *window,
 void         gdk_quartz_window_release_context (GdkWindowImplQuartz *window,
                                                 CGContextRef         context);
 
+_GDK_EXTERN /* Required for immmodule.cache */
+NSView *     gdk_quartz_window_search_for_nearest_nsview   (GdkWindow *window);
+_GDK_EXTERN /* Required for immmodule.cache */
+NSWindow *   gdk_quartz_window_search_for_nearest_nswindow (GdkWindow *window);
+
 /* Root window implementation for Quartz
  */
 
diff --git a/gtk/gtkdnd-quartz.c b/gtk/gtkdnd-quartz.c
index 3460de6edd..225c9353d2 100644
--- a/gtk/gtkdnd-quartz.c
+++ b/gtk/gtkdnd-quartz.c
@@ -42,7 +42,7 @@
 #include "gtkintl.h"
 #include "gtkquartz.h"
 #include "gdk/quartz/gdkquartz.h"
-#include "gdk/quartz/gdkquartz-cocoa-access.h"
+#include "gdk/quartz/gdkinternal-quartz.h"
 #include "gdk/quartz/gdkquartz-gtk-only.h"
 #include "gdk/quartz/gdkquartzdnd.h"
 #include "gtkselectionprivate.h"
@@ -364,7 +364,7 @@ get_toplevel_nswindow (GtkWidget *widget)
     return NULL;
 
   if (gtk_widget_is_toplevel (toplevel) && window)
-    return [gdk_quartz_window_get_nsview (window) window];
+    return [gdk_quartz_window_search_for_nearest_nsview (window) window];
   else
     return NULL;
 }
diff --git a/gtk/gtkfilechoosernativequartz.c b/gtk/gtkfilechoosernativequartz.c
index fb5abd5390..e295143b97 100644
--- a/gtk/gtkfilechoosernativequartz.c
+++ b/gtk/gtkfilechoosernativequartz.c
@@ -40,7 +40,7 @@
 #include "gtklabel.h"
 #include "gtkfilechooserentry.h"
 #include "gtkfilefilterprivate.h"
-#include <quartz/gdkquartz-cocoa-access.h>
+#include "gdk/quartz/gdkinternal-quartz.h"
 
 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
 typedef struct {
@@ -533,7 +533,7 @@ gtk_file_chooser_native_quartz_show (GtkFileChooserNative *self)
   if (transient_for)
     {
       gtk_widget_realize (GTK_WIDGET (transient_for));
-      data->parent = gdk_quartz_window_get_nswindow (gtk_widget_get_window (GTK_WIDGET (transient_for)));
+      data->parent = gdk_quartz_window_search_for_nearest_nswindow (gtk_widget_get_window (GTK_WIDGET 
(transient_for)));
 
       if (gtk_native_dialog_get_modal (GTK_NATIVE_DIALOG (self)))
         data->modal = TRUE;
diff --git a/modules/input/imquartz.c b/modules/input/imquartz.c
index bdee6da2f4..084e04f603 100644
--- a/modules/input/imquartz.c
+++ b/modules/input/imquartz.c
@@ -227,7 +227,7 @@ quartz_filter_keypress (GtkIMContext *context,
         return gtk_im_context_filter_keypress (qc->slave, event);
     }
 
-  nsview = gdk_quartz_window_get_nsview (qc->client_window);
+  nsview = gdk_quartz_window_search_for_nearest_nsview (qc->client_window);
 
   win = (GdkWindow *)[(GdkQuartzView *)[[nsevent window] contentView] gdkWindow];
   GTK_NOTE (MISC, g_print ("client_window: %p, win: %p, nsview: %p\n",
@@ -272,7 +272,7 @@ discard_preedit (GtkIMContext *context)
   if (!GDK_IS_QUARTZ_WINDOW (qc->client_window))
     return;
 
-  NSView *nsview = gdk_quartz_window_get_nsview (qc->client_window);
+  NSView *nsview = gdk_quartz_window_search_for_nearest_nsview (qc->client_window);
   if (!nsview)
     return;
 
@@ -361,8 +361,17 @@ quartz_set_cursor_location (GtkIMContext *context, GdkRectangle *area)
   if (!GDK_IS_QUARTZ_WINDOW (qc->client_window))
     return;
 
-  nsview = gdk_quartz_window_get_nsview (qc->client_window);
-  win = (GdkWindow *)[ (GdkQuartzView*)nsview gdkWindow];
+  nsview = gdk_quartz_window_search_for_nearest_nsview (qc->client_window);
+  if (nsview == NULL)
+    return;
+
+  win = (GdkWindow *)[(GdkQuartzView*)nsview gdkWindow];
+  if (win == NULL)
+    {
+      g_warning ("quartz_set_cursor_location received NULL gdkWindow");
+      return;
+    }
+
   g_object_set_data (G_OBJECT (win), GIC_CURSOR_RECT, qc->cursor_rect);
 }
 


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