Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ shared_module(
meson.project_name(),
gresource,
'src/Indicator.vala',
'src/InputSource.vala',
'src/LayoutButton.vala',
'src/LayoutManager.vala',
'src/PopoverWidget.vala',
config_file,
dependencies: [
Expand Down
9 changes: 7 additions & 2 deletions src/Indicator.vala
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,20 @@ public class Keyboard.Indicator : Wingpanel.Indicator {
update_visibility ();
});

popover_widget.updated ();
update_visibility ();

var layout_manager = LayoutManager.get_default ();

layout_manager.input_sources.items_changed.connect (() => {
layouts_revealer.reveal_child = layout_manager.input_sources.n_items > 0 || settings.get_boolean ("always-show-layout");
});
}

return indicator_box;
}

private void update_visibility () {
layouts_icon.label = popover_widget.current_language_code[0:2];
layouts_revealer.reveal_child = popover_widget.has_multiple_layouts () || settings.get_boolean ("always-show-layout");

numlock_revealer.reveal_child = keymap.get_num_lock_state () && settings.get_boolean ("numlock");
capslock_revealer.reveal_child = keymap.get_caps_lock_state () && settings.get_boolean ("capslock");
Expand Down
84 changes: 84 additions & 0 deletions src/InputSource.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright 2017-2025 elementary, Inc. (https://elementary.io)
* SPDX-License-Identifier: GPL-2.0-or-later
*/

/**
* Respresents a keyboard-InputSource according to "org.gnome.desktop.input-sources sources".
* This means that the enum parameter @layout_type equals the first string in the
* tupel of strings, and the @name parameter equals the second string.
*/
public class Keyboard.InputSource : Object {
/**
* Type of a keyboard-InputSource as described in the description of
* "org.gnome.desktop.input-sources sources".
*/
public enum LayoutType {
IBUS,
XKB
}

public LayoutType layout_type { get; construct; }

// Name of input source as stored in settings e.g. "gb" (xkb) or "xkb:gb:extd:eng" (ibus) or "mozc-jp" (ibus)
// These names are used both in org/gnome/desktop/input-sources and desktop/ibus/general/preload-engines
public string name { get; construct; }

private InputSource (LayoutType layout_type, string name) {
Object (
layout_type: layout_type,
name: name
);
}

public static InputSource? new_from_variant (Variant? variant) {
if (!variant.is_of_type (new VariantType ("(ss)"))) {
critical ("Ignoring attempt to create InputSource from invalid VariantType");
return null;
}

unowned string type;
unowned string name;
variant.get ("(&s&s)", out type, out name);

if (name == "") {
critical ("Attempt to create invalid InputSource name %s", name);
return null;
}

if (type == "xkb") {
return new InputSource (LayoutType.XKB, name);
} else if (type == "ibus") {
return new InputSource (LayoutType.IBUS, name);
}

return null;
}

public bool equal (InputSource other) {
return layout_type == other.layout_type && name == other.name;
}

/**
* GSettings saves values in the form of GLib.Variant and this
* function creates a Variant representing this object.
*/
public GLib.Variant to_variant () requires (name != "") {
string type_name = "";
switch (layout_type) {
case LayoutType.IBUS:
type_name = "ibus";
break;
case LayoutType.XKB:
type_name = "xkb";
break;
default:
assert_not_reached ();
}
GLib.Variant first = new GLib.Variant.string (type_name);
GLib.Variant second = new GLib.Variant.string (name);
GLib.Variant result = new GLib.Variant.tuple ({first, second});

return result;
}
}
41 changes: 41 additions & 0 deletions src/LayoutManager.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2025 elementary, Inc. (https://elementary.io)
* SPDX-License-Identifier: LGPL-2.1-or-later
*/

public class Keyboard.LayoutManager : Object {
public GLib.ListStore input_sources { get; private set; }

private static GLib.Once<LayoutManager> layout_manager;
public static LayoutManager get_default () {
return layout_manager.once (() => {
return new LayoutManager ();
});
}

private GLib.Settings settings;

private LayoutManager () {}

construct {
input_sources = new GLib.ListStore (typeof (InputSource));

settings = new Settings ("org.gnome.desktop.input-sources");
settings.changed["sources"].connect (update_sources);
}


private void update_sources () {
input_sources.remove_all ();

var sources = settings.get_value ("sources");
for (size_t i = 0; i < sources.n_children (); i++) {
var input_source = InputSource.new_from_variant (sources.get_child_value (i));

uint pos = -1;
if (!input_sources.find (input_source, out pos)) {
input_sources.append (input_source);
}
}
}
}
7 changes: 3 additions & 4 deletions src/PopoverWidget.vala
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,6 @@ public class Keyboard.Widgets.PopoverWidget : Gtk.Box {

settings = new GLib.Settings ("org.gnome.desktop.input-sources");

settings.changed["sources"].connect (() => {
populate_layouts ();
});

settings.changed["current"].connect_after (() => {
set_active_layout_from_settings (); // Gala will set the keymap if required
updated ();
Expand Down Expand Up @@ -154,6 +150,9 @@ public class Keyboard.Widgets.PopoverWidget : Gtk.Box {

show_all ();

var layout_manager = LayoutManager.get_default ();
layout_manager.input_sources.items_changed.connect (populate_layouts);

populate_layouts ();
}

Expand Down