Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 99 additions & 51 deletions src/modules/keyboard/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
#include "utils/Variant.h"

#include <QApplication>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QGuiApplication>
Comment thread
ptr1337 marked this conversation as resolved.
#include <QProcess>
#include <QRegularExpression>
Expand Down Expand Up @@ -119,6 +121,30 @@ xkbmap_query_grp_option()
return outputLine.mid( index, lastIndex - index );
}

static void
prepareGroupSwitcher( const BasicLayoutInfo& settings, AdditionalLayoutInfo& extra )
{
if ( extra.additionalLayout.isEmpty() )
{
extra.groupSwitcher.clear();
return;
}

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";
}
}

AdditionalLayoutInfo
Config::getAdditionalLayoutInfo( const QString& layout )
{
Expand Down Expand Up @@ -230,20 +256,7 @@ applyXkb( const BasicLayoutInfo& settings, AdditionalLayoutInfo& extra )
QStringList basicArguments = xkbmap_model_args( settings.selectedModel );
if ( !extra.additionalLayout.isEmpty() )
{
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";
}

prepareGroupSwitcher( settings, extra );
basicArguments.append(
xkbmap_layout_args_with_group_switch( { extra.additionalLayout, settings.selectedLayout },
{ extra.additionalVariant, settings.selectedVariant },
Expand Down Expand Up @@ -271,6 +284,7 @@ applyLocale1( const BasicLayoutInfo& settings, AdditionalLayoutInfo& extra )

if ( !extra.additionalLayout.isEmpty() )
{
prepareGroupSwitcher( settings, extra );
layout = extra.additionalLayout + "," + layout;
variant = extra.additionalVariant + "," + variant;
option = extra.groupSwitcher;
Expand All @@ -297,47 +311,90 @@ applyLocale1( const BasicLayoutInfo& settings, AdditionalLayoutInfo& extra )
}
}

// In a config-file's list of lines, replace lines <key>=<something> by <key>=<value>
// In kxkbrc content, set a key inside the [Layout] group and create the group if needed.
static void
replaceKey( QStringList& content, const QString& key, const QString& value )
setLayoutKey( QStringList& content, const QString& key, const QString& value )
{
int groupStart = -1;
int groupEnd = content.length();
for ( int i = 0; i < content.length(); ++i )
{
const QString line = content.at( i ).trimmed();
if ( line == QStringLiteral( "[Layout]" ) )
{
groupStart = i;
continue;
}
if ( groupStart >= 0 && i > groupStart && line.startsWith( '[' ) )
{
groupEnd = i;
break;
}
}

if ( groupStart < 0 )
{
if ( !content.isEmpty() && !content.constLast().isEmpty() )
{
content.append( QString() );
}
content.append( QStringLiteral( "[Layout]" ) );
groupStart = content.length() - 1;
groupEnd = content.length();
}

for ( int i = groupStart + 1; i < groupEnd; ++i )
{
if ( content.at( i ).startsWith( key ) )
{
content[ i ] = key + value;
return;
}
}

content.insert( groupEnd, key + value );
}

static bool
rewriteKWin( const QString& path, const QString& model, const QString& layouts, const QString& variants )
rewriteKWin( const QString& path,
const QString& model,
const QString& layouts,
const QString& variants,
const QString& options )
{
if ( !QFile::exists( path ) )
{
return false;
}

QFile config( path );
if ( !config.open( QIODevice::ReadOnly ) )
QStringList content;
if ( config.exists() )
{
return false;
if ( !config.open( QIODevice::ReadOnly ) )
{
return false;
}
content = []( QFile& f )
{
QTextStream s( &f );
return s.readAll().split( '\n' );
}( config );
config.close();
}
QStringList content = []( QFile& f )
else
{
QTextStream s( &f );
return s.readAll().split( '\n' );
}( config );
config.close();
QDir().mkpath( QFileInfo( path ).path() );
}

if ( !config.open( QIODevice::WriteOnly ) )
{
return false;
}

replaceKey( content, QStringLiteral( "Model=" ), model );
replaceKey( content, QStringLiteral( "LayoutList=" ), layouts );
replaceKey( content, QStringLiteral( "VariantList=" ), variants );
setLayoutKey( content, QStringLiteral( "Model=" ), model );
setLayoutKey( content, QStringLiteral( "LayoutList=" ), layouts );
setLayoutKey( content, QStringLiteral( "VariantList=" ), variants );
if ( !options.isEmpty() )
{
setLayoutKey( content, QStringLiteral( "Options=" ), options );
}
Comment on lines +397 to +400
setLayoutKey( content, QStringLiteral( "Use=" ), QStringLiteral( "true" ) );

config.write( content.join( '\n' ).toUtf8() );
config.close();
Expand All @@ -349,18 +406,20 @@ void
applyKWin( const BasicLayoutInfo& settings, AdditionalLayoutInfo& extra )
{
const auto paths = QStandardPaths::standardLocations( QStandardPaths::ConfigLocation );
prepareGroupSwitcher( settings, extra );

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( settings.selectedLayout, extra.additionalLayout );
const QString variants = join( settings.selectedVariant, extra.additionalVariant );
Comment thread
ptr1337 marked this conversation as resolved.
Outdated
const QString options = extra.groupSwitcher;

bool updated = false;
for ( const auto& path : paths )
{
const QString candidate = path + QStringLiteral( "/kxkbrc" );
if ( rewriteKWin( candidate, settings.selectedModel, layouts, variants ) )
if ( rewriteKWin( candidate, settings.selectedModel, layouts, variants, options ) )
{
updated = true;
break;
Expand Down Expand Up @@ -415,19 +474,7 @@ applyGnome( const BasicLayoutInfo& settings, AdditionalLayoutInfo& extra )
// 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";
}
prepareGroupSwitcher( settings, extra );

const QString xkbOptionsValue = QStringLiteral( "['%1']" ).arg( extra.groupSwitcher );
const QStringList xkbOptionsCommand = QStringList( sudoArguments ) << "xkb-options" << xkbOptionsValue;
Expand Down Expand Up @@ -651,22 +698,22 @@ Config::detectCurrentKeyboardLayout()
void
Config::cancel()
{
const auto extra = getAdditionalLayoutInfo( m_original.selectedLayout );
auto extra = getAdditionalLayoutInfo( m_original.selectedLayout );
if ( m_configureXkb )
{
applyXkb( m_original, m_additionalLayoutInfo );
applyXkb( m_original, extra );
}
if ( m_configureLocale1 )
{
applyLocale1( m_original, m_additionalLayoutInfo );
applyLocale1( m_original, extra );
}
if ( m_configureKWin )
{
applyKWin( m_original, m_additionalLayoutInfo );
applyKWin( m_original, extra );
}
if ( m_configureGnome )
{
applyGnome( m_original, m_additionalLayoutInfo );
applyGnome( m_original, extra );
}
}

Expand Down Expand Up @@ -892,6 +939,7 @@ Config::setConfigurationMap( const QVariantMap& configurationMap )
m_convertedKeymapPath = getString( configurationMap, "convertedKeymapPath" );
m_configureEtcDefaultKeyboard = getBool( configurationMap, "writeEtcDefaultKeyboard", true );
m_configureLocale1 = getBool( configurationMap, "useLocale1", !isX11 );
m_configureXkb = isX11 && !m_configureLocale1;
Comment thread
ptr1337 marked this conversation as resolved.
Outdated

bool bogus = false;
const auto configureItems = getSubMap( configurationMap, "configure", bogus );
Expand Down
20 changes: 18 additions & 2 deletions src/modules/keyboard/SetKeyboardLayoutJob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,22 @@ removeEmpty( QStringList&& list )
list.removeAll( QString() );
return list;
}

QStringList
variantList( const AdditionalLayoutInfo& additionalLayoutInfo, const QString& variant )
{
if ( additionalLayoutInfo.additionalLayout.isEmpty() )
{
return removeEmpty( { variant } );
Comment thread
ptr1337 marked this conversation as resolved.
Outdated
}

QStringList variants { additionalLayoutInfo.additionalVariant, variant };
if ( variants.join( QString() ).isEmpty() )
{
variants.clear();
}
return variants;
}
} // namespace

SetKeyboardLayoutJob::SetKeyboardLayoutJob( const QString& model,
Expand Down Expand Up @@ -280,7 +296,7 @@ SetKeyboardLayoutJob::writeX11Data( const QString& keyboardConfPath ) const


const QStringList layouts = removeEmpty( { m_additionalLayoutInfo.additionalLayout, m_layout } );
const QStringList variants = removeEmpty( { m_additionalLayoutInfo.additionalVariant, m_variant } );
const QStringList variants = variantList( m_additionalLayoutInfo, m_variant );
stream << " Option \"XkbLayout\" \"" << layouts.join( "," ) << "\"\n";
stream << " Option \"XkbVariant\" \"" << variants.join( "," ) << "\"\n";
if ( !m_additionalLayoutInfo.additionalLayout.isEmpty() )
Expand Down Expand Up @@ -314,7 +330,7 @@ SetKeyboardLayoutJob::writeDefaultKeyboardData( const QString& defaultKeyboardPa
QTextStream stream( &file );

const QStringList layouts = removeEmpty( { m_additionalLayoutInfo.additionalLayout, m_layout } );
const QStringList variants = removeEmpty( { m_additionalLayoutInfo.additionalVariant, m_variant } );
const QStringList variants = variantList( m_additionalLayoutInfo, m_variant );
stream << "# KEYBOARD CONFIGURATION FILE\n\n"
"# Consult the keyboard(5) manual page.\n\n";

Expand Down
4 changes: 2 additions & 2 deletions src/modules/keyboard/keyboard.conf
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ convertedKeymapPath: "/lib/kbd/keymaps/xkb"
# This is the modern mechanism for configuring the systemwide keyboard layout,
# and works on Wayland compositors to set the current layout.
# Defaults to false on X11 and true otherwise.
#useLocale1: true
useLocale1: true

# Guess the default layout from the user locale. If false, keeps the current
# OS keyboard layout as the default (useful if the layout is pre-configured).
Expand All @@ -42,6 +42,6 @@ configure:
# Systems that use KDE Plasma Wayland and locale1 can instead start the
# compositor KWin with command-line argument `--locale1`. That
# argument makes this configuration option unnecessary.
kwin: true
kwin: false
Comment thread
ptr1337 marked this conversation as resolved.
# Configure keyboard when using Wayland with Gnome on Ubuntu 24.10+
gnome: false
1 change: 1 addition & 0 deletions src/modules/keyboard/keyboard.schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ properties:
type: object
properties:
kwin: { type: boolean, default: false }
gnome: { type: boolean, default: false }
required: [ xOrgConfFileName, convertedKeymapPath ]