Compare commits

...

35 Commits

Author SHA1 Message Date
Aaron Rainbolt
c8398a7bf1 [bootloader] Enhance fallback bootloader installation on Debian
The fallback bootloader installation code previously only copied the
GRUB bootloader's EFI executable to the removable media path. This
doesn't work at all on Debian, the bootloader ends up being unusable at
worst (on Secure Boot systems) and drops you to a GRUB shell at best.
Add Debian-specific fallback bootloader installation code to fix this.
2025-04-15 13:42:21 +02:00
Adriaan de Groot
8e5276b523 Merge pull request #2447 from Neixen911/calamares
[users] Add a choice to display autologin checkbox
2025-04-15 13:30:35 +02:00
Neixen911
66ffc74df8 [users] Set displayAutologin to true by default
To match the existing behavior, the setting displayAutoLogin have to
be set to true bt default. This new setting is added to
users.schema.yaml too.
2025-04-09 09:53:55 +02:00
Neixen911
ebdcce11eb [users] Add a setting to displayAutologin
To add this new setting optionnal, a variable has need to be created
in the file users.conf. This variable can be modified and it changes
directly if the autologin checkbox is show or not.
2025-04-04 10:11:16 +02:00
dalto8
8b27bb6cbd Merge pull request #2448 from ptr1337/drop-orig
bootloader: Drop bootloader.orig file
2025-04-03 16:42:14 +00:00
Peter Jung
7e9af665b5 bootloader: Drop bootloader.orig file
Signed-off-by: Peter Jung <admin@ptr1337.dev>
2025-04-03 18:39:10 +02:00
Neixen911
eceee2ac7f [users] Add a choice to display autologin checkbox
By default, the autologin checkbox is display to the user and he can
choose if he wants to enable it or not. By adding a variable to display
the checkbox or not, this checkbox can be not displaying to the user and
avoid him to change it.
2025-04-03 16:51:46 +02:00
Adriaan de Groot
296be440cc Merge pull request #2445 from ArrayBolt3/arraybolt3/fix-grub-d
[grubcfg] Fix /etc/default/grub.d config file name
2025-03-23 22:01:18 +01:00
Adriaan de Groot
cad4f4476e Merge pull request #2422 from ArrayBolt3/arraybolt3/multi-firmware-boot
Hybrid bootloader (BIOS+UEFI) installation support
2025-03-23 22:00:43 +01:00
Aaron Rainbolt
5a47a6fc8b [grubcfg] Fix /etc/default/grub.d config file name
Under at least Debian, files under /etc/default/grub.d that don't carry
a file name extension of '.cfg' are ignored. Change the filename used
when grubcfg's prefer_grub_d option is set to 'true' to
00calamares.cfg, so that it is detected properly.
2025-03-23 14:56:32 -05:00
Aaron Rainbolt
4e09e1ff00 [partition] Add hybrid bootloader compatible partitioning mode
Some users may want to install their system in a way that it can be
booted with both BIOS and UEFI firmware. This requires installing both
BIOS and UEFI bootloaders. This commit adds the ability to
automatically partition a disk in a way that is compatible with this
setup.
2025-03-05 15:24:22 -06:00
Aaron Rainbolt
d29088e15d [bootloader] Add hybrid GRUB installation support
Some users may want to install their system in a way that it can be
booted with both BIOS and UEFI firmware. This requires installing both
BIOS and UEFI bootloaders. This commit adds the ability to do this
with GRUB.
2025-03-05 15:22:01 -06:00
Adriaan de Groot
12289ef230 Changes: typo- and plurals-fixes all over 2025-03-01 19:56:00 +01:00
Adriaan de Groot
1093881da8 Changes: credits for keyboard feature 2025-02-25 22:45:51 +01:00
Adriaan de Groot
886c0c191c [keyboard] Simplify construction of gsettings-command
- Factor out and document the sudo-arguments part
- Factor out the running-gsettings part up to setting keys
  in the input-sources section
- Improve constness
- Add the key-value parts only at the point-of-call.
2025-02-25 22:42:06 +01:00
Adriaan de Groot
e357b216c9 [keyboard] Replace complicated list-values
- Every entry is only interested in a value for xkb, so
  put the full strings of the xkb-values and drop the intermediate
  state of a list-of-pairs.
- Square-bracket the list before use.
2025-02-25 22:23:42 +01:00
Adriaan de Groot
461322bba3 [keyboard] Use QStringList methods and convenience to build the "[list]" 2025-02-25 22:11:23 +01:00
Adriaan de Groot
bef9d6d143 [keyboard] Don't make unnecessary copies 2025-02-25 22:05:21 +01:00
Adriaan de Groot
8c51d35a2d [keyboard] Simplify sudo arguments
- Don't use m_ for local variables
- GNU sudo understands numeric UIDs
- Calculate DBUS path only once
- Prefer const
2025-02-25 22:04:46 +01:00
Adriaan de Groot
700b725c3b [keyboard] Apply code formatting 2025-02-25 21:37:50 +01:00
Adriaan de Groot
dfc5210bab Merge pull request #2435 from SixK/calamares
Handle Keyboard on Ubuntu 24.10+ when using Wayland and Gnome.
2025-02-24 22:54:57 +01:00
vincent PENVERN
fb5af7d5da Handle Keyboard on Ubuntu 24.10+ when using Wayland and Gnome. 2025-02-24 11:29:54 +01:00
Adriaan de Groot
459c383be0 Changes: post-release housekeeping 2025-02-20 20:49:10 +01:00
Adriaan de Groot
21ea803527 Changes: pre-release housekeeping 2025-02-20 20:06:14 +01:00
Adriaan de Groot
0661ae8768 Merge pull request #2431 from calamares/issue-2377
Add cancellation support to view-steps
2025-02-20 20:04:20 +01:00
Adriaan de Groot
0d2a56b1fc Changes: document changes to keyboard, locale 2025-02-18 17:24:45 +01:00
Adriaan de Groot
24f732091d [locale] Cancel live timezone changes if needed 2025-02-18 19:16:50 +03:00
Adriaan de Groot
b781e552ea [locale] Add support for cancelling locale changes
This only has meaning if the live timezone is changed,
then change it back to the value it had on startup.
2025-02-18 19:14:07 +03:00
Adriaan de Groot
11184dbe24 [libcalamares] Convenience function for TZ formatting 2025-02-18 19:12:52 +03:00
Adriaan de Groot
1aeabcbd66 [libcalamaresui] Call cancel() on steps when cancelling the installation 2025-02-18 16:17:08 +01:00
Adriaan de Groot
6a84308797 [keyboard] Preserve original settings for cancel() 2025-02-18 15:49:26 +01:00
Adriaan de Groot
4de8f5c88d [keyboard] Factor out settings and additional settings
Place settings in a struct and hand it off to a free function
for update, rather than using methods of the Config class.
2025-02-18 15:44:29 +01:00
Adriaan de Groot
695a972aaa [keyboard,keyboardq] Call config's cancellation function 2025-02-18 15:00:23 +01:00
Adriaan de Groot
a43f960075 [keyboard] Add an (aspirational) cancel() function to keyboard-config 2025-02-18 14:59:52 +01:00
Adriaan de Groot
6c25a98793 [libcalamaresui] Add a cancel() function for view-steps 2025-02-18 14:59:18 +01:00
39 changed files with 476 additions and 154 deletions

