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.
18 #ifdef HAVE_SYS_ERRNO_H
19 #include <sys/errno.h>
23 #include <sys/types.h>
39 struct object obj
; /* object header */
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 int mode
; /* output mode */
50 struct console_input
*input
; /* associated console input */
51 int cursor_size
; /* size of cursor (percentage filled) */
52 int cursor_visible
;/* cursor visibility flag */
53 int pid
; /* xterm pid (hack) */
54 char *title
; /* console title */
58 static void console_input_dump( struct object
*obj
, int verbose
);
59 static int console_input_get_poll_events( struct object
*obj
);
60 static int console_input_get_read_fd( struct object
*obj
);
61 static void console_input_destroy( struct object
*obj
);
63 static void screen_buffer_dump( struct object
*obj
, int verbose
);
64 static int screen_buffer_get_poll_events( struct object
*obj
);
65 static int screen_buffer_get_write_fd( struct object
*obj
);
66 static void screen_buffer_destroy( struct object
*obj
);
69 static int console_get_info( struct object
*obj
, struct get_file_info_request
*req
);
71 static const struct object_ops console_input_ops
=
73 sizeof(struct console_input
), /* size */
74 console_input_dump
, /* dump */
75 default_poll_add_queue
, /* add_queue */
76 default_poll_remove_queue
, /* remove_queue */
77 default_poll_signaled
, /* signaled */
78 no_satisfied
, /* satisfied */
79 console_input_get_poll_events
, /* get_poll_events */
80 default_poll_event
, /* poll_event */
81 console_input_get_read_fd
, /* get_read_fd */
82 no_write_fd
, /* get_write_fd */
84 console_get_info
, /* get_file_info */
85 console_input_destroy
/* destroy */
88 static const struct object_ops screen_buffer_ops
=
90 sizeof(struct screen_buffer
), /* size */
91 screen_buffer_dump
, /* dump */
92 default_poll_add_queue
, /* add_queue */
93 default_poll_remove_queue
, /* remove_queue */
94 default_poll_signaled
, /* signaled */
95 no_satisfied
, /* satisfied */
96 screen_buffer_get_poll_events
, /* get_poll_events */
97 default_poll_event
, /* poll_event */
98 no_read_fd
, /* get_read_fd */
99 screen_buffer_get_write_fd
, /* get_write_fd */
100 no_flush
, /* flush */
101 console_get_info
, /* get_file_info */
102 screen_buffer_destroy
/* destroy */
106 static struct object
*create_console_input( int fd
)
108 struct console_input
*console_input
;
110 if ((fd
= (fd
!= -1) ? dup(fd
) : dup(0)) == -1)
115 if (!(console_input
= alloc_object( &console_input_ops
, fd
))) return NULL
;
116 console_input
->mode
= ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
|
117 ENABLE_ECHO_INPUT
| ENABLE_MOUSE_INPUT
;
118 console_input
->output
= NULL
;
119 console_input
->recnum
= 0;
120 console_input
->records
= NULL
;
121 return &console_input
->obj
;
124 static struct object
*create_console_output( int fd
, struct object
*input
)
126 struct console_input
*console_input
= (struct console_input
*)input
;
127 struct screen_buffer
*screen_buffer
;
129 if ((fd
= (fd
!= -1) ? dup(fd
) : dup(1)) == -1)
134 if (!(screen_buffer
= alloc_object( &screen_buffer_ops
, fd
))) return NULL
;
135 screen_buffer
->mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
136 screen_buffer
->input
= console_input
;
137 screen_buffer
->cursor_size
= 100;
138 screen_buffer
->cursor_visible
= 1;
139 screen_buffer
->pid
= 0;
140 screen_buffer
->title
= strdup( "Wine console" );
141 console_input
->output
= screen_buffer
;
142 return &screen_buffer
->obj
;
145 /* allocate a console for this process */
146 int alloc_console( struct process
*process
)
148 if (process
->console_in
|| process
->console_out
)
150 set_error( STATUS_ACCESS_DENIED
);
153 if ((process
->console_in
= create_console_input( -1 )))
155 if ((process
->console_out
= create_console_output( -1, process
->console_in
)))
157 release_object( process
->console_in
);
162 /* free the console for this process */
163 int free_console( struct process
*process
)
165 if (process
->console_in
) release_object( process
->console_in
);
166 if (process
->console_out
) release_object( process
->console_out
);
167 process
->console_in
= process
->console_out
= NULL
;
171 static int set_console_fd( int handle
, int fd_in
, int fd_out
, int pid
)
173 struct console_input
*input
;
174 struct screen_buffer
*output
;
177 if (!(obj
= get_handle_obj( current
->process
, handle
, 0, NULL
)))
179 if (obj
->ops
== &console_input_ops
)
181 input
= (struct console_input
*)obj
;
182 output
= input
->output
;
183 grab_object( output
);
185 else if (obj
->ops
== &screen_buffer_ops
)
187 output
= (struct screen_buffer
*)obj
;
188 input
= output
->input
;
189 grab_object( input
);
193 set_error( STATUS_OBJECT_TYPE_MISMATCH
);
194 release_object( obj
);
198 /* can't change the fd if someone is waiting on it */
199 assert( !input
->obj
.head
);
200 assert( !output
->obj
.head
);
202 change_select_fd( &input
->obj
, fd_in
);
203 change_select_fd( &output
->obj
, fd_out
);
205 release_object( input
);
206 release_object( output
);
210 static int get_console_mode( int handle
)
215 if ((obj
= get_handle_obj( current
->process
, handle
, GENERIC_READ
, NULL
)))
217 if (obj
->ops
== &console_input_ops
)
218 ret
= ((struct console_input
*)obj
)->mode
;
219 else if (obj
->ops
== &screen_buffer_ops
)
220 ret
= ((struct screen_buffer
*)obj
)->mode
;
222 set_error( STATUS_OBJECT_TYPE_MISMATCH
);
223 release_object( obj
);
228 static int set_console_mode( int handle
, int mode
)
233 if (!(obj
= get_handle_obj( current
->process
, handle
, GENERIC_READ
, NULL
)))
235 if (obj
->ops
== &console_input_ops
)
237 ((struct console_input
*)obj
)->mode
= mode
;
240 else if (obj
->ops
== &screen_buffer_ops
)
242 ((struct screen_buffer
*)obj
)->mode
= mode
;
245 else set_error( STATUS_OBJECT_TYPE_MISMATCH
);
246 release_object( obj
);
250 /* set misc console information (output handle only) */
251 static int set_console_info( int handle
, struct set_console_info_request
*req
,
252 const char *title
, size_t len
)
254 struct screen_buffer
*console
;
255 if (!(console
= (struct screen_buffer
*)get_handle_obj( current
->process
, handle
,
256 GENERIC_WRITE
, &screen_buffer_ops
)))
258 if (req
->mask
& SET_CONSOLE_INFO_CURSOR
)
260 console
->cursor_size
= req
->cursor_size
;
261 console
->cursor_visible
= req
->cursor_visible
;
263 if (req
->mask
& SET_CONSOLE_INFO_TITLE
)
265 char *new_title
= mem_alloc( len
+ 1 );
268 memcpy( new_title
, title
, len
);
270 if (console
->title
) free( console
->title
);
271 console
->title
= new_title
;
274 release_object( console
);
278 /* add input events to a console input queue */
279 static int write_console_input( int handle
, int count
, INPUT_RECORD
*records
)
281 INPUT_RECORD
*new_rec
;
282 struct console_input
*console
;
284 if (!(console
= (struct console_input
*)get_handle_obj( current
->process
, handle
,
285 GENERIC_WRITE
, &console_input_ops
)))
287 if (!(new_rec
= realloc( console
->records
,
288 (console
->recnum
+ count
) * sizeof(INPUT_RECORD
) )))
290 set_error( STATUS_NO_MEMORY
);
291 release_object( console
);
294 console
->records
= new_rec
;
295 memcpy( new_rec
+ console
->recnum
, records
, count
* sizeof(INPUT_RECORD
) );
296 console
->recnum
+= count
;
297 release_object( console
);
301 /* retrieve a pointer to the console input records */
302 static int read_console_input( int handle
, int count
, INPUT_RECORD
*rec
, int max
, int flush
)
304 struct console_input
*console
;
306 if (!(console
= (struct console_input
*)get_handle_obj( current
->process
, handle
,
307 GENERIC_READ
, &console_input_ops
)))
309 if ((count
< 0) || (count
> console
->recnum
)) count
= console
->recnum
;
310 if (count
> max
) count
= max
;
311 memcpy( rec
, console
->records
, count
* sizeof(INPUT_RECORD
) );
315 for (i
= count
; i
< console
->recnum
; i
++)
316 console
->records
[i
-count
] = console
->records
[i
];
317 if ((console
->recnum
-= count
) > 0)
319 INPUT_RECORD
*new_rec
= realloc( console
->records
,
320 console
->recnum
* sizeof(INPUT_RECORD
) );
321 if (new_rec
) console
->records
= new_rec
;
325 free( console
->records
);
326 console
->records
= NULL
;
329 release_object( console
);
333 static void console_input_dump( struct object
*obj
, int verbose
)
335 struct console_input
*console
= (struct console_input
*)obj
;
336 assert( obj
->ops
== &console_input_ops
);
337 fprintf( stderr
, "Console input fd=%d\n", console
->obj
.fd
);
340 static int console_input_get_poll_events( struct object
*obj
)
345 static int console_input_get_read_fd( struct object
*obj
)
347 struct console_input
*console
= (struct console_input
*)obj
;
348 assert( obj
->ops
== &console_input_ops
);
349 return dup( console
->obj
.fd
);
352 static int console_get_info( struct object
*obj
, struct get_file_info_request
*req
)
354 req
->type
= FILE_TYPE_CHAR
;
356 req
->access_time
= 0;
367 static void console_input_destroy( struct object
*obj
)
369 struct console_input
*console
= (struct console_input
*)obj
;
370 assert( obj
->ops
== &console_input_ops
);
371 if (console
->output
) console
->output
->input
= NULL
;
374 static void screen_buffer_dump( struct object
*obj
, int verbose
)
376 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
377 assert( obj
->ops
== &screen_buffer_ops
);
378 fprintf( stderr
, "Console screen buffer fd=%d\n", console
->obj
.fd
);
381 static int screen_buffer_get_poll_events( struct object
*obj
)
386 static int screen_buffer_get_write_fd( struct object
*obj
)
388 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
389 assert( obj
->ops
== &screen_buffer_ops
);
390 return dup( console
->obj
.fd
);
393 static void screen_buffer_destroy( struct object
*obj
)
395 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
396 assert( obj
->ops
== &screen_buffer_ops
);
397 if (console
->input
) console
->input
->output
= NULL
;
398 if (console
->title
) free( console
->title
);
401 /* allocate a console for the current process */
402 DECL_HANDLER(alloc_console
)
404 int in
= -1, out
= -1;
406 if (!alloc_console( current
->process
)) goto done
;
408 if ((in
= alloc_handle( current
->process
, current
->process
->console_in
,
409 req
->access
, req
->inherit
)) != -1)
411 if ((out
= alloc_handle( current
->process
, current
->process
->console_out
,
412 req
->access
, req
->inherit
)) != -1)
413 goto done
; /* everything is fine */
414 close_handle( current
->process
, in
);
417 free_console( current
->process
);
421 req
->handle_out
= out
;
424 /* free the console of the current process */
425 DECL_HANDLER(free_console
)
427 free_console( current
->process
);
430 /* open a handle to the process console */
431 DECL_HANDLER(open_console
)
433 struct object
*obj
= req
->output
? current
->process
->console_out
: current
->process
->console_in
;
435 if (obj
) req
->handle
= alloc_handle( current
->process
, obj
, req
->access
, req
->inherit
);
436 else set_error( STATUS_ACCESS_DENIED
);
439 /* set info about a console (output only) */
440 DECL_HANDLER(set_console_info
)
442 size_t len
= get_req_strlen( req
->title
);
443 set_console_info( req
->handle
, req
, req
->title
, len
);
446 /* get info about a console (output only) */
447 DECL_HANDLER(get_console_info
)
449 struct screen_buffer
*console
;
450 if ((console
= (struct screen_buffer
*)get_handle_obj( current
->process
, req
->handle
,
451 GENERIC_READ
, &screen_buffer_ops
)))
453 req
->cursor_size
= console
->cursor_size
;
454 req
->cursor_visible
= console
->cursor_visible
;
455 req
->pid
= console
->pid
;
456 strcpy( req
->title
, console
->title
? console
->title
: "" );
457 release_object( console
);
461 /* set a console fd */
462 DECL_HANDLER(set_console_fd
)
467 if (!(obj
= get_handle_obj( current
->process
, req
->file_handle
,
468 GENERIC_READ
| GENERIC_WRITE
, NULL
))) return;
469 if ((fd_in
= obj
->ops
->get_read_fd( obj
)) == -1)
471 release_object( obj
);
474 fd_out
= obj
->ops
->get_write_fd( obj
);
475 release_object( obj
);
478 if (set_console_fd( req
->handle
, fd_in
, fd_out
, req
->pid
)) return;
484 /* get a console mode (input or output) */
485 DECL_HANDLER(get_console_mode
)
487 req
->mode
= get_console_mode( req
->handle
);
490 /* set a console mode (input or output) */
491 DECL_HANDLER(set_console_mode
)
493 set_console_mode( req
->handle
, req
->mode
);
496 /* add input records to a console input queue */
497 DECL_HANDLER(write_console_input
)
499 int max
= get_req_size( req
+ 1, sizeof(INPUT_RECORD
) );
500 int count
= req
->count
;
502 if (count
> max
) count
= max
;
503 req
->written
= write_console_input( req
->handle
, count
, (INPUT_RECORD
*)(req
+ 1) );
506 /* fetch input records from a console input queue */
507 DECL_HANDLER(read_console_input
)
509 int max
= get_req_size( req
+ 1, sizeof(INPUT_RECORD
) );
510 req
->read
= read_console_input( req
->handle
, req
->count
, (INPUT_RECORD
*)(req
+ 1),