🐛 fix(_dir): prepare & extend for PKGBUILD

This commit is contained in:
Eshan Roy
2024-11-28 09:07:50 +05:30
parent 56ebd85ea4
commit 0aaa5761ce
12 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
#!/usr/bin/python
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_self_value = (datetime.strptime(self.last_modified, "%d-%b-%Y %H:%M").replace(tzinfo=None).date())
datetime_value_other = (datetime.strptime(self.last_modified, "%d-%b-%Y %H:%M").replace(tzinfo=None).date())
if datetime_value_other >= datetime_self_value:
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

File diff suppressed because it is too large Load Diff

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 libs.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://snigdhaos.org/"
authors = ["Eshan Roy", "Abhiraj Roy"]
program_name = "SnigdhaOS Kernel Switcher"
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 = "sks-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

View File

@@ -0,0 +1,668 @@
import datetime
import gi
import os
import libs.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
downgrade = False
community_repo = False
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]
):
downgrade = True
title = "Downgrading %s kernel" % kernel.name
else:
downgrade = False
title = "Upgrading %s kernel" % kernel.name
break
if title is None:
title = "Kernel installation"
if self.source == "community":
message = (
"<span foreground='orange'><b>Community kernel selected - this may break your system</b></span>\n"
"Confirm the install of <b>%s-%s</b>"
% (
kernel.name,
kernel.version,
)
)
# check if the community pacman repo is configured
if fn.check_pacman_repo(kernel.repository) is True:
community_repo = True
else:
community_repo = False
fn.logger.error(
"%s pacman repo is not configured" % kernel.repository
)
elif self.source == "official":
message = "Confirm the install of <b>%s-%s</b>" % (
kernel.name,
kernel.version,
)
if community_repo is False and self.source == "community":
mw = MessageWindow(
title="Cannot find %s pacman repo" % kernel.repository,
message="Enable the pacman repository then retry the installation",
transient_for=self.manager_gui,
detailed_message=False,
)
mw.present()
else:
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,
downgrade=downgrade,
)
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 = "Confirm the removal of <b>%s-%s</b>" % (
kernel.name,
kernel.version,
)
elif self.source == "official":
message = "Confirm the removal of <b>%s-%s</b>" % (
kernel.name,
kernel.version,
)
message_window = FlowBoxMessageWindow(
title="Kernel uninstallation",
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,
downgrade=downgrade,
)
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",
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,
)
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,
downgrade=None,
)
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",
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,
downgrade,
**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
self.downgrade = downgrade
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

View File

