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.
19 #include <sys/types.h>
36 struct object obj
; /* object header */
37 int mode
; /* input mode */
38 struct screen_buffer
*output
; /* associated screen buffer */
39 int recnum
; /* number of input records */
40 INPUT_RECORD
*records
; /* input records */
45 struct object obj
; /* object header */
46 int mode
; /* output mode */
47 struct console_input
*input
; /* associated console input */
48 int cursor_size
; /* size of cursor (percentage filled) */
49 int cursor_visible
;/* cursor visibility flag */
50 int pid
; /* xterm pid (hack) */
51 char *title
; /* console title */
55 static void console_input_dump( struct object
*obj
, int verbose
);
56 static int console_input_get_poll_events( struct object
*obj
);
57 static int console_input_get_fd( struct object
*obj
);
58 static void console_input_destroy( struct object
*obj
);
60 static void screen_buffer_dump( struct object
*obj
, int verbose
);
61 static int screen_buffer_get_poll_events( struct object
*obj
);
62 static int screen_buffer_get_fd( struct object
*obj
);
63 static void screen_buffer_destroy( struct object
*obj
);
66 static int console_get_info( struct object
*obj
, struct get_file_info_request
*req
);
68 static const struct object_ops console_input_ops
=
70 sizeof(struct console_input
), /* size */
71 console_input_dump
, /* dump */
72 default_poll_add_queue
, /* add_queue */
73 default_poll_remove_queue
, /* remove_queue */
74 default_poll_signaled
, /* signaled */
75 no_satisfied
, /* satisfied */
76 console_input_get_poll_events
, /* get_poll_events */
77 default_poll_event
, /* poll_event */
78 console_input_get_fd
, /* get_fd */
80 console_get_info
, /* get_file_info */
81 console_input_destroy
/* destroy */
84 static const struct object_ops screen_buffer_ops
=
86 sizeof(struct screen_buffer
), /* size */
87 screen_buffer_dump
, /* dump */
88 default_poll_add_queue
, /* add_queue */
89 default_poll_remove_queue
, /* remove_queue */
90 default_poll_signaled
, /* signaled */
91 no_satisfied
, /* satisfied */
92 screen_buffer_get_poll_events
, /* get_poll_events */
93 default_poll_event
, /* poll_event */
94 screen_buffer_get_fd
, /* get_fd */
96 console_get_info
, /* get_file_info */
97 screen_buffer_destroy
/* destroy */
101 static struct object
*create_console_input( int fd
)
103 struct console_input
*console_input
;
105 if ((fd
= (fd
!= -1) ? dup(fd
) : dup(0)) == -1)
110 if (!(console_input
= alloc_object( &console_input_ops
, fd
))) return NULL
;
111 console_input
->mode
= ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
|
112 ENABLE_ECHO_INPUT
| ENABLE_MOUSE_INPUT
;
113 console_input
->output
= NULL
;
114 console_input
->recnum
= 0;
115 console_input
->records
= NULL
;
116 return &console_input
->obj
;
119 static struct object
*create_console_output( int fd
, struct object
*input
)
121 struct console_input
*console_input
= (struct console_input
*)input
;
122 struct screen_buffer
*screen_buffer
;
124 if ((fd
= (fd
!= -1) ? dup(fd
) : dup(1)) == -1)
129 if (!(screen_buffer
= alloc_object( &screen_buffer_ops
, fd
))) return NULL
;
130 screen_buffer
->mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
131 screen_buffer
->input
= console_input
;
132 screen_buffer
->cursor_size
= 100;
133 screen_buffer
->cursor_visible
= 1;
134 screen_buffer
->pid
= 0;
135 screen_buffer
->title
= strdup( "Wine console" );
136 console_input
->output
= screen_buffer
;
137 return &screen_buffer
->obj
;
140 /* allocate a console for this process */
141 int alloc_console( struct process
*process
)
143 if (process
->console_in
|| process
->console_out
)
145 set_error( STATUS_ACCESS_DENIED
);
148 if ((process
->console_in
= create_console_input( -1 )))
150 if ((process
->console_out
= create_console_output( -1, process
->console_in
)))
152 release_object( process
->console_in
);
157 /* free the console for this process */
158 int free_console( struct process
*process
)
160 if (process
->console_in
) release_object( process
->console_in
);
161 if (process
->console_out
) release_object( process
->console_out
);
162 process
->console_in
= process
->console_out
= NULL
;
166 static int set_console_fd( handle_t handle
, int fd_in
, int fd_out
, int pid
)
168 struct console_input
*input
;
169 struct screen_buffer
*output
;
172 if (!(obj
= get_handle_obj( current
->process
, handle
, 0, NULL
)))
174 if (obj
->ops
== &console_input_ops
)
176 input
= (struct console_input
*)obj
;
177 output
= input
->output
;
178 grab_object( output
);
180 else if (obj
->ops
== &screen_buffer_ops
)
182 output
= (struct screen_buffer
*)obj
;
183 input
= output
->input
;
184 grab_object( input
);
188 set_error( STATUS_OBJECT_TYPE_MISMATCH
);
189 release_object( obj
);
193 /* can't change the fd if someone is waiting on it */
194 assert( !input
->obj
.head
);
195 assert( !output
->obj
.head
);
197 change_select_fd( &input
->obj
, fd_in
);
198 change_select_fd( &output
->obj
, fd_out
);
200 release_object( input
);
201 release_object( output
);
205 static int get_console_mode( handle_t handle
)
210 if ((obj
= get_handle_obj( current
->process
, handle
, GENERIC_READ
, NULL
)))
212 if (obj
->ops
== &console_input_ops
)
213 ret
= ((struct console_input
*)obj
)->mode
;
214 else if (obj
->ops
== &screen_buffer_ops
)
215 ret
= ((struct screen_buffer
*)obj
)->mode
;
217 set_error( STATUS_OBJECT_TYPE_MISMATCH
);
218 release_object( obj
);
223 static int set_console_mode( handle_t handle
, int mode
)
228 if (!(obj
= get_handle_obj( current
->process
, handle
, GENERIC_READ
, NULL
)))
230 if (obj
->ops
== &console_input_ops
)
232 ((struct console_input
*)obj
)->mode
= mode
;
235 else if (obj
->ops
== &screen_buffer_ops
)
237 ((struct screen_buffer
*)obj
)->mode
= mode
;
240 else set_error( STATUS_OBJECT_TYPE_MISMATCH
);
241 release_object( obj
);
245 /* set misc console information (output handle only) */
246 static int set_console_info( handle_t handle
, struct set_console_info_request
*req
,
247 const char *title
, size_t len
)
249 struct screen_buffer
*console
;
250 if (!(console
= (struct screen_buffer
*)get_handle_obj( current
->process
, handle
,
251 GENERIC_WRITE
, &screen_buffer_ops
)))
253 if (req
->mask
& SET_CONSOLE_INFO_CURSOR
)
255 console
->cursor_size
= req
->cursor_size
;
256 console
->cursor_visible
= req
->cursor_visible
;
258 if (req
->mask
& SET_CONSOLE_INFO_TITLE
)
260 char *new_title
= mem_alloc( len
+ 1 );
263 memcpy( new_title
, title
, len
);
265 if (console
->title
) free( console
->title
);
266 console
->title
= new_title
;
269 release_object( console
);
273 /* add input events to a console input queue */
274 static int write_console_input( handle_t handle
, int count
, INPUT_RECORD
*records
)
276 INPUT_RECORD
*new_rec
;
277 struct console_input
*console
;
279 if (!(console
= (struct console_input
*)get_handle_obj( current
->process
, handle
,
280 GENERIC_WRITE
, &console_input_ops
)))
282 if (!(new_rec
= realloc( console
->records
,
283 (console
->recnum
+ count
) * sizeof(INPUT_RECORD
) )))
285 set_error( STATUS_NO_MEMORY
);
286 release_object( console
);
289 console
->records
= new_rec
;
290 memcpy( new_rec
+ console
->recnum
, records
, count
* sizeof(INPUT_RECORD
) );
291 console
->recnum
+= count
;
292 release_object( console
);
296 /* retrieve a pointer to the console input records */
297 static int read_console_input( handle_t handle
, int count
, INPUT_RECORD
*rec
, int flush
)
299 struct console_input
*console
;
301 if (!(console
= (struct console_input
*)get_handle_obj( current
->process
, handle
,
302 GENERIC_READ
, &console_input_ops
)))
307 /* special case: do not retrieve anything, but return
308 * the total number of records available */
309 count
= console
->recnum
;
313 if (count
> console
->recnum
) count
= console
->recnum
;
314 memcpy( rec
, console
->records
, count
* sizeof(INPUT_RECORD
) );
319 for (i
= count
; i
< console
->recnum
; i
++)
320 console
->records
[i
-count
] = console
->records
[i
];
321 if ((console
->recnum
-= count
) > 0)
323 INPUT_RECORD
*new_rec
= realloc( console
->records
,
324 console
->recnum
* sizeof(INPUT_RECORD
) );
325 if (new_rec
) console
->records
= new_rec
;
329 free( console
->records
);
330 console
->records
= NULL
;
333 release_object( console
);
337 static void console_input_dump( struct object
*obj
, int verbose
)
339 struct console_input
*console
= (struct console_input
*)obj
;
340 assert( obj
->ops
== &console_input_ops
);
341 fprintf( stderr
, "Console input fd=%d\n", console
->obj
.fd
);
344 static int console_input_get_poll_events( struct object
*obj
)
349 static int console_input_get_fd( struct object
*obj
)
351 struct console_input
*console
= (struct console_input
*)obj
;
352 assert( obj
->ops
== &console_input_ops
);
353 return console
->obj
.fd
;
356 static int console_get_info( struct object
*obj
, struct get_file_info_request
*req
)
358 req
->type
= FILE_TYPE_CHAR
;
360 req
->access_time
= 0;
371 static void console_input_destroy( struct object
*obj
)
373 struct console_input
*console
= (struct console_input
*)obj
;
374 assert( obj
->ops
== &console_input_ops
);
375 if (console
->output
) console
->output
->input
= NULL
;
378 static void screen_buffer_dump( struct object
*obj
, int verbose
)
380 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
381 assert( obj
->ops
== &screen_buffer_ops
);
382 fprintf( stderr
, "Console screen buffer fd=%d\n", console
->obj
.fd
);
385 static int screen_buffer_get_poll_events( struct object
*obj
)
390 static int screen_buffer_get_fd( struct object
*obj
)
392 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
393 assert( obj
->ops
== &screen_buffer_ops
);
394 return console
->obj
.fd
;
397 static void screen_buffer_destroy( struct object
*obj
)
399 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
400 assert( obj
->ops
== &screen_buffer_ops
);
401 if (console
->input
) console
->input
->output
= NULL
;
402 if (console
->title
) free( console
->title
);
405 /* allocate a console for the current process */
406 DECL_HANDLER(alloc_console
)
408 handle_t in
= 0, out
= 0;
410 if (!alloc_console( current
->process
)) goto done
;
412 if ((in
= alloc_handle( current
->process
, current
->process
->console_in
,
413 req
->access
, req
->inherit
)))
415 if ((out
= alloc_handle( current
->process
, current
->process
->console_out
,
416 req
->access
, req
->inherit
)))
417 goto done
; /* everything is fine */
418 close_handle( current
->process
, in
, NULL
);
421 free_console( current
->process
);
425 req
->handle_out
= out
;
428 /* free the console of the current process */
429 DECL_HANDLER(free_console
)
431 free_console( current
->process
);
434 /* open a handle to the process console */
435 DECL_HANDLER(open_console
)
437 struct object
*obj
= req
->output
? current
->process
->console_out
: current
->process
->console_in
;
440 if (obj
) req
->handle
= alloc_handle( current
->process
, obj
, req
->access
, req
->inherit
);
441 else set_error( STATUS_ACCESS_DENIED
);
444 /* set info about a console (output only) */
445 DECL_HANDLER(set_console_info
)
447 set_console_info( req
->handle
, req
, get_req_data(req
), get_req_data_size(req
) );
450 /* get info about a console (output only) */
451 DECL_HANDLER(get_console_info
)
453 struct screen_buffer
*console
;
456 if ((console
= (struct screen_buffer
*)get_handle_obj( current
->process
, req
->handle
,
457 GENERIC_READ
, &screen_buffer_ops
)))
459 req
->cursor_size
= console
->cursor_size
;
460 req
->cursor_visible
= console
->cursor_visible
;
461 req
->pid
= console
->pid
;
464 len
= strlen( console
->title
);
465 if (len
> get_req_data_size(req
)) len
= get_req_data_size(req
);
466 memcpy( get_req_data(req
), console
->title
, len
);
468 release_object( console
);
470 set_req_data_size( req
, len
);
473 /* set a console fd */
474 DECL_HANDLER(set_console_fd
)
476 int fd_out
, fd_in
= thread_get_inflight_fd( current
, req
->fd_in
);
478 if (req
->fd_out
== req
->fd_in
) fd_out
= dup( fd_in
);
479 else fd_out
= thread_get_inflight_fd( current
, req
->fd_out
);
481 if (fd_in
== -1 || fd_out
== -1) set_error( STATUS_INVALID_HANDLE
);
482 else if (set_console_fd( req
->handle
, fd_in
, fd_out
, req
->pid
)) return;
484 if (fd_in
!= -1) close( fd_in
);
485 if (fd_out
!= -1) close( fd_out
);
488 /* get a console mode (input or output) */
489 DECL_HANDLER(get_console_mode
)
491 req
->mode
= get_console_mode( req
->handle
);
494 /* set a console mode (input or output) */
495 DECL_HANDLER(set_console_mode
)
497 set_console_mode( req
->handle
, req
->mode
);
500 /* add input records to a console input queue */
501 DECL_HANDLER(write_console_input
)
503 req
->written
= write_console_input( req
->handle
, get_req_data_size(req
) / sizeof(INPUT_RECORD
),
507 /* fetch input records from a console input queue */
508 DECL_HANDLER(read_console_input
)
510 size_t size
= get_req_data_size(req
) / sizeof(INPUT_RECORD
);
511 int res
= read_console_input( req
->handle
, size
, get_req_data(req
), req
->flush
);
512 /* if size was 0 we didn't fetch anything */
513 if (size
) set_req_data_size( req
, res
* sizeof(INPUT_RECORD
) );