Module: wine Branch: master Commit: 029843176b11404a77384b40ca3e9a99226477fe URL: https://source.winehq.org/git/wine.git/?a=commit;h=029843176b11404a77384b40c...
Author: Jacek Caban jacek@codeweavers.com Date: Thu Aug 27 15:04:48 2020 +0200
conhost: Initial support for screen buffers.
Signed-off-by: Jacek Caban jacek@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
programs/conhost/conhost.c | 100 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 2 deletions(-)
diff --git a/programs/conhost/conhost.c b/programs/conhost/conhost.c index 05a160f9cc..a5d9a8feeb 100644 --- a/programs/conhost/conhost.c +++ b/programs/conhost/conhost.c @@ -31,6 +31,7 @@
#include "wine/condrv.h" #include "wine/server.h" +#include "wine/rbtree.h" #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(conhost); @@ -45,6 +46,7 @@ struct console { HANDLE server; /* console server handle */ unsigned int mode; /* input mode */ + struct screen_buffer *active; /* active screen buffer */ INPUT_RECORD *records; /* input records */ unsigned int record_count; /* number of input records */ unsigned int record_size; /* size of input records buffer */ @@ -61,6 +63,15 @@ struct console unsigned int win; /* window handle if backend supports it */ };
+struct screen_buffer +{ + struct console *console; /* console reference */ + unsigned int id; /* screen buffer id */ + unsigned int width; /* size (w-h) of the screen buffer */ + unsigned int height; + struct wine_rb_entry entry; /* map entry */ +}; + static void *ioctl_buffer; static size_t ioctl_buffer_size;
@@ -76,6 +87,41 @@ static void *alloc_ioctl_buffer( size_t size ) return ioctl_buffer; }
+static int screen_buffer_compare_id( const void *key, const struct wine_rb_entry *entry ) +{ + struct screen_buffer *screen_buffer = WINE_RB_ENTRY_VALUE( entry, struct screen_buffer, entry ); + return (unsigned int)key - screen_buffer->id; +} + +static struct wine_rb_tree screen_buffer_map = { screen_buffer_compare_id }; + +static struct screen_buffer *create_screen_buffer( struct console *console, int id, int width, int height ) +{ + struct screen_buffer *screen_buffer; + + if (!(screen_buffer = malloc( sizeof(*screen_buffer) ))) return NULL; + screen_buffer->console = console; + screen_buffer->id = id; + screen_buffer->width = width; + screen_buffer->height = height; + + if (wine_rb_put( &screen_buffer_map, (const void *)id, &screen_buffer->entry )) + { + ERR( "id %x already exists\n", id ); + return NULL; + } + + return screen_buffer; +} + +static void destroy_screen_buffer( struct screen_buffer *screen_buffer ) +{ + if (screen_buffer->console->active == screen_buffer) + screen_buffer->console->active = NULL; + wine_rb_remove( &screen_buffer_map, &screen_buffer->entry ); + free( screen_buffer ); +} + static NTSTATUS read_console_input( struct console *console, size_t out_size ) { size_t count = min( out_size / sizeof(INPUT_RECORD), console->record_count ); @@ -158,7 +204,7 @@ static NTSTATUS set_console_title( struct console *console, const WCHAR *in_titl { WCHAR *title = NULL;
- TRACE( "%s\n", debugstr_wn(in_title, size) ); + TRACE( "%s\n", debugstr_wn(in_title, size / sizeof(WCHAR)) );
if (size) { @@ -171,6 +217,27 @@ static NTSTATUS set_console_title( struct console *console, const WCHAR *in_titl return STATUS_SUCCESS; }
+static NTSTATUS screen_buffer_ioctl( struct screen_buffer *screen_buffer, unsigned int code, + const void *in_data, size_t in_size, size_t *out_size ) +{ + switch (code) + { + case IOCTL_CONDRV_CLOSE_OUTPUT: + if (in_size || *out_size) return STATUS_INVALID_PARAMETER; + destroy_screen_buffer( screen_buffer ); + return STATUS_SUCCESS; + + case IOCTL_CONDRV_ACTIVATE: + if (in_size || *out_size) return STATUS_INVALID_PARAMETER; + screen_buffer->console->active = screen_buffer; + return STATUS_SUCCESS; + + default: + FIXME( "unsupported ioctl %x\n", code ); + return STATUS_NOT_SUPPORTED; + } +} + static NTSTATUS console_input_ioctl( struct console *console, unsigned int code, const void *in_data, size_t in_size, size_t *out_size ) { @@ -324,6 +391,7 @@ static NTSTATUS process_console_ioctls( struct console *console ) { size_t out_size = 0, in_size; unsigned int code; + int output; NTSTATUS status = STATUS_SUCCESS;
for (;;) @@ -339,6 +407,7 @@ static NTSTATUS process_console_ioctls( struct console *console ) wine_server_set_reply( req, ioctl_buffer, ioctl_buffer_size ); status = wine_server_call( req ); code = reply->code; + output = reply->output; out_size = reply->out_size; in_size = wine_server_reply_size( reply ); } @@ -357,7 +426,32 @@ static NTSTATUS process_console_ioctls( struct console *console ) return status; }
- status = console_input_ioctl( console, code, ioctl_buffer, in_size, &out_size ); + if (code == IOCTL_CONDRV_INIT_OUTPUT) + { + TRACE( "initializing output %x\n", output ); + if (console->active) + create_screen_buffer( console, output, console->active->width, console->active->height ); + else + create_screen_buffer( console, output, 80, 150 ); + } + else if (!output) + { + status = console_input_ioctl( console, code, ioctl_buffer, in_size, &out_size ); + } + else + { + struct wine_rb_entry *entry; + if (!(entry = wine_rb_get( &screen_buffer_map, (const void *)output ))) + { + ERR( "invalid screen buffer id %x\n", output ); + status = STATUS_INVALID_HANDLE; + } + else + { + status = screen_buffer_ioctl( WINE_RB_ENTRY_VALUE( entry, struct screen_buffer, entry ), code, + ioctl_buffer, in_size, &out_size ); + } + } } }
@@ -484,5 +578,7 @@ int __cdecl wmain(int argc, WCHAR *argv[]) return 1; }
+ if (!(console.active = create_screen_buffer( &console, 1, width, height ))) return 1; + return main_loop( &console, signal ); }