GTK3 DarkMode

Linux specific forum
User avatar
mk-soft
Always Here
Always Here
Posts: 6233
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

GTK3 DarkMode

Post by mk-soft »

DarkMode for GTK3 Application ... :wink:

Update v1.02.1

Update v1.02.2
- Change get/set property

Code: Select all

;-TOP

; GTK DarkMode by mk-soft, v1.02.2, 18.12.2022 - 22.08.2025
; Link: https://www.purebasic.fr/english/viewtopic.php?t=80298

;- Global glib gvalue

CompilerIf Not Defined(__G_TYPE_H__, #PB_Constant)
  #__G_TYPE_H__ = #True
  
  Macro G_TYPE_MAKE_FUNDAMENTAL(x)
    x << 2
  EndMacro
  
  #G_TYPE_INVALID = G_TYPE_MAKE_FUNDAMENTAL(0)
  #G_TYPE_NONE = G_TYPE_MAKE_FUNDAMENTAL(1)
  #G_TYPE_INTERFACE = G_TYPE_MAKE_FUNDAMENTAL(2)
  #G_TYPE_CHAR = G_TYPE_MAKE_FUNDAMENTAL(3)
  #G_TYPE_UCHAR = G_TYPE_MAKE_FUNDAMENTAL(4)
  #G_TYPE_BOOLEAN = G_TYPE_MAKE_FUNDAMENTAL(5)
  #G_TYPE_INT = G_TYPE_MAKE_FUNDAMENTAL(6)
  #G_TYPE_UINT = G_TYPE_MAKE_FUNDAMENTAL(7)
  #G_TYPE_LONG = G_TYPE_MAKE_FUNDAMENTAL(8)
  #G_TYPE_ULONG = G_TYPE_MAKE_FUNDAMENTAL(9)
  #G_TYPE_INT64 = G_TYPE_MAKE_FUNDAMENTAL(10)
  #G_TYPE_UINT64 = G_TYPE_MAKE_FUNDAMENTAL(11)
  #G_TYPE_ENUM = G_TYPE_MAKE_FUNDAMENTAL(12)
  #G_TYPE_FLAGS = G_TYPE_MAKE_FUNDAMENTAL(13)
  #G_TYPE_FLOAT = G_TYPE_MAKE_FUNDAMENTAL(14)
  #G_TYPE_DOUBLE = G_TYPE_MAKE_FUNDAMENTAL(15)
  #G_TYPE_STRING = G_TYPE_MAKE_FUNDAMENTAL(16)
  #G_TYPE_POINTER = G_TYPE_MAKE_FUNDAMENTAL(17)
  #G_TYPE_BOXED = G_TYPE_MAKE_FUNDAMENTAL(18)
  #G_TYPE_PARAM = G_TYPE_MAKE_FUNDAMENTAL(19)
  #G_TYPE_OBJECT = G_TYPE_MAKE_FUNDAMENTAL(20)
  
CompilerEndIf

Procedure.s GetThemeName()
  Protected ThemeName.s, *Settings, Theme.gvalue
  
  *Settings = gtk_settings_get_default_()
  If *Settings
    g_object_get_property_(*Settings, "gtk-theme-name", @Theme);
    ThemeName.s = PeekS(g_value_get_string_(Theme), -1, #PB_UTF8)
    g_value_unset_(Theme)
    ProcedureReturn ThemeName
  EndIf
EndProcedure

Procedure SetThemeName(ThemeName.s)
  Protected *Settings, Theme.gvalue
  
  *Settings = gtk_settings_get_default_()
  If *Settings
    g_value_init_(Theme, #G_TYPE_STRING)
    g_value_set_string_(Theme, ThemeName)
    g_object_set_property_(*Settings, "gtk-theme-name", Theme);
    g_value_unset_(Theme)
    ProcedureReturn #True
  EndIf
EndProcedure

; ----

Procedure IsDarkMode()
  Protected boolVal, *Settings, Value.gvalue
  
  *Settings = gtk_settings_get_default_()
  If *Settings
    g_object_get_property_(*Settings, "gtk-application-prefer-dark-theme", @Value);
    boolVal = g_value_get_boolean_(Value)
    ProcedureReturn boolVal
  EndIf
EndProcedure

Procedure SetDarkMode(State)
  Protected boolVal, *Settings, Value.gvalue
  
  *Settings = gtk_settings_get_default_()
  If *Settings
    g_value_init_(Value, #G_TYPE_BOOLEAN)
    g_object_get_property_(*Settings, "gtk-application-prefer-dark-theme", Value);
    boolVal = g_value_get_boolean_(Value)
    g_value_set_boolean_(Value, State)
    g_object_set_property_(*Settings, "gtk-application-prefer-dark-theme", Value);
    g_value_unset_(Value)
    ProcedureReturn boolVal
  EndIf
EndProcedure

; ****

;-TOP

; GTK GetWindowColor by mk-soft, v1.01.1, 27.08.2023

ImportC ""
  gtk_widget_get_style_context(Widget)
  gtk_style_context_get_background_color(context, state, pcolor)
EndImport

#GTK_STATE_FLAG_NORMAL       = 0
#GTK_STATE_FLAG_ACTIVE       = 1 << 0
#GTK_STATE_FLAG_PRELIGHT     = 1 << 1
#GTK_STATE_FLAG_SELECTED     = 1 << 2
#GTK_STATE_FLAG_INSENSITIVE  = 1 << 3
#GTK_STATE_FLAG_INCONSISTENT = 1 << 4
#GTK_STATE_FLAG_FOCUSED      = 1 << 5
#GTK_STATE_FLAG_BACKDROP     = 1 << 6
#GTK_STATE_FLAG_DIR_LTR      = 1 << 7
#GTK_STATE_FLAG_DIR_RTL      = 1 << 8

Structure GdkRGBA
  red.d;
  green.d;
  blue.d;
  alpha.d;
EndStructure

Procedure.l GetWindowColorEx(Window)
  Protected r1, context, color.GdkRGBA
  
  context = gtk_widget_get_style_context(WindowID(Window))
  gtk_style_context_get_background_color(context, #GTK_STATE_FLAG_NORMAL, @color)
  r1 = RGBA(color\red * 255, color\green * 255, color\blue * 255, color\alpha * 255)
  ProcedureReturn r1
EndProcedure

; ****

Enumeration Windows
  #Main
EndEnumeration

Enumeration MenuBar
  #MainMenu
EndEnumeration

Enumeration MenuItems
  
EndEnumeration

Enumeration Gadgets
  #MainEdit
  #MainButton1
  #MainButton2
EndEnumeration

Enumeration StatusBar
  #MainStatusBar
EndEnumeration

Procedure UpdateWindow()
  Protected dx, dy
  dx = WindowWidth(#Main)
  dy = WindowHeight(#Main) - StatusBarHeight(#MainStatusBar)
  ; Resize gadgets
  ResizeGadget(#MainEdit, 5, 5, dx -10, dy - 45)
  ResizeGadget(#MainButton1, 10, dy - 35, 120, 30)
  ResizeGadget(#MainButton2, dx - 130, dy - 35, 120, 30)
EndProcedure

Procedure Main()
  Protected dx, dy, Theme.s
  
  #MainStyle = #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MaximizeGadget | #PB_Window_MinimizeGadget
  
  If OpenWindow(#Main, #PB_Ignore, #PB_Ignore, 800, 600, "Window" , #MainStyle | #PB_Window_Invisible)
    ; Menu
    CreateMenu(#MainMenu, WindowID(#Main))
    
    ; StatusBar
    CreateStatusBar(#MainStatusBar, WindowID(#Main))
    AddStatusBarField(#PB_Ignore)
    
    ; Gadgets
    dx = WindowWidth(#Main)
    dy = WindowHeight(#Main) - StatusBarHeight(#MainStatusBar)
    EditorGadget(#MainEdit, 5, 5, dx -10, dy - 45)
    ButtonGadget(#MainButton1, 10, dy - 35, 120, 30, "Set Dark")
    ButtonGadget(#MainButton2, dx - 130, dy - 35, 120, 30, "Clear Dark")
    
    Theme = GetThemeName()
    AddGadgetItem(#MainEdit, -1, "System Theme Name: " +  GetThemeName())
    
    Theme = "Adwaita"
    SetThemeName(Theme)
    AddGadgetItem(#MainEdit, -1, "App Theme Name: " +  GetThemeName())
    
    If Not IsDarkMode()
      SetDarkMode(#True)
    EndIf
    
    ; Bind Events
    BindEvent(#PB_Event_SizeWindow, @UpdateWindow(), #Main)
    
    HideWindow(#Main, 0)
    
    Repeat
      Select WaitWindowEvent()
        Case #PB_Event_CloseWindow
          Break
          
        Case #PB_Event_Menu
          Select EventMenu()
            CompilerIf #PB_Compiler_OS = #PB_OS_MacOS   
              Case #PB_Menu_About
                
              Case #PB_Menu_Preferences
                
              Case #PB_Menu_Quit
                PostEvent(#PB_Event_CloseWindow, #Main, #Null)
                
            CompilerEndIf
              
          EndSelect
          
        Case #PB_Event_Gadget
          Select EventGadget()
            Case #MainEdit
              Select EventType()
                Case #PB_EventType_Change
                  ;
              EndSelect
              
            Case #MainButton1
              Select EventType()
                Case #PB_EventType_LeftClick
                  If SetDarkMode(#True)
                    StatusBarText(#MainStatusBar, 0, " Old DarkMode: True")
                  Else
                    StatusBarText(#MainStatusBar, 0, " Old DarkMode: False")
                  EndIf
                  
              EndSelect
              Debug "$" + RSet(Hex(GetWindowColorEx(#Main), #PB_Long), 8, "0")
              
            Case #MainButton2
              Select EventType()
                Case #PB_EventType_LeftClick
                  If SetDarkMode(#False)
                    StatusBarText(#MainStatusBar, 0, " Old DarkMode: True")
                  Else
                    StatusBarText(#MainStatusBar, 0, " Old DarkMode: False")
                  EndIf
                  
              EndSelect
              Debug "$" + RSet(Hex(GetWindowColorEx(#Main), #PB_Long), 8, "0")
              
          EndSelect
          
      EndSelect
    ForEver
    
  EndIf
  
EndProcedure : Main()
Last edited by mk-soft on Fri Aug 22, 2025 12:13 pm, edited 3 times in total.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
kenmo
Addict
Addict
Posts: 2036
Joined: Tue Dec 23, 2003 3:54 am

Re: GTK3 DarkMode

Post by kenmo »

Nice!!!!! Thanks!
User avatar
mk-soft
Always Here
Always Here
Posts: 6233
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: GTK3 DarkMode

Post by mk-soft »

Update v1.02.2
- Warning on new kernel: Change set/get property

I was bothered by the compiler warnings from g_object_get/set on the new kernel 6.12

Unfortunately, this only works with themes that support both modes. Like Adwaita or with many themes of Mint Linux.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Post Reply