Skip to content

Commit 2c54ea1

Browse files
committed
Daemon: Implement initial OSK
1 parent 6d0a894 commit 2c54ea1

File tree

6 files changed

+174
-2
lines changed

6 files changed

+174
-2
lines changed

daemon/Main.vala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public class Gala.Daemon.Application : Gtk.Application {
4242
Gtk.init ();
4343

4444
connection.register_object (object_path, new DBus ());
45+
connection.register_object (object_path, new OSKManager ());
4546

4647
return true;
4748
}

daemon/OSK/Keyboard.vala

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2026 elementary, Inc. (https://elementary.io)
3+
* SPDX-License-Identifier: GPL-3.0-or-later
4+
*
5+
* Authored by: Leonhard Kargl <leo.kargl@proton.me>
6+
*/
7+
8+
public class Gala.Daemon.Keyboard : Granite.Bin {
9+
public signal void key_clicked (uint keyval);
10+
11+
construct {
12+
var flowbox = new Gtk.FlowBox () {
13+
min_children_per_line = 12,
14+
};
15+
flowbox.append (create_button (Gdk.Key.A));
16+
flowbox.append (create_button (Gdk.Key.B));
17+
flowbox.append (create_button (Gdk.Key.C));
18+
flowbox.append (create_button (Gdk.Key.D));
19+
flowbox.append (create_button (Gdk.Key.E));
20+
flowbox.append (create_button (Gdk.Key.F));
21+
flowbox.append (create_button (Gdk.Key.G));
22+
flowbox.append (create_button (Gdk.Key.H));
23+
flowbox.append (create_button (Gdk.Key.I));
24+
flowbox.append (create_button (Gdk.Key.J));
25+
flowbox.append (create_button (Gdk.Key.K));
26+
flowbox.append (create_button (Gdk.Key.L));
27+
flowbox.append (create_button (Gdk.Key.M));
28+
flowbox.append (create_button (Gdk.Key.N));
29+
flowbox.append (create_button (Gdk.Key.O));
30+
flowbox.append (create_button (Gdk.Key.P));
31+
flowbox.append (create_button (Gdk.Key.Q));
32+
flowbox.append (create_button (Gdk.Key.R));
33+
flowbox.append (create_button (Gdk.Key.S));
34+
flowbox.append (create_button (Gdk.Key.T));
35+
flowbox.append (create_button (Gdk.Key.U));
36+
flowbox.append (create_button (Gdk.Key.V));
37+
flowbox.append (create_button (Gdk.Key.W));
38+
flowbox.append (create_button (Gdk.Key.X));
39+
flowbox.append (create_button (Gdk.Key.Y));
40+
flowbox.append (create_button (Gdk.Key.Z));
41+
flowbox.append (create_button (Gdk.Key.BackSpace));
42+
flowbox.append (create_button (Gdk.Key.space));
43+
flowbox.append (create_button (Gdk.Key.Escape));
44+
45+
child = flowbox;
46+
}
47+
48+
private Gtk.Button create_button (uint keyval) {
49+
var button = new Gtk.Button.with_label (Gdk.keyval_name (keyval)) {
50+
action_name = OSKWindow.ACTION_PREFIX + OSKWindow.ACTION_KEYVAL_CLICKED,
51+
action_target = keyval
52+
};
53+
return button;
54+
}
55+
}

daemon/OSK/OSKManager.vala

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2026 elementary, Inc. (https://elementary.io)
3+
* SPDX-License-Identifier: GPL-3.0-or-later
4+
*
5+
* Authored by: Leonhard Kargl <leo.kargl@proton.me>
6+
*/
7+
8+
[DBus (name = "io.elementary.OSK")]
9+
public class Gala.Daemon.OSKManager : Object {
10+
public signal void keyval_pressed (uint keyval);
11+
public signal void keyval_released (uint keyval);
12+
13+
private OSKWindow? osk;
14+
15+
public async void set_enabled (bool enabled) throws DBusError, IOError {
16+
if (!enabled) {
17+
osk?.destroy ();
18+
osk = null;
19+
return;
20+
}
21+
22+
osk = new OSKWindow ();
23+
24+
osk.keyval_pressed.connect (on_keyval_pressed);
25+
osk.keyval_released.connect (on_keyval_released);
26+
27+
osk.present ();
28+
}
29+
30+
private void on_keyval_pressed (uint keyval) {
31+
keyval_pressed (keyval);
32+
}
33+
34+
private void on_keyval_released (uint keyval) {
35+
keyval_released (keyval);
36+
}
37+
}

daemon/OSK/OSKWindow.vala

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright 2026 elementary, Inc. (https://elementary.io)
3+
* SPDX-License-Identifier: GPL-3.0-or-later
4+
*
5+
* Authored by: Leonhard Kargl <leo.kargl@proton.me>
6+
*/
7+
8+
public class Gala.Daemon.OSKWindow : Gtk.Window {
9+
public const string ACTION_GROUP_PREFIX = "osk";
10+
public const string ACTION_PREFIX = ACTION_GROUP_PREFIX + ".";
11+
public const string ACTION_KEYVAL_PRESSED = "keyval-pressed";
12+
public const string ACTION_KEYVAL_RELEASED = "keyval-released";
13+
14+
/**
15+
* Convenience for pressed + released
16+
*/
17+
public const string ACTION_KEYVAL_CLICKED = "keyval-clicked";
18+
19+
public signal void keyval_pressed (uint keyval);
20+
public signal void keyval_released (uint keyval);
21+
22+
construct {
23+
var keyboard = new Keyboard ();
24+
25+
child = keyboard;
26+
titlebar = new Gtk.Grid () { visible = false };
27+
title = "OSK";
28+
29+
((Gtk.Widget) this).realize.connect (update_size);
30+
31+
var pressed_action = new SimpleAction (ACTION_KEYVAL_PRESSED, new VariantType ("u"));
32+
pressed_action.activate.connect (on_keyval_pressed);
33+
34+
var released_action = new SimpleAction (ACTION_KEYVAL_RELEASED, new VariantType ("u"));
35+
released_action.activate.connect (on_keyval_released);
36+
37+
var clicked_action = new SimpleAction (ACTION_KEYVAL_CLICKED, new VariantType ("u"));
38+
clicked_action.activate.connect (on_keyval_clicked);
39+
40+
var action_group = new SimpleActionGroup ();
41+
action_group.add_action (pressed_action);
42+
action_group.add_action (released_action);
43+
action_group.add_action (clicked_action);
44+
insert_action_group (ACTION_GROUP_PREFIX, action_group);
45+
}
46+
47+
private void update_size () {
48+
var display = Gdk.Display.get_default ();
49+
var monitor = display.get_monitor_at_surface (get_surface ());
50+
var monitor_geom = monitor.geometry;
51+
52+
default_width = monitor_geom.width;
53+
default_height = monitor_geom.height / 3;
54+
}
55+
56+
private void on_keyval_pressed (SimpleAction action, Variant? parameter) {
57+
uint keyval = parameter.get_uint32 ();
58+
keyval_pressed (keyval);
59+
}
60+
61+
private void on_keyval_released (SimpleAction action, Variant? parameter) {
62+
uint keyval = parameter.get_uint32 ();
63+
keyval_released (keyval);
64+
}
65+
66+
private void on_keyval_clicked (SimpleAction action, Variant? parameter) {
67+
uint keyval = parameter.get_uint32 ();
68+
keyval_pressed (keyval);
69+
keyval_released (keyval);
70+
}
71+
}

daemon/meson.build

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@ gala_daemon_sources = files(
99
'IBus' / 'CandidateArea.vala',
1010
'IBus' / 'CandidateBox.vala',
1111
'IBus' / 'IBusService.vala',
12-
'IBus' / 'IBusCandidateWindow.vala'
12+
'IBus' / 'IBusCandidateWindow.vala',
13+
'OSK' / 'Keyboard.vala',
14+
'OSK' / 'OSKManager.vala',
15+
'OSK' / 'OSKWindow.vala',
1316
)
1417

18+
adw_dep = dependency('libadwaita-1')
1519
gtk4_dep = dependency('gtk4')
1620
granite7_dep = dependency('granite-7')
1721

@@ -21,6 +25,6 @@ executable(
2125
gala_common_enums,
2226
config_header,
2327
gala_resources,
24-
dependencies: [gtk4_dep, granite7_dep, ibus_dep],
28+
dependencies: [adw_dep, gtk4_dep, granite7_dep, ibus_dep],
2529
install: true
2630
)

src/DaemonManager.vala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ public class Gala.DaemonManager : GLib.Object {
8080
case "IBUS_CANDIDATE":
8181
ShellClientsManager.get_instance ().make_ibus_candidate_window (window);
8282
break;
83+
84+
case "OSK":
85+
ShellClientsManager.get_instance ().make_osk_window (window);
86+
break;
8387
}
8488
}
8589

0 commit comments

Comments
 (0)