View File

@@ -7,10 +7,26 @@ contributors are listed. Note that Calamares does not have a historical
changelog -- this log starts with version 3.3.0. See CHANGES-3.2 for
the history of the 3.2 series (2018-05 - 2022-08).
# 3.3.14 (2024-02-18)
# 3.3.15 (unreleased)
This release contains contributions from (alphabetically by given name):
- Adriaan de Groot
- Erik Dubois
- vincent PENVERN
## Core ##
- Typo fixes in examples and documentation.
## Modules ##
- The *keyboard* (and *keyboardq*) modules now support setting the live
keyboard layout in a GNOME-Wayland session. (thanks vincent, #2435)
# 3.3.14 (2024-02-20)
This release contains contributions from (alphabetically by given name):
- Adriaan de Groot
- Evan James
- TNE
- vincent PENVERN
@@ -19,8 +35,14 @@ This release contains contributions from (alphabetically by given name):
consistent. At least one valid Python program would work with
the Boost::Python bindings, but not the pybind11 bindings. A
memory-corruption problem in the Boost::Python bindings was resolved.
- Steps in the UI now have a hook to undo any changes they have made
to the live system, if the user cancels the installation.
## Modules ##
- *keyboard* module undoes changes to the keyboard layout if the
user cancels the installation (returning the system to whatever
layout was in use when Calamares started). (#2377, #2431)
- *locale* module undoes changes to the timezone. (#2377, #2431)
- *partition* module stores a global storage value in luksPassphrase,
for later modules that need to manipulate the encrypted partition.
(thanks vincent, #2424)
@@ -118,7 +140,7 @@ This release contains contributions from (alphabetically by given name):
- *partition* Module fixed unwanted behavior with the encryption checkbox. (thanks Aaron, #2376)
- *umount* Correctly unmounts the root filesystem of the target. (thanks Evan)
- *users* Supports a new `home_permissions` setting to override the
distro's `useradd` configuration of the umask. Supports octal and rwx-style
distribution's `useradd` configuration of the umask. Supports octal and rwx-style
specifications of permissions. Other places that use permissions now also
support octal and rwx-style. (#2362)
- *welcome* Follows system styling colors (e.g. Dark Mode).

View File

@@ -48,8 +48,8 @@
cmake_minimum_required(VERSION 3.16 FATAL_ERROR)
set(CALAMARES_VERSION 3.3.14)
set(CALAMARES_RELEASE_MODE ON) # Set to ON during a release
set(CALAMARES_VERSION 3.3.15)
set(CALAMARES_RELEASE_MODE OFF) # Set to ON during a release
if(CMAKE_SCRIPT_MODE_FILE)
include(${CMAKE_CURRENT_LIST_DIR}/CMakeModules/ExtendedVersion.cmake)
@@ -569,7 +569,7 @@ add_subdirectory(lang) # i18n tools
# squashed into the example filesystem.
#
# To build the example distro (for use by the default, example,
# unsquashfs module), build the target 'example-distro', eg.:
# unsquashfs module), build the target *example-distro*, eg.:
#
# make example-distro
#

View File

@@ -534,7 +534,13 @@ CalamaresWindow::ensureSize( QSize size )
void
CalamaresWindow::closeEvent( QCloseEvent* event )
{
if ( ( !m_viewManager ) || m_viewManager->confirmCancelInstallation() )
if ( m_viewManager )
{
m_viewManager->quit();
// If it didn't actually exit, eat the event to ignore close
event->ignore();
}
else
{
event->accept();
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
@@ -543,8 +549,4 @@ CalamaresWindow::closeEvent( QCloseEvent* event )
QApplication::exit( EXIT_SUCCESS );
#endif
}
else
{
event->ignore();
}
}

View File

@@ -60,6 +60,8 @@ public:
return std::tie( lhs.m_region, lhs.m_zone ) == std::tie( rhs.m_region, rhs.m_zone );
}
QString asString() const { return isValid() ? region() + QChar( '/' ) + zone() : QString(); }
private:
QString m_region;
QString m_zone;
@@ -68,13 +70,13 @@ private:
inline QDebug&
operator<<( QDebug&& s, const RegionZonePair& tz )
{
return s << tz.region() << '/' << tz.zone();
return s << tz.asString();
}
inline QDebug&
operator<<( QDebug& s, const RegionZonePair& tz )
{
return s << tz.region() << '/' << tz.zone();
return s << tz.asString();
}
/** @brief Splits a region/zone string into a pair.

View File

@@ -489,17 +489,31 @@ ViewManager::back()
void
ViewManager::quit()
{
if ( confirmCancelInstallation() )
const auto r = confirmCancelInstallation();
if ( r == Confirmation::Continue )
{
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QApplication::quit();
#else
QApplication::exit( EXIT_SUCCESS );
#endif
return;
}
if ( r == Confirmation::CancelInstallation )
{
// Cancel view steps in reverse
for ( int i = m_currentStep; i >= 0; --i )
{
auto* step = m_steps.at( i );
cDebug() << "Cancelling view step" << step->moduleInstanceKey();
step->onCancel();
}
}
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QApplication::quit();
#else
QApplication::exit( EXIT_SUCCESS );
#endif
}
bool
ViewManager::Confirmation
ViewManager::confirmCancelInstallation()
{
const auto* const settings = Calamares::Settings::instance();
@@ -507,17 +521,17 @@ ViewManager::confirmCancelInstallation()
// When we're at the very end, then it's always OK to exit.
if ( isAtVeryEnd( m_steps, m_currentStep ) )
{
return true;
return Confirmation::EndOfInstallation;
}
// Not at the very end, cancel/quit might be disabled
if ( settings->disableCancel() )
{
return false;
return Confirmation::Continue;
}
if ( settings->disableCancelDuringExec() && stepIsExecute( m_steps, m_currentStep ) )
{
return false;
return Confirmation::Continue;
}
// Otherwise, confirm cancel/quit.
@@ -530,7 +544,7 @@ ViewManager::confirmCancelInstallation()
mb.setDefaultButton( QMessageBox::No );
Calamares::fixButtonLabels( &mb );
int response = mb.exec();
return response == QMessageBox::Yes;
return ( response == QMessageBox::Yes ) ? Confirmation::CancelInstallation : Confirmation::Continue;
}
void

View File

@@ -101,14 +101,21 @@ public:
*/
int currentStepIndex() const;
enum class Confirmation
{
Continue, // User rejects cancel / close question
CancelInstallation, // User accepts cancel / close question
EndOfInstallation, // There was no question because the installation was already done
};
/**
* @brief Called when "Cancel" is clicked; asks for confirmation.
* Other means of closing Calamares also call this method, e.g. alt-F4.
* At the end of installation, no confirmation is asked.
*
* @return @c true if the user confirms closing the window.
* @return a Confirmation value, @c Unasked if the installation is complete
*/
bool confirmCancelInstallation();
Confirmation confirmCancelInstallation();
Qt::Orientations panelSides() const { return m_panelSides; }
void setPanelSides( Qt::Orientations panelSides ) { m_panelSides = panelSides; }

View File

@@ -45,6 +45,11 @@ ViewStep::onLeave()
{
}
void
ViewStep::onCancel()
{
}
void
ViewStep::next()
{

View File

@@ -168,6 +168,15 @@ public:
*/
virtual RequirementsList checkRequirements();
/**
* @brief Called when the user cancels the installation
*
* View steps are expected to leave the system unchanged when
* the installation is cancelled. The default implementation
* does nothing.
*/
virtual void onCancel();
signals:
/// @brief Tells the viewmanager to enable the *next* button according to @p status
void nextStatusChanged( bool status );

View File

@@ -81,3 +81,6 @@ efiBootMgr: "efibootmgr"
# to add another module to optionally install the fallback on those
# boards that need it.
installEFIFallback: true
# Optionally install both BIOS and UEFI GRUB bootloaders.
installHybridGRUB: false

View File

@@ -24,3 +24,4 @@ properties:
efiBootloaderId: { type: string }
installEFIFallback: { type: boolean }
installHybridGRUB: { type: boolean }

View File

@@ -28,7 +28,7 @@ import subprocess
import libcalamares
from libcalamares.utils import check_target_env_call
from libcalamares.utils import check_target_env_call, check_target_env_output
import gettext
@@ -605,7 +605,7 @@ def run_grub_mkconfig(partitions, output_file):
check_target_env_call([libcalamares.job.configuration["grubMkconfig"], "-o", output_file])
def run_grub_install(fw_type, partitions, efi_directory):
def run_grub_install(fw_type, partitions, efi_directory, install_hybrid_grub):
"""
Runs grub-install in the target environment
@@ -637,33 +637,52 @@ def run_grub_install(fw_type, partitions, efi_directory):
"--bootloader-id=" + efi_bootloader_id,
"--force"])
else:
assert efi_directory is None
if libcalamares.globalstorage.value("bootLoader") is None:
if efi_directory is not None and not install_hybrid_grub:
libcalamares.utils.warning(_("Cannot install BIOS bootloader on UEFI installation when install_hybrid_grub is 'False'!"))
return
boot_loader = libcalamares.globalstorage.value("bootLoader")
if boot_loader["installPath"] is None:
return
if libcalamares.globalstorage.value("bootLoader") is None:
efi_install_path = libcalamares.globalstorage.value("efiSystemPartition")
if efi_install_path is None or efi_install_path == "":
efi_install_path = "/boot/efi"
find_esp_disk_command = f"lsblk -o PKNAME \"$(df --output=source '{efi_install_path}' | tail -n1)\""
boot_loader_install_path = check_target_env_output(["sh", "-c", find_esp_disk_command]).strip()
if not "\n" in boot_loader_install_path:
libcalamares.utils.warning(_("Cannot find the drive containing the EFI system partition!"))
return
boot_loader_install_path = "/dev/" + boot_loader_install_path.split("\n")[1]
else:
boot_loader = libcalamares.globalstorage.value("bootLoader")
boot_loader_install_path = boot_loader["installPath"]
if boot_loader_install_path is None:
return
# boot_loader_install_path points to the physical disk to install GRUB
# to. It should start with "/dev/", and be at least as long as the
# string "/dev/sda".
if not boot_loader_install_path.startswith("/dev/") or len(boot_loader_install_path) < 8:
raise ValueError(f"boot_loader_install_path contains unexpected value '{boot_loader_install_path}'")
if is_zfs:
check_target_env_call(["sh", "-c", "ZPOOL_VDEV_NAME_PATH=1 "
+ libcalamares.job.configuration["grubInstall"]
+ " --target=i386-pc --recheck --force "
+ boot_loader["installPath"]])
+ boot_loader_install_path])
else:
check_target_env_call([libcalamares.job.configuration["grubInstall"],
"--target=i386-pc",
"--recheck",
"--force",
boot_loader["installPath"]])
boot_loader_install_path])
def install_grub(efi_directory, fw_type):
def install_grub(efi_directory, fw_type, install_hybrid_grub):
"""
Installs grub as bootloader, either in pc or efi mode.
:param efi_directory:
:param fw_type:
:param install_hybrid_grub:
"""
# get the partition from global storage
partitions = libcalamares.globalstorage.value("partitions")
@@ -671,8 +690,12 @@ def install_grub(efi_directory, fw_type):
libcalamares.utils.warning(_("Failed to install grub, no partitions defined in global storage"))
return
if fw_type == "efi":
if fw_type != "bios" and fw_type != "efi":
raise ValueError("fw_type must be 'bios' or 'efi'")
if fw_type == "efi" or install_hybrid_grub:
libcalamares.utils.debug("Bootloader: grub (efi)")
libcalamares.utils.debug(f"install_hybrid_grub: {install_hybrid_grub}")
installation_root_path = libcalamares.globalstorage.value("rootMountPoint")
install_efi_directory = installation_root_path + efi_directory
@@ -683,7 +706,7 @@ def install_grub(efi_directory, fw_type):
efi_target, efi_grub_file, efi_boot_file = get_grub_efi_parameters()
run_grub_install(fw_type, partitions, efi_directory)
run_grub_install("efi", partitions, efi_directory, install_hybrid_grub)
# VFAT is weird, see issue CAL-385
install_efi_directory_firmware = (vfat_correct_case(
@@ -706,15 +729,36 @@ def install_grub(efi_directory, fw_type):
libcalamares.utils.debug("UEFI Fallback: " + str(libcalamares.job.configuration.get(fallback, "<unset>")))
if libcalamares.job.configuration.get(fallback, True):
libcalamares.utils.debug(" .. installing '{!s}' fallback firmware".format(efi_boot_file))
efi_file_source = os.path.join(install_efi_directory_firmware,
efi_bootloader_id,
efi_grub_file)
efi_file_target = os.path.join(install_efi_boot_directory, efi_boot_file)
# Try to use a distro-specific installation routine first
distro_name = ""
with open(os.path.join(installation_root_path,
"/etc/os-release"), "r") as os_release_file:
for os_release_line in os_release_file:
if os_release_line.startswith("NAME="):
distro_name = os_release_line.split("=", 1)[1].strip("\"\n")
match distro_name:
case "Debian GNU/Linux":
efi_deb_pkg_arch = None
match efi_target:
# Note: No loongarch64 EFI support in Debian.
case "i386-efi":
efi_deb_pkg_arch = "ia32"
case "arm64-efi":
efi_deb_pkg_arch = "arm64"
case "x86_64-efi":
efi_deb_pkg_arch = "amd64"
if efi_deb_pkg_arch is not None:
check_target_env_call(["sh", "-c", f"echo 'grub-efi-{efi_deb_pkg_arch} grub2/force_efi_extra_removable boolean true' | debconf-set-selections && dpkg-reconfigure --default-priority grub-efi-{efi_deb_pkg_arch}"])
case _:
efi_file_source = os.path.join(install_efi_directory_firmware,
efi_bootloader_id,
efi_grub_file)
efi_file_target = os.path.join(install_efi_boot_directory, efi_boot_file)
shutil.copy2(efi_file_source, efi_file_target)
else:
shutil.copy2(efi_file_source, efi_file_target)
if fw_type == "bios" or install_hybrid_grub:
libcalamares.utils.debug("Bootloader: grub (bios)")
run_grub_install(fw_type, partitions, None)
run_grub_install("bios", partitions, efi_directory, install_hybrid_grub)
run_grub_mkconfig(partitions, libcalamares.job.configuration["grubCfg"])
@@ -844,7 +888,7 @@ def install_refind(efi_directory):
update_refind_config(efi_directory, installation_root_path)
def prepare_bootloader(fw_type):
def prepare_bootloader(fw_type, install_hybrid_grub):
"""
Prepares bootloader.
Based on value 'efi_boot_loader', it either calls systemd-boot
@@ -868,8 +912,8 @@ def prepare_bootloader(fw_type):
try:
efi_boot_loader = libcalamares.job.configuration["efiBootLoader"]
except KeyError:
if fw_type == "efi":
libcalamares.utils.warning("Configuration missing both efiBootLoader and efiBootLoaderVar on an EFI "
if fw_type == "efi" or install_hybrid_grub:
libcalamares.utils.warning("Configuration missing both efiBootLoader and efiBootLoaderVar on an EFI-enabled "
"system, bootloader not installed")
return
else:
@@ -894,7 +938,7 @@ def prepare_bootloader(fw_type):
elif efi_boot_loader == "refind" and fw_type == "efi":
install_refind(efi_directory)
elif efi_boot_loader == "grub" or fw_type != "efi":
install_grub(efi_directory, fw_type)
install_grub(efi_directory, fw_type, install_hybrid_grub)
else:
libcalamares.utils.debug("WARNING: the combination of "
"boot-loader '{!s}' and firmware '{!s}' "
@@ -909,8 +953,15 @@ def run():
"""
fw_type = libcalamares.globalstorage.value("firmwareType")
boot_loader = libcalamares.globalstorage.value("bootLoader")
if libcalamares.globalstorage.value("bootLoader") is None and fw_type != "efi":
install_hybrid_grub = libcalamares.job.configuration.get("installHybridGRUB", False)
efi_boot_loader = libcalamares.job.configuration.get("efiBootLoader", "")
if install_hybrid_grub == True and efi_boot_loader != "grub":
raise ValueError(f"efi_boot_loader '{efi_boot_loader}' is illegal when install_hybrid_grub is 'true'!")
if boot_loader is None and fw_type != "efi":
libcalamares.utils.warning("Non-EFI system, and no bootloader is set.")
return None
@@ -923,7 +974,7 @@ def run():
return None
try:
prepare_bootloader(fw_type)
prepare_bootloader(fw_type, install_hybrid_grub)
except subprocess.CalledProcessError as e:
libcalamares.utils.warning(str(e))
libcalamares.utils.debug("stdout:" + str(e.stdout))

View File

@@ -22,7 +22,7 @@ overwrite: false
# If set to true, prefer to write files in /etc/default/grub.d/
# rather than the single file /etc/default/grub. If this is set,
# Calamares will write /etc/default/grub.d/00Calamares instead.
# Calamares will write /etc/default/grub.d/00calamares.cfg instead.
prefer_grub_d: false
# If set to true, an **existing** setting for GRUB_DISTRIBUTOR is

View File

@@ -45,7 +45,7 @@ def get_grub_config_path(root_mount_point):
possible_dir = os.path.join(root_mount_point, "etc/default/grub.d")
if os.path.exists(possible_dir) and os.path.isdir(possible_dir):
default_dir = possible_dir
default_config_file = "00calamares"
default_config_file = "00calamares.cfg"
if not os.path.exists(default_dir):
try:

View File

@@ -12,6 +12,14 @@
#include <QString>
struct BasicLayoutInfo
{
QString selectedLayout;
QString selectedModel;
QString selectedVariant;
QString selectedGroup;
};
struct AdditionalLayoutInfo
{
QString additionalLayout;

View File

@@ -169,7 +169,7 @@ Config::Config( QObject* parent )
&KeyboardModelsModel::currentIndexChanged,
[ & ]( int index )
{
m_selectedModel = m_keyboardModelsModel->key( index );
m_current.selectedModel = m_keyboardModelsModel->key( index );
somethingChanged();
} );
@@ -177,7 +177,7 @@ Config::Config( QObject* parent )
&KeyboardLayoutModel::currentIndexChanged,
[ & ]( int index )
{
m_selectedLayout = m_keyboardLayoutsModel->item( index ).first;
m_current.selectedLayout = m_keyboardLayoutsModel->item( index ).first;
updateVariants( QPersistentModelIndex( m_keyboardLayoutsModel->index( index ) ) );
emit prettyStatusChanged();
} );
@@ -186,14 +186,14 @@ Config::Config( QObject* parent )
&KeyboardVariantsModel::currentIndexChanged,
[ & ]( int index )
{
m_selectedVariant = m_keyboardVariantsModel->key( index );
m_current.selectedVariant = m_keyboardVariantsModel->key( index );
somethingChanged();
} );
connect( m_KeyboardGroupSwitcherModel,
&KeyboardGroupsSwitchersModel::currentIndexChanged,
[ & ]( int index )
{
m_selectedGroup = m_KeyboardGroupSwitcherModel->key( index );
m_current.selectedGroup = m_KeyboardGroupSwitcherModel->key( index );
somethingChanged();
} );
@@ -207,10 +207,10 @@ Config::Config( QObject* parent )
this,
&Config::selectionChange );
m_selectedModel = m_keyboardModelsModel->key( m_keyboardModelsModel->currentIndex() );
m_selectedLayout = m_keyboardLayoutsModel->item( m_keyboardLayoutsModel->currentIndex() ).first;
m_selectedVariant = m_keyboardVariantsModel->key( m_keyboardVariantsModel->currentIndex() );
m_selectedGroup = m_KeyboardGroupSwitcherModel->key( m_KeyboardGroupSwitcherModel->currentIndex() );
m_current.selectedModel = m_keyboardModelsModel->key( m_keyboardModelsModel->currentIndex() );
m_current.selectedLayout = m_keyboardLayoutsModel->item( m_keyboardLayoutsModel->currentIndex() ).first;
m_current.selectedVariant = m_keyboardVariantsModel->key( m_keyboardVariantsModel->currentIndex() );
m_current.selectedGroup = m_KeyboardGroupSwitcherModel->key( m_KeyboardGroupSwitcherModel->currentIndex() );
}
void
@@ -224,38 +224,56 @@ Config::somethingChanged()
emit prettyStatusChanged();
}
void
Config::apply()
static void
applyXkb( const BasicLayoutInfo& settings, AdditionalLayoutInfo& extra )
{
if ( m_configureXkb )
QStringList basicArguments = xkbmap_model_args( settings.selectedModel );
if ( !extra.additionalLayout.isEmpty() )
{
applyXkb();
if ( !settings.selectedGroup.isEmpty() )
{
extra.groupSwitcher = "grp:" + settings.selectedGroup;
}
if ( extra.groupSwitcher.isEmpty() )
{
extra.groupSwitcher = xkbmap_query_grp_option();
}
if ( extra.groupSwitcher.isEmpty() )
{
extra.groupSwitcher = "grp:alt_shift_toggle";
}
basicArguments.append(
xkbmap_layout_args_with_group_switch( { extra.additionalLayout, settings.selectedLayout },
{ extra.additionalVariant, settings.selectedVariant },
extra.groupSwitcher ) );
QProcess::execute( "setxkbmap", basicArguments );
cDebug() << "xkbmap selection changed to: " << settings.selectedLayout << '-' << settings.selectedVariant
<< "(added " << extra.additionalLayout << "-" << extra.additionalVariant
<< " since current layout is not ASCII-capable)";
}
if ( m_configureLocale1 )
else
{
applyLocale1();
basicArguments.append( xkbmap_layout_args( settings.selectedLayout, settings.selectedVariant ) );
QProcess::execute( "setxkbmap", basicArguments );
cDebug() << "xkbmap selection changed to: " << settings.selectedLayout << '-' << settings.selectedVariant;
}
if ( m_configureKWin )
{
applyKWin();
}
// Writing /etc/ files is not needed "live"
}
void
Config::applyLocale1()
static void
applyLocale1( const BasicLayoutInfo& settings, AdditionalLayoutInfo& extra )
{
m_additionalLayoutInfo = getAdditionalLayoutInfo( m_selectedLayout );
QString layout = m_selectedLayout;
QString variant = m_selectedVariant;
QString layout = settings.selectedLayout;
QString variant = settings.selectedVariant;
QString option;
if ( !m_additionalLayoutInfo.additionalLayout.isEmpty() )
if ( !extra.additionalLayout.isEmpty() )
{
layout = m_additionalLayoutInfo.additionalLayout + "," + layout;
variant = m_additionalLayoutInfo.additionalVariant + "," + variant;
option = m_additionalLayoutInfo.groupSwitcher;
layout = extra.additionalLayout + "," + layout;
variant = extra.additionalVariant + "," + variant;
option = extra.groupSwitcher;
}
QDBusInterface locale1( "org.freedesktop.locale1",
@@ -270,7 +288,8 @@ Config::applyLocale1()
// Using convert=true, this also updates the VConsole config
{
QDBusReply< void > r = locale1.call( "SetX11Keyboard", layout, m_selectedModel, variant, option, true, false );
QDBusReply< void > r
= locale1.call( "SetX11Keyboard", layout, settings.selectedModel, variant, option, true, false );
if ( !r.isValid() )
{
cWarning() << "Could not set keyboard config through org.freedesktop.locale1.X11Keyboard." << r.error();
@@ -278,47 +297,6 @@ Config::applyLocale1()
}
}
void
Config::applyXkb()
{
m_additionalLayoutInfo = getAdditionalLayoutInfo( m_selectedLayout );
QStringList basicArguments = xkbmap_model_args( m_selectedModel );
if ( !m_additionalLayoutInfo.additionalLayout.isEmpty() )
{
if ( !m_selectedGroup.isEmpty() )
{
m_additionalLayoutInfo.groupSwitcher = "grp:" + m_selectedGroup;
}
if ( m_additionalLayoutInfo.groupSwitcher.isEmpty() )
{
m_additionalLayoutInfo.groupSwitcher = xkbmap_query_grp_option();
}
if ( m_additionalLayoutInfo.groupSwitcher.isEmpty() )
{
m_additionalLayoutInfo.groupSwitcher = "grp:alt_shift_toggle";
}
basicArguments.append(
xkbmap_layout_args_with_group_switch( { m_additionalLayoutInfo.additionalLayout, m_selectedLayout },
{ m_additionalLayoutInfo.additionalVariant, m_selectedVariant },
m_additionalLayoutInfo.groupSwitcher ) );
QProcess::execute( "setxkbmap", basicArguments );
cDebug() << "xkbmap selection changed to: " << m_selectedLayout << '-' << m_selectedVariant << "(added "
<< m_additionalLayoutInfo.additionalLayout << "-" << m_additionalLayoutInfo.additionalVariant
<< " since current layout is not ASCII-capable)";
}
else
{
basicArguments.append( xkbmap_layout_args( m_selectedLayout, m_selectedVariant ) );
QProcess::execute( "setxkbmap", basicArguments );
cDebug() << "xkbmap selection changed to: " << m_selectedLayout << '-' << m_selectedVariant;
}
m_applyTimer.stop();
}
// In a config-file's list of lines, replace lines <key>=<something> by <key>=<value>
static void
replaceKey( QStringList& content, const QString& key, const QString& value )
@@ -368,21 +346,21 @@ rewriteKWin( const QString& path, const QString& model, const QString& layouts,
}
void
Config::applyKWin()
applyKWin( const BasicLayoutInfo& settings, AdditionalLayoutInfo& extra )
{
const auto paths = QStandardPaths::standardLocations( QStandardPaths::ConfigLocation );
auto join = [ &additional = m_additionalLayoutInfo.additionalLayout ]( const QString& s1, const QString& s2 )
auto join = [ &additional = extra.additionalLayout ]( const QString& s1, const QString& s2 )
{ return additional.isEmpty() ? s1 : QStringLiteral( "%1,%2" ).arg( s1, s2 ); };
const QString layouts = join( m_selectedLayout, m_additionalLayoutInfo.additionalLayout );
const QString variants = join( m_selectedVariant, m_additionalLayoutInfo.additionalVariant );
const QString layouts = join( settings.selectedLayout, extra.additionalLayout );
const QString variants = join( settings.selectedVariant, extra.additionalVariant );
bool updated = false;
for ( const auto& path : paths )
{
const QString candidate = path + QStringLiteral( "/kxkbrc" );
if ( rewriteKWin( candidate, m_selectedModel, layouts, variants ) )
if ( rewriteKWin( candidate, settings.selectedModel, layouts, variants ) )
{
updated = true;
break;
@@ -397,6 +375,98 @@ Config::applyKWin()
}
}
QString
squareBracketedList( const QStringList& l )
{
return QStringLiteral( "[%1]" ).arg( l.join( ", " ) );
}
// Fpr a layout and variant, returns a string like "('xkb', 'uk+latin1')"
QString
concatLayoutAndVariant( const QString& layout, const QString& variant )
{
return QStringLiteral( "('xkb', '%1')" ).arg( variant.isEmpty() ? layout : ( layout + '+' + variant ) );
}
// Seem's keyboard settings don't work anymore with setxkbkeyboard with Gnome and Wayland
// use applyGnome() to use gsettings specific command
void
applyGnome( const BasicLayoutInfo& settings, AdditionalLayoutInfo& extra )
{
static constexpr int expectedUID = 1000; // Assume this is the live-cd user-id
const QString sudoUser
= QStringLiteral( "#%1" ).arg( expectedUID ); // GNU sudo can use '-u #nnn' with a literal '#' and numeric UID
const QString dbusPath = QStringLiteral( "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%1/bus" ).arg( expectedUID );
const QString sudo = QStringLiteral( "sudo" );
// clang-format off
// These are arguments to sudo to run gsettings to set something on input-sources
const QStringList sudoArguments{
"-u", sudoUser, // Run as numeric UID
dbusPath, // Set environment to pick up live user session bus
"gsettings", "set", "org.gnome.desktop.input-sources" // Command, still needs a key and a value after this
};
// clang-format on
QStringList sources { concatLayoutAndVariant( settings.selectedLayout, settings.selectedVariant ) };
// Case for ukrainian homophonic keyboard for exemple
// need to configure 2 keyboards and a toggle key
// gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'uk+latin1'), ('xkb','en')]"
// gsettings set org.gnome.desktop.input-sources xkb-options "['grp:lalt_lshift_toggle']"
if ( !extra.additionalLayout.isEmpty() )
{
// Get a reasonable value for the group switcher, defaulting to alt_shift_toggle if nothing else is set
if ( !settings.selectedGroup.isEmpty() )
{
extra.groupSwitcher = "grp:" + settings.selectedGroup;
}
if ( extra.groupSwitcher.isEmpty() )
{
extra.groupSwitcher = xkbmap_query_grp_option();
}
if ( extra.groupSwitcher.isEmpty() )
{
extra.groupSwitcher = "grp:alt_shift_toggle";
}
const QString xkbOptionsValue = QStringLiteral( "['%1']" ).arg( extra.groupSwitcher );
const QStringList xkbOptionsCommand = QStringList( sudoArguments ) << "xkb-options" << xkbOptionsValue;
QProcess::execute( "sudo", xkbOptionsCommand );
cDebug() << "Executed: sudo" << xkbOptionsCommand;
// And add additional layout to the sources-list
sources.append( concatLayoutAndVariant( extra.additionalLayout, extra.additionalVariant ) );
}
const QStringList sourcesCommand = QStringList( sudoArguments ) << "sources" << squareBracketedList( sources );
QProcess::execute( "sudo", sourcesCommand );
cDebug() << "Executed: sudo" << sourcesCommand;
}
void
Config::apply()
{
m_additionalLayoutInfo = getAdditionalLayoutInfo( m_current.selectedLayout );
if ( m_configureXkb )
{
applyXkb( m_current, m_additionalLayoutInfo );
}
if ( m_configureLocale1 )
{
applyLocale1( m_current, m_additionalLayoutInfo );
}
if ( m_configureKWin )
{
applyKWin( m_current, m_additionalLayoutInfo );
}
if ( m_configureGnome )
{
applyGnome( m_current, m_additionalLayoutInfo );
}
m_applyTimer.stop();
// Writing /etc/ files is not needed "live"
}
KeyboardModelsModel*
Config::keyboardModels() const
@@ -574,6 +644,30 @@ Config::detectCurrentKeyboardLayout()
break;
}
}
// The models have updated the m_current settings, copy them
m_original = m_current;
}
void
Config::cancel()
{
const auto extra = getAdditionalLayoutInfo( m_original.selectedLayout );
if ( m_configureXkb )
{
applyXkb( m_original, m_additionalLayoutInfo );
}
if ( m_configureLocale1 )
{
applyLocale1( m_original, m_additionalLayoutInfo );
}
if ( m_configureKWin )
{
applyKWin( m_original, m_additionalLayoutInfo );
}
if ( m_configureGnome )
{
applyGnome( m_original, m_additionalLayoutInfo );
}
}
QString
@@ -599,9 +693,9 @@ Config::createJobs()
{
QList< Calamares::job_ptr > list;
Calamares::Job* j = new SetKeyboardLayoutJob( m_selectedModel,
m_selectedLayout,
m_selectedVariant,
Calamares::Job* j = new SetKeyboardLayoutJob( m_current.selectedModel,
m_current.selectedLayout,
m_current.selectedVariant,
m_additionalLayoutInfo,
m_xOrgConfFileName,
m_convertedKeymapPath,
@@ -748,10 +842,10 @@ void
Config::finalize()
{
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
if ( !m_selectedLayout.isEmpty() )
if ( !m_current.selectedLayout.isEmpty() )
{
gs->insert( "keyboardLayout", m_selectedLayout );
gs->insert( "keyboardVariant", m_selectedVariant ); //empty means default variant
gs->insert( "keyboardLayout", m_current.selectedLayout );
gs->insert( "keyboardVariant", m_current.selectedVariant ); //empty means default variant
if ( !m_additionalLayoutInfo.additionalLayout.isEmpty() )
{
@@ -802,6 +896,7 @@ Config::setConfigurationMap( const QVariantMap& configurationMap )
bool bogus = false;
const auto configureItems = getSubMap( configurationMap, "configure", bogus );
m_configureKWin = getBool( configureItems, "kwin", false );
m_configureGnome = getBool( configureItems, "gnome", false );
m_guessLayout = getBool( configurationMap, "guessLayout", true );
}

View File

@@ -44,6 +44,9 @@ public:
/// @brief When leaving the page, write to GS
void finalize();
/// @brief Restore the system to whatever layout was in use when detectCurrentKeyboardLayout() was called
void cancel();
static AdditionalLayoutInfo getAdditionalLayoutInfo( const QString& layout );
/* A model is a physical configuration of a keyboard, e.g. 105-key PC
@@ -94,9 +97,6 @@ private:
*/
void somethingChanged();
void apply();
void applyLocale1();
void applyXkb();
void applyKWin();
void getCurrentKeyboardLayoutXkb( QString& currentLayout, QString& currentVariant, QString& currentModel );
void getCurrentKeyboardLayoutLocale1( QString& currentLayout, QString& currentVariant, QString& currentModel );
@@ -106,10 +106,8 @@ private:
KeyboardVariantsModel* m_keyboardVariantsModel;
KeyboardGroupsSwitchersModel* m_KeyboardGroupSwitcherModel;
QString m_selectedLayout;
QString m_selectedModel;
QString m_selectedVariant;
QString m_selectedGroup;
BasicLayoutInfo m_current;
BasicLayoutInfo m_original;
// Layout (and corresponding info) added if current one doesn't support ASCII (e.g. Russian or Japanese)
AdditionalLayoutInfo m_additionalLayoutInfo;
@@ -123,6 +121,7 @@ private:
bool m_configureEtcDefaultKeyboard = true;
bool m_configureLocale1 = false;
bool m_configureKWin = false;
bool m_configureGnome = false;
bool m_guessLayout = false;
// The state determines whether we guess settings or preserve them:

View File

@@ -104,6 +104,11 @@ KeyboardViewStep::onLeave()
m_config->finalize();
}
void
KeyboardViewStep::onCancel()
{
m_config->cancel();
}
void
KeyboardViewStep::setConfigurationMap( const QVariantMap& configurationMap )

View File

@@ -43,6 +43,7 @@ public:
void onActivate() override;
void onLeave() override;
void onCancel() override;
void setConfigurationMap( const QVariantMap& configurationMap ) override;

View File

@@ -43,3 +43,5 @@ configure:
# compositor KWin with command-line argument `--locale1`. That
# argument makes this configuration option unnecessary.
kwin: false
# Configure keyboard when using Wayland with Gnome on Ubuntu 24.10+
gnome: false

View File

@@ -80,6 +80,12 @@ KeyboardQmlViewStep::onLeave()
m_config->finalize();
}
void
KeyboardQmlViewStep::onCancel()
{
m_config->cancel();
}
QObject*
KeyboardQmlViewStep::getConfig()
{

View File

@@ -39,6 +39,7 @@ public:
void onActivate() override;
void onLeave() override;
void onCancel() override;
void setConfigurationMap( const QVariantMap& configurationMap ) override;
QObject* getConfig() override;

View File

@@ -378,7 +378,7 @@ Config::currentLocationStatus() const
{
if ( m_currentLocation )
{
return tr( "Set timezone to %1.", "@action" ).arg( currentTimezoneName());
return tr( "Set timezone to %1.", "@action" ).arg( currentTimezoneName() );
}
return QString();
}
@@ -513,6 +513,8 @@ getGeoIP( const QVariantMap& configurationMap, std::unique_ptr< Calamares::GeoIP
void
Config::setConfigurationMap( const QVariantMap& configurationMap )
{
m_originalTimezone = Calamares::GeoIP::splitTZString( QTimeZone::systemTimeZoneId() );
getLocaleGenLines( configurationMap, m_localeGenLines );
getAdjustLiveTimezone( configurationMap, m_adjustLiveTimezone );
getStartingTimezone( configurationMap, m_startingTimezone );
@@ -588,3 +590,12 @@ Config::completeGeoIP()
m_geoipWatcher.reset();
m_geoip.reset();
}
void
Config::cancel()
{
if ( m_adjustLiveTimezone && m_originalTimezone.isValid() )
{
QProcess::execute( "timedatectl", { "set-timezone", m_originalTimezone.asString() } );
}
}

View File

@@ -83,10 +83,12 @@ public:
const Calamares::Locale::TimeZoneData* currentLocation() const { return m_currentLocation; }
/// Special case, set location from starting timezone if not already set
void setCurrentLocation();
/// Restores original timezone, if any
void cancel();
private:
Calamares::Locale::TimeZoneData* currentLocation_c() const
{
@@ -176,6 +178,9 @@ private:
*/
Calamares::GeoIP::RegionZonePair m_startingTimezone;
/// @brief The timezone set in the system when Calamares started (not from config)
Calamares::GeoIP::RegionZonePair m_originalTimezone;
/** @brief Handler for GeoIP lookup (if configured)
*
* The GeoIP lookup needs to be started at some suitable time,

View File

@@ -130,6 +130,12 @@ LocaleViewStep::onLeave()
m_config->finalizeGlobalStorage();
}
void
LocaleViewStep::onCancel()
{
m_config->cancel();
}
void
LocaleViewStep::setConfigurationMap( const QVariantMap& configurationMap )
{

View File

@@ -44,6 +44,7 @@ public:
void onActivate() override;
void onLeave() override;
void onCancel() override;
void setConfigurationMap( const QVariantMap& configurationMap ) override;

View File

@@ -83,6 +83,12 @@ LocaleQmlViewStep::onLeave()
m_config->finalizeGlobalStorage();
}
void
LocaleQmlViewStep::onCancel()
{
m_config->cancel();
}
void
LocaleQmlViewStep::setConfigurationMap( const QVariantMap& configurationMap )
{

View File

@@ -34,8 +34,9 @@ public:
bool isAtBeginning() const override;
bool isAtEnd() const override;
virtual void onActivate() override;
virtual void onLeave() override;
void onActivate() override;
void onLeave() override;
void onCancel() override;
Calamares::JobList jobs() const override;

View File

@@ -918,6 +918,8 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap )
"will use gpt for efi or msdos for bios";
}
gs->insert( "defaultPartitionTableType", partitionTableName );
gs->insert( "createHybridBootloaderLayout",
Calamares::getBool( configurationMap, "createHybridBootloaderLayout", false ) );
// Now that we have the config, we load the PartitionCoreModule in the background
// because it could take a while. Then when it's done, we can set up the widgets

View File

@@ -616,7 +616,7 @@ canonicalFilesystemName( const QString& fsName, FileSystem::Type* fsType )
*fsType = FileSystem::Unknown;
}
#ifdef DEBUG_FILESYSTEMS
// This bit is for distro's debugging their settings, and shows
// This bit is for distros who are debugging their settings, and shows
// all the strings that KPMCore is matching against for FS type.
{
Logger::CDebug d;

View File

@@ -89,6 +89,11 @@ doAutopartition( PartitionCoreModule* core, Device* dev, Choices::AutoPartitionO
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
const bool isEfi = PartUtils::isEfiSystem();
bool createHybridBootloaderLayout = false;
if ( gs->contains( "createHybridBootloaderLayout" ) ) {
createHybridBootloaderLayout = gs->value( "createHybridBootloaderLayout" ).toBool();
}
// Partition sizes are expressed in MiB, should be multiples of
// the logical sector size (usually 512B). EFI starts with 2MiB
@@ -105,7 +110,7 @@ doAutopartition( PartitionCoreModule* core, Device* dev, Choices::AutoPartitionO
PartitionTable::TableType partType = PartitionTable::nameToTableType( o.defaultPartitionTableType );
if ( partType == PartitionTable::unknownTableType )
{
partType = isEfi ? PartitionTable::gpt : PartitionTable::msdos;
partType = ( isEfi || createHybridBootloaderLayout ) ? PartitionTable::gpt : PartitionTable::msdos;
}
// last usable sector possibly allowing for secondary GPT using 66 sectors (256 entries)
const qint64 lastUsableSector = dev->totalLogical() - ( partType == PartitionTable::gpt ? 67 : 1 );
@@ -118,7 +123,7 @@ doAutopartition( PartitionCoreModule* core, Device* dev, Choices::AutoPartitionO
core->createPartitionTable( dev, partType );
if ( isEfi )
if ( createHybridBootloaderLayout || isEfi )
{
qint64 uefisys_part_sizeB = PartUtils::efiFilesystemRecommendedSize();
qint64 efiSectorCount = Calamares::bytesToSectors( uefisys_part_sizeB, dev->logicalSize() );
@@ -144,6 +149,25 @@ doAutopartition( PartitionCoreModule* core, Device* dev, Choices::AutoPartitionO
}
core->createPartition( dev, efiPartition, KPM_PARTITION_FLAG_ESP );
firstFreeSector = lastSector + 1;
if ( createHybridBootloaderLayout )
{
qint64 bios_part_sizeB = 8_MiB;
qint64 biosSectorCount = Calamares::bytesToSectors( bios_part_sizeB, dev->logicalSize() );
Q_ASSERT( biosSectorCount > 0 );
qint64 lastSector = firstFreeSector + biosSectorCount - 1;
Partition* biosPartition = KPMHelpers::createNewPartition( dev->partitionTable(),
*dev,
PartitionRole( PartitionRole::Primary ),
FileSystem::Unformatted,
QString(),
firstFreeSector,
lastSector,
KPM_PARTITION_FLAG( None ) );
core->createPartition( dev, biosPartition, KPM_PARTITION_FLAG( BiosGrub ) );
firstFreeSector = lastSector + 1;
}
}
const bool mayCreateSwap

View File

@@ -13,6 +13,7 @@
#include "core/ColorUtils.h"
#include "core/PartitionModel.h"
#include "core/SizeUtils.h"
#include "core/KPMHelpers.h"
#include "utils/Gui.h"
#include "utils/Logger.h"
@@ -20,6 +21,7 @@
#include <kpmcore/core/device.h>
#include <kpmcore/fs/filesystem.h>
#include <kpmcore/core/partition.h>
// Qt
#include <QGuiApplication>
@@ -41,6 +43,12 @@ buildUnknownDisklabelTexts( Device* dev )
return texts;
}
static uint
getPartitionModelIndexFlags( const QModelIndex& index )
{
return static_cast< Partition* >( index.data( PartitionModel::PartitionPtrRole ).value< void* >() )->property( "_calamares_flags" ).toUInt();
}
PartitionLabelsView::PartitionLabelsView( QWidget* parent )
: QAbstractItemView( parent )
, m_canBeSelected( []( const QModelIndex& ) { return true; } )
@@ -190,6 +198,11 @@ PartitionLabelsView::buildTexts( const QModelIndex& index ) const
{
firstLine = tr( "EFI system", "@label" );
}
else if ( index.data( PartitionModel::FileSystemTypeRole ).toInt() == FileSystem::Unformatted
&& getPartitionModelIndexFlags( index ) & KPM_PARTITION_FLAG( BiosGrub ) )
{
firstLine = tr("BIOS boot", "@label" );
}
else if ( index.data( PartitionModel::FileSystemTypeRole ).toInt() == FileSystem::LinuxSwap )
{
firstLine = tr( "Swap", "@label" );

View File

@@ -30,7 +30,7 @@
#
# Both quantities must be at least 32MiB, this is enforced by the EFI
# spec. If minimum is not specified, it defaults to the recommended
# size. Distro's that allow more user latitude can set the minimum lower.
# size. Distros that allow more user latitude can set the minimum lower.
efi:
mountPoint: "/boot/efi"
recommendedSize: 300MiB
@@ -178,6 +178,13 @@ initialSwapChoice: none
#
# defaultPartitionTableType: msdos
# Specify whether to create a partition table layout suitable for a hybrid
# (BIOS + EFI) bootloader installation. This will prepend both bios-boot and
# EFI system partitions to the partition layout, regardless of whether the
# booted system uses BIOS or EFI firmware. Defaults to false.
#
# createHybridBootloaderLayout: false
# Requirement for partition table type
#
# Restrict the installation on disks that match the type of partition
@@ -294,7 +301,7 @@ essentialMounts: [ "live-*", "control", "ventoy" ]
# When enableLuksAutomatedPartitioning is true, this option will pre-check
# encryption checkbox. This option is only usefull to help people to not forget
# to cypher their disk when installing in enterprise (for exemple).
# to cypher their disk when installing in enterprise (for example).
#preCheckEncryption: false
# LVM support

View File

@@ -39,8 +39,8 @@
# of the details of that particular kind of tracking. If no policy
# is set, that tracking style is disabled. The example policy links
# go to Calamares' generic user manual (which is a terrible idea
# for distro's: you have GDPR obligations under most of these tracking
# styles, so do your homework).
# for a distribution: you have GDPR obligations under most of these
# tracking styles, so do your homework).
#
# Each area may have other configuration keys, depending on the
# area and how it needs to be configured.

View File

@@ -1017,6 +1017,7 @@ Config::setConfigurationMap( const QVariantMap& configurationMap )
// Renaming of Autologin -> AutoLogin in 4ffa79d4cf also affected
// configuration keys, which was not intended. Accept both.
m_displayAutoLogin = Calamares::getBool( configurationMap, "displayAutologin", false );
m_doAutoLogin = either(
Calamares::getBool, configurationMap, QStringLiteral( "doAutologin" ), QStringLiteral( "doAutoLogin" ), false );

View File

@@ -216,6 +216,8 @@ public:
/// Write /etc/hosts ?
bool writeEtcHosts() const { return m_writeEtcHosts; }
/// Should the user be able to changed the value of autologin?
bool displayAutoLogin() const { return m_displayAutoLogin; }
/// Should the user be automatically logged-in?
bool doAutoLogin() const { return m_doAutoLogin; }
/// Should the root password be written (if false, no password is set and the root account is disabled for login)
@@ -343,6 +345,7 @@ private:
QString m_rootPassword;
QString m_rootPasswordSecondary;
bool m_displayAutoLogin = false;
bool m_doAutoLogin = false;
bool m_writeRootPassword = true;

View File

@@ -136,6 +136,7 @@ UsersPage::UsersPage( Config* config, QWidget* parent )
connect( config, &Config::loginNameChanged, ui->textBoxLoginName, &QLineEdit::setText );
connect( config, &Config::loginNameStatusChanged, this, &UsersPage::reportLoginNameStatus );
ui->checkBoxDoAutoLogin->setVisible( m_config->displayAutoLogin() );
ui->checkBoxDoAutoLogin->setChecked( m_config->doAutoLogin() );
connect( ui->checkBoxDoAutoLogin,
Calamares::checkBoxStateChangedSignal,

View File

@@ -101,6 +101,13 @@ doReusePassword: true
# or another. Weak(er) passwords may be allowed, may cause a warning,
# or may be forbidden entirely.
# Autologin choice can be display to the user.
# Possible values are:
# - true to display it
# - false to hide it
# By default, this value is set to true.
displayAutologin: true
# You can control the initial state for the 'autologin checkbox' here.
# Possible values are:
# - true to check or

View File

@@ -31,6 +31,7 @@ properties:
sudoersGroup: { type: string }
sudoersConfigureWithGroup: { type: boolean, default: false }
# Skip login (depends on displaymanager support)
displayAutologin: { type: boolean, default: true }
doAutologin: { type: boolean, default: true }
# Root password separate from user password?
setRootPassword: { type: boolean, default: true }

View File

@@ -1,4 +1,3 @@
# SPDX-FileCopyrightText: no
# SPDX-License-Identifier: CC0-1.0
#
@@ -40,7 +39,8 @@ requirements:
# To check for internet connectivity, Calamares does a HTTP GET
# on this URL; on success (e.g. HTTP code 200) internet is OK.
# Use a privacy-respecting URL here, preferably in your distro's domain.
# Use a privacy-respecting URL here, preferably in your own
# distribution domain.
#
# The URL is only used if "internet" is in the *check* list below.
internetCheckUrl: http://example.com