chore(comp): change compositions

This commit is contained in:
Abhiraj Roy
2024-06-01 02:43:06 +05:30
parent 60c3b3b737
commit e9434a0b92
12 changed files with 2941 additions and 7 deletions

View File

@@ -70,17 +70,17 @@ thread_monitor_messages = "thread_monitor_messages"
thread_refresh_cache = "thread_refresh_cache"
thread_refresh_ui = "thread_refresh_ui"
cache_dir = "%s/.cache/archlinux-kernel-manager" % home
cache_dir = "%s/.cache/snigdhaos-kernel-manager" % home
cache_file = "%s/kernels.toml" % cache_dir
cache_update = "%s/update" % cache_dir
log_dir = "/var/log/archlinux-kernel-manager"
log_dir = "/var/log/snigdhaos-kernel-manager"
event_log_file = "%s/event.log" % log_dir
config_file_default = "%s/defaults/config.toml" % base_dir
config_dir = "%s/.config/archlinux-kernel-manager" % home
config_file = "%s/.config/archlinux-kernel-manager/config.toml" % home
config_dir = "%s/.config/snigdhaos-kernel-manager" % home
config_file = "%s/.config/snigdhaos-kernel-manager/config.toml" % home
logger = logging.getLogger("logger")
@@ -1603,7 +1603,7 @@ def update_bootloader(self):
else:
if (
"Skipping"
or "same boot loader version in place already." in stdout_lines
or "same boot loader version in place already." in self.stdout_lines
):
logger.info("%s update completed" % self.bootloader)
@@ -1636,7 +1636,7 @@ def update_bootloader(self):
)
logger.error("%s update failed" % self.bootloader)
logger.error(str(stdout_lines))
logger.error(str(self.stdout_lines))
self.messages_queue.put(event)
GLib.idle_add(

View File

@@ -0,0 +1,51 @@
# Store kernel data taken from
import datetime
from datetime import datetime
class Kernel:
def __init__(self, name, headers, version, size, last_modified, file_format):
self.name = name
self.headers = headers
self.version = version
self.size = size
self.last_modified = last_modified
self.file_format = file_format
def __gt__(self, other):
datetime_value_self = (
datetime.strptime(self.last_modified, "%d-%b-%Y %H:%M")
.replace(tzinfo=None)
.date()
)
datetime_value_other = (
datetime.strptime(other.last_modified, "%d-%b-%Y %H:%M")
.replace(tzinfo=None)
.date()
)
if datetime_value_other > datetime_value_self:
return datetime_value_other
class CommunityKernel:
def __init__(self, name, headers, repository, version, build_date, install_size):
self.name = name
self.headers = headers
self.repository = repository
self.version = version
self.build_date = build_date
self.install_size = install_size
def __gt__(self, other):
if other.name > self.name:
return other
class InstalledKernel:
def __init__(self, name, version, date, size):
self.name = name
self.version = version
self.date = date
self.size = size

View File

@@ -35,7 +35,7 @@ class Main(Gtk.Application):
display = Gtk.Widget.get_display(win)
# sourced from /usr/share/icons/hicolor/scalable/apps
win.set_icon_name("archlinux-kernel-manager-tux")
win.set_icon_name("snigdhaos-kernel-manager-tux")
provider = Gtk.CssProvider.new()
css_file = Gio.file_new_for_path(base_dir + "/snigdhaos-kernel-manager.css")
provider.load_from_file(css_file)

67
ui/AboutDialog.py Normal file
View File

@@ -0,0 +1,67 @@
# This class stores static information about the app, and is displayed in the about window
import os
import gi
import functions as fn
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk, Gio, Gdk
base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
class AboutDialog(Gtk.AboutDialog):
def __init__(self, manager_gui, **kwargs):
super().__init__(**kwargs)
website = "http://arcolinux.info/"
authors = ["Erik Dubois", "Fennec"]
program_name = "Arch Linux Kernel Manager"
comments = (
f"Add/Remove Officially supported Linux kernels on Arch based systems\n"
f"Powered by the Arch Linux Archive (a.k.a ALA)\n"
f"Community based Linux kernels are also supported\n"
f"Developed in Python with GTK 4\n"
)
icon_name = "akm-tux"
self.set_transient_for(manager_gui)
self.set_modal(True)
self.set_authors(authors)
self.set_program_name(program_name)
self.set_comments(comments)
self.set_website(website)
self.set_logo_icon_name(icon_name)
self.set_version("Version %s" % manager_gui.app_version)
self.connect("activate-link", self.on_activate_link)
tux_icon = Gdk.Texture.new_from_file(
file=Gio.File.new_for_path(
os.path.join(base_dir, "images/96x96/akm-tux.png")
)
)
self.set_logo(tux_icon)
def on_activate_link(self, about_dialog, uri):
try:
cmd = ["sudo", "-u", fn.sudo_username, "xdg-open", uri]
proc = fn.subprocess.Popen(
cmd,
shell=False,
stdout=fn.subprocess.PIPE,
stderr=fn.subprocess.STDOUT,
universal_newlines=True,
)
out, err = proc.communicate(timeout=50)
fn.logger.warning(out)
except Exception as e:
fn.logger.error("Exception in activate_link(): %s" % e)
return True

638
ui/FlowBox.py Normal file
View File

@@ -0,0 +1,638 @@
import datetime
import gi
import os
import functions as fn
from ui.ProgressWindow import ProgressWindow
from ui.MessageWindow import MessageWindow
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk, Gio, GLib
base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
class FlowBox(Gtk.FlowBox):
def __init__(
self,
kernel,
active_kernel,
manager_gui,
source,
):
super(FlowBox, self).__init__()
self.manager_gui = manager_gui
# self.set_row_spacing(1)
# self.set_column_spacing(1)
# self.set_name("hbox_kernel")
# self.set_activate_on_single_click(True)
# self.connect("child-activated", self.on_child_activated)
self.set_valign(Gtk.Align.START)
self.set_selection_mode(Gtk.SelectionMode.NONE)
# self.set_homogeneous(True)
self.set_max_children_per_line(2)
self.set_min_children_per_line(2)
self.kernel_count = 0
self.active_kernel_found = False
self.kernels = []
self.kernel = kernel
self.source = source
if self.source == "official":
self.flowbox_official()
if self.source == "community":
self.flowbox_community()
def flowbox_community(self):
for community_kernel in self.kernel:
self.kernels.append(community_kernel)
self.kernel_count += 1
if len(self.kernels) > 0:
installed = False
for cache in self.kernels:
fb_child = Gtk.FlowBoxChild()
fb_child.set_name(
"%s %s %s" % (cache.name, cache.version, cache.repository)
)
vbox_kernel_widgets = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL, spacing=0
)
vbox_kernel_widgets.set_name("vbox_kernel_widgets")
vbox_kernel_widgets.set_homogeneous(True)
switch_kernel = Gtk.Switch()
switch_kernel.set_halign(Gtk.Align.START)
hbox_kernel_switch = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL, spacing=0
)
hbox_kernel_switch.append(switch_kernel)
label_kernel_size = Gtk.Label(xalign=0, yalign=0)
label_kernel_size.set_name("label_kernel_flowbox")
label_kernel_name = Gtk.Label(xalign=0, yalign=0)
label_kernel_name.set_name("label_kernel_version")
label_kernel_name.set_markup(
"<b>%s</b> %s <i>%s</i>"
% (cache.name, cache.version, cache.repository)
)
label_kernel_name.set_selectable(True)
vbox_kernel_widgets.append(label_kernel_name)
tux_icon = Gtk.Picture.new_for_file(
file=Gio.File.new_for_path(
os.path.join(base_dir, "images/48x48/akm-tux.png")
)
)
tux_icon.set_can_shrink(True)
for installed_kernel in self.manager_gui.installed_kernels:
if "{}-{}".format(
installed_kernel.name, installed_kernel.version
) == "{}-{}".format(cache.name, cache.version):
installed = True
if cache.name == installed_kernel.name:
if (
cache.version > installed_kernel.version
or cache.version != installed_kernel.version
):
fn.logger.info(
"Kernel upgrade available - %s %s"
% (cache.name, cache.version)
)
tux_icon = Gtk.Picture.new_for_file(
file=Gio.File.new_for_path(
os.path.join(
base_dir, "images/48x48/akm-update.png"
)
)
)
tux_icon.set_can_shrink(True)
label_kernel_name.set_markup(
"<b>*%s</b> %s <i>%s</i>"
% (cache.name, cache.version, cache.repository)
)
if installed is True:
switch_kernel.set_state(True)
switch_kernel.set_active(True)
else:
switch_kernel.set_state(False)
switch_kernel.set_active(False)
tux_icon.set_content_fit(content_fit=Gtk.ContentFit.SCALE_DOWN)
tux_icon.set_halign(Gtk.Align.START)
installed = False
switch_kernel.connect("state-set", self.kernel_toggle_state, cache)
hbox_kernel = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
hbox_kernel.set_name("hbox_kernel")
label_kernel_size.set_text("%sM" % str(cache.install_size))
vbox_kernel_widgets.append(label_kernel_size)
label_kernel_build_date = Gtk.Label(xalign=0, yalign=0)
label_kernel_build_date.set_name("label_kernel_flowbox")
label_kernel_build_date.set_text(cache.build_date)
vbox_kernel_widgets.append(label_kernel_build_date)
vbox_kernel_widgets.append(hbox_kernel_switch)
hbox_kernel.append(tux_icon)
hbox_kernel.append(vbox_kernel_widgets)
fb_child.set_child(hbox_kernel)
self.append(fb_child)
def flowbox_official(self):
for official_kernel in self.manager_gui.official_kernels:
if official_kernel.name == self.kernel:
self.kernels.append(official_kernel)
self.kernel_count += 1
if len(self.kernels) > 0:
installed = False
latest = sorted(self.kernels)[:-1][0]
for cache in sorted(self.kernels):
fb_child = Gtk.FlowBoxChild()
fb_child.set_name("%s %s" % (cache.name, cache.version))
if cache == latest:
tux_icon = Gtk.Picture.new_for_file(
file=Gio.File.new_for_path(
os.path.join(base_dir, "images/48x48/akm-new.png")
)
)
else:
tux_icon = Gtk.Picture.new_for_file(
file=Gio.File.new_for_path(
os.path.join(base_dir, "images/48x48/akm-tux.png")
)
)
tux_icon.set_content_fit(content_fit=Gtk.ContentFit.SCALE_DOWN)
tux_icon.set_halign(Gtk.Align.START)
vbox_kernel_widgets = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL, spacing=0
)
vbox_kernel_widgets.set_homogeneous(True)
hbox_kernel_switch = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL, spacing=0
)
switch_kernel = Gtk.Switch()
switch_kernel.set_halign(Gtk.Align.START)
hbox_kernel_switch.append(switch_kernel)
label_kernel_version = Gtk.Label(xalign=0, yalign=0)
label_kernel_version.set_name("label_kernel_version")
label_kernel_version.set_selectable(True)
label_kernel_size = Gtk.Label(xalign=0, yalign=0)
label_kernel_size.set_name("label_kernel_flowbox")
if self.manager_gui.installed_kernels is None:
self.manager_gui.installed_kernels = fn.get_installed_kernels()
for installed_kernel in self.manager_gui.installed_kernels:
if (
"{}-{}".format(installed_kernel.name, installed_kernel.version)
== cache.version
):
installed = True
if installed is True:
switch_kernel.set_state(True)
switch_kernel.set_active(True)
else:
switch_kernel.set_state(False)
switch_kernel.set_active(False)
installed = False
switch_kernel.connect("state-set", self.kernel_toggle_state, cache)
label_kernel_version.set_markup("<b>%s</b>" % cache.version)
hbox_kernel = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
hbox_kernel.set_name("hbox_kernel")
label_kernel_size.set_text(cache.size)
vbox_kernel_widgets.append(label_kernel_version)
vbox_kernel_widgets.append(label_kernel_size)
label_kernel_modified = Gtk.Label(xalign=0, yalign=0)
label_kernel_modified.set_name("label_kernel_flowbox")
label_kernel_modified.set_text(cache.last_modified)
vbox_kernel_widgets.append(label_kernel_modified)
vbox_kernel_widgets.append(hbox_kernel_switch)
hbox_kernel.append(tux_icon)
hbox_kernel.append(vbox_kernel_widgets)
fb_child.set_child(hbox_kernel)
self.append(fb_child)
else:
fn.logger.error("Failed to read in kernels.")
def kernel_toggle_state(self, switch, data, kernel):
fn.logger.debug(
"Switch toggled, kernel selected = %s %s" % (kernel.name, kernel.version)
)
message = None
title = None
if fn.check_pacman_lockfile() is False:
# switch widget is currently toggled off
if switch.get_state() is False: # and switch.get_active() is True:
for inst_kernel in fn.get_installed_kernels():
if inst_kernel.name == kernel.name:
if self.source == "official":
if (
inst_kernel.version
> kernel.version.split("%s-" % inst_kernel.name)[1]
):
title = "Downgrading %s kernel" % kernel.name
else:
title = "Upgrading %s kernel" % kernel.name
break
if title is None:
title = "Kernel install"
if self.source == "community":
message = "This will install <b>%s-%s</b> - Is this ok ?" % (
kernel.name,
kernel.version,
)
elif self.source == "official":
message = (
"This will install <b>%s</b> - Is this ok ?" % kernel.version
)
message_window = FlowBoxMessageWindow(
title=title,
message=message,
action="install",
kernel=kernel,
transient_for=self.manager_gui,
textview=self.manager_gui.textview,
textbuffer=self.manager_gui.textbuffer,
switch=switch,
source=self.source,
manager_gui=self.manager_gui,
)
message_window.present()
return True
# switch widget is currently toggled on
# if widget.get_state() == True and widget.get_active() == False:
if switch.get_state() is True:
# and switch.get_active() is False:
installed_kernels = fn.get_installed_kernels()
if len(installed_kernels) > 1:
if self.source == "community":
message = "This will remove <b>%s-%s</b> - Is this ok ?" % (
kernel.name,
kernel.version,
)
elif self.source == "official":
message = (
"This will remove <b>%s</b> - Is this ok ?" % kernel.version
)
message_window = FlowBoxMessageWindow(
title="Kernel uninstall",
message=message,
action="uninstall",
kernel=kernel,
transient_for=self.manager_gui,
textview=self.manager_gui.textview,
textbuffer=self.manager_gui.textbuffer,
switch=switch,
source=self.source,
manager_gui=self.manager_gui,
)
message_window.present()
return True
else:
switch.set_state(True)
# switch.set_active(False)
fn.logger.warn(
"You only have 1 kernel installed, and %s-%s is currently running, uninstall aborted."
% (kernel.name, kernel.version)
)
msg_win = MessageWindow(
title="Warning: Uninstall aborted",
message=f"You only have 1 kernel installed\n"
f"<b>{kernel.name} {kernel.version}</b> is currently active\n",
image_path="images/48x48/akm-remove.png",
transient_for=self.manager_gui,
detailed_message=False,
)
msg_win.present()
return True
else:
fn.logger.error(
"Pacman lockfile found, is another pacman process running ?"
)
msg_win = MessageWindow(
title="Warning",
message="Pacman lockfile found, which indicates another pacman process is running",
transient_for=self.manager_gui,
detailed_message=False,
image_path="images/48x48/akm-warning.png",
)
msg_win.present()
return True
# while self.manager_gui.default_context.pending():
# self.manager_gui.default_context.iteration(True)
class FlowBoxInstalled(Gtk.FlowBox):
def __init__(self, installed_kernels, manager_gui, **kwargs):
super().__init__(**kwargs)
self.set_selection_mode(Gtk.SelectionMode.NONE)
self.set_homogeneous(True)
self.set_max_children_per_line(2)
self.set_min_children_per_line(2)
self.manager_gui = manager_gui
for installed_kernel in installed_kernels:
tux_icon = Gtk.Picture.new_for_file(
file=Gio.File.new_for_path(
os.path.join(base_dir, "images/48x48/akm-tux.png")
)
)
fb_child = Gtk.FlowBoxChild()
fb_child.set_name(
"%s %s" % (installed_kernel.name, installed_kernel.version)
)
tux_icon.set_content_fit(content_fit=Gtk.ContentFit.SCALE_DOWN)
tux_icon.set_halign(Gtk.Align.START)
label_installed_kernel_version = Gtk.Label(xalign=0, yalign=0)
label_installed_kernel_version.set_name("label_kernel_version")
label_installed_kernel_version.set_markup(
"<b>%s</b> %s" % (installed_kernel.name, installed_kernel.version)
)
label_installed_kernel_version.set_selectable(True)
hbox_installed_version = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL, spacing=0
)
hbox_installed_version.append(label_installed_kernel_version)
label_installed_kernel_size = Gtk.Label(xalign=0, yalign=0)
label_installed_kernel_size.set_name("label_kernel_flowbox")
label_installed_kernel_size.set_text("%sM" % str(installed_kernel.size))
label_installed_kernel_date = Gtk.Label(xalign=0, yalign=0)
label_installed_kernel_date.set_name("label_kernel_flowbox")
label_installed_kernel_date.set_text("%s" % installed_kernel.date)
btn_uninstall_kernel = Gtk.Button.new_with_label("Remove")
btn_context = btn_uninstall_kernel.get_style_context()
btn_context.add_class("destructive-action")
vbox_uninstall_button = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL, spacing=0
)
vbox_uninstall_button.set_name("box_padding_left")
btn_uninstall_kernel.set_hexpand(False)
btn_uninstall_kernel.set_halign(Gtk.Align.CENTER)
btn_uninstall_kernel.set_vexpand(False)
btn_uninstall_kernel.set_valign(Gtk.Align.CENTER)
vbox_uninstall_button.append(btn_uninstall_kernel)
btn_uninstall_kernel.connect(
"clicked", self.button_uninstall_kernel, installed_kernel
)
vbox_kernel_widgets = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL, spacing=0
)
vbox_kernel_widgets.append(hbox_installed_version)
vbox_kernel_widgets.append(label_installed_kernel_size)
vbox_kernel_widgets.append(label_installed_kernel_date)
vbox_kernel_widgets.append(vbox_uninstall_button)
hbox_kernel = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
hbox_kernel.set_name("hbox_kernel")
hbox_kernel.append(tux_icon)
hbox_kernel.append(vbox_kernel_widgets)
fb_child.set_child(hbox_kernel)
self.append(fb_child)
def button_uninstall_kernel(self, button, installed_kernel):
installed_kernels = fn.get_installed_kernels()
if len(installed_kernels) > 1:
fn.logger.info(
"Selected kernel to remove = %s %s"
% (installed_kernel.name, installed_kernel.version)
)
message_window = FlowBoxMessageWindow(
title="Kernel uninstall",
message="This will remove <b>%s-%s</b> - Is this ok ?"
% (installed_kernel.name, installed_kernel.version),
action="uninstall",
kernel=installed_kernel,
transient_for=self.manager_gui,
textview=self.manager_gui.textview,
textbuffer=self.manager_gui.textbuffer,
switch=None,
source=None,
manager_gui=self.manager_gui,
)
message_window.present()
else:
fn.logger.warn(
"You only have 1 kernel installed %s %s, uninstall aborted."
% (installed_kernel.name, installed_kernel.version)
)
msg_win = MessageWindow(
title="Warning: Uninstall aborted",
message=f"You only have 1 kernel installed\n"
f"<b>{installed_kernel.name} {installed_kernel.version}</b>\n",
image_path="images/48x48/akm-remove.png",
transient_for=self.manager_gui,
detailed_message=False,
)
msg_win.present()
class FlowBoxMessageWindow(Gtk.Window):
def __init__(
self,
title,
message,
action,
kernel,
textview,
textbuffer,
switch,
source,
manager_gui,
**kwargs,
):
super().__init__(**kwargs)
self.set_title(title=title)
self.set_modal(modal=True)
self.set_resizable(False)
self.set_icon_name("archlinux-kernel-manager-tux")
header_bar = Gtk.HeaderBar()
header_bar.set_show_title_buttons(False)
label_title = Gtk.Label(xalign=0.5, yalign=0.5)
label_title.set_markup("<b>%s</b>" % title)
self.set_titlebar(header_bar)
header_bar.set_title_widget(label_title)
self.textview = textview
self.textbuffer = textbuffer
self.manager_gui = manager_gui
self.kernel = kernel
self.action = action
self.switch = switch
self.source = source
vbox_flowbox_message = Gtk.Box.new(
orientation=Gtk.Orientation.VERTICAL, spacing=10
)
vbox_flowbox_message.set_name("vbox_flowbox_message")
self.set_child(child=vbox_flowbox_message)
label_flowbox_message = Gtk.Label(xalign=0, yalign=0)
label_flowbox_message.set_markup("%s" % message)
label_flowbox_message.set_name("label_flowbox_message")
vbox_flowbox_message.set_halign(Gtk.Align.CENTER)
# Widgets.
button_yes = Gtk.Button.new_with_label("Yes")
button_yes.set_size_request(100, 30)
button_yes.set_halign(Gtk.Align.END)
button_yes_context = button_yes.get_style_context()
button_yes_context.add_class("destructive-action")
button_yes.connect("clicked", self.on_button_yes_clicked)
button_no = Gtk.Button.new_with_label("No")
button_no.set_size_request(100, 30)
button_no.set_halign(Gtk.Align.END)
button_no.connect("clicked", self.on_button_no_clicked)
hbox_buttons = Gtk.Box.new(orientation=Gtk.Orientation.HORIZONTAL, spacing=15)
hbox_buttons.set_halign(Gtk.Align.CENTER)
hbox_buttons.append(button_yes)
hbox_buttons.append(button_no)
vbox_flowbox_message.append(label_flowbox_message)
vbox_flowbox_message.append(hbox_buttons)
def on_button_yes_clicked(self, button):
self.hide()
self.destroy()
progress_window = None
if fn.check_pacman_lockfile() is False:
if self.action == "uninstall":
progress_window = ProgressWindow(
title="Removing kernel",
action="uninstall",
textview=self.textview,
textbuffer=self.textbuffer,
kernel=self.kernel,
switch=self.switch,
source=self.source,
manager_gui=self.manager_gui,
transient_for=self.manager_gui,
)
if self.action == "install":
progress_window = ProgressWindow(
title="Installing kernel",
action="install",
textview=self.textview,
textbuffer=self.textbuffer,
kernel=self.kernel,
switch=self.switch,
source=self.source,
manager_gui=self.manager_gui,
transient_for=self.manager_gui,
)
else:
fn.logger.error(
"Pacman lockfile found, is another pacman process running ?"
)
def on_button_no_clicked(self, button):
if self.action == "uninstall":
if self.switch is not None:
self.switch.set_state(True)
elif self.action == "install":
if self.switch is not None:
self.switch.set_state(False)
self.hide()
self.destroy()
return True

