Detect whether the terminal has a display and a keyboard layout.

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.
This commit is contained in:
Jonas 'Sortie' Termansen 2016-11-19 16:44:35 +01:00
parent db7182ddc3
commit 6ef5a5cee3
12 changed files with 179 additions and 46 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012 Jonas 'Sortie' Termansen.
* Copyright (c) 2012, 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
@ -29,6 +29,7 @@ struct dispd_framebuffer
int bpp;
int width;
int height;
uint64_t fb_location;
};
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012 Jonas 'Sortie' Termansen.
* 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
@ -17,9 +17,10 @@
* Handles session management.
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/display.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <error.h>
#include <fcntl.h>
@ -34,9 +35,6 @@
#include "session.h"
static const uint64_t ONE_AND_ONLY_DEVICE = 0;
static const uint64_t ONE_AND_ONLY_CONNECTOR = 0;
struct dispd_session* global_session = NULL;
bool dispd__session_initialize(int* argc, char*** argv)
@ -48,8 +46,21 @@ bool dispd__session_initialize(int* argc, char*** argv)
if ( !global_session )
return false;
memset(global_session, 0, sizeof(*global_session));
global_session->device = ONE_AND_ONLY_DEVICE;
global_session->connector = ONE_AND_ONLY_CONNECTOR;
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;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012 Jonas 'Sortie' Termansen.
* 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
@ -17,8 +17,8 @@
* Handles windows.
*/
#include <sys/types.h>
#include <sys/display.h>
#include <sys/types.h>
#include <fcntl.h>
#include <ioleast.h>
@ -102,6 +102,7 @@ struct dispd_framebuffer* dispd_begin_render(struct dispd_window* window)
fb->pitch = fb->width * fb->bpp / 8;
fb->datasize = fb->pitch * fb->height;
fb->data = (uint8_t*) request_buffer(window, fb->datasize);
fb->fb_location = msg.mode.fb_location;
if ( !fb->data ) { free(fb); return NULL; }
return fb;
}
@ -113,7 +114,7 @@ bool dispd_finish_render(struct dispd_framebuffer* fb)
struct dispmsg_write_memory msg;
msg.msgid = DISPMSG_WRITE_MEMORY;
msg.device = window->session->device;
msg.offset = 0;
msg.offset = fb->fb_location;
msg.size = fb->datasize;
msg.src = fb->data;
if ( dispmsg_issue(&msg, sizeof(msg)) == 0 )

View File

