Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add background color to mainWindow to prevent white flashes while launching #274

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from

Conversation

pedr0luiz
Copy link

@pedr0luiz pedr0luiz commented Oct 22, 2021

Type: defect

Fix #817

notes: Add background color to mainWindow to prevent white flashes while launching. Got solution from official docs.

Signed-off-by: Pedro Costa pedroluiz51@gmail.com


Here's what your changelog entry will look like:

🐛 Bug Fixes

@pedr0luiz pedr0luiz requested a review from a team as a code owner October 22, 2021 15:51
src/electron-main.ts Outdated Show resolved Hide resolved
@@ -925,7 +925,7 @@ app.on('ready', async () => {
const preloadScript = path.normalize(`${__dirname}/preload.js`);
mainWindow = global.mainWindow = new BrowserWindow({
// https://www.electronjs.org/docs/faq#the-font-looks-blurry-what-is-this-and-what-can-i-do
backgroundColor: '#fff',
backgroundColor: nativeTheme.shouldUseDarkColors ? '#16191e' : '#fff',

Choose a reason for hiding this comment

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

Is it a good idea to hardcode the colors in the first place? Is there any way of importing them dynamically while still fixing the white flash?

Copy link
Author

Choose a reason for hiding this comment

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

I tried to not hardcode the colors, but i could't found the file with them. I've got these colors from the element-web repo theming.md file.

@@ -1015,7 +1015,9 @@ app.on('window-all-closed', () => {
});

app.on('activate', () => {
mainWindow.show();
mainWindow.once('ready-to-show', () => {

Choose a reason for hiding this comment

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

I mean, the background color might also be a moot point if you’re using the ready-to-show event…

Copy link
Author

Choose a reason for hiding this comment

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

I understand, but this line seems to do nothing.

@SimonBrandner
Copy link
Contributor

I would suggest making an IPC call from the react-sdk with the background colour every time the user changes their theme, this way we're not hardcoding the colour. Then I would listen for this on the Electron side and write the colour to electron store so that we can get it at load time.

We do something similar for spell checking, see #179

Copy link
Contributor

@germain-gg germain-gg left a comment

Choose a reason for hiding this comment

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

Agreed with everything that was mentioned here,
We can not afford to hardcode the colours in element-web as different users might use different themes

It would also be very useful to have a before/after screen recording for reference in the PR description

@elsiehupp
Copy link

It would also be very useful to have a before/after screen recording for reference in the PR description

I posted a short unlisted video of the “before” behavior on YouTube and linked it in the initial Issue.

I don’t have a build setup for Element, though, so I can’t compare any “after” at the moment.

@elsiehupp
Copy link

The colors for iOS are set in these three files:

The colors for Android are set in these two files:

On the web, colors are set by these files:

  • theme-light.css (on desktop as vector://vector/webapp/bundles/<hex_code>/theme-light.css)
  • theme-dark.css (on desktop as vector://vector/webapp/bundles/<hex_code>/theme-dark.css)

However, neither of these files appears anywhere in the Element GitHub organization . Only similar file I could find was src/skins/vector/css/common.css, but that file (along with the entire src/skins directory) abruptly disappears in April 2016.

It turns out that all of the theming code got moved to matrix-react-sdk around that time. This search was hugely complicated by the fact that you accidentally used #16191e instead of #15191e, so searching for it as a string didn't return anything anywhere. I found the latter color from inspecting the element myself after the former didn't appear in theme-dark.css. #15191e appears in matrix-react-sdk/res/themes/dark/css/_dark.scss and is referenced as $background elsewhere in the SCSS. In _common.scss, $background is referenced under body { background-color: : $background; }.

Best practices discourage referencing the CSS directly, though element-web/webpack.config.js does so with the following code:

const cssThemes = {
    // CSS themes
    "theme-legacy-light": "./node_modules/matrix-react-sdk/res/themes/legacy-light/css/legacy-light.scss",
    "theme-legacy-dark": "./node_modules/matrix-react-sdk/res/themes/legacy-dark/css/legacy-dark.scss",
    "theme-light": "./node_modules/matrix-react-sdk/res/themes/light/css/light.scss",
    "theme-light-high-contrast":
        "./node_modules/matrix-react-sdk/res/themes/light-high-contrast/css/light-high-contrast.scss",
    "theme-dark": "./node_modules/matrix-react-sdk/res/themes/dark/css/dark.scss",
    "theme-light-custom": "./node_modules/matrix-react-sdk/res/themes/light-custom/css/light-custom.scss",
    "theme-dark-custom": "./node_modules/matrix-react-sdk/res/themes/dark-custom/css/dark-custom.scss",
};

If you want to import the color value "correctly", you can probably do so with the function bodyToHtml in matrix-react-sdk/src/HtmlUtils.tsx. React is very much not my jam, but you can probably start with something like this:

import bodyToHtml from '@matrix-react-sdk/src/HtmlUtils';

...

const html = bodyToHtml(content, null);

backgroundColor = html.attribs['background-color'];

The main issue here is that I don't know what you would use for the parameter content at this point in the application loading, never mind that the required type, IContent, doesn't appear anywhere in the Element GitHub organization (though its descendent interfaces probably do). You can find more information on "skinning" at matrix-react-sdk/docs/skinning.md.

If you can't use bodyToHtml(), and the 'ready-to-show' Electron event doesn't seem to be working, you could element-web/webpack.config.js does and reference the CSS directly, but this would itself still be kind of a hack, since doing so would not allow the value of backgroundColor to derive from any custom skins. That said, you might find some useful guidance via element-hq/element-web#18741 or element-web/docs/theming.md.

@elsiehupp
Copy link

Another approach you could take if bodyToHtml() is unworkable is you could add an action to setTheme() in matrix-react-sdk/src/theme.ts that saves the background color to the settings (independent of the theme name, etc.). This way you would be able to call the cached background color before the CSS is loaded.

The main complication is that you would need to make this change over at matrix-react-sdk before you would be able to make the corresponding change here, so if you wanted to try this approach, you or I should probably open an issue over at element-web explaining the problem here in element-desktop (since matrix-react-sdk uses the element-web issue tracker).

@elsiehupp
Copy link

Actually, I just realized that despite this pull request being on element-desktop, my original issue was on element-web, so there’s no need to open another issue for matrix-react-sdk.

@pedr0luiz
Copy link
Author

Another approach you could take if bodyToHtml() is unworkable is you could add an action to setTheme() in matrix-react-sdk/src/theme.ts that saves the background color to the settings (independent of the theme name, etc.). This way you would be able to call the cached background color before the CSS is loaded.

The main complication is that you would need to make this change over at matrix-react-sdk before you would be able to make the corresponding change here, so if you wanted to try this approach, you or I should probably open an issue over at element-web explaining the problem here in element-desktop (since matrix-react-sdk uses the element-web issue tracker).

I'm facing some problems when calling the matrix-react-sdk from element-desktop. Do I need to install the package with yarn? Because I did that and there's a lot of typing errors.

@elsiehupp
Copy link

I'm facing some problems when calling the matrix-react-sdk from element-desktop. Do I need to install the package with yarn? Because I did that and there's a lot of typing errors.

I haven’t attempted anything myself, but I did a quick cross-repository search for matrix-react-sdk in the Element organization, and looking at Typescript, TSX, and JavaScript, the bulk of the results are in element-web, and none of them are in element-desktop. Similarly, there are far more relevant results for “settings” in matrix-react-sdk than in the Element organization.

Basically it seems like element-desktop is all things considered an extremely dumb wrapper around element-web, and in order to access anything in element-desktop, element-web needs to make explicitly available.

I’ve been digging into this on my own, and I will hopefully be able to get back to you with something soon.

@elsiehupp
Copy link

I just linked back from what I’ve been working on, but it’s kind of only tangentially related at this point. Two potential routes for making the background color available to Electron could be element-desktop/webcontents-handler.ts and element-web/ElectronPlatform.tsx. In either case you could find a way to write the background color to a JSON file on disk, or something like that. Another possibility is folding some of the functionality into electron-window-state, which element-desktop already uses and which already saves a JSON file to disk with other attributes of the window state.

@elsiehupp
Copy link

elsiehupp commented Nov 11, 2021

If you wanted to copy the basic functionality of electron-window-state, you could do the following. (The ... represent omitted code, not literal JavaScript ....)

First, create the functions for saving and loading the window background color to and from a JSON file on disk:

const path = require('path');
const jsonfile = require('jsonfile');
const mkdirp = require('mkdirp');
const backgroundColorStoreFilename = path.join(app.getPath('userData'), 'background-color.json');

...

function saveBackgroundColor(win) {
    state = {'backgroundColor':win.getBackgroundColor()}
    try {
        mkdirp.sync(path.dirname(backgroundColorStoreFilename));
        jsonfile.writeFileSync(backgroundColorStoreFilename, state);
    } catch (err) {
        // Do nothing
    }
}

function loadBackgroundColor() {}
    try {
        return jsonfile.readFileSync(backgroundColorStoreFilename)['backgroundColor']
    } catch (err) {
        return backgroundColorPreload = nativeTheme.shouldUseDarkColors ? '#15191e' : '#fff'
    }
}

Next, add a call to saveBackgroundColor() inside mainWindow.on('close'):

mainWindow.on('close', async (e) => {
    saveBackgroundColor(mainWindow)
    ...
});

(We use the window-close event rather than the app-quit event in case the user quits the application while no windows are open.)

Then, finally, add a call to loadBackgroundColor() in the parameters for the BrowserWindow() constructor:

mainWindow = global.mainWindow = new BrowserWindow({
    backgroundColor: loadBackgroundColor(),
    ...
})

I haven't tested this, but barring any typos it should probably work?

The main deficiency with this approach is that it doesn’t account for the possibility of the system switching between light and dark while the application is closed (assuming the user has the appearance set to match the system theme). Accounting for this scenario would require matrix-react-sdk to emit custom signals for the dark-background color, the light-background color, and whether to match the system, which I could add in the course of my pull request over there.

@ttheshreeyasingh
Copy link

ttheshreeyasingh commented Apr 21, 2022

you could add an action to setTheme() in matrix-react-sdk/src/theme.ts that saves the background color to the settings (independent of the theme name, etc.). This way you would be able to call the cached background color before the CSS is loaded.

Could you please elaborate more on this solution?

@elsiehupp
Copy link

you could add an action to setTheme() in matrix-react-sdk/src/theme.ts that saves the background color to the settings (independent of the theme name, etc.). This way you would be able to call the cached background color before the CSS is loaded.

Could you please elaborate more on this solution?

I'm not sure, but I think at the time I was misunderstanding how Electron interacts with the React client. If I remember correctly matrix-react-sdk has basically zero ability to interact with Electron, and Electron has basically zero ability to interact with matrix-react-sdk aside from whatever the latter puts into the DOM. This is why the theme-change code has to manually read what the colors are rather than checking some cached setting somewhere. (This is all a bit fuzzy for me, though, since I haven't looked at any of it in such a long time.)

@elsiehupp
Copy link

Basically if I remember correctly I couldn't find a way for React to cache the background color in such a way that Electron would have access to it, which is why I suggested piggy-backing on electron-window-state, which uses its own external file to cache and restore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Window Briefly Flashes White While Launching
6 participants