From 6d080706394a21cfc46b452575d4ab13b62f0d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juhani=20Krekel=C3=A4?= Date: Thu, 22 Jun 2023 01:46:14 +0300 Subject: [PATCH] fixup! Add display server. --- chvideomode/chvideomode.c | 3 + display/connection.c | 135 +++++++++++++++----------- libdisplay/include/display-protocol.h | 16 ++- libdisplay/include/display.h | 6 ++ libdisplay/libdisplay.c | 20 ++++ sysinstall/interactive.c | 76 ++++++++++++++- sysinstall/interactive.h | 2 +- 7 files changed, 201 insertions(+), 57 deletions(-) diff --git a/chvideomode/chvideomode.c b/chvideomode/chvideomode.c index 6657612c..045c4949 100644 --- a/chvideomode/chvideomode.c +++ b/chvideomode/chvideomode.c @@ -706,5 +706,8 @@ int main(int argc, char* argv[]) } } + if ( use_display ) + display_disconnect(connection); + return 0; } diff --git a/display/connection.c b/display/connection.c index 95cc1d18..57e2ccfb 100644 --- a/display/connection.c +++ b/display/connection.c @@ -76,6 +76,17 @@ void connection_schedule_transmit(struct connection* connection, connection->outgoing_used += count; } +void connection_schedule_ack_event(struct connection* connection, + uint32_t id, + int32_t error) +{ + struct event_ack event = { .id = id, .error = error }; + struct display_packet_header header = { .id = EVENT_ACK, + .size = sizeof(event) }; + connection_schedule_transmit(connection, &header, sizeof(header)); + connection_schedule_transmit(connection, &event, sizeof(event)); +} + void connection_initialize(struct connection* connection, struct display* display, int fd) @@ -235,18 +246,10 @@ CONNECTION_MESSAGE_HANDLER_NO_AUX(hide_window) CONNECTION_MESSAGE_HANDLER_SERVER(chkblayout) { - struct event_ack event; - event.id = msg->id; - event.error = 0; if ( tcsetblob(server->tty_fd, "kblayout", auxiliary, auxiliary_size) < 0 ) - event.error = errno; - - struct display_packet_header header; - header.id = EVENT_ACK; - header.size = sizeof(event); - - connection_schedule_transmit(connection, &header, sizeof(header)); - connection_schedule_transmit(connection, &event, sizeof(event)); + connection_schedule_ack_event(connection, msg->id, errno); + else + connection_schedule_ack_event(connection, msg->id, 0); } CONNECTION_MESSAGE_HANDLER_NO_AUX(request_displays) @@ -297,53 +300,84 @@ get_available_modes(const struct tiocgdisplay* display, CONNECTION_MESSAGE_HANDLER_NO_AUX_SERVER(request_display_modes) { - struct event_display_modes success; - success.id = msg->id; - success.modes_count = 0; - struct event_ack failure; - failure.id = msg->id; - failure.error = 0; + struct event_display_modes event; + event.id = msg->id; + event.modes_count = 0; struct dispmsg_crtc_mode* modes = NULL; // TODO: Multimonitor support. if ( msg->display_id != 0 ) - failure.error = EINVAL; - else { - size_t modes_count = 0; - modes = get_available_modes(&server->display->display, &modes_count); - if ( !modes ) - failure.error = errno; - else if ( (uint32_t) modes_count != modes_count ) - { - failure.error = EOVERFLOW; - free(modes); - } - success.modes_count = modes_count; - } - - if ( failure.error ) - { - struct display_packet_header header; - header.id = EVENT_ACK; - header.size = sizeof(failure); - - connection_schedule_transmit(connection, &header, sizeof(header)); - connection_schedule_transmit(connection, &failure, sizeof(failure)); + connection_schedule_ack_event(connection, msg->id, EINVAL); return; } + else + { + size_t modes_count; + modes = get_available_modes(&server->display->display, &modes_count); + if ( !modes ) + { + connection_schedule_ack_event(connection, msg->id, errno); + return; + } + else if ( (uint32_t) modes_count != modes_count ) + { + free(modes); + connection_schedule_ack_event(connection, msg->id, EOVERFLOW); + return; + } + event.modes_count = modes_count; + } - size_t modes_size = success.modes_count * sizeof(struct dispmsg_crtc_mode); + size_t modes_size = event.modes_count * sizeof(struct dispmsg_crtc_mode); struct display_packet_header header; header.id = EVENT_DISPLAY_MODES; - header.size = sizeof(success) + modes_size; + header.size = sizeof(event) + modes_size; connection_schedule_transmit(connection, &header, sizeof(header)); - connection_schedule_transmit(connection, &success, sizeof(success)); + connection_schedule_transmit(connection, &event, sizeof(event)); connection_schedule_transmit(connection, modes, modes_size); } +static bool get_current_mode(const struct tiocgdisplay* display, + struct dispmsg_crtc_mode* mode) +{ + struct dispmsg_set_crtc_mode msg; + msg.msgid = DISPMSG_GET_CRTC_MODE; + msg.device = display->device; + msg.connector = display->connector; + if ( dispmsg_issue(&msg, sizeof(msg)) ) + return false; + *mode = msg.mode; + return true; +} + +CONNECTION_MESSAGE_HANDLER_NO_AUX_SERVER(request_display_mode) +{ + struct event_display_mode event; + event.id = msg->id; + + // TODO: Multimonitor support. + if ( msg->display_id != 0 ) + { + connection_schedule_ack_event(connection, msg->id, EINVAL); + return; + } + else if ( !get_current_mode(&server->display->display, &event.mode) ) + { + connection_schedule_ack_event(connection, msg->id, EINVAL); + return; + } + + struct display_packet_header header; + header.id = EVENT_DISPLAY_MODE; + header.size = sizeof(event); + + connection_schedule_transmit(connection, &header, sizeof(header)); + connection_schedule_transmit(connection, &event, sizeof(event)); +} + static bool set_current_mode(const struct tiocgdisplay* display, struct dispmsg_crtc_mode mode) { @@ -357,21 +391,13 @@ static bool set_current_mode(const struct tiocgdisplay* display, CONNECTION_MESSAGE_HANDLER_NO_AUX_SERVER(set_display_mode) { - struct event_ack event; - event.id = msg->id; - event.error = 0; // TODO: Multimonitor support. if ( msg->display_id != 0 ) - event.error = EINVAL; + connection_schedule_ack_event(connection, msg->id, EINVAL); else if ( !set_current_mode(&server->display->display, msg->mode) ) - event.error = errno; - - struct display_packet_header header; - header.id = EVENT_ACK; - header.size = sizeof(event); - - connection_schedule_transmit(connection, &header, sizeof(header)); - connection_schedule_transmit(connection, &event, sizeof(event)); + connection_schedule_ack_event(connection, msg->id, errno); + else + connection_schedule_ack_event(connection, msg->id, 0); } typedef void (*connection_message_handler)(struct connection* connection, @@ -403,6 +429,7 @@ struct connection_message_handler_registration connection_message_handlers[] = REGISTER_CONNECTION_MESSAGE_HANDLER(chkblayout), REGISTER_CONNECTION_MESSAGE_HANDLER(request_displays), REGISTER_CONNECTION_MESSAGE_HANDLER(request_display_modes), + REGISTER_CONNECTION_MESSAGE_HANDLER(request_display_mode), REGISTER_CONNECTION_MESSAGE_HANDLER(set_display_mode), }; diff --git a/libdisplay/include/display-protocol.h b/libdisplay/include/display-protocol.h index eb196682..99a68db6 100644 --- a/libdisplay/include/display-protocol.h +++ b/libdisplay/include/display-protocol.h @@ -107,7 +107,14 @@ struct display_request_display_modes uint32_t display_id; }; -#define DISPLAY_SET_DISPLAY_MODE 11 +#define DISPLAY_REQUEST_DISPLAY_MODE 11 +struct display_request_display_mode +{ + uint32_t id; + uint32_t display_id; +}; + +#define DISPLAY_SET_DISPLAY_MODE 12 struct display_set_display_mode { uint32_t id; @@ -163,4 +170,11 @@ struct event_display_modes /* modes_count * sizeof(struct dispmsg_crtc_mode) video mode bytes follow */ }; +#define EVENT_DISPLAY_MODE 7 +struct event_display_mode +{ + uint32_t id; + struct dispmsg_crtc_mode mode; +}; + #endif diff --git a/libdisplay/include/display.h b/libdisplay/include/display.h index 5a617658..1153b6e0 100644 --- a/libdisplay/include/display.h +++ b/libdisplay/include/display.h @@ -71,6 +71,9 @@ void display_request_displays(struct display_connection* connection, void display_request_display_modes(struct display_connection* connection, uint32_t id, uint32_t display_id); +void display_request_display_mode(struct display_connection* connection, + uint32_t id, + uint32_t display_id); void display_set_display_mode(struct display_connection* connection, uint32_t id, uint32_t display_id, @@ -85,6 +88,8 @@ typedef void (*display_event_ack_handler_t)(void*, uint32_t, int32_t); typedef void (*display_event_displays_handler_t)(void*, uint32_t, uint32_t); typedef void (*display_event_display_modes_handler_t)(void*, uint32_t, uint32_t, void*, size_t); +typedef void (*display_event_display_mode_handler_t)(void*, uint32_t, + struct dispmsg_crtc_mode); struct display_event_handlers { @@ -96,6 +101,7 @@ struct display_event_handlers display_event_ack_handler_t ack_handler; display_event_displays_handler_t displays_handler; display_event_display_modes_handler_t display_modes_handler; + display_event_display_mode_handler_t display_mode_handler; }; int display_poll_event(struct display_connection* connection, diff --git a/libdisplay/libdisplay.c b/libdisplay/libdisplay.c index 867e876f..732e095b 100644 --- a/libdisplay/libdisplay.c +++ b/libdisplay/libdisplay.c @@ -249,6 +249,17 @@ void display_request_display_modes(struct display_connection* connection, sizeof(msg)); } +void display_request_display_mode(struct display_connection* connection, + uint32_t id, + uint32_t display_id) +{ + struct display_request_display_mode msg; + msg.id = id; + msg.display_id = display_id; + send_message_no_aux(connection, DISPLAY_REQUEST_DISPLAY_MODE, &msg, + sizeof(msg)); +} + void display_set_display_mode(struct display_connection* connection, uint32_t id, uint32_t display_id, @@ -381,6 +392,15 @@ static int display_dispatch_event(struct display_connection* connection, aux, aux_size); } + if ( connection->header.id == EVENT_DISPLAY_MODE && + connection->header.size == sizeof(struct event_display_mode) ) + { + struct event_display_mode* event = payload; + if ( handlers->display_mode_handler ) + handlers->display_mode_handler(handlers->context, event->id, + event->mode); + } + connection->header_got = 0; free(connection->payload); connection->payload = NULL; diff --git a/sysinstall/interactive.c b/sysinstall/interactive.c index 8ddd1df9..43974e58 100644 --- a/sysinstall/interactive.c +++ b/sysinstall/interactive.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2015, 2016, 2017 Jonas 'Sortie' Termansen. + * Copyright (c) 2015, 2016, 2017, 2023 Jonas 'Sortie' Termansen. + * Copyright (c) 2023 Juhani 'nortti' Krekelä. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -23,6 +24,7 @@ #include #include +#include #include #include #include @@ -40,6 +42,16 @@ #include "execute.h" #include "interactive.h" +#define REQUEST_DISPLAYS_ID 0 +#define REQUEST_DISPLAY_MODE_ID 1 + +static uint32_t displays_count; +static bool displays_count_received; + +static struct dispmsg_crtc_mode display_mode; +static int request_display_mode_error; +static bool display_mode_received; + void shlvl(void) { long shlvl = 0; @@ -265,8 +277,70 @@ bool missing_program(const char* program) return true; } +static void on_displays(void* ctx, uint32_t id, uint32_t displays) +{ + (void) ctx; + if ( id != REQUEST_DISPLAYS_ID ) + return; + displays_count = displays; + displays_count_received = true; +} + +static void on_display_mode(void* ctx, uint32_t id, + struct dispmsg_crtc_mode mode) +{ + (void) ctx; + if ( id != REQUEST_DISPLAY_MODE_ID ) + return; + display_mode = mode; + request_display_mode_error = 0; + display_mode_received = true; +} + +static void on_ack(void* ctx, uint32_t id, int32_t error) +{ + (void) ctx; + if ( id != REQUEST_DISPLAY_MODE_ID ) + return; + if ( error ) + { + request_display_mode_error = error; + display_mode_received = true; + } +} + bool get_video_mode(struct dispmsg_crtc_mode* mode) { + if ( getenv("DISPLAY_SOCKET") ) + { + struct display_connection* connection = display_connect_default(); + if ( !connection ) + return false; + struct display_event_handlers handlers = {0}; + handlers.displays_handler = on_displays; + handlers.display_mode_handler = on_display_mode; + handlers.ack_handler = on_ack; + display_request_displays(connection, REQUEST_DISPLAYS_ID); + displays_count_received = false; + while ( !displays_count_received ) + display_wait_event(connection, &handlers); + if ( displays_count < 1 ) + { + display_disconnect(connection); + return false; + } + // TODO: Multimonitor support. + display_request_display_mode(connection, REQUEST_DISPLAY_MODE_ID, 0); + display_mode_received = false; + while ( !display_mode_received ) + display_wait_event(connection, &handlers); + display_disconnect(connection); + if ( request_display_mode_error ) + return false; + *mode = display_mode; + return true; + } + struct tiocgdisplay display; struct tiocgdisplays gdisplays; memset(&gdisplays, 0, sizeof(gdisplays)); diff --git a/sysinstall/interactive.h b/sysinstall/interactive.h index 10d04447..2319f0b4 100644 --- a/sysinstall/interactive.h +++ b/sysinstall/interactive.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016 Jonas 'Sortie' Termansen. + * Copyright (c) 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