@@ -0,0 +1,657 @@
import gi
import os
import libs.functions as fn
from ui.FlowBox import FlowBox, FlowBoxInstalled
from ui.Stack import Stack
from libs.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(
"Active kernel: <b>%s</b>" % 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(
"Active kernel: <b>%s</b>" % 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=0)
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(
"Active kernel: <b>%s</b>" % 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")
if (
self.manager_gui.community_kernels is not None
and len(self.manager_gui.community_kernels) == 0
):
label_warning.set_markup(
f"<b>Cannot find any supported unofficial pacman repository's</b>\n"
f"<b>Add the Chaotic-AUR pacman repository to access Community based kernels</b>"
)
else:
label_warning.set_markup(
f"These kernels are user produced content\n"
f"These kernels may not work on your hardware\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() == "hbox_warning":
for w in stack_widget:
if w.get_name() == "label_community_warning":
if len(self.manager_gui.community_kernels) == 0:
w.set_markup(
f"<b>Cannot find any supported unofficial pacman repository's</b>\n"
f"<b>Add the Chaotic-AUR pacman repository to access Community based kernels</b>"
)
else:
w.set_markup(
f"These kernels are user produced content\n"
f"These kernels may not work on your hardware\n"
f"<b>Any use of the provided files is at your own risk</b>"
)
break
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:
widget.remove_all()
# scrolled_window_community.hide()
# vbox_search_entry = Gtk.Box(
# orientation=Gtk.Orientation.VERTICAL, spacing=5
# )
#
# vbox_search_entry.append(search_entry_community)
# widget.append(vbox_search_entry)
if (
self.manager_gui.community_kernels is not None
and len(self.manager_gui.community_kernels) > 0
):
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=0)
# 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"
)

View File

@@ -0,0 +1,573 @@
import gi
import os
from ui.MenuButton import MenuButton
from ui.Stack import Stack
from ui.KernelStack import KernelStack
from ui.FlowBox import FlowBox, FlowBoxInstalled
from ui.AboutDialog import AboutDialog
from ui.SplashScreen import SplashScreen
from ui.MessageWindow import MessageWindow
from ui.SettingsWindow import SettingsWindow
import libs.functions as fn
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk, Gio, Gdk, GLib
base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
class ManagerGUI(Gtk.ApplicationWindow):
def __init__(self, app_name, default_context, app_version, **kwargs):
super().__init__(**kwargs)
self.default_context = default_context
self.app_version = app_version
if self.app_version == "${app_version}":
self.app_version = "dev"
self.set_title(app_name)
self.set_resizable(True)
self.set_default_size(950, 650)
# get list of kernels from the arch archive website, aur, then cache
self.official_kernels = []
self.community_kernels = []
# splashscreen queue for threading
self.queue_load_progress = fn.Queue()
# official kernels queue for threading
self.queue_kernels = fn.Queue()
# community kernels queue for threading
self.queue_community_kernels = fn.Queue()
self.splash_screen = SplashScreen(app_name)
try:
fn.Thread(
target=self.wait_for_gui_load,
daemon=True,
).start()
except Exception as e:
fn.logger.error(e)
while self.default_context.pending():
fn.time.sleep(0.1)
self.default_context.iteration(True)
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)
# while self.default_context.pending():
# fn.time.sleep(0.1)
# self.default_context.iteration(True)
self.bootloader = None
self.bootloader_grub_cfg = None
# self.bootloader = fn.get_boot_loader()
config_data = fn.setup_config(self)
fn.logger.info("Version = %s" % self.app_version)
fn.logger.info("Distro = %s" % fn.distro.id())
if "bootloader" in config_data.keys():
if config_data["bootloader"]["name"] is not None:
self.bootloader = config_data["bootloader"]["name"].lower()
if self.bootloader == "grub":
if config_data["bootloader"]["grub_config"] is not None:
self.bootloader_grub_cfg = config_data["bootloader"][
"grub_config"
]
elif self.bootloader != "systemd-boot" or self.bootloader != "grub":
fn.logger.warning(
"Invalid bootloader config found it should only be systemd-boot or grub"
)
fn.logger.warning("Using bootctl to determine current bootloader")
self.bootloader = None
if self.bootloader is not None or self.bootloader_grub_cfg is not None:
fn.logger.info("User provided bootloader options read from config file")
fn.logger.info("User bootloader option = %s " % self.bootloader)
if self.bootloader_grub_cfg is not None:
fn.logger.info(
"User bootloader Grub config = %s " % self.bootloader_grub_cfg
)
else:
# no config setting found for bootloader use default method
self.bootloader = fn.get_boot_loader()
if self.bootloader == "grub":
self.bootloader_grub_cfg = "/boot/grub/grub.cfg"
if self.bootloader is not None:
fn.create_cache_dir()
fn.create_log_dir()
fn.get_pacman_repos()
self.stack = Stack(transition_type="OVER_DOWN")
self.kernel_stack = KernelStack(self)
header_bar = Gtk.HeaderBar()
label_title = Gtk.Label(xalign=0.5, yalign=0.5)
label_title.set_markup("<b>%s</b>" % app_name)
header_bar.set_title_widget(label_title)
header_bar.set_show_title_buttons(True)
self.set_titlebar(header_bar)
menu_outerbox = Gtk.Box(spacing=6, orientation=Gtk.Orientation.VERTICAL)
header_bar.pack_end(menu_outerbox)
menu_outerbox.show()
menubutton = MenuButton()
menu_outerbox.append(menubutton)
menubutton.show()
action_about = Gio.SimpleAction(name="about")
action_about.connect("activate", self.on_about)
action_settings = Gio.SimpleAction(name="settings")
action_settings.connect("activate", self.on_settings, fn)
self.add_action(action_settings)
self.add_action(action_about)
action_refresh = Gio.SimpleAction(name="refresh")
action_refresh.connect("activate", self.on_refresh)
self.add_action(action_refresh)
action_quit = Gio.SimpleAction(name="quit")
action_quit.connect("activate", self.on_quit)
self.add_action(action_quit)
# add shortcut keys
event_controller_key = Gtk.EventControllerKey.new()
event_controller_key.connect("key-pressed", self.key_pressed)
self.add_controller(event_controller_key)
# overlay = Gtk.Overlay()
# self.set_child(child=overlay)
self.vbox = Gtk.Box.new(orientation=Gtk.Orientation.VERTICAL, spacing=10)
self.vbox.set_name("main")
self.set_child(child=self.vbox)
self.vbox.append(self.notify_revealer)
self.installed_kernels = fn.get_installed_kernels()
if self.installed_kernels is not None:
fn.logger.info("Installed kernels = %s" % len(self.installed_kernels))
self.active_kernel = fn.get_active_kernel()
self.refresh_cache = False
self.refresh_cache = fn.get_latest_kernel_updates(self)
self.start_get_kernels_threads()
self.load_kernels_gui()
# validate bootloader
if self.bootloader_grub_cfg and not os.path.exists(
self.bootloader_grub_cfg
):
mw = MessageWindow(
title="Grub config file not found",
message=f"The specified Grub config file: {self.bootloader_grub_cfg} does not exist\n"
f"This will cause an issue when updating the bootloader\n"
f"Update the configuration file/use the Advanced Settings to change this\n",
detailed_message=False,
transient_for=self,
)
mw.present()
if self.bootloader == "systemd-boot":
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=f"Cannot select systemd-boot, UEFI boot mode is not available\n"
f"Update the configuration file\n"
f"Or use the Advanced Settings to change this\n",
detailed_message=False,
transient_for=self,
)
mw.present()
else:
fn.logger.error("Failed to set bootloader, application closing")
fn.sys.exit(1)
def key_pressed(self, keyval, keycode, state, userdata):
shortcut = Gtk.accelerator_get_label(
keycode, keyval.get_current_event().get_modifier_state()
)
# quit application
if shortcut in ("Ctrl+Q", "Ctrl+Mod2+Q"):
self.destroy()
def open_settings(self, fn):
settings_win = SettingsWindow(fn, self)
settings_win.present()
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 start_get_kernels_threads(self):
if self.refresh_cache is False:
fn.logger.info("Starting get official Linux kernels thread")
try:
fn.Thread(
name=fn.thread_get_kernels,
target=fn.get_official_kernels,
daemon=True,
args=(self,),
).start()
except Exception as e:
fn.logger.error("Exception in thread fn.get_official_kernels(): %s" % e)
finally:
self.official_kernels = self.queue_kernels.get()
self.queue_kernels.task_done()
else:
self.official_kernels = self.queue_kernels.get()
self.queue_kernels.task_done()
# =====================================================
# PACMAN DB SYNC
# =====================================================
def pacman_db_sync(self):
sync_err = fn.sync_package_db()
if sync_err is not None:
# fn.logger.error("Pacman db synchronization failed")
GLib.idle_add(
self.show_sync_window,
sync_err,
priority=GLib.PRIORITY_DEFAULT,
)
return False
else:
fn.logger.info("Pacman DB synchronization completed")
return True
def show_sync_window(self, sync_err):
mw = MessageWindow(
title="Error - Pacman db synchronization",
message=f"Pacman db synchronization failed\n"
f"Failed to run 'pacman -Syu'\n"
f"{sync_err}\n",
transient_for=self,
detailed_message=True,
)
mw.present()
# keep splash screen open, until main gui is loaded
def wait_for_gui_load(self):
while True:
if fn.logger.getEffectiveLevel() == 10:
fn.logger.debug("Waiting for GUI to load ..")
# fn.time.sleep(0.2)
status = self.queue_load_progress.get()
try:
if fn.logger.getEffectiveLevel() == 10:
fn.logger.debug("Status = %s" % status)
if status == 1:
if fn.logger.getEffectiveLevel() == 10:
fn.logger.debug("Destroying splashscreen")
GLib.idle_add(
self.splash_screen.destroy,
priority=GLib.PRIORITY_DEFAULT,
)
break
except Exception as e:
fn.logger.error("Exception in wait_for_gui_load(): %s" % e)
finally:
self.queue_load_progress.task_done()
def on_settings(self, action, param, fn):
self.open_settings(fn)
def on_about(self, action, param):
about_dialog = AboutDialog(self)
about_dialog.present()
def on_refresh(self, action, param):
if not fn.is_thread_alive(fn.thread_refresh_ui):
fn.Thread(
name=fn.thread_refresh_ui,
target=self.refresh_ui,
daemon=True,
).start()
def refresh_ui(self):
if fn.logger.getEffectiveLevel() == 10:
fn.logger.debug("Refreshing UI")
self.label_notify_revealer.set_text("Refreshing UI started")
GLib.idle_add(
self.reveal_notify,
priority=GLib.PRIORITY_DEFAULT,
)
fn.pacman_repos_list = []
fn.get_pacman_repos()
fn.cached_kernels_list = []
fn.community_kernels_list = []
self.official_kernels = None
self.community_kernels = None
self.installed_kernels = None
self.start_get_kernels_threads()
if self.pacman_db_sync() is False:
fn.logger.error("Pacman DB synchronization failed")
else:
if fn.logger.getEffectiveLevel() == 10:
fn.logger.debug("Adding community kernels to UI")
try:
thread_get_community_kernels = fn.Thread(
name=fn.thread_get_community_kernels,
target=fn.get_community_kernels,
daemon=True,
args=(self,),
)
thread_get_community_kernels.start()
except Exception as e:
fn.logger.error("Exception in thread_get_community_kernels: %s" % e)
finally:
self.community_kernels = self.queue_community_kernels.get()
self.queue_community_kernels.task_done()
self.installed_kernels = fn.get_installed_kernels()
self.label_notify_revealer.set_text("Refreshing official kernels")
GLib.idle_add(
self.reveal_notify,
priority=GLib.PRIORITY_DEFAULT,
)
GLib.idle_add(
self.kernel_stack.add_official_kernels_to_stack,
True,
priority=GLib.PRIORITY_DEFAULT,
)
self.label_notify_revealer.set_text("Refreshing community kernels")
GLib.idle_add(
self.reveal_notify,
priority=GLib.PRIORITY_DEFAULT,
)
GLib.idle_add(
self.kernel_stack.add_community_kernels_to_stack,
True,
priority=GLib.PRIORITY_DEFAULT,
)
self.label_notify_revealer.set_text("Refreshing installed kernels")
GLib.idle_add(
self.reveal_notify,
priority=GLib.PRIORITY_DEFAULT,
)
GLib.idle_add(
self.kernel_stack.add_installed_kernels_to_stack,
True,
priority=GLib.PRIORITY_DEFAULT,
)
while self.default_context.pending():
if fn.logger.getEffectiveLevel() == 10:
fn.logger.debug("Waiting for UI loop")
fn.time.sleep(0.3)
self.default_context.iteration(False)
# fn.time.sleep(0.5)
if fn.logger.getEffectiveLevel() == 10:
fn.logger.debug("Refresh UI completed")
self.label_notify_revealer.set_text("Refreshing UI completed")
GLib.idle_add(
self.reveal_notify,
priority=GLib.PRIORITY_DEFAULT,
)
def on_quit(self, action, param):
self.destroy()
fn.logger.info("Application quit")
def on_button_quit_response(self, widget):
self.destroy()
fn.logger.info("Application quit")
def load_kernels_gui(self):
self.queue_load_progress.put(0)
hbox_sep = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
hsep = Gtk.Separator(orientation=Gtk.Orientation.VERTICAL)
hbox_sep.append(hsep)
# handle error here with message
if self.official_kernels is None:
fn.logger.error("Failed to retrieve kernel list")
self.queue_load_progress.put(1)
stack_sidebar = Gtk.StackSidebar()
stack_sidebar.set_name("stack_sidebar")
stack_sidebar.set_stack(self.stack)
hbox_stack_sidebar = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
hbox_stack_sidebar.set_name("hbox_stack_sidebar")
hbox_stack_sidebar.append(stack_sidebar)
hbox_stack_sidebar.append(self.stack)
self.vbox.append(hbox_stack_sidebar)
button_quit = Gtk.Button.new_with_label("Quit")
# button_quit.set_size_request(100, 30)
button_quit.connect(
"clicked",
self.on_button_quit_response,
)
btn_context = button_quit.get_style_context()
btn_context.add_class("destructive-action")
grid_bottom_panel = Gtk.Grid()
grid_bottom_panel.set_halign(Gtk.Align.END)
grid_bottom_panel.set_row_homogeneous(True)
grid_bottom_panel.attach(button_quit, 0, 1, 1, 1)
self.vbox.append(grid_bottom_panel)
self.textbuffer = Gtk.TextBuffer()
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)
fn.logger.info("Creating kernel UI")
# add official kernel flowbox
if fn.logger.getEffectiveLevel() == 10:
fn.logger.debug("Adding official kernels to UI")
self.queue_load_progress.put(0)
self.kernel_stack.add_official_kernels_to_stack(reload=False)
# fn.logger.debug("Adding community kernels to UI")
# self.kernel_stack.add_community_kernels_to_stack(reload=False)
fn.logger.info("Starting pacman db synchronization")
if self.pacman_db_sync() is False:
fn.logger.error("Pacman DB synchronization failed")
else:
if fn.logger.getEffectiveLevel() == 10:
fn.logger.debug("Adding community kernels to UI")
try:
thread_get_community_kernels = fn.Thread(
name=fn.thread_get_community_kernels,
target=fn.get_community_kernels,
daemon=True,
args=(self,),
)
thread_get_community_kernels.start()
except Exception as e:
fn.logger.error("Exception in thread_get_community_kernels: %s" % e)
finally:
self.community_kernels = self.queue_community_kernels.get()
self.queue_community_kernels.task_done()
self.kernel_stack.add_community_kernels_to_stack(reload=False)
if fn.logger.getEffectiveLevel() == 10:
fn.logger.debug("Sending signal to destroy splashscreen")
# signal to destroy splash screen
self.queue_load_progress.put(1)
if fn.logger.getEffectiveLevel() == 10:
fn.logger.debug("Adding installed kernels to UI")
self.kernel_stack.add_installed_kernels_to_stack(reload=False)
fn.logger.info("Application started")
# while self.default_context.pending():
# if fn.logger.getEffectiveLevel() == 10:
# fn.logger.debug("Waiting for UI loop")
# self.default_context.iteration(False)
# fn.time.sleep(0.3)

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)

