manjaro-hello/src/manjaro_hello.py

319 lines
11 KiB
Python
Raw Normal View History

2016-12-04 18:09:15 +01:00
#!/usr/bin/env python3
2016-12-11 00:05:32 +01:00
import gettext
2016-12-08 18:11:08 +01:00
import gi
import json
import locale
2016-12-04 18:09:15 +01:00
import os
2016-12-08 18:11:08 +01:00
import subprocess
2016-12-06 18:54:02 +01:00
import sys
import webbrowser
2016-12-04 18:09:15 +01:00
gi.require_version("Gtk", "3.0")
2016-12-11 18:12:01 +01:00
from gi.repository import Gtk, GdkPixbuf
2016-12-04 18:09:15 +01:00
2016-12-21 15:35:54 +01:00
2016-12-05 22:18:23 +01:00
class ManjaroHello():
2016-12-04 18:09:15 +01:00
def __init__(self):
2016-12-05 21:49:29 +01:00
# App vars
self.app = "manjaro-hello"
2016-12-06 18:54:02 +01:00
2016-12-04 22:48:13 +01:00
# Path vars
2016-12-26 20:33:54 +01:00
self.home_path = os.path.expanduser("~")
2017-01-28 14:55:40 +01:00
self.logo_path = "/usr/share/icons/manjaro/maia/64x64.png"
2016-12-18 11:18:08 +01:00
if os.path.basename(sys.argv[0]) == self.app:
2016-12-18 12:15:52 +01:00
self.data_path = "/usr/share/" + self.app + "/data/"
2016-12-10 17:34:29 +01:00
self.locale_path = "/usr/share/locale/"
2016-12-18 12:06:15 +01:00
self.ui_path = "/usr/share/" + self.app + "/ui/"
2016-12-11 18:12:01 +01:00
self.desktop_path = "/usr/share/applications/" + self.app + ".desktop"
2016-12-10 17:34:29 +01:00
else:
2016-12-17 19:14:39 +01:00
self.data_path = "data/"
self.locale_path = "locale/"
self.ui_path = "ui/"
2016-12-18 14:02:37 +01:00
self.desktop_path = os.getcwd() + "/" + self.app + ".desktop"
2016-12-26 20:33:54 +01:00
self.config_path = self.home_path + "/.config/"
2016-12-10 17:34:29 +01:00
self.preferences_path = self.config_path + self.app + ".json"
2016-12-18 00:05:56 +01:00
self.urls_path = self.data_path + "urls.json"
2016-12-10 17:34:29 +01:00
self.autostart_path = self.config_path + "autostart/" + self.app + ".desktop"
2016-12-04 18:09:15 +01:00
2016-12-09 17:28:22 +01:00
# Load preferences
2016-12-04 18:09:15 +01:00
self.preferences = self.get_preferences()
2016-12-09 17:28:22 +01:00
2016-12-11 00:05:32 +01:00
# Load system infos
self.infos = get_infos()
2016-12-18 00:05:56 +01:00
# Load data files
self.urls = read_json(self.urls_path)
2016-12-11 00:05:32 +01:00
# Init window
self.builder = Gtk.Builder()
2016-12-26 20:27:16 +01:00
self.builder.add_from_file(self.ui_path + self.app + ".glade")
2016-12-11 00:05:32 +01:00
self.builder.connect_signals(self)
self.window = self.builder.get_object("window")
2016-12-26 17:38:17 +01:00
subtitle = self.infos["arch"]
if self.infos["codename"] and self.infos["release"]:
subtitle = self.infos["codename"] + " " + self.infos["release"] + " " + subtitle
self.builder.get_object("headerbar").props.subtitle = subtitle
2016-12-11 00:05:32 +01:00
2016-12-11 18:12:01 +01:00
# Load logos
2016-12-28 23:05:44 +01:00
logo = GdkPixbuf.Pixbuf.new_from_file(self.logo_path)
2016-12-11 18:12:01 +01:00
self.window.set_icon_from_file(self.logo_path)
2016-12-15 14:56:21 +01:00
self.builder.get_object("manjaroicon").set_from_pixbuf(logo)
self.builder.get_object("aboutdialog").set_logo(logo)
2016-12-11 18:12:01 +01:00
2016-12-26 18:12:17 +01:00
# Create pages
self.pages = ("readme", "release", "involved")
for page in self.pages:
scrolled_window = Gtk.ScrolledWindow()
viewport = Gtk.Viewport()
label = Gtk.Label(wrap=True)
viewport.add(label)
scrolled_window.add(viewport)
2016-12-26 18:19:16 +01:00
scrolled_window.show_all()
2016-12-26 18:12:17 +01:00
self.builder.get_object("stack").add_named(scrolled_window, page + "page")
2016-12-09 17:28:22 +01:00
# Init translation
2016-12-17 14:34:17 +01:00
self.default_locale = "en"
2016-12-11 00:05:32 +01:00
self.default_texts = {}
2016-12-09 17:28:22 +01:00
2016-12-11 00:05:32 +01:00
# Make translation
gettext.bindtextdomain(self.app, self.locale_path)
gettext.textdomain(self.app)
2016-12-28 14:53:32 +01:00
self.builder.get_object("languages").set_active_id(self.get_best_locale())
2016-12-09 17:28:22 +01:00
2016-12-10 17:34:29 +01:00
# Load images
2016-12-11 00:32:11 +01:00
for img in ("google+", "facebook", "twitter", "reddit"):
self.builder.get_object(img).set_from_file(self.data_path + "img/" + img + ".png")
2016-12-10 17:34:29 +01:00
2017-01-08 20:53:31 +01:00
for btn in ("wiki", "forums", "chat", "mailling", "development", "donate"):
2016-12-23 14:05:04 +01:00
img = Gtk.Image.new_from_file(self.data_path + "img/external-link.png")
2016-12-22 22:29:26 +01:00
img.set_margin_left(2)
self.builder.get_object(btn).set_image_position(Gtk.PositionType.RIGHT)
2016-12-23 16:08:38 +01:00
self.builder.get_object(btn).set_always_show_image(True)
2016-12-22 21:20:23 +01:00
self.builder.get_object(btn).set_image(img)
2016-12-11 00:37:11 +01:00
# Set autostart switcher state
2016-12-18 15:34:43 +01:00
self.autostart = os.path.isfile(self.autostart_path)
self.builder.get_object("autostart").set_active(self.autostart)
2016-12-11 00:37:11 +01:00
2016-12-08 17:39:52 +01:00
# Live systems
2016-12-22 22:32:30 +01:00
if self.infos["live"] and os.path.isfile("/usr/bin/calamares"):
self.builder.get_object("installlabel").set_visible(True)
2016-12-26 17:29:24 +01:00
self.builder.get_object("install").set_visible(True)
2016-12-08 17:39:52 +01:00
2016-12-26 18:19:16 +01:00
self.window.show()
2016-12-04 18:09:15 +01:00
def get_best_locale(self):
2016-12-20 00:29:03 +01:00
"""Choose best locale, based on user's preferences.
:return: locale to use
:rtype: str
"""
path = self.locale_path + "{}/LC_MESSAGES/" + self.app + ".mo"
if os.path.isfile(path.format(self.preferences["locale"])):
return self.preferences["locale"]
else:
2016-12-28 15:58:14 +01:00
sys_locale = locale.getdefaultlocale()[0]
# If user's locale is supported
2016-12-28 15:58:14 +01:00
if os.path.isfile(path.format(sys_locale)):
return sys_locale
# If two first letters of user's locale is supported (ex: en_US -> en)
2016-12-28 15:58:14 +01:00
elif os.path.isfile(path.format(sys_locale[:2])):
return sys_locale[:2]
else:
return self.default_locale
2016-12-11 00:38:36 +01:00
def set_locale(self, locale):
2016-12-17 23:19:05 +01:00
"""Set locale of ui and pages.
:param locale: locale to use
:type locale: str
"""
if "_" in locale:
locale = locale.replace("_", "-")
try:
2016-12-21 22:24:30 +01:00
tr = gettext.translation(self.app, self.locale_path, [locale], fallback=True)
tr.install()
except OSError:
return
2016-12-11 00:05:32 +01:00
# Dirty code to fix an issue with gettext that can't translate strings from glade files
# Redfining all translatables strings
2016-12-11 00:05:32 +01:00
# TODO: Find a better solution
elts = {
2016-12-26 21:15:04 +01:00
"comments": {
"aboutdialog"
},
"label": {
"autostartlabel",
2017-01-08 22:20:13 +01:00
"development",
2016-12-26 21:15:04 +01:00
"chat",
"donate",
"firstcategory",
"forums",
"install",
"installlabel",
"involved",
"mailling",
"readme",
"release",
"secondcategory",
"thirdcategory",
"welcomelabel",
"welcometitle",
"wiki"
},
"tooltip_text": {
"about",
"home"
}
2016-12-11 00:05:32 +01:00
}
2016-12-26 21:15:04 +01:00
for method in elts:
for elt in elts[method]:
if elt not in self.default_texts:
self.default_texts[elt] = getattr(self.builder.get_object(elt), "get_" + method)()
getattr(self.builder.get_object(elt), "set_" + method)(_(self.default_texts[elt]))
2016-12-11 00:05:32 +01:00
2016-12-26 18:12:17 +01:00
# Change content of pages
for page in self.pages:
child = self.builder.get_object("stack").get_child_by_name(page + "page")
label = child.get_children()[0].get_children()[0]
label.set_markup(self.get_page(page))
2016-12-17 00:07:49 +01:00
2016-12-28 14:53:32 +01:00
self.preferences["locale"] = locale
2016-12-26 15:50:54 +01:00
def set_autostart(self, autostart):
2016-12-17 23:19:05 +01:00
"""Set state of autostart.
:param autostart: wanted autostart state
:type autostart: bool
"""
2016-12-17 11:55:00 +01:00
try:
if autostart and not os.path.isfile(self.autostart_path):
2016-12-05 21:49:29 +01:00
os.symlink(self.desktop_path, self.autostart_path)
2016-12-17 11:55:00 +01:00
elif not autostart and os.path.isfile(self.autostart_path):
2016-12-05 21:49:29 +01:00
os.unlink(self.autostart_path)
2016-12-26 15:50:54 +01:00
# Specific to i3
2016-12-26 20:33:54 +01:00
i3_config = self.home_path + "/.i3/config"
2016-12-26 15:50:54 +01:00
if os.path.isfile(i3_config):
2016-12-26 20:27:16 +01:00
i3_autostart = "exec --no-startup-id " + self.app
2016-12-26 15:50:54 +01:00
with open(i3_config, "r+") as f:
content = f.read()
f.seek(0)
if autostart:
f.write(content.replace("#" + i3_autostart, i3_autostart))
else:
f.write(content.replace(i3_autostart, "#" + i3_autostart))
f.truncate()
self.autostart = autostart
2016-12-17 11:55:00 +01:00
except OSError as e:
print(e)
2016-12-04 18:09:15 +01:00
def save_preferences(self):
"""Save preferences in config file."""
2016-12-04 18:09:15 +01:00
try:
with open(self.preferences_path, "w") as f:
json.dump(self.preferences, f)
2016-12-04 19:32:11 +01:00
except OSError as e:
2016-12-04 18:09:15 +01:00
print(e)
def get_preferences(self):
"""Read preferences from config file."""
2016-12-18 00:05:56 +01:00
preferences = read_json(self.preferences_path)
if not preferences:
2016-12-18 15:34:43 +01:00
preferences = {"locale": None}
2016-12-18 00:05:56 +01:00
return preferences
2016-12-04 18:09:15 +01:00
2016-12-26 17:30:23 +01:00
def get_page(self, name):
2016-12-17 23:19:05 +01:00
"""Read page according to language.
:param name: name of page (filename)
:type name: str
:return: text to load
:rtype: str
"""
2016-12-10 17:34:29 +01:00
filename = self.data_path + "pages/{}/{}".format(self.preferences["locale"], name)
if not os.path.isfile(filename):
2016-12-10 17:34:29 +01:00
filename = self.data_path + "pages/{}/{}".format(self.default_locale, name)
2016-12-04 18:09:15 +01:00
try:
with open(filename, "r") as f:
return f.read()
2016-12-21 18:34:34 +01:00
except OSError:
2016-12-17 12:15:27 +01:00
return _("Can't load page.")
2016-12-04 18:09:15 +01:00
# Handlers
2016-12-09 17:28:22 +01:00
def on_languages_changed(self, combobox):
"""Event for selected language."""
2016-12-28 14:53:32 +01:00
self.set_locale(combobox.get_active_id())
2016-12-09 17:28:22 +01:00
def on_action_clicked(self, action, _=None):
"""Event for differents actions."""
name = action.get_name()
2016-12-26 17:29:24 +01:00
if name == "install":
subprocess.Popen(["pkexec", "calamares"])
elif name == "autostart":
self.set_autostart(action.get_active())
elif name == "about":
dialog = self.builder.get_object("aboutdialog")
dialog.run()
dialog.hide()
2016-12-04 18:09:15 +01:00
def on_btn_clicked(self, btn):
"""Event for clicked button."""
name = btn.get_name()
2016-12-26 21:05:38 +01:00
self.builder.get_object("home").set_sensitive(not name == "home")
self.builder.get_object("stack").set_visible_child_name(name + "page")
2016-12-11 00:58:59 +01:00
def on_link_clicked(self, link, _=None):
"""Event for clicked link."""
2016-12-11 00:58:59 +01:00
webbrowser.open_new_tab(self.urls[link.get_name()])
2016-12-04 18:09:15 +01:00
def on_delete_window(self, *args):
"""Event to quit app."""
2016-12-19 23:58:07 +01:00
self.save_preferences()
2016-12-04 18:09:15 +01:00
Gtk.main_quit(*args)
2016-12-21 15:35:54 +01:00
2016-12-04 19:17:48 +01:00
def get_infos():
2016-12-17 23:19:05 +01:00
"""Get informations about user's system.
:return: informations about user's system
:rtype: dict
"""
2016-12-17 11:57:13 +01:00
lsb = get_lsb_infos()
2016-12-04 19:17:48 +01:00
infos = {}
2016-12-06 18:54:02 +01:00
infos["codename"] = lsb.get("CODENAME", None)
infos["release"] = lsb.get("RELEASE", None)
infos["arch"] = "64-bits" if sys.maxsize > 2**32 else "32-bits"
2016-12-08 17:39:52 +01:00
infos["live"] = os.path.exists("/bootmnt/manjaro") or os.path.exists("/run/miso/bootmnt/manjaro")
2016-12-04 19:17:48 +01:00
return infos
2016-12-21 15:35:54 +01:00
2016-12-17 11:57:13 +01:00
def get_lsb_infos():
2016-12-17 23:19:05 +01:00
"""Read informations from the lsb-release file.
:return: args from lsb-release file
:rtype: dict
"""
2016-12-04 19:10:33 +01:00
lsb = {}
try:
2016-12-26 15:50:54 +01:00
with open("/etc/lsb-release") as f:
for line in f:
2016-12-04 19:10:33 +01:00
if "=" in line:
var, arg = line.rstrip().split("=")
if var.startswith("DISTRIB_"):
var = var[8:]
if arg.startswith("\"") and arg.endswith("\""):
arg = arg[1:-1]
if arg:
lsb[var] = arg
2016-12-04 20:28:41 +01:00
except OSError as e:
print(e)
2016-12-04 19:10:33 +01:00
return lsb
2016-12-21 15:35:54 +01:00
2016-12-18 00:05:56 +01:00
def read_json(path):
try:
with open(path, "r") as f:
return json.load(f)
2016-12-21 18:34:34 +01:00
except OSError:
2016-12-18 00:05:56 +01:00
return None
2016-12-21 15:35:54 +01:00
2016-12-05 22:18:23 +01:00
if __name__ == "__main__":
ManjaroHello()
Gtk.main()