2 * Server-side console management
4 * Copyright (C) 1998 Alexandre Julliard
23 static void console_input_dump( struct object
*obj
, int verbose
);
24 static void console_input_destroy( struct object
*obj
);
25 static int console_input_signaled( struct object
*obj
, struct thread
*thread
);
28 static int console_get_file_info( struct object
*obj
, struct get_file_info_reply
*reply
);
30 static const struct object_ops console_input_ops
=
32 sizeof(struct console_input
), /* size */
33 console_input_dump
, /* dump */
34 add_queue
, /* add_queue */
35 remove_queue
, /* remove_queue */
36 console_input_signaled
, /* signaled */
37 no_satisfied
, /* satisfied */
38 NULL
, /* get_poll_events */
39 NULL
, /* poll_event */
40 no_get_fd
, /* get_fd */
42 console_get_file_info
, /* get_file_info */
43 NULL
, /* queue_async */
44 console_input_destroy
/* destroy */
47 static void console_input_events_dump( struct object
*obj
, int verbose
);
48 static void console_input_events_destroy( struct object
*obj
);
49 static int console_input_events_signaled( struct object
*obj
, struct thread
*thread
);
51 struct console_input_events
53 struct object obj
; /* object header */
54 int num_alloc
; /* number of allocated events */
55 int num_used
; /* number of actually used events */
56 struct console_renderer_event
* events
;
59 static const struct object_ops console_input_events_ops
=
61 sizeof(struct console_input_events
), /* size */
62 console_input_events_dump
, /* dump */
63 add_queue
, /* add_queue */
64 remove_queue
, /* remove_queue */
65 console_input_events_signaled
, /* signaled */
66 no_satisfied
, /* satisfied */
67 NULL
, /* get_poll_events */
68 NULL
, /* poll_event */
69 no_get_fd
, /* get_fd */
71 no_get_file_info
, /* get_file_info */
72 NULL
, /* queue_async */
73 console_input_events_destroy
/* destroy */
78 struct object obj
; /* object header */
79 struct screen_buffer
*next
; /* linked list of all screen buffers */
80 struct screen_buffer
*prev
;
81 struct console_input
*input
; /* associated console input */
82 int mode
; /* output mode */
83 int cursor_size
; /* size of cursor (percentage filled) */
84 int cursor_visible
;/* cursor visibility flag */
85 int cursor_x
; /* position of cursor */
86 int cursor_y
; /* position of cursor */
87 int width
; /* size (w-h) of the screen buffer */
89 int max_width
; /* size (w-h) of the window given font size */
91 char_info_t
*data
; /* the data for each cell - a width x height matrix */
92 unsigned short attr
; /* default attribute for screen buffer */
93 rectangle_t win
; /* current visible window on the screen buffer *
94 * as seen in wineconsole */
97 static void screen_buffer_dump( struct object
*obj
, int verbose
);
98 static void screen_buffer_destroy( struct object
*obj
);
100 static const struct object_ops screen_buffer_ops
=
102 sizeof(struct screen_buffer
), /* size */
103 screen_buffer_dump
, /* dump */
104 no_add_queue
, /* add_queue */
105 NULL
, /* remove_queue */
107 NULL
, /* satisfied */
108 NULL
, /* get_poll_events */
109 NULL
, /* poll_event */
110 no_get_fd
, /* get_fd */
111 no_flush
, /* flush */
112 console_get_file_info
, /* get_file_info */
113 NULL
, /* queue_async */
114 screen_buffer_destroy
/* destroy */
117 static struct screen_buffer
*screen_buffer_list
;
119 static const char_info_t empty_char_info
= { ' ', 0x00f0 }; /* white on black space */
121 /* dumps the renderer events of a console */
122 static void console_input_events_dump( struct object
*obj
, int verbose
)
124 struct console_input_events
*evts
= (struct console_input_events
*)obj
;
125 assert( obj
->ops
== &console_input_events_ops
);
126 fprintf( stderr
, "Console input events: %d/%d events\n",
127 evts
->num_used
, evts
->num_alloc
);
130 /* destroys the renderer events of a console */
131 static void console_input_events_destroy( struct object
*obj
)
133 struct console_input_events
*evts
= (struct console_input_events
*)obj
;
134 assert( obj
->ops
== &console_input_events_ops
);
135 free( evts
->events
);
138 /* the renderer events list is signaled when it's not empty */
139 static int console_input_events_signaled( struct object
*obj
, struct thread
*thread
)
141 struct console_input_events
*evts
= (struct console_input_events
*)obj
;
142 assert( obj
->ops
== &console_input_events_ops
);
143 return (evts
->num_used
!= 0);
146 /* add an event to the console's renderer events list */
147 static void console_input_events_append( struct console_input_events
* evts
,
148 struct console_renderer_event
* evt
)
150 /* to be done even when the renderer generates the events ? */
151 if (evts
->num_used
== evts
->num_alloc
)
153 evts
->num_alloc
+= 16;
154 evts
->events
= realloc( evts
->events
, evts
->num_alloc
* sizeof(*evt
) );
155 assert(evts
->events
);
157 evts
->events
[evts
->num_used
++] = *evt
;
158 wake_up( &evts
->obj
, 0 );
161 /* retrieves events from the console's renderer events list */
162 static void console_input_events_get( struct console_input_events
* evts
)
164 size_t num
= get_reply_max_size() / sizeof(evts
->events
[0]);
166 if (num
> evts
->num_used
) num
= evts
->num_used
;
167 set_reply_data( evts
->events
, num
* sizeof(evts
->events
[0]) );
168 if (num
< evts
->num_used
)
170 memmove( &evts
->events
[0], &evts
->events
[num
],
171 (evts
->num_used
- num
) * sizeof(evts
->events
[0]) );
173 evts
->num_used
-= num
;
176 static struct console_input_events
*create_console_input_events(void)
178 struct console_input_events
* evt
;
180 if (!(evt
= alloc_object( &console_input_events_ops
, -1 ))) return NULL
;
181 evt
->num_alloc
= evt
->num_used
= 0;
186 static struct object
*create_console_input( struct thread
* renderer
)
188 struct console_input
*console_input
;
190 if (!(console_input
= alloc_object( &console_input_ops
, -1 ))) return NULL
;
191 console_input
->renderer
= renderer
;
192 console_input
->mode
= ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
|
193 ENABLE_ECHO_INPUT
| ENABLE_MOUSE_INPUT
;
194 console_input
->num_proc
= 0;
195 console_input
->active
= NULL
;
196 console_input
->recnum
= 0;
197 console_input
->records
= NULL
;
198 console_input
->evt
= create_console_input_events();
199 console_input
->title
= NULL
;
200 console_input
->history_size
= 50;
201 console_input
->history
= calloc( console_input
->history_size
, sizeof(WCHAR
*) );
202 console_input
->history_index
= 0;
203 console_input
->history_mode
= 0;
205 if (!console_input
->history
|| !console_input
->evt
)
207 release_object( console_input
);
210 return &console_input
->obj
;
213 static struct screen_buffer
*create_console_output( struct console_input
*console_input
)
215 struct screen_buffer
*screen_buffer
;
216 struct console_renderer_event evt
;
219 if (!(screen_buffer
= alloc_object( &screen_buffer_ops
, -1 ))) return NULL
;
220 screen_buffer
->mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
221 screen_buffer
->input
= console_input
;
222 screen_buffer
->cursor_size
= 100;
223 screen_buffer
->cursor_visible
= 1;
224 screen_buffer
->width
= 80;
225 screen_buffer
->height
= 150;
226 screen_buffer
->max_width
= 80;
227 screen_buffer
->max_height
= 25;
228 screen_buffer
->cursor_x
= 0;
229 screen_buffer
->cursor_y
= 0;
230 screen_buffer
->attr
= 0xF0;
231 screen_buffer
->win
.left
= 0;
232 screen_buffer
->win
.right
= screen_buffer
->max_width
- 1;
233 screen_buffer
->win
.top
= 0;
234 screen_buffer
->win
.bottom
= screen_buffer
->max_height
- 1;
236 if ((screen_buffer
->next
= screen_buffer_list
)) screen_buffer
->next
->prev
= screen_buffer
;
237 screen_buffer
->prev
= NULL
;
238 screen_buffer_list
= screen_buffer
;
240 if (!(screen_buffer
->data
= malloc( screen_buffer
->width
* screen_buffer
->height
*
241 sizeof(*screen_buffer
->data
) )))
243 release_object( screen_buffer
);
246 /* clear the first row */
247 for (i
= 0; i
< screen_buffer
->width
; i
++) screen_buffer
->data
[i
] = empty_char_info
;
248 /* and copy it to all other rows */
249 for (i
= 1; i
< screen_buffer
->height
; i
++)
250 memcpy( &screen_buffer
->data
[i
* screen_buffer
->width
], screen_buffer
->data
,
251 screen_buffer
->width
* sizeof(char_info_t
) );
253 if (!console_input
->active
)
255 console_input
->active
= (struct screen_buffer
*)grab_object( screen_buffer
);
257 /* generate the fist events */
258 evt
.event
= CONSOLE_RENDERER_ACTIVE_SB_EVENT
;
259 console_input_events_append( console_input
->evt
, &evt
);
261 evt
.event
= CONSOLE_RENDERER_SB_RESIZE_EVENT
;
262 evt
.u
.resize
.width
= screen_buffer
->width
;
263 evt
.u
.resize
.height
= screen_buffer
->height
;
264 console_input_events_append( console_input
->evt
, &evt
);
266 evt
.event
= CONSOLE_RENDERER_DISPLAY_EVENT
;
267 evt
.u
.display
.left
= screen_buffer
->win
.left
;
268 evt
.u
.display
.top
= screen_buffer
->win
.top
;
269 evt
.u
.display
.width
= screen_buffer
->win
.right
- screen_buffer
->win
.left
+ 1;
270 evt
.u
.display
.height
= screen_buffer
->win
.bottom
- screen_buffer
->win
.top
+ 1;
271 console_input_events_append( console_input
->evt
, &evt
);
273 evt
.event
= CONSOLE_RENDERER_UPDATE_EVENT
;
274 evt
.u
.update
.top
= 0;
275 evt
.u
.update
.bottom
= screen_buffer
->height
- 1;
276 console_input_events_append( console_input
->evt
, &evt
);
278 evt
.event
= CONSOLE_RENDERER_CURSOR_GEOM_EVENT
;
279 evt
.u
.cursor_geom
.size
= screen_buffer
->cursor_size
;
280 evt
.u
.cursor_geom
.visible
= screen_buffer
->cursor_visible
;
281 console_input_events_append( console_input
->evt
, &evt
);
283 evt
.event
= CONSOLE_RENDERER_CURSOR_POS_EVENT
;
284 evt
.u
.cursor_pos
.x
= screen_buffer
->cursor_x
;
285 evt
.u
.cursor_pos
.y
= screen_buffer
->cursor_y
;
286 console_input_events_append( console_input
->evt
, &evt
);
288 return screen_buffer
;
291 /* free the console for this process */
292 int free_console( struct process
*process
)
294 struct console_input
* console
= process
->console
;
296 if (!console
|| !console
->renderer
) return 0;
298 process
->console
= NULL
;
299 if (--console
->num_proc
== 0)
301 /* all processes have terminated... tell the renderer to terminate too */
302 struct console_renderer_event evt
;
303 evt
.event
= CONSOLE_RENDERER_EXIT_EVENT
;
304 console_input_events_append( console
->evt
, &evt
);
306 release_object( console
);
311 /* let process inherit the console from parent... this handle two cases :
312 * 1/ generic console inheritance
313 * 2/ parent is a renderer which launches process, and process should attach to the console
314 * renderered by parent
316 void inherit_console(struct thread
*parent_thread
, struct process
*process
, handle_t hconin
)
319 struct process
* parent
= parent_thread
->process
;
321 /* if parent is a renderer, then attach current process to its console
326 struct console_input
* console
;
328 if ((console
= (struct console_input
*)get_handle_obj( parent
, hconin
, 0, NULL
)))
330 if (console
->renderer
== parent_thread
)
332 process
->console
= (struct console_input
*)grab_object( console
);
333 process
->console
->num_proc
++;
336 release_object( console
);
339 /* otherwise, if parent has a console, attach child to this console */
340 if (!done
&& parent
->console
)
342 assert(parent
->console
->renderer
);
343 process
->console
= (struct console_input
*)grab_object( parent
->console
);
344 process
->console
->num_proc
++;
348 static struct console_input
* console_input_get( handle_t handle
, unsigned access
)
350 struct console_input
* console
= 0;
353 console
= (struct console_input
*)get_handle_obj( current
->process
, handle
,
354 access
, &console_input_ops
);
355 else if (current
->process
->console
)
357 assert( current
->process
->console
->renderer
);
358 console
= (struct console_input
*)grab_object( current
->process
->console
);
361 if (!console
&& !get_error()) set_error(STATUS_INVALID_PARAMETER
);
365 /* check if a console input is signaled: yes if non read input records */
366 static int console_input_signaled( struct object
*obj
, struct thread
*thread
)
368 struct console_input
*console
= (struct console_input
*)obj
;
369 assert( obj
->ops
== &console_input_ops
);
370 return console
->recnum
? 1 : 0;
373 static int get_console_mode( handle_t handle
)
378 if ((obj
= get_handle_obj( current
->process
, handle
, GENERIC_READ
, NULL
)))
380 if (obj
->ops
== &console_input_ops
)
381 ret
= ((struct console_input
*)obj
)->mode
;
382 else if (obj
->ops
== &screen_buffer_ops
)
383 ret
= ((struct screen_buffer
*)obj
)->mode
;
385 set_error( STATUS_OBJECT_TYPE_MISMATCH
);
386 release_object( obj
);
391 /* changes the mode of either a console input or a screen buffer */
392 static int set_console_mode( handle_t handle
, int mode
)
397 if (!(obj
= get_handle_obj( current
->process
, handle
, GENERIC_WRITE
, NULL
)))
399 if (obj
->ops
== &console_input_ops
)
401 /* FIXME: if we remove the edit mode bits, we need (???) to clean up the history */
402 ((struct console_input
*)obj
)->mode
= mode
;
405 else if (obj
->ops
== &screen_buffer_ops
)
407 ((struct screen_buffer
*)obj
)->mode
= mode
;
410 else set_error( STATUS_OBJECT_TYPE_MISMATCH
);
411 release_object( obj
);
415 /* add input events to a console input queue */
416 static int write_console_input( struct console_input
* console
, int count
,
417 const INPUT_RECORD
*records
)
419 INPUT_RECORD
*new_rec
;
421 if (!count
) return 0;
422 if (!(new_rec
= realloc( console
->records
,
423 (console
->recnum
+ count
) * sizeof(INPUT_RECORD
) )))
425 set_error( STATUS_NO_MEMORY
);
426 release_object( console
);
429 console
->records
= new_rec
;
430 memcpy( new_rec
+ console
->recnum
, records
, count
* sizeof(INPUT_RECORD
) );
431 console
->recnum
+= count
;
433 /* wake up all waiters */
434 wake_up( &console
->obj
, 0 );
438 /* retrieve a pointer to the console input records */
439 static int read_console_input( handle_t handle
, int count
, int flush
)
441 struct console_input
*console
;
443 if (!(console
= (struct console_input
*)get_handle_obj( current
->process
, handle
,
444 GENERIC_READ
, &console_input_ops
)))
449 /* special case: do not retrieve anything, but return
450 * the total number of records available */
451 count
= console
->recnum
;
455 if (count
> console
->recnum
) count
= console
->recnum
;
456 set_reply_data( console
->records
, count
* sizeof(INPUT_RECORD
) );
461 for (i
= count
; i
< console
->recnum
; i
++)
462 console
->records
[i
-count
] = console
->records
[i
];
463 if ((console
->recnum
-= count
) > 0)
465 INPUT_RECORD
*new_rec
= realloc( console
->records
,
466 console
->recnum
* sizeof(INPUT_RECORD
) );
467 if (new_rec
) console
->records
= new_rec
;
471 free( console
->records
);
472 console
->records
= NULL
;
475 release_object( console
);
479 /* set misc console input information */
480 static int set_console_input_info( const struct set_console_input_info_request
*req
,
481 const WCHAR
*title
, size_t len
)
483 struct console_input
*console
;
484 struct console_renderer_event evt
;
486 if (!(console
= console_input_get( req
->handle
, GENERIC_WRITE
))) goto error
;
488 if (req
->mask
& SET_CONSOLE_INPUT_INFO_ACTIVE_SB
)
490 struct screen_buffer
*screen_buffer
;
492 screen_buffer
= (struct screen_buffer
*)get_handle_obj( current
->process
, req
->active_sb
,
493 GENERIC_READ
, &screen_buffer_ops
);
494 if (!screen_buffer
|| screen_buffer
->input
!= console
)
496 set_error( STATUS_INVALID_PARAMETER
);
497 if (screen_buffer
) release_object( screen_buffer
);
501 if (screen_buffer
!= console
->active
)
503 if (console
->active
) release_object( console
->active
);
504 console
->active
= screen_buffer
;
505 evt
.event
= CONSOLE_RENDERER_ACTIVE_SB_EVENT
;
506 console_input_events_append( console
->evt
, &evt
);
509 release_object( screen_buffer
);
511 if (req
->mask
& SET_CONSOLE_INPUT_INFO_TITLE
)
513 WCHAR
*new_title
= mem_alloc( len
+ sizeof(WCHAR
) );
516 memcpy( new_title
, title
, len
+ sizeof(WCHAR
) );
517 new_title
[len
/ sizeof(WCHAR
)] = 0;
518 if (console
->title
) free( console
->title
);
519 console
->title
= new_title
;
522 if (req
->mask
& SET_CONSOLE_INPUT_INFO_HISTORY_MODE
)
524 console
->history_mode
= req
->history_mode
;
526 if ((req
->mask
& SET_CONSOLE_INPUT_INFO_HISTORY_SIZE
) &&
527 console
->history_size
!= req
->history_size
)
533 if (req
->history_size
)
535 mem
= mem_alloc( req
->history_size
* sizeof(WCHAR
*) );
536 if (!mem
) goto error
;
537 memset( mem
, 0, req
->history_size
* sizeof(WCHAR
*) );
540 delta
= (console
->history_index
> req
->history_size
) ?
541 (console
->history_index
- req
->history_size
) : 0;
543 for (i
= delta
; i
< console
->history_index
; i
++)
545 mem
[i
- delta
] = console
->history
[i
];
546 console
->history
[i
] = NULL
;
548 console
->history_index
-= delta
;
550 for (i
= 0; i
< console
->history_size
; i
++)
551 if (console
->history
[i
]) free( console
->history
[i
] );
552 free( console
->history
);
553 console
->history
= mem
;
554 console
->history_size
= req
->history_size
;
556 release_object( console
);
559 if (console
) release_object( console
);
563 /* resize a screen buffer */
564 static int change_screen_buffer_size( struct screen_buffer
*screen_buffer
,
565 int new_width
, int new_height
)
567 int i
, old_width
, old_height
, copy_width
, copy_height
;
568 char_info_t
*new_data
;
570 if (!(new_data
= malloc( new_width
* new_height
* sizeof(*new_data
) )))
572 set_error( STATUS_NO_MEMORY
);
575 old_width
= screen_buffer
->width
;
576 old_height
= screen_buffer
->height
;
577 copy_width
= min( old_width
, new_width
);
578 copy_height
= min( old_height
, new_height
);
580 /* copy all the rows */
581 for (i
= 0; i
< copy_height
; i
++)
583 memcpy( &new_data
[i
* new_width
], &screen_buffer
->data
[i
* old_width
],
584 copy_width
* sizeof(char_info_t
) );
587 /* clear the end of each row */
588 if (new_width
> old_width
)
591 for (i
= old_width
; i
< new_width
; i
++) new_data
[i
] = empty_char_info
;
592 /* and blast it to the other rows */
593 for (i
= 1; i
< copy_height
; i
++)
594 memcpy( &new_data
[i
* new_width
+ old_width
], &new_data
[old_width
],
595 (new_width
- old_width
) * sizeof(char_info_t
) );
598 /* clear remaining rows */
599 if (new_height
> old_height
)
602 for (i
= 0; i
< new_width
; i
++) new_data
[old_height
* new_width
+ i
] = empty_char_info
;
603 /* and blast it to the other rows */
604 for (i
= old_height
+1; i
< new_height
; i
++)
605 memcpy( &new_data
[i
* new_width
], &new_data
[old_height
* new_width
],
606 new_width
* sizeof(char_info_t
) );
608 free( screen_buffer
->data
);
609 screen_buffer
->data
= new_data
;
610 screen_buffer
->width
= new_width
;
611 screen_buffer
->height
= new_height
;
615 /* set misc screen buffer information */
616 static int set_console_output_info( struct screen_buffer
*screen_buffer
,
617 const struct set_console_output_info_request
*req
)
619 struct console_renderer_event evt
;
621 if (req
->mask
& SET_CONSOLE_OUTPUT_INFO_CURSOR_GEOM
)
623 if (req
->cursor_size
< 1 || req
->cursor_size
> 100)
625 set_error( STATUS_INVALID_PARAMETER
);
628 if (screen_buffer
->cursor_size
!= req
->cursor_size
||
629 screen_buffer
->cursor_visible
!= req
->cursor_visible
)
631 screen_buffer
->cursor_size
= req
->cursor_size
;
632 screen_buffer
->cursor_visible
= req
->cursor_visible
;
633 evt
.event
= CONSOLE_RENDERER_CURSOR_GEOM_EVENT
;
634 evt
.u
.cursor_geom
.size
= req
->cursor_size
;
635 evt
.u
.cursor_geom
.visible
= req
->cursor_visible
;
636 console_input_events_append( screen_buffer
->input
->evt
, &evt
);
639 if (req
->mask
& SET_CONSOLE_OUTPUT_INFO_CURSOR_POS
)
641 if (req
->cursor_x
< 0 || req
->cursor_x
>= screen_buffer
->width
||
642 req
->cursor_y
< 0 || req
->cursor_y
>= screen_buffer
->height
)
644 set_error( STATUS_INVALID_PARAMETER
);
647 if (screen_buffer
->cursor_x
!= req
->cursor_x
|| screen_buffer
->cursor_y
!= req
->cursor_y
)
649 screen_buffer
->cursor_x
= req
->cursor_x
;
650 screen_buffer
->cursor_y
= req
->cursor_y
;
651 evt
.event
= CONSOLE_RENDERER_CURSOR_POS_EVENT
;
652 evt
.u
.cursor_pos
.x
= req
->cursor_x
;
653 evt
.u
.cursor_pos
.y
= req
->cursor_y
;
654 console_input_events_append( screen_buffer
->input
->evt
, &evt
);
657 if (req
->mask
& SET_CONSOLE_OUTPUT_INFO_SIZE
)
659 /* FIXME: there are also some basic minimum and max size to deal with */
660 if (!change_screen_buffer_size( screen_buffer
, req
->width
, req
->height
)) return 0;
662 evt
.event
= CONSOLE_RENDERER_SB_RESIZE_EVENT
;
663 evt
.u
.resize
.width
= req
->width
;
664 evt
.u
.resize
.height
= req
->height
;
665 console_input_events_append( screen_buffer
->input
->evt
, &evt
);
667 if (screen_buffer
== screen_buffer
->input
->active
&&
668 screen_buffer
->input
->mode
& ENABLE_WINDOW_INPUT
)
671 ir
.EventType
= WINDOW_BUFFER_SIZE_EVENT
;
672 ir
.Event
.WindowBufferSizeEvent
.dwSize
.X
= req
->width
;
673 ir
.Event
.WindowBufferSizeEvent
.dwSize
.Y
= req
->height
;
674 write_console_input( screen_buffer
->input
, 1, &ir
);
677 if (req
->mask
& SET_CONSOLE_OUTPUT_INFO_ATTR
)
679 screen_buffer
->attr
= req
->attr
;
681 if (req
->mask
& SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW
)
683 if (req
->win_left
< 0 || req
->win_left
> req
->win_right
||
684 req
->win_right
>= screen_buffer
->width
||
685 req
->win_top
< 0 || req
->win_top
> req
->win_bottom
||
686 req
->win_bottom
>= screen_buffer
->height
)
688 set_error( STATUS_INVALID_PARAMETER
);
691 if (screen_buffer
->win
.left
!= req
->win_left
|| screen_buffer
->win
.top
!= req
->win_top
||
692 screen_buffer
->win
.right
!= req
->win_right
|| screen_buffer
->win
.bottom
!= req
->win_bottom
)
694 screen_buffer
->win
.left
= req
->win_left
;
695 screen_buffer
->win
.top
= req
->win_top
;
696 screen_buffer
->win
.right
= req
->win_right
;
697 screen_buffer
->win
.bottom
= req
->win_bottom
;
698 evt
.event
= CONSOLE_RENDERER_DISPLAY_EVENT
;
699 evt
.u
.display
.left
= req
->win_left
;
700 evt
.u
.display
.top
= req
->win_top
;
701 evt
.u
.display
.width
= req
->win_right
- req
->win_left
+ 1;
702 evt
.u
.display
.height
= req
->win_bottom
- req
->win_top
+ 1;
703 console_input_events_append( screen_buffer
->input
->evt
, &evt
);
706 if (req
->mask
& SET_CONSOLE_OUTPUT_INFO_MAX_SIZE
)
708 /* can only be done by renderer */
709 if (current
->process
->console
!= screen_buffer
->input
)
711 set_error( STATUS_INVALID_PARAMETER
);
715 screen_buffer
->max_width
= req
->max_width
;
716 screen_buffer
->max_height
= req
->max_height
;
722 /* appends a new line to history (history is a fixed size array) */
723 static void console_input_append_hist( struct console_input
* console
, const WCHAR
* buf
, size_t len
)
725 WCHAR
* ptr
= mem_alloc( (len
+ 1) * sizeof(WCHAR
) );
729 set_error( STATUS_NO_MEMORY
);
732 if (!console
|| !console
->history_size
)
734 set_error( STATUS_INVALID_PARAMETER
); /* FIXME */
738 memcpy( ptr
, buf
, len
* sizeof(WCHAR
) );
741 if (console
->history_mode
&& console
->history_index
&&
742 strncmpW( console
->history
[console
->history_index
- 1], ptr
, len
* sizeof(WCHAR
) ) == 0)
744 /* ok, mode ask us to not use twice the same string...
745 * so just free mem and returns
747 set_error( STATUS_ALIAS_EXISTS
);
752 if (console
->history_index
< console
->history_size
)
754 console
->history
[console
->history_index
++] = ptr
;
758 free( console
->history
[0]) ;
759 memmove( &console
->history
[0], &console
->history
[1],
760 (console
->history_size
- 1) * sizeof(WCHAR
*) );
761 console
->history
[console
->history_size
- 1] = ptr
;
765 /* returns a line from the cachde */
766 static size_t console_input_get_hist( struct console_input
*console
, int index
)
770 if (index
>= console
->history_index
) set_error( STATUS_INVALID_PARAMETER
);
773 ret
= strlenW( console
->history
[index
] ) * sizeof(WCHAR
);
774 set_reply_data( console
->history
[index
], min( ret
, get_reply_max_size() ));
780 static void console_input_dump( struct object
*obj
, int verbose
)
782 struct console_input
*console
= (struct console_input
*)obj
;
783 assert( obj
->ops
== &console_input_ops
);
784 fprintf( stderr
, "Console input active=%p evt=%p\n",
785 console
->active
, console
->evt
);
788 static int console_get_file_info( struct object
*obj
, struct get_file_info_reply
*reply
)
792 reply
->type
= FILE_TYPE_CHAR
;
794 reply
->access_time
= 0;
795 reply
->write_time
= 0;
796 reply
->size_high
= 0;
799 reply
->index_high
= 0;
800 reply
->index_low
= 0;
803 return FD_TYPE_CONSOLE
;
806 static void console_input_destroy( struct object
*obj
)
808 struct console_input
* console_in
= (struct console_input
*)obj
;
809 struct screen_buffer
* curr
;
812 assert( obj
->ops
== &console_input_ops
);
813 if (console_in
->title
) free( console_in
->title
);
814 if (console_in
->records
) free( console_in
->records
);
816 if (console_in
->active
) release_object( console_in
->active
);
817 console_in
->active
= NULL
;
819 for (curr
= screen_buffer_list
; curr
; curr
= curr
->next
)
821 if (curr
->input
== console_in
) curr
->input
= NULL
;
824 release_object( console_in
->evt
);
825 console_in
->evt
= NULL
;
827 for (i
= 0; i
< console_in
->history_size
; i
++)
828 if (console_in
->history
[i
]) free( console_in
->history
[i
] );
829 if (console_in
->history
) free( console_in
->history
);
832 static void screen_buffer_dump( struct object
*obj
, int verbose
)
834 struct screen_buffer
*screen_buffer
= (struct screen_buffer
*)obj
;
835 assert( obj
->ops
== &screen_buffer_ops
);
837 fprintf(stderr
, "Console screen buffer input=%p\n", screen_buffer
->input
);
840 static void screen_buffer_destroy( struct object
*obj
)
842 struct screen_buffer
*screen_buffer
= (struct screen_buffer
*)obj
;
844 assert( obj
->ops
== &screen_buffer_ops
);
846 if (screen_buffer
->next
) screen_buffer
->next
->prev
= screen_buffer
->prev
;
847 if (screen_buffer
->prev
) screen_buffer
->prev
->next
= screen_buffer
->next
;
848 else screen_buffer_list
= screen_buffer
->next
;
850 if (screen_buffer
->input
&& screen_buffer
->input
->active
== screen_buffer
)
852 struct screen_buffer
* sb
;
853 for (sb
= screen_buffer_list
; sb
&& sb
->input
!= screen_buffer
->input
; sb
= sb
->next
);
854 screen_buffer
->input
->active
= sb
;
856 if (screen_buffer
->data
) free( screen_buffer
->data
);
859 /* write data into a screen buffer */
860 static int write_console_output( struct screen_buffer
*screen_buffer
, size_t size
,
861 const void* data
, enum char_info_mode mode
,
862 int x
, int y
, int wrap
)
865 char_info_t
*end
, *dest
= screen_buffer
->data
+ y
* screen_buffer
->width
+ x
;
867 if (y
>= screen_buffer
->height
) return 0;
870 end
= screen_buffer
->data
+ screen_buffer
->height
* screen_buffer
->width
;
872 end
= screen_buffer
->data
+ (y
+1) * screen_buffer
->width
;
876 case CHAR_INFO_MODE_TEXT
:
878 const WCHAR
*ptr
= data
;
879 for (i
= 0; i
< size
/sizeof(*ptr
) && dest
< end
; dest
++, i
++) dest
->ch
= ptr
[i
];
882 case CHAR_INFO_MODE_ATTR
:
884 const unsigned short *ptr
= data
;
885 for (i
= 0; i
< size
/sizeof(*ptr
) && dest
< end
; dest
++, i
++) dest
->attr
= ptr
[i
];
888 case CHAR_INFO_MODE_TEXTATTR
:
890 const char_info_t
*ptr
= data
;
891 for (i
= 0; i
< size
/sizeof(*ptr
) && dest
< end
; dest
++, i
++) *dest
= ptr
[i
];
894 case CHAR_INFO_MODE_TEXTSTDATTR
:
896 const WCHAR
*ptr
= data
;
897 for (i
= 0; i
< size
/sizeof(*ptr
) && dest
< end
; dest
++, i
++)
900 dest
->attr
= screen_buffer
->attr
;
905 set_error( STATUS_INVALID_PARAMETER
);
909 if (i
&& screen_buffer
== screen_buffer
->input
->active
)
911 struct console_renderer_event evt
;
912 evt
.event
= CONSOLE_RENDERER_UPDATE_EVENT
;
913 evt
.u
.update
.top
= y
;
914 evt
.u
.update
.bottom
= (y
* screen_buffer
->width
+ x
+ i
- 1) / screen_buffer
->width
;
915 console_input_events_append( screen_buffer
->input
->evt
, &evt
);
920 /* fill a screen buffer with uniform data */
921 static int fill_console_output( struct screen_buffer
*screen_buffer
, char_info_t data
,
922 enum char_info_mode mode
, int x
, int y
, int count
, int wrap
)
925 char_info_t
*end
, *dest
= screen_buffer
->data
+ y
* screen_buffer
->width
+ x
;
927 if (y
>= screen_buffer
->height
) return 0;
930 end
= screen_buffer
->data
+ screen_buffer
->height
* screen_buffer
->width
;
932 end
= screen_buffer
->data
+ (y
+1) * screen_buffer
->width
;
934 if (count
> end
- dest
) count
= end
- dest
;
938 case CHAR_INFO_MODE_TEXT
:
939 for (i
= 0; i
< count
; i
++) dest
[i
].ch
= data
.ch
;
941 case CHAR_INFO_MODE_ATTR
:
942 for (i
= 0; i
< count
; i
++) dest
[i
].attr
= data
.attr
;
944 case CHAR_INFO_MODE_TEXTATTR
:
945 for (i
= 0; i
< count
; i
++) dest
[i
] = data
;
947 case CHAR_INFO_MODE_TEXTSTDATTR
:
948 for (i
= 0; i
< count
; i
++)
950 dest
[i
].ch
= data
.ch
;
951 dest
[i
].attr
= screen_buffer
->attr
;
955 set_error( STATUS_INVALID_PARAMETER
);
959 if (count
&& screen_buffer
== screen_buffer
->input
->active
)
961 struct console_renderer_event evt
;
962 evt
.event
= CONSOLE_RENDERER_UPDATE_EVENT
;
963 evt
.u
.update
.top
= y
;
964 evt
.u
.update
.bottom
= (y
* screen_buffer
->width
+ x
+ count
- 1) / screen_buffer
->width
;
965 console_input_events_append( screen_buffer
->input
->evt
, &evt
);
970 /* read data from a screen buffer */
971 static void read_console_output( struct screen_buffer
*screen_buffer
, int x
, int y
,
972 enum char_info_mode mode
, int wrap
)
975 char_info_t
*end
, *src
= screen_buffer
->data
+ y
* screen_buffer
->width
+ x
;
977 if (y
>= screen_buffer
->height
) return;
980 end
= screen_buffer
->data
+ screen_buffer
->height
* screen_buffer
->width
;
982 end
= screen_buffer
->data
+ (y
+1) * screen_buffer
->width
;
986 case CHAR_INFO_MODE_TEXT
:
989 int count
= min( end
- src
, get_reply_max_size() / sizeof(*data
) );
990 if ((data
= set_reply_data_size( count
* sizeof(*data
) )))
992 for (i
= 0; i
< count
; i
++) data
[i
] = src
[i
].ch
;
996 case CHAR_INFO_MODE_ATTR
:
998 unsigned short *data
;
999 int count
= min( end
- src
, get_reply_max_size() / sizeof(*data
) );
1000 if ((data
= set_reply_data_size( count
* sizeof(*data
) )))
1002 for (i
= 0; i
< count
; i
++) data
[i
] = src
[i
].attr
;
1006 case CHAR_INFO_MODE_TEXTATTR
:
1009 int count
= min( end
- src
, get_reply_max_size() / sizeof(*data
) );
1010 if ((data
= set_reply_data_size( count
* sizeof(*data
) )))
1012 for (i
= 0; i
< count
; i
++) data
[i
] = src
[i
];
1017 set_error( STATUS_INVALID_PARAMETER
);
1022 /* scroll parts of a screen buffer */
1023 static void scroll_console_output( handle_t handle
, int xsrc
, int ysrc
, int xdst
, int ydst
,
1026 struct screen_buffer
*screen_buffer
;
1028 char_info_t
*psrc
, *pdst
;
1029 struct console_renderer_event evt
;
1031 if (!(screen_buffer
= (struct screen_buffer
*)get_handle_obj( current
->process
, handle
,
1032 GENERIC_READ
, &screen_buffer_ops
)))
1034 if (xsrc
< 0 || ysrc
< 0 || xdst
< 0 || ydst
< 0 ||
1035 xsrc
+ w
> screen_buffer
->width
||
1036 xdst
+ w
> screen_buffer
->width
||
1037 ysrc
+ h
> screen_buffer
->height
||
1038 ydst
+ h
> screen_buffer
->height
||
1041 set_error( STATUS_INVALID_PARAMETER
);
1042 release_object( screen_buffer
);
1048 psrc
= &screen_buffer
->data
[(ysrc
+ h
- 1) * screen_buffer
->width
+ xsrc
];
1049 pdst
= &screen_buffer
->data
[(ydst
+ h
- 1) * screen_buffer
->width
+ xdst
];
1051 for (j
= h
; j
> 0; j
--)
1053 memcpy(pdst
, psrc
, w
* sizeof(*pdst
) );
1054 pdst
-= screen_buffer
->width
;
1055 psrc
-= screen_buffer
->width
;
1060 psrc
= &screen_buffer
->data
[ysrc
* screen_buffer
->width
+ xsrc
];
1061 pdst
= &screen_buffer
->data
[ydst
* screen_buffer
->width
+ xdst
];
1063 for (j
= 0; j
< h
; j
++)
1065 /* we use memmove here because when psrc and pdst are the same,
1066 * copies are done on the same row, so the dst and src blocks
1068 memmove( pdst
, psrc
, w
* sizeof(*pdst
) );
1069 pdst
+= screen_buffer
->width
;
1070 psrc
+= screen_buffer
->width
;
1074 /* FIXME: this could be enhanced, by signalling scroll */
1075 evt
.event
= CONSOLE_RENDERER_UPDATE_EVENT
;
1076 evt
.u
.update
.top
= min(ysrc
, ydst
);
1077 evt
.u
.update
.bottom
= max(ysrc
, ydst
) + h
- 1;
1078 console_input_events_append( screen_buffer
->input
->evt
, &evt
);
1080 release_object( screen_buffer
);
1083 /* allocate a console for the renderer */
1084 DECL_HANDLER(alloc_console
)
1088 struct process
*process
;
1089 struct process
*renderer
= current
->process
;
1090 struct console_input
*console
;
1092 process
= (req
->pid
) ? get_process_from_id( req
->pid
) :
1093 (struct process
*)grab_object( renderer
->parent
);
1095 reply
->handle_in
= 0;
1097 if (!process
) return;
1098 if (process
!= renderer
&& process
->console
)
1100 set_error( STATUS_ACCESS_DENIED
);
1104 if ((console
= (struct console_input
*)create_console_input( current
)))
1106 if ((in
= alloc_handle( renderer
, console
, req
->access
, req
->inherit
)))
1108 if ((evt
= alloc_handle( renderer
, console
->evt
,
1109 SYNCHRONIZE
|GENERIC_READ
|GENERIC_WRITE
, FALSE
)))
1111 if (process
!= renderer
)
1113 process
->console
= (struct console_input
*)grab_object( console
);
1114 console
->num_proc
++;
1116 reply
->handle_in
= in
;
1118 release_object( console
);
1121 close_handle( renderer
, in
, NULL
);
1123 free_console( process
);
1126 release_object( process
);
1129 /* free the console of the current process */
1130 DECL_HANDLER(free_console
)
1132 free_console( current
->process
);
1135 /* let the renderer peek the events it's waiting on */
1136 DECL_HANDLER(get_console_renderer_events
)
1138 struct console_input_events
*evt
;
1140 evt
= (struct console_input_events
*)get_handle_obj( current
->process
, req
->handle
,
1141 GENERIC_WRITE
, &console_input_events_ops
);
1143 console_input_events_get( evt
);
1144 release_object( evt
);
1147 /* open a handle to the process console */
1148 DECL_HANDLER(open_console
)
1150 struct object
*obj
= NULL
;
1156 if (current
->process
->console
&& current
->process
->console
->renderer
)
1157 obj
= grab_object( (struct object
*)current
->process
->console
);
1160 if (current
->process
->console
&& current
->process
->console
->renderer
&&
1161 current
->process
->console
->active
)
1162 obj
= grab_object( (struct object
*)current
->process
->console
->active
);
1165 if ((obj
= get_handle_obj( current
->process
, (handle_t
)req
->from
,
1166 GENERIC_READ
|GENERIC_WRITE
, &console_input_ops
)))
1168 struct console_input
* console
= (struct console_input
*)obj
;
1169 obj
= (console
->active
) ? grab_object( console
->active
) : NULL
;
1170 release_object( console
);
1175 /* FIXME: req->share is not used (as in screen buffer creation) */
1178 reply
->handle
= alloc_handle( current
->process
, obj
, req
->access
, req
->inherit
);
1179 release_object( obj
);
1181 else if (!get_error()) set_error( STATUS_ACCESS_DENIED
);
1184 /* set info about a console input */
1185 DECL_HANDLER(set_console_input_info
)
1187 set_console_input_info( req
, get_req_data(), get_req_data_size() );
1190 /* get info about a console (output only) */
1191 DECL_HANDLER(get_console_input_info
)
1193 struct console_input
*console
;
1195 if (!(console
= console_input_get( req
->handle
, GENERIC_READ
))) return;
1198 size_t len
= strlenW( console
->title
) * sizeof(WCHAR
);
1199 if (len
> get_reply_max_size()) len
= get_reply_max_size();
1200 set_reply_data( console
->title
, len
);
1202 reply
->history_mode
= console
->history_mode
;
1203 reply
->history_size
= console
->history_size
;
1204 reply
->history_index
= console
->history_index
;
1205 release_object( console
);
1208 /* get a console mode (input or output) */
1209 DECL_HANDLER(get_console_mode
)
1211 reply
->mode
= get_console_mode( req
->handle
);
1214 /* set a console mode (input or output) */
1215 DECL_HANDLER(set_console_mode
)
1217 set_console_mode( req
->handle
, req
->mode
);
1220 /* add input records to a console input queue */
1221 DECL_HANDLER(write_console_input
)
1223 struct console_input
*console
;
1226 if (!(console
= (struct console_input
*)get_handle_obj( current
->process
, req
->handle
,
1227 GENERIC_WRITE
, &console_input_ops
)))
1229 reply
->written
= write_console_input( console
, get_req_data_size() / sizeof(INPUT_RECORD
),
1231 release_object( console
);
1234 /* fetch input records from a console input queue */
1235 DECL_HANDLER(read_console_input
)
1237 int count
= get_reply_max_size() / sizeof(INPUT_RECORD
);
1238 reply
->read
= read_console_input( req
->handle
, count
, req
->flush
);
1241 /* appends a string to console's history */
1242 DECL_HANDLER(append_console_input_history
)
1244 struct console_input
*console
;
1246 if (!(console
= console_input_get( req
->handle
, GENERIC_WRITE
))) return;
1247 console_input_append_hist( console
, get_req_data(), get_req_data_size() / sizeof(WCHAR
) );
1248 release_object( console
);
1251 /* appends a string to console's history */
1252 DECL_HANDLER(get_console_input_history
)
1254 struct console_input
*console
;
1256 if (!(console
= console_input_get( req
->handle
, GENERIC_WRITE
))) return;
1257 reply
->total
= console_input_get_hist( console
, req
->index
);
1258 release_object( console
);
1261 /* creates a screen buffer */
1262 DECL_HANDLER(create_console_output
)
1264 struct console_input
* console
;
1265 struct screen_buffer
* screen_buffer
;
1267 if (!(console
= console_input_get( req
->handle_in
, GENERIC_WRITE
))) return;
1269 screen_buffer
= create_console_output( console
);
1272 /* FIXME: should store sharing and test it when opening the CONOUT$ device
1273 * see file.c on how this could be done */
1274 reply
->handle_out
= alloc_handle( current
->process
, screen_buffer
,
1275 req
->access
, req
->inherit
);
1276 release_object( screen_buffer
);
1278 release_object( console
);
1281 /* set info about a console screen buffer */
1282 DECL_HANDLER(set_console_output_info
)
1284 struct screen_buffer
*screen_buffer
;
1286 if ((screen_buffer
= (struct screen_buffer
*)get_handle_obj( current
->process
, req
->handle
,
1287 GENERIC_WRITE
, &screen_buffer_ops
)))
1289 set_console_output_info( screen_buffer
, req
);
1290 release_object( screen_buffer
);
1294 /* get info about a console screen buffer */
1295 DECL_HANDLER(get_console_output_info
)
1297 struct screen_buffer
*screen_buffer
;
1299 if ((screen_buffer
= (struct screen_buffer
*)get_handle_obj( current
->process
, req
->handle
,
1300 GENERIC_READ
, &screen_buffer_ops
)))
1302 reply
->cursor_size
= screen_buffer
->cursor_size
;
1303 reply
->cursor_visible
= screen_buffer
->cursor_visible
;
1304 reply
->cursor_x
= screen_buffer
->cursor_x
;
1305 reply
->cursor_y
= screen_buffer
->cursor_y
;
1306 reply
->width
= screen_buffer
->width
;
1307 reply
->height
= screen_buffer
->height
;
1308 reply
->attr
= screen_buffer
->attr
;
1309 reply
->win_left
= screen_buffer
->win
.left
;
1310 reply
->win_top
= screen_buffer
->win
.top
;
1311 reply
->win_right
= screen_buffer
->win
.right
;
1312 reply
->win_bottom
= screen_buffer
->win
.bottom
;
1313 reply
->max_width
= screen_buffer
->max_width
;
1314 reply
->max_height
= screen_buffer
->max_height
;
1315 release_object( screen_buffer
);
1319 /* read data (chars & attrs) from a screen buffer */
1320 DECL_HANDLER(read_console_output
)
1322 struct screen_buffer
*screen_buffer
;
1324 if ((screen_buffer
= (struct screen_buffer
*)get_handle_obj( current
->process
, req
->handle
,
1325 GENERIC_READ
, &screen_buffer_ops
)))
1327 read_console_output( screen_buffer
, req
->x
, req
->y
, req
->mode
, req
->wrap
);
1328 reply
->width
= screen_buffer
->width
;
1329 reply
->height
= screen_buffer
->height
;
1330 release_object( screen_buffer
);
1334 /* write data (char and/or attrs) to a screen buffer */
1335 DECL_HANDLER(write_console_output
)
1337 struct screen_buffer
*screen_buffer
;
1339 if ((screen_buffer
= (struct screen_buffer
*)get_handle_obj( current
->process
, req
->handle
,
1340 GENERIC_WRITE
, &screen_buffer_ops
)))
1342 reply
->written
= write_console_output( screen_buffer
, get_req_data_size(), get_req_data(),
1343 req
->mode
, req
->x
, req
->y
, req
->wrap
);
1344 reply
->width
= screen_buffer
->width
;
1345 reply
->height
= screen_buffer
->height
;
1346 release_object( screen_buffer
);
1350 /* fill a screen buffer with constant data (chars and/or attributes) */
1351 DECL_HANDLER(fill_console_output
)
1353 struct screen_buffer
*screen_buffer
;
1355 if ((screen_buffer
= (struct screen_buffer
*)get_handle_obj( current
->process
, req
->handle
,
1356 GENERIC_WRITE
, &screen_buffer_ops
)))
1358 reply
->written
= fill_console_output( screen_buffer
, req
->data
, req
->mode
,
1359 req
->x
, req
->y
, req
->count
, req
->wrap
);
1360 release_object( screen_buffer
);
1364 /* move a rect of data in a screen buffer */
1365 DECL_HANDLER(move_console_output
)
1367 scroll_console_output( req
->handle
, req
->x_src
, req
->y_src
, req
->x_dst
, req
->y_dst
,