2 * Server-side console management
4 * Copyright (C) 1998 Alexandre Julliard
6 * FIXME: all this stuff is a hack to avoid breaking
7 * the client-side console support.
16 #ifdef HAVE_SYS_ERRNO_H
17 #include <sys/errno.h>
21 #include <sys/types.h>
38 struct object obj
; /* object header */
39 struct select_user select
; /* select user */
40 int mode
; /* input mode */
41 struct screen_buffer
*output
; /* associated screen buffer */
42 int recnum
; /* number of input records */
43 INPUT_RECORD
*records
; /* input records */
48 struct object obj
; /* object header */
49 struct select_user select
; /* select user */
50 int mode
; /* output mode */
51 struct console_input
*input
; /* associated console input */
52 int cursor_size
; /* size of cursor (percentage filled) */
53 int cursor_visible
;/* cursor visibility flag */
54 int pid
; /* xterm pid (hack) */
55 char *title
; /* console title */
59 static void console_input_dump( struct object
*obj
, int verbose
);
60 static int console_input_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
61 static void console_input_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
62 static int console_input_signaled( struct object
*obj
, struct thread
*thread
);
63 static int console_input_get_read_fd( struct object
*obj
);
64 static void console_input_destroy( struct object
*obj
);
66 static void screen_buffer_dump( struct object
*obj
, int verbose
);
67 static int screen_buffer_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
68 static void screen_buffer_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
69 static int screen_buffer_signaled( struct object
*obj
, struct thread
*thread
);
70 static int screen_buffer_get_write_fd( struct object
*obj
);
71 static void screen_buffer_destroy( struct object
*obj
);
74 static int console_get_info( struct object
*obj
, struct get_file_info_request
*req
);
76 static const struct object_ops console_input_ops
=
78 sizeof(struct console_input
),
80 console_input_add_queue
,
81 console_input_remove_queue
,
82 console_input_signaled
,
84 console_input_get_read_fd
,
91 static const struct object_ops screen_buffer_ops
=
93 sizeof(struct screen_buffer
),
95 screen_buffer_add_queue
,
96 screen_buffer_remove_queue
,
97 screen_buffer_signaled
,
100 screen_buffer_get_write_fd
,
103 screen_buffer_destroy
107 static struct object
*create_console_input( int fd
)
109 struct console_input
*console_input
;
111 if ((fd
= (fd
!= -1) ? dup(fd
) : dup(0)) == -1)
116 if ((console_input
= alloc_object( &console_input_ops
)))
118 console_input
->select
.fd
= fd
;
119 console_input
->select
.func
= default_select_event
;
120 console_input
->select
.private = console_input
;
121 console_input
->mode
= ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
|
122 ENABLE_ECHO_INPUT
| ENABLE_MOUSE_INPUT
;
123 console_input
->output
= NULL
;
124 console_input
->recnum
= 0;
125 console_input
->records
= NULL
;
126 register_select_user( &console_input
->select
);
127 return &console_input
->obj
;
133 static struct object
*create_console_output( int fd
, struct object
*input
)
135 struct console_input
*console_input
= (struct console_input
*)input
;
136 struct screen_buffer
*screen_buffer
;
138 if ((fd
= (fd
!= -1) ? dup(fd
) : dup(1)) == -1)
143 if ((screen_buffer
= alloc_object( &screen_buffer_ops
)))
145 screen_buffer
->select
.fd
= fd
;
146 screen_buffer
->select
.func
= default_select_event
;
147 screen_buffer
->select
.private = screen_buffer
;
148 screen_buffer
->mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
149 screen_buffer
->input
= console_input
;
150 screen_buffer
->cursor_size
= 100;
151 screen_buffer
->cursor_visible
= 1;
152 screen_buffer
->pid
= 0;
153 screen_buffer
->title
= strdup( "Wine console" );
154 register_select_user( &screen_buffer
->select
);
155 console_input
->output
= screen_buffer
;
156 return &screen_buffer
->obj
;
162 /* allocate a console for this process */
163 int alloc_console( struct process
*process
)
165 if (process
->console_in
|| process
->console_out
)
167 set_error( ERROR_ACCESS_DENIED
);
170 if ((process
->console_in
= create_console_input( -1 )))
172 if ((process
->console_out
= create_console_output( -1, process
->console_in
)))
174 release_object( process
->console_in
);
179 /* free the console for this process */
180 int free_console( struct process
*process
)
182 if (process
->console_in
) release_object( process
->console_in
);
183 if (process
->console_out
) release_object( process
->console_out
);
184 process
->console_in
= process
->console_out
= NULL
;
188 static int set_console_fd( int handle
, int fd_in
, int fd_out
, int pid
)
190 struct console_input
*input
;
191 struct screen_buffer
*output
;
194 if (!(obj
= get_handle_obj( current
->process
, handle
, 0, NULL
)))
196 if (obj
->ops
== &console_input_ops
)
198 input
= (struct console_input
*)obj
;
199 output
= input
->output
;
200 grab_object( output
);
202 else if (obj
->ops
== &screen_buffer_ops
)
204 output
= (struct screen_buffer
*)obj
;
205 input
= output
->input
;
206 grab_object( input
);
210 set_error( ERROR_INVALID_HANDLE
);
211 release_object( obj
);
215 /* can't change the fd if someone is waiting on it */
216 assert( !input
->obj
.head
);
217 assert( !output
->obj
.head
);
219 unregister_select_user( &input
->select
);
220 unregister_select_user( &output
->select
);
221 close( input
->select
.fd
);
222 close( output
->select
.fd
);
223 input
->select
.fd
= fd_in
;
224 output
->select
.fd
= fd_out
;
226 register_select_user( &input
->select
);
227 register_select_user( &output
->select
);
228 release_object( input
);
229 release_object( output
);
233 static int get_console_mode( int handle
)
238 if ((obj
= get_handle_obj( current
->process
, handle
, GENERIC_READ
, NULL
)))
240 if (obj
->ops
== &console_input_ops
)
241 ret
= ((struct console_input
*)obj
)->mode
;
242 else if (obj
->ops
== &screen_buffer_ops
)
243 ret
= ((struct screen_buffer
*)obj
)->mode
;
245 set_error( ERROR_INVALID_HANDLE
);
246 release_object( obj
);
251 static int set_console_mode( int handle
, int mode
)
256 if (!(obj
= get_handle_obj( current
->process
, handle
, GENERIC_READ
, NULL
)))
258 if (obj
->ops
== &console_input_ops
)
260 ((struct console_input
*)obj
)->mode
= mode
;
263 else if (obj
->ops
== &screen_buffer_ops
)
265 ((struct screen_buffer
*)obj
)->mode
= mode
;
268 else set_error( ERROR_INVALID_HANDLE
);
269 release_object( obj
);
273 /* set misc console information (output handle only) */
274 static int set_console_info( int handle
, struct set_console_info_request
*req
,
275 const char *title
, size_t len
)
277 struct screen_buffer
*console
;
278 if (!(console
= (struct screen_buffer
*)get_handle_obj( current
->process
, handle
,
279 GENERIC_WRITE
, &screen_buffer_ops
)))
281 if (req
->mask
& SET_CONSOLE_INFO_CURSOR
)
283 console
->cursor_size
= req
->cursor_size
;
284 console
->cursor_visible
= req
->cursor_visible
;
286 if (req
->mask
& SET_CONSOLE_INFO_TITLE
)
288 char *new_title
= mem_alloc( len
+ 1 );
291 memcpy( new_title
, title
, len
);
293 if (console
->title
) free( console
->title
);
294 console
->title
= new_title
;
297 release_object( console
);
301 /* add input events to a console input queue */
302 static int write_console_input( int handle
, int count
, INPUT_RECORD
*records
)
304 INPUT_RECORD
*new_rec
;
305 struct console_input
*console
;
307 if (!(console
= (struct console_input
*)get_handle_obj( current
->process
, handle
,
308 GENERIC_WRITE
, &console_input_ops
)))
310 if (!(new_rec
= realloc( console
->records
,
311 (console
->recnum
+ count
) * sizeof(INPUT_RECORD
) )))
313 set_error( ERROR_NOT_ENOUGH_MEMORY
);
314 release_object( console
);
317 console
->records
= new_rec
;
318 memcpy( new_rec
+ console
->recnum
, records
, count
* sizeof(INPUT_RECORD
) );
319 console
->recnum
+= count
;
320 release_object( console
);
324 /* retrieve a pointer to the console input records */
325 static int read_console_input( int handle
, int count
, INPUT_RECORD
*rec
, int max
, int flush
)
327 struct console_input
*console
;
329 if (!(console
= (struct console_input
*)get_handle_obj( current
->process
, handle
,
330 GENERIC_READ
, &console_input_ops
)))
332 if ((count
< 0) || (count
> console
->recnum
)) count
= console
->recnum
;
333 if (count
> max
) count
= max
;
334 memcpy( rec
, console
->records
, count
* sizeof(INPUT_RECORD
) );
338 for (i
= count
; i
< console
->recnum
; i
++)
339 console
->records
[i
-count
] = console
->records
[i
];
340 if ((console
->recnum
-= count
) > 0)
342 INPUT_RECORD
*new_rec
= realloc( console
->records
,
343 console
->recnum
* sizeof(INPUT_RECORD
) );
344 if (new_rec
) console
->records
= new_rec
;
348 free( console
->records
);
349 console
->records
= NULL
;
352 release_object( console
);
356 static void console_input_dump( struct object
*obj
, int verbose
)
358 struct console_input
*console
= (struct console_input
*)obj
;
359 assert( obj
->ops
== &console_input_ops
);
360 fprintf( stderr
, "Console input fd=%d\n", console
->select
.fd
);
363 static int console_input_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
365 struct console_input
*console
= (struct console_input
*)obj
;
366 assert( obj
->ops
== &console_input_ops
);
367 if (!obj
->head
) /* first on the queue */
368 set_select_events( &console
->select
, READ_EVENT
);
369 add_queue( obj
, entry
);
373 static void console_input_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
375 struct console_input
*console
= (struct console_input
*)grab_object(obj
);
376 assert( obj
->ops
== &console_input_ops
);
378 remove_queue( obj
, entry
);
379 if (!obj
->head
) /* last on the queue is gone */
380 set_select_events( &console
->select
, 0 );
381 release_object( obj
);
384 static int console_input_signaled( struct object
*obj
, struct thread
*thread
)
386 struct console_input
*console
= (struct console_input
*)obj
;
387 assert( obj
->ops
== &console_input_ops
);
389 if (check_select_events( &console
->select
, READ_EVENT
))
391 /* stop waiting on select() if we are signaled */
392 set_select_events( &console
->select
, 0 );
397 /* restart waiting on select() if we are no longer signaled */
398 if (obj
->head
) set_select_events( &console
->select
, READ_EVENT
);
403 static int console_input_get_read_fd( struct object
*obj
)
405 struct console_input
*console
= (struct console_input
*)obj
;
406 assert( obj
->ops
== &console_input_ops
);
407 return dup( console
->select
.fd
);
410 static int console_get_info( struct object
*obj
, struct get_file_info_request
*req
)
412 req
->type
= FILE_TYPE_CHAR
;
414 req
->access_time
= 0;
425 static void console_input_destroy( struct object
*obj
)
427 struct console_input
*console
= (struct console_input
*)obj
;
428 assert( obj
->ops
== &console_input_ops
);
429 unregister_select_user( &console
->select
);
430 close( console
->select
.fd
);
431 if (console
->output
) console
->output
->input
= NULL
;
434 static void screen_buffer_dump( struct object
*obj
, int verbose
)
436 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
437 assert( obj
->ops
== &screen_buffer_ops
);
438 fprintf( stderr
, "Console screen buffer fd=%d\n", console
->select
.fd
);
441 static int screen_buffer_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
443 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
444 assert( obj
->ops
== &screen_buffer_ops
);
445 if (!obj
->head
) /* first on the queue */
446 set_select_events( &console
->select
, WRITE_EVENT
);
447 add_queue( obj
, entry
);
451 static void screen_buffer_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
453 struct screen_buffer
*console
= (struct screen_buffer
*)grab_object(obj
);
454 assert( obj
->ops
== &screen_buffer_ops
);
456 remove_queue( obj
, entry
);
457 if (!obj
->head
) /* last on the queue is gone */
458 set_select_events( &console
->select
, 0 );
459 release_object( obj
);
462 static int screen_buffer_signaled( struct object
*obj
, struct thread
*thread
)
464 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
465 assert( obj
->ops
== &screen_buffer_ops
);
467 if (check_select_events( &console
->select
, WRITE_EVENT
))
469 /* stop waiting on select() if we are signaled */
470 set_select_events( &console
->select
, 0 );
475 /* restart waiting on select() if we are no longer signaled */
476 if (obj
->head
) set_select_events( &console
->select
, WRITE_EVENT
);
481 static int screen_buffer_get_write_fd( struct object
*obj
)
483 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
484 assert( obj
->ops
== &screen_buffer_ops
);
485 return dup( console
->select
.fd
);
488 static void screen_buffer_destroy( struct object
*obj
)
490 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
491 assert( obj
->ops
== &screen_buffer_ops
);
492 unregister_select_user( &console
->select
);
493 close( console
->select
.fd
);
494 if (console
->input
) console
->input
->output
= NULL
;
495 if (console
->title
) free( console
->title
);
498 /* allocate a console for the current process */
499 DECL_HANDLER(alloc_console
)
501 int in
= -1, out
= -1;
503 if (!alloc_console( current
->process
)) goto done
;
505 if ((in
= alloc_handle( current
->process
, current
->process
->console_in
,
506 req
->access
, req
->inherit
)) != -1)
508 if ((out
= alloc_handle( current
->process
, current
->process
->console_out
,
509 req
->access
, req
->inherit
)) != -1)
510 goto done
; /* everything is fine */
511 close_handle( current
->process
, in
);
514 free_console( current
->process
);
518 req
->handle_out
= out
;
521 /* free the console of the current process */
522 DECL_HANDLER(free_console
)
524 free_console( current
->process
);
527 /* open a handle to the process console */
528 DECL_HANDLER(open_console
)
530 struct object
*obj
= req
->output
? current
->process
->console_out
: current
->process
->console_in
;
532 if (obj
) req
->handle
= alloc_handle( current
->process
, obj
, req
->access
, req
->inherit
);
533 else set_error( ERROR_ACCESS_DENIED
);
536 /* set info about a console (output only) */
537 DECL_HANDLER(set_console_info
)
539 size_t len
= get_req_strlen( req
->title
);
540 set_console_info( req
->handle
, req
, req
->title
, len
);
543 /* get info about a console (output only) */
544 DECL_HANDLER(get_console_info
)
546 struct screen_buffer
*console
;
547 if ((console
= (struct screen_buffer
*)get_handle_obj( current
->process
, req
->handle
,
548 GENERIC_READ
, &screen_buffer_ops
)))
550 req
->cursor_size
= console
->cursor_size
;
551 req
->cursor_visible
= console
->cursor_visible
;
552 req
->pid
= console
->pid
;
553 strcpy( req
->title
, console
->title
? console
->title
: "" );
554 release_object( console
);
558 /* set a console fd */
559 DECL_HANDLER(set_console_fd
)
564 if (!(obj
= get_handle_obj( current
->process
, req
->file_handle
,
565 GENERIC_READ
| GENERIC_WRITE
, NULL
))) return;
566 if ((fd_in
= obj
->ops
->get_read_fd( obj
)) == -1)
568 release_object( obj
);
571 fd_out
= obj
->ops
->get_write_fd( obj
);
572 release_object( obj
);
575 if (set_console_fd( req
->handle
, fd_in
, fd_out
, req
->pid
)) return;
581 /* get a console mode (input or output) */
582 DECL_HANDLER(get_console_mode
)
584 req
->mode
= get_console_mode( req
->handle
);
587 /* set a console mode (input or output) */
588 DECL_HANDLER(set_console_mode
)
590 set_console_mode( req
->handle
, req
->mode
);
593 /* add input records to a console input queue */
594 DECL_HANDLER(write_console_input
)
596 int max
= get_req_size( req
+ 1, sizeof(INPUT_RECORD
) );
597 int count
= req
->count
;
599 if (count
> max
) count
= max
;
600 req
->written
= write_console_input( req
->handle
, count
, (INPUT_RECORD
*)(req
+ 1) );
603 /* fetch input records from a console input queue */
604 DECL_HANDLER(read_console_input
)
606 int max
= get_req_size( req
+ 1, sizeof(INPUT_RECORD
) );
607 req
->read
= read_console_input( req
->handle
, req
->count
, (INPUT_RECORD
*)(req
+ 1),