Skip to content

Conversation

@mofux
Copy link
Contributor

@mofux mofux commented Nov 9, 2017

Fixes #946
Fixes #1081

This PR moves the canvas layers into their own div element, .xterm-screen. This allows us to apply a css padding to the .xterm element and to have the scrollbar still fill the whole height of the .xterm element.

The fit() addon has also been updated to support this new feature.

fit

@mofux mofux requested a review from Tyriar November 9, 2017 23:42
Copy link
Member

@Tyriar Tyriar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a scroll bar anymore on macOS Sierra, even during scrolling?


if (this.lastRecordedViewportHeight !== this.terminal.renderer.dimensions.canvasHeight) {
this.lastRecordedViewportHeight = this.terminal.renderer.dimensions.canvasHeight;
this.viewportElement.style.height = this.lastRecordedViewportHeight + 'px';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we not need to set this anymore?

Copy link
Contributor Author

@mofux mofux Nov 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well the new .xterm-screen element is positioned relative to the .xterm parent and has the same height as the canvas elements inside. Its width equals the width of the canvas + the width of the scrollbar on the viewport. If you add a padding to the .xterm element, that means that the .xterm element will grow by that padding. The viewport is positioned absolute to always match the size of the .xterm element. For that reason, we don't have to manually set the height of the viewport element any longer.

@mofux
Copy link
Contributor Author

mofux commented Nov 19, 2017

The scrollbar is still there, but OSX draws it black, so it is really hard to see:

screen shot 2017-11-19 at 02 00 24

OSX draws a light or dark scrollbar, depending on the background color of the scrolling container. Unfortunately we cannot set the background color on the scrolling container because that would hide the content (canvas) underneath it 😟 Setting a opacity on the scroll container also applies that opacity to the scrollbar, so that doesn't work. The only thing that is working is to set the terminal background color on the scroll container with a very low alpha value e.g. background-color: rgba(0,0,0,0.01) if the terminal background was rgb(0,0,0), but that would mean that we would have to calculate that very opaque color from the currently used background color of the theme, and it would also add a little performance impact to the rendering pipeline to draw the (likely invisible) semi-transparent background. Not sure how to go on with this really...

@mofux
Copy link
Contributor Author

mofux commented Nov 19, 2017

I have added a workaround for the overlay scrollbar being barely visible on OSX. It sets the background color of the viewport element by taking the background color from the theme (which by the current design must be a 7 digit hex value, e.g. #000000) and adding a very low alpha (01) to it (#00000001).

This background color on the viewport is not perceptible by the human eye, but it fools OSX into calculating the scrollbar thumb color based on that background color, ignoring the alpha. This solution adds another alpha pass to the browser's rendering pipeline which will slow it down a little bit.

Unfortunately I couldn't find any other workaround, so I made sure this workaround is only applied on OSX, and if an overlay scrollbar is used (which we can detect if the scrollbar width is 0).

@mofux
Copy link
Contributor Author

mofux commented Nov 19, 2017

The approach above doesn't work on all browsers (tested with the demo):

  • Chrome: Draws a white scrollbar thumb 👍
  • Firefox: Draws a black scrollbar thumb, works correctly if no background color is applied to the viewport element 👍/👎
  • Safari: Draws a black scrollbar thumb, only works when setting a background color alpha > 0.9 👎

Conclusion:
We can't get the overlay scrollbar to work reliably on all browsers.

Solutions:

  1. Account some extra space for the scrollbar if the scrollbar width is 0 (OSX overlay scrollbar). This will waste some space and make the terminal look weird if not currently being scrolled, but I think that is what we did before.
  2. Overwrite the scrollbar style with custom css. This will force OSX to always draw the scrollbar, but unfortunately we cannot re-use the system scrollbar style 😡
  3. Introduce the workarounds for Chrome and Firefox and fallback to 1. for the other browsers.
  4. Have somebody smarter than me figure out a css trick that works across all these browsers.

Workarounds I've tried:

  • Set opacity on the viewport element: Also applies that opacity to the scrollbar
  • Use the css clip property to clip away the background: Also clips away the scrollbar
  • Use background color with alpha: See above
  • Use transform: scaleX to scale down the width of the viewport element: Also applies that scale to the scrollbar
  • Make the viewport container only 1px wide but set overflow-x: visible on it: Only shows 1px of the scrollbar

@mofux
Copy link
Contributor Author

mofux commented Nov 20, 2017

I've fixed the code to support Firefox. At this stage, Chrome and Firefox both show the scrollbar thumb correctly - based on the terminal background color. I still can't get Safari to work correctly, but I'd argue that that's not a huge problem. The scrollbar is still visible on Safari, it's only dark no matter what background the terminal has...

@Tyriar
Copy link
Member

Tyriar commented Nov 22, 2017

I don't think the 01 alpha trick is ideal as that's extra a bunch of extra processing that needs to happen when compositing. I looked into a possible solution and got something that kind of works, the basic outline is:

  • Move the .xterm-screen element after .xterm-viewport so that it is drawn on top
  • If the OS is macOS and scroll bar width is 0, assume it's x pixels large
  • Make room for the scroll bar in .xterm-viewport, not .xterm-screen

The dark scroll bar still happens on Safari but that was there before.

Here's a very messy diff as a proof of concept:

diff --git a/src/Terminal.ts b/src/Terminal.ts
index c5a7575..a101473 100644
--- a/src/Terminal.ts
+++ b/src/Terminal.ts
@@ -589,10 +589,6 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
 
     this.element.setAttribute('tabindex', '0');
 
-    this.screenElement = document.createElement('div');
-    this.screenElement.classList.add('xterm-screen');
-    this.element.appendChild(this.screenElement);
-
     this.viewportElement = document.createElement('div');
     this.viewportElement.classList.add('xterm-viewport');
     this.element.appendChild(this.viewportElement);
@@ -600,6 +596,10 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
     this.viewportScrollArea.classList.add('xterm-scroll-area');
     this.viewportElement.appendChild(this.viewportScrollArea);
 
+    this.screenElement = document.createElement('div');
+    this.screenElement.classList.add('xterm-screen');
+    this.element.appendChild(this.screenElement);
+
     // preload audio
     this.syncBellSound();
 
diff --git a/src/Viewport.ts b/src/Viewport.ts
index 0581445..07fcbcb 100644
--- a/src/Viewport.ts
+++ b/src/Viewport.ts
@@ -33,7 +33,7 @@ export class Viewport implements IViewport {
     private scrollArea: HTMLElement,
     private charMeasure: CharMeasure
   ) {
-    this.scrollBarWidth = this.viewportElement.offsetWidth - this.scrollArea.offsetWidth;
+    this.scrollBarWidth = (this.viewportElement.offsetWidth - this.scrollArea.offsetWidth) || 10;
     this.viewportElement.addEventListener('scroll', this.onScroll.bind(this));
 
     // Perform this async to ensure the CharMeasure is ready.
@@ -47,9 +47,10 @@ export class Viewport implements IViewport {
     // calculates the scrollbar thumb color from the background color of the viewport element.
     // Since the viewport element has to be transparent in order to see the underlying canvas,
     // we use the terminal background color from the theme and add a very low alpha value to it.
-    if (isMac && isChrome && this.scrollBarWidth === 0 && colors.background.length === 7) {
-      this.viewportElement.style.backgroundColor = `${colors.background}01`;
-    }
+    // if (isMac && isChrome && this.scrollBarWidth === 0 && colors.background.length === 7) {
+
+    this.viewportElement.style.backgroundColor = colors.background;
+    // }
   }
 
   /**
@@ -57,6 +58,8 @@ export class Viewport implements IViewport {
    * necessary.
    */
   private refresh(): void {
+    console.log('scroll', this.scrollBarWidth);
+    this.viewportElement.style.width = `${this.terminal.renderer.dimensions.canvasWidth + this.scrollBarWidth}px`;
     if (this.charMeasure.height > 0) {
       this.currentRowHeight = this.terminal.renderer.dimensions.scaledCellHeight / window.devicePixelRatio;
       this.lastRecordedViewportHeight = this.viewportElement.offsetHeight;
diff --git a/src/renderer/Renderer.ts b/src/renderer/Renderer.ts
index b6a5c68..a7f6c0b 100644
--- a/src/renderer/Renderer.ts
+++ b/src/renderer/Renderer.ts
@@ -136,7 +136,7 @@ export class Renderer extends EventEmitter implements IRenderer {
     this._renderLayers.forEach(l => l.resize(this._terminal, this.dimensions, didCharSizeChange));
 
 		// Resize the screen
-    this._terminal.screenElement.style.width = `${this.dimensions.canvasWidth + this._terminal.viewport.scrollBarWidth}px`;
+    this._terminal.screenElement.style.width = `${this.dimensions.canvasWidth}px`;
     this._terminal.screenElement.style.height = `${this.dimensions.canvasHeight}px`;
 
     // Force a refresh

@mofux
Copy link
Contributor Author

mofux commented Nov 28, 2017

@Tyriar I'm tempted to not use a workaround for this at all. I agree that the hex value hack is bad and shouldn't go into production.

I think that having empty space beside the screen area is even worse than having a barely visible overlay scrollbar. Ultimately, this bug should be solved by Chrome and Safari - Firefox seems to do the best job here. Last but not least, implementors can always provide their own scrollbar style via css (like vscode does), which will work just fine. @parisk @Tyriar Any thoughts?

Copy link
Contributor

@parisk parisk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me it works great on Chrome and Firefox on High Sierra, but I get the barely visible scrollbar on Safari.

I think it's quite important to fix this, as it can lead Safari users to believe that they cannot scroll.

What we could do here is just detect safari and apply a custom scrollbar color on it. It won't look stellar, but it would do the work.

In general I am all in for this update after we fix this somehow. 👍

@Tyriar
Copy link
Member

Tyriar commented Dec 11, 2017

Let's defer this as we need to get v3 out, @mofux could you pull out the fix for #1081 into it's own PR? We should be able to merge something like that easily.

@mofux
Copy link
Contributor Author

mofux commented Dec 11, 2017

@Tyriar no problem. I'll get to it tomorrow, hope that's soon enough.

@Tyriar
Copy link
Member

Tyriar commented Dec 11, 2017

@mofux sounds good 👌

@mofux
Copy link
Contributor Author

mofux commented Dec 13, 2017

@Tyriar @parisk I have updated the PR to account additional 15px as the scrollbar width if the actual scrollbar width is 0 (as suggested by @Tyriar above). I think this is a good compromise for now (and it mirrors the current behaviour). Please review again, hope it's good to merge now. 🧐

@Tyriar
Copy link
Member

Tyriar commented Dec 14, 2017

Terminal.scrollToBottom doesn't seem to work properly when you have padding. On macOS, I scroll up to top then press a key (which triggers scrollToBottom) and the terminal scrolls to the second last line.

There is also a test failure on Linux (xterm output comparison t0500-bash_long_line.in https://travis-ci.org/xtermjs/xterm.js/jobs/315932024) and a compile problem :src\Viewport.ts(9,17): error TS2305: Module '"C:/Users/Daniel/Documents/dev/mofux/xterm.js/src/utils/Browser"' has no exported member 'isChrome'.

@Tyriar Tyriar added this to the 3.1.0 milestone Dec 18, 2017
@Tyriar
Copy link
Member

Tyriar commented Dec 18, 2017

Pulled the fit sizing fix into #1154

simark pushed a commit to eclipse-theia/theia that referenced this pull request Dec 21, 2017
The main reason for updating xterm.js is to get the fixes for the wrong
height and width computation.  Now, the output should not be too long or
to short for the available space, both vertically and horizontally.

Because of how things are computed now, it is not possible to apply a
padding on the terminal container as we currently do.  The padding will
work, but the canvas width won't be adjusted, so the output will go too
far on the right and at the bottom.  Once this PR

  xtermjs/xterm.js#1123

gets merged in xterm.js, we should be able to add back the padding.

The addon system has been reworked.  Before, just importing the addons
(fit and attach) would modify the Terminal prototype and add some
methods.  Now, we have to call the static method Terminal.applyAddon.

Also, because of the changes to the addon system, we don't need the
ignore-loader snippets in the webpack configuration anymore.

Signed-off-by: Simon Marchi <simon.marchi@ericsson.com>
simark pushed a commit to eclipse-theia/theia that referenced this pull request Dec 21, 2017
The main reason for updating xterm.js is to get the fixes for the wrong
height and width computation.  Now, the output should not be too long or
to short for the available space, both vertically and horizontally.

Because of how things are computed now, it is not possible to apply a
padding on the terminal container as we currently do.  The padding will
work, but the canvas width won't be adjusted, so the output will go too
far on the right and at the bottom.  Once this PR

  xtermjs/xterm.js#1123

gets merged in xterm.js, we should be able to add back the padding.

The addon system has been reworked.  Before, just importing the addons
(fit and attach) would modify the Terminal prototype and add some
methods.  Now, we have to call the static method Terminal.applyAddon.

Also, because of the changes to the addon system, we don't need the
ignore-loader snippets in the webpack configuration anymore.

Signed-off-by: Simon Marchi <simon.marchi@ericsson.com>
simark pushed a commit to eclipse-theia/theia that referenced this pull request Jan 4, 2018
The main reason for updating xterm.js is to get the fixes for the wrong
height and width computation.  Now, the output should not be too long or
to short for the available space, both vertically and horizontally.

Because of how things are computed now, it is not possible to apply a
padding on the terminal container as we currently do.  The padding will
work, but the canvas width won't be adjusted, so the output will go too
far on the right and at the bottom.  Once this PR

  xtermjs/xterm.js#1123

gets merged in xterm.js, we should be able to add back the padding.

The addon system has been reworked.  Before, just importing the addons
(fit and attach) would modify the Terminal prototype and add some
methods.  Now, we have to call the static method Terminal.applyAddon.

Also, because of the changes to the addon system, we don't need the
ignore-loader snippets in the webpack configuration anymore.

Signed-off-by: Simon Marchi <simon.marchi@ericsson.com>
akosyakov pushed a commit to eclipse-theia/theia that referenced this pull request Jan 5, 2018
The main reason for updating xterm.js is to get the fixes for the wrong
height and width computation.  Now, the output should not be too long or
to short for the available space, both vertically and horizontally.

Because of how things are computed now, it is not possible to apply a
padding on the terminal container as we currently do.  The padding will
work, but the canvas width won't be adjusted, so the output will go too
far on the right and at the bottom.  Once this PR

  xtermjs/xterm.js#1123

gets merged in xterm.js, we should be able to add back the padding.

The addon system has been reworked.  Before, just importing the addons
(fit and attach) would modify the Terminal prototype and add some
methods.  Now, we have to call the static method Terminal.applyAddon.

Also, because of the changes to the addon system, we don't need the
ignore-loader snippets in the webpack configuration anymore.

Signed-off-by: Simon Marchi <simon.marchi@ericsson.com>
Signed-off-by: Anton Kosiakov <anton.kosyakov@typefox.io>
@Tyriar Tyriar changed the base branch from v3 to master January 5, 2018 16:27
simark pushed a commit to eclipse-theia/theia that referenced this pull request Jan 5, 2018
The main reason for updating xterm.js is to get the fixes for the wrong
height and width computation.  Now, the output should not be too long or
to short for the available space, both vertically and horizontally.

Because of how things are computed now, it is not possible to apply a
padding on the terminal container as we currently do.  The padding will
work, but the canvas width won't be adjusted, so the output will go too
far on the right and at the bottom.  Once this PR

  xtermjs/xterm.js#1123

gets merged in xterm.js, we should be able to add back the padding.

The addon system has been reworked.  Before, just importing the addons
(fit and attach) would modify the Terminal prototype and add some
methods.  Now, we have to call the static method Terminal.applyAddon.

Also, because of the changes to the addon system, we don't need the
ignore-loader snippets in the webpack configuration anymore.

Signed-off-by: Simon Marchi <simon.marchi@ericsson.com>
simark pushed a commit to eclipse-theia/theia that referenced this pull request Jan 6, 2018
The main reason for updating xterm.js is to get the fixes for the wrong
height and width computation.  Now, the output should not be too long or
to short for the available space, both vertically and horizontally.

Because of how things are computed now, it is not possible to apply a
padding on the terminal container as we currently do.  The padding will
work, but the canvas width won't be adjusted, so the output will go too
far on the right and at the bottom.  Once this PR

  xtermjs/xterm.js#1123

gets merged in xterm.js, we should be able to add back the padding.

The addon system has been reworked.  Before, just importing the addons
(fit and attach) would modify the Terminal prototype and add some
methods.  Now, we have to call the static method Terminal.applyAddon.

Also, because of the changes to the addon system, we don't need the
ignore-loader snippets in the webpack configuration anymore.

Finally, I think we don't need @types/xterm anymore, since the xterm
package provides its own typings.

Signed-off-by: Simon Marchi <simon.marchi@ericsson.com>
simark pushed a commit to eclipse-theia/theia that referenced this pull request Jan 7, 2018
The main reason for updating xterm.js is to get the fixes for the wrong
height and width computation.  Now, the output should not be too long or
to short for the available space, both vertically and horizontally.

Because of how things are computed now, it is not possible to apply a
padding on the terminal container as we currently do.  The padding will
work, but the canvas width won't be adjusted, so the output will go too
far on the right and at the bottom.  Once this PR

  xtermjs/xterm.js#1123

gets merged in xterm.js, we should be able to add back the padding.

The addon system has been reworked.  Before, just importing the addons
(fit and attach) would modify the Terminal prototype and add some
methods.  Now, we have to call the static method Terminal.applyAddon.

Also, because of the changes to the addon system, we don't need the
ignore-loader snippets in the webpack configuration anymore.

Finally, I think we don't need @types/xterm anymore, since the xterm
package provides its own typings.

Signed-off-by: Simon Marchi <simon.marchi@ericsson.com>
@cancan101
Copy link

cancan101 commented Jan 12, 2018

Any updates on this PR? Also it seems like the black scroll bars are already an issue on master.

@mofux
Copy link
Contributor Author

mofux commented Jan 15, 2018

Closing this PR in favour of #1208

@mofux mofux closed this Jan 15, 2018
@Tyriar Tyriar removed this from the 3.1.0 milestone Feb 6, 2018
@mofux mofux deleted the fit branch September 15, 2023 08:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants