Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor DBus plugin and its child plugins #290

Closed
wants to merge 14 commits into from
4 changes: 2 additions & 2 deletions yin_yang/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from yin_yang.config import config, Modes
from yin_yang.ui import main_window_connector

logger = logging.getLogger()
logger = logging.getLogger(__name__)


def setup_logger(use_systemd_journal: bool):
Expand Down Expand Up @@ -97,7 +97,7 @@ def systray_icon_clicked(reason: QSystemTrayIcon.ActivationReason):
logger.debug(f'Using language {lang}')

# system translations
path = QLibraryInfo.path(QLibraryInfo.TranslationsPath)
path = QLibraryInfo.path(QLibraryInfo.LibraryPath.TranslationsPath)
translator = QTranslator(app)
if translator.load(QLocale.system(), 'qtbase', '_', path):
app.installTranslator(translator)
Expand Down
3 changes: 2 additions & 1 deletion yin_yang/plugins/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from typing import List
from ..meta import Desktop
from . import system, colors, gtk, icons, kvantum, wallpaper, custom
from . import firefox, only_office, okular
Expand All @@ -9,7 +10,7 @@
from yin_yang.plugins._plugin import Plugin, ExternalPlugin


def get_plugins(desktop: Desktop) -> [Plugin]:
def get_plugins(desktop: Desktop) -> List[Plugin]:
return [
system.System(desktop),
colors.Colors(desktop),
Expand Down
40 changes: 31 additions & 9 deletions yin_yang/plugins/_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
from abc import ABC, abstractmethod
from configparser import ConfigParser
from pathlib import Path
from typing import Optional, List
from typing import List, Optional

from PySide6.QtDBus import QDBusConnection, QDBusMessage
from PySide6.QtGui import QColor, QRgba64
from PySide6.QtWidgets import QGroupBox, QHBoxLayout, QLineEdit, QComboBox
from PySide6.QtWidgets import QComboBox, QGroupBox, QHBoxLayout, QLineEdit

from ..meta import UnsupportedDesktopError, FileFormat
from ..meta import FileFormat, UnsupportedDesktopError

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -253,25 +253,45 @@ def set_theme(self, theme: str):


class DBusPlugin(Plugin):
def __init__(self):
"""A class for plugins that mainly switching theme via DBus"""
def __init__(self, message_data: List[str]):
super().__init__()
self.connection = QDBusConnection.sessionBus()
self.message: QDBusMessage
self.message_data: List[str] = message_data # Store DBusMessage data(destination, path, interface, method)

def set_theme(self, theme: str):
"""Check arguments, create DBus message and then call"""
if not (self.available and self.enabled):
return

if not theme:
raise ValueError(f'Theme \"{theme}\" is invalid')

self.call(self.create_message(theme))
self.create_message(theme)
self.call()

@abstractmethod
def create_message(self, theme: str) -> QDBusMessage:
def create_message(self, theme: str) -> None:
heddxh marked this conversation as resolved.
Show resolved Hide resolved
raise NotImplementedError(f'Plugin {self.name} did not implement create_message()')

def call(self, message) -> QDBusMessage:
return self.connection.call(message)
def call(self) -> QDBusMessage:
return self.connection.call(self.message)

def list_paths(self, service: str, path: str) -> List[str]:
""" Get all subpath under given pth of service
heddxh marked this conversation as resolved.
Show resolved Hide resolved
:path: should start with / but without / on its end
"""
assert path.startswith('/') and not path.endswith('/'), "list_paths wrong, :path: should start with / but without / on its end"
msg = QDBusMessage.createMethodCall(service, path, "org.freedesktop.DBus.Introspectable", "Introspect")
reply = self.connection.call(msg)
if reply.errorName():
logger.debug(f"No subpath available under {service} {path}")
return []

xml = reply.arguments()[0]
sub_path_names = [line.split('"')[1] for line in xml.split("\n") if line.startswith(" <node name=")]
return [path + '/' + sub for sub in sub_path_names]


class ConfigFilePlugin(Plugin):
Expand All @@ -295,7 +315,7 @@ def open_config(self, path: Path):
case FileFormat.JSON.value:
try:
return json.load(file)
except json.decoder.JSONDecodeError as e:
except json.decoder.JSONDecodeError:
return self.default_config
case FileFormat.CONFIG.value:
config = ConfigParser()
Expand All @@ -308,8 +328,10 @@ def open_config(self, path: Path):
def write_config(self, value: str | ConfigParser, path: Path, **kwargs):
with open(path, 'w') as file:
if self.file_format.value == FileFormat.CONFIG.value:
assert type(value) is ConfigParser, "Should passing ConfigParser"
value.write(file, **kwargs)
else:
assert type(value) is str, "Should passing str"
file.write(value)

def set_theme(self, theme: str, ignore_theme_check=False):
Expand Down
42 changes: 23 additions & 19 deletions yin_yang/plugins/gtk.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ def __init__(self):
@property
def available(self) -> bool:
return test_gnome_availability(self.command)


class _Budgie(PluginCommandline):
name = 'GTK'

Expand All @@ -68,48 +68,52 @@ def available(self) -> bool:


class _Kde(DBusPlugin):
name = 'GTK'
@property
def name(self):
return 'GTK'

def __init__(self):
super().__init__()
super().__init__(['org.kde.GtkConfig', '/GtkConfig', 'org.kde.GtkConfig', 'setGtkTheme'])
self.theme_light = 'Breeze'
self.theme_dark = 'Breeze'

def create_message(self, theme: str) -> QDBusMessage:
message = QDBusMessage.createMethodCall(
'org.kde.GtkConfig',
'/GtkConfig',
'org.kde.GtkConfig',
'setGtkTheme'
)
message.setArguments([theme])
return message
def create_message(self, theme: str):
self.message = QDBusMessage.createMethodCall(*self.message_data)
self.message.setArguments([theme])

def set_theme(self, theme: str):
response = self.call(self.create_message(theme))
"""Call DBus interface of kde-gtk-config if installed.
Otherwise try changing xsettingsd's conf and dconf"""

if response.type() != QDBusMessage.MessageType.ErrorMessage:
if self.connection.interface().isServiceRegistered('org.kde.GtkConfig').value():
logger.debug("Detected kde-gtk-config, use it")
super().set_theme(theme)
return

logger.warning('kde-gtk-config not available, trying xsettingsd')
# User don't have kde-gtk-config installed, try xsettingsd and dconf
logger.warning('kde-gtk-config not available, trying xsettingsd and dconf')

# xsettingsd
xsettingsd_conf_path = Path.home() / '.config/xsettingsd/xsettingsd.conf'
if not xsettingsd_conf_path.exists():
logger.warning('xsettingsd not available')
return

with open(xsettingsd_conf_path, 'r') as f:
lines = f.readlines()
for i, line in enumerate(lines):
if line.startswith('Net/ThemeName'):
lines[i] = f'Net/ThemeName "{theme}"\n'
break

with open(xsettingsd_conf_path, 'w') as f:
f.writelines(lines)

# send signal to read new config
subprocess.run(['killall', '-HUP', 'xsettingsd'])

# change dconf db. since dconf sending data as GVariant, use gsettings instead
subprocess.run(['gsettings', 'set', 'org.gnome.desktop.interface', 'gtk-theme', f'{theme}'])
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't get rid of external command here. But since they are fallback method, can we avoid running them when under flatpak build? (Not read #185 yet, is there an easy way to detect that?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I think I got it. Waiting for that PR to be merged

color_scheme = 'prefer-dark' if theme == self.theme_dark else 'prefer-light'
subprocess.run(['gsettings', 'set', 'org.gnome.desktop.interface', 'color-scheme', f'{color_scheme}'])


class _Xfce(PluginCommandline):
def __init__(self):
Expand Down
Loading