@ -18,6 +18,7 @@
*/
#include <sys/display.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
@ -429,6 +430,14 @@ static void set_hostname(void)
static void set_kblayout(void)
{
int tty_fd = open("/dev/tty", O_RDWR);
if ( !tty_fd )
return warning("unable to set keyboard layout: /dev/tty: %m");
bool unsupported = tcgetblob(tty_fd, "kblayout", NULL, 0) < 0 &&
(errno == ENOTTY || errno == ENOENT);
close(tty_fd);
if ( unsupported )
return;
FILE* fp = fopen("/etc/kblayout", "r");
if ( !fp && errno == ENOENT )
return;
@ -440,7 +449,11 @@ static void set_kblayout(void)
return warning("unable to set keyboard layout: /etc/kblayout: %m");
pid_t child_pid = fork();
if ( child_pid < 0 )
return warning("unable to set keyboard layout: fork: %m");
{
free(kblayout);
warning("unable to set keyboard layout: fork: %m");
return;
}
if ( !child_pid )
{
execlp("chkblayout", "chkblayout", "--", kblayout, (const char*) NULL);
@ -454,6 +467,19 @@ static void set_kblayout(void)
static void set_videomode(void)
{
int tty_fd = open("/dev/tty", O_RDWR);
if ( !tty_fd )
return warning("unable to set video mode: /dev/tty: %m");
struct tiocgdisplay display;
struct tiocgdisplays gdisplays;
memset(&gdisplays, 0, sizeof(gdisplays));
gdisplays.count = 1;
gdisplays.displays = &display;
bool unsupported = ioctl(tty_fd, TIOCGDISPLAYS, &gdisplays) < 0 ||
gdisplays.count == 0;
close(tty_fd);
if ( unsupported )
return;
FILE* fp = fopen("/etc/videomode", "r");
if ( !fp && errno == ENOENT )
return;
@ -476,8 +502,8 @@ static void set_videomode(void)
struct dispmsg_get_crtc_mode get_mode;
memset(&get_mode, 0, sizeof(get_mode));
get_mode.msgid = DISPMSG_GET_CRTC_MODE;
get_mode.device = 0;
get_mode.connector = 0;
get_mode.device = display.device;
get_mode.connector = display.connector;
// Don't set the resolution if it's already correct.
if ( dispmsg_issue(&get_mode, sizeof(get_mode)) == 0 )
{
@ -530,10 +556,6 @@ static void init_early(void)
// Set up the PATH variable.
if ( setenv("PATH", "/bin:/sbin", 1) < 0 )
fatal("setenv: %m");
// Set the terminal type.
if ( setenv("TERM", "sortix", 1) < 0 )
fatal("setenv: %m");
}
static bool is_chain_init_mountpoint(const struct mountpoint* mountpoint)

View File

@ -161,6 +161,18 @@ struct dispmsg_read_memory
uint8_t* dst; // in, *out
};
struct tiocgdisplay
{
uint64_t device;
uint64_t connector;
};
struct tiocgdisplays
{
size_t count; // in, out
struct tiocgdisplay* displays; // in, *out
};
#ifdef __cplusplus
} /* extern "C" */
#endif

View File

@ -38,5 +38,6 @@
#define TIOCGPTLCK __IOCTL(5, __IOCTL_TYPE_PTR)
#define TIOCGNAME __IOCTL(6, __IOCTL_TYPE_PTR)
#define TIOCGPTN __IOCTL(7, __IOCTL_TYPE_PTR)
#define TIOCGDISPLAYS __IOCTL(8, __IOCTL_TYPE_PTR)
#endif

View File

@ -719,8 +719,8 @@ static void InitThread(void* /*user*/)
Log::PrintF("\r\e[m\e[J");
int envc = 0;
const char* envp[] = { NULL };
int envc = 1;
const char* envp[] = { "TERM=sortix", NULL };
struct thread_registers regs;
assert((((uintptr_t) &regs) & (alignof(regs)-1)) == 0);

View File

@ -26,6 +26,7 @@
#include <string.h>
#include <wchar.h>
#include <sortix/display.h>
#include <sortix/fcntl.h>
#include <sortix/ioctl.h>
#include <sortix/keycodes.h>
@ -332,6 +333,27 @@ int LogTerminal::ioctl(ioctx_t* ctx, int cmd, uintptr_t arg)
return -1;
return 0;
}
else if ( cmd == TIOCGDISPLAYS )
{
struct tiocgdisplays* input = (struct tiocgdisplays*) arg;
struct tiocgdisplays gdisplays;
if ( !ctx->copy_from_src(&gdisplays, input, sizeof(gdisplays)) )
return -1;
if ( 0 < gdisplays.count )
{
struct tiocgdisplay display;
memset(&display, 0, sizeof(display));
display.device = 0;
display.connector = 0;
if ( !ctx->copy_to_dest(gdisplays.displays, &display,
sizeof(display)) )
return -1;
}
gdisplays.count = 1;
if ( !ctx->copy_to_dest(input, &gdisplays, sizeof(gdisplays)) )
return -1;
return 0;
}
lock.Reset();
return TTY::ioctl(ctx, cmd, arg);
}

View File

