Skip to content

Commit

Permalink
LocaleManager: set system locale and keyboard via dbus (#205)
Browse files Browse the repository at this point in the history
  • Loading branch information
danirabbit authored Jun 18, 2024
1 parent dccc5c1 commit 2b8aa1e
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 96 deletions.
3 changes: 1 addition & 2 deletions data/locale.policy.in
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
<allow_inactive>no</allow_inactive>
<allow_active>auth_admin_keep</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.exec.path">/usr/bin/localectl</annotate>
<annotate key="org.freedesktop.policykit.imply">org.freedesktop.locale1.set-locale org.debian.apt.install-or-remove-packages</annotate>
<annotate key="org.freedesktop.policykit.imply">org.debian.apt.install-or-remove-packages</annotate>
</action>

</policyconfig>
113 changes: 28 additions & 85 deletions src/LocaleManager.vala
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ public interface AccountProxy : GLib.Object {
public interface Locale1Proxy : GLib.Object {
public abstract string[] locale { owned get; }

public abstract void set_locale (string[] arg_0, bool arg_1) throws GLib.Error;
public abstract void set_x11_keyboard (
string arg_0,
string arg_1,
string arg_2,
string arg_3,
bool arg_4,
bool arg_5
public abstract async void set_locale (string[] locale, bool interactive) throws GLib.Error;
public abstract async void set_x11_keyboard (
string layout,
string model,
string variant,
string options,
bool convert,
bool interactive
) throws GLib.Error;
}

Expand Down Expand Up @@ -167,70 +167,6 @@ namespace SwitchboardPlugLocale {
return get_system_locale () ?? "en_US.UTF-8";
}

private void localectl_set_locale (string locale, string? format = null) throws GLib.Error {
debug ("setting system-wide locale via localectl");
if (Utils.get_permission ().allowed) {
string output;
int status;
string cli = "/usr/bin/localectl";
string command = "set-locale";

try {
if (format == null) {
Process.spawn_sync (null,
{"pkexec", cli, command, locale},
Environ.get (),
SpawnFlags.SEARCH_PATH,
null, out output,
null, out status);
if (output != "") {
critical ("localectl failed to set locale");
}
} else {
Process.spawn_sync (null,
{"pkexec", cli, command, locale, "LC_TIME=%s".printf (format),
"LC_NUMERIC=%s".printf (format), "LC_MONETARY=%s".printf (format),
"LC_MEASUREMENT=%s".printf (format)},
Environ.get (),
SpawnFlags.SEARCH_PATH,
null, out output,
null, out status);
if (output != "") {
critical ("localectl failed to set locale");
}
}
} catch (Error e) {
critical ("localectl failed to set locale");
throw e;
}
}
}

private void localectl_set_x11_keymap (string layouts, string variants) throws GLib.Error {
if (Utils.get_permission ().allowed) {
string output;
int status;
string cli = "/usr/bin/localectl";
string command = "set-x11-keymap";

try {
Process.spawn_sync (null,
{"pkexec", cli, command, layouts, "", variants},
Environ.get (),
SpawnFlags.SEARCH_PATH,
null, out output,
null, out status);

if (output != "") {
critical ("localectl failed to set x11 keymap");
}
} catch (Error e) {
critical ("localectl failed to set x11 keymap");
throw e;
}
}
}

public string? get_system_locale () {
foreach (unowned var locale in locale1_proxy.locale) {
if (locale.has_prefix ("LANG=")) {
Expand All @@ -241,19 +177,20 @@ namespace SwitchboardPlugLocale {
return null;
}

public void apply_to_system (string language, string? format) {
/*
* This is a temporary solution for setting the system-wide locale.
* I am assuming systemd in version 204 (which we currently ship from Ubuntu repositories)
* is broken as SetLocale does not recognize the aquired polkit permission. Maybe that is
* intended, but I do not believe this. May be fixed in a later version of systemd and should
* be reversed (TODO) when introducing a newer version of systemd to elementary OS.
*/
public async void apply_to_system (string language, string? format) throws GLib.Error {
string[] locale = {"LANG=%s".printf (language)};

if (format != null) {
locale += "LC_TIME=%s".printf (format);
locale += "LC_NUMERIC=%s".printf (format);
locale += "LC_MONETARY=%s".printf (format);
locale += "LC_MEASUREMENT=%s".printf (format);
}

try {
localectl_set_locale ("LANG=%s".printf (language), format);
yield locale1_proxy.set_locale (locale, true);
} catch (Error e) {
warning (e.message);
throw (e);
}

string layouts = "";
Expand Down Expand Up @@ -282,10 +219,16 @@ namespace SwitchboardPlugLocale {
}

try {
/* TODO: temporary solution for systemd-localed polkit problem */
localectl_set_x11_keymap (layouts, variants);
yield locale1_proxy.set_x11_keyboard (
layouts,
"",
variants,
"",
true,
true
);
} catch (Error e) {
warning (e.message);
throw (e);
}
}

Expand Down
31 changes: 22 additions & 9 deletions src/Widgets/LocaleSetting.vala
Original file line number Diff line number Diff line change
Expand Up @@ -201,13 +201,7 @@ namespace SwitchboardPlugLocale.Widgets {
restart_infobar.revealed = true;
});

set_system_button.clicked.connect (() => {
if (!Utils.allowed_permission ()) {
return;
}

on_applied_to_system ();
});
set_system_button.clicked.connect (on_applied_to_system);

installer.check_missing_finished.connect (on_check_missing_finished);
}
Expand Down Expand Up @@ -333,9 +327,28 @@ namespace SwitchboardPlugLocale.Widgets {
var selected_locale = get_selected_locale ();
var selected_format = get_format ();
debug ("Setting system language to '%s' and format to '%s'", selected_locale, selected_format);
lm.apply_to_system (selected_locale, selected_format);
lm.apply_to_system.begin (selected_locale, selected_format, (obj, res) => {
try {
lm.apply_to_system.end (res);
restart_infobar.revealed = true;
} catch (Error e) {
if (e.matches (GLib.DBusError.quark (), GLib.DBusError.ACCESS_DENIED)) {
return;
}

restart_infobar.revealed = true;
var dialog = new Granite.MessageDialog (
_("Can't set system locale"),
e.message,
new ThemedIcon ("preferences-desktop-locale")
) {
badge_icon = new ThemedIcon ("dialog-error"),
modal = true,
transient_for = ((Gtk.Application) Application.get_default ()).active_window
};
dialog.present ();
dialog.response.connect (dialog.destroy);
}
});
}

private class Locale : Object {
Expand Down

0 comments on commit 2b8aa1e

Please sign in to comment.