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 #include <sys/errno.h>
19 #include <sys/types.h>
35 struct object obj
; /* object header */
36 struct select_user select
; /* select user */
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 struct select_user select
; /* select user */
47 int mode
; /* output mode */
48 struct console_input
*input
; /* associated console input */
49 int cursor_size
; /* size of cursor (percentage filled) */
50 int cursor_visible
;/* cursor visibility flag */
51 int pid
; /* xterm pid (hack) */
52 char *title
; /* console title */
56 static void console_input_dump( struct object
*obj
, int verbose
);
57 static int console_input_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
58 static void console_input_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
59 static int console_input_signaled( struct object
*obj
, struct thread
*thread
);
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_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
65 static void screen_buffer_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
66 static int screen_buffer_signaled( struct object
*obj
, struct thread
*thread
);
67 static int screen_buffer_get_write_fd( struct object
*obj
);
68 static void screen_buffer_destroy( struct object
*obj
);
71 static int console_get_info( struct object
*obj
, struct get_file_info_reply
*reply
);
73 static const struct object_ops console_input_ops
=
76 console_input_add_queue
,
77 console_input_remove_queue
,
78 console_input_signaled
,
80 console_input_get_read_fd
,
87 static const struct object_ops screen_buffer_ops
=
90 screen_buffer_add_queue
,
91 screen_buffer_remove_queue
,
92 screen_buffer_signaled
,
95 screen_buffer_get_write_fd
,
102 int create_console( int fd
, struct object
*obj
[2] )
104 struct console_input
*console_input
;
105 struct screen_buffer
*screen_buffer
;
106 int read_fd
, write_fd
;
108 if ((read_fd
= (fd
!= -1) ? dup(fd
) : dup(0)) == -1)
113 if ((write_fd
= (fd
!= -1) ? dup(fd
) : dup(1)) == -1)
119 if (!(console_input
= mem_alloc( sizeof(struct console_input
) )))
125 if (!(screen_buffer
= mem_alloc( sizeof(struct screen_buffer
) )))
129 free( console_input
);
132 init_object( &console_input
->obj
, &console_input_ops
, NULL
);
133 init_object( &screen_buffer
->obj
, &screen_buffer_ops
, NULL
);
134 console_input
->select
.fd
= read_fd
;
135 console_input
->select
.func
= default_select_event
;
136 console_input
->select
.private = console_input
;
137 console_input
->mode
= ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
|
138 ENABLE_ECHO_INPUT
| ENABLE_MOUSE_INPUT
;
139 console_input
->output
= screen_buffer
;
140 console_input
->recnum
= 0;
141 console_input
->records
= NULL
;
142 screen_buffer
->select
.fd
= write_fd
;
143 screen_buffer
->select
.func
= default_select_event
;
144 screen_buffer
->select
.private = screen_buffer
;
145 screen_buffer
->mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
146 screen_buffer
->input
= console_input
;
147 screen_buffer
->cursor_size
= 100;
148 screen_buffer
->cursor_visible
= 1;
149 screen_buffer
->pid
= 0;
150 screen_buffer
->title
= strdup( "Wine console" );
151 register_select_user( &console_input
->select
);
152 register_select_user( &screen_buffer
->select
);
154 obj
[0] = &console_input
->obj
;
155 obj
[1] = &screen_buffer
->obj
;
159 static int set_console_fd( int handle
, int fd
, int pid
)
161 struct console_input
*input
;
162 struct screen_buffer
*output
;
166 if (!(obj
= get_handle_obj( current
->process
, handle
, 0, NULL
)))
168 if (obj
->ops
== &console_input_ops
)
170 input
= (struct console_input
*)obj
;
171 output
= input
->output
;
172 grab_object( output
);
174 else if (obj
->ops
== &screen_buffer_ops
)
176 output
= (struct screen_buffer
*)obj
;
177 input
= output
->input
;
178 grab_object( input
);
182 SET_ERROR( ERROR_INVALID_HANDLE
);
183 release_object( obj
);
187 /* can't change the fd if someone is waiting on it */
188 assert( !input
->obj
.head
);
189 assert( !output
->obj
.head
);
191 if ((fd_in
= dup(fd
)) == -1)
194 release_object( input
);
195 release_object( output
);
198 if ((fd_out
= dup(fd
)) == -1)
202 release_object( input
);
203 release_object( output
);
206 unregister_select_user( &input
->select
);
207 unregister_select_user( &output
->select
);
208 close( input
->select
.fd
);
209 close( output
->select
.fd
);
210 input
->select
.fd
= fd_in
;
211 output
->select
.fd
= fd_out
;
213 register_select_user( &input
->select
);
214 register_select_user( &output
->select
);
215 release_object( input
);
216 release_object( output
);
220 static int get_console_mode( int handle
, int *mode
)
225 if (!(obj
= get_handle_obj( current
->process
, handle
, GENERIC_READ
, NULL
)))
227 if (obj
->ops
== &console_input_ops
)
229 *mode
= ((struct console_input
*)obj
)->mode
;
232 else if (obj
->ops
== &screen_buffer_ops
)
234 *mode
= ((struct screen_buffer
*)obj
)->mode
;
237 else SET_ERROR( ERROR_INVALID_HANDLE
);
238 release_object( obj
);
242 static int set_console_mode( int handle
, int mode
)
247 if (!(obj
= get_handle_obj( current
->process
, handle
, GENERIC_READ
, NULL
)))
249 if (obj
->ops
== &console_input_ops
)
251 ((struct console_input
*)obj
)->mode
= mode
;
254 else if (obj
->ops
== &screen_buffer_ops
)
256 ((struct screen_buffer
*)obj
)->mode
= mode
;
259 else SET_ERROR( ERROR_INVALID_HANDLE
);
260 release_object( obj
);
264 /* set misc console information (output handle only) */
265 static int set_console_info( int handle
, struct set_console_info_request
*req
, const char *title
)
267 struct screen_buffer
*console
;
268 if (!(console
= (struct screen_buffer
*)get_handle_obj( current
->process
, handle
,
269 GENERIC_WRITE
, &screen_buffer_ops
)))
271 if (req
->mask
& SET_CONSOLE_INFO_CURSOR
)
273 console
->cursor_size
= req
->cursor_size
;
274 console
->cursor_visible
= req
->cursor_visible
;
276 if (req
->mask
& SET_CONSOLE_INFO_TITLE
)
278 if (console
->title
) free( console
->title
);
279 console
->title
= strdup( title
);
281 release_object( console
);
285 /* get misc console information (output handle only) */
286 static int get_console_info( int handle
, struct get_console_info_reply
*reply
, const char **title
)
288 struct screen_buffer
*console
;
289 if (!(console
= (struct screen_buffer
*)get_handle_obj( current
->process
, handle
,
290 GENERIC_READ
, &screen_buffer_ops
)))
292 reply
->cursor_size
= console
->cursor_size
;
293 reply
->cursor_visible
= console
->cursor_visible
;
294 reply
->pid
= console
->pid
;
295 *title
= console
->title
;
296 release_object( console
);
300 /* add input events to a console input queue */
301 static int write_console_input( int handle
, int count
, INPUT_RECORD
*records
)
303 INPUT_RECORD
*new_rec
;
304 struct console_input
*console
;
306 if (!(console
= (struct console_input
*)get_handle_obj( current
->process
, handle
,
307 GENERIC_WRITE
, &console_input_ops
)))
309 if (!(new_rec
= realloc( console
->records
,
310 (console
->recnum
+ count
) * sizeof(INPUT_RECORD
) )))
312 SET_ERROR( ERROR_NOT_ENOUGH_MEMORY
);
313 release_object( console
);
316 console
->records
= new_rec
;
317 memcpy( new_rec
+ console
->recnum
, records
, count
* sizeof(INPUT_RECORD
) );
318 console
->recnum
+= count
;
319 release_object( console
);
323 /* retrieve a pointer to the console input records */
324 static int read_console_input( int handle
, int count
, int flush
)
326 struct console_input
*console
;
328 if (!(console
= (struct console_input
*)get_handle_obj( current
->process
, handle
,
329 GENERIC_READ
, &console_input_ops
)))
331 if ((count
< 0) || (count
> console
->recnum
)) count
= console
->recnum
;
332 send_reply( current
, -1, 1, console
->records
, count
* sizeof(INPUT_RECORD
) );
336 for (i
= count
; i
< console
->recnum
; i
++)
337 console
->records
[i
-count
] = console
->records
[i
];
338 if ((console
->recnum
-= count
) > 0)
340 INPUT_RECORD
*new_rec
= realloc( console
->records
,
341 console
->recnum
* sizeof(INPUT_RECORD
) );
342 if (new_rec
) console
->records
= new_rec
;
346 free( console
->records
);
347 console
->records
= NULL
;
350 release_object( console
);
354 static void console_input_dump( struct object
*obj
, int verbose
)
356 struct console_input
*console
= (struct console_input
*)obj
;
357 assert( obj
->ops
== &console_input_ops
);
358 fprintf( stderr
, "Console input fd=%d\n", console
->select
.fd
);
361 static int console_input_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
363 struct console_input
*console
= (struct console_input
*)obj
;
364 assert( obj
->ops
== &console_input_ops
);
365 if (!obj
->head
) /* first on the queue */
366 set_select_events( &console
->select
, READ_EVENT
);
367 add_queue( obj
, entry
);
371 static void console_input_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
373 struct console_input
*console
= (struct console_input
*)grab_object(obj
);
374 assert( obj
->ops
== &console_input_ops
);
376 remove_queue( obj
, entry
);
377 if (!obj
->head
) /* last on the queue is gone */
378 set_select_events( &console
->select
, 0 );
379 release_object( obj
);
382 static int console_input_signaled( struct object
*obj
, struct thread
*thread
)
384 struct console_input
*console
= (struct console_input
*)obj
;
385 assert( obj
->ops
== &console_input_ops
);
387 if (check_select_events( &console
->select
, READ_EVENT
))
389 /* stop waiting on select() if we are signaled */
390 set_select_events( &console
->select
, 0 );
395 /* restart waiting on select() if we are no longer signaled */
396 if (obj
->head
) set_select_events( &console
->select
, READ_EVENT
);
401 static int console_input_get_read_fd( struct object
*obj
)
403 struct console_input
*console
= (struct console_input
*)obj
;
404 assert( obj
->ops
== &console_input_ops
);
405 return dup( console
->select
.fd
);
408 static int console_get_info( struct object
*obj
, struct get_file_info_reply
*reply
)
410 memset( reply
, 0, sizeof(*reply
) );
411 reply
->type
= FILE_TYPE_CHAR
;
415 static void console_input_destroy( struct object
*obj
)
417 struct console_input
*console
= (struct console_input
*)obj
;
418 assert( obj
->ops
== &console_input_ops
);
419 unregister_select_user( &console
->select
);
420 close( console
->select
.fd
);
421 if (console
->output
) console
->output
->input
= NULL
;
425 static void screen_buffer_dump( struct object
*obj
, int verbose
)
427 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
428 assert( obj
->ops
== &screen_buffer_ops
);
429 fprintf( stderr
, "Console screen buffer fd=%d\n", console
->select
.fd
);
432 static int screen_buffer_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
434 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
435 assert( obj
->ops
== &screen_buffer_ops
);
436 if (!obj
->head
) /* first on the queue */
437 set_select_events( &console
->select
, WRITE_EVENT
);
438 add_queue( obj
, entry
);
442 static void screen_buffer_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
444 struct screen_buffer
*console
= (struct screen_buffer
*)grab_object(obj
);
445 assert( obj
->ops
== &screen_buffer_ops
);
447 remove_queue( obj
, entry
);
448 if (!obj
->head
) /* last on the queue is gone */
449 set_select_events( &console
->select
, 0 );
450 release_object( obj
);
453 static int screen_buffer_signaled( struct object
*obj
, struct thread
*thread
)
455 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
456 assert( obj
->ops
== &screen_buffer_ops
);
458 if (check_select_events( &console
->select
, WRITE_EVENT
))
460 /* stop waiting on select() if we are signaled */
461 set_select_events( &console
->select
, 0 );
466 /* restart waiting on select() if we are no longer signaled */
467 if (obj
->head
) set_select_events( &console
->select
, WRITE_EVENT
);
472 static int screen_buffer_get_write_fd( struct object
*obj
)
474 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
475 assert( obj
->ops
== &screen_buffer_ops
);
476 return dup( console
->select
.fd
);
479 static void screen_buffer_destroy( struct object
*obj
)
481 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
482 assert( obj
->ops
== &screen_buffer_ops
);
483 unregister_select_user( &console
->select
);
484 close( console
->select
.fd
);
485 if (console
->input
) console
->input
->output
= NULL
;
486 if (console
->pid
) kill( console
->pid
, SIGTERM
);
487 if (console
->title
) free( console
->title
);
491 /* allocate a console for the current process */
492 DECL_HANDLER(alloc_console
)
494 alloc_console( current
->process
);
495 send_reply( current
, -1, 0 );
498 /* free the console of the current process */
499 DECL_HANDLER(free_console
)
501 free_console( current
->process
);
502 send_reply( current
, -1, 0 );
505 /* open a handle to the process console */
506 DECL_HANDLER(open_console
)
509 struct open_console_reply reply
= { -1 };
510 if ((obj
= get_console( current
->process
, req
->output
)))
512 reply
.handle
= alloc_handle( current
->process
, obj
, req
->access
, req
->inherit
);
513 release_object( obj
);
515 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
518 /* set info about a console (output only) */
519 DECL_HANDLER(set_console_info
)
521 char *name
= (char *)data
;
522 if (!len
) name
= NULL
;
523 else CHECK_STRING( "set_console_info", name
, len
);
524 set_console_info( req
->handle
, req
, name
);
525 send_reply( current
, -1, 0 );
528 /* get info about a console (output only) */
529 DECL_HANDLER(get_console_info
)
531 struct get_console_info_reply reply
;
533 get_console_info( req
->handle
, &reply
, &title
);
534 send_reply( current
, -1, 2, &reply
, sizeof(reply
),
535 title
, title
? strlen(title
)+1 : 0 );
538 /* set a console fd */
539 DECL_HANDLER(set_console_fd
)
541 set_console_fd( req
->handle
, fd
, req
->pid
);
542 send_reply( current
, -1, 0 );
545 /* get a console mode (input or output) */
546 DECL_HANDLER(get_console_mode
)
548 struct get_console_mode_reply reply
;
549 get_console_mode( req
->handle
, &reply
.mode
);
550 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
553 /* set a console mode (input or output) */
554 DECL_HANDLER(set_console_mode
)
556 set_console_mode( req
->handle
, req
->mode
);
557 send_reply( current
, -1, 0 );
560 /* add input records to a console input queue */
561 DECL_HANDLER(write_console_input
)
563 struct write_console_input_reply reply
;
564 INPUT_RECORD
*records
= (INPUT_RECORD
*)data
;
566 if (len
!= req
->count
* sizeof(INPUT_RECORD
))
567 fatal_protocol_error( "write_console_input: bad length %d for %d records\n",
569 reply
.written
= write_console_input( req
->handle
, req
->count
, records
);
570 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
573 /* fetch input records from a console input queue */
574 DECL_HANDLER(read_console_input
)
576 read_console_input( req
->handle
, req
->count
, req
->flush
);