public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
From: Jocelyn Falempe <jfalempe@redhat.com>
To: git-commits@fedoraproject.org
Subject: [rpms/kmscon] f44: Update to v10.0.1
Date: Thu, 02 Jul 2026 16:23:46 GMT [thread overview]
Message-ID: <178300942664.1.6854664993962553899.rpms-kmscon-48ceef03d3a4@fedoraproject.org> (raw)
A new commit has been pushed.
Repo : rpms/kmscon
Branch : f44
Commit : 48ceef03d3a4a145919b346909c025f159e5328b
Author : Jocelyn Falempe <jfalempe@redhat.com>
Date : 2026-07-02T18:11:21+02:00
Stats : +37/-2883 in 7 file(s)
URL : https://src.fedoraproject.org/rpms/kmscon/c/48ceef03d3a4a145919b346909c025f159e5328b?branch=f44
Log:
Update to v10.0.1
Remove the patches that are now integrated upstream
Add a workaround for agetty on Fedora < 45
---
diff --git a/.gitignore b/.gitignore
index 2c98fba..871b8bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@
/kmscon-9.3.4.tar.gz
/kmscon-9.3.5.tar.gz
/kmscon-10.0.0.tar.gz
+/kmscon-10.0.1.tar.gz
diff --git a/0001-Use-agetty-on-Fedora.patch b/0001-Use-agetty-on-Fedora.patch
deleted file mode 100644
index c1f9097..0000000
--- a/0001-Use-agetty-on-Fedora.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From b4cc9b41306feaa37d600732993929090a73f2e8 Mon Sep 17 00:00:00 2001
-From: Stephen Gallagher <sgallagh@redhat.com>
-Date: Fri, 5 Jun 2026 09:46:55 -0400
-Subject: [PATCH] Use agetty on Fedora
-
-The upstream kmscon support for /usr/lib/issue.d is lacking and we need
-this for Fedora Server and Fedora ELN to inform the user of the Cockpit
-console address.
-
-Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
----
- scripts/systemd/kmsconvt@.service.in | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/scripts/systemd/kmsconvt@.service.in b/scripts/systemd/kmsconvt@.service.in
-index f86e5a9bb3de9d665e01dccfbb6ff551ccdd96ab..152bac2fbcaccc4c5f9c3b452b55458aa4645334 100644
---- a/scripts/systemd/kmsconvt@.service.in
-+++ b/scripts/systemd/kmsconvt@.service.in
-@@ -39,7 +39,7 @@ ConditionPathExists=/dev/tty0
-
- [Service]
- @PAM_CFG@
--ExecStart=kmscon --vt=%I --no-switchvt
-+ExecStart=kmscon --vt=%I --no-switchvt --no-issue --login -- /usr/bin/agetty -o '-p -- \\u' --noclear -- - $$TERM
- UtmpIdentifier=%I
- TTYPath=/dev/%I
- TTYReset=yes
---
-2.54.0
-
diff --git a/0001-seat-Fix-seat-startup-in-background.patch b/0001-seat-Fix-seat-startup-in-background.patch
deleted file mode 100644
index bf7359f..0000000
--- a/0001-seat-Fix-seat-startup-in-background.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From 087ded3ac1ef932e73fd0f1fb47a8d49c4404a67 Mon Sep 17 00:00:00 2001
-From: Jocelyn Falempe <jfalempe@redhat.com>
-Date: Tue, 9 Jun 2026 14:38:44 +0200
-Subject: [PATCH] seat: Fix seat startup in background
-
-If VT 2 is active, and you run systemctl restart kmsconvt@tty3
-
-Then the session will try to directly take the GPU, and fails.
-So don't awake the seat on startup, but wait for the tty be be activated.
-
-Fix: 0dffbd7 session: Simplify session management
-Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
----
- src/kmscon_seat.c | 2 --
- 1 file changed, 2 deletions(-)
-
-diff --git a/src/kmscon_seat.c b/src/kmscon_seat.c
-index 91b8db8..7dd13de 100644
---- a/src/kmscon_seat.c
-+++ b/src/kmscon_seat.c
-@@ -1101,8 +1101,6 @@ void kmscon_seat_startup(struct kmscon_seat *seat)
- if (!seat)
- return;
-
-- seat_go_awake(seat);
--
- s = kmscon_seat_new_session(seat);
- if (s)
- seat_switch(seat, s);
---
-2.54.0
-
diff --git a/Workaround-agetty-issue-file-on-Fedora.patch b/Workaround-agetty-issue-file-on-Fedora.patch
new file mode 100644
index 0000000..1e1b5fa
--- /dev/null
+++ b/Workaround-agetty-issue-file-on-Fedora.patch
@@ -0,0 +1,30 @@
+From e71a2064bc8a8917127cc74c983df28aebd82159 Mon Sep 17 00:00:00 2001
+From: Jocelyn Falempe <jfalempe@redhat.com>
+Date: Thu, 2 Jul 2026 17:58:30 +0200
+Subject: [PATCH] Workaround agetty issue-file on Fedora
+
+Fedora's version of agetty doesn't handle properly when /etc/issue is a
+symbolic link to /usr/lib/issue. So specify the issue-file to avoid
+printing the issue message twice.
+
+Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
+---
+ scripts/systemd/kmsconvt@.service.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/scripts/systemd/kmsconvt@.service.in b/scripts/systemd/kmsconvt@.service.in
+index 9762fc1..f166f94 100644
+--- a/scripts/systemd/kmsconvt@.service.in
++++ b/scripts/systemd/kmsconvt@.service.in
+@@ -39,7 +39,7 @@ ConditionPathExists=/dev/tty0
+
+ [Service]
+ @PAM_CFG@
+-ExecStart=kmscon --vt=%I --no-switchvt --login -- /sbin/agetty -8 -o '-p -- \\u' --noclear -- - $$TERM
++ExecStart=kmscon --vt=%I --no-switchvt --login -- /sbin/agetty -8 -o '-p -- \\u' --noclear --issue-file=/etc/issue:/etc/issue.d:/run/issue.d:/usr/lib/issue.d -- - $$TERM
+ UtmpIdentifier=%I
+ TTYPath=/dev/%I
+ TTYReset=yes
+--
+2.54.0
+
diff --git a/kmscon.spec b/kmscon.spec
index 33029c6..4f9ff79 100644
--- a/kmscon.spec
+++ b/kmscon.spec
@@ -1,5 +1,5 @@
Name: kmscon
-Version: 10.0.0
+Version: 10.0.1
Release: %autorelease
Summary: Linux KMS/DRM based virtual Console Emulator
License: MIT
@@ -7,7 +7,7 @@ URL: https://github.com/kmscon/kmscon/
Source: %{url}/archive/v%{version}/%{name}-%{version}.tar.gz
BuildRequires: check-devel
BuildRequires: docbook-style-xsl
-BuildRequires: libtsm-devel >= 4.5.0
+BuildRequires: libtsm-devel >= 4.6.0
BuildRequires: meson
BuildRequires: ncurses
BuildRequires: gcc
@@ -29,16 +29,9 @@ BuildRequires: pkgconfig(systemd)
BuildRequires: pkgconfig(xkbcommon) >= 0.5.0
BuildRequires: pkgconfig(zlib)
-Patch1: localectl_support.patch
-
-# Fix background startup:
-Patch2: 0001-seat-Fix-seat-startup-in-background.patch
-
-# Temporary downstream patch until kmscon natively supports /usr/lib/issue.d
-# This is needed by Fedora Server and Fedora ELN to display the Cockpit
-# console URL at the login prompt.
-# See https://github.com/kmscon/kmscon/issues/407 for more details
-Patch10: 0001-Use-agetty-on-Fedora.patch
+# agetty version on Fedora < 45 prints the /etc/issue file twice
+# without this workaround
+Patch: Workaround-agetty-issue-file-on-Fedora.patch
%description
Kmscon is a simple terminal emulator based on linux kernel mode setting (KMS).
diff --git a/localectl_support.patch b/localectl_support.patch
deleted file mode 100644
index 3fd517d..0000000
--- a/localectl_support.patch
+++ /dev/null
@@ -1,2807 +0,0 @@
-From 519a57b8546977d0378ac491065797d3040f914a Mon Sep 17 00:00:00 2001
-From: Jocelyn Falempe <jfalempe@redhat.com>
-Date: Fri, 5 Jun 2026 12:08:56 +0200
-Subject: [PATCH] Squashed commit of the following:
-
-commit 21a7f41266a881169609452d3d3d7623c10404ae
-Author: Jocelyn Falempe <jfalempe@redhat.com>
-Date: Fri Jun 5 11:11:42 2026 +0200
-
- dbus: Listen to locale1 property changes
-
- And update the keyboard layout accordingly.
-
- Don't listen to locale1 property changes if the keyboard layout was
- set in the config file or in command line argument.
-
- This allows to use `localectl set-keymap` to change the keyboard
- layout at runtime.
- One difference from "loadkeys" is that this is a system-wide setting,
- and that it will affect all kmscon instance on all tty.
-
- Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
-
-commit 99b5e7e840035f9f6a437cb4d1c506be085cbd92
-Author: Jocelyn Falempe <jfalempe@redhat.com>
-Date: Fri Jun 5 10:48:21 2026 +0200
-
- conf: Use NULL for default xkb config variable
-
- This better fit libxkbcommon API
- Remove the workaround in input, as it's no longer necessary.
-
- Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
-
-commit 3010008c5d810a794b47e38befbd780f406c4904
-Author: Jocelyn Falempe <jfalempe@redhat.com>
-Date: Fri Jun 5 10:22:01 2026 +0200
-
- input: Add input_update_keymap() to change the keymap at runtime
-
- Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
-
-commit d716d72cae6331e681a0f0a37dfa4ad2cc49366d
-Author: Jocelyn Falempe <jfalempe@redhat.com>
-Date: Fri Jun 5 10:16:09 2026 +0200
-
- input: split keyboard layout and compose initialization
-
- Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
-
-commit 0dffbd7a27db7f23806cfab0ecd5369e5f7b15ca
-Author: Jocelyn Falempe <jfalempe@redhat.com>
-Date: Thu Jun 4 00:38:20 2026 +0200
-
- session: Simplify session management
-
- Directly switch from one session to another.
-
- Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
-
-commit fa42d6d0adf806a05349efedceaa801df77aca6d
-Author: Jocelyn Falempe <jfalempe@redhat.com>
-Date: Wed Jun 3 17:37:47 2026 +0200
-
- terminal: pass directly the seat input, conf, name and eloop
-
- This avoid to use kmscon_seat_get_xxx() for each.
-
- Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
-
-commit 21011b1561c9199fdae2a1566d27e43b67bcc0b6
-Author: Jocelyn Falempe <jfalempe@redhat.com>
-Date: Wed Jun 3 16:24:24 2026 +0200
-
- session: Remove session callback
-
- As terminal sessions are the only session available, remove the
- callbacks, and call directly the corresponding terminal functions.
-
- Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
-
-commit 12c1072d254e6b04819850630def9028e0cf8d19
-Author: Jocelyn Falempe <jfalempe@redhat.com>
-Date: Wed Jun 3 12:26:13 2026 +0200
-
- dummy_session: Remove dummy sessions
-
- Kmscon wanted to provide different type of session, but only the
- terminal session is used.
- Dummy session is just a black screen, so has no real usage.
-
- Let's focus on terminal sessions, and remove the dummy session.
-
- Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
-
-commit a6e78153a5690659d99e587fe770eca4b56d09ad
-Author: Jocelyn Falempe <jfalempe@redhat.com>
-Date: Mon Jun 1 23:41:32 2026 +0200
-
- Remove startup script, as it is no more necessary
-
- kmscon now retrieve xkb keyboard configuration directly form dbus,
- so there is no need for the startup script.
-
- Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
-
-commit 06bb7413292d7c556ffc817bc3075c3c3c96fb0c
-Author: Jocelyn Falempe <jfalempe@redhat.com>
-Date: Thu May 21 18:09:51 2026 +0200
-
- Use libdbus directly to get locale
-
- Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
-
-commit 84501684db7dda606209c4c7ae04f7e66d964809
-Author: Fabian Vogt <fvogt@suse.de>
-Date: Tue Jun 2 12:31:05 2026 +0200
-
- freetype: Enable light hinting
-
- Not hinting at all results in blurry edges, especially visible with straight
- lines in common characters such as "-[]".
-
- Light hinting in FreeType has the nice property that it only tries to
- align edges vertically, so the width of glyphs does not change, preserving
- monospaceness.
-
-commit d789d1c3517d997f1271a38b4594c29898eaf199
-Author: Fabian Vogt <fvogt@suse.de>
-Date: Mon Jun 1 17:03:47 2026 +0200
-
- Define default issue search path in a single place
-
- It was hardcoded in four different places, of which only one has an actual
- effect. Consolidate it.
-
-commit 44c0df12ff202eb84394ea0c8e059894563fe501
-Author: Adam Duskett <adam.duskett@amarulasolutions.com>
-Date: Thu May 21 16:24:23 2026 +0200
-
- fix zlib cross-compiling errors
-
- zlib compression was introduced in version 9.3.3. However, when
- cross-compiling kmscon for an architecture other than x86_64, the
- genunifont executable tries to use the build-systems zlib instead
- of the hosts zlib.
-
- This leads to the following error during compiling:
- libz.so: error adding symbols: file in wrong format
-
- Fix this by adding a new native zlib dependency specifically for the
- genunifont executable.
----
- README.md | 2 -
- docs/man/kmscon.1.xml.in | 29 +-
- docs/man/kmscon.conf.5.xml.in | 14 -
- meson.build | 10 +-
- meson.options | 8 +-
- scripts/etc/kmscon.conf.example | 1 -
- scripts/kmscon.in | 63 ----
- src/dbus.c | 368 +++++++++++++++++++
- src/{kmscon_dummy.h => dbus.h} | 53 +--
- src/font/font_freetype.c | 4 +-
- src/font/meson.build | 4 +-
- src/input/input.c | 60 +++-
- src/input/input.h | 7 +-
- src/input/input_internal.h | 10 +-
- src/input/input_uxkb.c | 33 +-
- src/kmscon_conf.c | 26 +-
- src/kmscon_conf.h | 4 -
- src/kmscon_dummy.c | 154 --------
- src/kmscon_issue.c | 10 -
- src/kmscon_issue.h | 9 +
- src/kmscon_main.c | 33 ++
- src/kmscon_seat.c | 602 +++++++-------------------------
- src/kmscon_seat.h | 41 +--
- src/kmscon_terminal.c | 98 ++----
- src/kmscon_terminal.h | 34 +-
- src/meson.build | 25 +-
- src/shl/dlist.h | 10 +
- tests/test_input.c | 7 +-
- 28 files changed, 751 insertions(+), 968 deletions(-)
- delete mode 100755 scripts/kmscon.in
- create mode 100644 src/dbus.c
- rename src/{kmscon_dummy.h => dbus.h} (50%)
- delete mode 100644 src/kmscon_dummy.c
-
-diff --git a/README.md b/README.md
-index 8675413..3bf4912 100644
---- a/README.md
-+++ b/README.md
-@@ -82,8 +82,6 @@ explicitly enable it via command line:
- |`font_freetype`| `auto` | Freetype2 based scalable font renderer, also handle bitmap fonts |
- |`font_pango`| `auto` | Pango based scalable font renderer |
- |`renderer_gltex`| `auto` | OpenGLESv2 accelerated renderer |
--|`session_dummy`| `auto` | Dummy fallback session |
--|`session_terminal`| `auto` | Terminal-emulator sessions |
- |`docs`|`auto`| Build manpages and documentation |
-
-
-diff --git a/docs/man/kmscon.1.xml.in b/docs/man/kmscon.1.xml.in
-index 0538186..25cf29a 100644
---- a/docs/man/kmscon.1.xml.in
-+++ b/docs/man/kmscon.1.xml.in
-@@ -187,14 +187,6 @@
- sessions via keyboard input. (default: off)</para>
- </listitem>
- </varlistentry>
--
-- <varlistentry>
-- <term><option>--terminal-session</option></term>
-- <listitem>
-- <para>Start a terminal session after setup is done.
-- (default: on)</para>
-- </listitem>
-- </varlistentry>
- </variablelist>
-
- <para>Terminal Options:</para>
-@@ -463,14 +455,6 @@
- </listitem>
- </varlistentry>
-
-- <varlistentry>
-- <term><option>--grab-session-dummy {grab}</option></term>
-- <listitem>
-- <para>Switch to a dummy session (blank screen).
-- (default: <Ctrl><Logo>Escape)</para>
-- </listitem>
-- </varlistentry>
--
- <varlistentry>
- <term><option>--grab-session-close {grab}</option></term>
- <listitem>
-@@ -886,16 +870,11 @@
- <refsect1>
- <title>Sessions</title>
- <para>If KMSCON is active on a seat, the internal session-manager is woken
-- up. At most times, only the terminal-session is active, but KMSCON can
-- also support any other session type. You can switch between sessions
-- with keyboard-shortcuts and you can create/destroy sessions during
-- runtime.</para>
--
-- <para>Dummy sessions simply show a black screen and are used if no other
-- session is available. Otherwise, dummy sessions are hidden from the
-- user so they cannot switch to it.</para>
-+ up. At most times, only the terminal-session is active. You can switch
-+ between sessions with keyboard-shortcuts and you can create/destroy
-+ terminal sessions during runtime.</para>
-
-- <para>Terminal sessions provide a terminal emulator. They are the main
-+ <para>Terminal sessions provide a terminal emulator. They are the only
- session type and provide all the terminal-emulation
- functionality.</para>
- </refsect1>
-diff --git a/docs/man/kmscon.conf.5.xml.in b/docs/man/kmscon.conf.5.xml.in
-index dca056d..8af4580 100644
---- a/docs/man/kmscon.conf.5.xml.in
-+++ b/docs/man/kmscon.conf.5.xml.in
-@@ -161,13 +161,6 @@ font-name=Ubuntu Mono
- </listitem>
- </varlistentry>
-
-- <varlistentry>
-- <term><option>terminal-session</option></term>
-- <listitem>
-- <para>Enable terminal session. (default: on)</para>
-- </listitem>
-- </varlistentry>
--
- <varlistentry>
- <term><option>login</option></term>
- <listitem>
-@@ -368,13 +361,6 @@ font-name=Ubuntu Mono
- </listitem>
- </varlistentry>
-
-- <varlistentry>
-- <term><option>grab-session-dummy</option></term>
-- <listitem>
-- <para>Switch to dummy session. (default: <Ctrl><Logo>Escape)</para>
-- </listitem>
-- </varlistentry>
--
- <varlistentry>
- <term><option>grab-session-close</option></term>
- <listitem>
-diff --git a/meson.build b/meson.build
-index de89d72..1aa72f2 100644
---- a/meson.build
-+++ b/meson.build
-@@ -53,6 +53,7 @@ libudev_deps = dependency('libudev', version: '>=172')
- dl_deps = dependency('dl')
- threads_deps = dependency('threads')
- zlib_deps = dependency('zlib')
-+zlib_deps_native = dependency('zlib', native: true)
-
- python = find_program('python3')
-
-@@ -75,6 +76,7 @@ glesv2_deps = dependency('glesv2', disabler: true, required: require_glesv2)
- pango_deps = dependency('pangoft2', disabler: true, required: get_option('font_pango'))
- freetype_deps = dependency('freetype2', disabler: true, required: get_option('font_freetype'))
- fontconfig_deps = dependency('fontconfig', disabler: true, required: get_option('font_freetype'))
-+dbus_deps = dependency('dbus-1', disabler: true, required: get_option('dbus'))
- xsltproc = find_program('xsltproc', native: true, disabler: true, required: get_option('docs'))
- check_deps = dependency('check', disabler: true, required: get_option('tests'))
- tic = find_program('tic', required: false)
-@@ -89,7 +91,6 @@ sections = {
- 'video': 'Video Backends',
- 'font': 'Font Backends',
- 'renderer': 'Renderers',
-- 'session': 'Session Types',
- }
- config = configuration_data()
- # Note: keep this in sync with the dependencies above
-@@ -102,8 +103,7 @@ foreach name, reqs : {
- 'font_unifont': [],
- 'font_freetype': [freetype_deps, fontconfig_deps],
- 'font_pango': [pango_deps],
-- 'session_dummy': [],
-- 'session_terminal': [],
-+ 'dbus': [dbus_deps],
- }
- found = true
- foreach req : reqs
-@@ -195,10 +195,6 @@ else
- dirs_info.set('PAM_CFG', '')
- endif
- foreach filename, kwargs : {
-- 'scripts/kmscon.in': {
-- 'install_dir': bindir,
-- 'install_mode': 'rwxr-xr-x',
-- },
- 'scripts/kmscon-launch-gui.sh': {
- 'install_dir': bindir,
- 'install_mode': 'rwxr-xr-x',
-diff --git a/meson.options b/meson.options
-index 5cafa60..afa5b32 100644
---- a/meson.options
-+++ b/meson.options
-@@ -29,8 +29,6 @@ option('font_freetype', type: 'feature', value: 'auto',
- option('font_pango', type: 'feature', value: 'auto',
- description: 'pango font backend')
-
--# kmscon sessions
--option('session_dummy', type: 'feature', value: 'auto',
-- description: 'dummy session')
--option('session_terminal', type: 'feature', value: 'auto',
-- description: 'terminal session')
-+# dbus integration
-+option('dbus', type: 'feature', value: 'auto',
-+ description: 'dbus integration')
-diff --git a/scripts/etc/kmscon.conf.example b/scripts/etc/kmscon.conf.example
-index ca2232e..be45a4a 100644
---- a/scripts/etc/kmscon.conf.example
-+++ b/scripts/etc/kmscon.conf.example
-@@ -66,7 +66,6 @@
- #grab-zoom-out=<Ctrl>Minus
- #grab-session-next=<Ctrl><Logo>Right
- #grab-session-prev=<Ctrl><Logo>Left
--#grab-session-dummy=<Ctrl><Logo>Escape
- #grab-session-close=<Ctrl><Logo>BackSpace
- #grab-terminal-new=<Ctrl><Logo>Return
- #grab-rotate-cw=<Logo>Plus
-diff --git a/scripts/kmscon.in b/scripts/kmscon.in
-deleted file mode 100755
-index 6545399..0000000
---- a/scripts/kmscon.in
-+++ /dev/null
-@@ -1,63 +0,0 @@
--#!/bin/sh
--#
--# Copyright (c) 2018 Aetf <aetf@unlimitedcodeworks.xyz>
--# Copyright (c) 2018 Fabian Vogt <fvogt@suse.com>
--#
--# Permission is hereby granted, free of charge, to any person obtaining a copy
--# of this software and associated documentation files (the "Software"), to deal
--# in the Software without restriction, including without limitation the rights
--# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
--# copies of the Software, and to permit persons to whom the Software is
--# furnished to do so, subject to the following conditions:
--#
--# The above copyright notice and this permission notice shall be included in all
--# copies or substantial portions of the Software.
--#
--# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
--# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
--# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
--# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
--# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
--# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
--# SOFTWARE.
--
--# configuration path
--helperdir=@libexecdir@
--
--# Get a property from org.freedesktop.locale1
--queryLocaledbus() {
-- dbus-send --system --print-reply=literal --dest=org.freedesktop.locale1 /org/freedesktop/locale1 org.freedesktop.DBus.Properties.Get "string:org.freedesktop.locale1" "string:X11$1" 2>/dev/null | awk '{print $2}'
--}
--
--queryLocalectl() {
-- localectl status | awk "/X11 $1/ {print \$3}"
--}
--
--# Query and setup system locale settings before start kmscon
--setupLocale() {
-- # Don't override existing values. Also there is no point in setting only some of them
-- # as then they would not match anymore.
-- if test -n "${XKB_DEFAULT_MODEL}" -o -n "${XKB_DEFAULT_LAYOUT}" -o -n "${XKB_DEFAULT_VARIANT}" -o -n "${XKB_DEFAULT_OPTIONS}"; then
-- return
-- fi
--
-- if command -v dbus-send >/dev/null 2>/dev/null; then
-- querycmd="queryLocaledbus"
-- elif command -v localectl >/dev/null 2>/dev/null; then
-- querycmd="queryLocalectl"
-- else
-- return
-- fi
--
-- X11MODEL="$(${querycmd} Model)"
-- X11LAYOUT="$(${querycmd} Layout)"
-- X11VARIANT="$(${querycmd} Variant)"
-- X11OPTIONS="$(${querycmd} Options)"
-- [ -n "${X11MODEL}" ] && export XKB_DEFAULT_MODEL="${X11MODEL}"
-- [ -n "${X11LAYOUT}" ] && export XKB_DEFAULT_LAYOUT="${X11LAYOUT}"
-- [ -n "${X11VARIANT}" ] && export XKB_DEFAULT_VARIANT="${X11VARIANT}"
-- [ -n "${X11OPTIONS}" ] && export XKB_DEFAULT_OPTIONS="${X11OPTIONS}"
--}
--
--setupLocale
--exec ${helperdir}/kmscon "$@"
-diff --git a/src/dbus.c b/src/dbus.c
-new file mode 100644
-index 0000000..84c467d
---- /dev/null
-+++ b/src/dbus.c
-@@ -0,0 +1,368 @@
-+/*
-+ * dbus - D-Bus support
-+ *
-+ * Copyright (c) 2026 Red Hat.
-+ * Author: Jocelyn Falempe <jfalempe@redhat.com>
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining
-+ * a copy of this software and associated documentation files
-+ * (the "Software"), to deal in the Software without restriction, including
-+ * without limitation the rights to use, copy, modify, merge, publish,
-+ * distribute, sublicense, and/or sell copies of the Software, and to
-+ * permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ *
-+ * The above copyright notice and this permission notice shall be included
-+ * in all copies or substantial portions of the Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#include <dbus/dbus.h>
-+#include <errno.h>
-+#include <stdlib.h>
-+#include <string.h>
-+
-+#include "dbus.h"
-+#include "shl/eloop.h"
-+#include "shl/log.h"
-+
-+#define LOG_SUBSYSTEM "dbus"
-+
-+struct rmlvo {
-+ const char *model;
-+ const char *layout;
-+ const char *variant;
-+ const char *options;
-+};
-+
-+struct kmscon_dbus {
-+ DBusConnection *conn;
-+ struct ev_eloop *eloop;
-+ struct ev_fd *watch_fd;
-+ dbus_update_xkb_layout_cb cb;
-+ void *data;
-+};
-+
-+static void set_env_from_locale1_properties(DBusConnection *conn, const char *property_name,
-+ const char *env_name)
-+{
-+ DBusError error;
-+ DBusMessage *msg;
-+ DBusMessage *reply;
-+ DBusMessageIter args, variant_iter;
-+ const char *interface_name = "org.freedesktop.locale1";
-+ char *value = NULL;
-+
-+ dbus_error_init(&error);
-+
-+ msg = dbus_message_new_method_call("org.freedesktop.locale1", "/org/freedesktop/locale1",
-+ "org.freedesktop.DBus.Properties", "Get");
-+ if (!msg)
-+ return;
-+
-+ dbus_message_iter_init_append(msg, &args);
-+ if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &interface_name) ||
-+ !dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &property_name)) {
-+ dbus_message_unref(msg);
-+ return;
-+ }
-+
-+ reply = dbus_connection_send_with_reply_and_block(conn, msg, 2000, &error);
-+ dbus_message_unref(msg);
-+
-+ if (dbus_error_has_name(&error, DBUS_ERROR_UNKNOWN_INTERFACE) ||
-+ dbus_error_has_name(&error, DBUS_ERROR_UNKNOWN_PROPERTY)) {
-+ /* This is normal if the interface is not supported by the system */
-+ dbus_error_free(&error);
-+ return;
-+ } else if (dbus_error_is_set(&error)) {
-+ log_warning("dbus error: %s / %s", error.name, error.message);
-+ dbus_error_free(&error);
-+ return;
-+ } else if (!reply) {
-+ log_warning("no reply from dbus");
-+ return;
-+ }
-+
-+ if (!dbus_message_iter_init(reply, &args)) {
-+ log_debug("Reply message has no arguments.\n");
-+ } else if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_VARIANT) {
-+ log_debug("Reply argument is not a variant.\n");
-+ } else {
-+ dbus_message_iter_recurse(&args, &variant_iter);
-+
-+ if (dbus_message_iter_get_arg_type(&variant_iter) == DBUS_TYPE_STRING) {
-+ dbus_message_iter_get_basic(&variant_iter, &value);
-+ if (strlen(value) > 0) {
-+ setenv(env_name, value, 0);
-+ log_debug("Set %s to %s\n", env_name, value);
-+ }
-+ } else {
-+ log_debug("Unexpected inner data type in variant.\n");
-+ }
-+ }
-+
-+ dbus_message_unref(reply);
-+ return;
-+}
-+
-+static bool is_xkb_env_set(void)
-+{
-+ return getenv("XKB_DEFAULT_MODEL") || getenv("XKB_DEFAULT_LAYOUT") ||
-+ getenv("XKB_DEFAULT_VARIANT") || getenv("XKB_DEFAULT_OPTIONS");
-+}
-+
-+/* This is called once at startup to set the XKB environment variables from the locale1 properties.
-+ */
-+void kmscon_dbus_set_xkb_env_from_locale1(struct kmscon_dbus *dbus)
-+{
-+ DBusError error;
-+
-+ if (is_xkb_env_set())
-+ return;
-+
-+ dbus_error_init(&error);
-+
-+ set_env_from_locale1_properties(dbus->conn, "X11Model", "XKB_DEFAULT_MODEL");
-+ set_env_from_locale1_properties(dbus->conn, "X11Layout", "XKB_DEFAULT_LAYOUT");
-+ set_env_from_locale1_properties(dbus->conn, "X11Variant", "XKB_DEFAULT_VARIANT");
-+ set_env_from_locale1_properties(dbus->conn, "X11Options", "XKB_DEFAULT_OPTIONS");
-+}
-+
-+struct kmscon_dbus *kmscon_dbus_new(struct ev_eloop *eloop)
-+{
-+ struct kmscon_dbus *dbus;
-+ DBusError error;
-+
-+ dbus = malloc(sizeof(*dbus));
-+ if (!dbus)
-+ return NULL;
-+ memset(dbus, 0, sizeof(*dbus));
-+
-+ dbus->eloop = eloop;
-+
-+ dbus_error_init(&error);
-+ dbus->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
-+ if (dbus_error_is_set(&error)) {
-+ log_debug("Connection Error: %s\n", error.message);
-+ dbus_error_free(&error);
-+ return NULL;
-+ }
-+ return dbus;
-+}
-+
-+void kmscon_dbus_free(struct kmscon_dbus *dbus)
-+{
-+ if (!dbus)
-+ return;
-+ dbus_connection_unref(dbus->conn);
-+ free(dbus);
-+}
-+
-+static void set_rmlvo_property(struct rmlvo *rmlvo, const char *property_name,
-+ const char *property_value)
-+{
-+ if (!strcmp(property_name, "X11Model")) {
-+ rmlvo->model = property_value;
-+ } else if (!strcmp(property_name, "X11Layout")) {
-+ rmlvo->layout = property_value;
-+ } else if (!strcmp(property_name, "X11Variant")) {
-+ rmlvo->variant = property_value;
-+ } else if (!strcmp(property_name, "X11Options")) {
-+ rmlvo->options = property_value;
-+ }
-+}
-+
-+/* Parse the locale1 properties changed message and update the rmlvo struct */
-+void parse_locale_properties(DBusMessage *msg, struct rmlvo *rmlvo)
-+{
-+ DBusMessageIter root_iter;
-+ DBusMessageIter dict_iter;
-+ DBusMessageIter entry_iter;
-+ DBusMessageIter variant_iter;
-+ char *property_name;
-+ char *property_value;
-+
-+ if (!dbus_message_iter_init(msg, &root_iter)) {
-+ log_debug("Message has no arguments.\n");
-+ return;
-+ }
-+
-+ dbus_message_iter_next(&root_iter);
-+ if (dbus_message_iter_get_arg_type(&root_iter) != DBUS_TYPE_ARRAY) {
-+ log_debug("Not the container type we expect\n");
-+ return;
-+ }
-+
-+ dbus_message_iter_recurse(&root_iter, &dict_iter);
-+ while (dbus_message_iter_get_arg_type(&dict_iter) == DBUS_TYPE_DICT_ENTRY) {
-+
-+ dbus_message_iter_recurse(&dict_iter, &entry_iter);
-+
-+ dbus_message_iter_get_basic(&entry_iter, &property_name);
-+
-+ dbus_message_iter_next(&entry_iter);
-+
-+ if (dbus_message_iter_get_arg_type(&entry_iter) == DBUS_TYPE_VARIANT) {
-+
-+ dbus_message_iter_recurse(&entry_iter, &variant_iter);
-+
-+ if (dbus_message_iter_get_arg_type(&variant_iter) == DBUS_TYPE_STRING) {
-+ dbus_message_iter_get_basic(&variant_iter, &property_value);
-+ set_rmlvo_property(rmlvo, property_name, property_value);
-+ log_debug("property %s: %s\n", property_name, property_value);
-+ }
-+ }
-+ dbus_message_iter_next(&dict_iter);
-+ }
-+}
-+
-+static void handle_dispatch_status(DBusConnection *conn, DBusDispatchStatus status, void *data)
-+{
-+ struct kmscon_dbus *dbus = data;
-+ struct rmlvo rmlvo = {NULL, NULL, NULL, NULL};
-+
-+ if (status == DBUS_DISPATCH_DATA_REMAINS) {
-+ DBusMessage *msg = dbus_connection_pop_message(dbus->conn);
-+ if (msg) {
-+ log_debug("Received message %s\n", dbus_message_get_signature(msg));
-+ if (dbus_message_is_signal(msg, "org.freedesktop.DBus.Properties",
-+ "PropertiesChanged")) {
-+ parse_locale_properties(msg, &rmlvo);
-+ if (dbus->cb)
-+ dbus->cb(rmlvo.model, rmlvo.layout, rmlvo.variant,
-+ rmlvo.options, dbus->data);
-+ }
-+ dbus_message_unref(msg);
-+ }
-+ }
-+}
-+
-+static void locale1_properties_changed(struct ev_fd *fd, int mask, void *data)
-+{
-+ struct DBusWatch *watch = data;
-+ struct kmscon_dbus *dbus = dbus_watch_get_data(watch);
-+
-+ unsigned int flags = 0;
-+
-+ log_debug("locale1 property changed\n");
-+
-+ if (mask & EV_READABLE)
-+ flags |= DBUS_WATCH_READABLE;
-+ if (mask & EV_WRITEABLE)
-+ flags |= DBUS_WATCH_WRITABLE;
-+
-+ dbus_watch_handle(watch, flags);
-+
-+ while (dbus_connection_get_dispatch_status(dbus->conn) == DBUS_DISPATCH_DATA_REMAINS) {
-+ dbus_connection_dispatch(dbus->conn);
-+ // DBUS-1 API is a pain, but at least that works for this simple use case
-+ handle_dispatch_status(dbus->conn, DBUS_DISPATCH_DATA_REMAINS, dbus);
-+ }
-+}
-+
-+/* Only register one read watch, as we're not interested in writes */
-+static unsigned int dbus_add_watch(DBusWatch *watch, void *data)
-+{
-+ struct kmscon_dbus *dbus = data;
-+ int fd = dbus_watch_get_unix_fd(watch);
-+ unsigned int flags = dbus_watch_get_flags(watch);
-+ unsigned int ev_flags = 0;
-+ int ret = 0;
-+
-+ log_debug("Adding watch for fd %d with flags %d %p %d\n", fd, flags, watch,
-+ dbus_watch_get_enabled(watch));
-+
-+ if (!dbus_watch_get_enabled(watch))
-+ return TRUE;
-+
-+ if (dbus->watch_fd) {
-+ log_warning("dbus watch already registered");
-+ return TRUE;
-+ }
-+ if (flags & DBUS_WATCH_WRITABLE)
-+ ev_flags |= EV_WRITEABLE;
-+ if (flags & DBUS_WATCH_READABLE)
-+ ev_flags |= EV_READABLE;
-+
-+ ret = ev_eloop_new_fd(dbus->eloop, &dbus->watch_fd, fd, ev_flags,
-+ locale1_properties_changed, watch);
-+
-+ dbus_watch_set_data(watch, dbus, NULL);
-+
-+ if (ret)
-+ log_error("cannot add watch for fd %d: %d %d %p", fd, ret, ev_flags, watch);
-+ return TRUE;
-+}
-+
-+static void dbus_remove_watch(DBusWatch *watch, void *data)
-+{
-+ struct kmscon_dbus *dbus = data;
-+ log_debug("Removing watch for fd %d\n", dbus_watch_get_unix_fd(watch));
-+
-+ if (dbus_watch_get_data(watch) != dbus)
-+ return;
-+
-+ ev_eloop_rm_fd(dbus->watch_fd);
-+ dbus->watch_fd = NULL;
-+ dbus_watch_set_data(watch, NULL, NULL);
-+ return;
-+}
-+
-+static void dbus_toggle_watch(DBusWatch *watch, void *data)
-+{
-+ log_debug("Toggling watch for fd %d\n", dbus_watch_get_unix_fd(watch));
-+
-+ if (dbus_watch_get_enabled(watch))
-+ dbus_add_watch(watch, data);
-+ else
-+ dbus_remove_watch(watch, data);
-+}
-+
-+/* Listen to locale1 properties changed, and update the XKB layout if needed */
-+int kmscon_dbus_listen_locale1(struct kmscon_dbus *dbus, dbus_update_xkb_layout_cb cb, void *data)
-+{
-+ DBusError error;
-+
-+ log_debug("Listening to locale1\n");
-+
-+ if (!cb)
-+ return -EINVAL;
-+
-+ dbus->cb = cb;
-+ dbus->data = data;
-+
-+ dbus_error_init(&error);
-+
-+ dbus_connection_set_watch_functions(dbus->conn, dbus_add_watch, dbus_remove_watch,
-+ dbus_toggle_watch, dbus, NULL);
-+
-+ dbus_connection_set_dispatch_status_function(dbus->conn, handle_dispatch_status, dbus,
-+ NULL);
-+
-+ const char *match_rule = "type='signal',"
-+ "sender='org.freedesktop.locale1',"
-+ "path='/org/freedesktop/locale1',"
-+ "interface='org.freedesktop.DBus.Properties',"
-+ "member='PropertiesChanged'";
-+
-+ dbus_bus_add_match(dbus->conn, match_rule, &error);
-+
-+ if (dbus_error_is_set(&error)) {
-+ log_debug("Error adding match: %s\n", error.message);
-+ dbus_error_free(&error);
-+ return -EIO;
-+ }
-+ dbus_connection_flush(dbus->conn);
-+
-+ log_info("Listening to locale1 changes");
-+
-+ return 0;
-+}
-diff --git a/src/kmscon_dummy.h b/src/dbus.h
-similarity index 50%
-rename from src/kmscon_dummy.h
-rename to src/dbus.h
-index b4f3aa2..272434f 100644
---- a/src/kmscon_dummy.h
-+++ b/src/dbus.h
-@@ -1,7 +1,8 @@
- /*
-- * kmscon - Dummy Session
-+ * dbus - D-Bus support
- *
-- * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
-+ * Copyright (c) 2026 Red Hat.
-+ * Author: Jocelyn Falempe <jfalempe@redhat.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
-@@ -23,28 +24,38 @@
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
--/*
-- * Dummy Session
-- */
--
--#ifndef KMSCON_DUMMY_H
--#define KMSCON_DUMMY_H
-+#ifndef _KMSCON_DBUS_H
-+#define _KMSCON_DBUS_H
-
--#include <errno.h>
--#include <stdlib.h>
--#include "kmscon_seat.h"
-+struct ev_eloop;
-+struct kmscon_dbus;
-
--#ifdef BUILD_ENABLE_SESSION_DUMMY
-+typedef void (*dbus_update_xkb_layout_cb)(const char *model, const char *layout,
-+ const char *variant, const char *options, void *data);
-
--int kmscon_dummy_register(struct kmscon_session **out, struct kmscon_seat *seat);
-+#ifdef BUILD_ENABLE_DBUS
-+void kmscon_dbus_set_xkb_env_from_locale1(struct kmscon_dbus *dbus);
-+struct kmscon_dbus *kmscon_dbus_new(struct ev_eloop *eloop);
-+void kmscon_dbus_free(struct kmscon_dbus *dbus);
-+int kmscon_dbus_listen_locale1(struct kmscon_dbus *dbus, dbus_update_xkb_layout_cb cb, void *data);
-
--#else /* !BUILD_ENABLE_SESSION_DUMMY */
--
--static inline int kmscon_dummy_register(struct kmscon_session **out, struct kmscon_seat *seat)
-+#else
-+static inline void kmscon_dbus_set_xkb_env_from_locale1(struct kmscon_dbus *dbus)
- {
-- return -EOPNOTSUPP;
-+ return;
- }
--
--#endif /* BUILD_ENABLE_SESSION_DUMMY */
--
--#endif /* KMSCON_DUMMY_H */
-+static inline struct kmscon_dbus *kmscon_dbus_new(struct ev_eloop *eloop)
-+{
-+ return NULL;
-+}
-+static inline void kmscon_dbus_free(struct kmscon_dbus *dbus)
-+{
-+ return;
-+}
-+static inline int kmscon_dbus_listen_locale1(struct kmscon_dbus *dbus, dbus_update_xkb_layout_cb cb,
-+ void *data)
-+{
-+ return 0;
-+}
-+#endif /* BUILD_ENABLE_DBUS */
-+#endif /* _KMSCON_DBUS_H */
-\ No newline at end of file
-diff --git a/src/font/font_freetype.c b/src/font/font_freetype.c
-index a879d64..d0e3ee9 100644
---- a/src/font/font_freetype.c
-+++ b/src/font/font_freetype.c
-@@ -114,7 +114,7 @@ static int font_get_width(FT_Face face)
- {
- FT_UInt glyph_index = FT_Get_Char_Index(face, 'M');
-
-- if (FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT))
-+ if (FT_Load_Glyph(face, glyph_index, FT_LOAD_TARGET_LIGHT))
- return -1;
-
- if (FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL))
-@@ -377,7 +377,7 @@ static struct kmscon_glyph *render_glyph(FT_Face face, FT_UInt index, const uint
- if (!cwidth)
- return NULL;
-
-- if (FT_Load_Glyph(face, index, FT_LOAD_NO_HINTING)) {
-+ if (FT_Load_Glyph(face, index, FT_LOAD_TARGET_LIGHT)) {
- log_err("Failed to load glyph\n");
- return NULL;
- }
-diff --git a/src/font/meson.build b/src/font/meson.build
-index dd5d9dc..d265bb0 100644
---- a/src/font/meson.build
-+++ b/src/font/meson.build
-@@ -22,7 +22,7 @@ font_deps = declare_dependency(
- # Unifont Generator
- # This generates the unifont sources from raw hex-encoded font data.
- #
--genunifont = executable('genunifont', 'genunifont.c', dependencies: [zlib_deps], native: true)
-+genunifont = executable('genunifont', 'genunifont.c', dependencies: [zlib_deps_native], native: true)
-
- unifont_bin = custom_target('unifont-bin',
- input: ['font_unifont_data.hex'],
-@@ -68,4 +68,4 @@ if enable_font_pango
- install: true,
- install_dir: moduledir,
- )
--endif
-\ No newline at end of file
-+endif
-diff --git a/src/input/input.c b/src/input/input.c
-index 65c1d6f..71a053b 100644
---- a/src/input/input.c
-+++ b/src/input/input.c
-@@ -504,23 +504,48 @@ err_free:
-
- SHL_EXPORT
- int input_set_keymap(struct input *input, const char *model, const char *layout,
-- const char *variant, const char *options, const char *locale,
-- const char *keymap, const char *compose_file, size_t compose_file_len)
--{
-- /* xkbcommon won't use the XKB_DEFAULT_OPTIONS environment
-- * variable if options is an empty string.
-- * So if all variables are empty, use NULL instead.
-- */
-- if (model && *model == 0 && layout && *layout == 0 && variant && *variant == 0 && options &&
-- *options == 0) {
-- model = NULL;
-- layout = NULL;
-- variant = NULL;
-- options = NULL;
-- }
-+ const char *variant, const char *options, const char *keymap)
-+{
-+ return uxkb_layout_init(input, model, layout, variant, options, keymap);
-+}
-
-- return uxkb_desc_init(input, model, layout, variant, options, locale, keymap, compose_file,
-- compose_file_len);
-+SHL_EXPORT
-+void input_set_compose(struct input *input, const char *locale, const char *compose_file,
-+ size_t compose_file_len)
-+{
-+ uxkb_compose_table_init(input, compose_file, compose_file_len, locale);
-+}
-+
-+SHL_EXPORT
-+int input_update_keymap(struct input *input, const char *model, const char *layout,
-+ const char *variant, const char *options)
-+{
-+ struct shl_dlist *iter;
-+ struct input_dev *dev;
-+
-+ if (input->ctx) {
-+ shl_dlist_for_each(iter, &input->devices)
-+ {
-+ dev = shl_dlist_entry(iter, struct input_dev, list);
-+ if (dev->capabilities & DEVICE_HAS_KEYS) {
-+ input_sleep_dev(dev);
-+ input_exit_keyboard(dev);
-+ }
-+ }
-+ }
-+ uxkb_compose_table_destroy(input);
-+ uxkb_layout_destroy(input);
-+ uxkb_layout_init(input, model, layout, variant, options, NULL);
-+ shl_dlist_for_each(iter, &input->devices)
-+ {
-+ dev = shl_dlist_entry(iter, struct input_dev, list);
-+ if (dev->capabilities & DEVICE_HAS_KEYS) {
-+ input_init_keyboard(dev);
-+ if (input->awake)
-+ input_wake_up_dev(dev);
-+ }
-+ }
-+ return 0;
- }
-
- SHL_EXPORT
-@@ -565,7 +590,8 @@ void input_unref(struct input *input)
- input_free_dev(dev);
- }
-
-- uxkb_desc_destroy(input);
-+ uxkb_compose_table_destroy(input);
-+ uxkb_layout_destroy(input);
- shl_hook_free(input->key_hook);
- shl_hook_free(input->pointer_hook);
- ev_eloop_rm_timer(input->hide_pointer);
-diff --git a/src/input/input.h b/src/input/input.h
-index 8b81e00..9f269ff 100644
---- a/src/input/input.h
-+++ b/src/input/input.h
-@@ -92,8 +92,11 @@ typedef void (*uterm_close_cb)(int fd, int fd_id, void *data);
-
- int input_new(struct input **out, struct ev_eloop *eloop);
- int input_set_keymap(struct input *input, const char *model, const char *layout,
-- const char *variant, const char *options, const char *locale,
-- const char *keymap, const char *compose_file, size_t compose_file_len);
-+ const char *variant, const char *options, const char *keymap);
-+void input_set_compose(struct input *input, const char *locale, const char *compose_file,
-+ size_t compose_file_len);
-+int input_update_keymap(struct input *input, const char *model, const char *layout,
-+ const char *variant, const char *options);
- void input_set_conf(struct input *input, unsigned int repeat_delay, unsigned int repeat_rate,
- bool mouse_enabled);
- void input_ref(struct input *input);
-diff --git a/src/input/input_internal.h b/src/input/input_internal.h
-index 559e8ec..fc932fa 100644
---- a/src/input/input_internal.h
-+++ b/src/input/input_internal.h
-@@ -140,10 +140,12 @@ static inline bool input_bit_is_set(const unsigned long *array, int bit)
- return !!(array[bit / LONG_BIT] & (1UL << (bit % LONG_BIT)));
- }
-
--int uxkb_desc_init(struct input *input, const char *model, const char *layout, const char *variant,
-- const char *options, const char *locale, const char *keymap,
-- const char *compose_file, size_t compose_file_len);
--void uxkb_desc_destroy(struct input *input);
-+int uxkb_layout_init(struct input *input, const char *model, const char *layout,
-+ const char *variant, const char *options, const char *keymap);
-+void uxkb_compose_table_init(struct input *input, const char *compose_file, size_t compose_file_len,
-+ const char *locale);
-+void uxkb_layout_destroy(struct input *input);
-+void uxkb_compose_table_destroy(struct input *input);
-
- int uxkb_dev_init(struct input_dev *dev);
- void uxkb_dev_destroy(struct input_dev *dev);
-diff --git a/src/input/input_uxkb.c b/src/input/input_uxkb.c
-index 377e935..1ae2565 100644
---- a/src/input/input_uxkb.c
-+++ b/src/input/input_uxkb.c
-@@ -69,11 +69,10 @@ static void uxkb_log(struct xkb_context *context, enum xkb_log_level level, cons
- log_submit(LOG_DEFAULT, sev, format, args);
- }
-
--int uxkb_desc_init(struct input *input, const char *model, const char *layout, const char *variant,
-- const char *options, const char *locale, const char *keymap,
-- const char *compose_file, size_t compose_file_len)
-+int uxkb_layout_init(struct input *input, const char *model, const char *layout,
-+ const char *variant, const char *options, const char *keymap)
- {
-- int ret;
-+ int ret = 0;
- struct xkb_rule_names rmlvo = {
- .rules = "evdev",
- .model = model,
-@@ -140,7 +139,15 @@ int uxkb_desc_init(struct input *input, const char *model, const char *layout, c
- log_debug("new keyboard description (%s, %s, %s, %s)", model, layout, variant,
- options);
- }
-+ return 0;
-+err_ctx:
-+ xkb_context_unref(input->ctx);
-+ return ret;
-+}
-
-+void uxkb_compose_table_init(struct input *input, const char *compose_file, size_t compose_file_len,
-+ const char *locale)
-+{
- if (compose_file && *compose_file) {
- input->compose_table = xkb_compose_table_new_from_buffer(
- input->ctx, compose_file, compose_file_len, locale,
-@@ -161,19 +168,20 @@ int uxkb_desc_init(struct input *input, const char *model, const char *layout, c
- "table, disabling compose support");
- }
- }
--
-- return 0;
--
--err_ctx:
-- xkb_context_unref(input->ctx);
-- return ret;
- }
-
--void uxkb_desc_destroy(struct input *input)
-+void uxkb_compose_table_destroy(struct input *input)
- {
- xkb_compose_table_unref(input->compose_table);
-+ input->compose_table = NULL;
-+}
-+
-+void uxkb_layout_destroy(struct input *input)
-+{
- xkb_keymap_unref(input->keymap);
- xkb_context_unref(input->ctx);
-+ input->keymap = NULL;
-+ input->ctx = NULL;
- }
-
- static void timer_event(struct ev_timer *timer, uint64_t num, void *data)
-@@ -218,6 +226,9 @@ void uxkb_dev_destroy(struct input_dev *dev)
- xkb_compose_state_unref(dev->compose_state);
- xkb_state_unref(dev->state);
- ev_eloop_rm_timer(dev->repeat_timer);
-+ dev->compose_state = NULL;
-+ dev->state = NULL;
-+ dev->repeat_timer = NULL;
- }
-
- #define EVDEV_KEYCODE_OFFSET 8
-diff --git a/src/kmscon_conf.c b/src/kmscon_conf.c
-index 6a8728a..4b01d4a 100644
---- a/src/kmscon_conf.c
-+++ b/src/kmscon_conf.c
-@@ -34,6 +34,7 @@
- #include <xkbcommon/xkbcommon-keysyms.h>
- #include "conf.h"
- #include "kmscon_conf.h"
-+#include "kmscon_issue.h"
- #include "shl/githead.h"
- #include "shl/log.h"
- #include "shl/misc.h"
-@@ -78,14 +79,13 @@ static void print_help()
- "Session Options:\n"
- "\t --session-max <max> [50] Maximum number of sessions\n"
- "\t --session-control [off] Allow keyboard session-control\n"
-- "\t --terminal-session [on] Enable terminal session\n"
- "\n"
- "Terminal Options:\n"
- "\t --issue [on]\n"
- "\t Display issue files before the\n"
- "\t login prompt. Use --no-issue to\n"
- "\t let the login process handle it.\n"
-- "\t --issue-path <path> [/etc/issue:/etc/issue.d]\n"
-+ "\t --issue-path <path> [" ISSUE_DEFAULT_PATH "]\n"
- "\t Colon-separated list of issue\n"
- "\t files and directories to read\n"
- "\t-l, --login [/bin/login -p]\n"
-@@ -148,8 +148,6 @@ static void print_help()
- "\t Switch to the next session\n"
- "\t --grab-session-prev <grab> [<Ctrl><Logo>Left]\n"
- "\t Switch to the previous session\n"
-- "\t --grab-session-dummy <grab> [<Ctrl><Logo>Escape]\n"
-- "\t Switch to a dummy session\n"
- "\t --grab-session-close <grab> [<Ctrl><Logo>BackSpace]\n"
- "\t Close current session\n"
- "\t --grab-terminal-new <grab> [<Ctrl><Logo>Return]\n"
-@@ -659,9 +657,6 @@ static struct conf_grab def_grab_session_next =
- static struct conf_grab def_grab_session_prev =
- CONF_SINGLE_GRAB(SHL_CONTROL_MASK | SHL_LOGO_MASK, XKB_KEY_Left);
-
--static struct conf_grab def_grab_session_dummy =
-- CONF_SINGLE_GRAB(SHL_CONTROL_MASK | SHL_LOGO_MASK, XKB_KEY_Escape);
--
- static struct conf_grab def_grab_session_close =
- CONF_SINGLE_GRAB(SHL_CONTROL_MASK | SHL_LOGO_MASK, XKB_KEY_BackSpace);
-
-@@ -728,11 +723,10 @@ int kmscon_conf_new(struct conf_ctx **out)
- /* Session Options */
- CONF_OPTION_UINT(0, "session-max", &conf->session_max, 50),
- CONF_OPTION_BOOL(0, "session-control", &conf->session_control, false),
-- CONF_OPTION_BOOL(0, "terminal-session", &conf->terminal_session, true),
-
- /* Terminal Options */
- CONF_OPTION_BOOL(0, "issue", &conf->issue, true),
-- CONF_OPTION_STRING(0, "issue-path", &conf->issue_path, "/etc/issue:/etc/issue.d"),
-+ CONF_OPTION_STRING(0, "issue-path", &conf->issue_path, ISSUE_DEFAULT_PATH),
- CONF_OPTION(0, 'l', "login", &conf_login, aftercheck_login, NULL, file_login,
- &conf->login, false),
- CONF_OPTION_STRING('t', "term", &conf->term, "kmscon"),
-@@ -742,12 +736,12 @@ int kmscon_conf_new(struct conf_ctx **out)
- CONF_OPTION_BOOL(0, "bell", &conf->bell, false),
-
- /* Input Options */
-- CONF_OPTION_STRING(0, "xkb-model", &conf->xkb_model, ""),
-- CONF_OPTION_STRING(0, "xkb-layout", &conf->xkb_layout, ""),
-- CONF_OPTION_STRING(0, "xkb-variant", &conf->xkb_variant, ""),
-- CONF_OPTION_STRING(0, "xkb-options", &conf->xkb_options, ""),
-- CONF_OPTION_STRING(0, "xkb-keymap", &conf->xkb_keymap, ""),
-- CONF_OPTION_STRING(0, "xkb-compose-file", &conf->xkb_compose_file, ""),
-+ CONF_OPTION_STRING(0, "xkb-model", &conf->xkb_model, NULL),
-+ CONF_OPTION_STRING(0, "xkb-layout", &conf->xkb_layout, NULL),
-+ CONF_OPTION_STRING(0, "xkb-variant", &conf->xkb_variant, NULL),
-+ CONF_OPTION_STRING(0, "xkb-options", &conf->xkb_options, NULL),
-+ CONF_OPTION_STRING(0, "xkb-keymap", &conf->xkb_keymap, NULL),
-+ CONF_OPTION_STRING(0, "xkb-compose-file", &conf->xkb_compose_file, NULL),
- CONF_OPTION_UINT(0, "xkb-repeat-delay", &conf->xkb_repeat_delay, 250),
- CONF_OPTION_UINT(0, "xkb-repeat-rate", &conf->xkb_repeat_rate, 50),
- CONF_OPTION_BOOL(0, "mouse", &conf->mouse, true),
-@@ -767,8 +761,6 @@ int kmscon_conf_new(struct conf_ctx **out)
- &def_grab_session_next),
- CONF_OPTION_GRAB(0, "grab-session-prev", &conf->grab_session_prev,
- &def_grab_session_prev),
-- CONF_OPTION_GRAB(0, "grab-session-dummy", &conf->grab_session_dummy,
-- &def_grab_session_dummy),
- CONF_OPTION_GRAB(0, "grab-session-close", &conf->grab_session_close,
- &def_grab_session_close),
- CONF_OPTION_GRAB(0, "grab-terminal-new", &conf->grab_terminal_new,
-diff --git a/src/kmscon_conf.h b/src/kmscon_conf.h
-index 8dc7afd..377f8a3 100644
---- a/src/kmscon_conf.h
-+++ b/src/kmscon_conf.h
-@@ -79,8 +79,6 @@ struct kmscon_conf_t {
- unsigned int session_max;
- /* allow keyboard session control */
- bool session_control;
-- /* run terminal session */
-- bool terminal_session;
-
- /* Terminal Options */
- /* display /etc/issue before login prompt */
-@@ -145,8 +143,6 @@ struct kmscon_conf_t {
- struct conf_grab *grab_session_next;
- /* session-prev grab */
- struct conf_grab *grab_session_prev;
-- /* session-dummy grab */
-- struct conf_grab *grab_session_dummy;
- /* session-close grab */
- struct conf_grab *grab_session_close;
- /* terminal-new grab */
-diff --git a/src/kmscon_dummy.c b/src/kmscon_dummy.c
-deleted file mode 100644
-index fcafb6c..0000000
---- a/src/kmscon_dummy.c
-+++ /dev/null
-@@ -1,154 +0,0 @@
--/*
-- * kmscon - Dummy Session
-- *
-- * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
-- *
-- * Permission is hereby granted, free of charge, to any person obtaining
-- * a copy of this software and associated documentation files
-- * (the "Software"), to deal in the Software without restriction, including
-- * without limitation the rights to use, copy, modify, merge, publish,
-- * distribute, sublicense, and/or sell copies of the Software, and to
-- * permit persons to whom the Software is furnished to do so, subject to
-- * the following conditions:
-- *
-- * The above copyright notice and this permission notice shall be included
-- * in all copies or substantial portions of the Software.
-- *
-- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-- */
--
--/*
-- * Dummy Session
-- */
--
--#include <errno.h>
--#include <stdlib.h>
--#include <string.h>
--#include "kmscon_dummy.h"
--#include "kmscon_seat.h"
--#include "shl/dlist.h"
--#include "shl/log.h"
--#include "video/video.h"
--
--#define LOG_SUBSYSTEM "dummy"
--
--struct display {
-- struct shl_dlist list;
-- struct display *disp;
--};
--
--struct kmscon_dummy {
-- struct kmscon_session *session;
-- struct shl_dlist displays;
-- bool active;
--};
--
--static void dummy_redraw(struct kmscon_dummy *dummy, struct display *d)
--{
-- display_clear(d->disp, 0, 0, 0);
-- display_swap(d->disp);
--}
--
--static int dummy_session_event(struct kmscon_session *session, struct kmscon_session_event *ev,
-- void *data)
--{
-- struct kmscon_dummy *dummy = data;
-- struct display *d;
-- struct shl_dlist *iter;
--
-- switch (ev->type) {
-- case KMSCON_SESSION_DISPLAY_NEW:
-- d = malloc(sizeof(*d));
-- if (!d) {
-- log_error("cannot allocate memory for new display");
-- break;
-- }
-- memset(d, 0, sizeof(*d));
-- d->disp = ev->disp;
-- shl_dlist_link_tail(&dummy->displays, &d->list);
-- if (dummy->active)
-- dummy_redraw(dummy, d);
-- break;
-- case KMSCON_SESSION_DISPLAY_GONE:
-- shl_dlist_for_each(iter, &dummy->displays)
-- {
-- d = shl_dlist_entry(iter, struct display, list);
-- if (d->disp != ev->disp)
-- continue;
--
-- shl_dlist_unlink(&d->list);
-- free(d);
-- break;
-- }
-- break;
-- case KMSCON_SESSION_DISPLAY_REFRESH:
-- shl_dlist_for_each(iter, &dummy->displays)
-- {
-- d = shl_dlist_entry(iter, struct display, list);
-- if (d->disp != ev->disp)
-- continue;
--
-- if (dummy->active)
-- dummy_redraw(dummy, d);
-- break;
-- }
-- break;
-- case KMSCON_SESSION_ACTIVATE:
-- dummy->active = true;
-- shl_dlist_for_each(iter, &dummy->displays)
-- {
-- d = shl_dlist_entry(iter, struct display, list);
-- dummy_redraw(dummy, d);
-- }
-- break;
-- case KMSCON_SESSION_DEACTIVATE:
-- dummy->active = false;
-- break;
-- case KMSCON_SESSION_UNREGISTER:
-- while (!shl_dlist_empty(&dummy->displays)) {
-- d = shl_dlist_entry(dummy->displays.prev, struct display, list);
-- shl_dlist_unlink(&d->list);
-- free(d);
-- }
--
-- free(dummy);
-- break;
-- }
--
-- return 0;
--}
--
--int kmscon_dummy_register(struct kmscon_session **out, struct kmscon_seat *seat)
--{
-- struct kmscon_dummy *dummy;
-- int ret;
--
-- if (!out || !seat)
-- return -EINVAL;
--
-- dummy = malloc(sizeof(*dummy));
-- if (!dummy)
-- return -ENOMEM;
-- memset(dummy, 0, sizeof(*dummy));
-- shl_dlist_init(&dummy->displays);
--
-- ret = kmscon_seat_register_session(seat, &dummy->session, dummy_session_event, dummy);
-- if (ret) {
-- log_error("cannot register session for dummy: %d", ret);
-- goto err_free;
-- }
--
-- *out = dummy->session;
-- log_debug("new dummy object %p", dummy);
-- return 0;
--
--err_free:
-- free(dummy);
-- return ret;
--}
-diff --git a/src/kmscon_issue.c b/src/kmscon_issue.c
-index 3846f89..bffb792 100644
---- a/src/kmscon_issue.c
-+++ b/src/kmscon_issue.c
-@@ -36,16 +36,6 @@
- /* Cap total collected issue text to prevent runaway allocation. */
- #define ISSUE_MAX_SIZE (256u * 1024u)
-
--/*
-- * Default search path, matching agetty's default:
-- * /etc/issue:/etc/issue.d
-- *
-- * Distros can override this with --issue-path or the issue-path config
-- * option using a colon-separated list. Plain files are read directly;
-- * directories are scanned for *.issue files in lexicographic order.
-- */
--#define ISSUE_DEFAULT_PATH "/etc/issue:/etc/issue.d"
--
- /* Color escape codes */
- // clang-format off
- #define UL_COLOR_RESET "[0m"
-diff --git a/src/kmscon_issue.h b/src/kmscon_issue.h
-index f74382a..8900c95 100644
---- a/src/kmscon_issue.h
-+++ b/src/kmscon_issue.h
-@@ -29,6 +29,15 @@
- #include <libtsm.h>
- #include "pty.h"
-
-+/*
-+ * Default search path, matching agetty's default.
-+ *
-+ * Distros can override this with --issue-path or the issue-path config
-+ * option using a colon-separated list. Plain files are read directly;
-+ * directories are scanned for *.issue files in lexicographic order.
-+ */
-+#define ISSUE_DEFAULT_PATH "/etc/issue:/etc/issue.d"
-+
- void kmscon_issue_write(struct tsm_vte *vte, struct kmscon_pty *pty, const char *search_path);
-
- #endif /* KMSCON_ISSUE_H */
-diff --git a/src/kmscon_main.c b/src/kmscon_main.c
-index 6fb57a8..81343f4 100644
---- a/src/kmscon_main.c
-+++ b/src/kmscon_main.c
-@@ -31,6 +31,7 @@
- #include <string.h>
- #include <sys/signalfd.h>
- #include "conf.h"
-+#include "dbus.h"
- #include "kmscon_conf.h"
- #include "kmscon_seat.h"
- #include "render/text.h"
-@@ -39,6 +40,8 @@
- #include "shl/module.h"
- #include "video/video.h"
-
-+#define LOG_SUBSYSTEM "kmscon"
-+
- struct kmscon_app {
- struct conf_ctx *conf_ctx;
- struct kmscon_conf_t *conf;
-@@ -49,6 +52,7 @@ struct kmscon_app {
- struct conf_ctx *seat_ctx;
- struct kmscon_conf_t *seat_conf;
- struct kmscon_seat *seat;
-+ struct kmscon_dbus *dbus;
- };
-
- static int app_seat_event(struct kmscon_seat *s, unsigned int event, void *data)
-@@ -112,6 +116,30 @@ static void destroy_app(struct kmscon_app *app)
- ev_eloop_unregister_signal_cb(app->eloop, SIGINT, app_sig_generic, app);
- ev_eloop_unregister_signal_cb(app->eloop, SIGTERM, app_sig_generic, app);
- ev_eloop_unref(app->eloop);
-+ kmscon_dbus_free(app->dbus);
-+}
-+
-+static void update_xkb_layout(const char *model, const char *layout, const char *variant,
-+ const char *options, void *data)
-+{
-+ struct kmscon_app *app = data;
-+
-+ log_debug("updating xkb layout: %s, %s, %s, %s", model, layout, variant, options);
-+ if (kmscon_seat_update_xkb_layout(app->seat, model, layout, variant, options))
-+ log_error("cannot update xkb layout");
-+}
-+
-+static void listen_to_dbus_locale1(struct kmscon_app *app)
-+{
-+ int ret;
-+
-+ if (app->conf->xkb_keymap || app->conf->xkb_model || app->conf->xkb_layout ||
-+ app->conf->xkb_variant || app->conf->xkb_options)
-+ return;
-+
-+ ret = kmscon_dbus_listen_locale1(app->dbus, update_xkb_layout, app);
-+ if (ret)
-+ log_warning("cannot listen to locale1: %d", ret);
- }
-
- static int setup_app(struct kmscon_app *app)
-@@ -142,6 +170,11 @@ static int setup_app(struct kmscon_app *app)
- goto err_app;
- }
-
-+ app->dbus = kmscon_dbus_new(app->eloop);
-+ if (app->dbus) {
-+ kmscon_dbus_set_xkb_env_from_locale1(app->dbus);
-+ listen_to_dbus_locale1(app);
-+ }
- return 0;
-
- err_app:
-diff --git a/src/kmscon_seat.c b/src/kmscon_seat.c
-index 7b6759a..91b8db8 100644
---- a/src/kmscon_seat.c
-+++ b/src/kmscon_seat.c
-@@ -39,7 +39,6 @@
- #include "conf.h"
- #include "input/input.h"
- #include "kmscon_conf.h"
--#include "kmscon_dummy.h"
- #include "kmscon_seat.h"
- #include "kmscon_terminal.h"
- #include "shl/dlist.h"
-@@ -53,17 +52,12 @@
-
- struct kmscon_session {
- struct shl_dlist list;
-- unsigned long ref;
- struct kmscon_seat *seat;
-
-- bool enabled;
- bool foreground;
-- bool deactivating;
-
- struct ev_timer *timer;
--
-- kmscon_session_cb_t cb;
-- void *data;
-+ struct kmscon_terminal *term;
- };
-
- struct kmscon_display {
-@@ -85,12 +79,6 @@ struct kmscon_video {
- bool awake;
- };
-
--enum kmscon_async_schedule {
-- SCHEDULE_SWITCH,
-- SCHEDULE_VT,
-- SCHEDULE_UNREGISTER,
--};
--
- struct kmscon_seat {
- struct ev_eloop *eloop;
- struct conf_ctx *conf_ctx;
-@@ -110,10 +98,6 @@ struct kmscon_seat {
- bool awake;
- bool foreground;
- struct kmscon_session *current_sess;
-- struct kmscon_session *scheduled_sess;
-- struct kmscon_session *dummy_sess;
--
-- unsigned int async_schedule;
-
- /* DPMS timeout management */
- struct ev_timer *dpms_timer;
-@@ -133,48 +117,10 @@ static int kmscon_seat_add_video(struct kmscon_seat *seat, enum uterm_monitor_de
- static void kmscon_seat_remove_video(struct kmscon_seat *seat, void *data);
- static void kmscon_seat_poll_video(void *data);
-
--static int session_call(struct kmscon_session *sess, unsigned int event, struct display *disp)
--{
-- struct kmscon_session_event ev;
--
-- if (!sess->cb)
-- return 0;
--
-- memset(&ev, 0, sizeof(ev));
-- ev.type = event;
-- ev.disp = disp;
-- return sess->cb(sess, &ev, sess->data);
--}
--
--static int session_call_activate(struct kmscon_session *sess)
--{
-- log_debug("activate session %p", sess);
-- return session_call(sess, KMSCON_SESSION_ACTIVATE, NULL);
--}
--
--static int session_call_deactivate(struct kmscon_session *sess)
--{
-- log_debug("deactivate session %p", sess);
-- return session_call(sess, KMSCON_SESSION_DEACTIVATE, NULL);
--}
--
--static void session_call_display_new(struct kmscon_session *sess, struct display *disp)
--{
-- session_call(sess, KMSCON_SESSION_DISPLAY_NEW, disp);
--}
--
--static void session_call_display_gone(struct kmscon_session *sess, struct display *disp)
--{
-- session_call(sess, KMSCON_SESSION_DISPLAY_GONE, disp);
--}
--
--static void session_call_display_refresh(struct kmscon_session *sess, struct display *disp)
--{
-- session_call(sess, KMSCON_SESSION_DISPLAY_REFRESH, disp);
--}
--
- /* Forward declaration */
- static void seat_dpms_reset_timer(struct kmscon_seat *seat);
-+static struct kmscon_session *kmscon_seat_new_session(struct kmscon_seat *seat);
-+static void kmscon_session_unregister(struct kmscon_session *sess);
-
- static void activate_display(struct kmscon_display *d)
- {
-@@ -203,12 +149,12 @@ static void activate_display(struct kmscon_display *d)
- shl_dlist_for_each_safe(iter, tmp, &seat->sessions)
- {
- s = shl_dlist_entry(iter, struct kmscon_session, list);
-- session_call_display_new(s, d->disp);
-+ terminal_add_display(s->term, d->disp);
- }
- }
- }
-
--static int seat_go_foreground(struct kmscon_seat *seat, bool force)
-+static int seat_go_foreground(struct kmscon_seat *seat)
- {
- struct shl_dlist *iter, *tmp;
- struct kmscon_video *vid;
-@@ -217,7 +163,7 @@ static int seat_go_foreground(struct kmscon_seat *seat, bool force)
-
- if (seat->foreground)
- return 0;
-- if (!seat->awake || (!force && seat->current_sess))
-+ if (!seat->awake)
- return -EBUSY;
-
- seat->foreground = true;
-@@ -251,14 +197,14 @@ static int seat_go_foreground(struct kmscon_seat *seat, bool force)
- return 0;
- }
-
--static int seat_go_background(struct kmscon_seat *seat, bool force)
-+static int seat_go_background(struct kmscon_seat *seat)
- {
- struct shl_dlist *iter;
- struct kmscon_video *vid;
-
- if (!seat->foreground)
- return 0;
-- if (!seat->awake || (!force && seat->current_sess))
-+ if (!seat->awake)
- return -EBUSY;
-
- shl_dlist_for_each(iter, &seat->videos)
-@@ -271,25 +217,15 @@ static int seat_go_background(struct kmscon_seat *seat, bool force)
- return 0;
- }
-
--static int seat_go_asleep(struct kmscon_seat *seat, bool force)
-+static int seat_go_asleep(struct kmscon_seat *seat)
- {
-- int err = 0;
--
- if (!seat->awake)
- return 0;
-- if (seat->current_sess || seat->foreground) {
-- if (force) {
-- seat->foreground = false;
-- seat->current_sess = NULL;
-- err = -EBUSY;
-- } else {
-- return -EBUSY;
-- }
-- }
-+
- seat->awake = false;
- input_sleep(seat->input);
-
-- return err;
-+ return 0;
- }
-
- static int seat_go_awake(struct kmscon_seat *seat)
-@@ -313,196 +249,52 @@ static int seat_go_awake(struct kmscon_seat *seat)
- return 0;
- }
-
--static int seat_run(struct kmscon_seat *seat)
-+static void seat_switch(struct kmscon_seat *seat, struct kmscon_session *new)
- {
-- int ret;
-- struct kmscon_session *session;
--
-- if (!seat->awake)
-- return -EBUSY;
-- if (seat->current_sess)
-- return 0;
--
-- if (!seat->scheduled_sess) {
-- log_debug("no session scheduled to run (num %zu)", seat->session_count);
-- return -ENOENT;
-- }
-- session = seat->scheduled_sess;
--
-- if (session->foreground && !seat->foreground) {
-- ret = seat_go_foreground(seat, false);
-- if (ret) {
-- log_warning("cannot put seat %s into foreground for session %p", seat->name,
-- session);
-- return ret;
-- }
-- } else if (!session->foreground && seat->foreground) {
-- ret = seat_go_background(seat, false);
-- if (ret) {
-- log_warning("cannot put seat %s into background for session %p", seat->name,
-- session);
-- return ret;
-- }
-- }
--
-- ret = session_call_activate(session);
-- if (ret) {
-- log_warning("cannot activate session %p: %d", session, ret);
-- return ret;
-- }
--
-- seat->current_sess = session;
--
-- return 0;
--}
--
--static void session_deactivate(struct kmscon_session *sess)
--{
-- if (sess->seat->current_sess != sess)
-+ if (seat->current_sess == new)
- return;
-
-- sess->seat->async_schedule = SCHEDULE_SWITCH;
-- sess->deactivating = false;
-- sess->seat->current_sess = NULL;
--}
--
--static int seat_pause(struct kmscon_seat *seat, bool force)
--{
-- int ret;
--
-- if (!seat->current_sess)
-- return 0;
--
-- seat->current_sess->deactivating = true;
-- ret = session_call_deactivate(seat->current_sess);
-- if (ret) {
-- if (ret == -EINPROGRESS)
-- log_debug("pending deactivation for session %p", seat->current_sess);
-- else
-- log_warning("cannot deactivate session %p: %d", seat->current_sess, ret);
-- if (!force)
-- return ret;
-- }
--
-- session_deactivate(seat->current_sess);
--
-- return ret;
--}
--
--static void seat_reschedule(struct kmscon_seat *seat)
--{
-- struct shl_dlist *iter, *start;
-- struct kmscon_session *sess;
--
-- if (seat->scheduled_sess && seat->scheduled_sess->enabled)
-- return;
--
-- if (seat->current_sess && seat->current_sess->enabled) {
-- seat->scheduled_sess = seat->current_sess;
-- return;
-- }
-+ log_debug("switch session from %p to %p on seat %s", seat->current_sess, new, seat->name);
-
- if (seat->current_sess)
-- start = &seat->current_sess->list;
-- else
-- start = &seat->sessions;
--
-- shl_dlist_for_each_but_one(iter, start, &seat->sessions)
-- {
-- sess = shl_dlist_entry(iter, struct kmscon_session, list);
-- if (sess == seat->dummy_sess || !sess->enabled)
-- continue;
-- seat->scheduled_sess = sess;
-- return;
-+ terminal_deactivate(seat->current_sess->term);
-+ if (new) {
-+ if (new->foreground && !seat->foreground) {
-+ seat_go_foreground(seat);
-+ } else if (!new->foreground && seat->foreground) {
-+ seat_go_background(seat);
-+ }
-+ terminal_activate(new->term);
- }
--
-- if (seat->dummy_sess && seat->dummy_sess->enabled)
-- seat->scheduled_sess = seat->dummy_sess;
-- else
-- seat->scheduled_sess = NULL;
--}
--
--static bool seat_has_schedule(struct kmscon_seat *seat)
--{
-- return seat->scheduled_sess && seat->scheduled_sess != seat->current_sess;
--}
--
--static int seat_switch(struct kmscon_seat *seat)
--{
-- int ret;
--
-- seat->async_schedule = SCHEDULE_SWITCH;
-- ret = seat_pause(seat, false);
-- if (ret)
-- return ret;
--
-- return seat_run(seat);
-+ seat->current_sess = new;
- }
-
- static void seat_next(struct kmscon_seat *seat)
- {
-- struct shl_dlist *cur, *iter;
-- struct kmscon_session *s, *next;
-+ struct kmscon_session *next = NULL;
-
- if (seat->current_sess)
-- cur = &seat->current_sess->list;
-- else if (seat->session_count)
-- cur = &seat->sessions;
-- else
-- return;
--
-- next = NULL;
-- if (!seat->current_sess && seat->dummy_sess && seat->dummy_sess->enabled)
-- next = seat->dummy_sess;
--
-- shl_dlist_for_each_but_one(iter, cur, &seat->sessions)
-- {
-- s = shl_dlist_entry(iter, struct kmscon_session, list);
-- if (!s->enabled || seat->dummy_sess == s)
-- continue;
--
-- next = s;
-- break;
-- }
--
-+ next = shl_dlist_next(seat->current_sess, &seat->sessions, list);
- if (!next)
-- return;
-+ next = shl_dlist_first(&seat->sessions, struct kmscon_session, list);
-+ if (next && next == seat->current_sess)
-+ next = NULL;
-
-- seat->scheduled_sess = next;
-- seat_switch(seat);
-+ seat_switch(seat, next);
- }
-
- static void seat_prev(struct kmscon_seat *seat)
- {
-- struct shl_dlist *cur, *iter;
-- struct kmscon_session *s, *prev;
-+ struct kmscon_session *prev = NULL;
-
- if (seat->current_sess)
-- cur = &seat->current_sess->list;
-- else if (seat->session_count)
-- cur = &seat->sessions;
-- else
-- return;
--
-- prev = NULL;
-- if (!seat->current_sess && seat->dummy_sess && seat->dummy_sess->enabled)
-- prev = seat->dummy_sess;
--
-- shl_dlist_for_each_reverse_but_one(iter, cur, &seat->sessions)
-- {
-- s = shl_dlist_entry(iter, struct kmscon_session, list);
-- if (!s->enabled || seat->dummy_sess == s)
-- continue;
--
-- prev = s;
-- break;
-- }
--
-+ prev = shl_dlist_prev(seat->current_sess, &seat->sessions, list);
- if (!prev)
-- return;
-+ prev = shl_dlist_last(&seat->sessions, struct kmscon_session, list);
-+ if (prev && prev == seat->current_sess)
-+ prev = NULL;
-
-- seat->scheduled_sess = prev;
-- seat_switch(seat);
-+ seat_switch(seat, prev);
- }
-
- static void seat_add_display(struct kmscon_seat *seat, struct display *disp)
-@@ -536,7 +328,7 @@ static void seat_remove_display(struct kmscon_seat *seat, struct kmscon_display
- shl_dlist_for_each_safe(iter, tmp, &seat->sessions)
- {
- s = shl_dlist_entry(iter, struct kmscon_session, list);
-- session_call_display_gone(s, d->disp);
-+ terminal_rm_display(s->term, d->disp);
- }
- }
-
-@@ -569,7 +361,7 @@ static void seat_refresh_display(struct kmscon_seat *seat, struct kmscon_display
- shl_dlist_for_each(iter, &seat->sessions)
- {
- s = shl_dlist_entry(iter, struct kmscon_session, list);
-- session_call_display_refresh(s, d->disp);
-+ terminal_refresh_displays(s->term);
- }
- }
- }
-@@ -578,9 +370,14 @@ static void seat_vt_activate(struct uterm_vt *vt, void *data)
- {
- struct kmscon_seat *seat = data;
-
-+ log_debug("VT %d activated on seat %s", uterm_vt_get_num(vt), seat->name);
-+
- if (seat_go_awake(seat))
- return;
-- seat_run(seat);
-+ if (seat_go_foreground(seat))
-+ return;
-+ if (seat->current_sess)
-+ terminal_activate(seat->current_sess->term);
- }
-
- static int seat_vt_deactivate(struct uterm_vt *vt, bool force, void *data)
-@@ -588,14 +385,13 @@ static int seat_vt_deactivate(struct uterm_vt *vt, bool force, void *data)
- struct kmscon_seat *seat = data;
- int ret;
-
-- seat->async_schedule = SCHEDULE_VT;
-- ret = seat_pause(seat, false);
-- if (ret)
-- return ret;
-- ret = seat_go_background(seat, false);
-+ if (seat->current_sess)
-+ terminal_deactivate(seat->current_sess->term);
-+
-+ ret = seat_go_background(seat);
- if (ret)
- return ret;
-- ret = seat_go_asleep(seat, false);
-+ ret = seat_go_asleep(seat);
- if (ret)
- return ret;
- return 0;
-@@ -726,7 +522,6 @@ static void seat_input_event(struct input *input, struct input_key_event *ev, vo
- {
- struct kmscon_seat *seat = data;
- struct kmscon_session *s;
-- int ret;
-
- /* Reset DPMS timer on any input event */
- seat_dpms_reset_timer(seat);
-@@ -736,49 +531,27 @@ static void seat_input_event(struct input *input, struct input_key_event *ev, vo
-
- if (conf_grab_matches(seat->conf->grab_session_next, ev->mods, ev->num_syms, ev->keysyms)) {
- ev->handled = true;
-- if (!seat->conf->session_control)
-+ if (!seat->conf->session_control || seat->session_count < 2)
- return;
- seat_next(seat);
- return;
- }
- if (conf_grab_matches(seat->conf->grab_session_prev, ev->mods, ev->num_syms, ev->keysyms)) {
- ev->handled = true;
-- if (!seat->conf->session_control)
-+ if (!seat->conf->session_control || seat->session_count < 2)
- return;
- seat_prev(seat);
- return;
- }
-- if (conf_grab_matches(seat->conf->grab_session_dummy, ev->mods, ev->num_syms,
-- ev->keysyms)) {
-- ev->handled = true;
-- if (!seat->conf->session_control)
-- return;
-- seat->scheduled_sess = seat->dummy_sess;
-- seat_switch(seat);
-- return;
-- }
-+
- if (conf_grab_matches(seat->conf->grab_session_close, ev->mods, ev->num_syms,
- ev->keysyms)) {
- ev->handled = true;
-- if (!seat->conf->session_control)
-+ if (!seat->conf->session_control || seat->session_count < 2)
- return;
- s = seat->current_sess;
- if (!s)
- return;
-- if (s == seat->dummy_sess)
-- return;
--
-- /* First time this is invoked on a session, we simply try
-- * unloading it. If it fails, we give it some time. If this is
-- * invoked a second time, we notice that we already tried
-- * removing it and so we go straight to unregistering the
-- * session unconditionally. */
-- if (!s->deactivating) {
-- seat->async_schedule = SCHEDULE_UNREGISTER;
-- ret = seat_pause(seat, false);
-- if (ret)
-- return;
-- }
-
- kmscon_session_unregister(s);
- return;
-@@ -787,16 +560,9 @@ static void seat_input_event(struct input *input, struct input_key_event *ev, vo
- ev->handled = true;
- if (!seat->conf->session_control)
- return;
-- ret = kmscon_terminal_register(&s, seat, uterm_vt_get_num(seat->vt));
-- if (ret == -EOPNOTSUPP) {
-- log_notice("terminal support not compiled in");
-- } else if (ret) {
-- log_error("cannot register terminal session: %d", ret);
-- } else {
-- s->enabled = true;
-- seat->scheduled_sess = s;
-- seat_switch(seat);
-- }
-+ s = kmscon_seat_new_session(seat);
-+ if (s)
-+ seat_switch(seat, s);
- return;
- }
- if (seat->conf->grab_reboot &&
-@@ -829,12 +595,9 @@ static const char *find_locale(void)
-
- static int kmscon_seat_set_keymap(struct kmscon_seat *seat)
- {
-- const char *locale;
-- char *keymap, *compose_file;
-- size_t compose_file_len;
-- int ret;
-
-- locale = find_locale();
-+ char *keymap;
-+ int ret;
-
- /* TODO: The XKB-API currently requires zero-terminated strings as
- * keymap input. Hence, we have to read it in instead of using mmap().
-@@ -846,21 +609,49 @@ static int kmscon_seat_set_keymap(struct kmscon_seat *seat)
- log_error("cannot read keymap file %s: %d", seat->conf->xkb_keymap, ret);
- }
-
-+ ret = input_set_keymap(seat->input, seat->conf->xkb_model, seat->conf->xkb_layout,
-+ seat->conf->xkb_variant, seat->conf->xkb_options, keymap);
-+ if (ret)
-+ log_error("cannot set keymap: %d", ret);
-+
-+ free(keymap);
-+ return ret;
-+}
-+
-+static void kmscon_seat_set_compose(struct kmscon_seat *seat)
-+{
-+ const char *locale;
-+ char *compose_file;
-+ size_t compose_file_len;
-+ int ret;
-+
-+ locale = find_locale();
-+
- compose_file = NULL;
- compose_file_len = 0;
- if (seat->conf->xkb_compose_file && *seat->conf->xkb_compose_file) {
- ret = shl_read_file(seat->conf->xkb_compose_file, &compose_file, &compose_file_len);
-- if (ret)
-+ if (ret) {
- log_error("cannot read compose file %s: %d", seat->conf->xkb_compose_file,
- ret);
-+ return;
-+ }
- }
-- ret = input_set_keymap(seat->input, seat->conf->xkb_model, seat->conf->xkb_layout,
-- seat->conf->xkb_variant, seat->conf->xkb_options, locale, keymap,
-- compose_file, compose_file_len);
-- if (ret)
-- log_error("cannot set keymap: %d", ret);
-+ input_set_compose(seat->input, locale, compose_file, compose_file_len);
-+}
-
-- free(keymap);
-+int kmscon_seat_update_xkb_layout(struct kmscon_seat *seat, const char *model, const char *layout,
-+ const char *variant, const char *options)
-+{
-+ int ret;
-+
-+ ret = input_update_keymap(seat->input, model, layout, variant, options);
-+ if (ret) {
-+ log_error("cannot update keymap: %d", ret);
-+ return ret;
-+ }
-+ /* Compose table is lost when updating the keymap, so we need to set it again */
-+ kmscon_seat_set_compose(seat);
- return ret;
- }
-
-@@ -993,6 +784,8 @@ int kmscon_seat_new(struct kmscon_seat **out, struct conf_ctx *main_conf,
- if (ret)
- goto err_conf;
-
-+ kmscon_seat_set_compose(seat);
-+
- ret = uterm_monitor_new(&seat->mon, seat->eloop, &seat_monitor_cb, seat);
- if (ret) {
- log_error("cannot create device monitor: %d", ret);
-@@ -1063,12 +856,9 @@ void kmscon_seat_free(struct kmscon_seat *seat)
- if (!seat)
- return;
-
-- ret = seat_pause(seat, true);
-- if (ret)
-- log_warning("destroying seat %s while session %p is active", seat->name,
-- seat->current_sess);
-+ seat_switch(seat, NULL);
-
-- ret = seat_go_asleep(seat, true);
-+ ret = seat_go_asleep(seat);
- if (ret)
- log_warning("destroying seat %s while still awake: %d", seat->name, ret);
-
-@@ -1306,31 +1096,18 @@ static void kmscon_seat_poll_video(void *data)
-
- void kmscon_seat_startup(struct kmscon_seat *seat)
- {
-- int ret;
- struct kmscon_session *s;
-
- if (!seat)
- return;
-
-- ret = kmscon_dummy_register(&s, seat);
-- if (ret == -EOPNOTSUPP) {
-- log_notice("dummy sessions not compiled in");
-- } else if (ret) {
-- log_error("cannot register dummy session: %d", ret);
-- } else {
-- seat->dummy_sess = s;
-- kmscon_session_enable(s);
-- }
-+ seat_go_awake(seat);
-
-- if (seat->conf->terminal_session) {
-- ret = kmscon_terminal_register(&s, seat, uterm_vt_get_num(seat->vt));
-- if (ret == -EOPNOTSUPP)
-- log_notice("terminal support not compiled in");
-- else if (ret)
-- log_error("cannot register terminal session");
-- else
-- kmscon_session_enable(s);
-- }
-+ s = kmscon_seat_new_session(seat);
-+ if (s)
-+ seat_switch(seat, s);
-+ else
-+ log_error("cannot create new session on seat %s", seat->name);
-
- if (seat->conf->switchvt || uterm_vt_get_num(seat->vt) == 0)
- uterm_vt_activate(seat->vt);
-@@ -1339,30 +1116,6 @@ void kmscon_seat_startup(struct kmscon_seat *seat)
- uterm_monitor_scan(seat->mon, seat->name);
- }
-
--const char *kmscon_seat_get_name(struct kmscon_seat *seat)
--{
-- if (!seat)
-- return NULL;
--
-- return seat->name;
--}
--
--struct input *kmscon_seat_get_input(struct kmscon_seat *seat)
--{
-- if (!seat)
-- return NULL;
--
-- return seat->input;
--}
--
--struct ev_eloop *kmscon_seat_get_eloop(struct kmscon_seat *seat)
--{
-- if (!seat)
-- return NULL;
--
-- return seat->eloop;
--}
--
- struct conf_ctx *kmscon_seat_get_conf(struct kmscon_seat *seat)
- {
- if (!seat)
-@@ -1371,36 +1124,39 @@ struct conf_ctx *kmscon_seat_get_conf(struct kmscon_seat *seat)
- return seat->conf_ctx;
- }
-
--int kmscon_seat_register_session(struct kmscon_seat *seat, struct kmscon_session **out,
-- kmscon_session_cb_t cb, void *data)
-+static struct kmscon_session *kmscon_seat_new_session(struct kmscon_seat *seat)
- {
- struct kmscon_session *sess;
- struct shl_dlist *iter;
- struct kmscon_display *d;
-
-- if (!seat || !out)
-- return -EINVAL;
-+ if (!seat)
-+ return NULL;
-
- if (seat->conf->session_max && seat->session_count >= seat->conf->session_max) {
- log_warning("maximum number of sessions reached (%d), dropping new session",
- seat->conf->session_max);
-- return -EOVERFLOW;
-+ return NULL;
- }
-
- sess = malloc(sizeof(*sess));
- if (!sess) {
- log_error("cannot allocate memory for new session on seat %s", seat->name);
-- return -ENOMEM;
-+ return NULL;
- }
-
- log_debug("register session %p", sess);
-
- memset(sess, 0, sizeof(*sess));
-- sess->ref = 1;
- sess->seat = seat;
-- sess->cb = cb;
-- sess->data = data;
- sess->foreground = true;
-+ sess->term = terminal_new(sess, uterm_vt_get_num(seat->vt), seat->conf_ctx, seat->eloop,
-+ seat->input, seat->name);
-+ if (!sess->term) {
-+ log_error("cannot create terminal for new session on seat %s", seat->name);
-+ free(sess);
-+ return NULL;
-+ }
-
- /* register new sessions next to the current one */
- if (seat->current_sess)
-@@ -1409,39 +1165,18 @@ int kmscon_seat_register_session(struct kmscon_seat *seat, struct kmscon_session
- shl_dlist_link_tail(&seat->sessions, &sess->list);
-
- ++seat->session_count;
-- *out = sess;
-
- shl_dlist_for_each(iter, &seat->displays)
- {
- d = shl_dlist_entry(iter, struct kmscon_display, list);
-- session_call_display_new(sess, d->disp);
-+ terminal_add_display(sess->term, d->disp);
- }
--
-- return 0;
--}
--
--void kmscon_session_ref(struct kmscon_session *sess)
--{
-- if (!sess || !sess->ref)
-- return;
--
-- ++sess->ref;
-+ return sess;
- }
-
--void kmscon_session_unref(struct kmscon_session *sess)
--{
-- if (!sess || !sess->ref || --sess->ref)
-- return;
--
-- kmscon_session_unregister(sess);
-- free(sess);
--}
--
--void kmscon_session_unregister(struct kmscon_session *sess)
-+static void kmscon_session_unregister(struct kmscon_session *sess)
- {
- struct kmscon_seat *seat;
-- int ret;
-- bool forced = false;
-
- if (!sess || !sess->seat)
- return;
-@@ -1449,47 +1184,18 @@ void kmscon_session_unregister(struct kmscon_session *sess)
- log_debug("unregister session %p", sess);
-
- seat = sess->seat;
-- sess->enabled = false;
-- if (seat->dummy_sess == sess)
-- seat->dummy_sess = NULL;
-- seat_reschedule(seat);
-
- if (seat->current_sess == sess) {
-- ret = seat_pause(seat, true);
-- if (ret) {
-- forced = true;
-- log_warning("unregistering active session %p; skipping automatic "
-- "session-switch",
-- sess);
-- }
-+ terminal_deactivate(seat->current_sess->term);
-+ seat_next(seat);
- }
-
- shl_dlist_unlink(&sess->list);
- --seat->session_count;
- sess->seat = NULL;
-
-- session_call(sess, KMSCON_SESSION_UNREGISTER, NULL);
-- kmscon_session_unref(sess);
--
-- /* If this session was active and we couldn't deactivate it, then it
-- * might still have resources allocated that couldn't get freed. In this
-- * case we should not automatically switch to the next session as it is
-- * very likely that it will not be able to start.
-- * Instead, we stay inactive and wait for user/external input to switch
-- * to another session. This delay will then hopefully be long enough so
-- * all resources got freed. */
-- if (!forced)
-- seat_run(seat);
--}
--
--bool kmscon_session_is_registered(struct kmscon_session *sess)
--{
-- return sess && sess->seat;
--}
--
--bool kmscon_session_is_active(struct kmscon_session *sess)
--{
-- return sess && sess->seat && sess->seat->current_sess == sess;
-+ terminal_destroy(sess->term);
-+ free(sess);
- }
-
- int kmscon_session_set_foreground(struct kmscon_session *sess)
-@@ -1508,7 +1214,7 @@ int kmscon_session_set_foreground(struct kmscon_session *sess)
- if (ret)
- return ret;
-
-- ret = seat_go_foreground(seat, true);
-+ ret = seat_go_foreground(seat);
- if (ret)
- return ret;
- }
-@@ -1529,7 +1235,7 @@ int kmscon_session_set_background(struct kmscon_session *sess)
-
- seat = sess->seat;
- if (seat && seat->current_sess == sess && seat->foreground) {
-- ret = seat_go_background(seat, true);
-+ ret = seat_go_background(seat);
- if (ret)
- return ret;
- }
-@@ -1543,35 +1249,6 @@ bool kmscon_session_get_foreground(struct kmscon_session *sess)
- return sess->foreground;
- }
-
--void kmscon_session_enable(struct kmscon_session *sess)
--{
-- if (!sess || sess->enabled)
-- return;
--
-- log_debug("enable session %p", sess);
-- sess->enabled = true;
-- if (sess->seat &&
-- (!sess->seat->current_sess || sess->seat->current_sess == sess->seat->dummy_sess)) {
-- sess->seat->scheduled_sess = sess;
-- if (seat_has_schedule(sess->seat))
-- seat_switch(sess->seat);
-- }
--}
--
--void kmscon_session_disable(struct kmscon_session *sess)
--{
-- if (!sess || !sess->enabled)
-- return;
--
-- log_debug("disable session %p", sess);
-- sess->enabled = false;
--}
--
--bool kmscon_session_is_enabled(struct kmscon_session *sess)
--{
-- return sess && sess->enabled;
--}
--
- void kmscon_session_bell(struct kmscon_session *sess)
- {
- if (!sess || !sess->seat)
-@@ -1588,36 +1265,3 @@ void kmscon_session_set_leds(struct kmscon_session *sess, unsigned int scroll_lo
-
- input_set_leds(sess->seat->input, scroll_lock, num_lock, caps_lock);
- }
--
--void kmscon_session_notify_deactivated(struct kmscon_session *sess)
--{
-- struct kmscon_seat *seat;
-- int ret;
-- unsigned int sched;
--
-- if (!sess || !sess->seat)
-- return;
--
-- seat = sess->seat;
-- if (seat->current_sess != sess)
-- return;
--
-- sched = seat->async_schedule;
-- log_debug("session %p notified core about deactivation (schedule: %u)", sess, sched);
-- session_deactivate(sess);
-- seat_reschedule(seat);
--
-- if (sched == SCHEDULE_VT) {
-- ret = seat_go_background(seat, false);
-- if (ret)
-- return;
-- ret = seat_go_asleep(seat, false);
-- if (ret)
-- return;
-- uterm_vt_retry(seat->vt);
-- } else if (sched == SCHEDULE_UNREGISTER) {
-- kmscon_session_unregister(sess);
-- } else {
-- seat_switch(seat);
-- }
--}
-diff --git a/src/kmscon_seat.h b/src/kmscon_seat.h
-index c3fa707..31e8808 100644
---- a/src/kmscon_seat.h
-+++ b/src/kmscon_seat.h
-@@ -33,14 +33,9 @@
- #define KMSCON_SEAT_H
-
- #include <stdbool.h>
--#include <stdlib.h>
- #include "conf.h"
--#include "input/input.h"
- #include "kmscon_conf.h"
- #include "shl/eloop.h"
--#include "uterm_monitor.h"
--#include "uterm_vt.h"
--#include "video/video.h"
-
- struct kmscon_seat;
- struct kmscon_session;
-@@ -53,54 +48,22 @@ enum kmscon_seat_event {
-
- typedef int (*kmscon_seat_cb_t)(struct kmscon_seat *seat, unsigned int event, void *data);
-
--enum kmscon_session_event_type {
-- KMSCON_SESSION_DISPLAY_NEW,
-- KMSCON_SESSION_DISPLAY_GONE,
-- KMSCON_SESSION_DISPLAY_REFRESH,
-- KMSCON_SESSION_ACTIVATE,
-- KMSCON_SESSION_DEACTIVATE,
-- KMSCON_SESSION_UNREGISTER,
--};
--
--struct kmscon_session_event {
-- unsigned int type;
-- struct display *disp;
--};
--
--typedef int (*kmscon_session_cb_t)(struct kmscon_session *session,
-- struct kmscon_session_event *event, void *data);
--
- int kmscon_seat_new(struct kmscon_seat **out, struct conf_ctx *main_conf,
- struct kmscon_conf_t *conf, struct ev_eloop *eloop, kmscon_seat_cb_t cb,
- void *data);
- void kmscon_seat_free(struct kmscon_seat *seat);
- void kmscon_seat_startup(struct kmscon_seat *seat);
-+int kmscon_seat_update_xkb_layout(struct kmscon_seat *seat, const char *model, const char *layout,
-+ const char *variant, const char *options);
-
--const char *kmscon_seat_get_name(struct kmscon_seat *seat);
--struct input *kmscon_seat_get_input(struct kmscon_seat *seat);
--struct ev_eloop *kmscon_seat_get_eloop(struct kmscon_seat *seat);
- struct conf_ctx *kmscon_seat_get_conf(struct kmscon_seat *seat);
-
--int kmscon_seat_register_session(struct kmscon_seat *seat, struct kmscon_session **out,
-- kmscon_session_cb_t cb, void *data);
--
--void kmscon_session_ref(struct kmscon_session *sess);
--void kmscon_session_unref(struct kmscon_session *sess);
--void kmscon_session_unregister(struct kmscon_session *sess);
--bool kmscon_session_is_registered(struct kmscon_session *sess);
--
--bool kmscon_session_is_active(struct kmscon_session *sess);
- int kmscon_session_set_foreground(struct kmscon_session *sess);
- int kmscon_session_set_background(struct kmscon_session *sess);
- bool kmscon_session_get_foreground(struct kmscon_session *sess);
-
--void kmscon_session_enable(struct kmscon_session *sess);
--void kmscon_session_disable(struct kmscon_session *sess);
--bool kmscon_session_is_enabled(struct kmscon_session *sess);
- void kmscon_session_bell(struct kmscon_session *sess);
- void kmscon_session_set_leds(struct kmscon_session *sess, unsigned int scroll_lock,
- unsigned int num_lock, unsigned int caps_lock);
-
--void kmscon_session_notify_deactivated(struct kmscon_session *sess);
--
- #endif /* KMSCON_SEAT_H */
-diff --git a/src/kmscon_terminal.c b/src/kmscon_terminal.c
-index 391cd53..c5562f6 100644
---- a/src/kmscon_terminal.c
-+++ b/src/kmscon_terminal.c
-@@ -645,7 +645,7 @@ static void rotate_ccw_all(struct kmscon_terminal *term)
- update_pointer_max_all(term);
- }
-
--static int add_display(struct kmscon_terminal *term, struct display *disp)
-+int terminal_add_display(struct kmscon_terminal *term, struct display *disp)
- {
- struct shl_dlist *iter;
- struct screen *scr;
-@@ -741,7 +741,7 @@ static void free_screen(struct screen *scr, bool update)
- terminal_update_size_notify(term);
- }
-
--static void rm_display(struct kmscon_terminal *term, struct display *disp)
-+void terminal_rm_display(struct kmscon_terminal *term, struct display *disp)
- {
- struct shl_dlist *iter;
- struct screen *scr;
-@@ -1080,7 +1080,30 @@ static void terminal_close(struct kmscon_terminal *term)
- term->opened = false;
- }
-
--static void terminal_destroy(struct kmscon_terminal *term)
-+void terminal_refresh_displays(struct kmscon_terminal *term)
-+{
-+ if (term->pointer.visible)
-+ hw_cursor_show(term, term->pointer.x, term->pointer.y);
-+ redraw_all_text(term);
-+}
-+
-+void terminal_activate(struct kmscon_terminal *term)
-+{
-+ term->awake = true;
-+ if (!term->opened)
-+ terminal_open(term);
-+ if (term->pointer.visible)
-+ hw_cursor_show(term, term->pointer.x, term->pointer.y);
-+ redraw_all_text(term);
-+}
-+
-+void terminal_deactivate(struct kmscon_terminal *term)
-+{
-+ term->awake = false;
-+ hw_cursor_hide(term);
-+}
-+
-+void terminal_destroy(struct kmscon_terminal *term)
- {
- log_debug("free terminal object %p", term);
-
-@@ -1099,43 +1122,6 @@ static void terminal_destroy(struct kmscon_terminal *term)
- free(term);
- }
-
--static int session_event(struct kmscon_session *session, struct kmscon_session_event *ev,
-- void *data)
--{
-- struct kmscon_terminal *term = data;
--
-- switch (ev->type) {
-- case KMSCON_SESSION_DISPLAY_NEW:
-- add_display(term, ev->disp);
-- break;
-- case KMSCON_SESSION_DISPLAY_GONE:
-- rm_display(term, ev->disp);
-- break;
-- case KMSCON_SESSION_DISPLAY_REFRESH:
-- if (term->pointer.visible)
-- hw_cursor_show(term, term->pointer.x, term->pointer.y);
-- redraw_all_text(term);
-- break;
-- case KMSCON_SESSION_ACTIVATE:
-- term->awake = true;
-- if (!term->opened)
-- terminal_open(term);
-- if (term->pointer.visible)
-- hw_cursor_show(term, term->pointer.x, term->pointer.y);
-- redraw_all_text(term);
-- break;
-- case KMSCON_SESSION_DEACTIVATE:
-- term->awake = false;
-- hw_cursor_hide(term);
-- break;
-- case KMSCON_SESSION_UNREGISTER:
-- terminal_destroy(term);
-- break;
-- }
--
-- return 0;
--}
--
- static void pty_input(struct kmscon_pty *pty, const char *u8, size_t len, void *data)
- {
- struct kmscon_terminal *term = data;
-@@ -1163,26 +1149,25 @@ static void write_event(struct tsm_vte *vte, const char *u8, size_t len, void *d
- kmscon_pty_write(term->pty, u8, len);
- }
-
--int kmscon_terminal_register(struct kmscon_session **out, struct kmscon_seat *seat,
-- unsigned int vtnr)
-+struct kmscon_terminal *terminal_new(struct kmscon_session *session, unsigned int vtnr,
-+ struct conf_ctx *conf_ctx, struct ev_eloop *eloop,
-+ struct input *input, const char *seat_name)
- {
- struct kmscon_terminal *term;
- int ret;
-
-- if (!out || !seat)
-- return -EINVAL;
--
- term = malloc(sizeof(*term));
- if (!term)
-- return -ENOMEM;
-+ return NULL;
-
- memset(term, 0, sizeof(*term));
- term->ref = 1;
-- term->eloop = kmscon_seat_get_eloop(seat);
-- term->input = kmscon_seat_get_input(seat);
-+ term->session = session;
-+ term->eloop = eloop;
-+ term->input = input;
- shl_dlist_init(&term->screens);
-
-- term->conf_ctx = kmscon_seat_get_conf(seat);
-+ term->conf_ctx = conf_ctx;
- term->conf = conf_ctx_get_mem(term->conf_ctx);
-
- strncpy(term->font_attr.name, term->conf->font_name, KMSCON_FONT_MAX_NAME - 1);
-@@ -1221,7 +1206,7 @@ int kmscon_terminal_register(struct kmscon_session **out, struct kmscon_seat *se
- goto err_font;
-
- ret = kmscon_pty_set_conf(term->pty, term->conf->term, "truecolor", term->conf->argv,
-- kmscon_seat_get_name(seat), vtnr, term->conf->reset_env,
-+ seat_name, vtnr, term->conf->reset_env,
- term->conf->backspace_delete);
- if (ret)
- goto err_pty;
-@@ -1241,20 +1226,11 @@ int kmscon_terminal_register(struct kmscon_session **out, struct kmscon_seat *se
- goto err_input;
- }
-
-- ret = kmscon_seat_register_session(seat, &term->session, session_event, term);
-- if (ret) {
-- log_error("cannot register session for terminal: %d", ret);
-- goto err_pointer;
-- }
--
- ev_eloop_ref(term->eloop);
- input_ref(term->input);
-- *out = term->session;
- log_debug("new terminal object %p", term);
-- return 0;
-+ return term;
-
--err_pointer:
-- input_unregister_pointer_cb(term->input, pointer_event, term);
- err_input:
- input_unregister_key_cb(term->input, input_event, term);
- err_ptyfd:
-@@ -1269,5 +1245,5 @@ err_con:
- tsm_screen_unref(term->console);
- err_free:
- free(term);
-- return ret;
-+ return NULL;
- }
-diff --git a/src/kmscon_terminal.h b/src/kmscon_terminal.h
-index cd74bab..552242c 100644
---- a/src/kmscon_terminal.h
-+++ b/src/kmscon_terminal.h
-@@ -33,23 +33,21 @@
- #ifndef KMSCON_TERMINAL_H
- #define KMSCON_TERMINAL_H
-
--#include <errno.h>
--#include <stdlib.h>
--#include "kmscon_seat.h"
--
--#ifdef BUILD_ENABLE_SESSION_TERMINAL
--
--int kmscon_terminal_register(struct kmscon_session **out, struct kmscon_seat *seat,
-- unsigned int vtnr);
--
--#else /* !BUILD_ENABLE_SESSION_TERMINAL */
--
--static inline int kmscon_terminal_register(struct kmscon_session **out, struct kmscon_seat *seat,
-- unsigned int vtnr)
--{
-- return -EOPNOTSUPP;
--}
--
--#endif /* BUILD_ENABLE_SESSION_TERMINAL */
-+struct conf_ctx;
-+struct display;
-+struct ev_eloop;
-+struct kmscon_terminal;
-+struct kmscon_session;
-+struct input;
-+
-+struct kmscon_terminal *terminal_new(struct kmscon_session *session, unsigned int vtnr,
-+ struct conf_ctx *conf_ctx, struct ev_eloop *eloop,
-+ struct input *input, const char *seat_name);
-+void terminal_destroy(struct kmscon_terminal *term);
-+int terminal_add_display(struct kmscon_terminal *term, struct display *disp);
-+void terminal_rm_display(struct kmscon_terminal *term, struct display *disp);
-+void terminal_refresh_displays(struct kmscon_terminal *term);
-+void terminal_activate(struct kmscon_terminal *term);
-+void terminal_deactivate(struct kmscon_terminal *term);
-
- #endif /* KMSCON_TERMINAL_H */
-diff --git a/src/meson.build b/src/meson.build
-index 9547fe1..1c4ba12 100644
---- a/src/meson.build
-+++ b/src/meson.build
-@@ -88,16 +88,27 @@ kmscon_srcs = [
- 'kmscon_conf.c',
- 'kmscon_issue.c',
- 'kmscon_main.c',
-+ 'kmscon_terminal.c',
- ]
--if enable_session_dummy
-- kmscon_srcs += 'kmscon_dummy.c'
--endif
--if enable_session_terminal
-- kmscon_srcs += 'kmscon_terminal.c'
-+kmscon_dep = [xkbcommon_deps,
-+ libtsm_deps,
-+ threads_deps,
-+ dl_deps,
-+ conf_deps,
-+ shl_deps,
-+ eloop_deps,
-+ uterm_deps,
-+ render_deps,
-+ font_deps,
-+]
-+
-+if enable_dbus
-+ kmscon_srcs += 'dbus.c'
-+ kmscon_dep += dbus_deps
- endif
- kmscon = executable('kmscon', kmscon_srcs,
-- dependencies: [xkbcommon_deps, libtsm_deps, threads_deps, dl_deps, conf_deps, shl_deps, eloop_deps, uterm_deps, render_deps, font_deps],
-+ dependencies: kmscon_dep,
- export_dynamic: true,
- install: true,
-- install_dir: libexecdir,
-+ install_dir: bindir,
- )
-diff --git a/src/shl/dlist.h b/src/shl/dlist.h
-index 83cd233..0af5094 100644
---- a/src/shl/dlist.h
-+++ b/src/shl/dlist.h
-@@ -102,6 +102,16 @@ static inline bool shl_dlist_empty(struct shl_dlist *head)
-
- #define shl_dlist_last(head, type, member) shl_dlist_entry((head)->prev, type, member)
-
-+#define shl_dlist_next(iter, head, member) \
-+ ((iter)->member.next == (head) \
-+ ? NULL \
-+ : shl_dlist_entry((iter)->member.next, typeof(*iter), list))
-+
-+#define shl_dlist_prev(iter, head, member) \
-+ ((iter)->member.prev == (head) \
-+ ? NULL \
-+ : shl_dlist_entry((iter)->member.prev, typeof(*iter), list))
-+
- #define shl_dlist_for_each(iter, head) for (iter = (head)->next; iter != (head); iter = iter->next)
-
- #define shl_dlist_for_each_but_one(iter, start, head) \
-diff --git a/tests/test_input.c b/tests/test_input.c
-index 0ecefc0..b218edc 100644
---- a/tests/test_input.c
-+++ b/tests/test_input.c
-@@ -128,11 +128,12 @@ static void setup_input(struct uterm_monitor *mon)
- if (ret)
- return;
- ret = input_set_keymap(input, input_conf.xkb_model, input_conf.xkb_layout,
-- input_conf.xkb_variant, input_conf.xkb_options, input_conf.locale,
-- input_conf.xkb_keymap, input_conf.xkb_compose_file,
-- compose_file_len);
-+ input_conf.xkb_variant, input_conf.xkb_options,
-+ input_conf.xkb_keymap);
- if (ret)
- return;
-+
-+ input_set_compose(input, input_conf.locale, compose_file, compose_file_len);
- input_set_conf(input, 250, 50, true);
- ret = input_register_key_cb(input, input_arrived, NULL);
- if (ret)
---
-2.54.0
-
diff --git a/sources b/sources
index d2599b1..744f250 100644
--- a/sources
+++ b/sources
@@ -1,2 +1 @@
-SHA512 (kmscon-10.0.0.tar.gz) = da3b7f2d8aaa624561369939928dbc479da4abd9600f623d3eb49a4674674b84f200c72618fa57996bb739b5b0600eabd9ff27b46c3808e0c52bc80416e096b5
-SHA512 (kmscon-9.3.5.tar.gz) = 3595fef9af5aea93dae5c8fad2b9743f167d0224bec62a5f38f20a385832aa4afb8f268b777b523c9ec55db0e9f88e85cecbddb73c40441598d151cc6cf651e4
+SHA512 (kmscon-10.0.1.tar.gz) = 9db07651e426763bfeb05a7af013945f13727b37369b0a5c1faef28198e96cf0d27edd50b61d3d434111d315808f8f301465cbf8d10734d29ba96890f1d930df
reply other threads:[~2026-07-02 16:23 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=178300942664.1.6854664993962553899.rpms-kmscon-48ceef03d3a4@fedoraproject.org \
--to=jfalempe@redhat.com \
--cc=git-commits@fedoraproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox