From 0ad232423d5fc7214324a1db3bbde2e12a3c654c Mon Sep 17 00:00:00 2001 From: Anish Mishra Date: Sun, 10 Aug 2025 19:57:02 +0530 Subject: [PATCH] Android: Add method to set root window color at runtime --- doc/classes/DisplayServer.xml | 8 ++++++ platform/android/display_server_android.cpp | 6 +++++ platform/android/display_server_android.h | 2 ++ .../lib/src/org/godotengine/godot/Godot.kt | 26 ++++++++++++------- platform/android/java_godot_wrapper.cpp | 11 ++++++++ platform/android/java_godot_wrapper.h | 3 +++ servers/display_server.cpp | 2 ++ servers/display_server.h | 2 ++ 8 files changed, 50 insertions(+), 10 deletions(-) diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 9884860c0b..50473d0a19 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -2261,6 +2261,14 @@ Makes the window specified by [param window_id] request attention, which is materialized by the window title and taskbar entry blinking until the window is focused. This usually has no visible effect if the window is currently focused. The exact behavior varies depending on the operating system. + + + + + Sets the background color of the root window. + [b]Note:[/b] This method is implemented only on Android. + + diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index 7738b25c5e..376ab138e9 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -626,6 +626,12 @@ bool DisplayServerAndroid::can_any_window_draw() const { return true; } +void DisplayServerAndroid::window_set_color(const Color &p_color) { + GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java(); + ERR_FAIL_NULL(godot_java); + godot_java->set_window_color(p_color); +} + void DisplayServerAndroid::process_events() { Input::get_singleton()->flush_buffered_events(); } diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h index 5b09128ee3..ad332f7eff 100644 --- a/platform/android/display_server_android.h +++ b/platform/android/display_server_android.h @@ -220,6 +220,8 @@ public: virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override; virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override; + virtual void window_set_color(const Color &p_color) override; + virtual void process_events() override; void process_accelerometer(const Vector3 &p_accelerometer); diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt index 3311e7733d..ab551c6ffa 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt @@ -260,16 +260,7 @@ class Godot private constructor(val context: Context) { useImmersive.set(true) newArgs.add(commandLine[i]) } else if (commandLine[i] == "--background_color") { - val colorStr = commandLine[i + 1] - try { - backgroundColor = colorStr.toColorInt() - Log.d(TAG, "background color = $backgroundColor") - } catch (e: java.lang.IllegalArgumentException) { - Log.d(TAG, "Failed to parse background color: $colorStr") - } - runOnHostThread { - getActivity()?.window?.decorView?.setBackgroundColor(backgroundColor) - } + setWindowColor(commandLine[i + 1]) } else if (commandLine[i] == "--use_apk_expansion") { useApkExpansion = true } else if (hasExtra && commandLine[i] == "--apk_expansion_md5") { @@ -492,6 +483,21 @@ class Godot private constructor(val context: Context) { } } + fun setWindowColor(colorStr: String) { + val color = try { + colorStr.toColorInt() + } catch (e: java.lang.IllegalArgumentException) { + Log.w(TAG, "Failed to parse background color: $colorStr", e) + return + } + val decorView = getActivity()?.window?.decorView ?: return + runOnHostThread { + decorView.setBackgroundColor(color) + backgroundColor = color + setSystemBarsAppearance() + } + } + /** * Used to complete initialization of the view used by the engine for rendering. * diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp index 14fa75f5f1..087b0bb02c 100644 --- a/platform/android/java_godot_wrapper.cpp +++ b/platform/android/java_godot_wrapper.cpp @@ -85,6 +85,7 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_godot_instance) { _verify_apk = p_env->GetMethodID(godot_class, "nativeVerifyApk", "(Ljava/lang/String;)I"); _enable_immersive_mode = p_env->GetMethodID(godot_class, "nativeEnableImmersiveMode", "(Z)V"); _is_in_immersive_mode = p_env->GetMethodID(godot_class, "isInImmersiveMode", "()Z"); + _set_window_color = p_env->GetMethodID(godot_class, "setWindowColor", "(Ljava/lang/String;)V"); _on_editor_workspace_selected = p_env->GetMethodID(godot_class, "nativeOnEditorWorkspaceSelected", "(Ljava/lang/String;)V"); _get_activity = p_env->GetMethodID(godot_class, "getActivity", "()Landroid/app/Activity;"); } @@ -587,6 +588,16 @@ bool GodotJavaWrapper::is_in_immersive_mode() { } } +void GodotJavaWrapper::set_window_color(const Color &p_color) { + if (_set_window_color) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_NULL(env); + String color = "#" + p_color.to_html(false); + jstring jStrColor = env->NewStringUTF(color.utf8().get_data()); + env->CallVoidMethod(godot_instance, _set_window_color, jStrColor); + } +} + void GodotJavaWrapper::on_editor_workspace_selected(const String &p_workspace) { if (_on_editor_workspace_selected) { JNIEnv *env = get_jni_env(); diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h index a7957b1807..62e8e6ec82 100644 --- a/platform/android/java_godot_wrapper.h +++ b/platform/android/java_godot_wrapper.h @@ -81,6 +81,7 @@ private: jmethodID _verify_apk = nullptr; jmethodID _enable_immersive_mode = nullptr; jmethodID _is_in_immersive_mode = nullptr; + jmethodID _set_window_color = nullptr; jmethodID _on_editor_workspace_selected = nullptr; jmethodID _get_activity = nullptr; @@ -137,5 +138,7 @@ public: void enable_immersive_mode(bool p_enabled); bool is_in_immersive_mode(); + void set_window_color(const Color &p_color); + void on_editor_workspace_selected(const String &p_workspace); }; diff --git a/servers/display_server.cpp b/servers/display_server.cpp index d2acfd8c98..8cc87889b6 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -1476,6 +1476,8 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("window_start_drag", "window_id"), &DisplayServer::window_start_drag, DEFVAL(MAIN_WINDOW_ID)); ClassDB::bind_method(D_METHOD("window_start_resize", "edge", "window_id"), &DisplayServer::window_start_resize, DEFVAL(MAIN_WINDOW_ID)); + ClassDB::bind_method(D_METHOD("window_set_color", "color"), &DisplayServer::window_set_color); + ClassDB::bind_method(D_METHOD("accessibility_should_increase_contrast"), &DisplayServer::accessibility_should_increase_contrast); ClassDB::bind_method(D_METHOD("accessibility_should_reduce_animation"), &DisplayServer::accessibility_should_reduce_animation); ClassDB::bind_method(D_METHOD("accessibility_should_reduce_transparency"), &DisplayServer::accessibility_should_reduce_transparency); diff --git a/servers/display_server.h b/servers/display_server.h index 6283edc45f..3b3fab91cc 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -525,6 +525,8 @@ public: virtual void window_start_drag(WindowID p_window = MAIN_WINDOW_ID) {} + virtual void window_set_color(const Color &p_color) {} + enum WindowResizeEdge { WINDOW_EDGE_TOP_LEFT, WINDOW_EDGE_TOP,