diff --git a/Preferences/Keyboard.app/Keyboard b/Preferences/Keyboard.app/Keyboard index 69e88d6b..42ab2b91 100755 --- a/Preferences/Keyboard.app/Keyboard +++ b/Preferences/Keyboard.app/Keyboard @@ -343,21 +343,62 @@ class KeyboardSwitcher(QtWidgets.QMainWindow): pass def _showMenu(self): + menubar = self.window.menuBar() + fileMenu = menubar.addMenu('&File') + + saveAct = QtWidgets.QAction('&Save', self.window) + saveAct.setShortcut('Ctrl+S') + saveAct.setStatusTip('Save settings to persist reboots') + saveAct.triggered.connect(self.save) + fileMenu.addAction(saveAct) + + fileMenu.addSeparator() + exitAct = QtWidgets.QAction('&Quit', self.window) exitAct.setShortcut('Ctrl+Q') exitAct.setStatusTip('Exit application') exitAct.triggered.connect(QtWidgets.QApplication.quit) - menubar = self.window.menuBar() - fileMenu = menubar.addMenu('&File') fileMenu.addAction(exitAct) + self.variantsMenu = menubar.addMenu('&Variants') + + helpMenu = menubar.addMenu('&Help') + aboutAct = QtWidgets.QAction('&About', self.window) aboutAct.setStatusTip('About this application') aboutAct.triggered.connect(self._showAbout) - helpMenu = menubar.addMenu('&Help') + helpMenu.addAction(aboutAct) + def save(self): + print("save called") + print("TODO: To be implemented") + conf_file_path = "/tmp/00-keyboard.conf" + conf_file_template = """Section "InputClass" + Identifier "system-keyboard" + MatchIsKeyboard "on" + Option "XkbLayout" "@layout@" + Option "XkbModel" "@model@" + Option "XkbVariant" ",@variant@" + Option "XkbOptions" "@options@" +EndSection""" + conf_file_content = conf_file_template.replace("@layout@", self.xkbmap.layout).replace("@model@", self.xkbmap.model).replace("@variant@", self.xkbmap.variant).replace("@options@", ",".join(self.xkbmap.options)) + print("conf_file_content:") + print(conf_file_content) + + f = open(conf_file_path, "w") + f.write(conf_file_content) + f.close() + + # Run a helper tool as root that puts the config file into the system-wide Xorg configuration and/or writes the information to EFI + os.environ["SUDO_ASKPASS"] = os.path.dirname(__file__) + "/Resources/askpass.py" + # TODO: Implement error handling with an error dialog + proc = subprocess.Popen(["/usr/local/bin/sudo", "-A", "-E", os.path.dirname(__file__) + "/Resources/save.py"], stdout=subprocess.PIPE, env=os.environ) + for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"): + print(line) + + def _showAbout(self): print("showDialog") msg = QtWidgets.QMessageBox() diff --git a/Preferences/Keyboard.app/Resources/askpass.py b/Preferences/Keyboard.app/Resources/askpass.py new file mode 100755 index 00000000..2d168799 --- /dev/null +++ b/Preferences/Keyboard.app/Resources/askpass.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3.7 + + +# man sudo(8) +# -A, --askpass +# Normally, if sudo requires a password, it will read it from +# the user's terminal. If the -A (askpass) option is +# specified, a (possibly graphical) helper program is executed +# to read the user's password and output the password to the +# standard output. If the SUDO_ASKPASS environment variable is +# set, it specifies the path to the helper program. Otherwise, +# if sudo.conf(5) contains a line specifying the askpass +# program, that value will be used. For example: +# +# # Path to askpass helper program +# Path askpass /usr/X11R6/bin/ssh-askpass +# +# If no askpass program is available, sudo will exit with an +# error. + + +from PyQt5 import QtWidgets + +app = QtWidgets.QApplication([]) +password, ok = QtWidgets.QInputDialog.getText(None, "sudo", "Password", QtWidgets.QLineEdit.Password) +if ok: + print(password) +app.exit(0) \ No newline at end of file diff --git a/Preferences/Keyboard.app/Resources/save.py b/Preferences/Keyboard.app/Resources/save.py new file mode 100755 index 00000000..b4b0c737 --- /dev/null +++ b/Preferences/Keyboard.app/Resources/save.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3.7 + + +# Simple Keyboard Layout switcher for FreeBSD in PyQt5 + + +# Copyright (c) 2020, Simon Peter +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +import os, sys, subprocess, shutil + + +config_file = os.path.expanduser('~/.config/hello/keyboard.conf') + + +if __name__ == "__main__": + + user = os.getenv("SUDO_USER") + if user is None: + print("This program needs to be invoked through 'sudo'.") + exit(1) + + # Move the configuration file to its system-wide destination + conf_file_path = "/usr/local/etc/X11/xorg.conf.d/00-keyboard.conf" + try: + shutil.move("/tmp/00-keyboard.conf", conf_file_path) + except: + print("Could not move the configuration file to its system-wide destination") + exit(1) + + print("Done saving")