fixup! Add display server.

This commit is contained in:
Juhani Krekelä 2023-06-22 01:46:14 +03:00
parent 63260a916e
commit 6d08070639
7 changed files with 201 additions and 57 deletions

View File

@ -706,5 +706,8 @@ int main(int argc, char* argv[])
}
}
if ( use_display )
display_disconnect(connection);
return 0;
}

View File

@ -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),
};

View File

@ -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

View File

@ -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,

View File

@ -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;

View File

@ -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 <sys/types.h>
#include <ctype.h>
#include <display.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
@ -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));

View File

@ -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