Compare commits

..

37 Commits

Author SHA1 Message Date
Jonas 'Sortie' Termansen 039d9b8ea5 fixup! Add display server. 2023-06-18 13:25:57 +02:00
Jonas 'Sortie' Termansen 2bda23891d fixup! Add display server. 2023-06-17 23:10:33 +02:00
Jonas 'Sortie' Termansen 11a5d5a08a fixup! Add display server. 2023-06-17 22:24:36 +02:00
Jonas 'Sortie' Termansen 28e7a0f4df fixup! Add display server. 2023-06-17 22:01:26 +02:00
Jonas 'Sortie' Termansen 22be4abaa4 fixup! Add display server. 2023-06-17 21:25:33 +02:00
Jonas 'Sortie' Termansen c7d5b41605 Add nyan(1). 2023-06-17 20:36:42 +02:00
Jonas 'Sortie' Termansen 09bed49d56 Draft video-player. 2023-06-17 20:36:42 +02:00
Jonas 'Sortie' Termansen 0aad618aab Aurora procedural wallpaper. 2023-06-17 20:36:42 +02:00
Jonas 'Sortie' Termansen 437bc6ef69 Work around pty deadlock. 2023-06-17 20:36:42 +02:00
Jonas 'Sortie' Termansen d7ef9c126b Add cdrom mounting live environment. 2023-06-17 20:36:42 +02:00
Jonas 'Sortie' Termansen 3ee481562a Revert "Parallelize driver initialization."
This reverts commit 0fef08bbc4.
2023-06-17 20:36:42 +02:00
Jonas 'Sortie' Termansen 5a0bdac8e8 Parallelize driver initialization. 2023-06-17 20:36:42 +02:00
Jonas 'Sortie' Termansen 7a606cab32 Speed up ata(4) 400 ns waits.
Waiting for any non-zero duration currently waits for at least one timer
cycle (10 ms), which is especially expensive during early boot.

The current workaround of simply reading the status 14 times seems really
suspicious although the osdev wiki documents it, but let's see how well it
works on real hardware, it's probably good enough.

