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/process.h"
27 #include "server/thread.h"
33 struct object obj
; /* object header */
34 int fd
; /* Unix file descriptor */
35 int mode
; /* input mode */
36 struct screen_buffer
*output
; /* associated screen buffer */
37 int recnum
; /* number of input records */
38 INPUT_RECORD
*records
; /* input records */
43 struct object obj
; /* object header */
44 int fd
; /* Unix file descriptor */
45 int mode
; /* output mode */
46 struct console_input
*input
; /* associated console input */
47 int cursor_size
; /* size of cursor (percentage filled) */
48 int cursor_visible
;/* cursor visibility flag */
49 int pid
; /* xterm pid (hack) */
50 char *title
; /* console title */
54 static void console_input_dump( struct object
*obj
, int verbose
);
55 static int console_input_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
56 static void console_input_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
57 static int console_input_signaled( struct object
*obj
, struct thread
*thread
);
58 static int console_input_get_read_fd( struct object
*obj
);
59 static void console_input_destroy( struct object
*obj
);
61 static void screen_buffer_dump( struct object
*obj
, int verbose
);
62 static int screen_buffer_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
63 static void screen_buffer_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
);
64 static int screen_buffer_signaled( struct object
*obj
, struct thread
*thread
);
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_reply
*reply
);
71 static const struct object_ops console_input_ops
=
74 console_input_add_queue
,
75 console_input_remove_queue
,
76 console_input_signaled
,
78 console_input_get_read_fd
,
85 static const struct object_ops screen_buffer_ops
=
88 screen_buffer_add_queue
,
89 screen_buffer_remove_queue
,
90 screen_buffer_signaled
,
93 screen_buffer_get_write_fd
,
99 static const struct select_ops select_ops
=
101 default_select_event
,
102 NULL
/* we never set a timeout on a console */
105 int create_console( int fd
, struct object
*obj
[2] )
107 struct console_input
*console_input
;
108 struct screen_buffer
*screen_buffer
;
109 int read_fd
, write_fd
;
111 if ((read_fd
= (fd
!= -1) ? dup(fd
) : dup(0)) == -1)
116 if ((write_fd
= (fd
!= -1) ? dup(fd
) : dup(1)) == -1)
122 if (!(console_input
= mem_alloc( sizeof(struct console_input
) )))
128 if (!(screen_buffer
= mem_alloc( sizeof(struct screen_buffer
) )))
132 free( console_input
);
135 init_object( &console_input
->obj
, &console_input_ops
, NULL
);
136 init_object( &screen_buffer
->obj
, &screen_buffer_ops
, NULL
);
137 console_input
->fd
= read_fd
;
138 console_input
->mode
= ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
|
139 ENABLE_ECHO_INPUT
| ENABLE_MOUSE_INPUT
;
140 console_input
->output
= screen_buffer
;
141 console_input
->recnum
= 0;
142 console_input
->records
= NULL
;
143 screen_buffer
->fd
= write_fd
;
144 screen_buffer
->mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
145 screen_buffer
->input
= console_input
;
146 screen_buffer
->cursor_size
= 100;
147 screen_buffer
->cursor_visible
= 1;
148 screen_buffer
->pid
= 0;
149 screen_buffer
->title
= strdup( "Wine console" );
151 obj
[0] = &console_input
->obj
;
152 obj
[1] = &screen_buffer
->obj
;
156 int set_console_fd( int handle
, int fd
, int pid
)
158 struct console_input
*input
;
159 struct screen_buffer
*output
;
163 if (!(obj
= get_handle_obj( current
->process
, handle
, 0, NULL
)))
165 if (obj
->ops
== &console_input_ops
)
167 input
= (struct console_input
*)obj
;
168 output
= input
->output
;
169 grab_object( output
);
171 else if (obj
->ops
== &screen_buffer_ops
)
173 output
= (struct screen_buffer
*)obj
;
174 input
= output
->input
;
175 grab_object( input
);
179 SET_ERROR( ERROR_INVALID_HANDLE
);
180 release_object( obj
);
184 if ((fd_in
= dup(fd
)) == -1)
187 release_object( input
);
188 release_object( output
);
191 if ((fd_out
= dup(fd
)) == -1)
195 release_object( input
);
196 release_object( output
);
204 release_object( input
);
205 release_object( output
);
209 int get_console_mode( int handle
, int *mode
)
214 if (!(obj
= get_handle_obj( current
->process
, handle
, GENERIC_READ
, NULL
)))
216 if (obj
->ops
== &console_input_ops
)
218 *mode
= ((struct console_input
*)obj
)->mode
;
221 else if (obj
->ops
== &screen_buffer_ops
)
223 *mode
= ((struct screen_buffer
*)obj
)->mode
;
226 else SET_ERROR( ERROR_INVALID_HANDLE
);
227 release_object( obj
);
231 int set_console_mode( int handle
, int mode
)
236 if (!(obj
= get_handle_obj( current
->process
, handle
, GENERIC_READ
, NULL
)))
238 if (obj
->ops
== &console_input_ops
)
240 ((struct console_input
*)obj
)->mode
= mode
;
243 else if (obj
->ops
== &screen_buffer_ops
)
245 ((struct screen_buffer
*)obj
)->mode
= mode
;
248 else SET_ERROR( ERROR_INVALID_HANDLE
);
249 release_object( obj
);
253 /* set misc console information (output handle only) */
254 int set_console_info( int handle
, struct set_console_info_request
*req
, const char *title
)
256 struct screen_buffer
*console
;
257 if (!(console
= (struct screen_buffer
*)get_handle_obj( current
->process
, handle
,
258 GENERIC_WRITE
, &screen_buffer_ops
)))
260 if (req
->mask
& SET_CONSOLE_INFO_CURSOR
)
262 console
->cursor_size
= req
->cursor_size
;
263 console
->cursor_visible
= req
->cursor_visible
;
265 if (req
->mask
& SET_CONSOLE_INFO_TITLE
)
267 if (console
->title
) free( console
->title
);
268 console
->title
= strdup( title
);
270 release_object( console
);
274 /* get misc console information (output handle only) */
275 int get_console_info( int handle
, struct get_console_info_reply
*reply
, const char **title
)
277 struct screen_buffer
*console
;
278 if (!(console
= (struct screen_buffer
*)get_handle_obj( current
->process
, handle
,
279 GENERIC_READ
, &screen_buffer_ops
)))
281 reply
->cursor_size
= console
->cursor_size
;
282 reply
->cursor_visible
= console
->cursor_visible
;
283 reply
->pid
= console
->pid
;
284 *title
= console
->title
;
285 release_object( console
);
289 /* add input events to a console input queue */
290 int write_console_input( int handle
, int count
, INPUT_RECORD
*records
)
292 INPUT_RECORD
*new_rec
;
293 struct console_input
*console
;
295 if (!(console
= (struct console_input
*)get_handle_obj( current
->process
, handle
,
296 GENERIC_WRITE
, &console_input_ops
)))
298 if (!(new_rec
= realloc( console
->records
,
299 (console
->recnum
+ count
) * sizeof(INPUT_RECORD
) )))
301 SET_ERROR( ERROR_NOT_ENOUGH_MEMORY
);
302 release_object( console
);
305 console
->records
= new_rec
;
306 memcpy( new_rec
+ console
->recnum
, records
, count
* sizeof(INPUT_RECORD
) );
307 console
->recnum
+= count
;
308 release_object( console
);
312 /* retrieve a pointer to the console input records */
313 int read_console_input( int handle
, int count
, int flush
)
315 struct console_input
*console
;
317 if (!(console
= (struct console_input
*)get_handle_obj( current
->process
, handle
,
318 GENERIC_READ
, &console_input_ops
)))
320 if ((count
< 0) || (count
> console
->recnum
)) count
= console
->recnum
;
321 send_reply( current
, -1, 1, console
->records
, count
* sizeof(INPUT_RECORD
) );
325 for (i
= count
; i
< console
->recnum
; i
++)
326 console
->records
[i
-count
] = console
->records
[i
];
327 if ((console
->recnum
-= count
) > 0)
329 INPUT_RECORD
*new_rec
= realloc( console
->records
,
330 console
->recnum
* sizeof(INPUT_RECORD
) );
331 if (new_rec
) console
->records
= new_rec
;
335 free( console
->records
);
336 console
->records
= NULL
;
339 release_object( console
);
343 static void console_input_dump( struct object
*obj
, int verbose
)
345 struct console_input
*console
= (struct console_input
*)obj
;
346 assert( obj
->ops
== &console_input_ops
);
347 fprintf( stderr
, "Console input fd=%d\n", console
->fd
);
350 static int console_input_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
352 struct console_input
*console
= (struct console_input
*)obj
;
353 assert( obj
->ops
== &console_input_ops
);
354 if (!obj
->head
) /* first on the queue */
356 if (!add_select_user( console
->fd
, READ_EVENT
, &select_ops
, console
))
358 SET_ERROR( ERROR_OUTOFMEMORY
);
362 add_queue( obj
, entry
);
366 static void console_input_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
368 struct console_input
*console
= (struct console_input
*)grab_object(obj
);
369 assert( obj
->ops
== &console_input_ops
);
371 remove_queue( obj
, entry
);
372 if (!obj
->head
) /* last on the queue is gone */
373 remove_select_user( console
->fd
);
374 release_object( obj
);
377 static int console_input_signaled( struct object
*obj
, struct thread
*thread
)
380 struct timeval tv
= { 0, 0 };
381 struct console_input
*console
= (struct console_input
*)obj
;
382 assert( obj
->ops
== &console_input_ops
);
385 FD_SET( console
->fd
, &fds
);
386 return select( console
->fd
+ 1, &fds
, NULL
, NULL
, &tv
) > 0;
389 static int console_input_get_read_fd( struct object
*obj
)
391 struct console_input
*console
= (struct console_input
*)obj
;
392 assert( obj
->ops
== &console_input_ops
);
393 return dup( console
->fd
);
396 static int console_get_info( struct object
*obj
, struct get_file_info_reply
*reply
)
398 memset( reply
, 0, sizeof(*reply
) );
399 reply
->type
= FILE_TYPE_CHAR
;
403 static void console_input_destroy( struct object
*obj
)
405 struct console_input
*console
= (struct console_input
*)obj
;
406 assert( obj
->ops
== &console_input_ops
);
407 close( console
->fd
);
408 if (console
->output
) console
->output
->input
= NULL
;
412 static void screen_buffer_dump( struct object
*obj
, int verbose
)
414 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
415 assert( obj
->ops
== &screen_buffer_ops
);
416 fprintf( stderr
, "Console screen buffer fd=%d\n", console
->fd
);
419 static int screen_buffer_add_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
421 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
422 assert( obj
->ops
== &screen_buffer_ops
);
423 if (!obj
->head
) /* first on the queue */
425 if (!add_select_user( console
->fd
, WRITE_EVENT
, &select_ops
, console
))
427 SET_ERROR( ERROR_OUTOFMEMORY
);
431 add_queue( obj
, entry
);
435 static void screen_buffer_remove_queue( struct object
*obj
, struct wait_queue_entry
*entry
)
437 struct screen_buffer
*console
= (struct screen_buffer
*)grab_object(obj
);
438 assert( obj
->ops
== &screen_buffer_ops
);
440 remove_queue( obj
, entry
);
441 if (!obj
->head
) /* last on the queue is gone */
442 remove_select_user( console
->fd
);
443 release_object( obj
);
446 static int screen_buffer_signaled( struct object
*obj
, struct thread
*thread
)
449 struct timeval tv
= { 0, 0 };
450 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
451 assert( obj
->ops
== &screen_buffer_ops
);
454 FD_SET( console
->fd
, &fds
);
455 return select( console
->fd
+ 1, NULL
, &fds
, NULL
, &tv
) > 0;
458 static int screen_buffer_get_write_fd( struct object
*obj
)
460 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
461 assert( obj
->ops
== &screen_buffer_ops
);
462 return dup( console
->fd
);
465 static void screen_buffer_destroy( struct object
*obj
)
467 struct screen_buffer
*console
= (struct screen_buffer
*)obj
;
468 assert( obj
->ops
== &screen_buffer_ops
);
469 close( console
->fd
);
470 if (console
->input
) console
->input
->output
= NULL
;
471 if (console
->pid
) kill( console
->pid
, SIGTERM
);
472 if (console
->title
) free( console
->title
);