631
ui/KernelStack.py Normal file
View File

@@ -0,0 +1,631 @@
import gi
import os
import functions as fn
from ui.FlowBox import FlowBox, FlowBoxInstalled
from ui.Stack import Stack
from kernel import Kernel, InstalledKernel, CommunityKernel
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk, Gio, Gdk
base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
class KernelStack:
def __init__(
self,
manager_gui,
**kwargs,
):
super().__init__(**kwargs)
self.manager_gui = manager_gui
self.flowbox_stacks = []
self.search_entries = []
def add_installed_kernels_to_stack(self, reload):
vbox_header = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
vbox_header.set_name("vbox_header")
lbl_heading = Gtk.Label(xalign=0.5, yalign=0.5)
lbl_heading.set_name("label_flowbox_message")
lbl_heading.set_text("%s" % "Installed kernels".upper())
lbl_padding = Gtk.Label(xalign=0.0, yalign=0.0)
lbl_padding.set_text(" ")
grid_banner_img = Gtk.Grid()
image_settings = Gtk.Image.new_from_file(
os.path.join(base_dir, "images/48x48/akm-install.png")
)
image_settings.set_icon_size(Gtk.IconSize.LARGE)
image_settings.set_halign(Gtk.Align.START)
grid_banner_img.attach(image_settings, 0, 1, 1, 1)
grid_banner_img.attach_next_to(
lbl_padding,
image_settings,
Gtk.PositionType.RIGHT,
1,
1,
)
grid_banner_img.attach_next_to(
lbl_heading,
lbl_padding,
Gtk.PositionType.RIGHT,
1,
1,
)
vbox_header.append(grid_banner_img)
label_installed_desc = Gtk.Label(xalign=0, yalign=0)
label_installed_desc.set_text("Installed Linux kernel and modules")
label_installed_desc.set_name("label_stack_desc")
label_installed_count = Gtk.Label(xalign=0, yalign=0)
label_installed_count.set_name("label_stack_count")
vbox_search_entry = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
search_entry_installed = Gtk.SearchEntry()
search_entry_installed.set_name("search_entry_installed")
search_entry_installed.set_placeholder_text("Search installed kernels...")
search_entry_installed.connect("search_changed", self.flowbox_filter_installed)
vbox_search_entry.append(search_entry_installed)
if reload is True:
if self.manager_gui.vbox_installed_kernels is not None:
for widget in self.manager_gui.vbox_installed_kernels:
if widget.get_name() == "label_stack_count":
widget.set_markup(
"<i>%s Installed kernels</i>"
% len(self.manager_gui.installed_kernels)
)
if widget.get_name() == "scrolled_window_installed":
self.manager_gui.vbox_installed_kernels.remove(widget)
scrolled_window_installed = Gtk.ScrolledWindow()
scrolled_window_installed.set_name("scrolled_window_installed")
scrolled_window_installed.set_policy(
Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC
)
scrolled_window_installed.set_propagate_natural_height(True)
scrolled_window_installed.set_propagate_natural_width(True)
self.flowbox_installed = FlowBoxInstalled(
installed_kernels=self.manager_gui.installed_kernels,
manager_gui=self.manager_gui,
)
vbox_installed_flowbox = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL, spacing=12
)
# vbox_installed_flowbox.set_halign(align=Gtk.Align.FILL)
vbox_installed_flowbox.append(self.flowbox_installed)
scrolled_window_installed.set_child(vbox_installed_flowbox)
self.manager_gui.vbox_installed_kernels.append(scrolled_window_installed)
if self.manager_gui.vbox_active_installed_kernel is not None:
self.manager_gui.vbox_installed_kernels.reorder_child_after(
self.manager_gui.vbox_active_installed_kernel,
scrolled_window_installed,
)
else:
self.manager_gui.vbox_installed_kernels = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL, spacing=5
)
self.manager_gui.vbox_installed_kernels.set_name("vbox_installed_kernels")
self.manager_gui.vbox_active_installed_kernel = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL, spacing=5
)
self.manager_gui.vbox_active_installed_kernel.set_name("vbox_active_kernel")
label_active_installed_kernel = Gtk.Label(xalign=0.5, yalign=0.5)
label_active_installed_kernel.set_name("label_active_kernel")
label_active_installed_kernel.set_selectable(True)
label_active_installed_kernel.set_markup(
"<b>Active kernel:</b> %s" % self.manager_gui.active_kernel
)
label_active_installed_kernel.set_halign(Gtk.Align.START)
self.manager_gui.vbox_active_installed_kernel.append(
label_active_installed_kernel
)
scrolled_window_installed = Gtk.ScrolledWindow()
scrolled_window_installed.set_name("scrolled_window_installed")
scrolled_window_installed.set_policy(
Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC
)
scrolled_window_installed.set_propagate_natural_height(True)
scrolled_window_installed.set_propagate_natural_width(True)
label_installed_count.set_markup(
"<i>%s Installed kernels</i>" % len(self.manager_gui.installed_kernels)
)
self.flowbox_installed = FlowBoxInstalled(
installed_kernels=self.manager_gui.installed_kernels,
manager_gui=self.manager_gui,
)
vbox_installed_flowbox = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL, spacing=12
)
# vbox_installed_flowbox.set_halign(align=Gtk.Align.FILL)
vbox_installed_flowbox.append(self.flowbox_installed)
scrolled_window_installed.set_child(vbox_installed_flowbox)
# self.manager_gui.vbox_installed_kernels.append(label_installed_title)
self.manager_gui.vbox_installed_kernels.append(vbox_header)
self.manager_gui.vbox_installed_kernels.append(label_installed_desc)
self.manager_gui.vbox_installed_kernels.append(label_installed_count)
self.manager_gui.vbox_installed_kernels.append(vbox_search_entry)
self.manager_gui.vbox_installed_kernels.append(scrolled_window_installed)
self.manager_gui.vbox_installed_kernels.append(
self.manager_gui.vbox_active_installed_kernel
)
self.manager_gui.stack.add_titled(
self.manager_gui.vbox_installed_kernels, "Installed", "Installed"
)
def add_official_kernels_to_stack(self, reload):
if reload is True:
self.flowbox_stacks.clear()
for kernel in fn.supported_kernels_dict:
vbox_flowbox = None
stack_child = self.manager_gui.stack.get_child_by_name(kernel)
if stack_child is not None:
for stack_widget in stack_child:
if stack_widget.get_name() == "scrolled_window_official":
scrolled_window_official = stack_widget
vbox_flowbox = (
scrolled_window_official.get_child().get_child()
)
for widget in vbox_flowbox:
widget.remove_all()
self.flowbox_official_kernel = FlowBox(
kernel,
self.manager_gui.active_kernel,
self.manager_gui,
"official",
)
self.flowbox_stacks.append(self.flowbox_official_kernel)
vbox_flowbox.append(self.flowbox_official_kernel)
# while self.manager_gui.default_context.pending():
# self.manager_gui.default_context.iteration(True)
else:
for kernel in fn.supported_kernels_dict:
self.manager_gui.vbox_kernels = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL, spacing=5
)
self.manager_gui.vbox_kernels.set_name("stack_%s" % kernel)
hbox_sep_kernels = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL, spacing=10
)
hsep_kernels = Gtk.Separator(orientation=Gtk.Orientation.VERTICAL)
vbox_active_kernel = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL, spacing=5
)
vbox_active_kernel.set_name("vbox_active_kernel")
label_active_kernel = Gtk.Label(xalign=0.5, yalign=0.5)
label_active_kernel.set_name("label_active_kernel")
label_active_kernel.set_selectable(True)
label_active_kernel.set_markup(
"<b>Active kernel:</b> %s" % self.manager_gui.active_kernel
)
label_active_kernel.set_halign(Gtk.Align.START)
label_bottom_padding = Gtk.Label(xalign=0, yalign=0)
label_bottom_padding.set_text(" ")
hbox_sep_kernels.append(hsep_kernels)
self.flowbox_official_kernel = FlowBox(
kernel, self.manager_gui.active_kernel, self.manager_gui, "official"
)
self.flowbox_stacks.append(self.flowbox_official_kernel)
vbox_flowbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
vbox_flowbox.set_name("vbox_flowbox_%s" % kernel)
# vbox_flowbox.set_halign(align=Gtk.Align.FILL)
vbox_flowbox.append(self.flowbox_official_kernel)
scrolled_window_official = Gtk.ScrolledWindow()
scrolled_window_official.set_name("scrolled_window_official")
scrolled_window_official.set_policy(
Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC
)
scrolled_window_official.set_propagate_natural_height(True)
scrolled_window_official.set_propagate_natural_width(True)
label_title = Gtk.Label(xalign=0.5, yalign=0.5)
label_title.set_text(kernel.upper())
label_title.set_name("label_stack_kernel")
label_desc = Gtk.Label(xalign=0, yalign=0)
label_desc.set_text(fn.supported_kernels_dict[kernel][0])
label_desc.set_name("label_stack_desc")
label_count = Gtk.Label(xalign=0, yalign=0)
label_count.set_markup(
"<i>%s Available kernels</i>"
% self.flowbox_official_kernel.kernel_count
)
label_count.set_name("label_stack_count")
vbox_search_entry = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL, spacing=5
)
search_entry_official = Gtk.SearchEntry()
search_entry_official.set_name(kernel)
search_entry_official.set_placeholder_text(
"Search %s kernels..." % kernel
)
search_entry_official.connect(
"search_changed", self.flowbox_filter_official
)
self.search_entries.append(search_entry_official)
vbox_search_entry.append(search_entry_official)
vbox_active_kernel.append(label_active_kernel)
vbox_header = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
vbox_header.set_name("vbox_header")
lbl_heading = Gtk.Label(xalign=0.5, yalign=0.5)
lbl_heading.set_name("label_flowbox_message")
lbl_heading.set_text(
"%s - Verified and official kernels" % kernel.upper()
)
lbl_padding = Gtk.Label(xalign=0.0, yalign=0.0)
lbl_padding.set_text(" ")
grid_banner_img = Gtk.Grid()
image_settings = Gtk.Image.new_from_file(
os.path.join(base_dir, "images/48x48/akm-verified.png")
)
image_settings.set_icon_size(Gtk.IconSize.LARGE)
image_settings.set_halign(Gtk.Align.START)
grid_banner_img.attach(image_settings, 0, 1, 1, 1)
grid_banner_img.attach_next_to(
lbl_padding,
image_settings,
Gtk.PositionType.RIGHT,
1,
1,
)
grid_banner_img.attach_next_to(
lbl_heading,
lbl_padding,
Gtk.PositionType.RIGHT,
1,
1,
)
vbox_header.append(grid_banner_img)
# vbox_kernels.append(label_title)
self.manager_gui.vbox_kernels.append(vbox_header)
# self.manager_gui.vbox_kernels.append(label_title)
self.manager_gui.vbox_kernels.append(label_desc)
self.manager_gui.vbox_kernels.append(label_count)
self.manager_gui.vbox_kernels.append(vbox_search_entry)
self.manager_gui.vbox_kernels.append(hbox_sep_kernels)
scrolled_window_official.set_child(vbox_flowbox)
self.manager_gui.vbox_kernels.append(scrolled_window_official)
self.manager_gui.vbox_kernels.append(vbox_active_kernel)
kernel_sidebar_title = None
if kernel == "linux":
kernel_sidebar_title = "Linux"
elif kernel == "linux-lts":
kernel_sidebar_title = "Linux-LTS"
elif kernel == "linux-zen":
kernel_sidebar_title = "Linux-ZEN"
elif kernel == "linux-hardened":
kernel_sidebar_title = "Linux-Hardened"
elif kernel == "linux-rt":
kernel_sidebar_title = "Linux-RT"
elif kernel == "linux-rt-lts":
kernel_sidebar_title = "Linux-RT-LTS"
self.manager_gui.stack.add_titled(
self.manager_gui.vbox_kernels, kernel, kernel_sidebar_title
)
def flowbox_filter_official(self, search_entry):
def filter_func(fb_child, text):
if search_entry.get_name() == fb_child.get_name().split(" ")[0]:
if text in fb_child.get_name():
return True
else:
return False
else:
return True
text = search_entry.get_text()
for flowbox in self.flowbox_stacks:
flowbox.set_filter_func(filter_func, text)
def flowbox_filter_community(self, search_entry):
def filter_func(fb_child, text):
if search_entry.get_name() == "search_entry_community":
if text in fb_child.get_name():
return True
else:
return False
else:
return True
text = search_entry.get_text()
self.flowbox_community.set_filter_func(filter_func, text)
def flowbox_filter_installed(self, search_entry):
def filter_func(fb_child, text):
if search_entry.get_name() == "search_entry_installed":
if text in fb_child.get_name():
return True
else:
return False
else:
return True
text = search_entry.get_text()
self.flowbox_installed.set_filter_func(filter_func, text)
def add_community_kernels_to_stack(self, reload):
vbox_active_kernel = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
vbox_active_kernel.set_name("vbox_active_kernel")
vbox_kernels = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
hbox_sep_kernels = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
hsep_kernels = Gtk.Separator(orientation=Gtk.Orientation.VERTICAL)
hbox_sep_kernels.append(hsep_kernels)
label_active_kernel = Gtk.Label(xalign=0.5, yalign=0.5)
label_active_kernel.set_name("label_active_kernel")
label_active_kernel.set_selectable(True)
label_active_kernel.set_markup(
"<b>Active kernel:</b> %s" % self.manager_gui.active_kernel
)
label_active_kernel.set_halign(Gtk.Align.START)
label_count = Gtk.Label(xalign=0, yalign=0)
label_count.set_name("label_stack_count")
vbox_search_entry = None
search_entry_community = Gtk.SearchEntry()
search_entry_community.set_name("search_entry_community")
search_entry_community.set_placeholder_text(
"Search %s kernels..." % "community based"
)
search_entry_community.connect("search_changed", self.flowbox_filter_community)
hbox_warning_message = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL, spacing=5
)
hbox_warning_message.set_name("hbox_warning_message")
label_pacman_warning = Gtk.Label(xalign=0, yalign=0)
label_pacman_warning.set_name("label_community_warning")
image_warning = Gtk.Image.new_from_file(
os.path.join(base_dir, "images/48x48/akm-warning.png")
)
image_warning.set_name("image_warning")
image_warning.set_icon_size(Gtk.IconSize.LARGE)
image_warning.set_halign(Gtk.Align.CENTER)
hbox_warning = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
hbox_warning.set_name("hbox_warning")
hbox_warning.append(image_warning)
# hbox_warning.append(label_pacman_warning)
label_warning = Gtk.Label(xalign=0, yalign=0)
label_warning.set_name("label_community_warning")
label_warning.set_markup(
f"These are user produced content\n"
f"<b>Any use of the provided files is at your own risk</b>"
)
hbox_warning.append(label_warning)
if reload is True:
vbox_flowbox = None
stack_child = self.manager_gui.stack.get_child_by_name("Community Kernels")
if stack_child is not None:
for stack_widget in stack_child:
if stack_widget.get_name() == "label_stack_count":
stack_widget.set_markup(
"<i>%s Available kernels</i>"
% len(self.manager_gui.community_kernels)
)
if stack_widget.get_name() == "vbox_search_entry":
if len(self.manager_gui.community_kernels) == 0:
for search_entry in stack_widget:
search_entry.set_visible(False)
else:
for search_entry in stack_widget:
search_entry.set_visible(True)
if stack_widget.get_name() == "scrolled_window_community":
scrolled_window_community = stack_widget
vbox_flowbox = scrolled_window_community.get_child().get_child()
for widget in vbox_flowbox:
if widget.get_name() != "vbox_no_community":
widget.remove_all()
else:
if len(self.manager_gui.community_kernels) > 0:
# widget.hide()
for box_widget in widget:
box_widget.hide()
vbox_search_entry = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL, spacing=5
)
vbox_search_entry.append(search_entry_community)
# widget.append(hbox_warning)
widget.append(vbox_search_entry)
self.flowbox_community = FlowBox(
self.manager_gui.community_kernels,
self.manager_gui.active_kernel,
self.manager_gui,
"community",
)
vbox_flowbox.append(self.flowbox_community)
while self.manager_gui.default_context.pending():
# fn.time.sleep(0.1)
self.manager_gui.default_context.iteration(True)
else:
self.flowbox_community = None
vbox_flowbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
# vbox_flowbox.set_halign(align=Gtk.Align.FILL)
if len(self.manager_gui.community_kernels) == 0:
label_count.set_markup("<i>%s Available kernels</i>" % 0)
else:
self.flowbox_community = FlowBox(
self.manager_gui.community_kernels,
self.manager_gui.active_kernel,
self.manager_gui,
"community",
)
vbox_flowbox.append(self.flowbox_community)
label_count.set_markup(
"<i>%s Available kernels</i>" % self.flowbox_community.kernel_count
)
vbox_search_entry = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL, spacing=5
)
vbox_search_entry.set_name("vbox_search_entry")
vbox_search_entry.append(search_entry_community)
if reload is False:
scrolled_window_community = Gtk.ScrolledWindow()
scrolled_window_community.set_name("scrolled_window_community")
scrolled_window_community.set_policy(
Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC
)
scrolled_window_community.set_propagate_natural_height(True)
scrolled_window_community.set_propagate_natural_width(True)
label_title = Gtk.Label(xalign=0.5, yalign=0.5)
label_title.set_text("Community Kernels")
label_title.set_name("label_stack_kernel")
label_desc = Gtk.Label(xalign=0, yalign=0)
label_desc.set_text("Community Linux kernel and modules")
label_desc.set_name("label_stack_desc")
vbox_active_kernel.append(label_active_kernel)
vbox_header = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
vbox_header.set_name("vbox_header")
lbl_heading = Gtk.Label(xalign=0.5, yalign=0.5)
lbl_heading.set_name("label_flowbox_message")
lbl_heading.set_text(
"%s - Unofficial kernels" % "Community based".upper()
)
lbl_padding = Gtk.Label(xalign=0.0, yalign=0.0)
lbl_padding.set_text(" ")
grid_banner_img = Gtk.Grid()
image_settings = Gtk.Image.new_from_file(
os.path.join(base_dir, "images/48x48/akm-community.png")
)
image_settings.set_icon_size(Gtk.IconSize.LARGE)
image_settings.set_halign(Gtk.Align.START)
grid_banner_img.attach(image_settings, 0, 1, 1, 1)
grid_banner_img.attach_next_to(
lbl_padding,
image_settings,
Gtk.PositionType.RIGHT,
1,
1,
)
grid_banner_img.attach_next_to(
lbl_heading,
lbl_padding,
Gtk.PositionType.RIGHT,
1,
1,
)
vbox_header.append(grid_banner_img)
vbox_kernels.append(vbox_header)
vbox_kernels.append(label_desc)
vbox_kernels.append(hbox_warning)
vbox_kernels.append(label_count)
if vbox_search_entry is not None:
vbox_kernels.append(vbox_search_entry)
vbox_kernels.append(hbox_sep_kernels)
scrolled_window_community.set_child(vbox_flowbox)
vbox_kernels.append(scrolled_window_community)
vbox_kernels.append(vbox_active_kernel)
self.manager_gui.stack.add_titled(
vbox_kernels, "Community Kernels", "Community"
)