View File

@@ -0,0 +1,87 @@
import gi
import os
import libs.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, 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")
hbox_message = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
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_message.append(scrolled_window)
self.set_size_request(700, 500)
self.set_resizable(True)
else:
label_message = Gtk.Label(xalign=0.5, yalign=0.5)
label_message.set_markup("%s" % message)
label_message.set_name("label_flowbox_message")
hbox_message.append(label_message)
vbox_message.append(hbox_message)
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=50)
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()

View File

@@ -0,0 +1,658 @@
import random
import shutil
import sys
import gi
import os
import libs.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, 250)
self.connect("close-request", self.on_close)
self.textview = textview
self.textbuffer = textbuffer
self.kernel_state_queue = fn.Queue()
self.messages_queue = fn.Queue()
# create temp file to lock the close button
self.lockfile = "/tmp/.akm-progress.lock"
if os.path.exists(self.lockfile):
os.unlink(self.lockfile)
with open(self.lockfile, "w") as f:
f.write("")
self.kernel = kernel
self.timeout_id = None
self.errors_found = False
self.restore_kernel = None
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
self.local_modules_version = 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)
)
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.spinner)
self.hbox_spinner.append(self.label_spinner_progress)
vbox_padding = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
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
self.restore_kernel = None
if (
self.source == "official"
and action == "install"
or action == "uninstall"
and self.source == "official"
):
fn.logger.info("Official kernel selected")
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
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:
self.local_modules_version = fn.get_kernel_modules_version(
self.restore_kernel.name, "local"
)
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")
self.local_modules_version = fn.get_kernel_modules_version(
self.kernel.name, "local"
)
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) or os.path.exists(self.lockfile):
mw = MessageWindow(
title="Pacman process running",
message="Pacman is busy processing a transaction .. please wait",
transient_for=self,
detailed_message=False,
)
mw.present()
else:
self.destroy()
def on_close(self, data):
if fn.check_pacman_process(self) or os.path.exists(self.lockfile):
mw = MessageWindow(
title="Pacman process running",
message="Pacman is busy processing a transaction .. please wait",
transient_for=self,
detailed_message=False,
)
mw.present()
return True
return False
def check_kernel_state(self):
returncode = None
action = None
while True:
items = self.kernel_state_queue.get()
if items is not None:
returncode, action = items
try:
if returncode == 0:
self.errors_found = False
fn.logger.info("Kernel %s completed" % action)
self.label_status.set_markup(
"<span foreground='orange'><b>Kernel %s completed</b></span>"
% self.action
)
self.label_title.set_markup("<b>Kernel %s completed</b>" % action)
if fn.kernel_initrd(self) == 1:
self.errors_found = True
self.kernel_fail(action)
else:
fn.update_bootloader(self)
self.label_notify_revealer.set_text(
"Kernel %s completed" % action
)
self.reveal_notify()
fn.logger.info("Kernel %s completed" % action)
self.spinner.set_spinning(False)
self.hbox_spinner.hide()
self.label_status.set_markup(
"<span foreground='orange'><b>Kernel %s completed</b></span>"
% self.action
)
self.label_title.set_markup(
"<b>Kernel %s completed</b>" % action
)
break
elif returncode == 1:
self.errors_found = True
self.kernel_fail(action)
else:
self.restore = None
fn.kernel_initrd(self)
fn.update_bootloader(self)
self.spinner.set_spinning(False)
self.hbox_spinner.hide()
if self.errors_found is True:
self.label_status.set_markup(
f"<span foreground='orange'><b>Kernel %s failed - see logs above</b></span>\n"
% action
)
break
#
# else:
# break
except Exception as e:
fn.logger.error("Exception in check_kernel_state(): %s" % e)
finally:
self.kernel_state_queue.task_done()
if os.path.exists(self.lockfile):
os.unlink(self.lockfile)
self.update_installed_list()
self.update_official_list()
if len(self.manager_gui.community_kernels) > 0:
self.update_community_list()
while self.manager_gui.default_context.pending():
self.manager_gui.default_context.iteration(True)
fn.time.sleep(0.3)
self.spinner.set_spinning(False)
self.hbox_spinner.hide()
if self.errors_found is True:
event = (
"%s [ERROR]: Problems encountered with the last transaction, see logs"
% (fn.datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"),)
)
self.messages_queue.put(event)
else:
event = "%s [INFO]: A reboot is recommended" % (
fn.datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"),
)
self.messages_queue.put(event)
if os.path.exists("/usr/lib/modules/build"):
shutil.rmtree("/usr/lib/modules/build", ignore_errors=True)
break
def kernel_fail(self, action):
self.errors_found = True
self.label_notify_revealer.set_text("Kernel %s failed" % action)
self.reveal_notify()
fn.logger.error("Kernel %s failed" % action)
self.label_title.set_markup("<b>Kernel %s failed</b>" % action)
self.label_status.set_markup(
"<span foreground='orange'><b>Kernel %s failed - see logs above</b></span>"
% action
)
# self.action = "uninstall"
fn.logger.info(
"Installation failed, attempting removal of previous Linux package changes"
)
event = "%s [INFO]: Reverting package changes made\n" % (
fn.datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"),
)
self.label_spinner_progress.set_markup(
"<b>Please wait reverting package changes</b>"
)
self.messages_queue.put(event)
self.label_title.set_markup("<b>Kernel install failed</b>")
self.action = "uninstall"
fn.uninstall(self)
if self.restore_kernel is not None and self.source == "official":
self.restore = True
self.label_spinner_progress.set_markup(
"<b>Please wait restoring kernel %s</b>" % self.restore_kernel.version
)
fn.logger.info(
"Restoring previously installed kernel %s" % self.restore_kernel.version
)
event = "%s [INFO]: Restoring previously installed kernel %s\n" % (
fn.datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"),
self.restore_kernel.version,
)
self.messages_queue.put(event)
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
self.action = "install"
fn.install_archive_kernel(self)
self.label_title.set_markup("<b>Kernel restored due to failure</b>")
# elif self.source == "community":
# GLib.idle_add(
# fn.show_mw,
# self,
# "System changes",
# f"Kernel {self.action} failed\n"
# f"<b>There have been errors, please review the logs</b>\n",
# "images/48x48/akm-warning.png",
# priority=GLib.PRIORITY_DEFAULT,
# )
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)

View File

@@ -0,0 +1,703 @@
import gi
import os
from ui.Stack import Stack
from ui.MessageWindow import MessageWindow
import libs.functions as fn
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
)
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("hbox_warning")
hbox_warning.append(image_warning)
label_pacman_no_community = Gtk.Label(xalign=0, yalign=0)
label_pacman_no_community.set_name("label_community_warning")
label_pacman_no_community.set_markup(
f"<b>Cannot find any supported unofficial pacman repository's</b>\n"
f"<b>Add the Chaotic-AUR pacman repository to access Community based kernels</b>"
)
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 and len(self.kernel_versions) > 0:
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",
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(),
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_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 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

View File

@@ -0,0 +1,30 @@
import gi
import libs.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()

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)