#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from PyQt5.QtGui import QGuiApplication, QIcon, QScreen
from PyQt5.QtQuick import QQuickView
from PyQt5.QtCore import (
QUrl,
QLocale,
QTranslator,
QLibraryInfo,
QVariant,
QAbstractListModel,
QModelIndex,
Qt,
QObject,
pyqtSlot,
pyqtSignal,
QCoreApplication,
)
from PyQt5.QtNetwork import QNetworkConfigurationManager, QNetworkConfiguration
import sys
import os
import subprocess
from helpers import get_desktop_name, get_desktop_name2, is_installed
import pwd
# Workaround for opengl lib selection
from OpenGL import GL
translate = QCoreApplication.translate
class Networkstate(QObject):
def __init__(self):
QObject.__init__(self)
@pyqtSlot(result=bool)
def isOffLine(self):
# Search active network connections
net = QNetworkConfigurationManager()
return not net.isOnline()
class ConfList(QAbstractListModel):
NameRole = Qt.UserRole + 1
def __init__(self, parent=None):
super().__init__(parent)
# Changing working directory
abspath = os.path.abspath(__file__)
dname = os.path.dirname(abspath)
os.chdir(dname)
# collect sys info
release = subprocess.getoutput("lsb_release -sd")
release = release[1:-1]
release_nb = subprocess.getoutput("lsb_release -sr")
release_nb = release_nb.strip()
kernel = subprocess.getoutput("uname -r")
if os.uname()[4] == ("x86_64", "aarch64"):
arch = "64-bit"
elif os.uname()[4] in ("i586", "i686", "armv7hl"):
arch = "32-bit"
else:
arch = os.uname()[4]
try:
desktop = get_desktop_name(os.path.basename(os.getenv("DESKTOP_SESSION")))
except:
desktop = "Other"
if desktop == "Other":
desktop = get_desktop_name2(os.getenv("XDG_CURRENT_DESKTOP"))
if desktop == "unknown":
desktop = os.getenv("XDG_CURRENT_DESKTOP")
self.screen_factor = 0.0
if desktop == "Gnome Wayland":
import gi
gi.require_version("Gdk", "3.0")
from gi.repository.Gdk import Display
# pre-3.22, otherwise deprecated
# factor = Gdk.Screen.get_default().get_monitor_scale_factor(0)
self.screen_factor = Display.get_default().get_monitor(0).get_scale_factor()
# Search active network connections
net = QNetworkConfigurationManager()
first = True
if net.isOnline():
confs = net.allConfigurations(QNetworkConfiguration.Active)
for conf in confs:
if first:
netconfs = conf.name()
first = False
else:
netconfs += ", " + conf.name()
self.configuration = [
{
"name": translate(
"ConfList", "Congratulations!
You are now running {}"
).format(release)
},
{
"name": translate("ConfList", "You are using linux kernel: {}").format(
kernel
)
},
{
"name": translate("ConfList", "Your system architecture is: {}").format(
arch
)
},
{
"name": translate(
"ConfList", "You are now using the Desktop: {}"
).format(desktop)
},
{"name": translate("ConfList", "Your user id is: {}").format(os.getuid())},
]
if net.isOnline():
self.configuration.append(
{
"name": translate(
"ConfList", "You are connected to a network through {}"
).format(netconfs)
}
)
else:
self.configuration.append(
{"name": translate("ConfList", "You have no network connection")}
)
def factor(self, app):
"""
Determine screen factor
Can be specific for Gnome Wayland
"""
if self.screen_factor == 0:
screen = app.primaryScreen()
self.screen_factor = screen.devicePixelRatio()
return self.screen_factor
def data(self, index, role=Qt.DisplayRole):
row = index.row()
return self.configuration[row]["name"]
def rowCount(self, parent=QModelIndex()):
return len(self.configuration)
def roleNames(self):
return {
ConfList.NameRole: b"name",
}
class Callbrowser(QObject):
def __init__(self):
QObject.__init__(self)
@pyqtSlot(str)
def weblink(self, link):
subprocess.Popen(["xdg-open", link])
class Launcher(QObject):
installed = pyqtSignal()
needed = pyqtSignal(str, arguments=["repo"])
repo = pyqtSignal()
noprogram = pyqtSignal()
def __init__(self):
QObject.__init__(self)
@pyqtSlot(QVariant)
def command(self, app):
if app.isArray():
cmd = []
for i in range(0, app.property("length").toInt()):
cmd.append(app.property(i).toString())
self._command(cmd[0])
def _command(self, cmd):
try:
subprocess.Popen(cmd)
except:
print(f"Exception running {cmd}")
self.noprogram.emit()
return
@pyqtSlot(QVariant)
def install(self, app):
if app.isArray():
cmd = []
# app should contain package, repository
for i in range(0, app.property("length").toInt()):
cmd.append(app.property(i).toString())
repo = cmd[1]
# Check if repositories are enabled
core = False
updates = False
tainted = False
t_updates = False
nonfree = False
nf_updates = False
core32 = False
core32_updates = False
try:
active = subprocess.run(
["urpmq", "--list-media", "active"], capture_output=True, text=True
)
active.check_returncode()
except subprocess.CalledProcessError:
print("Error with urpmq")
return
for line in active.stdout.splitlines():
if line.startswith("Core Release"):
core = True
if line.startswith("Core Updates"):
updates = True
if line.startswith("Tainted Release"):
tainted = True
if line.startswith("Tainted Updates"):
t_updates = True
if line.startswith("Nonfree Release"):
nonfree = True
if line.startswith("Nonfree Updates"):
nf_updates = True
if line.startswith("Core 32bit Release"):
core32 = True
if line.startswith("Core 32bit Updates"):
core32_updates = True
if repo == "tainted" and not (tainted and t_updates):
# repo tainted not enabled
self.needed.emit(repo)
return
if repo == "non-free" and not (nonfree and nf_updates):
# repo nonfree not enabled
self.needed.emit(repo)
return
if repo == "steam" and not (
core32 and core32_updates and nonfree and nf_updates
):
# repo not enabled
self.needed.emit(repo)
return
if repo == "" and not (core and updates):
# repo not enabled
self.repo.emit()
return
proc = subprocess.Popen(["/usr/bin/gurpmi", cmd[0]])
proc.wait()
# Give the signal to reload the applist
self.installed.emit()
return
@pyqtSlot(QVariant)
def install_and_launch(self, app):
"""
app should be an array with the package name to install and then the command to launch
"""
if app.isArray():
cmd = []
# app should contain package, repository
for i in range(0, app.property("length").toInt()):
cmd.append(app.property(i).toString())
print(cmd)
is_app_installed, inst_repo = is_installed(cmd[0])
if not is_app_installed:
proc = subprocess.Popen(["/usr/bin/gurpmi", cmd[0]])
proc.wait()
self._command(cmd[1])
class Norun(QObject):
def __init__(self):
QObject.__init__(self)
self.home = os.getenv("HOME")
self.conffile = self.home + "/.config/mageiawelcome/norun.flag"
@pyqtSlot(bool)
def setRunAtLaunch(self, checked):
print("Setting", checked)
if checked:
if os.path.exists(self.conffile):
os.remove(self.conffile)
else:
os.makedirs(self.home + "/.config/mageiawelcome", exist_ok=True)
with open(self.conffile, "w"):
pass
@pyqtSlot(result=bool)
def startupcheck(self):
return not os.path.exists(self.conffile)
class Installable(QObject):
def __init__(self):
QObject.__init__(self)
@pyqtSlot(str, str, result=bool)
def installable(self, app, repo):
is_app_installed, inst_repo = is_installed(app)
installable = (not is_app_installed) or (repo != inst_repo and inst_repo == "")
return installable
@pyqtSlot(str, str, result=bool)
def other(self, app, repo):
is_app_installed, inst_repo = is_installed(app)
return is_app_installed and repo == "" and inst_repo != ""
def username():
user = pwd.getpwuid(os.getuid())[4] # pw_gecos, i e the real name
if user == "":
user = pwd.getpwuid(os.getuid())[0] # login
return user
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
locale = QLocale.system().name()
qtTranslator = QTranslator()
if qtTranslator.load(
"qt_" + locale, QLibraryInfo.location(QLibraryInfo.TranslationsPath)
):
app.installTranslator(qtTranslator)
appTranslator = QTranslator()
if appTranslator.load(
QLocale(), "mageiawelcome", "_", "/usr/share/mageiawelcome/translations"
):
app.installTranslator(appTranslator)
app.setOrganizationName("Mageia")
app.setApplicationName("Mageiawelcome")
view = QQuickView()
view.setResizeMode(QQuickView.SizeRootObjectToView)
view.setTitle(app.translate("app", "Welcome to Mageia"))
app.setWindowIcon(QIcon("/usr/share/icons/hicolor/32x32/apps/mageiawelcome.png"))
cb = Callbrowser()
la = Launcher()
us = username()
ins = Installable()
cl = ConfList()
nr = Norun()
ns = Networkstate()
sc = nr.startupcheck()
factor = cl.factor(app)
screen = app.primaryScreen()
# if density is high, use at least factor 2 to scale the initial window. Considering high is more than 190 px/inches.
if screen.logicalDotsPerInch() > 190:
factor = max(2.0, factor)
defaultHeight = min(int(700 * factor), screen.availableGeometry().height())
defaultWidth = min(int(1000 * factor), screen.availableGeometry().width())
centerPoint = screen.availableGeometry().center()
view.setGeometry(
centerPoint.x() - defaultWidth // 2,
centerPoint.y() - defaultHeight // 2,
defaultWidth,
defaultHeight,
)
view.rootContext().setContextProperty("link", cb)
view.rootContext().setContextProperty("launch", la)
view.rootContext().setContextProperty("user", us)
view.rootContext().setContextProperty("ConfList", cl)
view.rootContext().setContextProperty("pyinstallable", ins)
view.rootContext().setContextProperty("startupcheck", sc)
view.rootContext().setContextProperty("norun", nr)
view.rootContext().setContextProperty("networkstate", ns)
current_path = os.path.abspath(os.path.dirname(__file__))
qml_file = os.path.join(current_path, "mw-ui.qml")
view.setSource(QUrl.fromLocalFile(qml_file))
if view.status() == QQuickView.Error:
for error in view.errors():
print(error.description())
sys.exit(-1)
view.show()
res = app.exec_()
del view
sys.exit(res)