diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorComponentImpl.java index 175fc949f013..cc78f05bc2e6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorComponentImpl.java @@ -81,6 +81,8 @@ public final class EditorComponentImpl extends JTextComponent implements Scrolla private final EditorImpl editor; + private @Nullable Runnable myRepaintCallback; + public EditorComponentImpl(@NotNull EditorImpl editor) { this.editor = editor; enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.INPUT_METHOD_EVENT_MASK); @@ -136,6 +138,10 @@ public final class EditorComponentImpl extends JTextComponent implements Scrolla setupEditorSwingCaretUpdatesCourierIfRequired(); } + void setRepaintCallback(@Nullable Runnable repaintCallback) { + myRepaintCallback = repaintCallback; + } + @Override public void uiSettingsChanged(@NotNull UISettings uiSettings) { UISettingsUtils settingsUtils = UISettingsUtils.with(uiSettings); @@ -282,6 +288,9 @@ public final class EditorComponentImpl extends JTextComponent implements Scrolla int topOverhang = Math.max(0, editor.myView.getTopOverhang()); int bottomOverhang = Math.max(0, editor.myView.getBottomOverhang()); repaint(x, y - topOverhang, width, height + topOverhang + bottomOverhang); + if (myRepaintCallback != null && isShowing() && width > 0 && height > 0) { + myRepaintCallback.run(); + } } //--implementation of Scrollable interface-------------------------------------- diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index a96800e70606..bff433841a8a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -2038,6 +2038,40 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi LOG.assertTrue(success || isReleased); } + /** + * Sets a callback invoked after every repaint request. + *
+ * The callback is only invoked if the component is showing and the request has a non-empty rectangle. + * In other words, it's invoked when the repaint request is likely to be followed by an actual painting operation. + *
+ *+ * The callback must be fast, non-intrusive, and should not throw any exceptions. + *
+ *+ * This is an internal hack, which is why it doesn't follow the usual add-listener pattern. + *
+ * @param callback the callback, {@code null} removes the callback + */ + @ApiStatus.Internal + public void setRepaintCallback(@Nullable Runnable callback) { + myEditorComponent.setRepaintCallback(callback); + } + + /** + * Sets a callback invoked after every paint operation. + *+ * The callback must be fast, non-intrusive, and should not throw any exceptions. + *
+ *+ * This is an internal hack, which is why it doesn't follow the usual add-listener pattern. + *
+ * @param callback the callback, {@code null} removes the callback + */ + @ApiStatus.Internal + public void setPaintCallback(@Nullable Runnable callback) { + myView.setPaintCallback(callback); + } + @Override public boolean isStickySelection() { return myState.isStickySelection(); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorView.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorView.java index 86002d509273..c74e0dc10f0d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorView.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorView.java @@ -24,6 +24,7 @@ import com.intellij.util.concurrency.annotations.RequiresEdt; import org.intellij.lang.annotations.JdkConstants; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; import java.awt.*; @@ -75,6 +76,8 @@ public final class EditorView implements TextDrawingCallback, Disposable, Dumpab private final Object myLock = new Object(); + private @Nullable Runnable myPaintCallback; + public EditorView(@NotNull EditorImpl editor) { this(editor, editor.getEditorModel()); } @@ -99,6 +102,14 @@ public final class EditorView implements TextDrawingCallback, Disposable, Dumpab Disposer.register(this, mySizeManager); } + /** + * @see EditorImpl#setPaintCallback(Runnable) + */ + @ApiStatus.Internal + public void setPaintCallback(@Nullable Runnable paintCallback) { + myPaintCallback = paintCallback; + } + @RequiresEdt public int yToVisualLine(int y) { assertNotInBulkMode(); @@ -211,6 +222,9 @@ public final class EditorView implements TextDrawingCallback, Disposable, Dumpab getSoftWrapModel().prepareToMapping(); checkFontRenderContext(g.getFontRenderContext()); myPainter.paint(g); + if (myPaintCallback != null) { + myPaintCallback.run(); + } } @RequiresEdt