From f28f8cb0510c91905751bee0f128e0912d8324c8 Mon Sep 17 00:00:00 2001 From: Lakshmi Shanmugam Date: Fri, 18 Aug 2017 12:35:45 +0530 Subject: Bug 508129 - [10.11]PaintEvent.GC.copyArea () crashes Eclipse Neon on OSX 10.11 and above When a GC is created with a control as the Drawable and GC.copyArea() is called, a SWT.Paint event is sent unexpectedly. This happens because NSView.cacheDisplayInRect() calls drawRect() which causes a SWT.Paint event to be sent. The fix is to ignore this paint event and prevent SWT from sending it to the clients. This is handled by creating a custom callback for cacheDisplayInRect, setting the ignorePaint flag and then calling the Cocoa implementation of cacheDisplayInRect. The ignorePaint flag is reset after the call. Change-Id: I4c2e2986b83868082295ea187b543376bf4c8a7e --- .../Eclipse SWT PI/cocoa/library/os.c | 20 ++++++++++++++++++++ .../Eclipse SWT PI/cocoa/library/os_stats.c | 1 + .../Eclipse SWT PI/cocoa/library/os_stats.h | 1 + .../cocoa/org/eclipse/swt/internal/cocoa/OS.java | 2 ++ .../cocoa/org/eclipse/swt/graphics/GC.java | 4 ++++ .../cocoa/org/eclipse/swt/widgets/Control.java | 18 ++++++++++++++++++ .../cocoa/org/eclipse/swt/widgets/Display.java | 7 +++++++ .../cocoa/org/eclipse/swt/widgets/Widget.java | 4 ++++ 8 files changed, 57 insertions(+) (limited to 'bundles/org.eclipse.swt') diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os.c b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os.c index b62f41243f..b1162fdf9a 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os.c @@ -135,6 +135,26 @@ JNIEXPORT jintLong JNICALL OS_NATIVE(CALLBACK_1attributedSubstringFromRange_1) } #endif +#ifndef NO_CALLBACK_1cacheDisplayInRect_1toBitmapImageRep_1 +static jintLong CALLBACK_1cacheDisplayInRect_1toBitmapImageRep_1; +static void proc_CALLBACK_1cacheDisplayInRect_1toBitmapImageRep_1(id arg0, SEL arg1, NSRect arg2, NSBitmapImageRep* arg3) { + ((void (*)(id, SEL, NSRect*, NSBitmapImageRep*))CALLBACK_1cacheDisplayInRect_1toBitmapImageRep_1)(arg0, arg1, &arg2, arg3); +} +static jintLong CALLBACK_cacheDisplayInRect_toBitmapImageRep_(jintLong func) { + CALLBACK_1cacheDisplayInRect_1toBitmapImageRep_1 = func; + return (jintLong)proc_CALLBACK_1cacheDisplayInRect_1toBitmapImageRep_1; +} +JNIEXPORT jintLong JNICALL OS_NATIVE(CALLBACK_1cacheDisplayInRect_1toBitmapImageRep_1) + (JNIEnv *env, jclass that, jintLong arg0) +{ + jintLong rc = 0; + OS_NATIVE_ENTER(env, that, CALLBACK_1cacheDisplayInRect_1toBitmapImageRep_1_FUNC); + rc = (jintLong)CALLBACK_cacheDisplayInRect_toBitmapImageRep_(arg0); + OS_NATIVE_EXIT(env, that, CALLBACK_1cacheDisplayInRect_1toBitmapImageRep_1_FUNC); + return rc; +} +#endif + #ifndef NO_CALLBACK_1canDragRowsWithIndexes_1atPoint_1 static jintLong CALLBACK_1canDragRowsWithIndexes_1atPoint_1; static BOOL proc_CALLBACK_1canDragRowsWithIndexes_1atPoint_1(id arg0, SEL arg1, NSIndexSet* arg2, NSPoint arg3) { diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.c b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.c index bac2ebb6a5..951fa0111e 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.c @@ -23,6 +23,7 @@ char * OS_nativeFunctionNames[] = { "CALLBACK_1NSTextAttachmentCell_1cellSize", "CALLBACK_1accessibilityHitTest_1", "CALLBACK_1attributedSubstringFromRange_1", + "CALLBACK_1cacheDisplayInRect_1toBitmapImageRep_1", "CALLBACK_1canDragRowsWithIndexes_1atPoint_1", "CALLBACK_1cellBaselineOffset", "CALLBACK_1cellSize", diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.h index 3fcc56dfe6..b3aca449a3 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.h +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.h @@ -33,6 +33,7 @@ typedef enum { CALLBACK_1NSTextAttachmentCell_1cellSize_FUNC, CALLBACK_1accessibilityHitTest_1_FUNC, CALLBACK_1attributedSubstringFromRange_1_FUNC, + CALLBACK_1cacheDisplayInRect_1toBitmapImageRep_1_FUNC, CALLBACK_1canDragRowsWithIndexes_1atPoint_1_FUNC, CALLBACK_1cellBaselineOffset_FUNC, CALLBACK_1cellSize_FUNC, diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java index 9e6ce3da39..531dcf55cc 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java @@ -680,6 +680,8 @@ public static final native void objc_msgSend_stret(NSSize result, long /*int*/ i public static final native long /*int*/ CALLBACK_accessibilityHitTest_(long /*int*/ func); /** @method callback_types=NSAttributedString*;id;SEL;NSRange;,callback_flags=none;none;none;struct; */ public static final native long /*int*/ CALLBACK_attributedSubstringFromRange_(long /*int*/ func); +/** @method callback_types=void;id;SEL;NSRect;NSBitmapImageRep*;,callback_flags=none;none;none;struct;none; */ +public static final native long /*int*/ CALLBACK_cacheDisplayInRect_toBitmapImageRep_(long /*int*/ func); /** @method callback_types=BOOL;id;SEL;NSIndexSet*;NSPoint;,callback_flags=none;none;none;none;struct; */ public static final native long /*int*/ CALLBACK_canDragRowsWithIndexes_atPoint_(long /*int*/ func); /** @method callback_types=NSSize;id;SEL;,callback_flags=struct;none;none; */ diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GC.java index 802653a116..b61b83ef78 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GC.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GC.java @@ -457,6 +457,10 @@ public void copyArea(Image image, int x, int y) { rect.height = size.height; NSBitmapImageRep imageRep = topView.bitmapImageRepForCachingDisplayInRect(rect); imageRep.setSize(size); + /* + * NSView.cacheDisplayInRect will cause an unexpected SWT.Paint event to be sent. + * This is handled by Control.cacheDisplayInRect_toBitmapImageRep(). + */ topView.cacheDisplayInRect(rect, imageRep); NSBitmapImageRep rep = image.getRepresentation(); image.handle.addRepresentation(imageRep); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Control.java index 2fbacd7b75..9cc52654fe 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Control.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Control.java @@ -69,6 +69,7 @@ public abstract class Control extends Widget implements Drawable { NSBezierPath regionPath; long /*int*/ visibleRgn; Accessible accessible; + boolean ignorePaint; boolean touchEnabled; final static int CLIPPING = 1 << 10; @@ -1259,6 +1260,7 @@ boolean drawsBackground() { @Override void drawWidget (long /*int*/ id, NSGraphicsContext context, NSRect rect) { + if (ignorePaint) return; if (id != paintView().id) return; if (!hooks (SWT.Paint) && !filters (SWT.Paint)) return; @@ -3963,6 +3965,22 @@ void setFrameSize (long /*int*/ id, long /*int*/ sel, NSSize size) { } } +@Override +void cacheDisplayInRect_toBitmapImageRep (long id, long sel, NSRect rect, long rep) { + /* + * When a GC is created with a control as the Drawable and GC.copyArea() is + * called, a SWT.Paint event will be sent, unexpectedly. This happens because + * NSView.cacheDisplayInRect() calls drawRect() which causes a SWT.Paint event + * to be sent. The fix is to ignore this paint event and prevent SWT from + * sending it to the clients. + * In the callback, set the ignorePaint flag, then call the Cocoa + * implementation of cacheDisplayInRect_toBitmapImageRep(), then reset the ignorePaint flag. + */ + ignorePaint = true; + super.cacheDisplayInRect_toBitmapImageRep(id, sel, rect, rep); + ignorePaint = false; +} + /** * Sets the layout data associated with the receiver to the argument. * diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java index 4bed47a96d..e9f51eac3a 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java @@ -2473,6 +2473,7 @@ void initClasses () { long /*int*/ setNeedsDisplayInRectProc = OS.CALLBACK_setNeedsDisplayInRect_(proc3); long /*int*/ expansionFrameWithFrameProc = OS.CALLBACK_expansionFrameWithFrame_inView_ (proc4); long /*int*/ focusRingMaskBoundsForFrameProc = OS.CALLBACK_focusRingMaskBoundsForFrame_inView_ (proc4); + long /*int*/ cacheDisplayInRect_toBitmapImageRepProc = OS.CALLBACK_cacheDisplayInRect_toBitmapImageRep_ (proc4); long /*int*/ sizeOfLabelProc = OS.CALLBACK_sizeOfLabel_ (proc3); long /*int*/ drawLabelInRectProc = OS.CALLBACK_drawLabel_inRect_ (proc4); long /*int*/ drawViewBackgroundInRectProc = OS.CALLBACK_drawViewBackgroundInRect_(proc3); @@ -2547,6 +2548,7 @@ void initClasses () { OS.class_addMethod(cls, OS.sel_readSelectionFromPasteboard_, proc3, "@:@"); OS.class_addMethod(cls, OS.sel_writeSelectionToPasteboard_types_, proc4, "@:@@"); OS.class_addMethod(cls, OS.sel_viewWillMoveToWindow_, proc3, "@:@"); + OS.class_addMethod(cls, OS.sel_cacheDisplayInRect_toBitmapImageRep_, cacheDisplayInRect_toBitmapImageRepProc, "@:{NSRect}@"); addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc); addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc); addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc); @@ -2727,6 +2729,7 @@ void initClasses () { OS.class_addMethod(cls, OS.sel_pageUp_, proc3, "@:@"); OS.class_addMethod(cls, OS.sel_reflectScrolledClipView_, proc3, "@:@"); OS.class_addMethod(cls, OS.sel_scrollClipView_toPoint_, scrollClipView_ToPointProc, "@:@{NSPoint}"); + OS.class_addMethod(cls, OS.sel_cacheDisplayInRect_toBitmapImageRep_, cacheDisplayInRect_toBitmapImageRepProc, "@:{NSRect}@"); addEventMethods(cls, proc2, proc3, drawRectProc, hitTestProc, setNeedsDisplayInRectProc); addFrameMethods(cls, setFrameOriginProc, setFrameSizeProc); addAccessibilityMethods(cls, proc2, proc3, proc4, accessibilityHitTestProc); @@ -6046,6 +6049,10 @@ static long /*int*/ windowProc(long /*int*/ id, long /*int*/ sel, long /*int*/ a widget.menu_willHighlightItem(id, sel, arg0, arg1); } else if (sel == OS.sel_setMarkedText_selectedRange_) { widget.setMarkedText_selectedRange (id, sel, arg0, arg1); + } else if (sel == OS.sel_cacheDisplayInRect_toBitmapImageRep_) { + NSRect rect = new NSRect (); + OS.memmove (rect, arg0, NSRect.sizeof); + widget.cacheDisplayInRect_toBitmapImageRep(id, sel, rect, arg1); } else if (sel == OS.sel_drawInteriorWithFrame_inView_) { NSRect rect = new NSRect (); OS.memmove (rect, arg0, NSRect.sizeof); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Widget.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Widget.java index 4f72e1ba22..8b54afb794 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Widget.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Widget.java @@ -214,6 +214,10 @@ long /*int*/ attributedSubstringFromRange (long /*int*/ id, long /*int*/ sel, lo return 0; } +void cacheDisplayInRect_toBitmapImageRep (long id, long sel, NSRect rect, long imageRep) { + callSuper(id, sel, rect, imageRep); +} + void callSuper(long /*int*/ id, long /*int*/ sel) { objc_super super_struct = new objc_super(); super_struct.receiver = id; -- cgit v1.2.3