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>
26 #include "server/thread.h"
32 struct object obj
; /* object header */
33 int fd
; /* Unix file descriptor */
34 int mode
; /* input mode */
35 struct screen_buffer
*output
; /* associated screen buffer */
36 int recnum
; /* number of input records */
37 INPUT_RECORD
*records
; /* input records */
42 struct object obj
; /* object header */
43 int fd
; /* Unix file descriptor */
44 int mode
; /* output mode */
45 struct console_input
*input
; /* associated console input */
46 int cursor_size
; /* size of cursor (percentage filled) */
47 int cursor_visible
;/* cursor visibility flag */
48 int pid
; /* xterm pid (hack) */
49 char *title
; /* console title */
53 static void console_input_dump( struct object
*obj
, int verbose
);
54 static int console_input_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
55 static void console_input_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
56 static int console_input_signaled( struct object
*obj
, struct thread
*thread
);
57 static int console_input_get_read_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_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
62 static void screen_buffer_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
63 static int screen_buffer_signaled( struct object
*obj
, struct thread
*thread
);
64 static int screen_buffer_get_write_fd( struct object
*obj
);
65 static void screen_buffer_destroy( struct object
*obj
);
68 static int console_get_info( struct object
*obj
, struct get_file_info_reply
*reply
);
70 static const struct object_ops console_input_ops
=
73 console_input_add_queue
,
74 console_input_remove_queue
,
75 console_input_signaled
,
77 console_input_get_read_fd
,
84 static const struct object_ops screen_buffer_ops
=
87 screen_buffer_add_queue
,
88 screen_buffer_remove_queue
,
89 screen_buffer_signaled
,
92 screen_buffer_get_write_fd
,
98 static const struct select_ops select_ops
=
100 default_select_event
,
101 NULL
/* we never set a timeout on a console */
104 int create_console( int fd
, struct object
*obj
[2] )
106 struct console_input
*console_input
;
107 struct screen_buffer
*screen_buffer
;
108 int read_fd
, write_fd
;
110 if ((read_fd
= (fd
!= -1) ? dup(fd
) : dup(0)) == -1)
115 if ((write_fd
= (fd
!= -1) ? dup(fd
) : dup(1)) == -1)
121 if (!(console_input
= mem_alloc( sizeof(struct console_input
) )))
127 if (!(screen_buffer
= mem_alloc( sizeof(struct screen_buffer
) )))
131 free( console_input
);
134 init_object( &console_input
->obj
, &console_input_ops
, NULL
);
135 init_object( &screen_buffer
->obj
, &screen_buffer_ops
, NULL
);
136 console_input
->fd
= read_fd
;
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
->fd
= write_fd
;
143 screen_buffer
->mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
144 screen_buffer
->input
= console_input
;
145 screen_buffer
->cursor_size
= 100;
146 screen_buffer
->cursor_visible
= 1;
147 screen_buffer
->pid
= 0;
148 screen_buffer
->title
= strdup( "Wine console" );
150 obj
[0] = &console_input
->obj
;
151 obj
[1] = &screen_buffer
->obj
;
155 int set_console_fd( int handle
, int fd
, int pid
)
157 struct console_input
*input
;
158 struct screen_buffer
*output
;
162 if (!(obj
= get_handle_obj( current
->process
, handle
, 0, NULL
)))
164 if (obj
->ops
== &console_input_ops
)
166 input
= (struct console_input
*)obj
;
167 output
= input
->output
;
168 grab_object( output
);
170 else if (obj
->ops
== &screen_buffer_ops
)
172 output
= (struct screen_buffer
*)obj
;
173 input
= output
->input
;
174 grab_object( input
);
178 SET_ERROR( ERROR_INVALID_HANDLE
);
179 release_object( obj
);
183 if ((fd_in
= dup(fd
)) == -1)
186 release_object( input
);
187 release_object( output
);
190 if ((fd_out
= dup(fd
)) == -1)
194 release_object( input
);
195 release_object( output
);
203 release_object( input
);
204 release_object( output
);
208 int get_console_mode( int handle
, int *mode
)
213 if (!(obj
= get_handle_obj( current
->process
, handle
, GENERIC_READ
, NULL
)))
215 if (obj
->ops
== &console_input_ops
)
217 *mode
= ((struct console_input
*)obj
)->mode
;
220 else if (obj
->ops
== &screen_buffer_ops
)
222 *mode
= ((struct screen_buffer
*)obj
)->mode
;
225 else SET_ERROR( ERROR_INVALID_HANDLE
);
226 release_object( obj
);
230 int set_console_mode( int handle
, int mode
)
235 if (!(obj
= get_handle_obj( current
->process
, handle
, GENERIC_READ
, NULL
)))
237 if (obj
->ops
== &console_input_ops
)
239 ((struct console_input
*)obj
)->mode
= mode
;
242 else if (obj
->ops
== &screen_buffer_ops
)
244 ((struct screen_buffer
*)obj
)->mode
= mode
;
247 else SET_ERROR( ERROR_INVALID_HANDLE
);
248 release_object( obj
);
252 /* set misc console information (output handle only) */
253 int set_console_info( int handle
, struct set_console_info_request
*req
, const char *title
)
255 struct screen_buffer
*console
;
256 if (!(console
= (struct screen_buffer
*)get_handle_obj( current
->process
, handle
,
257 GENERIC_WRITE
, &screen_buffer_ops
)))
259 if (req
->mask
& SET_CONSOLE_INFO_CURSOR
)
261 console
->cursor_size
= req
->cursor_size
;
262 console
->cursor_visible
= req
->cursor_visible
;
264 if (req
->mask
& SET_CONSOLE_INFO_TITLE
)
266 if (console
->title
) free( console
->title
);
267 console
->title
= strdup( title
);
269 release_object( console
);
273 /* get misc console information (output handle only) */
274 int get_console_info( int handle
, struct get_console_info_reply
*reply
, const char **title
)
276 struct screen_buffer
*console
;
277 if (!(console
= (struct screen_buffer
*)get_handle_obj( current
->process
, handle
,
278 GENERIC_READ
, &screen_buffer_ops
)))
280 reply
->cursor_size
= console
->cursor_size
;
281 reply
->cursor_visible
= console
->cursor_visible
;
282 reply
->pid
= console
->pid
;
283 *title
= console
->title
;
284 release_object( console
);
288 /* add input events to a console input queue */
289 int write_console_input( int handle
, int count
, INPUT_RECORD
*records
)
291 INPUT_RECORD
*new_rec
;
292 struct console_input
*console
;
294 if (!(console
= (struct console_input
*)get_handle_obj( current
->process
, handle
,
295 GENERIC_WRITE
, &console_input_ops
)))
297 if (!(new_rec
= realloc( console
->records
,
298 (console
->recnum
+ count
) * sizeof(INPUT_RECORD
) )))
300 SET_ERROR( ERROR_NOT_ENOUGH_MEMORY
);
301 release_object( console
);
304 console
->records
= new_rec
;
305 memcpy( new_rec
+ console
->recnum
, records
, count
* sizeof(INPUT_RECORD
) );
306 console
->recnum
+= count
;
307 release_object( console
);
311 /* retrieve a pointer to the console input records */
312 int read_console_input( int handle
, int count
, int flush
)
314 struct console_input
*console
;
316 if (!(console
= (struct console_input
*)get_handle_obj( current
->process
, handle
,
317 GENERIC_READ
, &console_input_ops
)))
319 if ((count
< 0) || (count
> console
->recnum
)) count
= console
->recnum
;
320 send_reply( current
, -1, 1, console
->records
, count
* sizeof(INPUT_RECORD
) );
324 for (i
= count
; i
< console
->recnum
; i
++)
325 console
->records
[i
-count
] = console
->records
[i
];
326 if ((console
->recnum
-= count
) > 0)
328 INPUT_RECORD
*new_rec
= realloc( console
->records
,
329 console
->recnum
* sizeof(INPUT_RECORD
) );
330 if (new_rec
) console
->records
= new_rec
;
334 free( console
->records
);
335 console
->records
= NULL
;
338 release_object( console
);
342 static void console_input_dump( struct object
*obj
, int verbose
)
344 struct console_input
*console
= (struct console_input
*)obj
;
345 assert( obj
->ops
== &console_input_ops
);
346 fprintf( stderr
, "Console input fd=%d\n", console
->fd
);
349 static int console_input_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
351 struct console_input
*console
= (struct console_input
*)obj
;
352 assert( obj
->ops
== &console_input_ops
);
353 if (!obj
->head
) /* first on the queue */
355 if (!add_select_user( console
->fd
, READ_EVENT
, &select_ops
, console
))
357 SET_ERROR( ERROR_OUTOFMEMORY
);
361 add_queue( obj
, entry
);
365 static void console_input_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
367 struct console_input
*console
= (struct console_input
*)grab_object(obj
);
368 assert( obj
->ops
== &console_input_ops
);
370 remove_queue( obj
, entry
);
371 if (!obj
->head
) /* last on the queue is gone */
372 remove_select_user( console
->fd
);
373 release_object( obj
);
376 static int console_input_signaled( struct object
*obj
, struct thread
*thread
)
379 struct timeval tv
= { 0, 0 };
380 struct console_input
*console
= (struct console_input
*)obj
;
381 assert( obj
->ops
== &console_input_ops
);
384 FD_SET( console
->fd
, &fds
);
385 return select( console
->fd
+ 1, &fds
, NULL
, NULL
, &tv
) > 0;
388 static int console_input_get_read_fd( struct object
*obj
)
390 struct console_input
*console
= (struct console_input
*)obj
;
391 assert( obj
->ops
== &console_input_ops
);
392 return dup( console
->fd
);
395 static int console_get_info( struct object
*obj
, struct get_file_info_reply
*reply
)
397 memset( reply
, 0, sizeof(*reply
) );
398 reply
->type
= FILE_TYPE_CHAR
;
402 static void console_input_destroy( struct object
*obj
)
404 struct console_input
*console
= (struct console_input
*)obj
;
405 assert( obj
->ops
== &console_input_ops
);
406 close( console
->fd
);
407 if (console
->output
) console
->output
->input
= NULL
;
411 static void screen_buffer_dump( struct object
*obj
, int verbose
)
413 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
414 assert( obj
->ops
== &screen_buffer_ops
);
415 fprintf( stderr
, "Console screen buffer fd=%d\n", console
->fd
);
418 static int screen_buffer_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
420 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
421 assert( obj
->ops
== &screen_buffer_ops
);
422 if (!obj
->head
) /* first on the queue */
424 if (!add_select_user( console
->fd
, WRITE_EVENT
, &select_ops
, console
))
426 SET_ERROR( ERROR_OUTOFMEMORY
);
430 add_queue( obj
, entry
);
434 static void screen_buffer_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
436 struct screen_buffer
*console
= (struct screen_buffer
*)grab_object(obj
);
437 assert( obj
->ops
== &screen_buffer_ops
);
439 remove_queue( obj
, entry
);
440 if (!obj
->head
) /* last on the queue is gone */
441 remove_select_user( console
->fd
);
442 release_object( obj
);
445 static int screen_buffer_signaled( struct object
*obj
, struct thread
*thread
)
448 struct timeval tv
= { 0, 0 };
449 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
450 assert( obj
->ops
== &screen_buffer_ops
);
453 FD_SET( console
->fd
, &fds
);
454 return select( console
->fd
+ 1, NULL
, &fds
, NULL
, &tv
) > 0;
457 static int screen_buffer_get_write_fd( struct object
*obj
)
459 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
460 assert( obj
->ops
== &screen_buffer_ops
);
461 return dup( console
->fd
);
464 static void screen_buffer_destroy( struct object
*obj
)
466 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
467 assert( obj
->ops
== &screen_buffer_ops
);
468 close( console
->fd
);
469 if (console
->input
) console
->input
->output
= NULL
;
470 if (console
->pid
) kill( console
->pid
, SIGTERM
);
471 if (console
->title
) free( console
->title
);