@@ -271,6 +271,47 @@ def _needs_save():
271271 # No need to prompt for save
272272 return False
273273
274+ def _detect_system_dark_mode ():
275+ if sys .platform == "win32" :
276+ try :
277+ import winreg
278+ registry = winreg .ConnectRegistry (None , winreg .HKEY_CURRENT_USER )
279+ key = winreg .OpenKey (registry ,
280+ r"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" )
281+ value , _ = winreg .QueryValueEx (key , "AppsUseLightTheme" )
282+ winreg .CloseKey (key )
283+ return value == 0
284+ except (ImportError , OSError , WindowsError ) as _ :
285+ return False
286+
287+ elif sys .platform .startswith ("linux" ):
288+ if os .getenv ('GTK_THEME' , '' ).lower ().find ('dark' ) != - 1 :
289+ return True
290+
291+ import subprocess
292+ try :
293+ result = subprocess .run (
294+ ["gsettings" , "get" , "org.gnome.desktop.interface" , "gtk-theme" ],
295+ capture_output = True , text = True
296+ )
297+ if "dark" in result .stdout .lower ():
298+ return True
299+ except (subprocess .SubprocessError , OSError ) as _ :
300+ pass
301+
302+ try :
303+ result = subprocess .run (
304+ ["kreadconfig5" , "--group" , "General" , "--key" , "ColorScheme" ],
305+ capture_output = True , text = True
306+ )
307+ if "dark" in result .stdout .lower ():
308+ return True
309+ except (subprocess .SubprocessError , OSError ) as _ :
310+ return False
311+
312+ # TK 8.6.9+ supports dark mode natively on macOS
313+ return False
314+
274315
275316def _create_id_to_node ():
276317 global _id_to_node
@@ -393,6 +434,8 @@ def _fix_treeview_issues():
393434
394435def _init_misc_ui ():
395436 # Does misc. UI initialization, like setting the title, icon, and theme
437+ global _dark_mode
438+ _dark_mode = _detect_system_dark_mode ()
396439
397440 _root .title (_kconf .mainmenu_text )
398441 # iconphoto() isn't available in Python 2's Tkinter
@@ -404,10 +447,69 @@ def _init_misc_ui():
404447
405448 # Use the 'clam' theme on *nix if it's available. It looks nicer than the
406449 # 'default' theme.
407- if _root . tk . call ( "tk" , "windowingsystem" ) == "x11" :
450+ if _dark_mode :
408451 style = ttk .Style ()
409- if "clam" in style .theme_names ():
410- style .theme_use ("clam" )
452+ _root .configure (bg = '#2b2b2b' )
453+
454+ style .theme_use ('clam' )
455+
456+ style .configure ("." ,
457+ background = '#2b2b2b' ,
458+ foreground = '#ffffff' ,
459+ fieldbackground = '#3c3c3c' ,
460+ bordercolor = '#404040' ,
461+ darkcolor = '#222222' ,
462+ lightcolor = '#404040' ,
463+ selectbackground = '#5a5a5a' ,
464+ selectforeground = '#ffffff' )
465+
466+ style .configure ("Treeview" ,
467+ background = '#3c3c3c' ,
468+ foreground = '#ffffff' ,
469+ fieldbackground = '#3c3c3c' )
470+ style .configure ("Treeview.Heading" ,
471+ background = '#404040' ,
472+ foreground = '#ffffff' )
473+ style .map ("Treeview.Heading" ,
474+ background = [('active' , '#5a5a5a' )],
475+ foreground = [('active' , '#ffffff' )])
476+ style .map ('Treeview' ,
477+ background = [('selected' , '#5a5a5a' )],
478+ foreground = [('selected' , '#ffffff' )])
479+
480+ style .configure ("TButton" ,
481+ background = '#404040' ,
482+ foreground = '#ffffff' ,)
483+ style .map ("TButton" ,
484+ background = [('active' , '#5a5a5a' )])
485+
486+ style .configure ("TEntry" ,
487+ fieldbackground = '#3c3c3c' ,
488+ foreground = '#ffffff' ,
489+ insertcolor = '#ffffff' )
490+
491+ style .configure ("TLabel" ,
492+ background = '#2b2b2b' ,
493+ foreground = '#ffffff' )
494+
495+ style .configure ("TFrame" ,
496+ background = '#2b2b2b' )
497+
498+ style .configure ("TCheckbutton" ,
499+ background = '#2b2b2b' ,
500+ foreground = '#ffffff' ,
501+ focuscolor = 'none' )
502+ style .map ("TCheckbutton" ,
503+ background = [('active' , '#3c3c3c' )],
504+ foreground = [('active' , '#ffffff' )])
505+
506+ style .configure ("TPanedwindow" ,
507+ background = '#2b2b2b' )
508+ else :
509+ if _root .tk .call ("tk" , "windowingsystem" ) == "x11" :
510+ style = ttk .Style ()
511+ if "clam" in style .theme_names ():
512+ style .theme_use ("clam" )
411513
412514
413515def _create_top_widgets ():
@@ -584,12 +686,22 @@ def _create_kconfig_desc(parent):
584686
585687 frame = ttk .Frame (parent )
586688
587- desc = Text (frame , height = 12 , wrap = "none" , borderwidth = 0 ,
588- state = "disabled" )
589- desc .grid (column = 0 , row = 0 , sticky = "nsew" )
689+ if _dark_mode :
690+ desc = Text (frame , height = 12 , wrap = "word" , borderwidth = 0 ,
691+ state = "disabled" ,
692+ bg = '#3c3c3c' ,
693+ fg = '#ffffff' ,
694+ insertbackground = '#ffffff' ,
695+ selectbackground = '#5a5a5a' ,
696+ selectforeground = '#ffffff' ,
697+ relief = 'flat' )
698+ else :
699+ desc = Text (frame , height = 12 , wrap = "word" , borderwidth = 0 ,
700+ state = "disabled" )
590701
591702 # Work around not being to Ctrl-C/V text from a disabled Text widget, with a
592703 # tip found in https://stackoverflow.com/questions/3842155/is-there-a-way-to-make-the-tkinter-text-widget-read-only
704+ desc .grid (column = 0 , row = 0 , sticky = "nsew" )
593705 desc .bind ("<1>" , lambda _ : desc .focus_set ())
594706
595707 _add_vscrollbar (frame , desc )
@@ -1194,6 +1306,10 @@ def cancel(_=None):
11941306 sym = node .item
11951307
11961308 dialog = Toplevel (parent )
1309+
1310+ if _dark_mode :
1311+ dialog .configure (bg = '#2b2b2b' )
1312+
11971313 dialog .title ("Enter {} value" .format (TYPE_TO_STR [sym .type ]))
11981314 dialog .resizable (False , False )
11991315 dialog .transient (parent )
@@ -1780,6 +1896,10 @@ def tree_select(_):
17801896
17811897
17821898 dialog = Toplevel (_root )
1899+
1900+ if _dark_mode :
1901+ dialog .configure (bg = '#2b2b2b' )
1902+
17831903 dialog .geometry ("+{}+{}" .format (
17841904 _root .winfo_rootx () + 50 , _root .winfo_rooty () + 50 ))
17851905 dialog .title ("Jump to symbol/choice/menu/comment" )
0 commit comments