From daf0f5ecb7b9a71d93d7e41b000369d977ea4816 Mon Sep 17 00:00:00 2001 From: Michael Natterer Date: Thu, 25 Apr 2013 14:52:18 +0200 Subject: [PATCH 50/68] nsview: clip text field cursor drawing by replacing (not "normal" swizzling) drawInsertionPointInRect. This fixes cursor clipping for the *blinking* cursor, but not if the cusor moves. Patch patially from Kris.. --- gtk/gtknsview.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 159 insertions(+), 3 deletions(-) diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c index bc3cbfb..5e3aa59 100644 --- a/gtk/gtknsview.c +++ b/gtk/gtknsview.c @@ -145,14 +145,23 @@ static void gtk_ns_view_swizzle_draw_rect_recursive (NSView *view, gpointer associated_object); @implementation NSView (myDidAddSubview) -- (void) myDidAddSubview:(NSView *)aView +- (void) myDidAddSubview: (NSView *) aView { void *associated_object; associated_object = objc_getAssociatedObject (self, "gtknsview"); if (associated_object) - gtk_ns_view_swizzle_draw_rect_recursive (aView, "gtknsview", associated_object); + { + gtk_ns_view_swizzle_draw_rect_recursive (aView, "gtknsview", associated_object); + } + else + { + associated_object = objc_getAssociatedObject (self, "gtkwindow"); + + if (associated_object) + gtk_ns_view_swizzle_draw_rect_recursive (aView, "gtkwindow", associated_object); + } [self myDidAddSubview:aView]; } @@ -256,6 +265,110 @@ static void gtk_ns_view_swizzle_draw_rect_recursive (NSView *view, } @end +@implementation NSTextView (myDrawInsertionPointInRect) +- (void) myDrawInsertionPointInRect: (NSRect) aRect + color: (NSColor *) aColor + turnedOn: (BOOL) flag +{ + GtkNSView *ns_view; + GtkWidget *viewport; + CGContextRef cg_context; + + ns_view = (GtkNSView *) objc_getAssociatedObject (self, "gtknsview"); + + if (! ns_view && ([self class] == [NSTextView class])) + { + /* if it's not a GtkNSView, check if it's the NSWindow's cell + * editor editing an NSTextField managed by a GtkNSView + */ + GtkWindow *window = (GtkWindow *) objc_getAssociatedObject (self, "gtkwindow"); + + if (GTK_IS_WINDOW (window)) + { + GtkWidget *focus = gtk_window_get_focus (window); + + if (GTK_IS_NS_VIEW (focus)) + ns_view = GTK_NS_VIEW (focus); + } + } + + if (! ns_view || + ns_view->priv->view != [ns_view->priv->view ancestorSharedWithView: self]) + { + [self myDrawInsertionPointInRect: aRect + color: aColor + turnedOn: flag]; + return; + } + + cg_context = [[NSGraphicsContext currentContext] graphicsPort]; + CGContextSaveGState (cg_context); + + for (viewport = gtk_widget_get_ancestor (GTK_WIDGET (ns_view), GTK_TYPE_VIEWPORT); + viewport; + viewport = gtk_widget_get_ancestor (gtk_widget_get_parent (viewport), + GTK_TYPE_VIEWPORT)) + { + GdkWindow *window; + GtkAllocation viewport_allocation; + CGRect rect; + + gtk_widget_get_allocation (viewport, &viewport_allocation); + + /* evil: don't clip to the viewport's width/height but to that + * of its parent window, because we know we hacked an + * overshoot_window into GtkScrolledWindow and need to restrict + * rendering to its area + */ + window = gtk_widget_get_parent_window (viewport); + + viewport_allocation.width = gdk_window_get_width (window); + viewport_allocation.height = gdk_window_get_height (window); + + if (gtk_viewport_get_shadow_type (GTK_VIEWPORT (viewport)) != GTK_SHADOW_NONE) + { + GtkStyle *style = gtk_widget_get_style (viewport); + + viewport_allocation.x += style->xthickness; + viewport_allocation.y += style->ythickness; + viewport_allocation.width -= 2 * style->xthickness; + viewport_allocation.height -= 2 * style->ythickness; + } + + gtk_widget_translate_coordinates (viewport, GTK_WIDGET (ns_view), + viewport_allocation.x, + viewport_allocation.y, + &viewport_allocation.x, + &viewport_allocation.y); + + rect.origin.x = viewport_allocation.x; + rect.origin.y = viewport_allocation.y; + rect.size.width = viewport_allocation.width; + rect.size.height = viewport_allocation.height; + + /* need to translate rect if this is not the view itself but a subview */ + if (ns_view->priv->view != self) + { + NSRect offset = NSMakeRect (0, 0, 0, 0); + + offset = [ns_view->priv->view convertRect: offset + fromView: self]; + + rect.origin.x -= offset.origin.x; + rect.origin.y -= offset.origin.y; + } + + CGContextClipToRect (cg_context, rect); + } + + [self myDrawInsertionPointInRect: aRect + color: aColor + turnedOn: flag]; + + CGContextRestoreGState (cg_context); +} +@end + static void gtk_ns_view_swizzle_draw_rect_recursive (NSView *view, const gchar *associated_key, @@ -310,7 +423,6 @@ gtk_ns_view_swizzle_draw_rect_recursive (NSView *view, method_getTypeEncoding (my_didAddSubview)); } - objc_setAssociatedObject (view, associated_key, (id) associated_object, OBJC_ASSOCIATION_ASSIGN); @@ -325,6 +437,49 @@ gtk_ns_view_swizzle_draw_rect_recursive (NSView *view, } static void +gtk_ns_view_replace_draw_insertion_point (void) +{ + static volatile gsize draw_insertion_point_replaced = 0; + + /* We replace the drawInsertPointInRect:color:turnedOn: method of the + * NSTextView class. This should only be done once per application + * instance. + */ + + if (g_once_init_enter (&draw_insertion_point_replaced)) + { + Method original_drawInsertionPointInRect; + Method my_drawInsertionPointInRect; + IMP original_implementation; + Class text_view_class = [NSTextView class]; + + /* Get the original method and an explicit reference to the + * implementation behind this method. This because after the + * first replace method call, the method will point at a different + * implementation. + */ + original_drawInsertionPointInRect = class_getInstanceMethod (text_view_class, + @selector (drawInsertionPointInRect:color:turnedOn:)); + original_implementation = method_getImplementation (original_drawInsertionPointInRect); + + my_drawInsertionPointInRect = class_getInstanceMethod (text_view_class, + @selector (myDrawInsertionPointInRect:color:turnedOn:)); + + class_replaceMethod (text_view_class, + @selector (drawInsertionPointInRect:color:turnedOn:), + method_getImplementation (my_drawInsertionPointInRect), + method_getTypeEncoding (my_drawInsertionPointInRect)); + + class_replaceMethod (text_view_class, + @selector (myDrawInsertionPointInRect:color:turnedOn:), + original_implementation, + method_getTypeEncoding (original_drawInsertionPointInRect)); + + g_once_init_leave (&draw_insertion_point_replaced, TRUE); + } +} + +static void gtk_ns_view_constructed (GObject *object) { GtkNSView *ns_view = GTK_NS_VIEW (object); @@ -340,6 +495,7 @@ gtk_ns_view_constructed (GObject *object) gtk_widget_get_can_focus (GTK_WIDGET (ns_view))); #endif + gtk_ns_view_replace_draw_insertion_point (); gtk_ns_view_swizzle_draw_rect_recursive (ns_view->priv->view, "gtknsview", ns_view); } -- 1.7.10.2 (Apple Git-33)