Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion .github/workflows/developer-guide-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,17 @@ jobs:
- name: Sync Vale styles
run: |
set -euo pipefail
vale sync --config docs/developer-guide/.vale.ini
# Package downloads can return transient GitHub release HTTP 5xx errors.
# Keep the lint gate strict if all three sync attempts fail.
for attempt in 1 2 3; do
if vale sync --config docs/developer-guide/.vale.ini; then
break
fi
if [ "$attempt" -eq 3 ]; then
exit 1
fi
sleep "$((attempt * 5))"
done

- name: Run Vale style linter
run: |
Expand Down
13 changes: 13 additions & 0 deletions CodenameOne/src/com/codename1/impl/CodenameOneImplementation.java
Original file line number Diff line number Diff line change
Expand Up @@ -13182,6 +13182,19 @@ public boolean isAccessibilityTreeUpdateRequired() {
return isAccessibilityTreeSupported();
}

/// Internal port hook. Return a fresh snapshot; unsupported ports keep bundled defaults.
public NativeThemeSettings getNativeThemeSettings() {
return new NativeThemeSettings();
}

/// Loads the selected OS family using the original native alias's weight/style.
/// A family of "native:" means the platform's existing native aliases.
public Object loadNativeThemeFont(String family, String template, float size, int style) {
String name = "native:".equals(family) ? template : family;
Object font = loadTrueTypeFont(name, null);
return font == null ? null : deriveTrueTypeFont(font, size, style);
}

/// Returns true if the user has selected larger type fonts in the system settings.
/// Default implementation returns false.
///
Expand Down
127 changes: 127 additions & 0 deletions CodenameOne/src/com/codename1/impl/NativeThemeSettings.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Codename One designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Codename One through http://www.codenameone.com/ if you
* need additional information or have any questions.
*/
package com.codename1.impl;

import java.util.HashMap;
import java.util.Map;
import com.codename1.util.StringUtil;

/// Internal port snapshot of OS theme defaults. Font size is in CN1 device pixels,
/// before accessibility scaling. Missing values mean unsupported, never a guessed value.
public final class NativeThemeSettings {
private final Map<String, String> colors = new HashMap<String, String>();
private String fontFamily;
private float fontSize;

public NativeThemeSettings color(String token, int rgb) {
colors.put(token, Integer.toHexString(0x1000000 | (rgb & 0xffffff)).substring(1));
return this;
}

/// Compares only the categories the application opted into.
public NativeThemeSettings forInheritance(boolean inheritColors, boolean inheritFonts) {
NativeThemeSettings result = new NativeThemeSettings();
if (inheritColors) {
result.colors.putAll(colors);
}
if (inheritFonts) {
result.font(fontFamily, fontSize);
}
return result;
}

public NativeThemeSettings copy() {
NativeThemeSettings result = new NativeThemeSettings();
result.colors.putAll(colors);
result.fontFamily = fontFamily;
result.fontSize = fontSize;
return result;
}

public String getColor(String token) {
return colors.get(token);
}

public NativeThemeSettings font(String family, float pixels) {
if (family != null && family.length() > 0 && pixels > 0 && pixels < 10000) {
fontFamily = family;
fontSize = pixels;
}
return this;
}

public String getFontFamily() {
return fontFamily;
}

public float getFontSize() {
return fontSize;
}

/// Parses the native bridge's newline-separated key=value snapshot. Unknown
/// and malformed entries are ignored so partially supported settings still work.
public static NativeThemeSettings parse(String encoded) {
NativeThemeSettings result = new NativeThemeSettings();
if (encoded == null) {
return result;
}
String family = null;
float size = 0;
for (String line : StringUtil.tokenize(encoded, '\n')) {
int split = line.indexOf('=');
if (split <= 0) {
continue;
}
String key = line.substring(0, split);
String value = line.substring(split + 1);
try {
if ("fontFamily".equals(key)) {
family = value;
} else if ("fontSize".equals(key)) {
size = Float.parseFloat(value);
} else if (value.length() == 6) {
result.color(key, Integer.parseInt(value, 16));
}
} catch (IllegalArgumentException ignored) {
// An unavailable or invalid setting keeps the bundled fallback.
}
}
return result.font(family, size);
}

@Override
public boolean equals(Object other) {
if (!(other instanceof NativeThemeSettings)) {
return false;
}
NativeThemeSettings that = (NativeThemeSettings) other;
return colors.equals(that.colors) && Float.floatToIntBits(fontSize) == Float.floatToIntBits(that.fontSize)
&& (fontFamily == null ? that.fontFamily == null : fontFamily.equals(that.fontFamily));
}

@Override
public int hashCode() {
return colors.hashCode() * 31 + (fontFamily == null ? 0 : fontFamily.hashCode())
+ Float.floatToIntBits(fontSize);
}
}
29 changes: 29 additions & 0 deletions CodenameOne/src/com/codename1/ui/Display.java
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,35 @@ public void setDarkMode(Boolean darkMode) {
this.darkMode = darkMode;
}

/// Internal platform snapshot used by native-theme inheritance.
public com.codename1.impl.NativeThemeSettings getNativeThemeSettings() {
return impl.getNativeThemeSettings();
}

private boolean nativeThemeRefreshPending;

/// Port notification for OS theme changes and resume. Coalesces onto the CN1 EDT.
public void nativeThemeSettingsChanged() {
if (!isInitialized()) {
return;
}
synchronized (this) {
if (nativeThemeRefreshPending) {
return;
}
nativeThemeRefreshPending = true;
}
callSerially(new Runnable() {
@Override
public void run() {
synchronized (Display.this) {
nativeThemeRefreshPending = false;
}
UIManager.getInstance().refreshNativeThemeSettings();
}
});
}

/// Returns true if the user has selected larger type fonts in the system settings.
///
/// #### Returns
Expand Down
23 changes: 23 additions & 0 deletions CodenameOne/src/com/codename1/ui/Font.java
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,29 @@ public class Font extends CN {
private static final Hashtable bitmapCache = new Hashtable();
private static final HashMap<String, Font> derivedFontCache = new HashMap<String, Font>();

/// Internal theme hook: inherit only native UI fonts, never icon or bundled fonts.
public Font deriveNativeThemeFont(String family, float size) {
if (fontUniqueId == null || !fontUniqueId.startsWith("native:") || family == null) {
return this;
}
int style = getStyle();
if (fontUniqueId.indexOf("Bold") >= 0 || fontUniqueId.indexOf("Black") >= 0) {
style |= STYLE_BOLD;
}
if (fontUniqueId.indexOf("Italic") >= 0) {
style |= STYLE_ITALIC;
}
Object nativeFont = Display.impl.loadNativeThemeFont(family, fontUniqueId, size, style);
if (nativeFont == null) {
return this;
}
Font result = new Font(nativeFont);
result.ttf = true;
result.pixelSize = size;
result.fontUniqueId = "os:" + family + ":" + fontUniqueId;
return result;
}

/// Clears the cache of derived TrueType fonts. Called when the theme changes so
/// that fonts whose platform rendering depends on theme constants (e.g. a native
/// theme's text letter spacing) are re-derived against the freshly-installed
Expand Down
Loading
Loading