[gtk/wip/chergert/quartz4u] start on some event dispatch stuff



commit 00f42c14d84388c2a79fced05c4d4d1cde371245
Author: Christian Hergert <chergert redhat com>
Date:   Mon Apr 27 12:53:35 2020 -0700

    start on some event dispatch stuff

 gdk/macos/GdkMacosView.c                | 769 ++++++++++++++++++++++++++++++++
 gdk/macos/GdkMacosView.h                |  52 +++
 gdk/macos/gdkmacosdisplay-private.h     |   3 +-
 gdk/macos/gdkmacosdisplay.c             |  76 +++-
 gdk/macos/gdkmacoseventsource-private.h |  31 ++
 gdk/macos/gdkmacoseventsource.c         | 110 +++++
 gdk/macos/meson.build                   |   2 +
 7 files changed, 1041 insertions(+), 2 deletions(-)
---
diff --git a/gdk/macos/GdkMacosView.c b/gdk/macos/GdkMacosView.c
new file mode 100644
index 0000000000..4a3f97fa5b
--- /dev/null
+++ b/gdk/macos/GdkMacosView.c
@@ -0,0 +1,769 @@
+/* GdkMacosView.m
+ *
+ * Copyright (C) 2005-2007 Imendio AB
+ * Copyright (C) 2011 Hiroyuki Yamamoto
+ * Copyright (C) 2020 Red Hat, Inc.
+ *
+ * This library 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; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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 GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#import "GdkMacosView.h"
+
+#include "gdkinternals.h"
+#include "gdkmacossurface.h"
+
+@implementation GdkMacosView
+
+-(id)initWithFrame: (NSRect)frameRect
+{
+  if ((self = [super initWithFrame: frameRect]))
+    {
+      markedRange = NSMakeRange (NSNotFound, 0);
+      selectedRange = NSMakeRange (NSNotFound, 0);
+    }
+
+  return self;
+}
+
+-(BOOL)acceptsFirstResponder
+{
+  GDK_NOTE (EVENTS, g_message ("acceptsFirstResponder"));
+
+  return YES;
+}
+
+-(BOOL)becomeFirstResponder
+{
+  GDK_NOTE (EVENTS, g_message ("becomeFirstResponder"));
+  return YES;
+}
+
+-(BOOL)resignFirstResponder
+{
+  GDK_NOTE (EVENTS, g_message ("resignFirstResponder"));
+  return YES;
+}
+
+-(void) keyDown: (NSEvent *) theEvent
+{
+  GDK_NOTE (EVENTS, g_message ("keyDown"));
+  [self interpretKeyEvents: [NSArray arrayWithObject: theEvent]];
+}
+
+-(void)flagsChanged: (NSEvent *) theEvent
+{
+}
+
+-(NSUInteger)characterIndexForPoint: (NSPoint)aPoint
+{
+  GDK_NOTE (EVENTS, g_message ("characterIndexForPoint"));
+  return 0;
+}
+
+-(NSRect)firstRectForCharacterRange: (NSRange)aRange actualRange: (NSRangePointer)actualRange
+{
+  GdkRectangle *rect;
+  gint ns_x;
+  gint ns_y;
+
+  g_assert (GDK_IS_MACOS_SURFACE (gdk_surface));
+
+  GDK_NOTE (EVENTS, g_message ("firstRectForCharacterRange"));
+
+  rect = g_object_get_data (G_OBJECT (gdk_surface), GIC_CURSOR_RECT);
+
+  if (rect)
+    {
+      _gdk_macos_surface_gdk_xy_to_xy (rect->x, rect->y + rect->height, &ns_x, &ns_y);
+      return NSMakeRect (ns_x, ns_y, rect->width, rect->height);
+    }
+
+  return NSMakeRect (0, 0, 0, 0);
+}
+
+-(NSArray *)validAttributesForMarkedText
+{
+  GDK_NOTE (EVENTS, g_message ("validAttributesForMarkedText"));
+
+  return [NSArray arrayWithObjects: NSUnderlineStyleAttributeName, nil];
+}
+
+-(NSAttributedString *)attributedSubstringForProposedRange: (NSRange)aRange actualRange: 
(NSRangePointer)actualRange
+{
+  GDK_NOTE (EVENTS, g_message ("attributedSubstringForProposedRange"));
+
+  return nil;
+}
+
+-(BOOL)hasMarkedText
+{
+  GDK_NOTE (EVENTS, g_message ("hasMarkedText"));
+
+  return markedRange.location != NSNotFound && markedRange.length != 0;
+}
+
+-(NSRange)markedRange
+{
+  GDK_NOTE (EVENTS, g_message ("markedRange"));
+
+  return markedRange;
+}
+
+-(NSRange)selectedRange
+{
+  GDK_NOTE (EVENTS, g_message ("selectedRange"));
+
+  return selectedRange;
+}
+
+-(void)unmarkText
+{
+  g_assert (GDK_IS_MACOS_SURFACE (gdk_surface));
+
+  GDK_NOTE (EVENTS, g_message ("unmarkText"));
+
+  markedRange = selectedRange = NSMakeRange (NSNotFound, 0);
+  g_object_set_data_full (G_OBJECT (gdk_surface), TIC_MARKED_TEXT, NULL, g_free);
+}
+
+-(void)setMarkedText: (id)aString selectedRange: (NSRange)newSelection replacementRange: 
(NSRange)replacementRange
+{
+  const char *str;
+
+  g_assert (GDK_IS_MACOS_SURFACE (gdk_surface));
+
+  GDK_NOTE (EVENTS, g_message ("setMarkedText"));
+
+  if (replacementRange.location == NSNotFound)
+    {
+      markedRange = NSMakeRange (newSelection.location, [aString length]);
+      selectedRange = NSMakeRange (newSelection.location, newSelection.length);
+    }
+  else {
+      markedRange = NSMakeRange (replacementRange.location, [aString length]);
+      selectedRange = NSMakeRange (replacementRange.location + newSelection.location, newSelection.length);
+    }
+
+  if ([aString isKindOfClass: [NSAttributedString class]])
+    {
+      str = [[aString string] UTF8String];
+    }
+  else {
+      str = [aString UTF8String];
+    }
+
+  g_object_set_data_full (G_OBJECT (gdk_surface), TIC_MARKED_TEXT, g_strdup (str), g_free);
+  g_object_set_data (G_OBJECT (gdk_surface), TIC_SELECTED_POS,
+                     GUINT_TO_POINTER (selectedRange.location));
+  g_object_set_data (G_OBJECT (gdk_surface), TIC_SELECTED_LEN,
+                     GUINT_TO_POINTER (selectedRange.length));
+
+  GDK_NOTE (EVENTS, g_message ("setMarkedText: set %s (%p, nsview %p): %s",
+                               TIC_MARKED_TEXT, gdk_surface, self,
+                               str ? str : "(empty)"));
+
+  /* handle text input changes by mouse events */
+  if (!GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (gdk_surface), TIC_IN_KEY_DOWN)))
+    _gdk_macos_synthesize_null_key_event (gdk_surface);
+}
+
+-(void)doCommandBySelector: (SEL)aSelector
+{
+  GDK_NOTE (EVENTS, g_message ("doCommandBySelector"));
+
+  if ([self respondsToSelector: aSelector])
+    [self performSelector: aSelector];
+}
+
+-(void)insertText: (id)aString replacementRange: (NSRange)replacementRange
+{
+  const char *str;
+  NSString *string;
+
+  g_assert (GDK_IS_MACOS_SURFACE (gdk_surface));
+
+  GDK_NOTE (EVENTS, g_message ("insertText"));
+
+  if ([self hasMarkedText])
+    [self unmarkText];
+
+  if ([aString isKindOfClass: [NSAttributedString class]])
+      string = [aString string];
+  else
+      string = aString;
+
+  NSCharacterSet *ctrlChars = [NSCharacterSet controlCharacterSet];
+  NSCharacterSet *wsnlChars = [NSCharacterSet whitespaceAndNewlineCharacterSet];
+  if ([string rangeOfCharacterFromSet:ctrlChars].length &&
+      [string rangeOfCharacterFromSet:wsnlChars].length == 0)
+    {
+      /* discard invalid text input with Chinese input methods */
+      str = "";
+      [self unmarkText];
+      NSInputManager *currentInputManager = [NSInputManager currentInputManager];
+      [currentInputManager markedTextAbandoned:self];
+    }
+  else
+   {
+      str = [string UTF8String];
+   }
+
+  GDK_NOTE (EVENTS, g_message ("insertText: set %s (%p, nsview %p): %s",
+                               TIC_INSERT_TEXT, gdk_surface, self,
+                               str ? str : "(empty)"));
+
+  g_object_set_data_full (G_OBJECT (gdk_surface), TIC_INSERT_TEXT, g_strdup (str), g_free);
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY, GUINT_TO_POINTER (GIC_FILTER_FILTERED));
+
+  /* handle text input changes by mouse events */
+  if (!GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (gdk_surface), TIC_IN_KEY_DOWN)))
+    _gdk_macos_synthesize_null_key_event (gdk_surface);
+}
+
+-(void)deleteBackward: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("deleteBackward"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)deleteForward: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("deleteForward"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)deleteToBeginningOfLine: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("deleteToBeginningOfLine"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)deleteToEndOfLine: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("deleteToEndOfLine"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)deleteWordBackward: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("deleteWordBackward"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)deleteWordForward: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("deleteWordForward"));
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)insertBacktab: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("insertBacktab"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)insertNewline: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("insertNewline"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY, GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)insertTab: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("insertTab"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveBackward: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveBackward"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveBackwardAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveBackwardAndModifySelection"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveDown: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveDown"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveDownAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveDownAndModifySelection"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveForward: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveForward"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveForwardAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveForwardAndModifySelection"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveLeft: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveLeft"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveLeftAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveLeftAndModifySelection"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveRight: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveRight"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveRightAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveRightAndModifySelection"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToBeginningOfDocument: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveToBeginningOfDocument"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToBeginningOfDocumentAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveToBeginningOfDocumentAndModifySelection"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToBeginningOfLine: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveToBeginningOfLine"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToBeginningOfLineAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveToBeginningOfLineAndModifySelection"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToEndOfDocument: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveToEndOfDocument"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToEndOfDocumentAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveToEndOfDocumentAndModifySelection"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToEndOfLine: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveToEndOfLine"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToEndOfLineAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveToEndOfLineAndModifySelection"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveUp: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveUp"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveUpAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveUpAndModifySelection"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordBackward: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveWordBackward"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordBackwardAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveWordBackwardAndModifySelection"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordForward: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveWordForward"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordForwardAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveWordForwardAndModifySelection"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordLeft: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveWordLeft"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordLeftAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveWordLeftAndModifySelection"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordRight: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveWordRight"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordRightAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("moveWordRightAndModifySelection"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)pageDown: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("pageDown"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)pageDownAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("pageDownAndModifySelection"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)pageUp: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("pageUp"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)pageUpAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("pageUpAndModifySelection"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)selectAll: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("selectAll"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)selectLine: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("selectLine"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)selectWord: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("selectWord"));
+
+  g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
+                     GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)noop: (id)sender
+{
+  GDK_NOTE (EVENTS, g_message ("noop"));
+}
+
+-(void)dealloc
+{
+  if (trackingRect)
+    {
+      [self removeTrackingRect: trackingRect];
+      trackingRect = 0;
+    }
+
+  [super dealloc];
+}
+
+-(void)setGdkSurface: (GdkSurface *)surface
+{
+  g_assert (!surface || GDK_IS_MACOS_SURFACE (surface));
+
+  gdk_surface = surface;
+}
+
+-(GdkSurface *)gdkSurface
+{
+  return gdk_surface;
+}
+
+-(NSTrackingRectTag)trackingRect
+{
+  return trackingRect;
+}
+
+-(BOOL)isFlipped
+{
+  return YES;
+}
+
+-(BOOL)isOpaque
+{
+  if (GDK_SURFACE_DESTROYED (gdk_surface))
+    return YES;
+
+  return NO;
+}
+
+-(void)drawRect: (NSRect)rect
+{
+  GdkRectangle gdk_rect;
+  const NSRect *drawn_rects;
+  NSInteger count;
+  int i;
+  cairo_region_t *region;
+
+  if (GDK_SURFACE_DESTROYED (gdk_surface))
+    return;
+
+  if ((gdk_window->event_mask & GDK_EXPOSURE_MASK) == 0)
+    return;
+
+  if (NSEqualRects (rect, NSZeroRect))
+    return;
+
+  if (!GDK_SURFACE_IS_MAPPED (gdk_surface))
+    {
+      /* If the window is not yet mapped, clip_region_with_children
+       * will be empty causing the usual code below to draw nothing.
+       * To not see garbage on the screen, we draw an aesthetic color
+       * here. The garbage would be visible if any widget enabled
+       * the NSView's CALayer in order to add sublayers for custom
+       * native rendering.
+       */
+      [NSGraphicsContext saveGraphicsState];
+
+      [[NSColor windowBackgroundColor] setFill];
+      [NSBezierPath fillRect: rect];
+
+      [NSGraphicsContext restoreGraphicsState];
+
+      return;
+    }
+
+  /* Clear our own bookkeeping of regions that need display */
+  if (impl->needs_display_region)
+    {
+      cairo_region_destroy (impl->needs_display_region);
+      impl->needs_display_region = NULL;
+    }
+
+  [self getRectsBeingDrawn: &drawn_rects count: &count];
+  region = cairo_region_create ();
+
+  for (i = 0; i < count; i++)
+    {
+      gdk_rect.x = drawn_rects[i].origin.x;
+      gdk_rect.y = drawn_rects[i].origin.y;
+      gdk_rect.width = drawn_rects[i].size.width;
+      gdk_rect.height = drawn_rects[i].size.height;
+
+      cairo_region_union_rectangle (region, &gdk_rect);
+    }
+
+  impl->in_paint_rect_count++;
+  _gdk_surface_process_updates_recurse (gdk_surface, region);
+  impl->in_paint_rect_count--;
+
+  cairo_region_destroy (region);
+
+  if (needsInvalidateShadow)
+    {
+      [[self window] invalidateShadow];
+      needsInvalidateShadow = NO;
+    }
+}
+
+-(void)setNeedsInvalidateShadow: (BOOL)invalidate
+{
+  needsInvalidateShadow = invalidate;
+}
+
+/* For information on setting up tracking rects properly, see here:
+ * http://developer.apple.com/documentation/Cocoa/Conceptual/EventOverview/EventOverview.pdf
+ */
+-(void)updateTrackingRect
+{
+  GdkSurfaceImplMacos *impl = GDK_SURFACE_IMPL_MACOS (gdk_window->impl);
+  NSRect rect;
+
+  if (!impl || !impl->toplevel)
+    return;
+
+  if (trackingRect)
+    {
+      [self removeTrackingRect: trackingRect];
+      trackingRect = 0;
+    }
+
+  if (!impl->toplevel)
+    return;
+
+  /* Note, if we want to set assumeInside we can use:
+   * NSPointInRect ([[self window] convertScreenToBase:[NSEvent mouseLocation]], rect)
+   */
+
+  rect = [self bounds];
+  trackingRect = [self addTrackingRect: rect
+                  owner: self
+                  userData: nil
+                  assumeInside: NO];
+}
+
+-(void)viewDidMoveToWindow
+{
+  if (![self window]) /* We are destroyed already */
+    return;
+
+  [self updateTrackingRect];
+}
+
+-(void)viewWillMoveToWindow: (NSWindow *)newWindow
+{
+  if (newWindow == nil && trackingRect)
+    {
+      [self removeTrackingRect: trackingRect];
+      trackingRect = 0;
+    }
+}
+
+-(void)setFrame: (NSRect)frame
+{
+  [super setFrame: frame];
+
+  if ([self window])
+    [self updateTrackingRect];
+}
+
+-(BOOL)wantsDefaultClipping
+{
+  return NO;
+}
+
+@end
diff --git a/gdk/macos/GdkMacosView.h b/gdk/macos/GdkMacosView.h
new file mode 100644
index 0000000000..c0a706655e
--- /dev/null
+++ b/gdk/macos/GdkMacosView.h
@@ -0,0 +1,52 @@
+/* GdkMacosView.h
+ *
+ * Copyright (C) 2005 Imendio AB
+ *
+ * This library 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; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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 GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#import <AppKit/AppKit.h>
+
+#include "gdk/gdk.h"
+
+/* Text Input Client */
+#define TIC_MARKED_TEXT  "tic-marked-text"
+#define TIC_SELECTED_POS "tic-selected-pos"
+#define TIC_SELECTED_LEN "tic-selected-len"
+#define TIC_INSERT_TEXT  "tic-insert-text"
+#define TIC_IN_KEY_DOWN  "tic-in-key-down"
+
+/* GtkIMContext */
+#define GIC_CURSOR_RECT      "gic-cursor-rect"
+#define GIC_FILTER_KEY       "gic-filter-key"
+#define GIC_FILTER_PASSTHRU  0
+#define GIC_FILTER_FILTERED  1
+
+@interface GdkMacosView : NSView <NSTextInputClient>
+{
+  GdkSurface *gdk_surface;
+  NSTrackingRectTag trackingRect;
+  BOOL needsInvalidateShadow;
+  NSRange markedRange;
+  NSRange selectedRange;
+}
+
+- (void)setGdkSurface: (GdkSurface *)surface;
+- (GdkSurface *)gdkSurface;
+- (NSTrackingRectTag)trackingRect;
+- (void)setNeedsInvalidateShadow: (BOOL)invalidate;
+
+@end
diff --git a/gdk/macos/gdkmacosdisplay-private.h b/gdk/macos/gdkmacosdisplay-private.h
index 6a025213d8..6d6ac06332 100644
--- a/gdk/macos/gdkmacosdisplay-private.h
+++ b/gdk/macos/gdkmacosdisplay-private.h
@@ -24,7 +24,8 @@
 
 G_BEGIN_DECLS
 
