2 * Server-side console management
4 * Copyright (C) 1998 Alexandre Julliard
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/port.h"
33 #define WIN32_NO_STATUS
41 #include "wine/condrv.h"
44 struct console_input_events
;
54 struct object obj
; /* object header */
55 int num_proc
; /* number of processes attached to this console */
56 struct thread
*renderer
; /* console renderer thread */
57 int mode
; /* input mode */
58 struct screen_buffer
*active
; /* active screen buffer */
59 int recnum
; /* number of input records */
60 INPUT_RECORD
*records
; /* input records */
61 struct console_input_events
*evt
; /* synchronization event with renderer */
62 struct console_server
*server
; /* console server object */
63 WCHAR
*title
; /* console title */
64 data_size_t title_len
; /* length of console title */
65 struct history_line
**history
; /* lines history */
66 int history_size
; /* number of entries in history array */
67 int history_index
; /* number of used entries in history array */
68 int history_mode
; /* mode of history (non zero means remove doubled strings */
69 int edition_mode
; /* index to edition mode flavors */
70 int input_cp
; /* console input codepage */
71 int output_cp
; /* console output codepage */
72 user_handle_t win
; /* window handle if backend supports it */
73 unsigned int last_id
; /* id of last created console buffer */
74 struct event
*event
; /* event to wait on for input queue */
75 struct fd
*fd
; /* for bare console, attached input fd */
76 struct async_queue ioctl_q
; /* ioctl queue */
77 struct async_queue read_q
; /* read queue */
80 static void console_input_dump( struct object
*obj
, int verbose
);
81 static void console_input_destroy( struct object
*obj
);
82 static struct fd
*console_input_get_fd( struct object
*obj
);
83 static struct object
*console_input_open_file( struct object
*obj
, unsigned int access
,
84 unsigned int sharing
, unsigned int options
);
86 static const struct object_ops console_input_ops
=
88 sizeof(struct console_input
), /* size */
89 console_input_dump
, /* dump */
90 no_get_type
, /* get_type */
91 no_add_queue
, /* add_queue */
92 NULL
, /* remove_queue */
94 no_satisfied
, /* satisfied */
95 no_signal
, /* signal */
96 console_input_get_fd
, /* get_fd */
97 default_fd_map_access
, /* map_access */
98 default_get_sd
, /* get_sd */
99 default_set_sd
, /* set_sd */
100 no_lookup_name
, /* lookup_name */
101 no_link_name
, /* link_name */
102 NULL
, /* unlink_name */
103 console_input_open_file
, /* open_file */
104 no_kernel_obj_list
, /* get_kernel_obj_list */
105 no_close_handle
, /* close_handle */
106 console_input_destroy
/* destroy */
109 static enum server_fd_type
console_get_fd_type( struct fd
*fd
);
110 static int console_input_ioctl( struct fd
*fd
, ioctl_code_t code
, struct async
*async
);
112 static const struct fd_ops console_input_fd_ops
=
114 default_fd_get_poll_events
, /* get_poll_events */
115 default_poll_event
, /* poll_event */
116 console_get_fd_type
, /* get_fd_type */
117 no_fd_read
, /* read */
118 no_fd_write
, /* write */
119 no_fd_flush
, /* flush */
120 no_fd_get_file_info
, /* get_file_info */
121 no_fd_get_volume_info
, /* get_volume_info */
122 console_input_ioctl
, /* ioctl */
123 default_fd_queue_async
, /* queue_async */
124 default_fd_reselect_async
/* reselect_async */
127 static void console_input_events_dump( struct object
*obj
, int verbose
);
128 static void console_input_events_destroy( struct object
*obj
);
129 static struct fd
*console_input_events_get_fd( struct object
*obj
);
130 static struct object
*console_input_events_open_file( struct object
*obj
, unsigned int access
,
131 unsigned int sharing
, unsigned int options
);
133 struct console_input_events
135 struct object obj
; /* object header */
136 struct fd
*fd
; /* pseudo-fd for ioctls */
137 struct console_input
*console
; /* attached console */
138 int num_alloc
; /* number of allocated events */
139 int num_used
; /* number of actually used events */
140 struct condrv_renderer_event
*events
;
141 struct async_queue read_q
; /* read queue */
144 static const struct object_ops console_input_events_ops
=
146 sizeof(struct console_input_events
), /* size */
147 console_input_events_dump
, /* dump */
148 no_get_type
, /* get_type */
149 add_queue
, /* add_queue */
150 remove_queue
, /* remove_queue */
152 no_satisfied
, /* satisfied */
153 no_signal
, /* signal */
154 console_input_events_get_fd
, /* get_fd */
155 default_fd_map_access
, /* map_access */
156 default_get_sd
, /* get_sd */
157 default_set_sd
, /* set_sd */
158 no_lookup_name
, /* lookup_name */
159 no_link_name
, /* link_name */
160 NULL
, /* unlink_name */
161 console_input_events_open_file
, /* open_file */
162 no_kernel_obj_list
, /* get_kernel_obj_list */
163 no_close_handle
, /* close_handle */
164 console_input_events_destroy
/* destroy */
167 static int console_input_events_ioctl( struct fd
*fd
, ioctl_code_t code
, struct async
*async
);
169 static const struct fd_ops console_input_events_fd_ops
=
171 default_fd_get_poll_events
, /* get_poll_events */
172 default_poll_event
, /* poll_event */
173 console_get_fd_type
, /* get_fd_type */
174 no_fd_read
, /* read */
175 no_fd_write
, /* write */
176 no_fd_flush
, /* flush */
177 no_fd_get_file_info
, /* get_file_info */
178 no_fd_get_volume_info
, /* get_volume_info */
179 console_input_events_ioctl
, /* ioctl */
180 default_fd_queue_async
, /* queue_async */
181 default_fd_reselect_async
/* reselect_async */
184 struct console_host_ioctl
186 unsigned int code
; /* ioctl code */
187 int output
; /* output id for screen buffer ioctls */
188 struct async
*async
; /* ioctl async */
189 struct list entry
; /* list entry */
192 struct console_server
194 struct object obj
; /* object header */
195 struct fd
*fd
; /* pseudo-fd for ioctls */
196 struct console_input
*console
; /* attached console */
197 struct list queue
; /* ioctl queue */
198 struct list read_queue
; /* blocking read queue */
199 int busy
; /* flag if server processing an ioctl */
202 static void console_server_dump( struct object
*obj
, int verbose
);
203 static void console_server_destroy( struct object
*obj
);
204 static int console_server_signaled( struct object
*obj
, struct wait_queue_entry
*entry
);
205 static struct fd
*console_server_get_fd( struct object
*obj
);
206 static struct object
*console_server_lookup_name( struct object
*obj
, struct unicode_str
*name
, unsigned int attr
);
207 static struct object
*console_server_open_file( struct object
*obj
, unsigned int access
,
208 unsigned int sharing
, unsigned int options
);
210 static const struct object_ops console_server_ops
=
212 sizeof(struct console_server
), /* size */
213 console_server_dump
, /* dump */
214 no_get_type
, /* get_type */
215 add_queue
, /* add_queue */
216 remove_queue
, /* remove_queue */
217 console_server_signaled
, /* signaled */
218 no_satisfied
, /* satisfied */
219 no_signal
, /* signal */
220 console_server_get_fd
, /* get_fd */
221 default_fd_map_access
, /* map_access */
222 default_get_sd
, /* get_sd */
223 default_set_sd
, /* set_sd */
224 console_server_lookup_name
, /* lookup_name */
225 no_link_name
, /* link_name */
226 NULL
, /* unlink_name */
227 console_server_open_file
, /* open_file */
228 no_kernel_obj_list
, /* get_kernel_obj_list */
229 fd_close_handle
, /* close_handle */
230 console_server_destroy
/* destroy */
233 static int console_server_ioctl( struct fd
*fd
, ioctl_code_t code
, struct async
*async
);
235 static const struct fd_ops console_server_fd_ops
=
237 default_fd_get_poll_events
, /* get_poll_events */
238 default_poll_event
, /* poll_event */
239 console_get_fd_type
, /* get_fd_type */
240 no_fd_read
, /* read */
241 no_fd_write
, /* write */
242 no_fd_flush
, /* flush */
243 no_fd_get_file_info
, /* get_file_info */
244 no_fd_get_volume_info
, /* get_volume_info */
245 console_server_ioctl
, /* ioctl */
246 default_fd_queue_async
, /* queue_async */
247 default_fd_reselect_async
/* reselect_async */
255 short int pitch_family
;
257 data_size_t face_len
;
262 struct object obj
; /* object header */
263 struct list entry
; /* entry in list of all screen buffers */
264 struct console_input
*input
; /* associated console input */
265 unsigned int id
; /* buffer id */
266 unsigned int mode
; /* output mode */
267 int cursor_size
; /* size of cursor (percentage filled) */
268 int cursor_visible
;/* cursor visibility flag */
269 int cursor_x
; /* position of cursor */
270 int cursor_y
; /* position of cursor */
271 int width
; /* size (w-h) of the screen buffer */
273 int max_width
; /* size (w-h) of the window given font size */
275 char_info_t
*data
; /* the data for each cell - a width x height matrix */
276 unsigned short attr
; /* default fill attributes (screen colors) */
277 unsigned short popup_attr
; /* pop-up color attributes */
278 unsigned int color_map
[16]; /* color table */
279 rectangle_t win
; /* current visible window on the screen buffer *
280 * as seen in wineconsole */
281 struct font_info font
; /* console font information */
282 struct fd
*fd
; /* for bare console, attached output fd */
283 struct async_queue ioctl_q
; /* ioctl queue */
286 static void screen_buffer_dump( struct object
*obj
, int verbose
);
287 static void screen_buffer_destroy( struct object
*obj
);
288 static struct fd
*screen_buffer_get_fd( struct object
*obj
);
289 static struct object
*screen_buffer_open_file( struct object
*obj
, unsigned int access
,
290 unsigned int sharing
, unsigned int options
);
292 static const struct object_ops screen_buffer_ops
=
294 sizeof(struct screen_buffer
), /* size */
295 screen_buffer_dump
, /* dump */
296 no_get_type
, /* get_type */
297 no_add_queue
, /* add_queue */
298 NULL
, /* remove_queue */
300 NULL
, /* satisfied */
301 no_signal
, /* signal */
302 screen_buffer_get_fd
, /* get_fd */
303 default_fd_map_access
, /* map_access */
304 default_get_sd
, /* get_sd */
305 default_set_sd
, /* set_sd */
306 no_lookup_name
, /* lookup_name */
307 no_link_name
, /* link_name */
308 NULL
, /* unlink_name */
309 screen_buffer_open_file
, /* open_file */
310 no_kernel_obj_list
, /* get_kernel_obj_list */
311 no_close_handle
, /* close_handle */
312 screen_buffer_destroy
/* destroy */
315 static int screen_buffer_ioctl( struct fd
*fd
, ioctl_code_t code
, struct async
*async
);
317 static const struct fd_ops screen_buffer_fd_ops
=
319 default_fd_get_poll_events
, /* get_poll_events */
320 default_poll_event
, /* poll_event */
321 console_get_fd_type
, /* get_fd_type */
322 no_fd_read
, /* read */
323 no_fd_write
, /* write */
324 no_fd_flush
, /* flush */
325 no_fd_get_file_info
, /* get_file_info */
326 no_fd_get_volume_info
, /* get_volume_info */
327 screen_buffer_ioctl
, /* ioctl */
328 default_fd_queue_async
, /* queue_async */
329 default_fd_reselect_async
/* reselect_async */
332 static struct object_type
*console_device_get_type( struct object
*obj
);
333 static void console_device_dump( struct object
*obj
, int verbose
);
334 static struct object
*console_device_lookup_name( struct object
*obj
, struct unicode_str
*name
, unsigned int attr
);
335 static struct object
*console_device_open_file( struct object
*obj
, unsigned int access
,
336 unsigned int sharing
, unsigned int options
);
338 static const struct object_ops console_device_ops
=
340 sizeof(struct object
), /* size */
341 console_device_dump
, /* dump */
342 console_device_get_type
, /* get_type */
343 no_add_queue
, /* add_queue */
344 NULL
, /* remove_queue */
346 no_satisfied
, /* satisfied */
347 no_signal
, /* signal */
348 no_get_fd
, /* get_fd */
349 default_fd_map_access
, /* map_access */
350 default_get_sd
, /* get_sd */
351 default_set_sd
, /* set_sd */
352 console_device_lookup_name
, /* lookup_name */
353 directory_link_name
, /* link_name */
354 default_unlink_name
, /* unlink_name */
355 console_device_open_file
, /* open_file */
356 no_kernel_obj_list
, /* get_kernel_obj_list */
357 no_close_handle
, /* close_handle */
358 no_destroy
/* destroy */
361 static struct list screen_buffer_list
= LIST_INIT(screen_buffer_list
);
363 static const char_info_t empty_char_info
= { ' ', 0x000f }; /* white on black space */
365 static int console_input_is_bare( struct console_input
* cin
)
367 return cin
->evt
== NULL
;
370 static struct fd
*console_input_get_fd( struct object
* obj
)
372 struct console_input
*console_input
= (struct console_input
*)obj
;
373 assert( obj
->ops
== &console_input_ops
);
374 return (struct fd
*)grab_object( console_input
->fd
);
377 static enum server_fd_type
console_get_fd_type( struct fd
*fd
)
382 /* dumps the renderer events of a console */
383 static void console_input_events_dump( struct object
*obj
, int verbose
)
385 struct console_input_events
*evts
= (struct console_input_events
*)obj
;
386 assert( obj
->ops
== &console_input_events_ops
);
387 fprintf( stderr
, "Console input events: %d/%d events\n",
388 evts
->num_used
, evts
->num_alloc
);
391 /* destroys the renderer events of a console */
392 static void console_input_events_destroy( struct object
*obj
)
394 struct console_input_events
*evts
= (struct console_input_events
*)obj
;
395 assert( obj
->ops
== &console_input_events_ops
);
396 if (evts
->console
) evts
->console
->evt
= NULL
;
397 free_async_queue( &evts
->read_q
);
398 if (evts
->fd
) release_object( evts
->fd
);
399 free( evts
->events
);
402 static struct fd
*console_input_events_get_fd( struct object
* obj
)
404 struct console_input_events
*evts
= (struct console_input_events
*)obj
;
405 assert( obj
->ops
== &console_input_events_ops
);
406 return (struct fd
*)grab_object( evts
->fd
);
409 static struct object
*console_input_events_open_file( struct object
*obj
, unsigned int access
,
410 unsigned int sharing
, unsigned int options
)
412 return grab_object( obj
);
415 /* retrieves events from the console's renderer events list */
416 static int get_renderer_events( struct console_input_events
* evts
, struct async
*async
)
418 struct iosb
*iosb
= async_get_iosb( async
);
421 num
= min( iosb
->out_size
/ sizeof(evts
->events
[0]), evts
->num_used
);
422 if (num
&& !(iosb
->out_data
= malloc( num
* sizeof(evts
->events
[0] ))))
424 async_terminate( async
, STATUS_NO_MEMORY
);
425 release_object( iosb
);
429 iosb
->status
= STATUS_SUCCESS
;
430 iosb
->out_size
= iosb
->result
= num
* sizeof(evts
->events
[0]);
431 if (num
) memcpy( iosb
->out_data
, evts
->events
, iosb
->result
);
432 release_object( iosb
);
433 async_terminate( async
, STATUS_ALERTED
);
435 if (num
&& num
< evts
->num_used
)
437 memmove( &evts
->events
[0], &evts
->events
[num
],
438 (evts
->num_used
- num
) * sizeof(evts
->events
[0]) );
440 evts
->num_used
-= num
;
444 /* add an event to the console's renderer events list */
445 static void console_input_events_append( struct console_input
* console
,
446 struct condrv_renderer_event
* evt
)
448 struct console_input_events
* evts
;
449 int collapsed
= FALSE
;
452 if (!(evts
= console
->evt
)) return;
453 /* to be done even when evt has been generated by the renderer ? */
455 /* try to collapse evt into current queue's events */
458 struct condrv_renderer_event
* last
= &evts
->events
[evts
->num_used
- 1];
460 if (last
->event
== CONSOLE_RENDERER_UPDATE_EVENT
&&
461 evt
->event
== CONSOLE_RENDERER_UPDATE_EVENT
)
463 /* if two update events overlap, collapse them into a single one */
464 if (last
->u
.update
.bottom
+ 1 >= evt
->u
.update
.top
&&
465 evt
->u
.update
.bottom
+ 1 >= last
->u
.update
.top
)
467 last
->u
.update
.top
= min(last
->u
.update
.top
, evt
->u
.update
.top
);
468 last
->u
.update
.bottom
= max(last
->u
.update
.bottom
, evt
->u
.update
.bottom
);
475 if (evts
->num_used
== evts
->num_alloc
)
477 evts
->num_alloc
+= 16;
478 evts
->events
= realloc( evts
->events
, evts
->num_alloc
* sizeof(*evt
) );
479 assert(evts
->events
);
481 evts
->events
[evts
->num_used
++] = *evt
;
483 while (evts
->num_used
&& (async
= find_pending_async( &evts
->read_q
)))
485 get_renderer_events( evts
, async
);
486 release_object( async
);
490 static struct object
*create_console_input_events(void)
492 struct console_input_events
* evt
;
494 if (!(evt
= alloc_object( &console_input_events_ops
))) return NULL
;
496 evt
->num_alloc
= evt
->num_used
= 0;
498 init_async_queue( &evt
->read_q
);
499 if (!(evt
->fd
= alloc_pseudo_fd( &console_input_events_fd_ops
, &evt
->obj
, 0 )))
501 release_object( evt
);
507 static struct object
*create_console_input( int fd
)
509 struct console_input
*console_input
;
511 if (!(console_input
= alloc_object( &console_input_ops
)))
513 if (fd
!= -1) close( fd
);
516 console_input
->renderer
= NULL
;
517 console_input
->mode
= ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
|
518 ENABLE_ECHO_INPUT
| ENABLE_MOUSE_INPUT
| ENABLE_INSERT_MODE
|
519 ENABLE_EXTENDED_FLAGS
;
520 console_input
->num_proc
= 0;
521 console_input
->active
= NULL
;
522 console_input
->recnum
= 0;
523 console_input
->records
= NULL
;
524 console_input
->evt
= NULL
;
525 console_input
->server
= NULL
;
526 console_input
->title
= NULL
;
527 console_input
->title_len
= 0;
528 console_input
->history_size
= 50;
529 console_input
->history
= calloc( console_input
->history_size
, sizeof(*console_input
->history
) );
530 console_input
->history_index
= 0;
531 console_input
->history_mode
= 0;
532 console_input
->edition_mode
= 0;
533 console_input
->input_cp
= 0;
534 console_input
->output_cp
= 0;
535 console_input
->win
= 0;
536 console_input
->event
= create_event( NULL
, NULL
, 0, 1, 0, NULL
);
537 console_input
->fd
= NULL
;
538 console_input
->last_id
= 0;
539 init_async_queue( &console_input
->ioctl_q
);
540 init_async_queue( &console_input
->read_q
);
542 if (!console_input
->history
|| !console_input
->event
)
544 if (fd
!= -1) close( fd
);
545 console_input
->history_size
= 0;
546 release_object( console_input
);
549 if (fd
!= -1) /* bare console */
551 console_input
->fd
= create_anonymous_fd( &console_input_fd_ops
, fd
, &console_input
->obj
,
552 FILE_SYNCHRONOUS_IO_NONALERT
);
556 console_input
->fd
= alloc_pseudo_fd( &console_input_fd_ops
, &console_input
->obj
,
557 FILE_SYNCHRONOUS_IO_NONALERT
);
559 if (!console_input
->fd
)
561 release_object( console_input
);
564 allow_fd_caching( console_input
->fd
);
565 return &console_input
->obj
;
568 static void console_host_ioctl_terminate( struct console_host_ioctl
*call
, unsigned int status
)
572 async_terminate( call
->async
, status
);
573 release_object( call
->async
);
578 static int queue_host_ioctl( struct console_server
*server
, unsigned int code
, unsigned int output
,
579 struct async
*async
, struct async_queue
*queue
)
581 struct console_host_ioctl
*ioctl
;
583 if (!(ioctl
= mem_alloc( sizeof(*ioctl
) ))) return 0;
585 ioctl
->output
= output
;
589 ioctl
->async
= (struct async
*)grab_object( async
);
590 queue_async( queue
, async
);
592 list_add_tail( &server
->queue
, &ioctl
->entry
);
593 wake_up( &server
->obj
, 0 );
594 if (async
) set_error( STATUS_PENDING
);
598 static void disconnect_console_server( struct console_server
*server
)
600 while (!list_empty( &server
->queue
))
602 struct console_host_ioctl
*call
= LIST_ENTRY( list_head( &server
->queue
), struct console_host_ioctl
, entry
);
603 list_remove( &call
->entry
);
604 console_host_ioctl_terminate( call
, STATUS_CANCELLED
);
606 while (!list_empty( &server
->read_queue
))
608 struct console_host_ioctl
*call
= LIST_ENTRY( list_head( &server
->read_queue
), struct console_host_ioctl
, entry
);
609 list_remove( &call
->entry
);
610 console_host_ioctl_terminate( call
, STATUS_CANCELLED
);
615 assert( server
->console
->server
== server
);
616 server
->console
->server
= NULL
;
617 server
->console
= NULL
;
618 wake_up( &server
->obj
, 0 );
622 static void set_active_screen_buffer( struct console_input
*console_input
, struct screen_buffer
*screen_buffer
)
624 struct condrv_renderer_event evt
;
626 if (console_input
->active
== screen_buffer
) return;
627 if (console_input
->active
) release_object( console_input
->active
);
628 console_input
->active
= (struct screen_buffer
*)grab_object( screen_buffer
);
630 if (console_input
->server
) queue_host_ioctl( console_input
->server
, IOCTL_CONDRV_ACTIVATE
,
631 screen_buffer
->id
, NULL
, NULL
);
633 evt
.event
= CONSOLE_RENDERER_SB_RESIZE_EVENT
;
634 evt
.u
.resize
.width
= screen_buffer
->width
;
635 evt
.u
.resize
.height
= screen_buffer
->height
;
636 console_input_events_append( console_input
, &evt
);
638 evt
.event
= CONSOLE_RENDERER_DISPLAY_EVENT
;
639 evt
.u
.display
.left
= screen_buffer
->win
.left
;
640 evt
.u
.display
.top
= screen_buffer
->win
.top
;
641 evt
.u
.display
.width
= screen_buffer
->win
.right
- screen_buffer
->win
.left
+ 1;
642 evt
.u
.display
.height
= screen_buffer
->win
.bottom
- screen_buffer
->win
.top
+ 1;
643 console_input_events_append( console_input
, &evt
);
645 evt
.event
= CONSOLE_RENDERER_UPDATE_EVENT
;
646 evt
.u
.update
.top
= 0;
647 evt
.u
.update
.bottom
= screen_buffer
->height
- 1;
648 console_input_events_append( console_input
, &evt
);
650 evt
.event
= CONSOLE_RENDERER_CURSOR_GEOM_EVENT
;
651 evt
.u
.cursor_geom
.size
= screen_buffer
->cursor_size
;
652 evt
.u
.cursor_geom
.visible
= screen_buffer
->cursor_visible
;
653 console_input_events_append( console_input
, &evt
);
655 evt
.event
= CONSOLE_RENDERER_CURSOR_POS_EVENT
;
656 evt
.u
.cursor_pos
.x
= screen_buffer
->cursor_x
;
657 evt
.u
.cursor_pos
.y
= screen_buffer
->cursor_y
;
658 console_input_events_append( console_input
, &evt
);
661 static struct object
*create_console_output( struct console_input
*console_input
, int fd
)
663 struct screen_buffer
*screen_buffer
;
666 if (console_input
->last_id
== ~0)
668 set_error( STATUS_NO_MEMORY
);
672 if (!(screen_buffer
= alloc_object( &screen_buffer_ops
)))
674 if (fd
!= -1) close( fd
);
677 screen_buffer
->id
= ++console_input
->last_id
;
678 screen_buffer
->mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
679 screen_buffer
->input
= console_input
;
680 screen_buffer
->cursor_size
= 100;
681 screen_buffer
->cursor_visible
= 1;
682 screen_buffer
->width
= 80;
683 screen_buffer
->height
= 150;
684 screen_buffer
->max_width
= 80;
685 screen_buffer
->max_height
= 25;
686 screen_buffer
->cursor_x
= 0;
687 screen_buffer
->cursor_y
= 0;
688 screen_buffer
->attr
= 0x0F;
689 screen_buffer
->popup_attr
= 0xF5;
690 screen_buffer
->win
.left
= 0;
691 screen_buffer
->win
.right
= screen_buffer
->max_width
- 1;
692 screen_buffer
->win
.top
= 0;
693 screen_buffer
->win
.bottom
= screen_buffer
->max_height
- 1;
694 screen_buffer
->data
= NULL
;
695 screen_buffer
->font
.width
= 0;
696 screen_buffer
->font
.height
= 0;
697 screen_buffer
->font
.weight
= FW_NORMAL
;
698 screen_buffer
->font
.pitch_family
= FIXED_PITCH
| FF_DONTCARE
;
699 screen_buffer
->font
.face_name
= NULL
;
700 screen_buffer
->font
.face_len
= 0;
701 memset( screen_buffer
->color_map
, 0, sizeof(screen_buffer
->color_map
) );
702 init_async_queue( &screen_buffer
->ioctl_q
);
703 list_add_head( &screen_buffer_list
, &screen_buffer
->entry
);
706 screen_buffer
->fd
= create_anonymous_fd( &screen_buffer_fd_ops
, fd
, &screen_buffer
->obj
,
707 FILE_SYNCHRONOUS_IO_NONALERT
);
709 screen_buffer
->fd
= alloc_pseudo_fd( &screen_buffer_fd_ops
, &screen_buffer
->obj
,
710 FILE_SYNCHRONOUS_IO_NONALERT
);
711 if (!screen_buffer
->fd
)
713 release_object( screen_buffer
);
716 allow_fd_caching(screen_buffer
->fd
);
718 if (!(screen_buffer
->data
= malloc( screen_buffer
->width
* screen_buffer
->height
*
719 sizeof(*screen_buffer
->data
) )))
721 release_object( screen_buffer
);
724 /* clear the first row */
725 for (i
= 0; i
< screen_buffer
->width
; i
++) screen_buffer
->data
[i
] = empty_char_info
;
726 /* and copy it to all other rows */
727 for (i
= 1; i
< screen_buffer
->height
; i
++)
728 memcpy( &screen_buffer
->data
[i
* screen_buffer
->width
], screen_buffer
->data
,
729 screen_buffer
->width
* sizeof(char_info_t
) );
731 if (console_input
->server
) queue_host_ioctl( console_input
->server
, IOCTL_CONDRV_INIT_OUTPUT
,
732 screen_buffer
->id
, NULL
, NULL
);
733 if (!console_input
->active
) set_active_screen_buffer( console_input
, screen_buffer
);
734 return &screen_buffer
->obj
;
737 /* free the console for this process */
738 int free_console( struct process
*process
)
740 struct console_input
* console
= process
->console
;
742 if (!console
) return 0;
744 process
->console
= NULL
;
745 if (--console
->num_proc
== 0 && console
->renderer
)
747 /* all processes have terminated... tell the renderer to terminate too */
748 struct condrv_renderer_event evt
;
749 evt
.event
= CONSOLE_RENDERER_EXIT_EVENT
;
750 memset(&evt
.u
, 0, sizeof(evt
.u
));
751 console_input_events_append( console
, &evt
);
753 release_object( console
);
758 /* let process inherit the console from parent... this handle two cases :
759 * 1/ generic console inheritance
760 * 2/ parent is a renderer which launches process, and process should attach to the console
763 obj_handle_t
inherit_console( struct thread
*parent_thread
, obj_handle_t handle
, struct process
*process
,
764 obj_handle_t hconin
)
766 struct console_input
*console
= NULL
;
768 if (handle
&& !(console
= (struct console_input
*)get_handle_obj( current
->process
, handle
, 0,
769 &console_input_ops
)))
772 /* if parent is a renderer, then attach current process to its console
775 if (!console
&& hconin
&& parent_thread
)
777 /* FIXME: should we check some access rights ? */
778 if (!(console
= (struct console_input
*)get_handle_obj( parent_thread
->process
, hconin
,
779 0, &console_input_ops
)))
780 clear_error(); /* ignore error */
782 if (!console
) return 0;
784 process
->console
= console
;
786 return alloc_handle( process
, process
->console
,
787 SYNCHRONIZE
| GENERIC_READ
| GENERIC_WRITE
, 0 );
790 struct thread
*console_get_renderer( struct console_input
*console
)
792 return console
->renderer
;
795 static struct console_input
* console_input_get( obj_handle_t handle
, unsigned access
)
797 struct console_input
* console
= NULL
;
800 console
= (struct console_input
*)get_handle_obj( current
->process
, handle
,
801 access
, &console_input_ops
);
802 else if (current
->process
->console
)
804 console
= (struct console_input
*)grab_object( current
->process
->console
);
807 if (!console
&& !get_error()) set_error(STATUS_INVALID_PARAMETER
);
811 struct console_signal_info
813 struct console_input
*console
;
818 static int propagate_console_signal_cb(struct process
*process
, void *user
)
820 struct console_signal_info
* csi
= (struct console_signal_info
*)user
;
822 if (process
->console
== csi
->console
&& process
->running_threads
&&
823 (!csi
->group
|| process
->group_id
== csi
->group
))
825 /* find a suitable thread to signal */
826 struct thread
*thread
;
827 LIST_FOR_EACH_ENTRY( thread
, &process
->thread_list
, struct thread
, proc_entry
)
829 if (send_thread_signal( thread
, csi
->signal
)) break;
835 static void propagate_console_signal( struct console_input
*console
,
836 int sig
, process_id_t group_id
)
838 struct console_signal_info csi
;
842 set_error( STATUS_INVALID_PARAMETER
);
845 /* FIXME: should support the other events (like CTRL_BREAK) */
846 if (sig
!= CTRL_C_EVENT
)
848 set_error( STATUS_NOT_IMPLEMENTED
);
851 csi
.console
= console
;
853 csi
.group
= group_id
;
855 enum_processes(propagate_console_signal_cb
, &csi
);
858 /* retrieve a pointer to the console input records */
859 static int read_console_input( struct console_input
*console
, struct async
*async
, int flush
)
861 struct iosb
*iosb
= async_get_iosb( async
);
864 count
= min( iosb
->out_size
/ sizeof(INPUT_RECORD
), console
->recnum
);
867 if (!(iosb
->out_data
= malloc( count
* sizeof(INPUT_RECORD
) )))
869 set_error( STATUS_NO_MEMORY
);
870 release_object( iosb
);
873 iosb
->out_size
= iosb
->result
= count
* sizeof(INPUT_RECORD
);
874 memcpy( iosb
->out_data
, console
->records
, iosb
->result
);
875 iosb
->status
= STATUS_SUCCESS
;
876 async_terminate( async
, STATUS_ALERTED
);
880 async_terminate( async
, STATUS_SUCCESS
);
883 release_object( iosb
);
887 if (console
->recnum
> count
)
889 INPUT_RECORD
*new_rec
;
890 memmove( console
->records
, console
->records
+ count
, (console
->recnum
- count
) * sizeof(*console
->records
) );
891 console
->recnum
-= count
;
892 new_rec
= realloc( console
->records
, console
->recnum
* sizeof(*console
->records
) );
893 if (new_rec
) console
->records
= new_rec
;
898 free( console
->records
);
899 console
->records
= NULL
;
900 reset_event( console
->event
);
907 /* add input events to a console input queue */
908 static int write_console_input( struct console_input
* console
, int count
,
909 const INPUT_RECORD
*records
)
911 INPUT_RECORD
*new_rec
;
914 if (!count
) return 1;
915 if (!(new_rec
= realloc( console
->records
,
916 (console
->recnum
+ count
) * sizeof(INPUT_RECORD
) )))
918 set_error( STATUS_NO_MEMORY
);
921 console
->records
= new_rec
;
922 memcpy( new_rec
+ console
->recnum
, records
, count
* sizeof(INPUT_RECORD
) );
924 if (console
->mode
& ENABLE_PROCESSED_INPUT
)
929 if (records
[i
].EventType
== KEY_EVENT
&&
930 records
[i
].Event
.KeyEvent
.uChar
.UnicodeChar
== 'C' - 64 &&
931 !(records
[i
].Event
.KeyEvent
.dwControlKeyState
& ENHANCED_KEY
))
934 memcpy( &console
->records
[console
->recnum
+ i
],
935 &console
->records
[console
->recnum
+ i
+ 1],
936 (count
- i
- 1) * sizeof(INPUT_RECORD
) );
938 if (records
[i
].Event
.KeyEvent
.bKeyDown
)
940 /* send SIGINT to all processes attached to this console */
941 propagate_console_signal( console
, CTRL_C_EVENT
, 0 );
947 console
->recnum
+= count
;
948 while (console
->recnum
&& (async
= find_pending_async( &console
->read_q
)))
950 read_console_input( console
, async
, 1 );
951 release_object( async
);
953 if (console
->recnum
) set_event( console
->event
);
957 /* resize a screen buffer */
958 static int change_screen_buffer_size( struct screen_buffer
*screen_buffer
,
959 int new_width
, int new_height
)
961 int i
, old_width
, old_height
, copy_width
, copy_height
;
962 char_info_t
*new_data
;
964 if (!(new_data
= malloc( new_width
* new_height
* sizeof(*new_data
) )))
966 set_error( STATUS_NO_MEMORY
);
969 old_width
= screen_buffer
->width
;
970 old_height
= screen_buffer
->height
;
971 copy_width
= min( old_width
, new_width
);
972 copy_height
= min( old_height
, new_height
);
974 /* copy all the rows */
975 for (i
= 0; i
< copy_height
; i
++)
977 memcpy( &new_data
[i
* new_width
], &screen_buffer
->data
[i
* old_width
],
978 copy_width
* sizeof(char_info_t
) );
981 /* clear the end of each row */
982 if (new_width
> old_width
)
985 for (i
= old_width
; i
< new_width
; i
++) new_data
[i
] = empty_char_info
;
986 /* and blast it to the other rows */
987 for (i
= 1; i
< copy_height
; i
++)
988 memcpy( &new_data
[i
* new_width
+ old_width
], &new_data
[old_width
],
989 (new_width
- old_width
) * sizeof(char_info_t
) );
992 /* clear remaining rows */
993 if (new_height
> old_height
)
996 for (i
= 0; i
< new_width
; i
++) new_data
[old_height
* new_width
+ i
] = empty_char_info
;
997 /* and blast it to the other rows */
998 for (i
= old_height
+1; i
< new_height
; i
++)
999 memcpy( &new_data
[i
* new_width
], &new_data
[old_height
* new_width
],
1000 new_width
* sizeof(char_info_t
) );
1002 free( screen_buffer
->data
);
1003 screen_buffer
->data
= new_data
;
1004 screen_buffer
->width
= new_width
;
1005 screen_buffer
->height
= new_height
;
1009 static int set_output_info( struct screen_buffer
*screen_buffer
,
1010 const struct condrv_output_info_params
*params
, data_size_t extra_size
)
1012 const struct condrv_output_info
*info
= ¶ms
->info
;
1013 struct condrv_renderer_event evt
;
1016 if (params
->mask
& SET_CONSOLE_OUTPUT_INFO_CURSOR_GEOM
)
1018 if (info
->cursor_size
< 1 || info
->cursor_size
> 100)
1020 set_error( STATUS_INVALID_PARAMETER
);
1023 if (screen_buffer
->cursor_size
!= info
->cursor_size
||
1024 screen_buffer
->cursor_visible
!= info
->cursor_visible
)
1026 screen_buffer
->cursor_size
= info
->cursor_size
;
1027 screen_buffer
->cursor_visible
= info
->cursor_visible
;
1028 evt
.event
= CONSOLE_RENDERER_CURSOR_GEOM_EVENT
;
1029 memset( &evt
.u
, 0, sizeof(evt
.u
) );
1030 evt
.u
.cursor_geom
.size
= info
->cursor_size
;
1031 evt
.u
.cursor_geom
.visible
= info
->cursor_visible
;
1032 console_input_events_append( screen_buffer
->input
, &evt
);
1035 if (params
->mask
& SET_CONSOLE_OUTPUT_INFO_CURSOR_POS
)
1037 if (info
->cursor_x
< 0 || info
->cursor_x
>= screen_buffer
->width
||
1038 info
->cursor_y
< 0 || info
->cursor_y
>= screen_buffer
->height
)
1040 set_error( STATUS_INVALID_PARAMETER
);
1043 if (screen_buffer
->cursor_x
!= info
->cursor_x
|| screen_buffer
->cursor_y
!= info
->cursor_y
)
1045 screen_buffer
->cursor_x
= info
->cursor_x
;
1046 screen_buffer
->cursor_y
= info
->cursor_y
;
1047 evt
.event
= CONSOLE_RENDERER_CURSOR_POS_EVENT
;
1048 memset( &evt
.u
, 0, sizeof(evt
.u
) );
1049 evt
.u
.cursor_pos
.x
= info
->cursor_x
;
1050 evt
.u
.cursor_pos
.y
= info
->cursor_y
;
1051 console_input_events_append( screen_buffer
->input
, &evt
);
1054 if (params
->mask
& SET_CONSOLE_OUTPUT_INFO_SIZE
)
1058 /* new screen-buffer cannot be smaller than actual window */
1059 if (info
->width
< screen_buffer
->win
.right
- screen_buffer
->win
.left
+ 1 ||
1060 info
->height
< screen_buffer
->win
.bottom
- screen_buffer
->win
.top
+ 1)
1062 set_error( STATUS_INVALID_PARAMETER
);
1065 /* FIXME: there are also some basic minimum and max size to deal with */
1066 if (!change_screen_buffer_size( screen_buffer
, info
->width
, info
->height
)) return 0;
1068 evt
.event
= CONSOLE_RENDERER_SB_RESIZE_EVENT
;
1069 memset( &evt
.u
, 0, sizeof(evt
.u
) );
1070 evt
.u
.resize
.width
= info
->width
;
1071 evt
.u
.resize
.height
= info
->height
;
1072 console_input_events_append( screen_buffer
->input
, &evt
);
1074 evt
.event
= CONSOLE_RENDERER_UPDATE_EVENT
;
1075 memset( &evt
.u
, 0, sizeof(evt
.u
) );
1076 evt
.u
.update
.top
= 0;
1077 evt
.u
.update
.bottom
= screen_buffer
->height
- 1;
1078 console_input_events_append( screen_buffer
->input
, &evt
);
1080 /* scroll window to display sb */
1081 if (screen_buffer
->win
.right
>= info
->width
)
1083 screen_buffer
->win
.right
-= screen_buffer
->win
.left
;
1084 screen_buffer
->win
.left
= 0;
1086 if (screen_buffer
->win
.bottom
>= info
->height
)
1088 screen_buffer
->win
.bottom
-= screen_buffer
->win
.top
;
1089 screen_buffer
->win
.top
= 0;
1091 /* reset cursor if needed (normally, if cursor was outside of new sb, the
1092 * window has been shifted so that the new position of the cursor will be
1095 if (screen_buffer
->cursor_x
>= info
->width
)
1097 screen_buffer
->cursor_x
= info
->width
- 1;
1100 if (screen_buffer
->cursor_y
>= info
->height
)
1102 screen_buffer
->cursor_y
= info
->height
- 1;
1107 evt
.event
= CONSOLE_RENDERER_CURSOR_POS_EVENT
;
1108 memset( &evt
.u
, 0, sizeof(evt
.u
) );
1109 evt
.u
.cursor_pos
.x
= info
->cursor_x
;
1110 evt
.u
.cursor_pos
.y
= info
->cursor_y
;
1111 console_input_events_append( screen_buffer
->input
, &evt
);
1114 if (screen_buffer
== screen_buffer
->input
->active
&&
1115 screen_buffer
->input
->mode
& ENABLE_WINDOW_INPUT
)
1118 ir
.EventType
= WINDOW_BUFFER_SIZE_EVENT
;
1119 ir
.Event
.WindowBufferSizeEvent
.dwSize
.X
= info
->width
;
1120 ir
.Event
.WindowBufferSizeEvent
.dwSize
.Y
= info
->height
;
1121 write_console_input( screen_buffer
->input
, 1, &ir
);
1124 if (params
->mask
& SET_CONSOLE_OUTPUT_INFO_ATTR
)
1126 screen_buffer
->attr
= info
->attr
;
1128 if (params
->mask
& SET_CONSOLE_OUTPUT_INFO_POPUP_ATTR
)
1130 screen_buffer
->popup_attr
= info
->popup_attr
;
1132 if (params
->mask
& SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW
)
1134 if (info
->win_left
< 0 || info
->win_left
> info
->win_right
||
1135 info
->win_right
>= screen_buffer
->width
||
1136 info
->win_top
< 0 || info
->win_top
> info
->win_bottom
||
1137 info
->win_bottom
>= screen_buffer
->height
)
1139 set_error( STATUS_INVALID_PARAMETER
);
1142 if (screen_buffer
->win
.left
!= info
->win_left
|| screen_buffer
->win
.top
!= info
->win_top
||
1143 screen_buffer
->win
.right
!= info
->win_right
|| screen_buffer
->win
.bottom
!= info
->win_bottom
)
1145 screen_buffer
->win
.left
= info
->win_left
;
1146 screen_buffer
->win
.top
= info
->win_top
;
1147 screen_buffer
->win
.right
= info
->win_right
;
1148 screen_buffer
->win
.bottom
= info
->win_bottom
;
1149 evt
.event
= CONSOLE_RENDERER_DISPLAY_EVENT
;
1150 memset( &evt
.u
, 0, sizeof(evt
.u
) );
1151 evt
.u
.display
.left
= info
->win_left
;
1152 evt
.u
.display
.top
= info
->win_top
;
1153 evt
.u
.display
.width
= info
->win_right
- info
->win_left
+ 1;
1154 evt
.u
.display
.height
= info
->win_bottom
- info
->win_top
+ 1;
1155 console_input_events_append( screen_buffer
->input
, &evt
);
1158 if (params
->mask
& SET_CONSOLE_OUTPUT_INFO_MAX_SIZE
)
1160 screen_buffer
->max_width
= info
->max_width
;
1161 screen_buffer
->max_height
= info
->max_height
;
1163 if (params
->mask
& SET_CONSOLE_OUTPUT_INFO_COLORTABLE
)
1165 memcpy( screen_buffer
->color_map
, info
->color_map
, sizeof(info
->color_map
) );
1167 if (params
->mask
& SET_CONSOLE_OUTPUT_INFO_FONT
)
1169 screen_buffer
->font
.width
= info
->font_width
;
1170 screen_buffer
->font
.height
= info
->font_height
;
1171 screen_buffer
->font
.weight
= info
->font_weight
;
1172 screen_buffer
->font
.pitch_family
= info
->font_pitch_family
;
1175 extra_size
= extra_size
/ sizeof(WCHAR
) * sizeof(WCHAR
);
1176 font_name
= mem_alloc( extra_size
);
1179 memcpy( font_name
, info
+ 1, extra_size
);
1180 free( screen_buffer
->font
.face_name
);
1181 screen_buffer
->font
.face_name
= font_name
;
1182 screen_buffer
->font
.face_len
= extra_size
;
1190 /* appends a new line to history (history is a fixed size array) */
1191 static void console_input_append_hist( struct console_input
* console
, const WCHAR
* buf
, data_size_t len
)
1193 struct history_line
*ptr
;
1195 if (!console
|| !console
->history_size
)
1197 set_error( STATUS_INVALID_PARAMETER
); /* FIXME */
1201 len
= (len
/ sizeof(WCHAR
)) * sizeof(WCHAR
);
1202 if (console
->history_mode
&& console
->history_index
&&
1203 console
->history
[console
->history_index
- 1]->len
== len
&&
1204 !memcmp( console
->history
[console
->history_index
- 1]->text
, buf
, len
))
1206 /* don't duplicate entry */
1207 set_error( STATUS_ALIAS_EXISTS
);
1210 if (!(ptr
= mem_alloc( offsetof( struct history_line
, text
[len
/ sizeof(WCHAR
)] )))) return;
1212 memcpy( ptr
->text
, buf
, len
);
1214 if (console
->history_index
< console
->history_size
)
1216 console
->history
[console
->history_index
++] = ptr
;
1220 free( console
->history
[0]) ;
1221 memmove( &console
->history
[0], &console
->history
[1],
1222 (console
->history_size
- 1) * sizeof(*console
->history
) );
1223 console
->history
[console
->history_size
- 1] = ptr
;
1227 /* returns a line from the cache */
1228 static data_size_t
console_input_get_hist( struct console_input
*console
, int index
)
1230 data_size_t ret
= 0;
1232 if (index
>= console
->history_index
) set_error( STATUS_INVALID_PARAMETER
);
1235 ret
= console
->history
[index
]->len
;
1236 set_reply_data( console
->history
[index
]->text
, min( ret
, get_reply_max_size() ));
1242 static void console_input_dump( struct object
*obj
, int verbose
)
1244 struct console_input
*console
= (struct console_input
*)obj
;
1245 assert( obj
->ops
== &console_input_ops
);
1246 fprintf( stderr
, "Console input active=%p evt=%p\n",
1247 console
->active
, console
->evt
);
1250 static void console_input_destroy( struct object
*obj
)
1252 struct console_input
* console_in
= (struct console_input
*)obj
;
1253 struct screen_buffer
* curr
;
1256 assert( obj
->ops
== &console_input_ops
);
1258 if (console_in
->server
)
1260 assert( console_in
->server
->console
== console_in
);
1261 disconnect_console_server( console_in
->server
);
1264 free( console_in
->title
);
1265 free( console_in
->records
);
1267 if (console_in
->active
) release_object( console_in
->active
);
1268 console_in
->active
= NULL
;
1270 LIST_FOR_EACH_ENTRY( curr
, &screen_buffer_list
, struct screen_buffer
, entry
)
1272 if (curr
->input
== console_in
) curr
->input
= NULL
;
1275 free_async_queue( &console_in
->ioctl_q
);
1276 free_async_queue( &console_in
->read_q
);
1277 if (console_in
->evt
)
1278 console_in
->evt
->console
= NULL
;
1279 if (console_in
->event
)
1280 release_object( console_in
->event
);
1282 release_object( console_in
->fd
);
1284 for (i
= 0; i
< console_in
->history_size
; i
++)
1285 free( console_in
->history
[i
] );
1286 free( console_in
->history
);
1289 static struct object
*console_input_open_file( struct object
*obj
, unsigned int access
,
1290 unsigned int sharing
, unsigned int options
)
1292 return grab_object( obj
);
1295 static void screen_buffer_dump( struct object
*obj
, int verbose
)
1297 struct screen_buffer
*screen_buffer
= (struct screen_buffer
*)obj
;
1298 assert( obj
->ops
== &screen_buffer_ops
);
1300 fprintf(stderr
, "Console screen buffer input=%p\n", screen_buffer
->input
);
1303 static void screen_buffer_destroy( struct object
*obj
)
1305 struct screen_buffer
*screen_buffer
= (struct screen_buffer
*)obj
;
1307 assert( obj
->ops
== &screen_buffer_ops
);
1309 list_remove( &screen_buffer
->entry
);
1310 if (screen_buffer
->input
&& screen_buffer
->input
->server
)
1311 queue_host_ioctl( screen_buffer
->input
->server
, IOCTL_CONDRV_CLOSE_OUTPUT
,
1312 screen_buffer
->id
, NULL
, NULL
);
1313 if (screen_buffer
->fd
) release_object( screen_buffer
->fd
);
1314 free_async_queue( &screen_buffer
->ioctl_q
);
1315 free( screen_buffer
->data
);
1316 free( screen_buffer
->font
.face_name
);
1319 static struct object
*screen_buffer_open_file( struct object
*obj
, unsigned int access
,
1320 unsigned int sharing
, unsigned int options
)
1322 return grab_object( obj
);
1325 static struct fd
*screen_buffer_get_fd( struct object
*obj
)
1327 struct screen_buffer
*screen_buffer
= (struct screen_buffer
*)obj
;
1328 assert( obj
->ops
== &screen_buffer_ops
);
1329 if (screen_buffer
->fd
)
1330 return (struct fd
*)grab_object( screen_buffer
->fd
);
1331 set_error( STATUS_OBJECT_TYPE_MISMATCH
);
1335 /* read data from a screen buffer */
1336 static void read_console_output( struct screen_buffer
*screen_buffer
, unsigned int x
, unsigned int y
,
1337 enum char_info_mode mode
, unsigned int width
)
1339 unsigned int i
, count
;
1342 if (x
>= screen_buffer
->width
|| y
>= screen_buffer
->height
)
1344 if (width
) set_error( STATUS_INVALID_PARAMETER
);
1347 src
= screen_buffer
->data
+ y
* screen_buffer
->width
+ x
;
1351 case CHAR_INFO_MODE_TEXT
:
1354 count
= min( screen_buffer
->data
+ screen_buffer
->height
* screen_buffer
->width
- src
,
1355 get_reply_max_size() / sizeof(*data
) );
1356 if ((data
= set_reply_data_size( count
* sizeof(*data
) )))
1358 for (i
= 0; i
< count
; i
++) data
[i
] = src
[i
].ch
;
1362 case CHAR_INFO_MODE_ATTR
:
1364 unsigned short *data
;
1365 count
= min( screen_buffer
->data
+ screen_buffer
->height
* screen_buffer
->width
- src
,
1366 get_reply_max_size() / sizeof(*data
) );
1367 if ((data
= set_reply_data_size( count
* sizeof(*data
) )))
1369 for (i
= 0; i
< count
; i
++) data
[i
] = src
[i
].attr
;
1373 case CHAR_INFO_MODE_TEXTATTR
:
1377 if (!width
|| get_reply_max_size() < sizeof(*region
))
1379 set_error( STATUS_INVALID_PARAMETER
);
1382 count
= min( (get_reply_max_size() - sizeof(*region
)) / (width
* sizeof(*data
)), screen_buffer
->height
- y
);
1383 width
= min( width
, screen_buffer
->width
- x
);
1384 if (!(region
= set_reply_data_size( sizeof(*region
) + width
* count
* sizeof(*data
) ))) return;
1387 region
->Right
= x
+ width
- 1;
1388 region
->Bottom
= y
+ count
- 1;
1389 data
= (char_info_t
*)(region
+ 1);
1390 for (i
= 0; i
< count
; i
++)
1392 memcpy( &data
[i
* width
], &src
[i
* screen_buffer
->width
], width
* sizeof(*data
) );
1397 set_error( STATUS_INVALID_PARAMETER
);
1402 /* write data into a screen buffer */
1403 static void write_console_output( struct screen_buffer
*screen_buffer
, const struct condrv_output_params
*params
,
1406 unsigned int i
, entry_size
, entry_cnt
, x
, y
;
1410 entry_size
= params
->mode
== CHAR_INFO_MODE_TEXTATTR
? sizeof(char_info_t
) : sizeof(WCHAR
);
1411 if (size
% entry_size
)
1413 set_error( STATUS_INVALID_PARAMETER
);
1416 if (params
->x
>= screen_buffer
->width
) return;
1417 entry_cnt
= size
/ entry_size
;
1419 for (i
= 0, src
= (char *)(params
+ 1); i
< entry_cnt
; i
++, src
+= entry_size
)
1423 x
= params
->x
+ i
% params
->width
;
1424 y
= params
->y
+ i
/ params
->width
;
1425 if (x
>= screen_buffer
->width
) continue;
1429 x
= (params
->x
+ i
) % screen_buffer
->width
;
1430 y
= params
->y
+ (params
->x
+ i
) / screen_buffer
->width
;
1432 if (y
>= screen_buffer
->height
) break;
1434 dest
= &screen_buffer
->data
[y
* screen_buffer
->width
+ x
];
1435 switch(params
->mode
)
1437 case CHAR_INFO_MODE_TEXT
:
1438 dest
->ch
= *(const WCHAR
*)src
;
1440 case CHAR_INFO_MODE_ATTR
:
1441 dest
->attr
= *(const unsigned short *)src
;
1443 case CHAR_INFO_MODE_TEXTATTR
:
1444 *dest
= *(const char_info_t
*)src
;
1446 case CHAR_INFO_MODE_TEXTSTDATTR
:
1447 dest
->ch
= *(const WCHAR
*)src
;
1448 dest
->attr
= screen_buffer
->attr
;
1451 set_error( STATUS_INVALID_PARAMETER
);
1456 if (i
&& screen_buffer
== screen_buffer
->input
->active
)
1458 struct condrv_renderer_event evt
;
1459 evt
.event
= CONSOLE_RENDERER_UPDATE_EVENT
;
1460 memset(&evt
.u
, 0, sizeof(evt
.u
));
1461 evt
.u
.update
.top
= params
->y
;
1462 evt
.u
.update
.bottom
= params
->width
1463 ? min( params
->y
+ entry_cnt
/ params
->width
, screen_buffer
->height
) - 1
1464 : params
->y
+ (params
->x
+ i
- 1) / screen_buffer
->width
;
1465 console_input_events_append( screen_buffer
->input
, &evt
);
1468 if (get_reply_max_size() == sizeof(SMALL_RECT
))
1471 region
.Left
= params
->x
;
1472 region
.Top
= params
->y
;
1473 region
.Right
= min( params
->x
+ params
->width
, screen_buffer
->width
) - 1;
1474 region
.Bottom
= min( params
->y
+ entry_cnt
/ params
->width
, screen_buffer
->height
) - 1;
1475 set_reply_data( ®ion
, sizeof(region
) );
1477 else set_reply_data( &i
, sizeof(i
) );
1480 /* fill a screen buffer with uniform data */
1481 static int fill_console_output( struct screen_buffer
*screen_buffer
, char_info_t data
,
1482 enum char_info_mode mode
, int x
, int y
, int count
, int wrap
)
1485 char_info_t
*end
, *dest
= screen_buffer
->data
+ y
* screen_buffer
->width
+ x
;
1487 if (y
>= screen_buffer
->height
) return 0;
1490 end
= screen_buffer
->data
+ screen_buffer
->height
* screen_buffer
->width
;
1492 end
= screen_buffer
->data
+ (y
+1) * screen_buffer
->width
;
1494 if (count
> end
- dest
) count
= end
- dest
;
1498 case CHAR_INFO_MODE_TEXT
:
1499 for (i
= 0; i
< count
; i
++) dest
[i
].ch
= data
.ch
;
1501 case CHAR_INFO_MODE_ATTR
:
1502 for (i
= 0; i
< count
; i
++) dest
[i
].attr
= data
.attr
;
1504 case CHAR_INFO_MODE_TEXTATTR
:
1505 for (i
= 0; i
< count
; i
++) dest
[i
] = data
;
1507 case CHAR_INFO_MODE_TEXTSTDATTR
:
1508 for (i
= 0; i
< count
; i
++)
1510 dest
[i
].ch
= data
.ch
;
1511 dest
[i
].attr
= screen_buffer
->attr
;
1515 set_error( STATUS_INVALID_PARAMETER
);
1519 if (count
&& screen_buffer
== screen_buffer
->input
->active
)
1521 struct condrv_renderer_event evt
;
1522 evt
.event
= CONSOLE_RENDERER_UPDATE_EVENT
;
1523 memset(&evt
.u
, 0, sizeof(evt
.u
));
1524 evt
.u
.update
.top
= y
;
1525 evt
.u
.update
.bottom
= (y
* screen_buffer
->width
+ x
+ count
- 1) / screen_buffer
->width
;
1526 console_input_events_append( screen_buffer
->input
, &evt
);
1531 /* scroll parts of a screen buffer */
1532 static void scroll_console_output( struct screen_buffer
*screen_buffer
, int xsrc
, int ysrc
, int xdst
, int ydst
,
1533 int w
, int h
, const rectangle_t
*clip
, char_info_t fill
)
1535 struct condrv_renderer_event evt
;
1536 rectangle_t src
, dst
;
1539 src
.left
= max( xsrc
, clip
->left
);
1540 src
.top
= max( ysrc
, clip
->top
);
1541 src
.right
= min( xsrc
+ w
- 1, clip
->right
);
1542 src
.bottom
= min( ysrc
+ h
- 1, clip
->bottom
);
1546 dst
.right
= xdst
+ w
- 1;
1547 dst
.bottom
= ydst
+ h
- 1;
1549 if (dst
.left
< clip
->left
)
1551 xsrc
+= clip
->left
- dst
.left
;
1552 w
-= clip
->left
- dst
.left
;
1553 dst
.left
= clip
->left
;
1555 if (dst
.top
< clip
->top
)
1557 ysrc
+= clip
->top
- dst
.top
;
1558 h
-= clip
->top
- dst
.top
;
1559 dst
.top
= clip
->top
;
1561 if (dst
.right
> clip
->right
) w
-= dst
.right
- clip
->right
;
1562 if (dst
.bottom
> clip
->bottom
) h
-= dst
.bottom
- clip
->bottom
;
1568 for (y
= h
; y
> 0; y
--)
1570 memcpy( &screen_buffer
->data
[(dst
.top
+ y
- 1) * screen_buffer
->width
+ dst
.left
],
1571 &screen_buffer
->data
[(ysrc
+ y
- 1) * screen_buffer
->width
+ xsrc
],
1572 w
* sizeof(screen_buffer
->data
[0]) );
1577 for (y
= 0; y
< h
; y
++)
1579 /* we use memmove here because when psrc and pdst are the same,
1580 * copies are done on the same row, so the dst and src blocks
1582 memmove( &screen_buffer
->data
[(dst
.top
+ y
) * screen_buffer
->width
+ dst
.left
],
1583 &screen_buffer
->data
[(ysrc
+ y
) * screen_buffer
->width
+ xsrc
],
1584 w
* sizeof(screen_buffer
->data
[0]) );
1589 for (y
= src
.top
; y
<= src
.bottom
; y
++)
1591 int left
= src
.left
;
1592 int right
= src
.right
;
1593 if (dst
.top
<= y
&& y
<= dst
.bottom
)
1595 if (dst
.left
<= src
.left
) left
= max( left
, dst
.right
+ 1 );
1596 if (dst
.left
>= src
.left
) right
= min( right
, dst
.left
- 1 );
1598 for (x
= left
; x
<= right
; x
++) screen_buffer
->data
[y
* screen_buffer
->width
+ x
] = fill
;
1601 /* FIXME: this could be enhanced, by signalling scroll */
1602 evt
.event
= CONSOLE_RENDERER_UPDATE_EVENT
;
1603 memset(&evt
.u
, 0, sizeof(evt
.u
));
1604 evt
.u
.update
.top
= min( src
.top
, dst
.top
);
1605 evt
.u
.update
.bottom
= max( src
.bottom
, dst
.bottom
);
1606 console_input_events_append( screen_buffer
->input
, &evt
);
1609 static void console_server_dump( struct object
*obj
, int verbose
)
1611 assert( obj
->ops
== &console_server_ops
);
1612 fprintf( stderr
, "Console server\n" );
1615 static void console_server_destroy( struct object
*obj
)
1617 struct console_server
*server
= (struct console_server
*)obj
;
1618 assert( obj
->ops
== &console_server_ops
);
1619 disconnect_console_server( server
);
1620 if (server
->fd
) release_object( server
->fd
);
1623 static struct object
*console_server_lookup_name( struct object
*obj
, struct unicode_str
*name
, unsigned int attr
)
1625 struct console_server
*server
= (struct console_server
*)obj
;
1626 static const WCHAR referenceW
[] = {'R','e','f','e','r','e','n','c','e'};
1627 assert( obj
->ops
== &console_server_ops
);
1629 if (name
->len
== sizeof(referenceW
) && !memcmp( name
->str
, referenceW
, name
->len
))
1631 struct screen_buffer
*screen_buffer
;
1633 if (server
->console
)
1635 set_error( STATUS_INVALID_HANDLE
);
1638 if (!(server
->console
= (struct console_input
*)create_console_input( -1 ))) return NULL
;
1639 if (!(screen_buffer
= (struct screen_buffer
*)create_console_output( server
->console
, -1 )))
1641 release_object( server
->console
);
1642 server
->console
= NULL
;
1645 release_object( screen_buffer
);
1646 server
->console
->server
= server
;
1648 return &server
->console
->obj
;
1654 static int console_server_signaled( struct object
*obj
, struct wait_queue_entry
*entry
)
1656 struct console_server
*server
= (struct console_server
*)obj
;
1657 assert( obj
->ops
== &console_server_ops
);
1658 return !server
->console
|| !list_empty( &server
->queue
);
1661 static struct fd
*console_server_get_fd( struct object
* obj
)
1663 struct console_server
*server
= (struct console_server
*)obj
;
1664 assert( obj
->ops
== &console_server_ops
);
1665 return (struct fd
*)grab_object( server
->fd
);
1668 static struct object
*console_server_open_file( struct object
*obj
, unsigned int access
,
1669 unsigned int sharing
, unsigned int options
)
1671 return grab_object( obj
);
1674 static struct object
*create_console_server( void )
1676 struct console_server
*server
;
1678 if (!(server
= alloc_object( &console_server_ops
))) return NULL
;
1679 server
->console
= NULL
;
1681 list_init( &server
->queue
);
1682 list_init( &server
->read_queue
);
1683 server
->fd
= alloc_pseudo_fd( &console_server_fd_ops
, &server
->obj
, FILE_SYNCHRONOUS_IO_NONALERT
);
1686 release_object( server
);
1689 allow_fd_caching(server
->fd
);
1691 return &server
->obj
;
1694 static int is_blocking_read_ioctl( unsigned int code
)
1696 return code
== IOCTL_CONDRV_READ_INPUT
;
1699 static int console_input_ioctl( struct fd
*fd
, ioctl_code_t code
, struct async
*async
)
1701 struct console_input
*console
= get_fd_user( fd
);
1705 case IOCTL_CONDRV_GET_MODE
:
1706 if (console
->server
)
1707 return queue_host_ioctl( console
->server
, code
, 0, async
, &console
->ioctl_q
);
1708 if (get_reply_max_size() != sizeof(console
->mode
))
1710 set_error( STATUS_INVALID_PARAMETER
);
1713 return set_reply_data( &console
->mode
, sizeof(console
->mode
) ) != NULL
;
1715 case IOCTL_CONDRV_SET_MODE
:
1716 if (console
->server
)
1717 return queue_host_ioctl( console
->server
, code
, 0, async
, &console
->ioctl_q
);
1718 if (get_req_data_size() != sizeof(console
->mode
))
1720 set_error( STATUS_INVALID_PARAMETER
);
1723 console
->mode
= *(unsigned int *)get_req_data();
1726 case IOCTL_CONDRV_READ_INPUT
:
1729 if (console
->server
)
1730 return queue_host_ioctl( console
->server
, code
, 0, async
, &console
->ioctl_q
);
1731 if (get_reply_max_size() % sizeof(INPUT_RECORD
))
1733 set_error( STATUS_INVALID_PARAMETER
);
1736 if (get_req_data_size())
1738 if (get_req_data_size() != sizeof(int))
1740 set_error( STATUS_INVALID_PARAMETER
);
1743 blocking
= *(int *)get_req_data();
1745 set_error( STATUS_PENDING
);
1746 if (blocking
&& !console
->recnum
)
1748 queue_async( &console
->read_q
, async
);
1751 return read_console_input( console
, async
, 1 );
1754 case IOCTL_CONDRV_WRITE_INPUT
:
1755 if (console
->server
)
1756 return queue_host_ioctl( console
->server
, code
, 0, async
, &console
->ioctl_q
);
1757 return write_console_input( console
, get_req_data_size() / sizeof(INPUT_RECORD
), get_req_data() );
1759 case IOCTL_CONDRV_PEEK
:
1760 if (console
->server
)
1761 return queue_host_ioctl( console
->server
, code
, 0, async
, &console
->ioctl_q
);
1762 if (get_reply_max_size() % sizeof(INPUT_RECORD
))
1764 set_error( STATUS_INVALID_PARAMETER
);
1767 set_error( STATUS_PENDING
);
1768 return read_console_input( console
, async
, 0 );
1770 case IOCTL_CONDRV_GET_INPUT_INFO
:
1772 struct condrv_input_info info
;
1773 if (console
->server
)
1774 return queue_host_ioctl( console
->server
, code
, 0, async
, &console
->ioctl_q
);
1775 if (get_reply_max_size() != sizeof(info
))
1777 set_error( STATUS_INVALID_PARAMETER
);
1780 info
.input_cp
= console
->input_cp
;
1781 info
.output_cp
= console
->output_cp
;
1782 info
.history_mode
= console
->history_mode
;
1783 info
.history_size
= console
->history_size
;
1784 info
.history_index
= console
->history_index
;
1785 info
.edition_mode
= console
->edition_mode
;
1786 info
.input_count
= console
->recnum
;
1787 info
.win
= console
->win
;
1788 return set_reply_data( &info
, sizeof(info
) ) != NULL
;
1791 case IOCTL_CONDRV_SET_INPUT_INFO
:
1793 const struct condrv_input_info_params
*params
= get_req_data();
1794 if (console
->server
)
1795 return queue_host_ioctl( console
->server
, code
, 0, async
, &console
->ioctl_q
);
1796 if (get_req_data_size() != sizeof(*params
))
1798 set_error( STATUS_INVALID_PARAMETER
);
1801 if (params
->mask
& SET_CONSOLE_INPUT_INFO_HISTORY_MODE
)
1803 console
->history_mode
= params
->info
.history_mode
;
1805 if ((params
->mask
& SET_CONSOLE_INPUT_INFO_HISTORY_SIZE
) &&
1806 console
->history_size
!= params
->info
.history_size
)
1808 struct history_line
**mem
= NULL
;
1811 if (params
->info
.history_size
)
1813 if (!(mem
= mem_alloc( params
->info
.history_size
* sizeof(*mem
) ))) return 0;
1814 memset( mem
, 0, params
->info
.history_size
* sizeof(*mem
) );
1817 delta
= (console
->history_index
> params
->info
.history_size
) ?
1818 (console
->history_index
- params
->info
.history_size
) : 0;
1820 for (i
= delta
; i
< console
->history_index
; i
++)
1822 mem
[i
- delta
] = console
->history
[i
];
1823 console
->history
[i
] = NULL
;
1825 console
->history_index
-= delta
;
1827 for (i
= 0; i
< console
->history_size
; i
++)
1828 free( console
->history
[i
] );
1829 free( console
->history
);
1830 console
->history
= mem
;
1831 console
->history_size
= params
->info
.history_size
;
1833 if (params
->mask
& SET_CONSOLE_INPUT_INFO_EDITION_MODE
)
1835 console
->edition_mode
= params
->info
.edition_mode
;
1837 if (params
->mask
& SET_CONSOLE_INPUT_INFO_INPUT_CODEPAGE
)
1839 console
->input_cp
= params
->info
.input_cp
;
1841 if (params
->mask
& SET_CONSOLE_INPUT_INFO_OUTPUT_CODEPAGE
)
1843 console
->output_cp
= params
->info
.output_cp
;
1845 if (params
->mask
& SET_CONSOLE_INPUT_INFO_WIN
)
1847 console
->win
= params
->info
.win
;
1852 case IOCTL_CONDRV_GET_TITLE
:
1853 if (console
->server
)
1854 return queue_host_ioctl( console
->server
, code
, 0, async
, &console
->ioctl_q
);
1855 if (!console
->title_len
) return 1;
1856 return set_reply_data( console
->title
, min( console
->title_len
, get_reply_max_size() )) != NULL
;
1858 case IOCTL_CONDRV_SET_TITLE
:
1860 data_size_t len
= get_req_data_size();
1861 struct condrv_renderer_event evt
;
1862 WCHAR
*title
= NULL
;
1864 if (console
->server
)
1865 return queue_host_ioctl( console
->server
, code
, 0, async
, &console
->ioctl_q
);
1866 if (len
% sizeof(WCHAR
))
1868 set_error( STATUS_INVALID_PARAMETER
);
1872 if (len
&& !(title
= memdup( get_req_data(), len
))) return 0;
1873 free( console
->title
);
1874 console
->title
= title
;
1875 console
->title_len
= len
;
1876 evt
.event
= CONSOLE_RENDERER_TITLE_EVENT
;
1877 console_input_events_append( console
, &evt
);
1881 case IOCTL_CONDRV_CTRL_EVENT
:
1883 const struct condrv_ctrl_event
*event
= get_req_data();
1885 if (get_req_data_size() != sizeof(*event
))
1887 set_error( STATUS_INVALID_PARAMETER
);
1890 group
= event
->group_id
? event
->group_id
: current
->process
->group_id
;
1893 set_error( STATUS_INVALID_PARAMETER
);
1896 propagate_console_signal( console
, event
->event
, group
);
1897 return !get_error();
1901 set_error( STATUS_INVALID_HANDLE
);
1906 static int screen_buffer_ioctl( struct fd
*fd
, ioctl_code_t code
, struct async
*async
)
1908 struct screen_buffer
*screen_buffer
= get_fd_user( fd
);
1912 case IOCTL_CONDRV_GET_MODE
:
1913 if (screen_buffer
->input
&& screen_buffer
->input
->server
)
1914 return queue_host_ioctl( screen_buffer
->input
->server
, code
, screen_buffer
->id
,
1915 async
, &screen_buffer
->ioctl_q
);
1916 if (get_reply_max_size() != sizeof(screen_buffer
->mode
))
1918 set_error( STATUS_INVALID_PARAMETER
);
1921 return set_reply_data( &screen_buffer
->mode
, sizeof(screen_buffer
->mode
) ) != NULL
;
1923 case IOCTL_CONDRV_SET_MODE
:
1924 if (screen_buffer
->input
&& screen_buffer
->input
->server
)
1925 return queue_host_ioctl( screen_buffer
->input
->server
, code
, screen_buffer
->id
,
1926 async
, &screen_buffer
->ioctl_q
);
1927 if (get_req_data_size() != sizeof(screen_buffer
->mode
))
1929 set_error( STATUS_INVALID_PARAMETER
);
1932 screen_buffer
->mode
= *(unsigned int *)get_req_data();
1935 case IOCTL_CONDRV_READ_OUTPUT
:
1937 const struct condrv_output_params
*params
= get_req_data();
1938 if (screen_buffer
->input
&& screen_buffer
->input
->server
)
1939 return queue_host_ioctl( screen_buffer
->input
->server
, code
, screen_buffer
->id
,
1940 async
, &screen_buffer
->ioctl_q
);
1941 if (get_req_data_size() != sizeof(*params
))
1943 set_error( STATUS_INVALID_PARAMETER
);
1946 if (console_input_is_bare( screen_buffer
->input
))
1948 set_error( STATUS_OBJECT_TYPE_MISMATCH
);
1951 read_console_output( screen_buffer
, params
->x
, params
->y
, params
->mode
, params
->width
);
1952 return !get_error();
1955 case IOCTL_CONDRV_WRITE_OUTPUT
:
1956 if (screen_buffer
->input
&& screen_buffer
->input
->server
)
1957 return queue_host_ioctl( screen_buffer
->input
->server
, code
, screen_buffer
->id
,
1958 async
, &screen_buffer
->ioctl_q
);
1959 if (get_req_data_size() < sizeof(struct condrv_output_params
) ||
1960 (get_reply_max_size() != sizeof(SMALL_RECT
) && get_reply_max_size() != sizeof(unsigned int)))
1962 set_error( STATUS_INVALID_PARAMETER
);
1965 if (console_input_is_bare( screen_buffer
->input
))
1967 set_error( STATUS_OBJECT_TYPE_MISMATCH
);
1970 write_console_output( screen_buffer
, get_req_data(), get_req_data_size() - sizeof(struct condrv_output_params
) );
1971 return !get_error();
1973 case IOCTL_CONDRV_GET_OUTPUT_INFO
:
1975 struct condrv_output_info
*info
;
1978 if (screen_buffer
->input
&& screen_buffer
->input
->server
)
1979 return queue_host_ioctl( screen_buffer
->input
->server
, code
, screen_buffer
->id
,
1980 async
, &screen_buffer
->ioctl_q
);
1981 size
= min( sizeof(*info
) + screen_buffer
->font
.face_len
, get_reply_max_size() );
1982 if (size
< sizeof(*info
))
1984 set_error( STATUS_INVALID_PARAMETER
);
1987 if (!(info
= set_reply_data_size( size
))) return 0;
1989 info
->cursor_size
= screen_buffer
->cursor_size
;
1990 info
->cursor_visible
= screen_buffer
->cursor_visible
;
1991 info
->cursor_x
= screen_buffer
->cursor_x
;
1992 info
->cursor_y
= screen_buffer
->cursor_y
;
1993 info
->width
= screen_buffer
->width
;
1994 info
->height
= screen_buffer
->height
;
1995 info
->attr
= screen_buffer
->attr
;
1996 info
->popup_attr
= screen_buffer
->popup_attr
;
1997 info
->win_left
= screen_buffer
->win
.left
;
1998 info
->win_top
= screen_buffer
->win
.top
;
1999 info
->win_right
= screen_buffer
->win
.right
;
2000 info
->win_bottom
= screen_buffer
->win
.bottom
;
2001 info
->max_width
= screen_buffer
->max_width
;
2002 info
->max_height
= screen_buffer
->max_height
;
2003 info
->font_width
= screen_buffer
->font
.width
;
2004 info
->font_height
= screen_buffer
->font
.height
;
2005 info
->font_weight
= screen_buffer
->font
.weight
;
2006 info
->font_pitch_family
= screen_buffer
->font
.pitch_family
;
2007 memcpy( info
->color_map
, screen_buffer
->color_map
, sizeof(info
->color_map
) );
2008 size
-= sizeof(*info
);
2009 if (size
) memcpy( info
+ 1, screen_buffer
->font
.face_name
, size
);
2013 case IOCTL_CONDRV_SET_OUTPUT_INFO
:
2015 const struct condrv_output_info_params
*params
= get_req_data();
2016 if (screen_buffer
->input
&& screen_buffer
->input
->server
)
2017 return queue_host_ioctl( screen_buffer
->input
->server
, code
, screen_buffer
->id
,
2018 async
, &screen_buffer
->ioctl_q
);
2019 if (get_req_data_size() < sizeof(*params
))
2021 set_error( STATUS_INVALID_PARAMETER
);
2024 if (!screen_buffer
->input
)
2026 set_error( STATUS_INVALID_HANDLE
);
2029 return set_output_info( screen_buffer
, params
, get_req_data_size() - sizeof(*params
) );
2032 case IOCTL_CONDRV_ACTIVATE
:
2033 if (screen_buffer
->input
&& screen_buffer
->input
->server
)
2034 return queue_host_ioctl( screen_buffer
->input
->server
, code
, screen_buffer
->id
,
2035 async
, &screen_buffer
->ioctl_q
);
2037 if (!screen_buffer
->input
)
2039 set_error( STATUS_INVALID_HANDLE
);
2043 set_active_screen_buffer( screen_buffer
->input
, screen_buffer
);
2046 case IOCTL_CONDRV_FILL_OUTPUT
:
2048 const struct condrv_fill_output_params
*params
= get_req_data();
2051 if (screen_buffer
->input
&& screen_buffer
->input
->server
)
2052 return queue_host_ioctl( screen_buffer
->input
->server
, code
, screen_buffer
->id
,
2053 async
, &screen_buffer
->ioctl_q
);
2054 if (get_req_data_size() != sizeof(*params
) ||
2055 (get_reply_max_size() && get_reply_max_size() != sizeof(written
)))
2057 set_error( STATUS_INVALID_PARAMETER
);
2060 data
.ch
= params
->ch
;
2061 data
.attr
= params
->attr
;
2062 written
= fill_console_output( screen_buffer
, data
, params
->mode
,
2063 params
->x
, params
->y
, params
->count
, params
->wrap
);
2064 if (written
&& get_reply_max_size() == sizeof(written
))
2065 set_reply_data( &written
, sizeof(written
) );
2066 return !get_error();
2069 case IOCTL_CONDRV_SCROLL
:
2071 const struct condrv_scroll_params
*params
= get_req_data();
2074 if (screen_buffer
->input
&& screen_buffer
->input
->server
)
2075 return queue_host_ioctl( screen_buffer
->input
->server
, code
, screen_buffer
->id
,
2076 async
, &screen_buffer
->ioctl_q
);
2078 if (get_req_data_size() != sizeof(*params
))
2080 set_error( STATUS_INVALID_PARAMETER
);
2083 if (console_input_is_bare( screen_buffer
->input
) || !screen_buffer
->input
)
2085 set_error( STATUS_OBJECT_TYPE_MISMATCH
);
2088 clip
.left
= max( params
->clip
.Left
, 0 );
2089 clip
.top
= max( params
->clip
.Top
, 0 );
2090 clip
.right
= min( params
->clip
.Right
, screen_buffer
->width
- 1 );
2091 clip
.bottom
= min( params
->clip
.Bottom
, screen_buffer
->height
- 1 );
2092 if (clip
.left
> clip
.right
|| clip
.top
> clip
.bottom
|| params
->scroll
.Left
< 0 || params
->scroll
.Top
< 0 ||
2093 params
->scroll
.Right
>= screen_buffer
->width
|| params
->scroll
.Bottom
>= screen_buffer
->height
||
2094 params
->scroll
.Right
< params
->scroll
.Left
|| params
->scroll
.Top
> params
->scroll
.Bottom
||
2095 params
->origin
.X
< 0 || params
->origin
.X
>= screen_buffer
->width
|| params
->origin
.Y
< 0 ||
2096 params
->origin
.Y
>= screen_buffer
->height
)
2098 set_error( STATUS_INVALID_PARAMETER
);
2102 scroll_console_output( screen_buffer
, params
->scroll
.Left
, params
->scroll
.Top
, params
->origin
.X
, params
->origin
.Y
,
2103 params
->scroll
.Right
- params
->scroll
.Left
+ 1, params
->scroll
.Bottom
- params
->scroll
.Top
+ 1,
2104 &clip
, params
->fill
);
2105 return !get_error();
2109 if (!screen_buffer
->input
|| !screen_buffer
->input
->server
|| code
>> 16 != FILE_DEVICE_CONSOLE
)
2111 set_error( STATUS_INVALID_HANDLE
);
2114 return queue_host_ioctl( screen_buffer
->input
->server
, code
, screen_buffer
->id
,
2115 async
, &screen_buffer
->ioctl_q
);
2119 static int console_input_events_ioctl( struct fd
*fd
, ioctl_code_t code
, struct async
*async
)
2121 struct console_input_events
*evts
= get_fd_user( fd
);
2125 case IOCTL_CONDRV_GET_RENDERER_EVENTS
:
2126 set_error( STATUS_PENDING
);
2127 if (evts
->num_used
) return get_renderer_events( evts
, async
);
2128 queue_async( &evts
->read_q
, async
);
2131 case IOCTL_CONDRV_ATTACH_RENDERER
:
2133 struct console_input
*console_input
;
2134 if (get_req_data_size() != sizeof(condrv_handle_t
))
2136 set_error( STATUS_INVALID_PARAMETER
);
2139 console_input
= (struct console_input
*)get_handle_obj( current
->process
, *(condrv_handle_t
*)get_req_data(),
2140 0, &console_input_ops
);
2141 if (!console_input
) return 0;
2143 if (!console_input
->evt
&& !evts
->console
)
2145 console_input
->evt
= evts
;
2146 console_input
->renderer
= current
;
2147 evts
->console
= console_input
;
2149 else set_error( STATUS_INVALID_HANDLE
);
2151 release_object( console_input
);
2152 return !get_error();
2155 case IOCTL_CONDRV_SCROLL
:
2156 case IOCTL_CONDRV_SET_MODE
:
2157 case IOCTL_CONDRV_WRITE_OUTPUT
:
2158 case IOCTL_CONDRV_READ_OUTPUT
:
2159 case IOCTL_CONDRV_FILL_OUTPUT
:
2160 case IOCTL_CONDRV_GET_OUTPUT_INFO
:
2161 case IOCTL_CONDRV_SET_OUTPUT_INFO
:
2162 if (!evts
->console
|| !evts
->console
->active
)
2164 set_error( STATUS_INVALID_HANDLE
);
2167 return screen_buffer_ioctl( evts
->console
->active
->fd
, code
, async
);
2172 set_error( STATUS_INVALID_HANDLE
);
2175 return console_input_ioctl( evts
->console
->fd
, code
, async
);
2179 static int console_server_ioctl( struct fd
*fd
, ioctl_code_t code
, struct async
*async
)
2181 struct console_server
*server
= get_fd_user( fd
);
2185 case IOCTL_CONDRV_CTRL_EVENT
:
2187 const struct condrv_ctrl_event
*event
= get_req_data();
2188 if (get_req_data_size() != sizeof(*event
))
2190 set_error( STATUS_INVALID_PARAMETER
);
2193 if (!server
->console
)
2195 set_error( STATUS_INVALID_HANDLE
);
2198 propagate_console_signal( server
->console
, event
->event
, event
->group_id
);
2199 return !get_error();
2203 set_error( STATUS_INVALID_HANDLE
);
2208 static struct object_type
*console_device_get_type( struct object
*obj
)
2210 static const WCHAR name
[] = {'D','e','v','i','c','e'};
2211 static const struct unicode_str str
= { name
, sizeof(name
) };
2212 return get_object_type( &str
);
2215 static void console_device_dump( struct object
*obj
, int verbose
)
2217 fputs( "Console device\n", stderr
);
2220 static struct object
*console_device_lookup_name( struct object
*obj
, struct unicode_str
*name
, unsigned int attr
)
2222 static const WCHAR consoleW
[] = {'C','o','n','s','o','l','e'};
2223 static const WCHAR current_inW
[] = {'C','u','r','r','e','n','t','I','n'};
2224 static const WCHAR current_outW
[] = {'C','u','r','r','e','n','t','O','u','t'};
2225 static const WCHAR rendererW
[] = {'R','e','n','d','e','r','e','r'};
2226 static const WCHAR screen_bufferW
[] = {'S','c','r','e','e','n','B','u','f','f','e','r'};
2227 static const WCHAR serverW
[] = {'S','e','r','v','e','r'};
2229 if (name
->len
== sizeof(current_inW
) && !memcmp( name
->str
, current_inW
, name
->len
))
2231 if (!current
->process
->console
)
2233 set_error( STATUS_INVALID_HANDLE
);
2237 return grab_object( current
->process
->console
);
2240 if (name
->len
== sizeof(current_outW
) && !memcmp( name
->str
, current_outW
, name
->len
))
2242 if (!current
->process
->console
|| !current
->process
->console
->active
)
2244 set_error( STATUS_INVALID_HANDLE
);
2248 return grab_object( current
->process
->console
->active
);
2251 if (name
->len
== sizeof(consoleW
) && !memcmp( name
->str
, consoleW
, name
->len
))
2254 return grab_object( obj
);
2257 if (name
->len
== sizeof(rendererW
) && !memcmp( name
->str
, rendererW
, name
->len
))
2260 return create_console_input_events();
2263 if (name
->len
== sizeof(screen_bufferW
) && !memcmp( name
->str
, screen_bufferW
, name
->len
))
2265 if (!current
->process
->console
)
2267 set_error( STATUS_INVALID_HANDLE
);
2271 return create_console_output( current
->process
->console
, -1 );
2274 if (name
->len
== sizeof(serverW
) && !memcmp( name
->str
, serverW
, name
->len
))
2277 return create_console_server();
2283 static struct object
*console_device_open_file( struct object
*obj
, unsigned int access
,
2284 unsigned int sharing
, unsigned int options
)
2287 access
= default_fd_map_access( obj
, access
);
2288 is_output
= access
& FILE_WRITE_DATA
;
2289 if (!current
->process
->console
|| (is_output
&& !current
->process
->console
))
2291 set_error( STATUS_INVALID_HANDLE
);
2294 if (is_output
&& (access
& FILE_READ_DATA
))
2296 set_error( STATUS_INVALID_PARAMETER
);
2299 return is_output
? grab_object( current
->process
->console
->active
) : grab_object( current
->process
->console
);
2302 struct object
*create_console_device( struct object
*root
, const struct unicode_str
*name
)
2304 return create_named_object( root
, &console_device_ops
, name
, 0, NULL
);
2307 /* allocate a console for the renderer */
2308 DECL_HANDLER(alloc_console
)
2310 struct process
*process
;
2311 struct console_input
*console
;
2315 if (req
->input_fd
!= -1)
2317 if ((fd
= thread_get_inflight_fd( current
, req
->input_fd
)) == -1)
2319 set_error( STATUS_INVALID_PARAMETER
);
2328 /* console to be attached to parent process */
2329 if (!(process
= get_process_from_id( current
->process
->parent_id
)))
2331 if (fd
!= -1) close( fd
);
2332 set_error( STATUS_ACCESS_DENIED
);
2338 /* console to be attached to current process */
2339 process
= current
->process
;
2340 grab_object( process
);
2344 /* console to be attached to req->pid */
2345 if (!(process
= get_process_from_id( req
->pid
)))
2347 if (fd
!= -1) close( fd
);
2352 if (attach
&& process
->console
)
2354 if (fd
!= -1) close( fd
);
2355 set_error( STATUS_ACCESS_DENIED
);
2357 else if ((console
= (struct console_input
*)create_console_input( fd
)))
2359 if ((reply
->handle_in
= alloc_handle( current
->process
, console
, req
->access
,
2360 req
->attributes
)) && attach
)
2362 process
->console
= (struct console_input
*)grab_object( console
);
2363 console
->num_proc
++;
2365 release_object( console
);
2367 release_object( process
);
2370 /* free the console of the current process */
2371 DECL_HANDLER(free_console
)
2373 free_console( current
->process
);
2376 /* attach to a other process's console */
2377 DECL_HANDLER(attach_console
)
2379 struct process
*process
;
2381 if (current
->process
->console
)
2383 set_error( STATUS_ACCESS_DENIED
);
2387 process
= get_process_from_id( req
->pid
== ATTACH_PARENT_PROCESS
2388 ? current
->process
->parent_id
: req
->pid
);
2389 if (!process
) return;
2391 if (process
->console
&& process
->console
->active
)
2393 current
->process
->console
= (struct console_input
*)grab_object( process
->console
);
2394 current
->process
->console
->num_proc
++;
2398 set_error( STATUS_INVALID_HANDLE
);
2401 release_object( process
);
2405 /* appends a string to console's history */
2406 DECL_HANDLER(append_console_input_history
)
2408 struct console_input
*console
;
2410 if (!(console
= console_input_get( req
->handle
, FILE_WRITE_PROPERTIES
))) return;
2411 console_input_append_hist( console
, get_req_data(), get_req_data_size() );
2412 release_object( console
);
2415 /* appends a string to console's history */
2416 DECL_HANDLER(get_console_input_history
)
2418 struct console_input
*console
;
2420 if (!(console
= console_input_get( req
->handle
, FILE_READ_PROPERTIES
))) return;
2421 reply
->total
= console_input_get_hist( console
, req
->index
);
2422 release_object( console
);
2425 /* creates a screen buffer */
2426 DECL_HANDLER(create_console_output
)
2428 struct console_input
*console
;
2429 struct object
*screen_buffer
;
2434 if ((fd
= thread_get_inflight_fd( current
, req
->fd
)) == -1)
2436 set_error( STATUS_INVALID_HANDLE
);
2441 if (!(console
= console_input_get( req
->handle_in
, FILE_WRITE_PROPERTIES
)))
2443 if (fd
!= -1) close( fd
);
2446 if (console_input_is_bare( console
) ^ (fd
!= -1))
2448 if (fd
!= -1) close( fd
);
2449 release_object( console
);
2450 set_error( STATUS_INVALID_HANDLE
);
2454 screen_buffer
= create_console_output( console
, fd
);
2457 /* FIXME: should store sharing and test it when opening the CONOUT$ device
2458 * see file.c on how this could be done */
2459 reply
->handle_out
= alloc_handle( current
->process
, screen_buffer
, req
->access
, req
->attributes
);
2460 release_object( screen_buffer
);
2462 release_object( console
);
2465 /* get console which renderer is 'current' */
2466 static int cgwe_enum( struct process
* process
, void* user
)
2468 if (process
->console
&& process
->console
->renderer
== current
)
2470 *(struct console_input
**)user
= (struct console_input
*)grab_object( process
->console
);
2476 DECL_HANDLER(get_console_wait_event
)
2478 struct console_input
* console
= NULL
;
2483 if (!(obj
= get_handle_obj( current
->process
, req
->handle
, FILE_READ_PROPERTIES
, NULL
))) return;
2484 if (obj
->ops
== &console_input_ops
)
2485 console
= (struct console_input
*)grab_object( obj
);
2486 else if (obj
->ops
== &screen_buffer_ops
)
2487 console
= (struct console_input
*)grab_object( ((struct screen_buffer
*)obj
)->input
);
2489 set_error( STATUS_OBJECT_TYPE_MISMATCH
);
2490 release_object( obj
);
2492 else if (current
->process
->console
)
2493 console
= (struct console_input
*)grab_object( current
->process
->console
);
2494 else enum_processes(cgwe_enum
, &console
);
2498 reply
->event
= alloc_handle( current
->process
, console
->event
, EVENT_ALL_ACCESS
, 0 );
2499 release_object( console
);
2501 else set_error( STATUS_INVALID_PARAMETER
);
2504 /* retrieve the next pending console ioctl request */
2505 DECL_HANDLER(get_next_console_request
)
2507 struct console_host_ioctl
*ioctl
= NULL
, *next
;
2508 struct console_server
*server
;
2509 struct iosb
*iosb
= NULL
;
2511 server
= (struct console_server
*)get_handle_obj( current
->process
, req
->handle
, 0, &console_server_ops
);
2512 if (!server
) return;
2514 if (!server
->console
)
2516 set_error( STATUS_INVALID_HANDLE
);
2517 release_object( server
);
2521 if (req
->signal
) set_event( server
->console
->event
);
2522 else reset_event( server
->console
->event
);
2526 /* set result of current pending ioctl */
2527 if (list_empty( &server
->read_queue
))
2529 set_error( STATUS_INVALID_HANDLE
);
2530 release_object( server
);
2534 ioctl
= LIST_ENTRY( list_head( &server
->read_queue
), struct console_host_ioctl
, entry
);
2535 list_remove( &ioctl
->entry
);
2536 list_move_tail( &server
->queue
, &server
->read_queue
);
2538 else if (server
->busy
)
2540 /* set result of previous ioctl */
2541 ioctl
= LIST_ENTRY( list_head( &server
->queue
), struct console_host_ioctl
, entry
);
2542 list_remove( &ioctl
->entry
);
2547 unsigned int status
= req
->status
;
2550 iosb
= async_get_iosb( ioctl
->async
);
2551 iosb
->status
= req
->status
;
2552 iosb
->out_size
= min( iosb
->out_size
, get_req_data_size() );
2555 if ((iosb
->out_data
= memdup( get_req_data(), iosb
->out_size
)))
2557 iosb
->result
= iosb
->out_size
;
2558 status
= STATUS_ALERTED
;
2562 iosb
->status
= STATUS_NO_MEMORY
;
2567 console_host_ioctl_terminate( ioctl
, status
);
2568 if (iosb
) release_object( iosb
);
2572 release_object( server
);
2578 /* if we have a blocking read ioctl in queue head and previous blocking read is still waiting,
2579 * move it to read queue for execution after current read is complete. move all blocking
2580 * ioctl at the same time to preserve their order. */
2581 if (!list_empty( &server
->queue
) && !list_empty( &server
->read_queue
))
2583 ioctl
= LIST_ENTRY( list_head( &server
->queue
), struct console_host_ioctl
, entry
);
2584 if (is_blocking_read_ioctl( ioctl
->code
))
2586 LIST_FOR_EACH_ENTRY_SAFE( ioctl
, next
, &server
->queue
, struct console_host_ioctl
, entry
)
2588 if (!is_blocking_read_ioctl( ioctl
->code
)) continue;
2589 list_remove( &ioctl
->entry
);
2590 list_add_tail( &server
->read_queue
, &ioctl
->entry
);
2595 /* return the next ioctl */
2596 if (!list_empty( &server
->queue
))
2598 ioctl
= LIST_ENTRY( list_head( &server
->queue
), struct console_host_ioctl
, entry
);
2599 iosb
= ioctl
->async
? async_get_iosb( ioctl
->async
) : NULL
;
2601 if (!iosb
|| get_reply_max_size() >= iosb
->in_size
)
2603 reply
->code
= ioctl
->code
;
2604 reply
->output
= ioctl
->output
;
2608 reply
->out_size
= iosb
->out_size
;
2609 set_reply_data_ptr( iosb
->in_data
, iosb
->in_size
);
2610 iosb
->in_data
= NULL
;
2613 if (is_blocking_read_ioctl( ioctl
->code
))
2615 list_remove( &ioctl
->entry
);
2616 assert( list_empty( &server
->read_queue
));
2617 list_add_tail( &server
->read_queue
, &ioctl
->entry
);
2619 else server
->busy
= 1;
2623 reply
->out_size
= iosb
->in_size
;
2624 set_error( STATUS_BUFFER_OVERFLOW
);
2626 if (iosb
) release_object( iosb
);
2630 set_error( STATUS_PENDING
);
2633 release_object( server
);