@ -20,6 +20,7 @@
#include <sys/display.h>
#include <sys/display.h>
#include <sys/kernelinfo.h>
#include <sys/ioctl.h>
#include <sys/termmode.h>
#include <assert.h>
@ -106,17 +107,21 @@ struct glogin
bool pointer_working;
struct termios old_tio;
bool has_old_tio;
uint64_t device;
uint64_t connector;
};
static struct glogin state;
static bool get_graphical_mode(struct dispmsg_crtc_mode* mode)
static bool get_graphical_mode(uint64_t device,
uint64_t connector,
struct dispmsg_crtc_mode* mode)
{
struct dispmsg_get_crtc_mode msg;
memset(&msg, 0, sizeof(msg));
msg.msgid = DISPMSG_GET_CRTC_MODE;
msg.device = 0; // TODO: Multi-screen support!
msg.connector = 0; // TODO: Multi-screen support!
msg.device = device;
msg.connector = connector;
if ( dispmsg_issue(&msg, sizeof(msg)) != 0 )
{
warn("dispmsg_issue: DISPMSG_GET_CRTC_MODE");
@ -496,8 +501,8 @@ static bool screen_capture(struct glogin* state, struct framebuffer* fb)
struct dispmsg_write_memory msg;
memset(&msg, 0, sizeof(msg));
msg.msgid = DISPMSG_READ_MEMORY;
msg.device = 0; // TODO: Multi-screen support!
msg.offset = 0; // TODO: mode.fb_location!
msg.device = state->device;
msg.offset = state->mode.fb_location;
msg.size = fb->xres * fb->yres * sizeof(fb->buffer[0]);
msg.src = (uint8_t*) fb->buffer;
if ( dispmsg_issue(&msg, sizeof(msg)) != 0 )
@ -510,7 +515,7 @@ static bool screen_capture(struct glogin* state, struct framebuffer* fb)
static bool begin_render(struct glogin* state, struct framebuffer* fb)
{
if ( !get_graphical_mode(&state->mode) )
if ( !get_graphical_mode(state->device, state->connector, &state->mode) )
return false;
fb->xres = state->mode.view_xres;
fb->yres = state->mode.view_yres;
@ -530,8 +535,8 @@ static bool finish_render(struct glogin* state, struct framebuffer* fb)
struct dispmsg_write_memory msg;
memset(&msg, 0, sizeof(msg));
msg.msgid = DISPMSG_WRITE_MEMORY;
msg.device = 0; // TODO: Multi-screen support!
msg.offset = 0; // TODO: mode.fb_location!
msg.device = state->device;
msg.offset = state->mode.fb_location;
msg.size = sizeof(uint32_t) * fb->xres * fb->yres;
msg.src = (uint8_t*) fb->buffer;
if ( dispmsg_issue(&msg, sizeof(msg)) != 0 )
@ -730,8 +735,19 @@ bool glogin_init(struct glogin* state)
{
memset(state, 0, sizeof(*state));
state->fd_mouse = -1;
if ( !get_graphical_mode(&state->mode) )
struct tiocgdisplay display;
struct tiocgdisplays gdisplays;
memset(&gdisplays, 0, sizeof(gdisplays));
gdisplays.count = 1;
gdisplays.displays = &display;
if ( ioctl(1, TIOCGDISPLAYS, &gdisplays) < 0 || gdisplays.count == 0 )
{
glogin_destroy(state);
return false;
}
state->device = display.device;
state->connector = display.connector;
if ( !get_graphical_mode(state->device, state->connector, &state->mode) )
{
warn("dispmsg_issue");
glogin_destroy(state);

View File

@ -18,6 +18,7 @@
*/
#include <sys/display.h>
#include <sys/ioctl.h>
#include <sys/kernelinfo.h>
#include <sys/mount.h>
#include <sys/stat.h>
@ -37,6 +38,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
// Sortix libc doesn't have its own proper <limits.h> at this time.
@ -472,7 +474,8 @@ int main(void)
install_configurationf("upgrade.conf", "a", "src = yes\n");
while ( true )
bool kblayout_setable = 0 <= tcgetblob(0, "kblayout", NULL, 0);
while ( kblayout_setable )
{
// TODO: Detect the name of the current keyboard layout.
prompt(input, sizeof(input),
@ -510,25 +513,36 @@ int main(void)
if ( execute(argv, "f") == 0 )
break;
}
if ( !input[0] || !strcmp(input, "default") )
text("/etc/kblayout will not be created (default).\n");
else
if ( kblayout_setable )
{
textf("/etc/kblayout will be set to \"%s\".\n", input);
mode_t old_umask = getumask();
umask(022);
install_configurationf("kblayout", "w", "%s\n", input);
umask(old_umask);
if ( !input[0] || !strcmp(input, "default") )
text("/etc/kblayout will not be created (default).\n");
else
{
textf("/etc/kblayout will be set to \"%s\".\n", input);
mode_t old_umask = getumask();
umask(022);
install_configurationf("kblayout", "w", "%s\n", input);
umask(old_umask);
}
text("\n");
}
text("\n");
struct tiocgdisplay display;
struct tiocgdisplays gdisplays;
memset(&gdisplays, 0, sizeof(gdisplays));
gdisplays.count = 1;
gdisplays.displays = &display;
struct dispmsg_get_driver_name dgdn = { 0 };
dgdn.msgid = DISPMSG_GET_DRIVER_NAME;
dgdn.device = 0;
dgdn.driver_index = 0;
dgdn.name.byte_size = 0;
dgdn.name.str = NULL;
if ( dispmsg_issue(&dgdn, sizeof(dgdn)) == 0 || errno != ENODEV )
if ( ioctl(1, TIOCGDISPLAYS, &gdisplays) == 0 &&
1 < gdisplays.count &&
(dgdn.device = display.device, true) &&
(dispmsg_issue(&dgdn, sizeof(dgdn)) == 0 || errno != ENODEV) )
{
while ( true )
{

View File

@ -18,6 +18,7 @@
*/
#include <sys/display.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/wait.h>
@ -32,6 +33,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>
@ -379,7 +381,8 @@ int main(void)
prompt(input, sizeof(input), "Ready?", ready);
text("\n");
while ( true )
bool kblayout_setable = 0 <= tcgetblob(0, "kblayout", NULL, 0);
while ( kblayout_setable )
{
// TODO: Detect the name of the current keyboard layout.
prompt(input, sizeof(input),
@ -417,15 +420,24 @@ int main(void)
if ( execute(argv, "f") == 0 )
break;
}
text("\n");
if ( kblayout_setable )
text("\n");
struct tiocgdisplay display;
struct tiocgdisplays gdisplays;
memset(&gdisplays, 0, sizeof(gdisplays));
gdisplays.count = 1;
gdisplays.displays = &display;
struct dispmsg_get_driver_name dgdn = { 0 };
dgdn.msgid = DISPMSG_GET_DRIVER_NAME;
dgdn.device = 0;
dgdn.driver_index = 0;
dgdn.name.byte_size = 0;
dgdn.name.str = NULL;
if ( dispmsg_issue(&dgdn, sizeof(dgdn)) == 0 || errno != ENODEV )
if ( ioctl(1, TIOCGDISPLAYS, &gdisplays) == 0 &&
1 < gdisplays.count &&
(dgdn.device = display.device, true) &&
(dispmsg_issue(&dgdn, sizeof(dgdn)) == 0 || errno != ENODEV) )
{
while ( true )
{
@ -439,8 +451,8 @@ int main(void)
continue;
break;
}
text("\n");
}
text("\n");
struct release new_release;
if ( !os_release_load(&new_release, "/etc/sortix-release",

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, 2014 Jonas 'Sortie' Termansen.
* Copyright (c) 2012, 2013, 2014, 2015, 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
@ -18,12 +18,14 @@
*/
#include <sys/display.h>
#include <sys/ioctl.h>
#include <sys/keycodes.h>
#include <sys/termmode.h>
#include <sys/wait.h>
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>
@ -34,6 +36,9 @@
#include <termios.h>
#include <unistd.h>
static uint64_t device;
static uint64_t connector;
bool SetCurrentMode(struct dispmsg_crtc_mode mode)
{
struct dispmsg_set_crtc_mode msg;
@ -324,6 +329,22 @@ int main(int argc, char* argv[])
compact_arguments(&argc, &argv);
int tty_fd = open("/dev/tty", O_RDWR);
if ( tty_fd < 0 )
error(1, errno, "/dev/tty");
struct tiocgdisplay display;
struct tiocgdisplays gdisplays;
memset(&gdisplays, 0, sizeof(gdisplays));
gdisplays.count = 1;
gdisplays.displays = &display;
if ( ioctl(1, TIOCGDISPLAYS, &gdisplays) < 0 || gdisplays.count == 0 )
{
fprintf(stderr, "No video devices are associated with this terminal.\n");
exit(13);
}
device = display.device;
connector = display.connector;
size_t num_modes = 0;
struct dispmsg_crtc_mode* modes = GetAvailableModes(&num_modes);
if ( !modes )