diff --git a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java index 833f28f69d3e..91ec8db6e103 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java @@ -218,7 +218,7 @@ public class JBScrollPane extends JScrollPane { * It is needed to repaint translucent scroll bars on viewport repainting. */ private static boolean isOptimizedDrawingEnabledFor(JScrollBar bar) { - return bar == null || bar.isOpaque() || !bar.isVisible(); + return bar == null || !bar.isVisible() || (bar.isOpaque() && bar.isOptimizedDrawingEnabled()); } private void updateViewportBorder() { 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 7aa5ac862b1b..0f619c7929be 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 @@ -320,6 +320,8 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi private volatile int myExpectedCaretOffset = -1; + private boolean myBackgroundImageSet; + EditorImpl(@NotNull Document document, boolean viewer, @Nullable Project project) { assertIsDispatchThread(); myProject = project; @@ -505,15 +507,9 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi myEditorComponent = new EditorComponentImpl(this); myScrollPane.putClientProperty(JBScrollPane.BRIGHTNESS_FROM_VIEW, true); myVerticalScrollBar = (MyScrollBar)myScrollPane.getVerticalScrollBar(); - // JBScrollPane.Layout relies on "opaque" property directly (instead of "editor.transparent.scrollbar") - myVerticalScrollBar.setOpaque(shouldScrollBarBeOpaque(project)); + myVerticalScrollBar.setOpaque(false); myPanel = new JPanel(); - // JBScrollPane.Layout relies on "opaque" property directly (instead of "editor.transparent.scrollbar") - if (myVerticalScrollBar.isOpaque()) { - //Do not set opaque to false if a scroll bar is opaque (System Preferences / Show scroll bars / Always) - myScrollPane.getHorizontalScrollBar().setOpaque(true); - } UIUtil.putClientProperty( myPanel, UIUtil.NOT_IN_HIERARCHY_COMPONENTS, (Iterable)() -> { JComponent component = getPermanentHeaderComponent(); @@ -555,9 +551,25 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } - static boolean shouldScrollBarBeOpaque(Project project) { - if (IdeBackgroundUtil.isBackgroundImageSet(project)) return false; - return JBScrollPane.isPreciseRotationSupported() || SystemProperties.isTrueSmoothScrollingEnabled(); + /** + * This method is intended to control a blit-accelerated scrolling, because transparent scrollbars suppress it. + * Blit-acceleration copies as much of the rendered area as possible and then repaints only newly exposed region. + * It is possible to disable blit-acceleration using by the registry key {@code editor.transparent.scrollbar=true}. + * Also, when there's a background image, blit-acceleration cannot be used (because of the static overlay). + * In such cases this method returns {@code false} to use transparent scrollbars as designed. + * Enabled blit-acceleration improves scrolling performance and reduces CPU usage + * (especially if drawing is compute-intensive). + *

+ * To have both the hardware acceleration and the background image + * we need to completely redesign JViewport machinery to support independent layers, + * which is (probably) possible, but it's a rather cumbersome task. + * Smooth scrolling still works event without the blit-acceleration, + * but with suboptimal performance and CPU usage. + * + * @return {@code true} if a scrollbar should be opaque, {@code false} otherwise + */ + boolean shouldScrollBarBeOpaque() { + return !myBackgroundImageSet && !Registry.is("editor.transparent.scrollbar"); } public boolean shouldSoftWrapsBeForced() { @@ -878,10 +890,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi myEditorComponent.setTransferHandler(new MyTransferHandler()); myEditorComponent.setAutoscrolls(true); - /* Default mode till 1.4.0 - * myScrollPane.getViewport().setScrollMode(JViewport.BLIT_SCROLL_MODE); - */ - if (mayShowToolbar()) { JLayeredPane layeredPane = new JBLayeredPane() { @Override @@ -907,16 +915,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi }; layeredPane.add(myScrollPane, JLayeredPane.DEFAULT_LAYER); - // When there's a background image, suppress hardware-accelerated scrolling as blitting cannot be used with the static overlay. - // For the simplicity, editor re-opening is required for the toggle to take effect. - // To have both the hardware acceleration and the background image we need to completely redesign JViewport machinery to support - // independent layers, which is (probably) possible, but it's a rather cumbersome task. - // Smooth scrolling still works event without the blit-acceleration, but with suboptimal performance and CPU usage. - if (SystemProperties.isTrueSmoothScrollingEnabled() && IdeBackgroundUtil.isBackgroundImageSet(myProject)) { - JComponent component = new JComponent() {}; // transparent - component.setPreferredSize(new Dimension(1, 1)); - layeredPane.add(component, JLayeredPane.POPUP_LAYER); - } myPanel.add(layeredPane); new ContextMenuImpl(layeredPane, myScrollPane, this); @@ -1665,6 +1663,13 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi if (myProject != null && myProject.isDisposed()) return; myView.paint(g); + + boolean isBackgroundImageSet = IdeBackgroundUtil.isEditorBackgroundImageSet(myProject); + if (myBackgroundImageSet != isBackgroundImageSet) { + myBackgroundImageSet = isBackgroundImageSet; + updateOpaque(myScrollPane.getHorizontalScrollBar()); + updateOpaque(myScrollPane.getVerticalScrollBar()); + } } Color getDisposedBackground() { @@ -2746,10 +2751,39 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } } + private static void updateOpaque(JScrollBar bar) { + if (bar instanceof OpaqueAwareScrollBar) { + bar.setOpaque(((OpaqueAwareScrollBar)bar).myOpaque); + } + } + + private class OpaqueAwareScrollBar extends JBScrollBar { + private boolean myOpaque; + + private OpaqueAwareScrollBar(@JdkConstants.AdjustableOrientation int orientation) { + super(orientation); + addPropertyChangeListener("opaque", event -> { + revalidate(); + repaint(); + }); + } + + @Override + public void setOpaque(boolean opaque) { + myOpaque = opaque; + super.setOpaque(opaque || shouldScrollBarBeOpaque()); + } + + @Override + public boolean isOptimizedDrawingEnabled() { + return !myBackgroundImageSet; + } + } + private static final Field decrButtonField = ReflectionUtil.getDeclaredField(BasicScrollBarUI.class, "decrButton"); private static final Field incrButtonField = ReflectionUtil.getDeclaredField(BasicScrollBarUI.class, "incrButton"); - class MyScrollBar extends JBScrollBar { + class MyScrollBar extends OpaqueAwareScrollBar { @NonNls private static final String APPLE_LAF_AQUA_SCROLL_BAR_UI_CLASS = "apple.laf.AquaScrollBarUI"; private ScrollBarUI myPersistentUI; @@ -2767,14 +2801,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi public void setUI(ScrollBarUI ui) { if (myPersistentUI == null) myPersistentUI = ui; super.setUI(myPersistentUI); - - /* Placing component(s) on top of JViewport suppresses blit-accelerated scrolling (for obvious reasons). - - Blit-acceleration copies as much of the rendered area as possible and then repaints only newly exposed region. - This helps to improve scrolling performance and to reduce CPU usage (especially if drawing is compute-intensive). - - When there's a background image, blit-acceleration cannot be used (because of the static overlay). */ - setOpaque(shouldScrollBarBeOpaque(myProject)); } /** @@ -4470,6 +4496,12 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi super.processMouseWheelEvent(e); } + @NotNull + @Override + public JScrollBar createHorizontalScrollBar() { + return new OpaqueAwareScrollBar(Adjustable.HORIZONTAL); + } + @NotNull @Override public JScrollBar createVerticalScrollBar() { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java index 4ae29f58e844..c08057911cf9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java @@ -479,16 +479,7 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark } private boolean transparent() { - /* Placing component(s) on top of JViewport suppresses blit-accelerated scrolling (for obvious reasons). - - Blit-acceleration copies as much of the rendered area as possible and then repaints only newly exposed region. - This helps to improve scrolling performance and to reduce CPU usage (especially if drawing is compute-intensive). - - When there's a background image, blit-acceleration cannot be used (because of the static overlay). */ - boolean opaque = EditorImpl.shouldScrollBarBeOpaque(myEditor.getProject()); - return !opaque && - Registry.is("editor.transparent.scrollbar", false) && - EditorUtil.isRealFileEditor(myEditor); + return !myEditor.shouldScrollBarBeOpaque() && EditorUtil.isRealFileEditor(myEditor); } private class MyErrorPanel extends ButtonlessScrollBarUI implements MouseMotionListener, MouseListener, MouseWheelListener, UISettingsListener { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeBackgroundUtil.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeBackgroundUtil.java index f705c93a72e5..db595d483445 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeBackgroundUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeBackgroundUtil.java @@ -179,9 +179,8 @@ public class IdeBackgroundUtil { return StringUtil.notNullize(spec, System.getProperty(propertyName, "")); } - public static boolean isBackgroundImageSet(@Nullable Project project) { - return StringUtil.isNotEmpty(getBackgroundSpec(project, EDITOR_PROP)) || - StringUtil.isNotEmpty(getBackgroundSpec(project, FRAME_PROP)); + public static boolean isEditorBackgroundImageSet(@Nullable Project project) { + return StringUtil.isNotEmpty(getBackgroundSpec(project, EDITOR_PROP)); } public static void repaintAllWindows() { diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 54ed819b13d8..49e282bd4887 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -749,7 +749,7 @@ editor.caret.width=2 editor.caret.width.description=Caret width editor.caret.width.restartRequired=true -editor.transparent.scrollbar=true +editor.transparent.scrollbar=false editor.transparent.scrollbar.description=Don't paint background for editor scroll bars editor.full.width.scrollbar=false