Skip to content

Commit bf27d5a

Browse files
committed
Add settings-daemon application launcher support
1 parent 901db79 commit bf27d5a

11 files changed

Lines changed: 382 additions & 346 deletions

src/Shortcuts/AppInfo.vala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/* SPDX-License-Identifier: GPL-3.0-or-later
2+
* SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
3+
*/
4+
5+
public struct Keyboard.AppInfo {
6+
public string name;
7+
public string comment;
8+
public string icon;
9+
public string path;
10+
}

src/Shortcuts/Backend/ConflictsManager.vala

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* SPDX-License-Identifier: GPL-2.0-or-later
3-
* SPDX-FileCopyrightText: 2017-2023 elementary, Inc. (https://elementary.io)
3+
* SPDX-FileCopyrightText: 2017-2025 elementary, Inc. (https://elementary.io)
44
*/
55

66
class Keyboard.Shortcuts.ConflictsManager : GLib.Object {
@@ -40,6 +40,19 @@
4040
private static bool custom_shortcut_conflicts (Shortcut shortcut, out string name, out string group) {
4141
name = "";
4242
group = SectionID.CUSTOM.to_string ();
43-
return CustomShortcutSettings.shortcut_conflicts (shortcut, out name, null);
43+
44+
var application_shortcuts = new GLib.Settings (CustomShortcuts.SETTINGS_SCHEMA);
45+
var shortcuts = (CustomShortcuts.ParsedShortcut[]) application_shortcuts.get_value (CustomShortcuts.APPLICATION_SHORTCUTS);
46+
for (int i = 0; i < shortcuts.length; i++) {
47+
for (int j = 0; j < shortcuts[i].keybindings.length; j++) {
48+
var action_shortcut = new Shortcut.parse (shortcuts[i].keybindings[j]);
49+
if (shortcut.is_equal (action_shortcut)) {
50+
name = shortcuts[i].target;
51+
return true;
52+
}
53+
}
54+
}
55+
56+
return false;
4457
}
4558
}

src/Shortcuts/Backend/CustomShortcutSettings.vala

Lines changed: 0 additions & 158 deletions
This file was deleted.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* SPDX-License-Identifier: GPL-2.0-or-later
3+
* SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
4+
*/
5+
6+
namespace Keyboard.Shortcuts.CustomShortcuts {
7+
public enum ActionType {
8+
DESKTOP_FILE,
9+
COMMAND_LINE
10+
}
11+
12+
public struct ParsedShortcut {
13+
ActionType type;
14+
string target;
15+
GLib.HashTable<string, Variant> parameters;
16+
string[] keybindings;
17+
}
18+
19+
public const string SETTINGS_SCHEMA = "io.elementary.settings-daemon.applications";
20+
public const string APPLICATION_SHORTCUTS = "application-shortcuts";
21+
}

src/Shortcuts/Shortcuts.vala

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,6 @@ namespace Keyboard.Shortcuts {
6262
private SwitcherRow custom_shortcuts_row;
6363

6464
construct {
65-
CustomShortcutSettings.init ();
66-
6765
unowned var list = Shortcuts.ShortcutsList.get_default ();
6866

6967
section_switcher = new Gtk.ListBox ();
@@ -113,12 +111,7 @@ namespace Keyboard.Shortcuts {
113111
for (int id = 0; id < SectionID.CUSTOM; id++) {
114112
shortcut_views += new ShortcutListBox ((SectionID) id);
115113
}
116-
117-
if (CustomShortcutSettings.available) {
118-
var custom_tree = new CustomShortcutListBox ();
119-
120-
shortcut_views += custom_tree;
121-
}
114+
shortcut_views += new CustomShortcutListBox ();
122115

123116
foreach (unowned Gtk.Widget view in shortcut_views) {
124117
stack.add_child (view);
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/* SPDX-License-Identifier: GPL-3.0-or-later
2+
* SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
3+
*/
4+
5+
public class Keyboard.AppChooser : Granite.Dialog {
6+
public signal void app_chosen (string path);
7+
public signal void custom_command_chosen (string command);
8+
9+
private Gtk.ListBox list;
10+
private Gtk.SearchEntry search_entry;
11+
private Gtk.Entry custom_entry;
12+
13+
construct {
14+
search_entry = new Gtk.SearchEntry () {
15+
placeholder_text = _("Search Applications")
16+
};
17+
18+
list = new Gtk.ListBox () {
19+
hexpand = true,
20+
vexpand = true
21+
};
22+
list.add_css_class (Granite.STYLE_CLASS_RICH_LIST);
23+
list.set_sort_func (sort_function);
24+
list.set_filter_func (filter_function);
25+
26+
var scrolled = new Gtk.ScrolledWindow () {
27+
child = list
28+
};
29+
30+
var frame = new Gtk.Frame (null) {
31+
child = scrolled
32+
};
33+
34+
custom_entry = new Gtk.Entry () {
35+
placeholder_text = _("Type in a custom command"),
36+
primary_icon_activatable = false,
37+
primary_icon_name = "utilities-terminal-symbolic"
38+
};
39+
40+
var box = new Gtk.Box (VERTICAL, 6);
41+
box.append (search_entry);
42+
box.append (frame);
43+
box.append (custom_entry);
44+
45+
modal = true;
46+
default_height = 500;
47+
default_width = 400;
48+
get_content_area ().append (box);
49+
add_button (_("Cancel"), Gtk.ResponseType.CANCEL);
50+
51+
// TRANSLATORS: This string is used by screen reader
52+
update_property (Gtk.AccessibleProperty.LABEL, _("Select startup app"), -1);
53+
54+
search_entry.grab_focus ();
55+
search_entry.search_changed.connect (() => {
56+
list.invalidate_filter ();
57+
});
58+
59+
response.connect (hide);
60+
61+
list.row_activated.connect (on_app_selected);
62+
custom_entry.activate.connect (on_custom_command_entered);
63+
}
64+
65+
public void init_list (GLib.List<AppInfo?> app_infos) {
66+
foreach (var app_info in app_infos) {
67+
var app_row = new AppChooserRow (app_info);
68+
list.prepend (app_row);
69+
}
70+
}
71+
72+
private int sort_function (Gtk.ListBoxRow row1, Gtk.ListBoxRow row2) {
73+
unowned AppChooserRow row_1 = (AppChooserRow) row1.get_child ();
74+
unowned AppChooserRow row_2 = (AppChooserRow) row2.get_child ();
75+
76+
var name_1 = row_1.app_info.name;
77+
var name_2 = row_2.app_info.name;
78+
79+
return name_1.collate (name_2);
80+
}
81+
82+
private bool filter_function (Gtk.ListBoxRow list_box_row) {
83+
var app_row = (AppChooserRow) list_box_row.get_child ();
84+
return search_entry.text.down () in app_row.app_info.name.down ()
85+
|| search_entry.text.down () in app_row.app_info.comment.down ();
86+
}
87+
88+
private void on_app_selected (Gtk.ListBoxRow list_box_row) {
89+
var app_row = (AppChooserRow) list_box_row.get_child ();
90+
app_chosen (app_row.app_info.path);
91+
hide ();
92+
}
93+
94+
private void on_custom_command_entered () {
95+
custom_command_chosen (custom_entry.text);
96+
hide ();
97+
}
98+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/* SPDX-License-Identifier: GPL-3.0-or-later
2+
* SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
3+
*/
4+
5+
public class Keyboard.AppChooserRow : Gtk.Grid {
6+
public signal void deleted ();
7+
8+
public AppInfo app_info { get; construct; }
9+
10+
public AppChooserRow (AppInfo app_info) {
11+
Object (app_info: app_info);
12+
}
13+
14+
construct {
15+
var image = new Gtk.Image () {
16+
pixel_size = 32
17+
};
18+
19+
var icon_theme = Gtk.IconTheme.get_for_display (Gdk.Display.get_default ());
20+
if (icon_theme.has_icon (app_info.icon)) {
21+
image.gicon = new ThemedIcon (app_info.icon);
22+
} else {
23+
image.gicon = new ThemedIcon ("application-default-icon");
24+
}
25+
26+
var app_name = new Gtk.Label (app_info.name) {
27+
xalign = 0,
28+
ellipsize = Pango.EllipsizeMode.END
29+
};
30+
31+
var app_comment = new Gtk.Label (app_info.comment) {
32+
xalign = 0,
33+
ellipsize = Pango.EllipsizeMode.END
34+
};
35+
app_comment.add_css_class (Granite.STYLE_CLASS_SMALL_LABEL);
36+
37+
column_spacing = 6;
38+
attach (image, 0, 0, 1, 2);
39+
attach (app_name, 1, 0);
40+
attach (app_comment, 1, 1);
41+
}
42+
}

0 commit comments

Comments
 (0)