45
ui/MenuButton.py Normal file
View File

@@ -0,0 +1,45 @@
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk
# Gtk.Builder xml for the application menu
APP_MENU = """
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id='app-menu'>
<section>
<item>
<attribute name='label' translatable='yes'>_About</attribute>
<attribute name='action'>win.about</attribute>
</item>
<item>
<attribute name='label' translatable='yes'>_Settings</attribute>
<attribute name='action'>win.settings</attribute>
</item>
<item>
<attribute name='label' translatable='yes'>_Refresh</attribute>
<attribute name='action'>win.refresh</attribute>
</item>
<item>
<attribute name='label' translatable='yes'>_Quit</attribute>
<attribute name='action'>win.quit</attribute>
</item>
</section>
</menu>
</interface>
"""
class MenuButton(Gtk.MenuButton):
"""
Wrapper class for at Gtk.Menubutton with a menu defined
in a Gtk.Builder xml string
"""
def __init__(self, icon_name="open-menu-symbolic"):
super(MenuButton, self).__init__()
builder = Gtk.Builder.new_from_string(APP_MENU, -1)
menu = builder.get_object("app-menu")
self.set_menu_model(menu)
self.set_icon_name(icon_name)

95
ui/MessageWindow.py Normal file
View File

@@ -0,0 +1,95 @@
import gi
import os
import functions as fn
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk, Gio, GLib
base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
class MessageWindow(Gtk.Window):
def __init__(self, title, message, image_path, detailed_message, **kwargs):
super().__init__(**kwargs)
# self.set_title(title=title)
self.set_modal(modal=True)
self.set_resizable(False)
icon_name = "akm-tux"
self.set_icon_name(icon_name)
header_bar = Gtk.HeaderBar()
header_bar.set_show_title_buttons(True)
hbox_title = Gtk.Box.new(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
label_title = Gtk.Label(xalign=0.5, yalign=0.5)
label_title.set_markup("<b>%s</b>" % title)
hbox_title.append(label_title)
header_bar.set_title_widget(hbox_title)
self.set_titlebar(header_bar)
vbox_message = Gtk.Box.new(orientation=Gtk.Orientation.VERTICAL, spacing=10)
vbox_message.set_name("vbox_flowbox_message")
image = Gtk.Picture.new_for_filename(os.path.join(base_dir, image_path))
image.set_content_fit(content_fit=Gtk.ContentFit.SCALE_DOWN)
image.set_halign(Gtk.Align.START)
hbox_image = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
# hbox_image.append(image)
self.set_child(child=vbox_message)
if detailed_message is True:
scrolled_window = Gtk.ScrolledWindow()
textview = Gtk.TextView()
textview.set_property("editable", False)
textview.set_property("monospace", True)
textview.set_vexpand(True)
textview.set_hexpand(True)
msg_buffer = textview.get_buffer()
msg_buffer.insert(
msg_buffer.get_end_iter(),
"Event timestamp = %s\n"
% fn.datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
)
msg_buffer.insert(msg_buffer.get_end_iter(), "%s\n" % message)
scrolled_window.set_child(textview)
hbox_image.append(scrolled_window)
self.set_size_request(700, 500)
self.set_resizable(True)
else:
label_message = Gtk.Label(xalign=0, yalign=0)
label_message.set_markup("%s" % message)
label_message.set_name("label_flowbox_message")
hbox_image.append(image)
hbox_image.append(label_message)
vbox_message.append(hbox_image)
button_ok = Gtk.Button.new_with_label("OK")
button_ok.set_size_request(100, 30)
button_ok.set_halign(Gtk.Align.END)
button_ok.connect("clicked", self.on_button_ok_clicked)
hbox_buttons = Gtk.Box.new(orientation=Gtk.Orientation.HORIZONTAL, spacing=20)
hbox_buttons.set_halign(Gtk.Align.END)
hbox_buttons.append(button_ok)
vbox_message.append(hbox_buttons)
def on_button_ok_clicked(self, button):
self.hide()
self.destroy()

632
ui/ProgressWindow.py Normal file
View File

@@ -0,0 +1,632 @@
import sys
import gi
import os
import functions as fn
from ui.MessageWindow import MessageWindow
from gi.repository import Gtk, Gio, GLib
base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
class ProgressWindow(Gtk.Window):
def __init__(
self,
title,
action,
textview,
textbuffer,
kernel,
switch,
source,
manager_gui,
**kwargs,
):
super().__init__(**kwargs)
self.set_title(title=title)
self.set_modal(modal=True)
self.set_resizable(True)
self.set_size_request(700, 400)
self.connect("close-request", self.on_close)
self.textview = textview
self.textbuffer = textbuffer
self.kernel_state_queue = fn.Queue()
self.messages_queue = fn.Queue()
self.kernel = kernel
self.timeout_id = None
self.errors_found = False
self.action = action
self.switch = switch
self.restore = False
self.source = source
self.manager_gui = manager_gui
self.bootloader = self.manager_gui.bootloader
self.bootloader_grub_cfg = self.manager_gui.bootloader_grub_cfg
vbox_progress = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
vbox_progress.set_name("main")
self.set_child(child=vbox_progress)
header_bar = Gtk.HeaderBar()
self.label_title = Gtk.Label(xalign=0.5, yalign=0.5)
header_bar.set_show_title_buttons(True)
self.set_titlebar(header_bar)
self.label_title.set_markup("<b>%s</b>" % title)
header_bar.set_title_widget(self.label_title)
vbox_icon_settings = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
vbox_icon_settings.set_name("vbox_icon_settings")
lbl_heading = Gtk.Label(xalign=0.5, yalign=0.5)
lbl_heading.set_name("label_flowbox_message")
lbl_padding = Gtk.Label(xalign=0.0, yalign=0.0)
lbl_padding.set_text(" ")
grid_banner_img = Gtk.Grid()
image_settings = None
if action == "install":
image_settings = Gtk.Image.new_from_file(
os.path.join(base_dir, "images/48x48/akm-install.png")
)
lbl_heading.set_markup(
"Installing <b>%s version %s </b>"
% (self.kernel.name, self.kernel.version)
)
if action == "uninstall":
image_settings = Gtk.Image.new_from_file(
os.path.join(base_dir, "images/48x48/akm-remove.png")
)
lbl_heading.set_markup(
"Removing <b>%s version %s </b>"
% (self.kernel.name, self.kernel.version)
)
# get kernel version from pacman
self.installed_kernel_version = fn.get_kernel_version(self.kernel.name)
if self.installed_kernel_version is not None:
fn.logger.debug(
"Installed kernel version = %s" % self.installed_kernel_version
)
else:
fn.logger.debug("Nothing to remove .. previous kernel not installed")
image_settings.set_halign(Gtk.Align.START)
image_settings.set_icon_size(Gtk.IconSize.LARGE)
hbox_header = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
hbox_header.set_name("vbox_header")
hbox_header.append(image_settings)
hbox_header.append(lbl_heading)
vbox_progress.append(hbox_header)
self.spinner = Gtk.Spinner()
self.spinner.set_spinning(True)
image_warning = Gtk.Image.new_from_file(
os.path.join(base_dir, "images/48x48/akm-warning.png")
)
image_warning.set_icon_size(Gtk.IconSize.LARGE)
image_warning.set_halign(Gtk.Align.START)
hbox_progress_warning = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL, spacing=5
)
hbox_progress_warning.set_name("hbox_warning")
hbox_progress_warning.append(image_warning)
self.label_progress_window_desc = Gtk.Label(xalign=0, yalign=0)
self.label_progress_window_desc.set_markup(
f"Do not close this window while a kernel {self.action} activity is in progress\n"
f"Progress can be monitored in the log below\n"
f"<b>A reboot is recommended when Linux packages have changed</b>"
)
hbox_progress_warning.append(self.label_progress_window_desc)
self.label_status = Gtk.Label(xalign=0, yalign=0)
button_close = Gtk.Button.new_with_label("Close")
button_close.set_size_request(100, 30)
button_close.set_halign(Gtk.Align.END)
button_close.connect(
"clicked",
self.on_button_close_response,
)
self.label_spinner_progress = Gtk.Label(xalign=0, yalign=0)
if self.action == "install":
self.label_spinner_progress.set_markup(
"<b>Please wait kernel %s is in progress</b>" % "installation"
)
elif self.action == "uninstall":
self.label_spinner_progress.set_markup(
"<b>Please wait kernel %s is in progress</b>" % "removal"
)
self.hbox_spinner = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
self.hbox_spinner.append(self.label_spinner_progress)
self.hbox_spinner.append(self.spinner)
vbox_padding = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=20)
vbox_padding.set_valign(Gtk.Align.END)
label_padding = Gtk.Label(xalign=0, yalign=0)
label_padding.set_valign(Gtk.Align.END)
vbox_padding.append(label_padding)
hbox_button_close = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=20)
hbox_button_close.append(button_close)
hbox_button_close.set_halign(Gtk.Align.END)
self.scrolled_window = Gtk.ScrolledWindow()
self.scrolled_window.set_propagate_natural_height(True)
self.scrolled_window.set_propagate_natural_width(True)
self.scrolled_window.set_policy(
Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC
)
hbox_notify_revealer = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL, spacing=20
)
hbox_notify_revealer.set_name("hbox_notify_revealer")
hbox_notify_revealer.set_halign(Gtk.Align.CENTER)
self.notify_revealer = Gtk.Revealer()
self.notify_revealer.set_reveal_child(False)
self.label_notify_revealer = Gtk.Label(xalign=0, yalign=0)
self.label_notify_revealer.set_name("label_notify_revealer")
self.notify_revealer.set_child(hbox_notify_revealer)
hbox_notify_revealer.append(self.label_notify_revealer)
if self.textview.get_buffer() is not None:
self.textview = Gtk.TextView()
self.textview.set_property("editable", False)
self.textview.set_property("monospace", True)
self.textview.set_vexpand(True)
self.textview.set_hexpand(True)
self.textview.set_buffer(self.textbuffer)
self.scrolled_window.set_child(self.textview)
self.scrolled_window.set_size_request(300, 300)
vbox_progress.append(hbox_progress_warning)
vbox_progress.append(self.notify_revealer)
vbox_progress.append(self.scrolled_window)
vbox_progress.append(self.hbox_spinner)
vbox_progress.append(self.label_status)
vbox_progress.append(vbox_padding)
vbox_progress.append(hbox_button_close)
self.present()
self.linux_headers = None
if (
self.source == "official"
and action == "install"
or action == "uninstall"
and self.source == "official"
):
if kernel.name == "linux":
self.linux_headers = "linux-headers"
if kernel.name == "linux-rt":
self.linux_headers = "linux-rt-headers"
if kernel.name == "linux-rt-lts":
self.linux_headers = "linux-rt-lts-headers"
if kernel.name == "linux-hardened":
self.linux_headers = "linux-hardened-headers"
if kernel.name == "linux-zen":
self.linux_headers = "linux-zen-headers"
if kernel.name == "linux-lts":
self.linux_headers = "linux-lts-headers"
self.official_kernels = [
"%s/packages/l/%s/%s-x86_64%s"
% (
fn.archlinux_mirror_archive_url,
kernel.name,
kernel.version,
kernel.file_format,
),
"%s/packages/l/%s/%s-x86_64%s"
% (
fn.archlinux_mirror_archive_url,
self.linux_headers,
kernel.headers,
kernel.file_format,
),
]
# in the event an install goes wrong, fallback and reinstall previous kernel
if self.source == "official":
self.restore_kernel = None
for inst_kernel in fn.get_installed_kernels():
if inst_kernel.name == self.kernel.name:
self.restore_kernel = inst_kernel
break
if self.restore_kernel:
fn.logger.info("Restore kernel = %s" % self.restore_kernel.name)
fn.logger.info(
"Restore kernel version = %s" % self.restore_kernel.version
)
else:
fn.logger.info("No previous %s kernel installed" % self.kernel.name)
else:
fn.logger.info("Community kernel, no kernel restore available")
if fn.check_pacman_lockfile() is False:
th_monitor_messages_queue = fn.threading.Thread(
name=fn.thread_monitor_messages,
target=fn.monitor_messages_queue,
daemon=True,
args=(self,),
)
th_monitor_messages_queue.start()
if fn.is_thread_alive(fn.thread_monitor_messages):
self.textbuffer.delete(
self.textbuffer.get_start_iter(), self.textbuffer.get_end_iter()
)
if not fn.is_thread_alive(fn.thread_check_kernel_state):
th_check_kernel_state = fn.threading.Thread(
name=fn.thread_check_kernel_state,
target=self.check_kernel_state,
daemon=True,
)
th_check_kernel_state.start()
if action == "install" and self.source == "community":
self.label_notify_revealer.set_text(
"Installing from %s" % kernel.repository
)
self.reveal_notify()
event = (
"%s [INFO]: Installing kernel from repository %s, kernel = %s-%s\n"
% (
fn.datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"),
self.kernel.repository,
self.kernel.name,
self.kernel.version,
)
)
self.messages_queue.put(event)
if not fn.is_thread_alive(fn.thread_install_community_kernel):
th_install_ch = fn.threading.Thread(
name=fn.thread_install_community_kernel,
target=fn.install_community_kernel,
args=(self,),
daemon=True,
)
th_install_ch.start()
if action == "install" and self.source == "official":
self.label_notify_revealer.set_text("Installing kernel packages ...")
self.reveal_notify()
event = "%s [INFO]: Installing kernel = %s | version = %s\n" % (
fn.datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"),
self.kernel.name,
self.kernel.version,
)
self.messages_queue.put(event)
if not fn.is_thread_alive(fn.thread_install_archive_kernel):
th_install = fn.threading.Thread(
name=fn.thread_install_archive_kernel,
target=fn.install_archive_kernel,
args=(self,),
daemon=True,
)
th_install.start()
if action == "uninstall":
if fn.check_pacman_lockfile() is False:
self.label_notify_revealer.set_text("Removing kernel packages ...")
self.reveal_notify()
event = "%s [INFO]: Uninstalling kernel %s %s\n" % (
fn.datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"),
self.kernel.name,
self.kernel.version,
)
self.messages_queue.put(event)
if not fn.is_thread_alive(fn.thread_uninstall_kernel):
th_uninstall_kernel = fn.threading.Thread(
name=fn.thread_uninstall_kernel,
target=self.uninstall_kernel,
daemon=True,
)
th_uninstall_kernel.start()
else:
self.label_notify_revealer.set_text(
"Pacman lockfile found cannot continue ..."
)
self.reveal_notify()
fn.logger.error(
"Pacman lockfile found, is another pacman process running ?"
)
def timeout(self):
self.hide_notify()
def hide_notify(self):
self.notify_revealer.set_reveal_child(False)
if self.timeout_id is not None:
GLib.source_remove(self.timeout_id)
self.timeout_id = None
def reveal_notify(self):
# reveal = self.notify_revealer.get_reveal_child()
self.notify_revealer.set_reveal_child(True)
self.timeout_id = GLib.timeout_add(3000, self.timeout)
def on_button_close_response(self, widget):
if fn.check_pacman_process(self):
mw = MessageWindow(
title="Pacman process running",
message="Pacman is busy processing a transaction .. please wait",
image_path="images/48x48/akm-progress.png",
transient_for=self,
detailed_message=False,
)
mw.present()
else:
self.destroy()
def on_close(self, data):
if fn.check_pacman_process(self):
mw = MessageWindow(
title="Pacman process running",
message="Pacman is busy processing a transaction .. please wait",
image_path="images/48x48/akm-progress.png",
transient_for=self,
detailed_message=False,
)
mw.present()
return True
return False
def check_kernel_state(self):
returncode = None
kernel = None
while True:
items = self.kernel_state_queue.get()
try:
if items is not None:
returncode, action, kernel = items
if returncode == 0:
self.label_notify_revealer.set_text(
"Kernel %s completed" % action
)
self.reveal_notify()
fn.logger.info("Kernel %s completed" % action)
if returncode == 1:
self.errors_found = True
self.label_notify_revealer.set_text("Kernel %s failed" % action)
self.reveal_notify()
fn.logger.error("Kernel %s failed" % action)
event = "%s <b>[ERROR]: Kernel %s failed</b>\n" % (
fn.datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"),
action,
)
self.messages_queue.put(event)
self.label_status.set_markup(
"<span foreground='orange'><b>Kernel %s failed - see logs above</b></span>"
% action
)
# undo action here if action == install
event = (
"%s<b> [INFO]: Attempting to undo previous Linux package changes</b>\n"
% (
fn.datetime.datetime.now().strftime(
"%Y-%m-%d-%H-%M-%S"
),
)
)
self.messages_queue.put(event)
if action == "install" and self.restore_kernel is not None:
self.restore = True
fn.logger.info(
"Installation failed, attempting removal of previous Linux package changes"
)
self.set_title("Kernel installation failed")
self.label_spinner_progress.set_markup(
"<b>Please wait restoring kernel %s</b>"
% self.restore_kernel.version
)
fn.uninstall(self)
fn.logger.info(
"Restoring previously installed kernel %s"
% self.restore_kernel.version
)
self.official_kernels = [
"%s/packages/l/%s/%s-%s-x86_64%s"
% (
fn.archlinux_mirror_archive_url,
self.restore_kernel.name,
self.restore_kernel.name,
self.restore_kernel.version,
".pkg.tar.zst",
),
"%s/packages/l/%s/%s-%s-x86_64%s"
% (
fn.archlinux_mirror_archive_url,
self.linux_headers,
self.linux_headers,
self.restore_kernel.version,
".pkg.tar.zst",
),
]
self.errors_found = False
fn.install_archive_kernel(self)
self.set_title("Kernel installation failed")
self.label_status.set_markup(
f"<span foreground='orange'><b>Kernel %s failed - see logs above</b></span>\n"
% action
)
# self.spinner.set_spinning(False)
# self.hbox_spinner.hide()
#
# self.label_progress_window_desc.set_markup(
# f"<b>This window can be now closed</b>\n"
# f"<b>A reboot is recommended when Linux packages have changed</b>"
# )
# break
else:
if (
returncode == 0
and "-headers" in kernel
or action == "uninstall"
or action == "install"
and self.errors_found is False
):
fn.update_bootloader(self)
self.update_installed_list()
self.update_official_list()
if len(self.manager_gui.community_kernels) > 0:
self.update_community_list()
if self.restore == False:
self.label_title.set_markup(
"<b>Kernel %s completed</b>" % action
)
self.label_status.set_markup(
"<span foreground='orange'><b>Kernel %s completed</b></span>"
% action
)
self.spinner.set_spinning(False)
self.hbox_spinner.hide()
self.label_progress_window_desc.set_markup(
f"<b>This window can be now closed</b>\n"
f"<b>A reboot is recommended when Linux packages have changed</b>"
)
else:
self.label_title.set_markup(
"<b>Kernel %s failed</b>" % action
)
self.label_status.set_markup(
"<span foreground='orange'><b>Kernel %s failed</b></span>"
% action
)
self.spinner.set_spinning(False)
self.hbox_spinner.hide()
self.label_progress_window_desc.set_markup(
f"<b>This window can be now closed</b>\n"
f"<b>Previous kernel restored due to failure</b>\n"
f"<b>A reboot is recommended when Linux packages have changed</b>"
)
# # else:
# self.spinner.set_spinning(False)
# self.hbox_spinner.hide()
#
# self.label_progress_window_desc.set_markup(
# f"<b>This window can be now closed</b>\n"
# f"<b>A reboot is recommended when Linux packages have changed</b>"
# )
break
except Exception as e:
fn.logger.error("Exception in check_kernel_state(): %s" % e)
finally:
self.kernel_state_queue.task_done()
def update_installed_list(self):
self.manager_gui.installed_kernels = fn.get_installed_kernels()
GLib.idle_add(
self.manager_gui.kernel_stack.add_installed_kernels_to_stack, True
)
def update_official_list(self):
self.manager_gui.installed_kernels = fn.get_installed_kernels()
GLib.idle_add(
self.manager_gui.kernel_stack.add_official_kernels_to_stack,
True,
)
def update_community_list(self):
self.manager_gui.installed_kernels = fn.get_installed_kernels()
GLib.idle_add(
self.manager_gui.kernel_stack.add_community_kernels_to_stack,
True,
)
def uninstall_kernel(self):
event = "%s [INFO]: Uninstalling kernel %s\n" % (
fn.datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"),
self.kernel.version,
)
self.messages_queue.put(event)
fn.uninstall(self)