-GdkDisplay *_gdk_macos_display_open (const gchar *display_name);
+GdkDisplay *_gdk_macos_display_open   (const gchar     *display_name);
+int         _gdk_macos_display_get_fd (GdkMacosDisplay *self);
 
 G_END_DECLS
 
diff --git a/gdk/macos/gdkmacosdisplay.c b/gdk/macos/gdkmacosdisplay.c
index 9950f43cc5..beab658a9c 100644
--- a/gdk/macos/gdkmacosdisplay.c
+++ b/gdk/macos/gdkmacosdisplay.c
@@ -20,7 +20,16 @@
 #include "config.h"
 
 #include <AppKit/AppKit.h>
+#include <fcntl.h>
 #include <gdk/gdk.h>
+#include <unistd.h>
+
+#include <dispatch/dispatch.h>
+#include <errno.h>
+#include <mach/mach.h>
+#include <mach/port.h>
+#include <sys/event.h>
+#include <sys/time.h>
 
 #include "gdkdisplayprivate.h"
 #include "gdkmacosdisplay-private.h"
@@ -29,6 +38,11 @@
 #include "gdkmacossurface-private.h"
 #include "gdkmacosutils-private.h"
 
+/* See https://daurnimator.com/post/147024385399/using-your-own-main-loop-on-osx
+ * for more information on integrating Cocoa's CFRunLoop using an FD.
+ */
+extern mach_port_t _dispatch_get_main_queue_port_4CF (void);
+
 /**
  * SECTION:macos_interaction
  * @Short_description: macOS backend-specific functions
@@ -66,9 +80,12 @@
 struct _GdkMacosDisplay
 {
   GdkDisplay      parent_instance;
+
   gchar          *name;
   GPtrArray      *monitors;
   GdkMacosKeymap *keymap;
+
+  int             fd;
 };
 
 struct _GdkMacosDisplayClass
@@ -261,10 +278,18 @@ gdk_macos_display_create_surface (GdkDisplay     *display,
                                   int             width,
                                   int             height)
 {
+  GdkMacosSurface *surface;
+
   g_assert (GDK_IS_MACOS_DISPLAY (display));
   g_assert (!parent || GDK_IS_MACOS_SURFACE (parent));
 
-  return _gdk_macos_surface_new (display, surface_type, parent, x, y, width, height);
+  surface = _gdk_macos_surface_new (GDK_MACOS_DISPLAY (display),
+                                    surface_type,
+                                    parent,
+                                    x, y,
+                                    width, height);
+
+  return GDK_SURFACE (surface);
 }
 
 static GdkKeymap *
@@ -285,6 +310,12 @@ gdk_macos_display_finalize (GObject *object)
   g_clear_pointer (&self->monitors, g_ptr_array_unref);
   g_clear_pointer (&self->name, g_free);
 
+  if (self->fd != -1)
+    {
+      close (self->fd);
+      self->fd = -1;
+    }
+
   G_OBJECT_CLASS (gdk_macos_display_parent_class)->finalize (object);
 }
 
@@ -320,6 +351,7 @@ static void
 gdk_macos_display_init (GdkMacosDisplay *self)
 {
   self->monitors = g_ptr_array_new_with_free_func (g_object_unref);
+  self->fd = -1;
 }
 
 GdkDisplay *
@@ -347,3 +379,45 @@ _gdk_macos_display_open (const gchar *display_name)
 
   return GDK_DISPLAY (self);
 }
+
+int
+_gdk_macos_display_get_fd (GdkMacosDisplay *self)
+{
+  g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (self), -1);
+
+  if (self->fd == -1)
+    {
+      int fd = kqueue ();
+
+      if (fd != -1)
+        {
+          mach_port_t port;
+          mach_port_t portset;
+
+          fcntl (fd, F_SETFD, FD_CLOEXEC);
+          port = _dispatch_get_main_queue_port_4CF ();
+
+          if (KERN_SUCCESS == mach_port_allocate (mach_task_self (),
+                                                  MACH_PORT_RIGHT_PORT_SET,
+                                                  &portset))
+            {
+              struct kevent64_s event;
+
+              EV_SET64 (&event, portset, EVFILT_MACHPORT, EV_ADD|EV_CLEAR, MACH_RCV_MSG, 0, 0, 0, 0);
+
+              if (kevent64 (fd, &event, 1, NULL, 0, 0, &(struct timespec){0,0}) != 0)
+                {
+                  if (KERN_SUCCESS == mach_port_insert_member (mach_task_self (), port, portset))
+                    {
+                      self->fd = fd;
+                      return fd;
+                    }
+                }
+            }
+
+          close (fd);
+        }
+    }
+
+  return self->fd;
+}
diff --git a/gdk/macos/gdkmacoseventsource-private.h b/gdk/macos/gdkmacoseventsource-private.h
new file mode 100644
index 0000000000..60edcfdfa6
--- /dev/null
+++ b/gdk/macos/gdkmacoseventsource-private.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library 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; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_EVENT_SOURCE_PRIVATE_H__
+#define __GDK_MACOS_EVENT_SOURCE_PRIVATE_H__
+
+#include "gdkmacosdisplay.h"
+
+G_BEGIN_DECLS
+
+GSource *_gdk_macos_event_source_new (GdkMacosDisplay *display);
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_EVENT_SOURCE_PRIVATE_H__ */
diff --git a/gdk/macos/gdkmacoseventsource.c b/gdk/macos/gdkmacoseventsource.c
new file mode 100644
index 0000000000..3f500ee55a
--- /dev/null
+++ b/gdk/macos/gdkmacoseventsource.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library 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; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include <mach/mach.h>
+#include <mach/port.h>
+
+#include "gdkinternals.h"
+
+#include "gdkmacoseventsource-private.h"
+#include "gdkmacosdisplay-private.h"
+
+/* See https://daurnimator.com/post/147024385399/using-your-own-main-loop-on-osx
+ * for more information on integrating Cocoa's CFRunLoop using an FD.
+ */
+extern void _dispatch_main_queue_callback_4CF (void);
+
+typedef struct _GdkMacosEventSource
+{
+  GSource          source;
+  GPollFD          pfd;
+  GdkMacosDisplay *display;
+} GdkMacosEventSource;
+
+static gboolean
+gdk_macos_event_source_check (GSource *base)
+{
+  GdkMacosEventSource *source = (GdkMacosEventSource *)base;
+
+  g_assert (source != NULL);
+  g_assert (GDK_IS_MACOS_DISPLAY (source->display));
+
+  return (source->pfd.revents & G_IO_IN) != 0;
+}
+
+static gboolean
+gdk_macos_event_source_dispatch (GSource     *base,
+                                 GSourceFunc  callback,
+                                 gpointer     data)
+{
+  GdkMacosEventSource *source = (GdkMacosEventSource *)base;
+
+  g_assert (source != NULL);
+  g_assert (GDK_IS_MACOS_DISPLAY (source->display));
+
+  _dispatch_main_queue_callback_4CF ();
+
+  return G_SOURCE_CONTINUE;
+}
+
+static void
+gdk_macos_event_source_finalize (GSource *base)
+{
+  GdkMacosEventSource *source = (GdkMacosEventSource *)base;
+  source->display = NULL;
+}
+
+static GSourceFuncs macos_event_source_funcs = {
+  .prepare = NULL,
+  .check = gdk_macos_event_source_check,
+  .dispatch = gdk_macos_event_source_dispatch,
+  .finalize = gdk_macos_event_source_finalize,
+};
+
+GSource *
+_gdk_macos_event_source_new (GdkMacosDisplay *display)
+{
+  GdkMacosEventSource *macos_source;
+  GSource *source;
+  gchar *name;
+
+  g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
+
+  source = g_source_new (&macos_event_source_funcs, sizeof (GdkMacosEventSource));
+
+  macos_source = (GdkMacosEventSource *)source;
+  macos_source->display = display;
+  macos_source->pfd.fd = _gdk_macos_display_get_fd (display);
+  macos_source->pfd.events = G_IO_IN;
+  g_source_add_poll (source, &macos_source->pfd);
+
+  name = g_strdup_printf ("GDK macOS Event Source (%s)",
+                          gdk_display_get_name (GDK_DISPLAY (display)));
+
+  g_source_set_name (source, name);
+  g_source_set_priority (source, GDK_PRIORITY_EVENTS);
+  g_source_set_can_recurse (source, TRUE);
+  g_source_attach (source, NULL);
+
+  g_free (name);
+
+  return source;
+}
diff --git a/gdk/macos/meson.build b/gdk/macos/meson.build
index 2136f0759a..da4b9911b1 100644
--- a/gdk/macos/meson.build
+++ b/gdk/macos/meson.build
@@ -1,8 +1,10 @@
 gdk_macos_sources = files([
   'gdkmacosdisplay.c',
+  'gdkmacoseventsource.c',
   'gdkmacoskeymap.c',
   'gdkmacosmonitor.c',
   'gdkmacossurface.c',
+  # 'GdkMacosView.c',
   'GdkMacosWindow.c',
 
   # 'gdkapplaunchcontext-macos.c',


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