diff --git a/CHANGELOG b/CHANGELOG
index df5fa0a68..56b0a08eb 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,8 @@
#Nmap Changelog ($Id$); -*-text-*-
+o [Zenmap][GH#2358] Added dark mode, accessed via Help->Toggle Dark Mode or
+ window::dark_mode in zenmap.conf. [Daniel Miller]
+
o Upgraded included libraries: Lua 5.4.7, libssh2 1.11.1, libpcap 1.10.5,
libpcre 10.45
diff --git a/zenmap/zenmapCore/UmitConf.py b/zenmap/zenmapCore/UmitConf.py
index 876378a05..3f602e90b 100644
--- a/zenmap/zenmapCore/UmitConf.py
+++ b/zenmap/zenmapCore/UmitConf.py
@@ -84,6 +84,14 @@ except ImportError:
def is_maemo():
return MAEMO
+def boolean_sanity(attr):
+ if attr is True or \
+ attr == "True" or \
+ attr == "true" or \
+ attr == "1":
+ return "True"
+ return "False"
+
class SearchConfig(UmitConfigParser, object):
section_name = "search"
@@ -109,14 +117,6 @@ class SearchConfig(UmitConfigParser, object):
def _set_it(self, p_name, value):
config_parser.set(self.section_name, p_name, value)
- def boolean_sanity(self, attr):
- if attr is True or \
- attr == "True" or \
- attr == "true" or \
- attr == "1":
- return "True"
- return "False"
-
def get_directory(self):
return self._get_it("directory", "")
@@ -142,16 +142,16 @@ class SearchConfig(UmitConfigParser, object):
self._set_it("save_time", save_time)
def get_store_results(self):
- return self.boolean_sanity(self._get_it("store_results", True))
+ return boolean_sanity(self._get_it("store_results", True))
def set_store_results(self, store_results):
- self._set_it("store_results", self.boolean_sanity(store_results))
+ self._set_it("store_results", boolean_sanity(store_results))
def get_search_db(self):
- return self.boolean_sanity(self._get_it("search_db", True))
+ return boolean_sanity(self._get_it("search_db", True))
def set_search_db(self, search_db):
- self._set_it("search_db", self.boolean_sanity(search_db))
+ self._set_it("search_db", boolean_sanity(search_db))
def get_converted_save_time(self):
try:
@@ -251,6 +251,7 @@ class WindowConfig(UmitConfigParser, object):
default_y = 0
default_width = -1
default_height = 650
+ default_dark_mode = False
def __init__(self):
if not config_parser.has_section(self.section_name):
@@ -265,6 +266,7 @@ class WindowConfig(UmitConfigParser, object):
self.y = self.default_y
self.width = self.default_width
self.height = self.default_height
+ self.dark_mode = self.default_dark_mode
def _get_it(self, p_name, default):
return config_parser.get(self.section_name, p_name, fallback=default)
@@ -340,10 +342,17 @@ class WindowConfig(UmitConfigParser, object):
def set_height(self, height):
self._set_it("height", "%d" % height)
+ def get_dark_mode(self):
+ return boolean_sanity(self._get_it("dark_mode", self.default_dark_mode))
+
+ def set_dark_mode(self, mode):
+ self._set_it("dark_mode", boolean_sanity(mode))
+
x = property(get_x, set_x)
y = property(get_y, set_y)
width = property(get_width, set_width)
height = property(get_height, set_height)
+ dark_mode = property(get_dark_mode, set_dark_mode)
class CommandProfile (Profile, object):
diff --git a/zenmap/zenmapGUI/MainWindow.py b/zenmap/zenmapGUI/MainWindow.py
index ca0d7f452..afefe76b6 100644
--- a/zenmap/zenmapGUI/MainWindow.py
+++ b/zenmap/zenmapGUI/MainWindow.py
@@ -132,6 +132,9 @@ class ScanWindow(UmitScanWindow):
UmitScanWindow.__init__(self)
window = WindowConfig()
+ settings = Gtk.Settings.get_default()
+ settings.set_property("gtk-application-prefer-dark-theme",
+ window.dark_mode)
self.set_title(_(APP_DISPLAY_NAME))
self.move(window.x, window.y)
@@ -303,6 +306,13 @@ class ScanWindow(UmitScanWindow):
None,
_('Shows the application help'),
self._help_cb),
+
+ ('Toggle Dark Mode',
+ None,
+ _('Toggle Dark Mode'),
+ None,
+ None,
+ self._toggle_dark),
]
# See info on UIManager at:
@@ -351,6 +361,7 @@ class ScanWindow(UmitScanWindow):
+
@@ -767,6 +778,14 @@ This scan has not been run yet. Start the scan with the "Scan" button first.'))
def _help_cb(self, action):
self.show_help()
+ def _toggle_dark(self, action):
+ window = WindowConfig()
+ window.dark_mode = not window.dark_mode
+ settings = Gtk.Settings.get_default()
+ settings.set_property("gtk-application-prefer-dark-theme",
+ window.dark_mode)
+
+
def _exit_cb(self, *args):
"""Closes the window, prompting for confirmation if necessary. If one
of the tabs couldn't be closed, the function returns True and doesn't