715
ui/SettingsWindow.py Normal file
View File

@@ -0,0 +1,715 @@
import gi
import os
from ui.Stack import Stack
from ui.MessageWindow import MessageWindow
import functions as fn
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk, Gio, GLib, GObject
base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
class SettingsWindow(Gtk.Window):
def __init__(self, fn, manager_gui, **kwargs):
super().__init__(**kwargs)
self.set_title("Arch Linux Kernel Manager - Settings")
self.set_resizable(False)
self.set_size_request(600, 600)
stack = Stack(transition_type="CROSSFADE")
self.set_icon_name("akm-tux")
self.manager_gui = manager_gui
self.set_modal(True)
self.set_transient_for(self.manager_gui)
self.queue_kernels = self.manager_gui.queue_kernels
header_bar = Gtk.HeaderBar()
header_bar.set_show_title_buttons(True)
self.set_titlebar(header_bar)
hbox_main = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
hbox_main.set_name("box")
self.set_child(child=hbox_main)
vbox_header = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
vbox_header.set_name("vbox_header")
lbl_heading = Gtk.Label(xalign=0.5, yalign=0.5)
lbl_heading.set_name("label_flowbox_message")
lbl_heading.set_text("Preferences")
lbl_padding = Gtk.Label(xalign=0.0, yalign=0.0)
lbl_padding.set_text(" ")
grid_banner_img = Gtk.Grid()
image_settings = Gtk.Image.new_from_file(
os.path.join(base_dir, "images/48x48/akm-settings.png")
)
image_settings.set_icon_size(Gtk.IconSize.LARGE)
image_settings.set_halign(Gtk.Align.START)
grid_banner_img.attach(image_settings, 0, 1, 1, 1)
grid_banner_img.attach_next_to(
lbl_padding,
image_settings,
Gtk.PositionType.RIGHT,
1,
1,
)
grid_banner_img.attach_next_to(
lbl_heading,
lbl_padding,
Gtk.PositionType.RIGHT,
1,
1,
)
vbox_header.append(grid_banner_img)
hbox_main.append(vbox_header)
stack_switcher = Gtk.StackSwitcher()
stack_switcher.set_orientation(Gtk.Orientation.HORIZONTAL)
stack_switcher.set_stack(stack)
button_close = Gtk.Button(label="Close")
button_close.connect("clicked", self.on_close_clicked)
hbox_stack_sidebar = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
hbox_stack_sidebar.set_name("box")
hbox_stack_sidebar.append(stack_switcher)
hbox_stack_sidebar.append(stack)
hbox_main.append(hbox_stack_sidebar)
vbox_button = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
vbox_button.set_halign(Gtk.Align.END)
vbox_button.set_name("box")
vbox_button.append(button_close)
hbox_stack_sidebar.append(vbox_button)
vbox_settings = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
vbox_settings.set_name("box")
label_official_kernels = Gtk.Label(xalign=0, yalign=0)
label_official_kernels.set_markup(
"<b>Latest Official kernels (%s)</b>" % len(fn.supported_kernels_dict)
)
label_community_kernels = Gtk.Label(xalign=0, yalign=0)
label_community_kernels.set_markup(
"<b>Latest Community based kernels (%s)</b>"
% len(self.manager_gui.community_kernels)
)
vbox_settings_listbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
self.listbox_official_kernels = Gtk.ListBox()
self.listbox_official_kernels.set_selection_mode(Gtk.SelectionMode.NONE)
self.label_loading_kernels = Gtk.Label(xalign=0, yalign=0)
self.label_loading_kernels.set_text("Loading ...")
self.listbox_official_kernels.append(self.label_loading_kernels)
listbox_community_kernels = Gtk.ListBox()
listbox_community_kernels.set_selection_mode(Gtk.SelectionMode.NONE)
scrolled_window_community = Gtk.ScrolledWindow()
scrolled_window_official = Gtk.ScrolledWindow()
scrolled_window_community.set_policy(
Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC
)
scrolled_window_official.set_policy(
Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC
)
scrolled_window_community.set_size_request(0, 150)
scrolled_window_official.set_size_request(0, 150)
scrolled_window_official.set_child(self.listbox_official_kernels)
vbox_community_warning = None
self.kernel_versions_queue = fn.Queue()
fn.Thread(
target=fn.get_latest_versions,
args=(self,),
daemon=True,
).start()
fn.Thread(target=self.check_official_version_queue, daemon=True).start()
if len(self.manager_gui.community_kernels) > 0:
for community_kernel in self.manager_gui.community_kernels:
row_community_kernel = Gtk.ListBoxRow()
hbox_community_kernel = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL, spacing=5
)
hbox_community_kernel.set_name("box_row")
hbox_row_official_kernel_row = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL, spacing=10
)
label_community_kernel = Gtk.Label(xalign=0, yalign=0)
label_community_kernel.set_text("%s" % community_kernel.name)
label_community_kernel_version = Gtk.Label(xalign=0, yalign=0)
label_community_kernel_version.set_text("%s" % community_kernel.version)
hbox_row_official_kernel_row.append(label_community_kernel)
hbox_row_official_kernel_row.append(label_community_kernel_version)
hbox_community_kernel.append(hbox_row_official_kernel_row)
row_community_kernel.set_child(hbox_community_kernel)
listbox_community_kernels.append(row_community_kernel)
scrolled_window_community.set_child(listbox_community_kernels)
else:
vbox_community_warning = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL, spacing=10
)
vbox_community_warning.set_name("box")
image_warning = Gtk.Image.new_from_file(
os.path.join(base_dir, "images/48x48/akm-warning.png")
)
image_warning.set_icon_size(Gtk.IconSize.LARGE)
image_warning.set_halign(Gtk.Align.START)
hbox_warning = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
hbox_warning.set_name("box")
hbox_warning.append(image_warning)
label_pacman_no_community = Gtk.Label(xalign=0, yalign=0)
label_pacman_no_community.set_markup(
f"<b>Cannot find any supported unofficial pacman repository's</b>\n"
f"Add unofficial pacman repository's to use community based kernels"
)
hbox_warning.append(label_pacman_no_community)
vbox_community_warning.append(hbox_warning)
vbox_settings_listbox.append(label_official_kernels)
vbox_settings_listbox.append(scrolled_window_official)
vbox_settings_listbox.append(label_community_kernels)
if len(self.manager_gui.community_kernels) > 0:
vbox_settings_listbox.append(scrolled_window_community)
else:
vbox_settings_listbox.append(vbox_community_warning)
vbox_settings.append(vbox_settings_listbox)
vbox_settings_adv = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
vbox_settings_adv.set_name("box")
self.listbox_settings_adv = Gtk.ListBox()
self.listbox_settings_adv.set_selection_mode(Gtk.SelectionMode.NONE)
row_settings_adv = Gtk.ListBoxRow()
self.listbox_settings_adv.append(row_settings_adv)
hbox_bootloader_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
hbox_bootloader_row.set_name("box_row")
hbox_bootloader_row.set_halign(Gtk.Align.START)
self.hbox_bootloader_grub_row = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL, spacing=5
)
self.hbox_bootloader_grub_row.set_name("box_row")
self.hbox_bootloader_grub_row.set_halign(Gtk.Align.START)
self.text_entry_bootloader_file = Gtk.Entry()
hbox_switch_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
hbox_switch_row.set_name("box_row")
hbox_switch_row.set_halign(Gtk.Align.START)
hbox_log_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
hbox_log_row.set_name("box_row")
hbox_log_row.set_halign(Gtk.Align.START)
label_bootloader = Gtk.Label(xalign=0, yalign=0)
label_bootloader.set_markup("<b>Bootloader</b>")
hbox_warning = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
hbox_warning.set_name("hbox_warning")
label_bootloader_warning = Gtk.Label(xalign=0, yalign=0)
label_bootloader_warning.set_markup(
f"Only change this setting if you know what you are doing\n"
f"The selected Grub/Systemd-boot bootloader entry will be updated\n"
f"<b>This may break your system</b>"
)
hbox_warning.append(label_bootloader_warning)
label_settings_bootloader_title = Gtk.Label(xalign=0.5, yalign=0.5)
label_settings_bootloader_title.set_markup("Current Bootloader")
self.label_settings_bootloader_file = Gtk.Label(xalign=0.5, yalign=0.5)
self.label_settings_bootloader_file.set_text("GRUB config file")
self.button_override_bootloader = Gtk.Button(
label="Override bootloader settings"
)
self.button_override_bootloader.connect("clicked", self.on_override_clicked)
self.hbox_bootloader_override_row = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL, spacing=20
)
self.hbox_bootloader_override_row.set_name("box_row")
self.hbox_bootloader_override_row.append(self.button_override_bootloader)
boot_loaders = {0: "grub", 1: "systemd-boot"}
# Set up the factory
factory = Gtk.SignalListItemFactory()
factory.connect("setup", self._on_factory_setup)
factory.connect("bind", self._on_factory_bind)
self.model = Gio.ListStore(item_type=Bootloader)
for bootloader_id in boot_loaders.keys():
self.model.append(
Bootloader(
id=bootloader_id,
name=boot_loaders[bootloader_id],
)
)
self.dropdown_bootloader = Gtk.DropDown(
model=self.model, factory=factory, hexpand=True
)
self.dropdown_bootloader.set_sensitive(False)
self.selected_bootloader = None
self._bootloader_grub_config = "/boot/grub/grub.cfg"
row_settings_override_grub = Gtk.ListBoxRow()
row_settings_grub = Gtk.ListBoxRow()
self.listbox_settings_adv.append(row_settings_grub)
self.listbox_settings_adv.append(row_settings_override_grub)
self.text_entry_bootloader_file.connect("changed", self.on_entry_changed)
self.text_entry_bootloader_file.props.editable = False
text_entry_buffer_file = Gtk.EntryBuffer()
if self.manager_gui.bootloader_grub_cfg is not None:
text_entry_buffer_file.set_text(
self.manager_gui.bootloader_grub_cfg,
len(self.manager_gui.bootloader_grub_cfg),
)
else:
text_entry_buffer_file.set_text(
self._bootloader_grub_config,
len(self._bootloader_grub_config),
)
self.text_entry_bootloader_file.set_buffer(text_entry_buffer_file)
self.text_entry_bootloader_file.set_halign(Gtk.Align.END)
self.text_entry_bootloader_file.set_sensitive(False)
label_grub_file_path = Gtk.Label(xalign=0.5, yalign=0.5)
label_grub_file_path.set_markup("Grub file path")
self.hbox_bootloader_grub_row.append(label_grub_file_path)
self.hbox_bootloader_grub_row.append(self.text_entry_bootloader_file)
row_settings_grub.set_child(self.hbox_bootloader_grub_row)
if manager_gui.bootloader == "grub":
self.dropdown_bootloader.set_selected(0)
self.selected_bootloader = 0
self.hbox_bootloader_grub_row.set_visible(True)
row_settings_override_grub.set_child(self.hbox_bootloader_override_row)
if manager_gui.bootloader == "systemd-boot":
self.selected_bootloader = 1
self.dropdown_bootloader.set_selected(1)
row_settings_override_systemd = Gtk.ListBoxRow()
self.listbox_settings_adv.append(row_settings_override_systemd)
row_settings_override_systemd.set_child(self.hbox_bootloader_override_row)
self.hbox_bootloader_grub_row.set_visible(False)
self.dropdown_bootloader.connect(
"notify::selected-item", self._on_selected_item_notify
)
hbox_bootloader_row.append(label_settings_bootloader_title)
hbox_bootloader_row.append(self.dropdown_bootloader)
row_settings_adv.set_child(hbox_bootloader_row)
vbox_settings_adv.append(label_bootloader)
vbox_settings_adv.append(hbox_warning)
vbox_settings_adv.append(self.listbox_settings_adv)
listbox_settings_cache = Gtk.ListBox()
listbox_settings_cache.set_selection_mode(Gtk.SelectionMode.NONE)
row_settings_cache = Gtk.ListBoxRow()
listbox_settings_cache.append(row_settings_cache)
label_cache = Gtk.Label(xalign=0, yalign=0)
label_cache.set_markup("<b>Refresh data from Arch Linux Archive</b>")
label_cache_update = Gtk.Label(xalign=0.5, yalign=0.5)
label_cache_update.set_text("Update (this will take some time)")
self.label_cache_update_status = Gtk.Label(xalign=0.5, yalign=0.5)
switch_refresh_cache = Gtk.Switch()
switch_refresh_cache.connect("state-set", self.refresh_toggle)
label_cache_file = Gtk.Label(xalign=0, yalign=0)
label_cache_file.set_text(fn.cache_file)
label_cache_file.set_selectable(True)
self.label_cache_lastmodified = Gtk.Label(xalign=0, yalign=0)
self.label_cache_lastmodified.set_markup(
"Last modified date: <b>%s</b>" % fn.get_cache_last_modified()
)
hbox_switch_row.append(label_cache_update)
hbox_switch_row.append(switch_refresh_cache)
hbox_switch_row.append(self.label_cache_update_status)
row_settings_cache.set_child(hbox_switch_row)
label_logfile = Gtk.Label(xalign=0, yalign=0)
label_logfile.set_markup("<b>Log file</b>")
button_logfile = Gtk.Button(label="Open event log file")
button_logfile.connect("clicked", self.on_button_logfile_clicked)
label_logfile_location = Gtk.Label(xalign=0.5, yalign=0.5)
label_logfile_location.set_text(fn.event_log_file)
label_logfile_location.set_selectable(True)
hbox_log_row.append(button_logfile)
hbox_log_row.append(label_logfile_location)
listbox_settings_log = Gtk.ListBox()
listbox_settings_log.set_selection_mode(Gtk.SelectionMode.NONE)
row_settings_log = Gtk.ListBoxRow()
listbox_settings_log.append(row_settings_log)
row_settings_log.set_child(hbox_log_row)
vbox_settings_adv.append(label_cache)
vbox_settings_adv.append(self.label_cache_lastmodified)
vbox_settings_adv.append(label_cache_file)
vbox_settings_adv.append(listbox_settings_cache)
vbox_settings_adv.append(label_logfile)
vbox_settings_adv.append(listbox_settings_log)
stack.add_titled(vbox_settings_adv, "Advanced Settings", "Advanced")
stack.add_titled(vbox_settings, "Kernels", "Kernel versions")
def populate_official_kernels(self):
self.label_loading_kernels.hide()
for official_kernel in fn.supported_kernels_dict:
row_official_kernel = Gtk.ListBoxRow()
hbox_row_official = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
hbox_row_official_kernel_row = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL, spacing=10
)
hbox_row_official.set_name("box_row")
label_kernel = Gtk.Label(xalign=0, yalign=0)
label_kernel.set_text("%s" % official_kernel)
label_kernel_version = Gtk.Label(xalign=0, yalign=0)
label_kernel_version.set_text("%s" % self.kernel_versions[official_kernel])
hbox_row_official_kernel_row.append(label_kernel)
hbox_row_official_kernel_row.append(label_kernel_version)
hbox_row_official.append(hbox_row_official_kernel_row)
row_official_kernel.set_child(hbox_row_official)
self.listbox_official_kernels.append(row_official_kernel)
def check_official_version_queue(self):
while True:
self.kernel_versions = self.kernel_versions_queue.get()
if self.kernel_versions is not None:
break
self.kernel_versions_queue.task_done()
GLib.idle_add(self.populate_official_kernels, priority=GLib.PRIORITY_DEFAULT)
def on_entry_changed(self, entry):
if (
len(entry.get_text()) > 0
and entry.get_text() != self.manager_gui.bootloader_grub_cfg
):
self.button_override_bootloader.get_child().set_text("Apply changes")
def _on_factory_setup(self, factory, list_item):
label = Gtk.Label()
list_item.set_child(label)
def _on_factory_bind(self, factory, list_item):
label = list_item.get_child()
bootloader = list_item.get_item()
label.set_text(bootloader.name)
def on_override_clicked(self, widget):
if self.button_override_bootloader.get_child().get_text() == "Apply changes":
# validate bootloader
if self.dropdown_bootloader.get_selected() == 1:
if not os.path.exists(
"/sys/firmware/efi/fw_platform_size"
) or not os.path.exists("/sys/firmware/efi/efivars"):
mw = MessageWindow(
title="Legacy boot detected",
message="Cannot select systemd-boot, UEFI boot mode is not available",
image_path="images/48x48/akm-warning.png",
transient_for=self,
detailed_message=False,
)
mw.present()
self.dropdown_bootloader.set_selected(0)
return
config_data = fn.read_config(self)
if config_data is not None:
# grub
if (
self.dropdown_bootloader.get_selected() == 0
and len(
self.text_entry_bootloader_file.get_buffer().get_text().strip()
)
> 0
):
if fn.os.path.exists(
self.text_entry_bootloader_file.get_buffer().get_text().strip()
):
if "bootloader" in config_data.keys():
config_data.remove("bootloader")
bootloader = fn.tomlkit.table(True)
bootloader.update({"name": "grub"})
bootloader.update(
{
"grub_config": self.text_entry_bootloader_file.get_buffer()
.get_text()
.strip()
}
)
config_data.append("bootloader", bootloader)
if fn.update_config(config_data, "grub") is True:
self.manager_gui.bootloader = "grub"
self.manager_gui.bootloader_grub_cfg = (
self.text_entry_bootloader_file.get_buffer()
.get_text()
.strip()
)
else:
mw = MessageWindow(
title="Grub config file",
message="The specified Grub config file %s does not exist"
% self.text_entry_bootloader_file.get_buffer()
.get_text()
.strip(),
image_path="images/48x48/akm-warning.png",
transient_for=self,
detailed_message=False,
)
mw.present()
self.button_override_bootloader.get_child().set_text(
"Override bootloader settings"
)
elif (
self.dropdown_bootloader.get_selected() == 1
and self.selected_bootloader
!= self.dropdown_bootloader.get_selected()
):
if "bootloader" in config_data.keys():
config_data.remove("bootloader")
self.hbox_bootloader_grub_row.set_visible(True)
bootloader = fn.tomlkit.table(True)
bootloader.update({"name": "systemd-boot"})
config_data.append("bootloader", bootloader)
if fn.update_config(config_data, "systemd-boot") is True:
self.manager_gui.bootloader = "systemd-boot"
else:
self.dropdown_bootloader.set_sensitive(True)
if self.dropdown_bootloader.get_selected() == 0:
self.hbox_bootloader_grub_row.set_visible(True)
self.text_entry_bootloader_file.set_sensitive(True)
self.text_entry_bootloader_file.props.editable = True
elif self.dropdown_bootloader.get_selected() == 1:
self.hbox_bootloader_grub_row.set_visible(False)
def _on_selected_item_notify(self, dd, _):
if self.dropdown_bootloader.get_selected() != self.selected_bootloader:
self.button_override_bootloader.get_child().set_text("Apply changes")
else:
self.button_override_bootloader.get_child().set_text(
"Override bootloader settings"
)
if dd.get_selected() == 1:
if self.text_entry_bootloader_file is not None:
self.hbox_bootloader_grub_row.set_visible(False)
elif dd.get_selected() == 0:
if self.text_entry_bootloader_file is not None:
self.hbox_bootloader_grub_row.set_visible(True)
self.text_entry_bootloader_file.set_sensitive(True)
self.text_entry_bootloader_file.props.editable = True
def monitor_kernels_queue(self, switch):
while True:
if len(fn.fetched_kernels_dict) > 0:
self.manager_gui.official_kernels = self.queue_kernels.get()
self.queue_kernels.task_done()
self.refreshed = True
if self.manager_gui.official_kernels is not None:
switch.set_sensitive(False)
self.update_official_list()
self.update_community_list()
self.update_timestamp()
self.label_cache_update_status.set_markup(
"<b>Cache refresh completed</b>"
)
else:
self.label_cache_update_status.set_markup(
"<b>Cache refresh failed</b>"
)
self.refreshed = False
self.update_timestamp()
break
else:
self.label_cache_update_status.set_markup(
"<b>Cache refresh in progress</b>"
)
# fn.time.sleep(0.3)
def refresh_toggle(self, switch, data):
if switch.get_active() is True:
# refresh cache
fn.logger.info("Refreshing cache file %s" % fn.cache_file)
switch.set_sensitive(False)
try:
th_refresh_cache = fn.Thread(
name=fn.thread_refresh_cache,
target=fn.refresh_cache,
args=(self,),
daemon=True,
)
th_refresh_cache.start()
# monitor queue
fn.Thread(
target=self.monitor_kernels_queue, daemon=True, args=(switch,)
).start()
except Exception as e:
fn.logger.error("Exception in refresh_toggle(): %s" % e)
self.label_cache_update_status.set_markup("<b>Cache refresh failed</b>")
def update_timestamp(self):
if self.refreshed is True:
self.label_cache_lastmodified.set_markup(
"Last modified date: <span foreground='orange'><b>%s</b></span>"
% fn.get_cache_last_modified()
)
else:
self.label_cache_lastmodified.set_markup(
"Last modified date: <span foreground='orange'><b>%s</b></span>"
% "Refresh failed"
)
def update_official_list(self):
self.manager_gui.installed_kernels = fn.get_installed_kernels()
GLib.idle_add(
self.manager_gui.kernel_stack.add_official_kernels_to_stack,
True,
)
def update_community_list(self):
self.manager_gui.installed_kernels = fn.get_installed_kernels()
GLib.idle_add(
self.manager_gui.kernel_stack.add_community_kernels_to_stack,
True,
)
def on_close_clicked(self, widget):
self.destroy()
def on_button_logfile_clicked(self, widget):
try:
cmd = ["sudo", "-u", fn.sudo_username, "xdg-open", fn.event_log_file]
fn.subprocess.Popen(
cmd,
shell=False,
stdout=fn.subprocess.PIPE,
stderr=fn.subprocess.STDOUT,
)
except Exception as e:
fn.logger.error("Exception in on_button_logfile_clicked(): %s" % e)
class Bootloader(GObject.Object):
__gtype_name__ = "Bootloader"
def __init__(self, id, name):
super().__init__()
self.id = id
self.name = name
@GObject.Property
def bootloader_id(self):
return self.id
@GObject.Property
def bootloader_name(self):
return self.name

