Compare commits
37 Commits
08b581914d
...
039d9b8ea5
Author | SHA1 | Date |
---|---|---|
Jonas 'Sortie' Termansen | 039d9b8ea5 | |
Jonas 'Sortie' Termansen | 2bda23891d | |
Jonas 'Sortie' Termansen | 11a5d5a08a | |
Jonas 'Sortie' Termansen | 28e7a0f4df | |
Jonas 'Sortie' Termansen | 22be4abaa4 | |
Jonas 'Sortie' Termansen | c7d5b41605 | |
Jonas 'Sortie' Termansen | 09bed49d56 | |
Jonas 'Sortie' Termansen | 0aad618aab | |
Jonas 'Sortie' Termansen | 437bc6ef69 | |
Jonas 'Sortie' Termansen | d7ef9c126b | |
Jonas 'Sortie' Termansen | 3ee481562a | |
Jonas 'Sortie' Termansen | 5a0bdac8e8 | |
Jonas 'Sortie' Termansen | 7a606cab32 | |
Jonas 'Sortie' Termansen | ff494650f0 | |
Jonas 'Sortie' Termansen | fa1e285634 | |
Jonas 'Sortie' Termansen | 76de810d00 | |
Jonas 'Sortie' Termansen | edaa069a79 | |
Jonas 'Sortie' Termansen | 7e4eae1ad4 | |
Jonas 'Sortie' Termansen | cca0c715dd | |
Jonas 'Sortie' Termansen | fe48a71a4d | |
Jonas 'Sortie' Termansen | 757957b601 | |
Jonas 'Sortie' Termansen | a15169a9bf | |
Jonas 'Sortie' Termansen | af0b3c8bc8 | |
Jonas 'Sortie' Termansen | 1159ac09fe | |
Jonas 'Sortie' Termansen | a5e1dede5a | |
Jonas 'Sortie' Termansen | f775878f23 | |
Jonas 'Sortie' Termansen | ef8fddd3b4 | |
Jonas 'Sortie' Termansen | ad448cdf7e | |
Jonas 'Sortie' Termansen | 588c308893 | |
Jonas 'Sortie' Termansen | 270610e9df | |
Jonas 'Sortie' Termansen | 648b2fc3da | |
Jonas 'Sortie' Termansen | 97bcd7b883 | |
Jonas 'Sortie' Termansen | f89c0ae76e | |
Jonas 'Sortie' Termansen | 2645cbaca1 | |
Jonas 'Sortie' Termansen | 07d3ceba96 | |
Juhani Krekelä | 0660d420f3 | |
Juhani Krekelä | 1773d6a131 |
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -16,7 +16,7 @@ libdisplay.o \
|
|||
|
||||
all: $(LIBRARY)
|
||||
|
||||
.PHONY: all install uninstall clean
|
||||
.PHONY: all install clean
|
||||
|
||||
install: all
|
||||
mkdir -p $(DESTDIR)$(LIBDIR)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -38,8 +38,8 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include <display.h>
|
||||
#include <nyan.h>
|
||||
|
||||
#include "nyan.h"
|
||||
#include "pixel.h"
|
||||
|
||||
uint32_t WINDOW_ID = 0;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue