modeset.c revision 23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek This file is part of systemd.
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek systemd is free software; you can redistribute it and/or modify it
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek under the terms of the GNU Lesser General Public License as published by
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek the Free Software Foundation; either version 2.1 of the License, or
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek (at your option) any later version.
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek systemd is distributed in the hope that it will be useful, but
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek WITHOUT ANY WARRANTY; without even the implied warranty of
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek Lesser General Public License for more details.
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek You should have received a copy of the GNU Lesser General Public License
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek along with systemd; If not, see <http://www.gnu.org/licenses/>.
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering * Modeset Testing
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering * The modeset tool attaches to the session of the caller and shows a
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering * test-pattern on all displays of this session. It is meant as debugging tool
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering * for the grdev infrastructure.
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmekstatic int modeset_exit_fn(sd_event_source *source, void *userdata) {
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek grdev_session_restore(m->grdev_session);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmekstatic Modeset *modeset_free(Modeset *m) {
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek m->grdev_session = grdev_session_free(m->grdev_session);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek m->grdev = grdev_context_unref(m->grdev);
8eea868708923a092ee85d6146ba4c04b7baea06Zbigniew Jędrzejewski-Szmek m->sysview = sysview_context_free(m->sysview);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek m->exit_src = sd_event_source_unref(m->exit_src);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek m->event = sd_event_unref(m->event);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-SzmekDEFINE_TRIVIAL_CLEANUP_FUNC(Modeset*, modeset_free);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmekstatic bool is_my_tty(const char *session) {
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek /* Using logind's Controller API is highly fragile if there is already
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek * a session controller running. If it is registered as controller
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek * itself, TakeControl will simply fail. But if its a legacy controller
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek * that does not use logind's controller API, we must never register
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek * our own controller. Otherwise, we really mess up the VT. Therefore,
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek * only run in managed mode if there's no-one else. Furthermore, never
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek * try to access graphics devices if there's someone else. Unlike input
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek * devices, graphics devies cannot be shared easily. */
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sd_session_get_vt(session, &vtnr);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek if (r < 0 || vtnr < 1 || vtnr > 63)
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek if (r < 0 || minor(st.st_rdev) != vtnr)
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek _cleanup_(modeset_freep) Modeset *m = NULL;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sd_pid_get_session(getpid(), &m->session);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return log_error_errno(r, "Cannot retrieve logind session: %m");
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sd_session_get_seat(m->session, &m->seat);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return log_error_errno(r, "Cannot retrieve seat of logind session: %m");
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek m->my_tty = is_my_tty(m->session);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek m->managed = m->my_tty && geteuid() > 0;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek m->r_up = m->g_up = m->b_up = true;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sd_event_default(&m->event);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sd_bus_open_system(&m->bus);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sd_bus_attach_event(m->bus, m->event, SD_EVENT_PRIORITY_NORMAL);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sd_event_add_exit(m->event, &m->exit_src, modeset_exit_fn, m);
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering /* schedule before sd-bus close */
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sd_event_source_set_priority(m->exit_src, -10);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = grdev_context_new(&m->grdev, m->event, m->bus);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmekstatic uint8_t next_color(bool *up, uint8_t cur, unsigned int mod) {
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek /* generate smoothly morphing colors */
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek next = cur + (*up ? 1 : -1) * (rand() % mod);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek if ((*up && next < cur) || (!*up && next > cur)) {
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmekstatic void modeset_draw(Modeset *m, const grdev_display_target *t) {
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek assert(t->back->format == DRM_FORMAT_XRGB8888 || t->back->format == DRM_FORMAT_ARGB8888);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek for (j = 0; j < t->height; ++j) {
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek for (k = 0; k < t->width; ++k) {
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek b[k] = (0xff << 24) | (m->r << 16) | (m->g << 8) | m->b;
const grdev_display_target *t;
GRDEV_DISPLAY_FOREACH_TARGET(d, t) {
modeset_draw(m, t);
grdev_display_flip_target(d, t);
case GRDEV_EVENT_DISPLAY_ADD:
sysview_device *d;
const char *name;
flags = 0;
if (m->managed)
m->grdev,
name,
if (m->managed) {
if (!m->grdev_session)
return -errno;
assert(m);
if (!m->my_tty) {
return -EACCES;
goto out;
r = -errno;
goto out;
r = -errno;
goto out;
out:
static int help(void) {
help();
case ARG_VERSION:
return -EINVAL;
return -EINVAL;
log_open();
goto finish;
r = modeset_new(&m);
goto finish;
r = modeset_run(m);