30
ui/SplashScreen.py Normal file
View File

@@ -0,0 +1,30 @@
import gi
import functions as fn
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk, Gio
base_dir = fn.os.path.abspath(fn.os.path.join(fn.os.path.dirname(__file__), ".."))
class SplashScreen(Gtk.Window):
def __init__(self, app_name, **kwargs):
super().__init__(**kwargs)
self.set_decorated(False)
self.set_resizable(False)
self.set_default_size(600, 400)
self.set_modal(True)
self.set_title(app_name)
self.set_icon_name("archlinux-kernel-manager-tux")
tux_icon = Gtk.Picture.new_for_file(
file=Gio.File.new_for_path(
fn.os.path.join(base_dir, "images/600x400/akm-tux-splash.png")
)
)
tux_icon.set_content_fit(content_fit=Gtk.ContentFit.FILL)
self.set_child(child=tux_icon)
self.present()

30
ui/Stack.py Normal file
View File

@@ -0,0 +1,30 @@
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk
class Stack(Gtk.Stack):
def __init__(self, transition_type):
super(Stack, self).__init__()
# self.set_transition_type(Gtk.StackTransitionType.ROTATE_LEFT)
if transition_type == "ROTATE_LEFT":
transition_type = Gtk.StackTransitionType.ROTATE_LEFT
if transition_type == "ROTATE_RIGHT":
transition_type = Gtk.StackTransitionType.ROTATE_RIGHT
if transition_type == "CROSSFADE":
transition_type = Gtk.StackTransitionType.CROSSFADE
if transition_type == "SLIDE_UP":
transition_type = Gtk.StackTransitionType.SLIDE_UP
if transition_type == "SLIDE_DOWN":
transition_type = Gtk.StackTransitionType.SLIDE_DOWN
if transition_type == "OVER_DOWN":
transition_type = Gtk.StackTransitionType.OVER_DOWN
self.set_transition_type(transition_type)
self.set_hexpand(True)
self.set_vexpand(True)
self.set_transition_duration(250)
self.set_hhomogeneous(False)
self.set_vhomogeneous(False)