1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "logind-seat.h"
27 #include "dbus-common.h"
30 #define BUS_SEAT_INTERFACE \
31 " <interface name=\"org.freedesktop.login1.Seat\">\n" \
32 " <method name=\"Terminate\"/>\n" \
33 " <method name=\"ActivateSession\">\n" \
34 " <arg name=\"id\" type=\"s\"/>\n" \
36 " <property name=\"Id\" type=\"s\" access=\"read\"/>\n" \
37 " <property name=\"ActiveSession\" type=\"so\" access=\"read\"/>\n" \
38 " <property name=\"CanMultiSession\" type=\"b\" access=\"read\"/>\n" \
39 " <property name=\"Sessions\" type=\"a(so)\" access=\"read\"/>\n" \
40 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
41 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
42 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
45 #define INTROSPECTION \
46 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
49 BUS_PROPERTIES_INTERFACE \
51 BUS_INTROSPECTABLE_INTERFACE \
54 #define INTERFACES_LIST \
55 BUS_GENERIC_INTERFACES_LIST \
56 "org.freedesktop.login1.Seat\0"
58 static int bus_seat_append_active(DBusMessageIter *i, const char *property, void *data) {
61 const char *id, *path;
68 if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
73 path = p = session_bus_path(s->active);
82 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
83 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path)) {
90 if (!dbus_message_iter_close_container(i, &sub))
96 static int bus_seat_append_sessions(DBusMessageIter *i, const char *property, void *data) {
97 DBusMessageIter sub, sub2;
105 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(so)", &sub))
108 LIST_FOREACH(sessions_by_seat, session, s->sessions) {
111 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
114 p = session_bus_path(session);
118 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
119 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
126 if (!dbus_message_iter_close_container(&sub, &sub2))
130 if (!dbus_message_iter_close_container(i, &sub))
136 static int bus_seat_append_multi_session(DBusMessageIter *i, const char *property, void *data) {
144 b = seat_can_multi_session(s);
146 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
152 static int bus_seat_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
160 b = seat_get_idle_hint(s, NULL) > 0;
161 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
167 static int bus_seat_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
176 seat_get_idle_hint(s, &t);
177 k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
179 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &k))
185 static int get_seat_for_path(Manager *m, const char *path, Seat **_s) {
193 if (!startswith(path, "/org/freedesktop/login1/seat/"))
196 id = bus_path_unescape(path + 29);
200 s = hashmap_get(m->seats, id);
210 static const BusProperty bus_login_seat_properties[] = {
211 { "Id", bus_property_append_string, "s", offsetof(Seat, id), true },
212 { "ActiveSession", bus_seat_append_active, "(so)", 0 },
213 { "CanMultiSession", bus_seat_append_multi_session, "b", 0 },
214 { "Sessions", bus_seat_append_sessions, "a(so)", 0 },
215 { "IdleHint", bus_seat_append_idle_hint, "b", 0 },
216 { "IdleSinceHint", bus_seat_append_idle_hint_since, "t", 0 },
217 { "IdleSinceHintMonotonic", bus_seat_append_idle_hint_since, "t", 0 },
221 static DBusHandlerResult seat_message_dispatch(
223 DBusConnection *connection,
224 DBusMessage *message) {
227 DBusMessage *reply = NULL;
234 dbus_error_init(&error);
236 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Seat", "Terminate")) {
238 r = seat_stop_sessions(s);
240 return bus_send_error_reply(connection, message, NULL, r);
242 reply = dbus_message_new_method_return(message);
246 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Seat", "ActivateSession")) {
250 if (!dbus_message_get_args(
253 DBUS_TYPE_STRING, &name,
255 return bus_send_error_reply(connection, message, &error, -EINVAL);
257 session = hashmap_get(s->manager->sessions, name);
258 if (!session || session->seat != s)
259 return bus_send_error_reply(connection, message, &error, -ENOENT);
261 r = session_activate(session);
263 return bus_send_error_reply(connection, message, NULL, r);
265 reply = dbus_message_new_method_return(message);
269 const BusBoundProperties bps[] = {
270 { "org.freedesktop.login1.Seat", bus_login_seat_properties, s },
273 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
277 if (!dbus_connection_send(connection, reply, NULL))
280 dbus_message_unref(reply);
283 return DBUS_HANDLER_RESULT_HANDLED;
287 dbus_message_unref(reply);
289 dbus_error_free(&error);
291 return DBUS_HANDLER_RESULT_NEED_MEMORY;
294 static DBusHandlerResult seat_message_handler(
295 DBusConnection *connection,
296 DBusMessage *message,
299 Manager *m = userdata;
303 r = get_seat_for_path(m, dbus_message_get_path(message), &s);
307 return DBUS_HANDLER_RESULT_NEED_MEMORY;
313 dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown seat");
314 return bus_send_error_reply(connection, message, &e, r);
317 return bus_send_error_reply(connection, message, NULL, r);
320 return seat_message_dispatch(s, connection, message);
323 const DBusObjectPathVTable bus_seat_vtable = {
324 .message_function = seat_message_handler
327 char *seat_bus_path(Seat *s) {
332 t = bus_path_escape(s->id);
336 r = strappend("/org/freedesktop/login1/seat/", t);
342 int seat_send_signal(Seat *s, bool new_seat) {
349 m = dbus_message_new_signal("/org/freedesktop/login1",
350 "org.freedesktop.login1.Manager",
351 new_seat ? "SeatNew" : "SeatRemoved");
356 p = seat_bus_path(s);
360 if (!dbus_message_append_args(
362 DBUS_TYPE_STRING, &s->id,
363 DBUS_TYPE_OBJECT_PATH, &p,
367 if (!dbus_connection_send(s->manager->bus, m, NULL))
373 dbus_message_unref(m);
379 int seat_send_changed(Seat *s, const char *properties) {
389 p = seat_bus_path(s);
393 m = bus_properties_changed_new(p, "org.freedesktop.login1.Seat", properties);
397 if (!dbus_connection_send(s->manager->bus, m, NULL))
404 dbus_message_unref(m);