| Server IP : 104.21.25.180 / Your IP : 104.23.197.123 Web Server : Apache/2.4.37 System : Linux almalinux.duckdns.org 4.18.0-553.111.1.el8_10.x86_64 #1 SMP Sun Mar 8 20:06:07 EDT 2026 x86_64 User : ricodeal ( 1046) PHP Version : 7.4.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /lib/python3.6/site-packages/gtweak/ |
Upload File : |
# Copyright (c) 2011 John Stowers
# SPDX-License-Identifier: GPL-3.0+
# License-Filename: LICENSES/GPL-3.0
import os.path
import logging
import tempfile
import shutil
import subprocess
import glob
import itertools
import gtweak
from gtweak.gsettings import GSettingsSetting
import gi
gi.require_version("Notify", "0.7")
from gi.repository import GObject
from gi.repository import GLib
from gi.repository import Gio
from gi.repository import Notify
def singleton(cls):
"""
Singleton decorator that works with GObject derived types. The 'recommended'
python one - http://wiki.python.org/moin/PythonDecoratorLibrary#Singleton
does not (interacts badly with GObjectMeta
"""
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance
def make_combo_list_with_default(opts, default, title=True, default_text=None):
"""
Turns a list of values into a list of value,name (where name is the
display name a user will see in a combo box). If a value is opt is
equal to that supplied in default the display name for that value is
modified to "value <i>(default)</i>"
@opts: a list of value
@returns: a list of 2-tuples (value, name)
"""
themes = []
for t in opts:
if t.lower() == "default" and t != default:
#some themes etc are actually called default. Ick. Dont show them if they
#are not the actual default value
continue
if title and len(t):
name = t[0].upper() + t[1:]
else:
name = t
if t == default:
#indicates the default theme, e.g Adwaita (default)
name = default_text or _("%s <i>(default)</i>") % name
themes.append((t, name))
return themes
def walk_directories(dirs, filter_func):
valid = []
try:
for thdir in dirs:
if os.path.isdir(thdir):
for t in os.listdir(thdir):
if filter_func(os.path.join(thdir, t)):
valid.append(t)
except:
logging.critical("Error parsing directories", exc_info=True)
return valid
def extract_zip_file(z, members_path, dest):
""" returns (true_if_extracted_ok, true_if_updated) """
tmp = tempfile.mkdtemp()
tmpdest = os.path.join(tmp, members_path)
ok = True
updated = False
try:
if os.path.exists(dest):
shutil.rmtree(dest)
updated = True
z.extractall(tmp)
shutil.copytree(tmpdest, dest)
except OSError:
ok = False
logging.warning("Error extracting zip", exc_info=True)
if ok:
logging.info("Extracted zip to %s, copied to %s" % (tmpdest, dest))
return ok, updated
def execute_subprocess(cmd_then_args, block=True):
p = subprocess.Popen(
cmd_then_args,
stdin=subprocess.PIPE, stdout=subprocess.PIPE, close_fds=True,
universal_newlines=True)
if block:
stdout, stderr = p.communicate()
return stdout, stderr, p.returncode
def get_resource_dirs(resource):
"""Returns a list of all known resource dirs for a given resource.
:param str resource:
Name of the resource (e.g. "themes")
:return:
A list of resource dirs
"""
dirs = [os.path.join(dir, resource)
for dir in itertools.chain(GLib.get_system_data_dirs(),
(gtweak.DATA_DIR,
GLib.get_user_data_dir()))]
dirs += [os.path.join(os.path.expanduser("~"), ".{}".format(resource))]
return [dir for dir in dirs if os.path.isdir(dir)]
@singleton
class AutostartManager:
@staticmethod
def get_desktop_files():
return [a.get_filename() for a in Gio.app_info_get_all()]
@staticmethod
def get_user_autostart_files():
return glob.glob(
os.path.join(
GLib.get_user_config_dir(), "autostart", "*.desktop"))
@staticmethod
def get_system_autostart_files():
f = []
for d in GLib.get_system_config_dirs():
f.extend( glob.glob(os.path.join(d, "autostart", "*.desktop")) )
return f
class AutostartFile:
def __init__(self, appinfo, autostart_desktop_filename="", exec_cmd="", extra_exec_args=""):
if appinfo:
self._desktop_file = appinfo.get_filename()
self._autostart_desktop_filename = autostart_desktop_filename or os.path.basename(self._desktop_file)
self._create_file = False
elif autostart_desktop_filename:
self._desktop_file = None
self._autostart_desktop_filename = autostart_desktop_filename
self._create_file = True
else:
raise Exception("Need either an appinfo or a file name")
self._exec_cmd = exec_cmd
if extra_exec_args:
self._extra_exec_args = " %s\n" % extra_exec_args
else:
self._extra_exec_args = "\n"
user_autostart_dir = os.path.join(GLib.get_user_config_dir(), "autostart")
os.makedirs(user_autostart_dir, exist_ok=True)
self._user_autostart_file = os.path.join(user_autostart_dir, self._autostart_desktop_filename)
if self._desktop_file:
logging.debug("Found desktop file: %s" % self._desktop_file)
logging.debug("User autostart desktop file: %s" % self._user_autostart_file)
def _create_user_autostart_file(self):
f = open(self._user_autostart_file, "w")
f.write("[Desktop Entry]\nType=Application\nName=%s\nExec=%s\n" %
(self._autostart_desktop_filename[0:-len('.desktop')], self._exec_cmd + self._extra_exec_args))
f.close()
def is_start_at_login_enabled(self):
if os.path.exists(self._user_autostart_file):
#prefer user directories first
#if it contains X-GNOME-Autostart-enabled=false then it has
#has been disabled by the user in the session applet, otherwise
#it is enabled
return open(self._user_autostart_file).read().find("X-GNOME-Autostart-enabled=false") == -1
else:
#check the system directories
for f in AutostartManager().get_system_autostart_files():
if os.path.basename(f) == self._autostart_desktop_filename:
return True
return False
def update_start_at_login(self, update):
if os.path.exists(self._user_autostart_file):
logging.info("Removing user autostart file %s" % self._user_autostart_file)
os.remove(self._user_autostart_file)
if update:
if (not self._desktop_file) or (not os.path.exists(self._desktop_file)):
if self._create_file:
self._create_user_autostart_file()
else:
logging.critical("Could not find desktop file: %s" % self._desktop_file)
return
logging.info("Adding autostart %s" % self._user_autostart_file)
#copy the original file to the new file, but add the extra exec args
old = open(self._desktop_file, "r")
new = open(self._user_autostart_file, "w")
for l in old.readlines():
if l.startswith("Exec="):
if self._exec_cmd:
new.write("Exec=%s\n" % self._exec_cmd)
else:
new.write(l[0:-1])
new.write(self._extra_exec_args)
else:
new.write(l)
old.close()
new.close()
class SchemaList:
__list = None
def __init__(self):
if SchemaList.__list == None:
SchemaList.__list = []
def get(self):
return SchemaList.__list
def insert(self, key_name, schema_name):
v = [key_name, schema_name]
SchemaList.__list.append(v)
def reset(self):
for i in SchemaList.__list:
s = Gio.Settings(i[1])
s.reset(i[0])
@singleton
class DisableExtension(GObject.GObject):
__gsignals__ = {
"disable-extension": (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE,()),
}
def __init__(self):
GObject.GObject.__init__(self)
def disable(self):
self.emit("disable-extension")
@singleton
class XSettingsOverrides:
VARIANT_TYPES = {
'Gtk/ShellShowsAppMenu': GLib.Variant.new_int32,
'Gtk/EnablePrimaryPaste': GLib.Variant.new_int32,
'Gdk/WindowScalingFactor': GLib.Variant.new_int32,
}
def __init__(self):
self._settings = Gio.Settings(schema='org.gnome.settings-daemon.plugins.xsettings')
self._variant = self._settings.get_value("overrides")
def _dup_variant_as_dict(self):
items = {}
for k in list(self._variant.keys()):
try:
#variant override doesnt support .items()
v = self._variant[k]
items[k] = self.VARIANT_TYPES[k](v)
except KeyError:
pass
return items
def _dup_variant(self):
return GLib.Variant('a{sv}', self._dup_variant_as_dict())
def _set_override(self, name, v):
items = self._dup_variant_as_dict()
items[name] = self.VARIANT_TYPES[name](v)
n = GLib.Variant('a{sv}', items)
self._settings.set_value('overrides', n)
self._variant = self._settings.get_value("overrides")
def _get_override(self, name, default):
try:
return self._variant[name]
except KeyError:
return default
#while I could store meta type information in the VARIANT_TYPES
#dict, its easiest to do default value handling and missing value
#checks in dedicated functions
def set_shell_shows_app_menu(self, v):
self._set_override('Gtk/ShellShowsAppMenu', int(v))
def get_shell_shows_app_menu(self):
return self._get_override('Gtk/ShellShowsAppMenu', True)
def set_enable_primary_paste(self, v):
self._set_override('Gtk/EnablePrimaryPaste', int(v))
def get_enable_primary_paste(self):
return self._get_override('Gtk/EnablePrimaryPaste', True)
def set_window_scaling_factor(self, v):
self._set_override('Gdk/WindowScalingFactor', int(v))
def get_window_scaling_factor(self):
return self._get_override('Gdk/WindowScalingFactor', 1)
class Notification:
def __init__(self, summary, body):
if Notify.is_initted() or Notify.init(_("GNOME Tweaks")):
self.notification = Notify.Notification.new(
summary,
body,
'gnome-tweaks'
)
self.notification.set_hint(
"desktop-entry",
GLib.Variant('s', 'org.gnome.tweaks'))
self.notification.show()
else:
raise Exception("Not Supported")
@singleton
class LogoutNotification:
def __init__(self):
if Notify.is_initted() or Notify.init(_("GNOME Tweaks")):
self.notification = Notify.Notification.new(
_("Configuration changes require restart"),
_("Your session needs to be restarted for settings to take effect"),
'gnome-tweaks')
self.notification.add_action(
"restart",
_("Restart Session"),
self._logout, None, None)
self.notification.set_hint(
"desktop-entry",
GLib.Variant('s', 'org.gnome.tweaks'))
self.notification.show()
else:
raise Exception("Not Supported")
def _logout(self, btn, action, user_data, unknown):
d = Gio.bus_get_sync(Gio.BusType.SESSION, None)
proxy = Gio.DBusProxy.new_sync(
d,Gio.DBusProxyFlags.NONE, None,
'org.gnome.SessionManager',
'/org/gnome/SessionManager',
'org.gnome.SessionManager',
None)
proxy.Logout('(u)', 0)