Bug 1683204 - Include content theme configuration details in FullLookAndFeel. r=spohl

And re-enable the RemoteLookAndFeel by default with Gtk.

When the RemoteLookAndFeel is enabled and the non-native theme is not
enabled, we still need to configure the Gtk theme in content processes,
since we're still using Gtk to paint widget backgrounds etc. Without
this, we can end up using LookAndFeel colors from a light theme but
painting widget backgrounds from a dark theme.

Other platforms don't configure themes for content processes
differently, so on those platforms LookAndFeelTheme is an empty struct
and we skip the ConfigureTheme call.

Differential Revision: https://phabricator.services.mozilla.com/D100223
This commit is contained in:
Cameron McCormack 2020-12-22 19:26:41 +00:00
parent 4932b4f870
commit eefbb537b9
9 changed files with 100 additions and 43 deletions

View File

@ -10424,7 +10424,7 @@
- name: widget.remote-look-and-feel
type: bool
#ifdef MOZ_WIDGET_GTK
value: false
value: true
#else
value: false
#endif

View File

@ -36,8 +36,6 @@ struct LookAndFeelCache {
};
/**
* Stores the entirety of a LookAndFeel's data.
*
* The format allows for some compression compared with having fixed
* length arrays for each value type and some indication of whether
* a value is present. This is because not all values are present on
@ -55,7 +53,7 @@ struct LookAndFeelCache {
* LookAndFeel::FontID value minus 1, as 1 is the minimum value of that
* enum.)
*/
struct FullLookAndFeel {
struct LookAndFeelTables {
int32_t[] ints;
float[] floats;
nscolor[] colors;
@ -70,6 +68,23 @@ struct FullLookAndFeel {
bool passwordEcho;
};
struct LookAndFeelTheme {
#ifdef MOZ_WIDGET_GTK
nsCString themeName;
bool preferDarkTheme;
#endif
};
/**
* Stores the entirety of a LookAndFeel's data.
*/
struct FullLookAndFeel {
LookAndFeelTables tables;
#ifdef MOZ_WIDGET_GTK
LookAndFeelTheme theme;
#endif
};
union LookAndFeelData {
LookAndFeelCache;
FullLookAndFeel;

View File

@ -12,6 +12,8 @@
#include "mozilla/Assertions.h"
#include "mozilla/Result.h"
#include "mozilla/ResultExtensions.h"
#include "mozilla/StaticPrefs_widget.h"
#include "nsLookAndFeel.h"
#include "nsXULAppAPI.h"
#include <limits>
@ -20,19 +22,35 @@
namespace mozilla::widget {
RemoteLookAndFeel::RemoteLookAndFeel(FullLookAndFeel&& aTables)
: mTables(std::move(aTables)) {
RemoteLookAndFeel::RemoteLookAndFeel(FullLookAndFeel&& aData)
: mTables(std::move(aData.tables())) {
MOZ_ASSERT(XRE_IsContentProcess(),
"Only content processes should be using a RemoteLookAndFeel");
#ifdef MOZ_WIDGET_GTK
if (!StaticPrefs::widget_disable_native_theme_for_content()) {
// Configure the theme in this content process with the Gtk theme that was
// chosen by WithThemeConfiguredForContent in the parent process.
nsLookAndFeel::ConfigureTheme(aData.theme());
}
#endif
}
RemoteLookAndFeel::~RemoteLookAndFeel() = default;
void RemoteLookAndFeel::SetDataImpl(FullLookAndFeel&& aTables) {
void RemoteLookAndFeel::SetDataImpl(FullLookAndFeel&& aData) {
MOZ_ASSERT(XRE_IsContentProcess(),
"Only content processes should be using a RemoteLookAndFeel");
MOZ_ASSERT(NS_IsMainThread());
mTables = std::move(aTables);
mTables = std::move(aData.tables());
#ifdef MOZ_WIDGET_GTK
if (!StaticPrefs::widget_disable_native_theme_for_content()) {
// Configure the theme in this content process with the Gtk theme that was
// chosen by WithThemeConfiguredForContent in the parent process.
nsLookAndFeel::ConfigureTheme(aData.theme());
}
#endif
}
namespace {
@ -130,14 +148,14 @@ const FullLookAndFeel* RemoteLookAndFeel::ExtractData() {
MOZ_ASSERT(XRE_IsParentProcess(),
"Only parent processes should be extracting LookAndFeel data");
if (sCachedTables) {
return sCachedTables;
if (sCachedLookAndFeelData) {
return sCachedLookAndFeelData;
}
static bool sInitialized = false;
if (!sInitialized) {
sInitialized = true;
ClearOnShutdown(&sCachedTables);
ClearOnShutdown(&sCachedLookAndFeelData);
}
FullLookAndFeel* lf = new FullLookAndFeel{};
@ -148,7 +166,7 @@ const FullLookAndFeel* RemoteLookAndFeel::ExtractData() {
impl->NativeGetInt(IntID::SystemUsesDarkTheme, darkTheme);
impl->NativeGetInt(IntID::UseAccessibilityTheme, accessibilityTheme);
impl->WithThemeConfiguredForContent([&]() {
impl->WithThemeConfiguredForContent([&](const LookAndFeelTheme& aTheme) {
for (auto id : MakeEnumeratedRange(IntID::End)) {
int32_t theInt;
nsresult rv;
@ -172,21 +190,21 @@ const FullLookAndFeel* RemoteLookAndFeel::ExtractData() {
rv = impl->NativeGetInt(id, theInt);
break;
}
AddToMap(&lf->ints(), &lf->intMap(),
AddToMap(&lf->tables().ints(), &lf->tables().intMap(),
NS_SUCCEEDED(rv) ? Some(theInt) : Nothing{});
}
for (auto id : MakeEnumeratedRange(FloatID::End)) {
float theFloat;
nsresult rv = impl->NativeGetFloat(id, theFloat);
AddToMap(&lf->floats(), &lf->floatMap(),
AddToMap(&lf->tables().floats(), &lf->tables().floatMap(),
NS_SUCCEEDED(rv) ? Some(theFloat) : Nothing{});
}
for (auto id : MakeEnumeratedRange(ColorID::End)) {
nscolor theColor;
nsresult rv = impl->NativeGetColor(id, theColor);
AddToMap(&lf->colors(), &lf->colorMap(),
AddToMap(&lf->tables().colors(), &lf->tables().colorMap(),
NS_SUCCEEDED(rv) ? Some(theColor) : Nothing{});
}
@ -219,25 +237,29 @@ const FullLookAndFeel* RemoteLookAndFeel::ExtractData() {
#endif
maybeFont = Some(std::move(font));
}
AddToMap(&lf->fonts(), &lf->fontMap(), std::move(maybeFont));
AddToMap(&lf->tables().fonts(), &lf->tables().fontMap(),
std::move(maybeFont));
}
lf->passwordChar() = impl->GetPasswordCharacterImpl();
lf->passwordEcho() = impl->GetEchoPasswordImpl();
lf->tables().passwordChar() = impl->GetPasswordCharacterImpl();
lf->tables().passwordEcho() = impl->GetEchoPasswordImpl();
#ifdef MOZ_WIDGET_GTK
lf->theme() = aTheme;
#endif
});
// This assignment to sCachedTables must be done after the
// This assignment to sCachedLookAndFeelData must be done after the
// WithThemeConfiguredForContent call, since it can end up calling RefreshImpl
// on the LookAndFeel, which will clear out sCachedTables.
sCachedTables = lf;
return sCachedTables;
sCachedLookAndFeelData = lf;
return sCachedLookAndFeelData;
}
void RemoteLookAndFeel::ClearCachedData() {
MOZ_ASSERT(XRE_IsParentProcess());
sCachedTables = nullptr;
sCachedLookAndFeelData = nullptr;
}
StaticAutoPtr<FullLookAndFeel> RemoteLookAndFeel::sCachedTables;
StaticAutoPtr<FullLookAndFeel> RemoteLookAndFeel::sCachedLookAndFeelData;
} // namespace mozilla::widget

View File

@ -51,11 +51,11 @@ class RemoteLookAndFeel final : public nsXPLookAndFeel {
// implementation.
//
// This is called in the parent process when the default LookAndFeel is
// refreshed, to invalidate sCachedTables.
// refreshed, to invalidate sCachedLookAndFeelData.
static void ClearCachedData();
private:
FullLookAndFeel mTables;
LookAndFeelTables mTables;
// A cached copy of the data extracted by ExtractData.
//
@ -63,7 +63,7 @@ class RemoteLookAndFeel final : public nsXPLookAndFeel {
// time we create a new content process.
//
// Only used in the parent process.
static StaticAutoPtr<FullLookAndFeel> sCachedTables;
static StaticAutoPtr<FullLookAndFeel> sCachedLookAndFeelData;
};
} // namespace mozilla::widget

View File

@ -975,18 +975,32 @@ static nsCString GetGtkTheme() {
return ret;
}
static bool GetPreferDarkTheme() {
GtkSettings* settings = gtk_settings_get_default();
gboolean preferDarkTheme = FALSE;
g_object_get(settings, "gtk-application-prefer-dark-theme", &preferDarkTheme,
nullptr);
return preferDarkTheme == TRUE;
}
void nsLookAndFeel::ConfigureTheme(const LookAndFeelTheme& aTheme) {
MOZ_ASSERT(XRE_IsContentProcess());
GtkSettings* settings = gtk_settings_get_default();
g_object_set(settings, "gtk-theme-name", aTheme.themeName().get(),
"gtk-application-prefer-dark-theme",
aTheme.preferDarkTheme() ? TRUE : FALSE, nullptr);
}
void nsLookAndFeel::WithThemeConfiguredForContent(
const std::function<void()>& aFn) {
const std::function<void(const LookAndFeelTheme& aTheme)>& aFn) {
nsWindow::WithSettingsChangesIgnored([&]() {
// Available on Gtk 3.20+.
static auto sGtkSettingsResetProperty =
(void (*)(GtkSettings*, const gchar*))dlsym(
RTLD_DEFAULT, "gtk_settings_reset_property");
GtkSettings* settings = gtk_settings_get_default();
nsCString themeName;
gboolean preferDarkTheme = FALSE;
bool preferDarkTheme = false;
if (!sGtkSettingsResetProperty) {
// When gtk_settings_reset_property is not available, we instead
@ -996,8 +1010,7 @@ void nsLookAndFeel::WithThemeConfiguredForContent(
// could listen to xsettings changes and update the GtkSettings object
// ourselves in response, if we wanted to fix this.)
themeName = GetGtkTheme();
g_object_get(settings, "gtk-application-prefer-dark-theme",
&preferDarkTheme, nullptr);
preferDarkTheme = GetPreferDarkTheme();
}
bool changed = ConfigureContentGtkTheme();
@ -1005,17 +1018,22 @@ void nsLookAndFeel::WithThemeConfiguredForContent(
RefreshImpl();
}
aFn();
LookAndFeelTheme theme;
theme.themeName() = GetGtkTheme();
theme.preferDarkTheme() = GetPreferDarkTheme();
aFn(theme);
if (changed) {
GtkSettings* settings = gtk_settings_get_default();
if (sGtkSettingsResetProperty) {
sGtkSettingsResetProperty(settings, "gtk-theme-name");
sGtkSettingsResetProperty(settings,
"gtk-application-prefer-dark-theme");
} else {
g_object_set(settings, "gtk-theme-name", themeName.get(),
"gtk-application-prefer-dark-theme", preferDarkTheme,
nullptr);
"gtk-application-prefer-dark-theme",
preferDarkTheme ? TRUE : FALSE, nullptr);
}
RefreshImpl();
}
@ -1047,10 +1065,7 @@ bool nsLookAndFeel::ConfigureContentGtkTheme() {
}
// Try to select the light variant of the current theme first...
gboolean preferDarkTheme;
g_object_get(settings, "gtk-application-prefer-dark-theme", &preferDarkTheme,
nullptr);
if (preferDarkTheme) {
if (GetPreferDarkTheme()) {
LOG((" disabling gtk-application-prefer-dark-theme\n"));
g_object_set(settings, "gtk-application-prefer-dark-theme", FALSE, nullptr);
changed = true;

View File

@ -35,7 +35,9 @@ class nsLookAndFeel final : public nsXPLookAndFeel {
LookAndFeelCache GetCacheImpl() override;
void SetCacheImpl(const LookAndFeelCache& aCache) override;
void WithThemeConfiguredForContent(const std::function<void()>& aFn) override;
void WithThemeConfiguredForContent(
const std::function<void(const LookAndFeelTheme& aTheme)>& aFn) override;
static void ConfigureTheme(const LookAndFeelTheme& aTheme);
bool IsCSDAvailable() const { return mCSDAvailable; }

View File

@ -346,7 +346,7 @@ else:
"headless/HeadlessWidgetTypes.ipdlh",
]
IPDL_SOURCES += [
PREPROCESSED_IPDL_SOURCES += [
"LookAndFeelTypes.ipdlh",
]

View File

@ -22,6 +22,7 @@
#include "mozilla/StaticPrefs_editor.h"
#include "mozilla/StaticPrefs_findbar.h"
#include "mozilla/StaticPrefs_ui.h"
#include "mozilla/StaticPrefs_widget.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/widget/WidgetMessageUtils.h"
#include "mozilla/Telemetry.h"

View File

@ -84,6 +84,7 @@ class nsXPLookAndFeel : public mozilla::LookAndFeel {
using LookAndFeelInt = mozilla::widget::LookAndFeelInt;
using LookAndFeelFont = mozilla::widget::LookAndFeelFont;
using LookAndFeelColor = mozilla::widget::LookAndFeelColor;
using LookAndFeelTheme = mozilla::widget::LookAndFeelTheme;
virtual LookAndFeelCache GetCacheImpl();
virtual void SetCacheImpl(const LookAndFeelCache& aCache) {}
@ -91,8 +92,9 @@ class nsXPLookAndFeel : public mozilla::LookAndFeel {
virtual void NativeInit() = 0;
virtual void WithThemeConfiguredForContent(const std::function<void()>& aFn) {
aFn();
virtual void WithThemeConfiguredForContent(
const std::function<void(const LookAndFeelTheme& aTheme)>& aFn) {
aFn(LookAndFeelTheme{});
}
protected: