[gtk/wip/chergert/quartz4u] start on some event dispatch stuff
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/chergert/quartz4u] start on some event dispatch stuff
- Date: Mon, 27 Apr 2020 19:56:56 +0000 (UTC)
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]