diff --git a/Handlers/GtkWebViewPlatformView.cs b/Handlers/GtkWebViewPlatformView.cs
index 9501222..a879b84 100644
--- a/Handlers/GtkWebViewPlatformView.cs
+++ b/Handlers/GtkWebViewPlatformView.cs
@@ -154,6 +154,9 @@ public sealed class GtkWebViewPlatformView : IDisposable
};
GtkNative.gtk_window_set_title(gtkDialog, title);
+ // Apply theme-aware CSS styling based on app's current theme
+ ApplyDialogTheme(gtkDialog);
+
// Make dialog modal to parent if we have a parent
if (parentWindow != IntPtr.Zero)
{
@@ -211,6 +214,9 @@ public sealed class GtkWebViewPlatformView : IDisposable
return false;
}
+ // Apply theme-aware CSS styling
+ ApplyDialogTheme(gtkDialog);
+
// Get the content area
IntPtr contentArea = GtkNative.gtk_dialog_get_content_area(gtkDialog);
@@ -277,6 +283,134 @@ public sealed class GtkWebViewPlatformView : IDisposable
}
}
+ ///
+ /// Applies theme-aware CSS styling to a GTK dialog based on the app's current theme.
+ ///
+ private void ApplyDialogTheme(IntPtr gtkDialog)
+ {
+ try
+ {
+ // Check the app's current theme (not the system theme)
+ bool isDark = Microsoft.Maui.Controls.Application.Current?.UserAppTheme == Microsoft.Maui.ApplicationModel.AppTheme.Dark;
+
+ // If UserAppTheme is Unspecified, fall back to RequestedTheme
+ if (Microsoft.Maui.Controls.Application.Current?.UserAppTheme == Microsoft.Maui.ApplicationModel.AppTheme.Unspecified)
+ {
+ isDark = Microsoft.Maui.Controls.Application.Current?.RequestedTheme == Microsoft.Maui.ApplicationModel.AppTheme.Dark;
+ }
+
+ Console.WriteLine($"[GtkWebViewPlatformView] ApplyDialogTheme: isDark={isDark}, UserAppTheme={Microsoft.Maui.Controls.Application.Current?.UserAppTheme}");
+
+ // Create comprehensive CSS based on the theme - targeting all dialog elements
+ string css = isDark
+ ? @"
+ * {
+ background-color: #303030;
+ color: #E0E0E0;
+ }
+ window, dialog, messagedialog, .background {
+ background-color: #303030;
+ color: #E0E0E0;
+ }
+ headerbar, headerbar *, .titlebar, .titlebar * {
+ background-color: #252525;
+ background-image: none;
+ color: #E0E0E0;
+ border-color: #404040;
+ box-shadow: none;
+ }
+ headerbar button, .titlebar button {
+ background-color: #353535;
+ background-image: none;
+ color: #E0E0E0;
+ }
+ .dialog-action-area, .dialog-action-box, actionbar {
+ background-color: #303030;
+ }
+ label, .message-dialog-message, .message-dialog-secondary-message {
+ color: #E0E0E0;
+ }
+ button {
+ background-image: none;
+ background-color: #505050;
+ color: #E0E0E0;
+ border-color: #606060;
+ }
+ button:hover {
+ background-color: #606060;
+ }
+ entry {
+ background-color: #404040;
+ color: #E0E0E0;
+ }
+ "
+ : @"
+ * {
+ background-color: #FFFFFF;
+ color: #212121;
+ }
+ window, dialog, messagedialog, .background {
+ background-color: #FFFFFF;
+ color: #212121;
+ }
+ headerbar, headerbar *, .titlebar, .titlebar * {
+ background-color: #F5F5F5;
+ background-image: none;
+ color: #212121;
+ border-color: #E0E0E0;
+ box-shadow: none;
+ }
+ headerbar button, .titlebar button {
+ background-color: #EBEBEB;
+ background-image: none;
+ color: #212121;
+ }
+ .dialog-action-area, .dialog-action-box, actionbar {
+ background-color: #FFFFFF;
+ }
+ label, .message-dialog-message, .message-dialog-secondary-message {
+ color: #212121;
+ }
+ button {
+ background-image: none;
+ background-color: #F5F5F5;
+ color: #212121;
+ border-color: #E0E0E0;
+ }
+ button:hover {
+ background-color: #E0E0E0;
+ }
+ entry {
+ background-color: #FFFFFF;
+ color: #212121;
+ }
+ ";
+
+ // Create CSS provider and apply to the screen so all child widgets inherit it
+ IntPtr cssProvider = GtkNative.gtk_css_provider_new();
+ if (cssProvider != IntPtr.Zero)
+ {
+ GtkNative.gtk_css_provider_load_from_data(cssProvider, css, -1, IntPtr.Zero);
+
+ // Get the screen from the dialog and apply CSS to entire screen for this dialog
+ IntPtr screen = GtkNative.gtk_widget_get_screen(gtkDialog);
+ if (screen == IntPtr.Zero)
+ {
+ screen = GtkNative.gdk_screen_get_default();
+ }
+
+ if (screen != IntPtr.Zero)
+ {
+ GtkNative.gtk_style_context_add_provider_for_screen(screen, cssProvider, GtkNative.GTK_STYLE_PROVIDER_PRIORITY_USER);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"[GtkWebViewPlatformView] Error applying dialog theme: {ex.Message}");
+ }
+ }
+
private void OnLoadChanged(IntPtr webView, int loadEvent, IntPtr userData)
{
try
diff --git a/LinuxApplication.cs b/LinuxApplication.cs
index ef0c50e..6c8b4c9 100644
--- a/LinuxApplication.cs
+++ b/LinuxApplication.cs
@@ -310,12 +310,19 @@ public class LinuxApplication : IDisposable
Console.WriteLine("[LinuxApplication] Set initial UserAppTheme to Light based on system theme");
}
+ // Initialize GTK theme service and apply initial CSS
+ GtkThemeService.ApplyTheme();
+
// Handle user-initiated theme changes
((BindableObject)mauiApplication).PropertyChanged += (s, e) =>
{
if (e.PropertyName == "UserAppTheme")
{
Console.WriteLine($"[LinuxApplication] User theme changed to: {mauiApplication.UserAppTheme}");
+
+ // Apply GTK CSS for dialogs, menus, and window decorations
+ GtkThemeService.ApplyTheme();
+
LinuxViewRenderer.CurrentSkiaShell?.RefreshTheme();
// Force re-render the entire page to pick up theme changes
diff --git a/Native/GtkNative.cs b/Native/GtkNative.cs
index 04067fe..3e94d08 100644
--- a/Native/GtkNative.cs
+++ b/Native/GtkNative.cs
@@ -235,6 +235,31 @@ internal static class GtkNative
[DllImport("libgtk-3.so.0")]
public static extern void gtk_window_set_modal(IntPtr window, bool modal);
+ // CSS styling for dialogs
+ [DllImport("libgtk-3.so.0")]
+ public static extern IntPtr gtk_css_provider_new();
+
+ [DllImport("libgtk-3.so.0")]
+ public static extern bool gtk_css_provider_load_from_data(IntPtr provider, string data, int length, IntPtr error);
+
+ [DllImport("libgtk-3.so.0")]
+ public static extern IntPtr gtk_widget_get_style_context(IntPtr widget);
+
+ [DllImport("libgtk-3.so.0")]
+ public static extern void gtk_style_context_add_provider(IntPtr context, IntPtr provider, uint priority);
+
+ [DllImport("libgtk-3.so.0")]
+ public static extern void gtk_style_context_add_provider_for_screen(IntPtr screen, IntPtr provider, uint priority);
+
+ [DllImport("libgtk-3.so.0")]
+ public static extern IntPtr gtk_widget_get_screen(IntPtr widget);
+
+ [DllImport("libgdk-3.so.0")]
+ public static extern IntPtr gdk_screen_get_default();
+
+ public const uint GTK_STYLE_PROVIDER_PRIORITY_APPLICATION = 600;
+ public const uint GTK_STYLE_PROVIDER_PRIORITY_USER = 800;
+
// Dialog with custom content (for prompt dialogs)
[DllImport("libgtk-3.so.0")]
public static extern IntPtr gtk_dialog_new_with_buttons(
diff --git a/OpenMaui.Controls.Linux.csproj b/OpenMaui.Controls.Linux.csproj
index 7ac086c..66db52d 100644
--- a/OpenMaui.Controls.Linux.csproj
+++ b/OpenMaui.Controls.Linux.csproj
@@ -55,6 +55,11 @@
+
+
+
+
+
diff --git a/Services/GtkContextMenuService.cs b/Services/GtkContextMenuService.cs
index ed576eb..a04fa46 100644
--- a/Services/GtkContextMenuService.cs
+++ b/Services/GtkContextMenuService.cs
@@ -75,6 +75,9 @@ public static class GtkContextMenuService
GtkNative.gtk_widget_show(menuItem);
}
+ // Apply theme-aware CSS styling
+ ApplyMenuTheme(menu);
+
GtkNative.gtk_widget_show(menu);
IntPtr currentEvent = GtkNative.gtk_get_current_event();
@@ -87,4 +90,81 @@ public static class GtkContextMenuService
Console.WriteLine($"[GtkContextMenuService] Showed GTK menu with {items.Count} items");
}
+
+ ///
+ /// Applies theme-aware CSS styling to a GTK menu based on the app's current theme.
+ ///
+ private static void ApplyMenuTheme(IntPtr menu)
+ {
+ try
+ {
+ // Check the app's current theme (not the system theme)
+ bool isDark = Microsoft.Maui.Controls.Application.Current?.UserAppTheme == Microsoft.Maui.ApplicationModel.AppTheme.Dark;
+
+ // If UserAppTheme is Unspecified, fall back to RequestedTheme
+ if (Microsoft.Maui.Controls.Application.Current?.UserAppTheme == Microsoft.Maui.ApplicationModel.AppTheme.Unspecified)
+ {
+ isDark = Microsoft.Maui.Controls.Application.Current?.RequestedTheme == Microsoft.Maui.ApplicationModel.AppTheme.Dark;
+ }
+
+ Console.WriteLine($"[GtkContextMenuService] ApplyMenuTheme: isDark={isDark}");
+
+ // Create comprehensive CSS based on the theme
+ string css = isDark
+ ? @"
+ * {
+ background-color: #303030;
+ color: #E0E0E0;
+ }
+ menu, menuitem, .menu, .menuitem {
+ background-color: #303030;
+ color: #E0E0E0;
+ }
+ menuitem:hover, .menuitem:hover {
+ background-color: #505050;
+ }
+ separator {
+ background-color: #505050;
+ }
+ "
+ : @"
+ * {
+ background-color: #FFFFFF;
+ color: #212121;
+ }
+ menu, menuitem, .menu, .menuitem {
+ background-color: #FFFFFF;
+ color: #212121;
+ }
+ menuitem:hover, .menuitem:hover {
+ background-color: #E0E0E0;
+ }
+ separator {
+ background-color: #E0E0E0;
+ }
+ ";
+
+ // Create CSS provider and apply to the screen
+ IntPtr cssProvider = GtkNative.gtk_css_provider_new();
+ if (cssProvider != IntPtr.Zero)
+ {
+ GtkNative.gtk_css_provider_load_from_data(cssProvider, css, -1, IntPtr.Zero);
+
+ IntPtr screen = GtkNative.gtk_widget_get_screen(menu);
+ if (screen == IntPtr.Zero)
+ {
+ screen = GtkNative.gdk_screen_get_default();
+ }
+
+ if (screen != IntPtr.Zero)
+ {
+ GtkNative.gtk_style_context_add_provider_for_screen(screen, cssProvider, GtkNative.GTK_STYLE_PROVIDER_PRIORITY_USER);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"[GtkContextMenuService] Error applying menu theme: {ex.Message}");
+ }
+ }
}
diff --git a/Services/GtkThemeService.cs b/Services/GtkThemeService.cs
new file mode 100644
index 0000000..d4220b4
--- /dev/null
+++ b/Services/GtkThemeService.cs
@@ -0,0 +1,544 @@
+using System;
+using Microsoft.Maui.Platform.Linux.Native;
+
+namespace Microsoft.Maui.Platform.Linux.Services;
+
+///
+/// Service for applying theme-aware CSS to GTK widgets.
+///
+public static class GtkThemeService
+{
+ private static IntPtr _currentCssProvider = IntPtr.Zero;
+ private static bool _initialized = false;
+
+ ///
+ /// Initializes the GTK theme service and applies initial CSS.
+ ///
+ public static void Initialize()
+ {
+ if (_initialized) return;
+ _initialized = true;
+ ApplyTheme();
+ }
+
+ ///
+ /// Applies GTK CSS based on the app's current theme.
+ /// Call this whenever the app theme changes.
+ ///
+ public static void ApplyTheme()
+ {
+ try
+ {
+ // Check the app's current theme
+ bool isDark = Microsoft.Maui.Controls.Application.Current?.UserAppTheme == Microsoft.Maui.ApplicationModel.AppTheme.Dark;
+
+ // If UserAppTheme is Unspecified, fall back to RequestedTheme
+ if (Microsoft.Maui.Controls.Application.Current?.UserAppTheme == Microsoft.Maui.ApplicationModel.AppTheme.Unspecified)
+ {
+ isDark = Microsoft.Maui.Controls.Application.Current?.RequestedTheme == Microsoft.Maui.ApplicationModel.AppTheme.Dark;
+ }
+
+ Console.WriteLine($"[GtkThemeService] ApplyTheme: isDark={isDark}");
+
+ // Create comprehensive CSS based on the theme
+ string css = isDark ? GetDarkCss() : GetLightCss();
+
+ // Get the default screen
+ IntPtr screen = GtkNative.gdk_screen_get_default();
+ if (screen == IntPtr.Zero)
+ {
+ Console.WriteLine("[GtkThemeService] Failed to get default screen");
+ return;
+ }
+
+ // Create new CSS provider
+ IntPtr newProvider = GtkNative.gtk_css_provider_new();
+ if (newProvider == IntPtr.Zero)
+ {
+ Console.WriteLine("[GtkThemeService] Failed to create CSS provider");
+ return;
+ }
+
+ // Load CSS data
+ if (!GtkNative.gtk_css_provider_load_from_data(newProvider, css, -1, IntPtr.Zero))
+ {
+ Console.WriteLine("[GtkThemeService] Failed to load CSS data");
+ return;
+ }
+
+ // Apply to screen (this affects all GTK widgets)
+ GtkNative.gtk_style_context_add_provider_for_screen(screen, newProvider, GtkNative.GTK_STYLE_PROVIDER_PRIORITY_USER);
+
+ // Store reference to current provider
+ _currentCssProvider = newProvider;
+
+ Console.WriteLine("[GtkThemeService] CSS applied successfully");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"[GtkThemeService] Error applying theme: {ex.Message}");
+ }
+ }
+
+ private static string GetDarkCss()
+ {
+ return @"
+ /* Dark theme - base */
+ * {
+ background-color: #303030;
+ color: #E0E0E0;
+ }
+
+ /* Windows and dialogs */
+ window, dialog, .background {
+ background-color: #303030;
+ color: #E0E0E0;
+ }
+
+ /* Message dialogs - all parts same color */
+ messagedialog,
+ messagedialog.background,
+ messagedialog .background,
+ messagedialog box,
+ messagedialog grid,
+ messagedialog .dialog-vbox,
+ messagedialog .message-area,
+ messagedialog .dialog-action-area,
+ messagedialog .dialog-action-box,
+ messagedialog actionbar,
+ messagedialog buttonbox,
+ messagedialog box.vertical,
+ messagedialog box.horizontal,
+ messagedialog .linked,
+ messagedialog .linked button,
+ dialog box,
+ dialog .dialog-vbox,
+ dialog .dialog-action-area {
+ background-color: #303030;
+ background-image: none;
+ border: none;
+ border-style: none;
+ box-shadow: none;
+ }
+
+ messagedialog separator,
+ dialog separator {
+ background-color: transparent;
+ background-image: none;
+ min-height: 0;
+ min-width: 0;
+ border: none;
+ }
+
+ messagedialog .dialog-action-area,
+ dialog .dialog-action-area {
+ background-color: #303030;
+ background-image: none;
+ border: none;
+ border-top-style: none;
+ margin: 0;
+ padding: 8px;
+ }
+
+ messagedialog .dialog-action-area button,
+ dialog .dialog-action-area button {
+ background-color: #505050;
+ background-image: none;
+ }
+
+ /* Header bars and title bars */
+ headerbar, .titlebar {
+ background-color: #252525;
+ background-image: none;
+ color: #E0E0E0;
+ border: none;
+ box-shadow: none;
+ }
+
+ headerbar *, .titlebar * {
+ background-color: transparent;
+ background-image: none;
+ }
+
+ headerbar button, .titlebar button {
+ background-color: #353535;
+ background-image: none;
+ color: #E0E0E0;
+ border-color: #353535;
+ border-radius: 6px;
+ }
+
+ headerbar button:hover, .titlebar button:hover {
+ background-color: #454545;
+ border-color: #454545;
+ }
+
+ /* Window control buttons */
+ windowcontrols button,
+ button.titlebutton,
+ .titlebutton {
+ background-color: #252525;
+ background-image: none;
+ border-color: #252525;
+ border-radius: 50%;
+ min-width: 24px;
+ min-height: 24px;
+ padding: 4px;
+ }
+
+ windowcontrols button *,
+ button.titlebutton *,
+ .titlebutton * {
+ background-color: transparent;
+ background-image: none;
+ }
+
+ windowcontrols button:hover,
+ button.titlebutton:hover,
+ .titlebutton:hover {
+ background-color: #404040;
+ border-color: #404040;
+ }
+
+ /* Dialog action areas */
+ .dialog-action-area,
+ .dialog-action-box,
+ actionbar {
+ background-color: #303030;
+ background-image: none;
+ border: none;
+ }
+
+ /* Labels */
+ label {
+ background-color: transparent;
+ color: #E0E0E0;
+ }
+
+ /* Buttons */
+ button {
+ background-image: none;
+ background-color: #505050;
+ color: #E0E0E0;
+ border-color: #505050;
+ border-radius: 6px;
+ }
+
+ button * {
+ background-color: transparent;
+ background-image: none;
+ }
+
+ button:hover {
+ background-color: #606060;
+ border-color: #606060;
+ }
+
+ button:hover * {
+ background-color: transparent;
+ }
+
+ button:active {
+ background-color: #404040;
+ border-color: #404040;
+ }
+
+ /* Entries and text inputs */
+ entry, textview, text {
+ background-color: #404040;
+ color: #E0E0E0;
+ border-color: #505050;
+ border-radius: 4px;
+ }
+
+ /* Menus and context menus */
+ menu, .menu, .popup {
+ background-color: #303030;
+ color: #E0E0E0;
+ border: none;
+ border-radius: 8px;
+ padding: 4px;
+ }
+
+ menuitem {
+ background-color: transparent;
+ color: #E0E0E0;
+ border: none;
+ border-radius: 6px;
+ padding: 6px 12px;
+ margin: 2px 4px;
+ }
+
+ menuitem * {
+ background-color: transparent;
+ background-image: none;
+ }
+
+ menuitem:hover {
+ background-color: #505050;
+ }
+
+ menuitem:hover * {
+ background-color: transparent;
+ }
+
+ /* Popover */
+ popover, popover.background {
+ background-color: #303030;
+ border: none;
+ border-radius: 8px;
+ }
+
+ /* Separators */
+ separator {
+ background-color: #505050;
+ }
+
+ /* Scrollbars */
+ scrollbar {
+ background-color: #252525;
+ }
+
+ scrollbar slider {
+ background-color: #505050;
+ border-radius: 4px;
+ }
+
+ /* Focus styling */
+ *:focus {
+ outline-color: #606060;
+ }
+ ";
+ }
+
+ private static string GetLightCss()
+ {
+ return @"
+ /* Light theme - base */
+ * {
+ background-color: #FFFFFF;
+ color: #212121;
+ }
+
+ /* Windows and dialogs */
+ window, dialog, .background {
+ background-color: #FFFFFF;
+ color: #212121;
+ }
+
+ /* Message dialogs - all parts same color */
+ messagedialog,
+ messagedialog.background,
+ messagedialog .background,
+ messagedialog box,
+ messagedialog grid,
+ messagedialog .dialog-vbox,
+ messagedialog .message-area,
+ messagedialog .dialog-action-area,
+ messagedialog .dialog-action-box,
+ messagedialog actionbar,
+ messagedialog buttonbox,
+ messagedialog box.vertical,
+ messagedialog box.horizontal,
+ messagedialog .linked,
+ messagedialog .linked button,
+ dialog box,
+ dialog .dialog-vbox,
+ dialog .dialog-action-area {
+ background-color: #FFFFFF;
+ background-image: none;
+ border: none;
+ border-style: none;
+ box-shadow: none;
+ }
+
+ messagedialog separator,
+ dialog separator {
+ background-color: transparent;
+ background-image: none;
+ min-height: 0;
+ min-width: 0;
+ border: none;
+ }
+
+ messagedialog .dialog-action-area,
+ dialog .dialog-action-area {
+ background-color: #FFFFFF;
+ background-image: none;
+ border: none;
+ border-top-style: none;
+ margin: 0;
+ padding: 8px;
+ }
+
+ messagedialog .dialog-action-area button,
+ dialog .dialog-action-area button {
+ background-color: #F5F5F5;
+ background-image: none;
+ }
+
+ /* Header bars and title bars */
+ headerbar, .titlebar {
+ background-color: #F5F5F5;
+ background-image: none;
+ color: #212121;
+ border: none;
+ box-shadow: none;
+ }
+
+ headerbar *, .titlebar * {
+ background-color: transparent;
+ background-image: none;
+ }
+
+ headerbar button, .titlebar button {
+ background-color: #EBEBEB;
+ background-image: none;
+ color: #212121;
+ border-color: #EBEBEB;
+ border-radius: 6px;
+ }
+
+ headerbar button:hover, .titlebar button:hover {
+ background-color: #DDDDDD;
+ border-color: #DDDDDD;
+ }
+
+ /* Window control buttons */
+ windowcontrols button,
+ button.titlebutton,
+ .titlebutton {
+ background-color: #F5F5F5;
+ background-image: none;
+ border-color: #F5F5F5;
+ border-radius: 50%;
+ min-width: 24px;
+ min-height: 24px;
+ padding: 4px;
+ }
+
+ windowcontrols button *,
+ button.titlebutton *,
+ .titlebutton * {
+ background-color: transparent;
+ background-image: none;
+ }
+
+ windowcontrols button:hover,
+ button.titlebutton:hover,
+ .titlebutton:hover {
+ background-color: #E0E0E0;
+ border-color: #E0E0E0;
+ }
+
+ /* Dialog action areas */
+ .dialog-action-area,
+ .dialog-action-box,
+ actionbar {
+ background-color: #FFFFFF;
+ background-image: none;
+ border: none;
+ }
+
+ /* Labels */
+ label {
+ background-color: transparent;
+ color: #212121;
+ }
+
+ /* Buttons */
+ button {
+ background-image: none;
+ background-color: #F5F5F5;
+ color: #212121;
+ border-color: #E0E0E0;
+ border-radius: 6px;
+ }
+
+ button * {
+ background-color: transparent;
+ background-image: none;
+ }
+
+ button:hover {
+ background-color: #E0E0E0;
+ border-color: #D0D0D0;
+ }
+
+ button:hover * {
+ background-color: transparent;
+ }
+
+ button:active {
+ background-color: #D0D0D0;
+ border-color: #C0C0C0;
+ }
+
+ /* Entries and text inputs */
+ entry, textview, text {
+ background-color: #FFFFFF;
+ color: #212121;
+ border-color: #E0E0E0;
+ border-radius: 4px;
+ }
+
+ /* Menus and context menus */
+ menu, .menu, .popup {
+ background-color: #FFFFFF;
+ color: #212121;
+ border: none;
+ border-radius: 8px;
+ padding: 4px;
+ }
+
+ menuitem {
+ background-color: transparent;
+ color: #212121;
+ border: none;
+ border-radius: 6px;
+ padding: 6px 12px;
+ margin: 2px 4px;
+ }
+
+ menuitem * {
+ background-color: transparent;
+ background-image: none;
+ }
+
+ menuitem:hover {
+ background-color: #E8E8E8;
+ }
+
+ menuitem:hover * {
+ background-color: transparent;
+ }
+
+ /* Popover */
+ popover, popover.background {
+ background-color: #FFFFFF;
+ border: none;
+ border-radius: 8px;
+ }
+
+ /* Separators */
+ separator {
+ background-color: #E0E0E0;
+ }
+
+ /* Scrollbars */
+ scrollbar {
+ background-color: #F5F5F5;
+ }
+
+ scrollbar slider {
+ background-color: #C0C0C0;
+ border-radius: 4px;
+ }
+
+ /* Focus styling */
+ *:focus {
+ outline-color: #C0C0C0;
+ }
+ ";
+ }
+}
diff --git a/Views/LinuxDialogService.cs b/Views/LinuxDialogService.cs
index 9ac4287..b72294c 100644
--- a/Views/LinuxDialogService.cs
+++ b/Views/LinuxDialogService.cs
@@ -63,8 +63,10 @@ public static class LinuxDialogService
public static void DrawDialogsOnly(SKCanvas canvas, SKRect bounds)
{
+ Console.WriteLine($"[LinuxDialogService] DrawDialogsOnly: {_activeDialogs.Count} dialogs, IsDarkMode={SkiaTheme.IsDarkMode}");
foreach (var dialog in _activeDialogs)
{
+ Console.WriteLine($"[LinuxDialogService] Drawing dialog: IsVisible={dialog.IsVisible}, Opacity={dialog.Opacity}");
dialog.Measure(new Size(bounds.Width, bounds.Height));
dialog.Arrange(new Rect(bounds.Left, bounds.Top, bounds.Width, bounds.Height));
dialog.Draw(canvas);
diff --git a/Views/SkiaAlertDialog.cs b/Views/SkiaAlertDialog.cs
index e8a8ebd..1afea84 100644
--- a/Views/SkiaAlertDialog.cs
+++ b/Views/SkiaAlertDialog.cs
@@ -22,17 +22,17 @@ public class SkiaAlertDialog : SkiaView
private bool _cancelHovered;
private bool _acceptHovered;
- // Dialog styling - using SkiaTheme for MAUI-compliant theming
- private static readonly SKColor OverlayColor = SkiaTheme.Overlay50SK;
- private static readonly SKColor DialogBackground = SkiaTheme.BackgroundWhiteSK;
- private static readonly SKColor TitleColor = SkiaTheme.TextPrimarySK;
- private static readonly SKColor MessageColor = SkiaTheme.TextSecondarySK;
- private static readonly SKColor ButtonColor = SkiaTheme.PrimarySK;
- private static readonly SKColor ButtonHoverColor = SkiaTheme.PrimaryDarkSK;
- private static readonly SKColor ButtonTextColor = SkiaTheme.BackgroundWhiteSK;
- private static readonly SKColor CancelButtonColor = SkiaTheme.ButtonCancelSK;
- private static readonly SKColor CancelButtonHoverColor = SkiaTheme.ButtonCancelHoverSK;
- private static readonly SKColor BorderColor = SkiaTheme.BorderLightSK;
+ // Dialog styling - theme-aware colors (evaluated at draw time)
+ private static SKColor OverlayColor => SkiaTheme.Overlay50SK;
+ private static SKColor DialogBackground => SkiaTheme.CurrentSurfaceSK;
+ private static SKColor TitleColor => SkiaTheme.CurrentTextSK;
+ private static SKColor MessageColor => SkiaTheme.IsDarkMode ? SkiaTheme.Gray400SK : SkiaTheme.TextSecondarySK;
+ private static SKColor ButtonColor => SkiaTheme.PrimarySK;
+ private static SKColor ButtonHoverColor => SkiaTheme.PrimaryDarkSK;
+ private static SKColor ButtonTextColor => SKColors.White;
+ private static SKColor CancelButtonColor => SkiaTheme.IsDarkMode ? SkiaTheme.Gray600SK : SkiaTheme.ButtonCancelSK;
+ private static SKColor CancelButtonHoverColor => SkiaTheme.IsDarkMode ? SkiaTheme.Gray700SK : SkiaTheme.ButtonCancelHoverSK;
+ private static SKColor BorderColor => SkiaTheme.CurrentBorderSK;
private const float DialogWidth = 400;
private const float DialogPadding = 24;
@@ -61,6 +61,9 @@ public class SkiaAlertDialog : SkiaView
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
+ var app = Application.Current;
+ Console.WriteLine($"[SkiaAlertDialog] OnDraw: app={app != null}, UserAppTheme={app?.UserAppTheme}, RequestedTheme={app?.RequestedTheme}, IsDarkMode={SkiaTheme.IsDarkMode}, DialogBg={DialogBackground}");
+
// Draw semi-transparent overlay covering entire screen
using var overlayPaint = new SKPaint
{
diff --git a/Views/SkiaContextMenu.cs b/Views/SkiaContextMenu.cs
index dd94ee9..fec03ef 100644
--- a/Views/SkiaContextMenu.cs
+++ b/Views/SkiaContextMenu.cs
@@ -12,15 +12,13 @@ public class SkiaContextMenu : SkiaView
private int _hoveredIndex = -1;
private SKRect[] _itemBounds = Array.Empty();
- private static readonly SKColor MenuBackground = SkiaTheme.BackgroundWhiteSK;
- private static readonly SKColor MenuBackgroundDark = SkiaTheme.DarkBackgroundSK;
- private static readonly SKColor ItemHoverBackground = SkiaTheme.PrimarySelectionSK;
- private static readonly SKColor ItemHoverBackgroundDark = SkiaTheme.DarkHoverSK;
- private static readonly SKColor ItemTextColor = SkiaTheme.TextPrimarySK;
- private static readonly SKColor ItemTextColorDark = SkiaTheme.DarkTextSK;
- private static readonly SKColor DisabledTextColor = SkiaTheme.TextDisabledSK;
- private static readonly SKColor SeparatorColor = SkiaTheme.Gray300SK;
- private static readonly SKColor ShadowColor = SkiaTheme.Shadow25SK;
+ // Theme-aware colors (evaluated at draw time)
+ private static SKColor MenuBackground => SkiaTheme.CurrentSurfaceSK;
+ private static SKColor ItemHoverBackground => SkiaTheme.IsDarkMode ? SkiaTheme.DarkHoverSK : SkiaTheme.PrimarySelectionSK;
+ private static SKColor ItemTextColor => SkiaTheme.CurrentTextSK;
+ private static SKColor DisabledTextColor => SkiaTheme.TextDisabledSK;
+ private static SKColor SeparatorColor => SkiaTheme.IsDarkMode ? SkiaTheme.Gray600SK : SkiaTheme.Gray300SK;
+ private static SKColor ShadowColor => SkiaTheme.Shadow25SK;
private const float MenuPadding = 4f;
private const float ItemHeight = 32f;
@@ -29,14 +27,12 @@ public class SkiaContextMenu : SkiaView
private const float CornerRadius = 4f;
private const float MinWidth = 120f;
- private bool _isDarkTheme;
-
public SkiaContextMenu(float x, float y, List items, bool isDarkTheme = false)
{
_x = x;
_y = y;
_items = items;
- _isDarkTheme = isDarkTheme;
+ // isDarkTheme parameter kept for API compatibility but ignored - we use SkiaTheme.IsDarkMode instead
IsFocusable = true;
}
@@ -73,7 +69,7 @@ public class SkiaContextMenu : SkiaView
// Draw background
using (var bgPaint = new SKPaint
{
- Color = _isDarkTheme ? MenuBackgroundDark : MenuBackground,
+ Color = MenuBackground,
IsAntialias = true
})
{
@@ -120,7 +116,7 @@ public class SkiaContextMenu : SkiaView
{
using (var hoverPaint = new SKPaint
{
- Color = _isDarkTheme ? ItemHoverBackgroundDark : ItemHoverBackground,
+ Color = ItemHoverBackground,
IsAntialias = true
})
{
@@ -131,7 +127,7 @@ public class SkiaContextMenu : SkiaView
// Draw text
using (var textPaint = new SKPaint
{
- Color = !item.IsEnabled ? DisabledTextColor : (_isDarkTheme ? ItemTextColorDark : ItemTextColor),
+ Color = !item.IsEnabled ? DisabledTextColor : ItemTextColor,
TextSize = 14f,
IsAntialias = true,
Typeface = SKTypeface.Default
diff --git a/Views/SkiaTheme.cs b/Views/SkiaTheme.cs
index 6bec6b8..46645a3 100644
--- a/Views/SkiaTheme.cs
+++ b/Views/SkiaTheme.cs
@@ -322,8 +322,23 @@ public static class SkiaTheme
///
/// Returns true if dark mode is currently active.
+ /// Checks UserAppTheme first, falls back to system RequestedTheme.
///
- public static bool IsDarkMode => Application.Current?.UserAppTheme == AppTheme.Dark;
+ public static bool IsDarkMode
+ {
+ get
+ {
+ var app = Application.Current;
+ if (app == null) return false;
+
+ // If user explicitly set a theme, use that
+ if (app.UserAppTheme != AppTheme.Unspecified)
+ return app.UserAppTheme == AppTheme.Dark;
+
+ // Otherwise use system theme
+ return app.RequestedTheme == AppTheme.Dark;
+ }
+ }
///
/// Gets the appropriate button background color for the current theme.
diff --git a/build/OpenMaui.Controls.Linux.targets b/build/OpenMaui.Controls.Linux.targets
index 02c70b8..8ac24ae 100644
--- a/build/OpenMaui.Controls.Linux.targets
+++ b/build/OpenMaui.Controls.Linux.targets
@@ -1,28 +1,21 @@
-
-
+
-
-
-
-
-
+
-
-
-
+
+
+
+