A new ioctl TIOCGDISPLAYS allow detecting which displays the terminal has associated. The ability to set a keyboard layout can be detected with tcgetblob kblayout. Improve the user-space multi-monitor support while here. The kernel now sets TERM rather than init(8). This is a compatible ABI change riding on the previous commit's bump.
133 lines
3.8 KiB
C
133 lines
3.8 KiB
C
/*
|
|
* Copyright (c) 2012, 2013, 2014, 2016 Jonas 'Sortie' Termansen.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
* session.c
|
|
* Handles session management.
|
|
*/
|
|
|
|
#include <sys/ioctl.h>
|
|
#include <sys/display.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/types.h>
|
|
|
|
#include <error.h>
|
|
#include <fcntl.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <dispd.h>
|
|
|
|
#include "session.h"
|
|
|
|
struct dispd_session* global_session = NULL;
|
|
|
|
bool dispd__session_initialize(int* argc, char*** argv)
|
|
{
|
|
(void) argc;
|
|
(void) argv;
|
|
size_t size = sizeof(struct dispd_session);
|
|
global_session = (struct dispd_session*) malloc(size);
|
|
if ( !global_session )
|
|
return false;
|
|
memset(global_session, 0, sizeof(*global_session));
|
|
int tty_fd = open("/dev/tty", O_RDWR);
|
|
if ( tty_fd < 0 )
|
|
return free(global_session), false;
|
|
struct tiocgdisplay display;
|
|
struct tiocgdisplays gdisplays;
|
|
memset(&gdisplays, 0, sizeof(gdisplays));
|
|
gdisplays.count = 1;
|
|
gdisplays.displays = &display;
|
|
bool fail = ioctl(tty_fd, TIOCGDISPLAYS, &gdisplays) < 0 ||
|
|
gdisplays.count == 0;
|
|
close(tty_fd);
|
|
if ( fail )
|
|
return free(global_session), false;
|
|
global_session->device = display.device;
|
|
global_session->connector = display.connector;
|
|
return true;
|
|
}
|
|
|
|
struct dispd_session* dispd_attach_default_session()
|
|
{
|
|
global_session->refcount++;
|
|
return global_session;
|
|
}
|
|
|
|
bool dispd_detach_session(struct dispd_session* session)
|
|
{
|
|
session->refcount--;
|
|
return true;
|
|
}
|
|
|
|
bool dispd_session_setup_game_rgba(struct dispd_session* session)
|
|
{
|
|
if ( session->is_rgba )
|
|
return true;
|
|
if ( session->current_window )
|
|
return false;
|
|
struct dispmsg_get_crtc_mode msg;
|
|
msg.msgid = DISPMSG_GET_CRTC_MODE;
|
|
msg.device = session->device;
|
|
msg.connector = session->connector;
|
|
if ( dispmsg_issue(&msg, sizeof(msg)) != 0 )
|
|
return false;
|
|
if ( !(msg.mode.control & 1) || msg.mode.fb_format != 32 )
|
|
{
|
|
pid_t childpid = fork();
|
|
if ( childpid < 0 )
|
|
return false;
|
|
if ( childpid )
|
|
{
|
|
int status;
|
|
waitpid(childpid, &status, 0);
|
|
return session->is_rgba = (WIFEXITED(status) && !WEXITSTATUS(status));
|
|
}
|
|
const char* chvideomode = "chvideomode";
|
|
#if 1
|
|
// TODO chvideomode currently launches --bpp 32 as a program...
|
|
execlp(chvideomode, chvideomode, (const char*) NULL);
|
|
#else
|
|
execlp(chvideomode, chvideomode,
|
|
"--bpp", "32",
|
|
"--show-graphics", "true",
|
|
"--show-text", "false",
|
|
(const char*) NULL);
|
|
#endif
|
|
perror(chvideomode);
|
|
exit(127);
|
|
}
|
|
|
|
// HACK: The console may be rendered asynchronously and it might still be
|
|
// rendering to the framebuffer, however this process is about to do
|
|
// bitmapped graphics to the framebuffer as well. Since there is no
|
|
// synchronization with the terminal except not writing to it, there
|
|
// is a small window where both are fighting for the framebuffer.
|
|
// We can resolve this issue by simply fsync()ing the terminal, which
|
|
// causes the scheduled console rendering to finish before returning.
|
|
int tty_fd = open("/dev/tty", O_WRONLY);
|
|
if ( 0 <= tty_fd )
|
|
{
|
|
fsync(tty_fd);
|
|
close(tty_fd);
|
|
}
|
|
|
|
return session->is_rgba = true;
|
|
}
|