Try to determine the initial selected drive to save one drive selection.
2023-06-17 20:36:41 +02:00
Jonas 'Sortie' Termansen ff494650f0 Decrease PS/2 timeouts. 2023-06-17 20:36:41 +02:00
Jonas 'Sortie' Termansen fa1e285634 Add uptime(1) -pr options. 2023-06-17 20:36:41 +02:00
Jonas 'Sortie' Termansen 76de810d00 Add iso9660 filesystem implementation. 2023-06-17 20:36:41 +02:00
Jonas 'Sortie' Termansen edaa069a79 Add kernel virtual address space usage debug information. 2023-06-17 20:36:41 +02:00
Jonas 'Sortie' Termansen 7e4eae1ad4 Revert "Update to bison-3.8.2."
This reverts commit b82fae810b42c5426d21c4dc153b32f086dd7fde.
2023-06-17 20:36:41 +02:00
Jonas 'Sortie' Termansen cca0c715dd Update to bison-3.8.2. 2023-06-17 20:36:41 +02:00
Jonas 'Sortie' Termansen fe48a71a4d Debug TCP socket state listing. 2023-06-17 20:36:41 +02:00
Jonas 'Sortie' Termansen 757957b601 Add kernel heap allocation tracing debug facility. 2023-06-17 20:36:41 +02:00
Jonas 'Sortie' Termansen a15169a9bf Add m4, perl, and texinfo to the basic ports set. 2023-06-17 20:36:41 +02:00
Jonas 'Sortie' Termansen af0b3c8bc8 Trianglix 4. 2023-06-17 20:36:41 +02:00
Jonas 'Sortie' Termansen 1159ac09fe Add tix-check(8). 2023-06-17 20:36:41 +02:00
Jonas 'Sortie' Termansen a5e1dede5a Volatile release. 2023-06-17 20:36:41 +02:00
Jonas 'Sortie' Termansen f775878f23 Add tix-upgrade(8). 2023-06-17 20:36:41 +02:00
Jonas 'Sortie' Termansen ef8fddd3b4 Add display server.
Remove the obsolete dispd.
2023-06-17 20:36:41 +02:00
Jonas 'Sortie' Termansen ad448cdf7e Add pty(1). 2023-06-17 13:19:07 +02:00
Jonas 'Sortie' Termansen 588c308893 Add signify port. 2023-06-17 13:19:07 +02:00
Jonas 'Sortie' Termansen 270610e9df Add irc(1).
Co-authored-by: Juhani Krekelä <juhani@krekelä.fi>
2023-06-17 13:19:07 +02:00
Jonas 'Sortie' Termansen 648b2fc3da Add getaddrinfo(1). 2023-06-17 13:19:07 +02:00
Jonas 'Sortie' Termansen 97bcd7b883 Add host(1). 2023-06-17 13:19:07 +02:00
Jonas 'Sortie' Termansen f89c0ae76e Enable stack smash protection by default. 2023-06-17 13:19:07 +02:00
Jonas 'Sortie' Termansen 2645cbaca1 Enable undefined behavior sanitization by default. 2023-06-17 13:19:07 +02:00
Jonas 'Sortie' Termansen 07d3ceba96 Switch trianglix(1) from dispd to dispmsg_issue(2). 2023-06-17 13:19:07 +02:00
Juhani Krekelä 0660d420f3 Fix pagination in chvideomode(1).
Pagination code deals with two indices for video modes, one relative to
the start of video modes array and one relative to the start of current
page. Previously when displaying the list of modes, the video mode array
would be accessed using the one relative to the start of the current
page, meaning that pages 2 and onwards displayed repeats of the video
modes on page 1. This changes the the display code to use indices
relative to the start of the video modes array when accessing the array.
2023-06-14 20:05:03 +03:00
Juhani Krekelä 1773d6a131 Fix setting custom modes on command line in chvideomode(1).
Previously setting a mode from the command line would only work if it
was one of the pre-set resolutions offered by the driver. If the driver
supported custom resolutions and a user tried to set one on the command
line, chvideomode(1) would instead launch in interactive mode.
2023-06-14 01:28:11 +03:00
16 changed files with 657 additions and 440 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
* Copyright (c) 2012, 2013, 2014, 2015, 2016, 2023 Jonas 'Sortie' Termansen.
* Copyright (c) 2023 Juhani 'nortti' Krekelä.
*
* Permission to use, copy, modify, and distribute this software for any
@ -38,25 +38,25 @@
#include <termios.h>
#include <unistd.h>
static uint64_t device;
static uint64_t connector;
static bool set_current_mode(struct dispmsg_crtc_mode mode)
static bool set_current_mode(const struct tiocgdisplay* display,
struct dispmsg_crtc_mode mode)
{
struct dispmsg_set_crtc_mode msg;
msg.msgid = DISPMSG_SET_CRTC_MODE;
msg.device = 0;
msg.connector = 0;
msg.device = display->device;
msg.connector = display->connector;
msg.mode = mode;
return dispmsg_issue(&msg, sizeof(msg)) == 0;
}
static struct dispmsg_crtc_mode* get_available_modes(size_t* num_modes_ptr)
static struct dispmsg_crtc_mode*
get_available_modes(const struct tiocgdisplay* display,
size_t* num_modes_ptr)
{
struct dispmsg_get_crtc_modes msg;
msg.msgid = DISPMSG_GET_CRTC_MODES;
msg.device = 0;
msg.connector = 0;
msg.device = display->device;
msg.connector = display->connector;
size_t guess = 1;
while ( true )
{
@ -133,7 +133,9 @@ static bool mode_passes_filter(struct dispmsg_crtc_mode mode,
return true;
}
static void filter_modes(struct dispmsg_crtc_mode* modes, size_t* num_modes_ptr, struct filter* filter)
static void filter_modes(struct dispmsg_crtc_mode* modes,
size_t* num_modes_ptr,
struct filter* filter)
{
size_t in_num = *num_modes_ptr;
size_t out_num = 0;
@ -145,6 +147,247 @@ static void filter_modes(struct dispmsg_crtc_mode* modes, size_t* num_modes_ptr,
*num_modes_ptr = out_num;
}
static bool get_mode(struct dispmsg_crtc_mode* modes,
size_t num_modes,
unsigned int xres,
unsigned int yres,
unsigned int bpp,
struct dispmsg_crtc_mode* mode)
{
bool found = false;
bool found_other = false;
size_t index;
size_t other_index = 0;
for ( size_t i = 0; i < num_modes; i++ )
{
if ( modes[i].view_xres == xres &&
modes[i].view_yres == yres &&
modes[i].fb_format == bpp )
{
index = i;
found = true;
break;
}
if ( modes[i].control & DISPMSG_CONTROL_OTHER_RESOLUTIONS )
{
found_other = true;
other_index = i;
}
}
if ( !found )
{
if ( found_other )
index = other_index;
else
// Not in the list of pre-set resolutions and setting a custom
// resolution is not supported.
return false;
}
*mode = modes[index];
if ( mode->control & DISPMSG_CONTROL_OTHER_RESOLUTIONS )
{
mode->fb_format = bpp;
mode->view_xres = xres;
mode->view_yres = yres;
mode->control &= ~DISPMSG_CONTROL_OTHER_RESOLUTIONS;
mode->control |= DISPMSG_CONTROL_VALID;
}
return true;
}
static bool select_mode(struct dispmsg_crtc_mode* modes,
size_t num_modes,
int mode_set_error,
struct dispmsg_crtc_mode* mode)
{
int num_modes_display_length = 1;
for ( size_t i = num_modes; 10 <= i; i /= 10 )
num_modes_display_length++;
size_t selection;
bool decided;
bool first_render;
struct wincurpos render_at;
selection = 0;
decided = false;
first_render = true;
memset(&render_at, 0, sizeof(render_at));
while ( !decided )
{
fflush(stdout);
struct winsize ws;
if ( tcgetwinsize(1, &ws) != 0 )
{
ws.ws_col = 80;
ws.ws_row = 25;
}
struct wincurpos wcp;
if ( tcgetwincurpos(1, &wcp) != 0 )
{
wcp.wcp_col = 1;
wcp.wcp_row = 1;
}
size_t off = 1; // The "Please select ..." line at the top.
if ( mode_set_error )
off++;
size_t entries_per_page = ws.ws_row - off;
size_t page = selection / entries_per_page;
size_t from = page * entries_per_page;
size_t how_many_available = num_modes - from;
size_t how_many = entries_per_page;
if ( how_many_available < how_many )
how_many = how_many_available;
size_t lines_on_screen = off + how_many;
if ( first_render )
{
while ( wcp.wcp_row &&
ws.ws_row - (wcp.wcp_row + 1) < lines_on_screen )
{
printf("\e[S");
printf("\e[%juH", 1 + (uintmax_t) wcp.wcp_row);
wcp.wcp_row--;
wcp.wcp_col = 1;
}
render_at = wcp;
first_render = false;
}
printf("\e[m");
printf("\e[%juH", 1 + (uintmax_t) render_at.wcp_row);
printf("\e[2K");
if ( mode_set_error )
printf("Error: Could not set desired mode: %s\n",
strerror(mode_set_error));
printf("Please select one of these video modes or press ESC to "
"abort.\n");
for ( size_t i = 0; i < how_many; i++ )
{
size_t index = from + i;
size_t screenline = off + index - from;
const char* color = index == selection ? "\e[31m" : "\e[m";
printf("\e[%zuH", 1 + render_at.wcp_row + screenline);
printf("%s", color);
printf("\e[2K");
printf(" [%-*zu] ", num_modes_display_length, index);
if ( modes[index].control & DISPMSG_CONTROL_VALID )
printf("%ux%ux%u",
modes[index].view_xres,
modes[index].view_yres,
modes[index].fb_format);
else if ( modes[index].control & DISPMSG_CONTROL_OTHER_RESOLUTIONS )
printf("(enter a custom resolution)");
else
printf("(unknown video device feature)");
printf("\e[m");
}
printf("\e[J");
fflush(stdout);
unsigned int oldtermmode;
if ( gettermmode(0, &oldtermmode) < 0 )
err(1, "gettermmode");
if ( settermmode(0, TERMMODE_KBKEY | TERMMODE_UNICODE |
TERMMODE_SIGNAL) < 0 )
err(1, "settermmode");
bool redraw = false;
while ( !redraw && !decided )
{
uint32_t codepoint;
ssize_t numbytes = read(0, &codepoint, sizeof(codepoint));
if ( numbytes < 0 )
err(1, "read");
int kbkey = KBKEY_DECODE(codepoint);
if ( kbkey )
{
switch ( kbkey )
{
case KBKEY_ESC:
if ( settermmode(0, oldtermmode) < 0 )
err(1, "settermmode");
printf("\n");
return false;
break;
case KBKEY_UP:
if ( selection )
selection--;
else
selection = num_modes -1;
redraw = true;
break;
case KBKEY_DOWN:
if ( selection + 1 == num_modes )
selection = 0;
else
selection++;
redraw = true;
break;
case KBKEY_ENTER:
if ( settermmode(0, oldtermmode) < 0 )
err(1, "settermmode");
fgetc(stdin);
printf("\n");
decided = true;
break;
}
}
else
{
if ( L'0' <= codepoint && codepoint <= '9' )
{
uint32_t requested = codepoint - '0';
if ( requested < num_modes )
{
selection = requested;
redraw = true;
}
}
}
}
if ( settermmode(0, oldtermmode) < 0 )
err(1, "settermmode");
}
*mode = modes[selection];
if ( mode->control & DISPMSG_CONTROL_OTHER_RESOLUTIONS )
{
uintmax_t req_bpp, req_width, req_height;
while ( true )
{
printf("Enter video mode [WIDTHxHEIGHTxBPP]: ");
fflush(stdout);
if ( scanf("%jux%jux%ju", &req_width, &req_height, &req_bpp) != 3 )
{
fgetc(stdin);
fflush(stdin);
continue;
}
fgetc(stdin);
break;
}
mode->fb_format = req_bpp;
mode->view_xres = req_width;
mode->view_yres = req_height;
mode->control &= ~DISPMSG_CONTROL_OTHER_RESOLUTIONS;
mode->control |= DISPMSG_CONTROL_VALID;
}
return true;
}
static size_t parse_size_t(const char* str)
{
char* endptr;
@ -254,20 +497,6 @@ int main(int argc, char* argv[])
}
}
unsigned int xres = 0;
unsigned int yres = 0;
unsigned int bpp = 0;
if ( 1 <= argc - optind )
{
if ( 1 < argc - optind )
errx(1, "Unexpected extra operand");
if ( sscanf(argv[optind], "%ux%ux%u", &xres, &yres, &bpp) != 3 )
errx(1, "Invalid video mode: %s", argv[optind]);
}
int tty_fd = open("/dev/tty", O_RDWR);
if ( tty_fd < 0 )
err(1, "/dev/tty");
struct tiocgdisplay display;
struct tiocgdisplays gdisplays;
memset(&gdisplays, 0, sizeof(gdisplays));
@ -278,248 +507,67 @@ int main(int argc, char* argv[])
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 = get_available_modes(&num_modes);
struct dispmsg_crtc_mode* modes = get_available_modes(&display, &num_modes);
if ( !modes )
err(1, "Unable to detect available video modes");
if ( !num_modes )
{
fprintf(stderr, "No video modes are currently available.\n");
fprintf(stderr, "Try make sure a device driver exists and is activated.\n");
fprintf(stderr, "Try make sure a device driver exists and is "
"activated.\n");
exit(11);
}
filter_modes(modes, &num_modes, &filter);
if ( !num_modes )
{
fprintf(stderr, "No video mode remains after filtering away unwanted modes.\n");
fprintf(stderr, "Try make sure the desired device driver is loaded and is configured correctly.\n");
fprintf(stderr, "No video mode remains after filtering away unwanted "
"modes.\n");
fprintf(stderr, "Try make sure the desired device driver is loaded and "
"is configured correctly.\n");
exit(12);
}
int num_modes_display_length = 1;
for ( size_t i = num_modes; 10 <= i; i /= 10 )
num_modes_display_length++;
int mode_set_error = 0;
size_t selection;
bool decided;
bool first_render;
struct wincurpos render_at;
retry_pick_mode:
selection = 0;
decided = false;
first_render = true;
memset(&render_at, 0, sizeof(render_at));
if ( 1 <= argc - optind )
if ( 1 < argc - optind )
errx(1, "Unexpected extra operand");
else if ( argc - optind == 1 )
{
bool found_other = true;
size_t other_selection = 0;
for ( size_t i = 0; i < num_modes; i++ )
{
if ( modes[i].view_xres == xres &&
modes[i].view_yres == yres &&
modes[i].fb_format == bpp )
{
selection = i;
decided = true;
break;
}
if ( modes[i].control & DISPMSG_CONTROL_OTHER_RESOLUTIONS )
{
found_other = true;
other_selection = i;
}
}
if ( !decided )
{
if ( found_other )
selection = other_selection;
else
err(1, "No such available resolution: %s", argv[optind]);
}
unsigned int xres, yres, bpp;
if ( sscanf(argv[optind], "%ux%ux%u", &xres, &yres, &bpp) != 3 )
errx(1, "Invalid video mode: %s", argv[optind]);
struct dispmsg_crtc_mode mode;
if ( !get_mode(modes, num_modes, xres, yres, bpp, &mode) )
errx(1, "No such available resolution: %s", argv[optind]);
if ( !set_current_mode(&display, mode) )
err(1, "Failed to set video mode %jux%jux%ju",
(uintmax_t) mode.view_xres,
(uintmax_t) mode.view_yres,
(uintmax_t) mode.fb_format);
}
while ( !decided )
else
{
fflush(stdout);
struct winsize ws;
if ( tcgetwinsize(1, &ws) != 0 )
int mode_set_error = 0;
bool mode_set = false;
while ( !mode_set )
{
ws.ws_col = 80;
ws.ws_row = 25;
}
struct dispmsg_crtc_mode mode;
if ( !select_mode(modes, num_modes, mode_set_error, &mode) )
exit(10);
struct wincurpos wcp;
if ( tcgetwincurpos(1, &wcp) != 0 )
{
wcp.wcp_col = 1;
wcp.wcp_row = 1;
}
size_t off = 1; // The "Please select ..." line at the top.
if ( mode_set_error )
off++;
size_t entries_per_page = ws.ws_row - off;
size_t page = selection / entries_per_page;
size_t from = page * entries_per_page;
size_t how_many_available = num_modes - from;
size_t how_many = entries_per_page;
if ( how_many_available < how_many )
how_many = how_many_available;
size_t lines_on_screen = off + how_many;
if ( first_render )
{
while ( wcp.wcp_row && ws.ws_row - (wcp.wcp_row + 1) < lines_on_screen )
if ( !(mode_set = set_current_mode(&display, mode)) )
{
printf("\e[S");
printf("\e[%juH", 1 + (uintmax_t) wcp.wcp_row);
wcp.wcp_row--;
wcp.wcp_col = 1;
}
render_at = wcp;
first_render = false;
}
printf("\e[m");
printf("\e[%juH", 1 + (uintmax_t) render_at.wcp_row);
printf("\e[2K");
if ( mode_set_error )
printf("Error: Could not set desired mode: %s\n", strerror(mode_set_error));
printf("Please select one of these video modes or press ESC to abort.\n");
for ( size_t i = 0; i < how_many; i++ )
{
size_t index = from + i;
size_t screenline = off + index - from;
const char* color = index == selection ? "\e[31m" : "\e[m";
printf("\e[%zuH", 1 + render_at.wcp_row + screenline);
printf("%s", color);
printf("\e[2K");
printf(" [%-*zu] ", num_modes_display_length, index);
if ( modes[i].control & DISPMSG_CONTROL_VALID )
printf("%ux%ux%u",
modes[i].view_xres,
modes[i].view_yres,
modes[i].fb_format);
else if ( modes[i].control & DISPMSG_CONTROL_OTHER_RESOLUTIONS )
printf("(enter a custom resolution)");
else
printf("(unknown video device feature)");
printf("\e[m");
}
printf("\e[J");
fflush(stdout);
unsigned int oldtermmode;
if ( gettermmode(0, &oldtermmode) < 0 )
err(1, "gettermmode");
if ( settermmode(0, TERMMODE_KBKEY | TERMMODE_UNICODE | TERMMODE_SIGNAL) < 0 )
err(1, "settermmode");
bool redraw = false;
while ( !redraw && !decided )
{
uint32_t codepoint;
ssize_t numbytes = read(0, &codepoint, sizeof(codepoint));
if ( numbytes < 0 )
err(1, "read");
int kbkey = KBKEY_DECODE(codepoint);
if ( kbkey )
{
switch ( kbkey )
{
case KBKEY_ESC:
if ( settermmode(0, oldtermmode) < 0 )
err(1, "settermmode");
printf("\n");
exit(10);
break;
case KBKEY_UP:
if ( selection )
selection--;
else
selection = num_modes -1;
redraw = true;
break;
case KBKEY_DOWN:
if ( selection + 1 == num_modes )
selection = 0;
else
selection++;
redraw = true;
break;
case KBKEY_ENTER:
if ( settermmode(0, oldtermmode) < 0 )
err(1, "settermmode");
fgetc(stdin);
printf("\n");
decided = true;
break;
}
}
else
{
if ( L'0' <= codepoint && codepoint <= '9' )
{
uint32_t requested = codepoint - '0';
if ( requested < num_modes )
{
selection = requested;
redraw = true;
}
}
mode_set_error = errno;
warn("Failed to set video mode %jux%jux%ju",
(uintmax_t) mode.view_xres,
(uintmax_t) mode.view_yres,
(uintmax_t) mode.fb_format);
}
}
if ( settermmode(0, oldtermmode) < 0 )
err(1, "settermmode");
}
struct dispmsg_crtc_mode mode = modes[selection];
if ( mode.control & DISPMSG_CONTROL_OTHER_RESOLUTIONS )
{
uintmax_t req_bpp = bpp;
uintmax_t req_width = xres;
uintmax_t req_height = yres;
while ( argc - optind < 1 )
{
printf("Enter video mode [WIDTHxHEIGHTxBPP]: ");
fflush(stdout);
if ( scanf("%jux%jux%ju", &req_width, &req_height, &req_bpp) != 3 )
{
fgetc(stdin);
fflush(stdin);
continue;
}
fgetc(stdin);
break;
}
mode.fb_format = req_bpp;
mode.view_xres = req_width;
mode.view_yres = req_height;
mode.control &= ~DISPMSG_CONTROL_OTHER_RESOLUTIONS;
mode.control |= DISPMSG_CONTROL_VALID;
}
if ( !set_current_mode(mode) )
{
mode_set_error = errno;
warn("Unable to set video mode %jux%jux%ju",
(uintmax_t) mode.view_xres,
(uintmax_t) mode.view_yres,
(uintmax_t) mode.fb_format);
goto retry_pick_mode;
}
return 0;

View File

@ -42,18 +42,21 @@ void connection_schedule_transmit(struct connection* connection,
size_t available = connection->outgoing_size - connection->outgoing_used;
if ( available < count )
{
// TODO: Overflow.
size_t required_size = connection->outgoing_used + count;
unsigned char* new_outgoing = (unsigned char*) malloc(required_size);
size_t first_part_available = connection->outgoing_size - connection->outgoing_offset;
size_t first_part = connection->outgoing_used < first_part_available ?
connection->outgoing_used :
first_part_available;
// TODO: Check allocation.
unsigned char* new_outgoing = malloc(required_size);
size_t first_available =
connection->outgoing_size - connection->outgoing_offset;
size_t first = connection->outgoing_used < first_available ?
connection->outgoing_used :
first_available;
if ( connection->outgoing )
{
memcpy(new_outgoing, connection->outgoing +
connection->outgoing_offset, first_part);
size_t second_part = connection->outgoing_used - first_part;
memcpy(new_outgoing + first_part, connection->outgoing, second_part);
connection->outgoing_offset, first);
size_t second = connection->outgoing_used - first;
memcpy(new_outgoing + first, connection->outgoing, second);
free(connection->outgoing);
}
connection->outgoing_offset = 0;
@ -61,12 +64,14 @@ void connection_schedule_transmit(struct connection* connection,
connection->outgoing = new_outgoing;
}
size_t used_offset = (connection->outgoing_offset + connection->outgoing_used) % connection->outgoing_size;
size_t first_part_available = connection->outgoing_size - used_offset;
size_t first_part = count < first_part_available ? count : first_part_available;
memcpy(connection->outgoing + used_offset, buffer, first_part);
size_t second_part = count - first_part;
memcpy(connection->outgoing, (const unsigned char*) buffer + first_part, second_part);
size_t used_offset =
(connection->outgoing_offset + connection->outgoing_used) %
connection->outgoing_size;
size_t first_available = connection->outgoing_size - used_offset;
size_t first = count < first_available ? count : first_available;
memcpy(connection->outgoing + used_offset, buffer, first);
size_t second = count - first;
memcpy(connection->outgoing, (const unsigned char*) buffer + first, second);
connection->outgoing_used += count;
}
@ -97,25 +102,28 @@ struct window* connection_find_window(struct connection* connection,
}
#define CONNECTION_MESSAGE_HANDLER_NO_AUX(message_name) \
void connection_handler_##message_name(struct connection* connection, \
struct display_##message_name* msg, \
void* auxiliary __attribute__((unused)), \
size_t auxiliary_size __attribute__((unused)), \
const struct server* server __attribute__((unused)))
void connection_handler_##message_name( \
struct connection* connection, \
struct display_##message_name* msg, \
void* auxiliary __attribute__((unused)), \
size_t auxiliary_size __attribute__((unused)), \
const struct server* server __attribute__((unused)))
#define CONNECTION_MESSAGE_HANDLER(message_name) \
void connection_handler_##message_name(struct connection* connection, \
struct display_##message_name* msg, \
unsigned char* auxiliary, \
size_t auxiliary_size, \
const struct server* server __attribute__((unused)))
void connection_handler_##message_name( \
struct connection* connection, \
struct display_##message_name* msg, \
unsigned char* auxiliary, \
size_t auxiliary_size, \
const struct server* server __attribute__((unused)))
#define CONNECTION_MESSAGE_HANDLER_SERVER(message_name) \
void connection_handler_##message_name(struct connection* connection, \
struct display_##message_name* msg, \
unsigned char* auxiliary, \
size_t auxiliary_size, \
const struct server* server)
void connection_handler_##message_name( \
struct connection* connection, \
struct display_##message_name* msg, \
unsigned char* auxiliary, \
size_t auxiliary_size, \
const struct server* server)
CONNECTION_MESSAGE_HANDLER_NO_AUX(shutdown)
{
@ -134,7 +142,8 @@ CONNECTION_MESSAGE_HANDLER_NO_AUX(shutdown)
CONNECTION_MESSAGE_HANDLER_NO_AUX(create_window)
{
struct window* window = connection_find_window_raw(connection, msg->window_id);
struct window* window =
connection_find_window_raw(connection, msg->window_id);
if ( !window )
return;
if ( window->created )
@ -265,7 +274,8 @@ short connection_interested_poll_events(struct connection* connection)
void connection_can_read(struct connection* connection,
const struct server* server)
{
while ( connection->packet_header_received < sizeof(connection->packet_header) )
while ( connection->packet_header_received <
sizeof(connection->packet_header) )
{
ssize_t amount = read(connection->fd,
(unsigned char*) &connection->packet_header +
@ -275,12 +285,13 @@ void connection_can_read(struct connection* connection,
if ( amount < 0 && (errno == EAGAIN || errno == EWOULDBLOCK) )
return;
if ( amount < 0 || amount == 0 )
return; // TODO: No longer signal interest in reading and disconnect.
return; // TODO: No longer signal interest in reading + disconnect.
connection->packet_header_received += amount;
}
size_t packet_length = connection->packet_header.message_length;
// TODO: Check allocation and protect against too big buffers.
if ( !connection->packet )
connection->packet = (unsigned char*) malloc(packet_length);
@ -292,7 +303,7 @@ void connection_can_read(struct connection* connection,
if ( amount < 0 && (errno == EAGAIN || errno == EWOULDBLOCK) )
return;
if ( amount < 0 || amount == 0 )
return; // TODO: No longer signal interest in reading and disconnect.
return; // TODO: No longer signal interest in reading + disconnect.
connection->packet_received += amount;
}
@ -313,7 +324,7 @@ void connection_can_read(struct connection* connection,
connection->packet = NULL;
connection->packet_received = 0;
// TODO: Check if we can received another packet, but only if we haven't
// TODO: Check if we can receive another packet, but only if we haven't
// done so much work that the display server is starved.
}
@ -321,14 +332,18 @@ void connection_can_write(struct connection* connection)
{
while ( connection->outgoing_used )
{
size_t available = connection->outgoing_size - connection->outgoing_offset;
size_t count = connection->outgoing_used < available ? connection->outgoing_used : available;
ssize_t amount = write(connection->fd, connection->outgoing + connection->outgoing_offset, count);
size_t available =
connection->outgoing_size - connection->outgoing_offset;
size_t count = connection->outgoing_used < available ?
connection->outgoing_used : available;
unsigned char* buf = connection->outgoing + connection->outgoing_offset;
ssize_t amount = write(connection->fd, buf, count);
if ( amount < 0 && (errno == EAGAIN || errno == EWOULDBLOCK) )
return;
if ( amount < 0 || amount == 0 )
return; // TODO: No longer signal interest in writing and disconnect.
connection->outgoing_offset = (connection->outgoing_offset + amount) % connection->outgoing_size;
return; // TODO: No longer signal interest in writing + disconnect.
connection->outgoing_offset = (connection->outgoing_offset + amount) %
connection->outgoing_size;
connection->outgoing_used -= amount;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2015, 2016, 2018, 2022 Jonas 'Sortie' Termansen.
* Copyright (c) 2014, 2015, 2016, 2018, 2022, 2023 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,7 +17,6 @@
* Display server logic.
*/
#include <sys/display.h>
#include <sys/keycodes.h>
#include <sys/ps2mouse.h>
@ -124,7 +123,8 @@ void display_unlink_window(struct display* display, struct window* window)
assert_is_well_formed_display_list(display);
}
void display_unlink_window_removal(struct display* display, struct window* window)
void display_unlink_window_removal(struct display* display,
struct window* window)
{
assert_is_well_formed_display_list(display);
@ -145,7 +145,8 @@ void display_unlink_window_removal(struct display* display, struct window* windo
assert_is_well_formed_display_list(display);
}
void display_unmark_active_window(struct display* display, struct window* window)
void display_unmark_active_window(struct display* display,
struct window* window)
{
assert(display->active_window == window);
window->focus = false;
@ -173,7 +174,8 @@ void display_move_window_to_top(struct display* display, struct window* window)
display_link_window_at_top(display, window);
}
void display_change_active_window(struct display* display, struct window* window)
void display_change_active_window(struct display* display,
struct window* window)
{
if ( display->active_window == window )
{
@ -284,7 +286,8 @@ void display_composit(struct display* display, struct framebuffer fb)
uint32_t bg_color = make_color(0x89 * 2/3, 0xc7 * 2/3, 0xff * 2/3);
for ( size_t y = 0; y < damage_rect.height; y++ )
for ( size_t x = 0; x < damage_rect.width; x++ )
framebuffer_set_pixel(fb, damage_rect.left + x, damage_rect.top + y, bg_color);
framebuffer_set_pixel(fb, damage_rect.left + x, damage_rect.top + y,
bg_color);
#endif
framebuffer_copy_to_framebuffer(fb, display->wallpaper);
@ -303,7 +306,8 @@ void display_composit(struct display* display, struct framebuffer fb)
if ( window->left < 0 )
{
winfb_left = 0;
winfb = framebuffer_crop(winfb, -window->left, 0, winfb.xres, winfb.yres);
winfb = framebuffer_crop(winfb, -window->left, 0,
winfb.xres, winfb.yres);
}
else
winfb_left = window->left;
@ -311,7 +315,8 @@ void display_composit(struct display* display, struct framebuffer fb)
if ( window->top < 0 )
{
winfb_top = 0;
winfb = framebuffer_crop(winfb, 0, -window->top, winfb.xres, winfb.yres);
winfb = framebuffer_crop(winfb, 0, -window->top,
winfb.xres, winfb.yres);
}
else
winfb_top = window->top;
@ -320,14 +325,19 @@ void display_composit(struct display* display, struct framebuffer fb)
size_t winfb_height = winfb.yres;
#if 0
if ( winfb_left < damage_rect.left && winfb_width < damage_rect.left - winfb_left )
if ( winfb_left < damage_rect.left &&
winfb_width < damage_rect.left - winfb_left )
continue;
if ( winfb_left < damage_rect.left )
winfb_left = damage_rect.left, winfb_width -= damage_rect.left - winfb_left;
{
winfb_left = damage_rect.left;
winfb_width -= damage_rect.left - winfb_left;
}
#endif
struct framebuffer fb_dst =
framebuffer_crop(fb, winfb_left, winfb_top, winfb_width, winfb_height);
framebuffer_crop(fb, winfb_left, winfb_top,
winfb_width, winfb_height);
framebuffer_copy_to_framebuffer_blend(fb_dst, winfb);
}
@ -336,6 +346,7 @@ void display_composit(struct display* display, struct framebuffer fb)
switch ( display->mouse_state )
{
case MOUSE_STATE_NONE: break;
case MOUSE_STATE_BUTTON_PRESS: break;
case MOUSE_STATE_TITLE_MOVE: break;
case MOUSE_STATE_RESIZE_BOTTOM: cursor_text = ""; break;
case MOUSE_STATE_RESIZE_BOTTOM_LEFT: cursor_text = ""; break;
@ -356,12 +367,14 @@ void display_composit(struct display* display, struct framebuffer fb)
struct framebuffer arrow_render = arrow_framebuffer;
if ( pointer_x < 0 )
{
arrow_render = framebuffer_crop(arrow_render, -pointer_x, 0, arrow_render.xres, arrow_render.yres);
arrow_render = framebuffer_crop(arrow_render, -pointer_x, 0,
arrow_render.xres, arrow_render.yres);
pointer_x = 0;
}
if ( pointer_y < 0 )
{
arrow_render = framebuffer_crop(arrow_render, 0, -pointer_y, arrow_render.xres, arrow_render.yres);
arrow_render = framebuffer_crop(arrow_render, 0, -pointer_y,
arrow_render.xres, arrow_render.yres);
pointer_y = 0;
}
@ -378,19 +391,13 @@ void display_composit(struct display* display, struct framebuffer fb)
void display_render(struct display* display)
{
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!
if ( dispmsg_issue(&msg, sizeof(msg)) != 0 )
err(1, "dispmsg_issue: dispmsg_get_crtc_mode");
mode = msg.mode;
}
struct dispmsg_get_crtc_mode get_mode_msg = {0};
get_mode_msg.msgid = DISPMSG_GET_CRTC_MODE;
get_mode_msg.device = display->display.device;
get_mode_msg.connector = display->display.connector;
if ( dispmsg_issue(&get_mode_msg, sizeof(get_mode_msg)) != 0 )
err(1, "dispmsg_issue: dispmsg_get_crtc_mode");
struct dispmsg_crtc_mode mode = get_mode_msg.mode;
if ( !(mode.control & DISPMSG_CONTROL_VALID) )
errx(1, "No valid video mode was set");
@ -425,18 +432,13 @@ void display_render(struct display* display)
display_composit(display, display->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.size = framebuffer_size;
msg.src = (uint8_t*) display->fb.buffer;
if ( dispmsg_issue(&msg, sizeof(msg)) != 0 )
err(1, "dispmsg_issue: dispmsg_write_memory");
}
struct dispmsg_write_memory write_memory_msg = {0};
write_memory_msg.msgid = DISPMSG_WRITE_MEMORY;
write_memory_msg.device = display->display.device;
write_memory_msg.size = framebuffer_size;
write_memory_msg.src = (uint8_t*) display->fb.buffer;
if ( dispmsg_issue(&write_memory_msg, sizeof(write_memory_msg)) != 0 )
err(1, "dispmsg_issue: dispmsg_write_memory");
}
void display_keyboard_event(struct display* display, uint32_t codepoint)
@ -537,7 +539,8 @@ void display_keyboard_event(struct display* display, uint32_t codepoint)
{
// TODO: window->title can be null.
char* new_title;
if ( 0 <= asprintf(&new_title, "%s%s", window->title, grab_inputbed_string) )
if ( 0 <= asprintf(&new_title, "%s%s", window->title,
grab_inputbed_string) )
{
window->grab_input = true;
free(window->title);
@ -651,34 +654,83 @@ void display_mouse_event(struct display* display, uint8_t byte)
ssize_t window_pointer_x = display->pointer_x - window->left;
ssize_t window_pointer_y = display->pointer_y - window->top;
if ( display->active_window != window )
{
if ( bytes[0] & (MOUSE_BUTTON_LEFT | MOUSE_BUTTON_MIDDLE |
MOUSE_BUTTON_RIGHT) )
{
// TODO: Exit mouse from the current window.
display_set_active_window(display, window);
}
else
return;
}
size_t border_width = window_border_width(window);
size_t button_width = FONT_WIDTH * 2;
ssize_t buttons_x = window->width - border_width
- button_width * 3 + 1;
size_t tt_height = FONT_HEIGHT;
size_t tt_pos_y = (TITLE_HEIGHT - FONT_HEIGHT) / 2 + 2;
bool mouse_on_title = 0 <= window_pointer_x &&
window_pointer_x < (ssize_t) window->width &&
0 <= window_pointer_y &&
window_pointer_y <= (ssize_t) TITLE_HEIGHT;
for ( size_t n = 0; n < 3; n++ )
{
if ( (ssize_t) tt_pos_y <= window_pointer_y &&
window_pointer_y <= (ssize_t) (tt_height + tt_pos_y) &&
(ssize_t) (button_width * n) <= window_pointer_x - buttons_x &&
window_pointer_x - buttons_x < (ssize_t) (button_width * (n + 1)) )
{
if ( display->mouse_state == MOUSE_STATE_NONE &&
(bytes[0] & MOUSE_BUTTON_LEFT) )
{
display->mouse_state = MOUSE_STATE_BUTTON_PRESS;
window->button_states[n] = BUTTON_STATE_PRESSED;
window_render_frame(window);
}
else if ( display->mouse_state == MOUSE_STATE_BUTTON_PRESS &&
window->button_states[n] == BUTTON_STATE_PRESSED )
{
window->button_states[n] = BUTTON_STATE_NORMAL;
window_render_frame(window);
switch ( n )
{
case 0: /* TODO: Minimize. */ break;
case 1: window_toggle_maximized(window); break;
case 2: window_quit(window); break;
}
return;
}
else if ( display->mouse_state == MOUSE_STATE_NONE &&
window->button_states[n] != BUTTON_STATE_HOVER )
{
window->button_states[n] = BUTTON_STATE_HOVER;
window_render_frame(window);
}
}
else if ( window->button_states[n] != BUTTON_STATE_NORMAL )
{
window->button_states[n] = BUTTON_STATE_NORMAL;
display->mouse_state = MOUSE_STATE_NONE;
window_render_frame(window);
}
}
if ( bytes[0] & MOUSE_BUTTON_LEFT )
{
display_set_active_window(display, window);
if ( display->mouse_state == MOUSE_STATE_NONE )
{
// TODO: Stay in state until mouse release.
if ( display->key_lalt ||
(0 <= window_pointer_x &&
window_pointer_x < (ssize_t) window->width &&
0 <= window_pointer_y &&
window_pointer_y <= (ssize_t) TITLE_HEIGHT) )
if ( display->key_lalt || mouse_on_title )
{
size_t border_width = window_border_width(window);
size_t button_width = FONT_WIDTH * 2;
ssize_t buttons_x = window->width - border_width
- button_width * 3 + 1;
ssize_t rel_x = window_pointer_x - buttons_x;
if ( 0 <= rel_x && rel_x < (ssize_t) button_width )
{
// TODO Minimize window.
}
else if ( 0 <= rel_x && rel_x < (ssize_t) button_width * 2 )
window_toggle_maximized(window);
else if ( 0 <= rel_x && rel_x < (ssize_t) button_width * 3 )
window_quit(window);
else
if ( window_pointer_x < buttons_x || !mouse_on_title )
display->mouse_state = MOUSE_STATE_TITLE_MOVE;
} else if ( window_pointer_x < 0 && window_pointer_y < 0 )
}
else if ( window_pointer_x < 0 && window_pointer_y < 0 )
display->mouse_state = MOUSE_STATE_RESIZE_TOP_LEFT;
else if ( window_pointer_x < 0 &&
0 <= window_pointer_y &&
@ -709,18 +761,19 @@ void display_mouse_event(struct display* display, uint8_t byte)
if ( xm || ym )
{
bool floating = window->window_state == WINDOW_STATE_REGULAR;
bool on_edge = display->pointer_x == 0
|| display->pointer_y == 0
|| display->pointer_x
== (ssize_t) display->screen_width
|| display->pointer_y
== (ssize_t) display->screen_height;
bool on_edge =
display->pointer_x == 0 ||
display->pointer_y == 0 ||
display->pointer_x == (ssize_t) display->screen_width ||
display->pointer_y == (ssize_t) display->screen_height;
switch ( display->mouse_state )
{
case MOUSE_STATE_NONE: break;
case MOUSE_STATE_BUTTON_PRESS: break;
case MOUSE_STATE_TITLE_MOVE:
if ( clipped_edge )
{
// TODO: Clean these up.
// I'd declare those in function scope but I'm afraid of
// messing with the code too much.
ssize_t x = display->pointer_x;
@ -732,22 +785,22 @@ void display_mouse_event(struct display* display, uint8_t byte)
ssize_t corner_size = (sw < sh ? sw : sh) / 4;
if ( x < corner_size && y < corner_size )
window_tile_top_left(window);
else if (sw - x < corner_size && y < corner_size )
else if ( sw - x < corner_size && y < corner_size )
window_tile_top_right(window);
else if ( x < corner_size && sh - y < corner_size )
window_tile_bottom_left(window);
else if (sw - x < corner_size && sh - y < corner_size )
else if ( sw - x < corner_size && sh - y < corner_size )
window_tile_bottom_right(window);
else if (x == 0)
else if ( x == 0 )
window_tile_left(window);
else if (x == sw)
else if ( x == sw )
window_tile_right(window);
else if (y == 0)
else if ( y == 0 )
window_tile_top(window);
else if (y == sh)
else if ( y == sh )
window_tile_bottom(window);
}
else if (floating || !on_edge)
else if ( floating || !on_edge )
{
if ( !floating )
{
@ -799,7 +852,8 @@ void display_mouse_event(struct display* display, uint8_t byte)
}
}
void display_on_resolution_change(struct display* display, size_t width, size_t height)
void display_on_resolution_change(struct display* display, size_t width,
size_t height)
{
if ( display->screen_width == width && display->screen_height == height )
return;
@ -807,7 +861,9 @@ void display_on_resolution_change(struct display* display, size_t width, size_t
display->screen_height = height;
display->pointer_x = width / 2;
display->pointer_y = height / 2;
for ( struct window* window = display->bottom_window; window; window = window->above_window )
for ( struct window* window = display->bottom_window;
window;
window = window->above_window )
window_on_display_resolution_change(window, display);
wallpaper(display->wallpaper);
}

View File

@ -1,5 +1,5 @@
.Dd June 11, 2023
.Dt DISPLAY 8
.Dt DISPLAY 1
.Os
.Sh NAME
.Nm display
@ -25,6 +25,25 @@ script in the background.
.Nm
exits when Control + Alt + Delete is pressed.
.Pp
The options are as follows:
.Bl -tag -width "12345678"
.It Fl m Ar mouse
Use
.Pa mouse
device instead of
.Pa /dev/mouse .
.It Fl t Ar tty
Use
.Pa tty
device instead of
.Pa /dev/tty .
.It Fl s Ar socket
Listen on
.Pa socket
instead of
.Pa /var/run/display .
.El
.Pp
The keyboard shortcuts are as follows:
.Bl -tag -width "Control + Alt + Delete"
.It Alt + F4
@ -93,7 +112,7 @@ Applications use
to connect to
.Nm
or
.Pa /run/display
.Pa /var/run/display
by default.
.El
.Sh FILES
@ -101,7 +120,7 @@ by default.
.It Pa ~/.displayrc , /etc/displayrc , /etc/default/displayrc
.Xr displayrc 5
script that spawns the user's preferred startup applications.
.It Pa /run/display
.It Pa /var/run/display
.Xr unix 4
socket where
.Nm

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2015, 2016, 2017, 2022 Jonas 'Sortie' Termansen.
* Copyright (c) 2014, 2015, 2016, 2017, 2022, 2023 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
@ -45,43 +45,23 @@ static void ready(void)
unsetenv("READYFD");
}
static void compact_arguments(int* argc, char*** argv)
{
for ( int i = 0; i < *argc; i++ )
{
while ( i < *argc && !(*argv)[i] )
{
for ( int n = i; n < *argc; n++ )
(*argv)[n] = (*argv)[n+1];
(*argc)--;
}
}
}
int main(int argc, char* argv[])
{
for ( int i = 1; i < argc; i++ )
{
const char* arg = argv[i];
if ( arg[0] != '-' || !arg[1] )
continue;
argv[i] = NULL;
if ( !strcmp(arg, "--") )
break;
if ( arg[1] != '-' )
{
char c;
while ( (c = *++arg) ) switch ( c )
{
default:
errx(1, "unknown option -- '%c'", c);
}
}
else
errx(1, "unknown option: %s", arg);
}
const char* mouse = "/dev/mouse";
const char* socket = "/var/run/display";
const char* tty = NULL;
compact_arguments(&argc, &argv);
int opt;
while ( (opt = getopt(argc, argv, "m:s:t:")) != -1 )
{
switch ( opt )
{
case 'm': mouse = optarg; break;
case 's': socket = optarg; break;
case 't': tty = optarg; break;
default: return 1;
}
}
memcpy(arrow_buffer, arrow, sizeof(arrow));
@ -95,7 +75,7 @@ int main(int argc, char* argv[])
display_initialize(&display);
struct server server;
server_initialize(&server, &display);
server_initialize(&server, &display, tty, mouse, socket);
if ( setenv("DISPLAY_SOCKET", server.server_path, 1) < 0 )
err(1, "setenv");
@ -104,8 +84,8 @@ int main(int argc, char* argv[])
char* home_session = NULL;
char** session_argv = NULL;
if ( 1 < argc )
session_argv = argv + 1;
if ( optind < argc )
session_argv = argv + optind;
else
{
const char* home = getenv("HOME");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2015, 2016, 2022 Jonas 'Sortie' Termansen.
* Copyright (c) 2014, 2015, 2016, 2022, 2023 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
@ -20,6 +20,7 @@
#ifndef DISPLAY_H
#define DISPLAY_H
#include <sys/display.h>
#include <sys/ps2mouse.h>
#include <stdbool.h>
@ -31,6 +32,7 @@
enum mouse_state
{
MOUSE_STATE_NONE,
MOUSE_STATE_BUTTON_PRESS,
MOUSE_STATE_TITLE_MOVE,
MOUSE_STATE_RESIZE_BOTTOM,
MOUSE_STATE_RESIZE_BOTTOM_LEFT,
@ -46,6 +48,7 @@ struct window;
struct display
{
struct tiocgdisplay display;
struct framebuffer fb;
struct framebuffer wallpaper;
size_t fb_size;
@ -74,19 +77,23 @@ void assert_is_well_formed_display_list(struct display* display);
void assert_is_well_formed_display(struct display* display);
void display_link_window_at_top(struct display* display, struct window* window);
void display_unlink_window(struct display* display, struct window* window);
void display_unlink_window_removal(struct display* display, struct window* window);
void display_unmark_active_window(struct display* display, struct window* window);
void display_unlink_window_removal(struct display* display,
struct window* window);
void display_unmark_active_window(struct display* display,
struct window* window);
void display_mark_active_window(struct display* display, struct window* window);
void display_update_active_window(struct display* display);
void display_move_window_to_top(struct display* display, struct window* window);
void display_change_active_window(struct display* display, struct window* window);
void display_change_active_window(struct display* display,
struct window* window);
void display_set_active_window(struct display* display, struct window* window);
void display_add_window(struct display* display, struct window* window);
void display_remove_window(struct display* display, struct window* window);
void display_composit(struct display* display, struct framebuffer fb);
void display_render(struct display* display);
void display_keyboard_event(struct display* display, uint32_t codepoint);
void display_on_resolution_change(struct display* display, size_t width, size_t height);
void display_on_resolution_change(struct display* display, size_t width,
size_t height);
void display_mouse_event(struct display* display, uint8_t byte);
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2015, 2016 Jonas 'Sortie' Termansen.
* Copyright (c) 2014, 2015, 2016, 2023 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,6 +17,7 @@
* Display server main loop.
*/
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/termmode.h>
#include <sys/un.h>
@ -43,7 +44,7 @@ static int open_local_server_socket(const char* path, int flags)
{
size_t path_length = strlen(path);
size_t addr_size = offsetof(struct sockaddr_un, sun_path) + path_length + 1;
struct sockaddr_un* sockaddr = (struct sockaddr_un*) malloc(addr_size);
struct sockaddr_un* sockaddr = malloc(addr_size);
if ( !sockaddr )
return -1;
sockaddr->sun_family = AF_LOCAL;
@ -59,7 +60,8 @@ static int open_local_server_socket(const char* path, int flags)
return fd;
}
void server_initialize(struct server* server, struct display* display)
void server_initialize(struct server* server, struct display* display,
const char* tty, const char* mouse, const char* socket)
{
memset(server, 0, sizeof(*server));
@ -68,18 +70,27 @@ void server_initialize(struct server* server, struct display* display)
load_font();
server->tty_fd = 0;
if ( !isatty(server->tty_fd) )
if ( tty || !isatty(server->tty_fd) )
{
server->tty_fd = open("/dev/tty", O_RDONLY);
tty = tty ? tty : "/dev/tty";
server->tty_fd = open(tty, O_RDONLY);
if ( server->tty_fd < 0 )
err(1, "/dev/tty");
err(1, tty);
}
server->mouse_fd = open("/dev/mouse", O_RDONLY | O_CLOEXEC);
if ( server->mouse_fd < 0 )
err(1, "%s", "/dev/mouse");
// TODO: Support for multiple displays.
struct tiocgdisplays gdisplays = {0};
gdisplays.count = 1;
gdisplays.displays = &display->display;
if ( ioctl(server->tty_fd, TIOCGDISPLAYS, &gdisplays) < 0 ||
gdisplays.count == 0 )
errx(1, "%s: No video devices are associated with this terminal", tty);
server->server_path = "/run/display";
server->mouse_fd = open(mouse, O_RDONLY | O_CLOEXEC);
if ( server->mouse_fd < 0 )
err(1, "%s", mouse);
server->server_path = socket;
server->server_fd = open_local_server_socket(server->server_path,
SOCK_NONBLOCK | SOCK_CLOEXEC);
if ( server->server_fd < 0 )
@ -87,11 +98,11 @@ void server_initialize(struct server* server, struct display* display)
unsigned int termmode =
TERMMODE_KBKEY | TERMMODE_UNICODE | TERMMODE_NONBLOCK;
if ( settermmode(0, termmode) < 0 )
if ( settermmode(server->tty_fd, termmode) < 0 )
err(1, "settermmode");
server->pfds_count = server_pfds_count(server);
server->pfds = (struct pollfd*)
server->pfds =
reallocarray(NULL, sizeof(struct pollfd), server->pfds_count);
if ( !server->pfds )
err(1, "malloc");
@ -111,7 +122,7 @@ bool server_accept(struct server* server)
size_t new_length = server->connections_length * 2;
if ( !new_length )
new_length = 16;
struct connection** new_connections = (struct connection**)
struct connection** new_connections =
reallocarray(server->connections, new_length,
sizeof(struct connection*));
if ( !new_connections )
@ -125,7 +136,7 @@ bool server_accept(struct server* server)
}
size_t new_pfds_count = server_pfds_count(server) + 1;
struct pollfd* new_pfds = (struct pollfd*)
struct pollfd* new_pfds =
reallocarray(server->pfds, sizeof(struct pollfd), new_pfds_count);
if ( !new_pfds )
{
@ -136,8 +147,7 @@ bool server_accept(struct server* server)
server->pfds = new_pfds;
server->pfds_count = new_pfds_count;
struct connection* connection = (struct connection*)
malloc(sizeof(struct connection));
struct connection* connection = malloc(sizeof(struct connection));
if ( !connection )
{
warn("dropped connection: %s: malloc", server->server_path);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2015, 2016 Jonas 'Sortie' Termansen.
* Copyright (c) 2014, 2015, 2016, 2023 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
@ -41,7 +41,8 @@ struct server
size_t pfds_count;
};
void server_initialize(struct server* server, struct display* display);
void server_initialize(struct server* server, struct display* display,
const char* tty, const char* mouse, const char* socket);
bool server_accept(struct server* server);
size_t server_pfds_count(const struct server* server);
void server_poll(struct server* server);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2015, 2016, 2017, 2022 Jonas 'Sortie' Termansen.
* Copyright (c) 2014, 2015, 2016, 2017, 2022, 2023 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
@ -56,6 +56,8 @@ void window_render_frame(struct window* window)
: make_color_a(180, 180, 255, 128);
uint32_t title_color = has_focus ? make_color_a(16, 16, 16, 240)
: make_color_a(32, 32, 32, 200);
uint32_t button_hover_glass = make_color_a(220, 220, 255, 255);
uint32_t button_press_glass = make_color_a(180, 180, 255, 255);
size_t start_x = 0;
size_t start_y = 0;
@ -125,6 +127,21 @@ void window_render_frame(struct window* window)
for (size_t y = 0; y < button_height; y++)
framebuffer_set_pixel(buttons_fb, button_width * 2 + x, y, 0xFF8080FF);
#endif
for ( size_t n = 0; n < 3; n++ )
{
uint32_t color = glass_color;
switch ( window->button_states[n] )
{
case BUTTON_STATE_NORMAL: continue;
case BUTTON_STATE_HOVER: color = button_hover_glass; break;
case BUTTON_STATE_PRESSED: color = button_press_glass; break;
}
size_t bx = button_width * n;
size_t by = 0;
for ( size_t y = 0; y < tt_height; y++ )
for ( size_t x = 0; x < button_width; x++ )
framebuffer_set_pixel(buttons_fb, bx + x, by + y, color);
}
for ( size_t i = 0; i < button_size; i++ )
{
size_t bx = button_width * 0 + (button_width - button_size) / 2;
@ -191,7 +208,8 @@ void window_render_frame(struct window* window)
tt_width = buttons_x - border_width;
tt_width = 0 < tt_width ? tt_width : 0;
}
render_text(framebuffer_crop(window->buffer, tt_pos_x, tt_pos_y, tt_width, tt_height), tt, tt_color);
render_text(framebuffer_crop(window->buffer, tt_pos_x, tt_pos_y,
tt_width, tt_height), tt, tt_color);
}
void window_move(struct window* window, size_t left, size_t top)
@ -215,7 +233,8 @@ void window_client_resize(struct window* window,
window->buffer.xres = window->width;
window->buffer.yres = window->height;
window->buffer.pitch = window->width;
window->buffer.buffer = (uint32_t*)
// TODO: Check malloc.
window->buffer.buffer =
malloc(sizeof(uint32_t) * window->width * window->height);
for ( size_t y = 0; y < window->height; y++ )
for ( size_t x = 0; x < window->width; x++ )
@ -307,9 +326,10 @@ void window_destroy(struct window* window)
window->created = false;
}
void window_on_display_resolution_change(struct window* window, struct display* display)
void window_on_display_resolution_change(struct window* window,
struct display* display)
{
// TODO: Potentially move window back inside screen?
// TODO: Move window back inside screen.
if ( window->window_state == WINDOW_STATE_MAXIMIZED )
{
// TODO: Change size of maximized window.
@ -317,7 +337,8 @@ void window_on_display_resolution_change(struct window* window, struct display*
}
}
void window_tile(struct window* window, enum window_state state, size_t left, size_t top, size_t width, size_t height)
void window_tile(struct window* window, enum window_state state, size_t left,
size_t top, size_t width, size_t height)
{
if ( window->window_state == state )
return;
@ -337,12 +358,13 @@ void window_tile(struct window* window, enum window_state state, size_t left, si
window->width = width;
window->height = height;
// TODO: Share logic with window_client_resize.
window->buffer.xres = window->width;
window->buffer.yres = window->height;
window->buffer.pitch = window->width;
window->buffer.buffer = (uint32_t*)
malloc(sizeof(uint32_t) * window->width * window->height);
memset(window->buffer.buffer, 0, sizeof(uint32_t) * window->width * window->height);
// TODO: Check malloc.
window->buffer.buffer =
calloc(1, sizeof(uint32_t) * window->width * window->height);
window->window_state = state;
@ -363,7 +385,8 @@ void window_restore(struct window* window)
return;
window->top = window->saved_top;
window->left = window->saved_left;
window_client_resize(window, window->saved_width - 2 * BORDER_WIDTH, window->saved_height - TITLE_HEIGHT - BORDER_WIDTH);
window_client_resize(window, window->saved_width - 2 * BORDER_WIDTH,
window->saved_height - TITLE_HEIGHT - BORDER_WIDTH);
window_notify_client_resize(window);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2015, 2016, 2018, 2022 Jonas 'Sortie' Termansen.
* Copyright (c) 2014, 2015, 2016, 2018, 2022, 2023 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
@ -35,6 +35,13 @@ static const size_t BORDER_WIDTH = 8;
static const size_t TITLE_HEIGHT = 28;
static const size_t RESIZE_GRACE = 16;
enum button_state
{
BUTTON_STATE_NORMAL,
BUTTON_STATE_HOVER,
BUTTON_STATE_PRESSED,
};
enum window_state
{
WINDOW_STATE_REGULAR,
@ -68,6 +75,7 @@ struct window
size_t saved_height;
uint32_t window_id;
enum window_state window_state;
enum button_state button_states[3];
bool created;
bool show;
bool focus;
@ -78,16 +86,20 @@ struct framebuffer window_client_buffer(struct window* window);
void window_render_frame(struct window* window);
void window_move(struct window* window, size_t left, size_t top);
void window_resize(struct window* window, size_t width, size_t height);
void window_client_resize(struct window* window, size_t client_width, size_t client_height);
void window_initialize(struct window* window, struct connection* connection, struct display* display, uint32_t window_id);
void window_client_resize(struct window* window, size_t client_width,
size_t client_height);
void window_initialize(struct window* window, struct connection* connection,
struct display* display, uint32_t window_id);
void window_quit(struct window* window);
void window_destroy(struct window* window);
void window_drag_resize(struct window* window, int ld, int td, int wd, int hd);
void window_on_display_resolution_change(struct window* window, struct display* display);
void window_on_display_resolution_change(struct window* window,
struct display* display);
void window_maximize(struct window* window);
void window_restore(struct window* window);
void window_toggle_maximized(struct window* window);
void window_tile(struct window* window, enum window_state state, size_t left, size_t top, size_t width, size_t height);
void window_tile(struct window* window, enum window_state state, size_t left,
size_t top, size_t width, size_t height);
void window_tile_leftward(struct window* window);
void window_tile_rightward(struct window* window);
void window_tile_up(struct window* window);
@ -101,7 +113,6 @@ void window_tile_bottom(struct window* window);
void window_tile_bottom_left(struct window* window);
void window_tile_bottom_right(struct window* window);
void window_notify_client_resize(struct window* window);
size_t window_border_width(const struct window* window);
#endif

View File

@ -16,7 +16,7 @@ libdisplay.o \
all: $(LIBRARY)
.PHONY: all install uninstall clean
.PHONY: all install clean
install: all
mkdir -p $(DESTDIR)$(LIBDIR)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2015, 2016, 2017 Jonas 'Sortie' Termansen.
* Copyright (c) 2014, 2015, 2016, 2017, 2023 Jonas 'Sortie' Termansen.
* Copyright (c) 2023 Juhani 'nortti' Krekelä.
*
* Permission to use, copy, modify, and distribute this software for any
@ -100,7 +100,7 @@ struct display_connection* display_connect_default(void)
{
return display_connect(getenv("DISPLAY_SOCKET") ?
getenv("DISPLAY_SOCKET") :
"/run/display");
"/var/run/display");
}
void display_disconnect(struct display_connection* connection)

View File

@ -38,8 +38,8 @@
#include <unistd.h>
#include <display.h>
#include <nyan.h>
#include "nyan.h"
#include "pixel.h"
uint32_t WINDOW_ID = 0;

View File

@ -9,6 +9,7 @@ CFLAGS?=$(OPTLEVEL)
CFLAGS:=$(CFLAGS) -Wall -Wextra
PROGRAM=terminal
MANPAGES1 = terminal.1
OBJS=\
terminal.o \
@ -22,6 +23,8 @@ all: $(PROGRAM)
install: all
mkdir -p $(DESTDIR)$(BINDIR)
install $(PROGRAM) $(DESTDIR)$(BINDIR)
mkdir -p $(DESTDIR)$(MANDIR)/man1
install $(MANPAGES1) $(DESTDIR)$(MANDIR)/man1
$(PROGRAM): $(OBJS)
$(CC) -std=gnu11 $(CFLAGS) $(CPPFLAGS) $(OBJS) -o $@ $(LIBS)

44
terminal/terminal.1 Normal file
View File

@ -0,0 +1,44 @@
.Dd June 17, 2023
.Dt TERMINAL 1
.Os
.Sh NAME
.Nm terminal
.Nd graphical terminal emulator
.Sh SYNOPSIS
.Nm
.Op Ar command ...
.Sh DESCRIPTION
.Nm
is a graphical terminal emulator for the
.Xr display 1
desktop environment.
.Nm
has essentially the same features as the
.Xr kernel 7
console.
.Pp
The
.Ar command
is executed inside a
.Xr pts 4
psuedoterminal.
A login shell can be requested with a leading hyphen
.Sq - .
If no command was specified, the user's shell per
.Xr passwd 5
is run as a login shell with
.Xr sh 1
as a fallback.
.Sh ENVIRONMENT
.Bl -tag -width "TERM"
.It TERM Ns = Ns Sy sortix
The terminal type.
.El
.Sh EXIT STATUS
.Nm
will exit 0 on success and non-zero otherwise.
.Sh SEE ALSO
.Xr display 1 ,
.Xr sh 1 ,
.Xr pts 4 ,
.Xr tty 4