server: Enhanced the console input object so that it doesn't require a wineconsole to be running.
This commit is contained in:
parent
258dba1a52
commit
b39a8d9ea2
|
@ -1426,6 +1426,8 @@ struct alloc_console_request
|
|||
unsigned int access;
|
||||
unsigned int attributes;
|
||||
process_id_t pid;
|
||||
int input_fd;
|
||||
char __pad_28[4];
|
||||
};
|
||||
struct alloc_console_reply
|
||||
{
|
||||
|
@ -5504,6 +5506,6 @@ union generic_reply
|
|||
struct set_cursor_reply set_cursor_reply;
|
||||
};
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 404
|
||||
#define SERVER_PROTOCOL_VERSION 405
|
||||
|
||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||
|
|
|
@ -596,6 +596,7 @@ static struct inner_data* WINECON_Init(HINSTANCE hInst, DWORD pid, LPCWSTR appna
|
|||
req->access = GENERIC_READ | GENERIC_WRITE;
|
||||
req->attributes = 0;
|
||||
req->pid = pid;
|
||||
req->input_fd = -1;
|
||||
|
||||
ret = !wine_server_call_err( req );
|
||||
data->hConIn = wine_server_ptr_handle( reply->handle_in );
|
||||
|
|
153
server/console.c
153
server/console.c
|
@ -28,6 +28,9 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
|
@ -62,10 +65,13 @@ struct console_input
|
|||
int output_cp; /* console output codepage */
|
||||
user_handle_t win; /* window handle if backend supports it */
|
||||
struct event *event; /* event to wait on for input queue */
|
||||
struct fd *fd; /* for bare console, attached input fd */
|
||||
struct termios termios; /* for bare console, saved termio info */
|
||||
};
|
||||
|
||||
static void console_input_dump( struct object *obj, int verbose );
|
||||
static void console_input_destroy( struct object *obj );
|
||||
static struct fd *console_input_get_fd( struct object *obj );
|
||||
|
||||
static const struct object_ops console_input_ops =
|
||||
{
|
||||
|
@ -77,7 +83,7 @@ static const struct object_ops console_input_ops =
|
|||
NULL, /* signaled */
|
||||
no_satisfied, /* satisfied */
|
||||
no_signal, /* signal */
|
||||
no_get_fd, /* get_fd */
|
||||
console_input_get_fd, /* get_fd */
|
||||
default_fd_map_access, /* map_access */
|
||||
default_get_sd, /* get_sd */
|
||||
default_set_sd, /* set_sd */
|
||||
|
@ -162,10 +168,36 @@ static const struct object_ops screen_buffer_ops =
|
|||
screen_buffer_destroy /* destroy */
|
||||
};
|
||||
|
||||
static enum server_fd_type console_get_fd_type( struct fd *fd );
|
||||
|
||||
static const struct fd_ops console_fd_ops =
|
||||
{
|
||||
default_fd_get_poll_events, /* get_poll_events */
|
||||
default_poll_event, /* poll_event */
|
||||
no_flush, /* flush */
|
||||
console_get_fd_type, /* get_fd_type */
|
||||
default_fd_ioctl, /* ioctl */
|
||||
default_fd_queue_async, /* queue_async */
|
||||
default_fd_reselect_async, /* reselect_async */
|
||||
default_fd_cancel_async /* cancel_async */
|
||||
};
|
||||
|
||||
static struct list screen_buffer_list = LIST_INIT(screen_buffer_list);
|
||||
|
||||
static const char_info_t empty_char_info = { ' ', 0x000f }; /* white on black space */
|
||||
|
||||
static struct fd *console_input_get_fd( struct object* obj )
|
||||
{
|
||||
struct console_input *console_input = (struct console_input*)obj;
|
||||
assert( obj->ops == &console_input_ops );
|
||||
return console_input->fd ? (struct fd*)grab_object( console_input->fd ) : NULL;
|
||||
}
|
||||
|
||||
static enum server_fd_type console_get_fd_type( struct fd *fd )
|
||||
{
|
||||
return FD_TYPE_CHAR;
|
||||
}
|
||||
|
||||
/* dumps the renderer events of a console */
|
||||
static void console_input_events_dump( struct object *obj, int verbose )
|
||||
{
|
||||
|
@ -197,7 +229,8 @@ static void console_input_events_append( struct console_input_events* evts,
|
|||
{
|
||||
int collapsed = FALSE;
|
||||
|
||||
/* to be done even when evt has been generated by the rendere ? */
|
||||
if (!evts) return;
|
||||
/* to be done even when evt has been generated by the renderer ? */
|
||||
|
||||
/* try to collapse evt into current queue's events */
|
||||
if (evts->num_used)
|
||||
|
@ -255,7 +288,7 @@ static struct console_input_events *create_console_input_events(void)
|
|||
return evt;
|
||||
}
|
||||
|
||||
static struct object *create_console_input( struct thread* renderer )
|
||||
static struct object *create_console_input( struct thread* renderer, int fd )
|
||||
{
|
||||
struct console_input *console_input;
|
||||
|
||||
|
@ -267,7 +300,7 @@ static struct object *create_console_input( struct thread* renderer )
|
|||
console_input->active = NULL;
|
||||
console_input->recnum = 0;
|
||||
console_input->records = NULL;
|
||||
console_input->evt = create_console_input_events();
|
||||
console_input->evt = renderer ? create_console_input_events() : NULL;
|
||||
console_input->title = NULL;
|
||||
console_input->history_size = 50;
|
||||
console_input->history = calloc( console_input->history_size, sizeof(WCHAR*) );
|
||||
|
@ -278,12 +311,50 @@ static struct object *create_console_input( struct thread* renderer )
|
|||
console_input->output_cp = 0;
|
||||
console_input->win = 0;
|
||||
console_input->event = create_event( NULL, NULL, 0, 1, 0, NULL );
|
||||
console_input->fd = NULL;
|
||||
|
||||
if (!console_input->history || !console_input->evt || !console_input->event)
|
||||
if (!console_input->history || (renderer && !console_input->evt) || !console_input->event)
|
||||
{
|
||||
release_object( console_input );
|
||||
return NULL;
|
||||
}
|
||||
if (fd != -1) /* bare console */
|
||||
{
|
||||
struct termios term;
|
||||
|
||||
if (!(console_input->fd = create_anonymous_fd( &console_fd_ops, fd, &console_input->obj,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT )))
|
||||
{
|
||||
release_object( console_input );
|
||||
return NULL;
|
||||
}
|
||||
if (tcgetattr(fd, &term) < 0)
|
||||
{
|
||||
release_object( console_input );
|
||||
set_error( STATUS_INVALID_HANDLE );
|
||||
return NULL;
|
||||
}
|
||||
console_input->termios = term;
|
||||
term.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
|
||||
term.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
||||
term.c_cflag &= ~(CSIZE | PARENB);
|
||||
term.c_cflag |= CS8;
|
||||
/* FIXME: we should actually disable output processing here
|
||||
* and let kernel32/console.c do the job (with support of enable/disable of
|
||||
* processed output)
|
||||
*/
|
||||
/* term.c_oflag &= ~(OPOST); */
|
||||
term.c_cc[VMIN] = 1;
|
||||
term.c_cc[VTIME] = 0;
|
||||
if (tcsetattr(fd, TCSANOW, &term) < 0)
|
||||
{
|
||||
release_object( console_input );
|
||||
set_error( STATUS_INVALID_HANDLE );
|
||||
return NULL;
|
||||
}
|
||||
allow_fd_caching( console_input->fd );
|
||||
}
|
||||
|
||||
return &console_input->obj;
|
||||
}
|
||||
|
||||
|
@ -374,10 +445,10 @@ int free_console( struct process *process )
|
|||
{
|
||||
struct console_input* console = process->console;
|
||||
|
||||
if (!console || !console->renderer) return 0;
|
||||
if (!console) return 0;
|
||||
|
||||
process->console = NULL;
|
||||
if (--console->num_proc == 0)
|
||||
if (--console->num_proc == 0 && console->renderer)
|
||||
{
|
||||
/* all processes have terminated... tell the renderer to terminate too */
|
||||
struct console_renderer_event evt;
|
||||
|
@ -424,7 +495,6 @@ void inherit_console(struct thread *parent_thread, struct process *process, obj_
|
|||
/* otherwise, if parent has a console, attach child to this console */
|
||||
if (!done && parent->console)
|
||||
{
|
||||
assert(parent->console->renderer);
|
||||
process->console = (struct console_input*)grab_object( parent->console );
|
||||
process->console->num_proc++;
|
||||
}
|
||||
|
@ -444,7 +514,6 @@ static struct console_input* console_input_get( obj_handle_t handle, unsigned ac
|
|||
access, &console_input_ops );
|
||||
else if (current->process->console)
|
||||
{
|
||||
assert( current->process->console->renderer );
|
||||
console = (struct console_input *)grab_object( current->process->console );
|
||||
}
|
||||
|
||||
|
@ -1020,9 +1089,17 @@ static void console_input_destroy( struct object *obj )
|
|||
if (curr->input == console_in) curr->input = NULL;
|
||||
}
|
||||
|
||||
release_object( console_in->evt );
|
||||
console_in->evt = NULL;
|
||||
if (console_in->evt)
|
||||
{
|
||||
release_object( console_in->evt );
|
||||
console_in->evt = NULL;
|
||||
}
|
||||
release_object( console_in->event );
|
||||
if (console_in->fd)
|
||||
{
|
||||
tcsetattr(get_unix_fd(console_in->fd), TCSANOW, &console_in->termios);
|
||||
release_object( console_in->fd );
|
||||
}
|
||||
|
||||
for (i = 0; i < console_in->history_size; i++)
|
||||
free( console_in->history[i] );
|
||||
|
@ -1295,35 +1372,58 @@ DECL_HANDLER(alloc_console)
|
|||
obj_handle_t in = 0;
|
||||
obj_handle_t evt = 0;
|
||||
struct process *process;
|
||||
struct thread *renderer;
|
||||
struct console_input *console;
|
||||
int fd;
|
||||
|
||||
if (req->pid)
|
||||
{
|
||||
if (!(process = get_process_from_id( req->pid ))) return;
|
||||
}
|
||||
else
|
||||
switch (req->pid)
|
||||
{
|
||||
case 0:
|
||||
/* renderer is current, console to be attached to parent process */
|
||||
renderer = current;
|
||||
if (!(process = current->process->parent))
|
||||
{
|
||||
set_error( STATUS_ACCESS_DENIED );
|
||||
return;
|
||||
}
|
||||
grab_object( process );
|
||||
break;
|
||||
case 0xffffffff:
|
||||
/* no renderer, console to be attached to current process */
|
||||
renderer = NULL;
|
||||
process = current->process;
|
||||
grab_object( process );
|
||||
break;
|
||||
default:
|
||||
/* renderer is current, console to be attached to req->pid */
|
||||
renderer = current;
|
||||
if (!(process = get_process_from_id( req->pid ))) return;
|
||||
}
|
||||
|
||||
if (process != current->process && process->console)
|
||||
{
|
||||
set_error( STATUS_ACCESS_DENIED );
|
||||
else if ((console = (struct console_input*)create_console_input( current )))
|
||||
goto the_end;
|
||||
}
|
||||
if (req->input_fd != -1)
|
||||
{
|
||||
if ((fd = thread_get_inflight_fd( current, req->input_fd )) == -1)
|
||||
{
|
||||
set_error( STATUS_INVALID_PARAMETER );
|
||||
goto the_end;
|
||||
}
|
||||
}
|
||||
else fd = -1;
|
||||
|
||||
if ((console = (struct console_input*)create_console_input( renderer, fd )))
|
||||
{
|
||||
if ((in = alloc_handle( current->process, console, req->access, req->attributes )))
|
||||
{
|
||||
if ((evt = alloc_handle( current->process, console->evt, SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE, 0 )))
|
||||
if (!console->evt ||
|
||||
(evt = alloc_handle( current->process, console->evt, SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE, 0 )))
|
||||
{
|
||||
if (process != current->process)
|
||||
{
|
||||
process->console = (struct console_input*)grab_object( console );
|
||||
console->num_proc++;
|
||||
}
|
||||
process->console = (struct console_input*)grab_object( console );
|
||||
console->num_proc++;
|
||||
reply->handle_in = in;
|
||||
reply->event = evt;
|
||||
release_object( console );
|
||||
|
@ -1363,13 +1463,12 @@ DECL_HANDLER(open_console)
|
|||
reply->handle = 0;
|
||||
if (!req->from)
|
||||
{
|
||||
if (current->process->console && current->process->console->renderer)
|
||||
if (current->process->console)
|
||||
obj = grab_object( (struct object*)current->process->console );
|
||||
}
|
||||
else if (req->from == (obj_handle_t)1)
|
||||
{
|
||||
if (current->process->console && current->process->console->renderer &&
|
||||
current->process->console->active)
|
||||
if (current->process->console && current->process->console->active)
|
||||
obj = grab_object( (struct object*)current->process->console->active );
|
||||
}
|
||||
else if ((obj = get_handle_obj( current->process, req->from,
|
||||
|
@ -1608,7 +1707,7 @@ DECL_HANDLER(get_console_wait_event)
|
|||
{
|
||||
struct console_input* console = NULL;
|
||||
|
||||
if (current->process->console && current->process->console->renderer)
|
||||
if (current->process->console)
|
||||
console = (struct console_input*)grab_object( (struct object*)current->process->console );
|
||||
else enum_processes(cgwe_enum, &console);
|
||||
|
||||
|
|
|
@ -426,8 +426,12 @@ static int debugger_attach( struct process *process, struct thread *debugger )
|
|||
if (list_empty( &process->thread_list )) goto error; /* no thread running in the process */
|
||||
|
||||
/* don't let a debugger debug its console... won't work */
|
||||
if (debugger->process->console && console_get_renderer(debugger->process->console)->process == process)
|
||||
goto error;
|
||||
if (debugger->process->console)
|
||||
{
|
||||
struct thread *renderer = console_get_renderer(debugger->process->console);
|
||||
if (renderer && renderer->process == process)
|
||||
goto error;
|
||||
}
|
||||
|
||||
suspend_process( process );
|
||||
if (!set_process_debugger( process, debugger ))
|
||||
|
|
|
@ -1137,6 +1137,7 @@ enum server_fd_type
|
|||
unsigned int access; /* wanted access rights */
|
||||
unsigned int attributes; /* object attributes */
|
||||
process_id_t pid; /* pid of process which shall be attached to the console */
|
||||
int input_fd; /* if pid=-1 (bare console to current process), fd for input */
|
||||
@REPLY
|
||||
obj_handle_t handle_in; /* handle to console input */
|
||||
obj_handle_t event; /* handle to renderer events change notification */
|
||||
|
|
|
@ -954,7 +954,8 @@ C_ASSERT( sizeof(struct set_socket_deferred_request) == 24 );
|
|||
C_ASSERT( FIELD_OFFSET(struct alloc_console_request, access) == 12 );
|
||||
C_ASSERT( FIELD_OFFSET(struct alloc_console_request, attributes) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct alloc_console_request, pid) == 20 );
|
||||
C_ASSERT( sizeof(struct alloc_console_request) == 24 );
|
||||
C_ASSERT( FIELD_OFFSET(struct alloc_console_request, input_fd) == 24 );
|
||||
C_ASSERT( sizeof(struct alloc_console_request) == 32 );
|
||||
C_ASSERT( FIELD_OFFSET(struct alloc_console_reply, handle_in) == 8 );
|
||||
C_ASSERT( FIELD_OFFSET(struct alloc_console_reply, event) == 12 );
|
||||
C_ASSERT( sizeof(struct alloc_console_reply) == 16 );
|
||||
|
|
|
@ -1588,6 +1588,7 @@ static void dump_alloc_console_request( const struct alloc_console_request *req
|
|||
fprintf( stderr, " access=%08x", req->access );
|
||||
fprintf( stderr, ", attributes=%08x", req->attributes );
|
||||
fprintf( stderr, ", pid=%04x", req->pid );
|
||||
fprintf( stderr, ", input_fd=%d", req->input_fd );
|
||||
}
|
||||
|
||||
static void dump_alloc_console_reply( const struct alloc_console_reply *req )
|
||||
|
|
Loading…
Reference in New Issue