# Qube Manager & Tools: Dark Mode
| # Qubes OS - Qubes tools - Dark mode
---
## Preview
|
Add an option in the view menu to enable/disable dark mode.
The script must be launch in a dom0 terminal.
Make sure to have only `space` character for python part.
If you have `tab` character, qube manager will fail to start.
Dark mode can be set in the qube-manager config file:
`$HOME/.config/The Qubes Project/qubes-qube-manager.conf`
```
| 
## Introduction
---
See the first reply for simpler methods.
### Description
Add an option in the view menu of Qube Manager to enable/disable dark mode.
Dark mode can also be set in the Qube Manager config file:
```bash
[user@dom0 ~]$ cat "$HOME/.config/The Qubes Project/qubes-qube-manager.conf"
[...]
|
## Stylesheet
Colors are based on Arc-Dark theme.
You can extract the css file from your theme with `gresource`.
| This script is a one-file format (single `.sh` file).
### Usage
Copy the script to `dom0`, make it executable, then launch it.
[qubes-os.org/doc/how-to-copy-from-dom0/#copying-to-dom0](https://qubes-os.org/doc/how-to-copy-from-dom0/#copying-to-dom0)
> :warning: **Caution**:
> The code you run in dom0 **MUST** be understood.
|
qubes_cfg_dir="$HOME/.config//The Qubes Project/"
dark_stylesheet=dark-stylesheet.css
echo '
| file_name=qubes_tools_dark_mode.sh
qvm-run --pass-io sys-usb "
cat /home/user/$file_name" > $HOME/$file_name
chmod +x $HOME/$file_name
$HOME/$file_name
```
Make sure to have only `space` characters for python code.
If you have `tab` characters, Qube Manager & Tools will fail to start.
## Theme colors
---
You can extract the CSS file of your theme with the `gresource` utility.
If `gresource` isn't available, you need to install the package that contain it.
[details="Fedora"]
```bash
[user@disp42 ~]$ sudo dnf install glib2-devel
```
[/details]
[details="Debian"]
```bash
[user@disp42 ~]$ sudo apt install libglib2.0-bin
```
[/details]
e.g.
List the files of your `gtk.gresource` theme.
```bash
[user@disp42 ~]$ gresource list /usr/share/themes/Arc-Dark/gtk-3.0/gtk.gresource
[...]
/org/gnome/arc-theme/gtk-main.css
```
Once the file path is known, extract it.
```bash
[user@disp42 ~]$ gresource extract /usr/share/themes/Arc-Dark/gtk-3.0/gtk.gresource /org/gnome/arc-theme/gtk-main.css > gtk-arc-dark.css
```
You may want to use an online CSS formatter to make it easier to read.
You can now find the color values you want to use.
## CSS file
---
Colors are based on the Arc-Dark theme.
[details="CSS content"]
```bash
#!/usr/bin/bash
set -eu -o pipefail
css_content='
|
}' > "$qubes_cfg_dir/$dark_stylesheet"
| }'
```
[/details]
Save the css file in the 'Qubes Project' config directory.
It can be an other directory (e.g. `$HOME/Documents`).
```bash
qubes_cfg_dir="$HOME/.config/The Qubes Project/"
css_file=dark-stylesheet.css
echo "$css_content" > "$qubes_cfg_dir/$css_file"
```
## Qubes Tools
---
Location of the Qubes Tools files.
```bash
python_version=$(python3 --version | grep -Eo '[0-9]+\.[0-9]+')
lib_python_dir=/usr/lib/python$python_version/site-packages/
qm_dir=$lib_python_dir/qubesmanager/
|
## Function
Terms to feed to your favorite search engine:
- bash sed
- bash <()
- bash function $#
- bash function $@
- bash if [[ ]]
- bash recursive function
Bash command `<()` doesn't handle sudo.
Just like file redirection (`text > file`) doesn't.
A backup file is made for each file!
| Helper function to backup a file (to be able to reverse the changes).
[details="create_backup_file ()"]
|
python_version=$(python3 --version | grep -Eo '[0-9]+\.[0-9]+')
qm_dir=/usr/lib/python$python_version/site-packages/qubesmanager/
| create_backup_file ()
{
if [ ! -f $1.bak ]
then
sudo cp $1 $1.bak
fi
}
```
[/details]
Helper function to add our code to the Qubes files.
[details="add_data_after_pattern ()"]
```bash
|
sed -i -E "/$2/ r"<(echo "$3") $1
handle_data $1 "${@:4}"
| echo "$3" | sudo tee /tmp/qm_content.tmp > /dev/null
sudo sed -i -E "/$2/ r /tmp/qm_content.tmp" $1
$FUNCNAME $1 "${@:4}"
|
local qtmp=$HOME/$1
if [ ! -f $qtool.bak ]; then
sudo cp $qtool $qtool.bak
fi
sudo cp $qtool $qtmp
sudo chown user:user $qtmp
handle_data $qtmp "${@:2}"
sudo mv $qtmp $qtool
sudo chown root:root $qtool
| create_backup_file $qtool
handle_data $qtool "${@:2}"
|
```
## Qubes tools
If setting is set to dark mode, use our css stylesheet.
| ```
[/details]
Enable dark mode (or not) according to the setting made in Qube Manager.
[details="add_dark_mode ()"]
|
stylesheet = open(qubes_cfg_dir + '$dark_stylesheet', 'r')
self.setStyleSheet(stylesheet.read())
stylesheet.close()"
| with open(qubes_cfg_dir + '$css_file') as css_file:
self.setStyleSheet(css_file.read())"
|
| ```
[/details]
Add our code to the Qubes Tools files.
(`template_manager.py` is actually the code for Template Switcher).
For 4.2, remove `global_settings.py`.
```bash
|
| backup.py \
clone_vm.py \
create_new_vm.py \
|
| log_dialog.py \
restore.py \
|
template_manager.py \
create_new_vm.py \
clone_vm.py \
backup.py \
restore.py \
log_dialog.py
| template_manager.py
|
## Qube manager
Add a toggle option in the view menu.
| ### Template Manager (4.2)
Add our code to the Template Manager tool.
|
| add_dark_mode qvm_template_gui.py
sudo sed -i -E -e '/^import PyQt5\.QtWidgets/ a from PyQt5 import QtCore' \
-e 's/self, actions/&, parent=None/' \
-e 's/TemplateInstallConfirmDialog\(actions/&, parent/' \
-e 's/TemplateInstallProgressDialog\(actions/&, parent/' \
-e 's/do_install\(self/&, parent=None/' \
$qm_dir/qvm_template_gui.py
```
### Global Config, Policy Editor, Update & Create New Qube (4.2)
Make the new GUI tools use Arc-Dark theme values.
```bash
qui_dark_css=$lib_python_dir/qui/styles/qubes-colors-dark.css
create_backup_file $qui_dark_css
sudo sed -i -E -e '/top-background / s/#[^;]+/#2F343F/' \
-e '/top-background-2/ s/#[^;]+/#383C4A/' \
-e '/bottom-background/ s/#[^;]+/#404552/' \
-e '/background-frame/ s/#[^;]+/#252A32/' \
$qui_dark_css
```
### Application menu (4.2)
Make the menu use Arc-Dark theme values.
(need logout or kill & restart the new menu to take effect)
```bash
qmenu_dark_css=$lib_python_dir/qubes_menu/qubes-menu-dark.css
create_backup_file $qmenu_dark_css
sudo sed -i -E -e '/left-background/ s/#[^;]+/#383C4A/' \
-e '/right-background/ s/#[^;]+/#404552/' \
-e '/outer-background/ s/#[^;]+/#252A32/' \
$qmenu_dark_css
```
## Qube Manager
---
### ui_qubemanager.py
Widget to be added in the view menu.
[details="qm_darkmode_widget"]
```bash
qm_darkmode_widget="
self.action_dark_mode = QtWidgets.QAction(VmManagerWindow)
self.action_dark_mode.setCheckable(True)
self.action_dark_mode.setChecked(False)
self.action_dark_mode.setObjectName('action_dark_mode')"
```
[/details]
Text displayed in the view menu.
[details="qm_darkmode_text"]
```bash
qm_darkmode_text="
self.action_dark_mode.setText(_translate('VmManagerWindow', 'Dark mode'))"
```
[/details]
Add our code to `ui_qubemanager.py`.
```bash
add_data_after_pattern ui_qubemanager.py \
'"action_compact_view"' "$qm_darkmode_widget" \
'Compact view' "$qm_darkmode_text"
```
### qube_manager.py
Add the dark mode widget to the existing view menu.
[details="qm_darkmode_menu"]
```bash
qm_darkmode_menu="
self.menu_view.addAction(self.action_dark_mode)"
```
[/details]
Restore the preference of light or dark mode.
[details="qm_darkmode_restore"]
```bash
qm_darkmode_restore="
if self.manager_settings.value('view/darkmode',
defaultValue='false') != 'false':
self.action_dark_mode.setChecked(True)"
```
[/details]
Enable or disable dark mode when we click on the menu item.
Save the preference in the config file.
[details="qm_set_darkmode"]
```bash
|
stylesheet = open(qubes_cfg_dir + '$dark_stylesheet', 'r')
self.setStyleSheet(stylesheet.read())
stylesheet.close()
| with open(qubes_cfg_dir + '$css_file') as css_file:
self.setStyleSheet(css_file.read())
|
self.manager_settings.setValue('view/darkmode', checked)"
qm_menu () {
echo " self.menu_view.addAction(self.$1)"
}
qm_darkmode_menu=$(qm_menu action_dark_mode)
qm_restore () {
echo "
if self.manager_settings.value('$1',
defaultValue='false') != 'false':
self.action_dark_mode.setChecked(True)"
}
qm_darkmode_restore=$(qm_restore 'view/darkmode')
| self.manager_settings.setValue('view/darkmode', checked)"
```
[/details]
Add our code to `qube_manager.py`.
```bash
|
'self\.close' "$qm_set_darkmode" \
| |
'Action\(self\.action_compact_view' "$qm_darkmode_menu"
```
Create the Qt widget to handle dark mode. (Qt is the gui framework)
| 'Action\(self\.action_compact_view' "$qm_darkmode_menu" \
'self\.close' "$qm_set_darkmode"
```
## Restore backup
---
A script to restore the backup files.
In case the Dark Mode doesn't behave as expected.
[details="restore_backup_file ()"]
|
qm_widget () {
echo "
self.$1 = QtWidgets.QAction(VmManagerWindow)
self.$1.setCheckable(True)
self.$1.setChecked($2)
self.$1.setObjectName('$1')"
}
qm_darkmode_widget=$(qm_widget action_dark_mode 'False')
qm_text () {
echo " self.$1.$2(_translate('VmManagerWindow', '$3'))"
}
qm_darkmode_text=$(qm_text action_dark_mode setText 'Dark mode')
add_data_after_pattern ui_qubemanager.py \
'"action_compact_view"' "$qm_darkmode_widget" \
'Compact view' "$qm_darkmode_text"
```
## Note
qube manager version: 4.1.25-1
Dark mode will be erase if qube manager get updated. | #!/bin/bash
python_version=$(python3 --version | grep -Eo '[0-9]+\.[0-9]+')
lib_python_dir=/usr/lib/python$python_version/site-packages/
qm_dir=$lib_python_dir/qubesmanager/
restore_backup_file ()
{
for qtool in $@
do
if [ -f $qtool.bak ]
then
sudo cp $qtool.bak $qtool
else
echo "${qtool##*/}: no backup file"
fi
done
}
restore_backup_file \
$qm_dir/backup.py \
$qm_dir/clone_vm.py \
$qm_dir/create_new_vm.py \
$qm_dir/log_dialog.py \
$qm_dir/restore.py \
$qm_dir/settings.py \
$qm_dir/template_manager.py \
$qm_dir/qube_manager.py \
$qm_dir/ui_qubemanager.py
# 4.2
qui_dark_css=$lib_python_dir/qui/styles/qubes-colors-dark.css
qmenu_dark_css=$lib_python_dir/qubes_menu/qubes-menu-dark.css
restore_backup_file \
$qm_dir/qvm_template_gui.py \
$qui_dark_css \
$qmenu_dark_css
```
[/details]
## Remarks
---
The dark mode will be erased on Qube Manager update.
<div data-theme-toc="true"> </div> |