More general approach to file descriptor types and flags.
[wine/wine64.git] / server / console.c
blob29f76e577708d1def8f58b4af400583c0a95a424
1 /*
2 * Server-side console management
4 * Copyright (C) 1998 Alexandre Julliard
5 * 2001 Eric Pouech
7 */
9 #include "config.h"
11 #include <assert.h>
12 #include <string.h>
13 #include <stdio.h>
14 #include <unistd.h>
16 #include "handle.h"
17 #include "process.h"
18 #include "request.h"
19 #include "unicode.h"
20 #include "console.h"
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 );
27 /* common routine */
28 static int console_get_file_info( struct object *obj, struct get_file_info_reply *reply, int *flags );
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 */
41 no_flush, /* flush */
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 */
70 no_flush, /* flush */
71 no_get_file_info, /* get_file_info */
72 NULL, /* queue_async */
73 console_input_events_destroy /* destroy */
76 struct screen_buffer
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 */
88 int height;
89 int max_width; /* size (w-h) of the window given font size */
90 int max_height;
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 */
106 NULL, /* signaled */
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 = { ' ', 0x000f }; /* 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;
182 evt->events = NULL;
183 return evt;
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 );
208 return NULL;
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;
217 int i;
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 = 0x0F;
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 );
244 return NULL;
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 );
308 return 1;
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)
318 int done = 0;
319 struct process* parent = parent_thread->process;
321 /* if parent is a renderer, then attach current process to its console
322 * a bit hacky....
324 if (hconin)
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++;
334 done = 1;
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;
352 if (handle)
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);
362 return console;
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 )
375 struct object *obj;
376 int ret = 0;
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;
384 else
385 set_error( STATUS_OBJECT_TYPE_MISMATCH );
386 release_object( obj );
388 return ret;
391 /* changes the mode of either a console input or a screen buffer */
392 static int set_console_mode( handle_t handle, int mode )
394 struct object *obj;
395 int ret = 0;
397 if (!(obj = get_handle_obj( current->process, handle, GENERIC_WRITE, NULL )))
398 return 0;
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;
403 ret = 1;
405 else if (obj->ops == &screen_buffer_ops)
407 ((struct screen_buffer *)obj)->mode = mode;
408 ret = 1;
410 else set_error( STATUS_OBJECT_TYPE_MISMATCH );
411 release_object( obj );
412 return ret;
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 );
427 return -1;
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 );
435 return count;
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 )))
445 return -1;
447 if (!count)
449 /* special case: do not retrieve anything, but return
450 * the total number of records available */
451 count = console->recnum;
453 else
455 if (count > console->recnum) count = console->recnum;
456 set_reply_data( console->records, count * sizeof(INPUT_RECORD) );
458 if (flush)
460 int i;
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;
469 else
471 free( console->records );
472 console->records = NULL;
475 release_object( console );
476 return count;
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 );
498 goto error;
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 );
508 else
509 release_object( screen_buffer );
511 if (req->mask & SET_CONSOLE_INPUT_INFO_TITLE)
513 WCHAR *new_title = mem_alloc( len + sizeof(WCHAR) );
514 if (new_title)
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)
529 WCHAR** mem = NULL;
530 int i;
531 int delta;
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 );
557 return 1;
558 error:
559 if (console) release_object( console );
560 return 0;
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 );
573 return 0;
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)
590 /* fill first row */
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)
601 /* fill first row */
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;
612 return 1;
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 );
626 return 0;
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 );
645 return 0;
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)
670 INPUT_RECORD ir;
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 );
689 return 0;
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 );
712 return 0;
715 screen_buffer->max_width = req->max_width;
716 screen_buffer->max_height = req->max_height;
719 return 1;
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) );
727 if (!ptr)
729 set_error( STATUS_NO_MEMORY );
730 return;
732 if (!console || !console->history_size)
734 set_error( STATUS_INVALID_PARAMETER ); /* FIXME */
735 return;
738 memcpy( ptr, buf, len * sizeof(WCHAR) );
739 ptr[len] = 0;
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 );
748 free(ptr);
749 return;
752 if (console->history_index < console->history_size)
754 console->history[console->history_index++] = ptr;
756 else
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 )
768 size_t ret = 0;
770 if (index >= console->history_index) set_error( STATUS_INVALID_PARAMETER );
771 else
773 ret = strlenW( console->history[index] ) * sizeof(WCHAR);
774 set_reply_data( console->history[index], min( ret, get_reply_max_size() ));
776 return ret;
779 /* dumb dump */
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, int *flags )
790 if (reply)
792 reply->type = FILE_TYPE_CHAR;
793 reply->attr = 0;
794 reply->access_time = 0;
795 reply->write_time = 0;
796 reply->size_high = 0;
797 reply->size_low = 0;
798 reply->links = 0;
799 reply->index_high = 0;
800 reply->index_low = 0;
801 reply->serial = 0;
803 *flags = 0;
804 return FD_TYPE_CONSOLE;
807 static void console_input_destroy( struct object *obj )
809 struct console_input* console_in = (struct console_input *)obj;
810 struct screen_buffer* curr;
811 int i;
813 assert( obj->ops == &console_input_ops );
814 if (console_in->title) free( console_in->title );
815 if (console_in->records) free( console_in->records );
817 if (console_in->active) release_object( console_in->active );
818 console_in->active = NULL;
820 for (curr = screen_buffer_list; curr; curr = curr->next)
822 if (curr->input == console_in) curr->input = NULL;
825 release_object( console_in->evt );
826 console_in->evt = NULL;
828 for (i = 0; i < console_in->history_size; i++)
829 if (console_in->history[i]) free( console_in->history[i] );
830 if (console_in->history) free( console_in->history );
833 static void screen_buffer_dump( struct object *obj, int verbose )
835 struct screen_buffer *screen_buffer = (struct screen_buffer *)obj;
836 assert( obj->ops == &screen_buffer_ops );
838 fprintf(stderr, "Console screen buffer input=%p\n", screen_buffer->input );
841 static void screen_buffer_destroy( struct object *obj )
843 struct screen_buffer *screen_buffer = (struct screen_buffer *)obj;
845 assert( obj->ops == &screen_buffer_ops );
847 if (screen_buffer->next) screen_buffer->next->prev = screen_buffer->prev;
848 if (screen_buffer->prev) screen_buffer->prev->next = screen_buffer->next;
849 else screen_buffer_list = screen_buffer->next;
851 if (screen_buffer->input && screen_buffer->input->active == screen_buffer)
853 struct screen_buffer* sb;
854 for (sb = screen_buffer_list; sb && sb->input != screen_buffer->input; sb = sb->next);
855 screen_buffer->input->active = sb;
857 if (screen_buffer->data) free( screen_buffer->data );
860 /* write data into a screen buffer */
861 static int write_console_output( struct screen_buffer *screen_buffer, size_t size,
862 const void* data, enum char_info_mode mode,
863 int x, int y, int wrap )
865 int i;
866 char_info_t *end, *dest = screen_buffer->data + y * screen_buffer->width + x;
868 if (y >= screen_buffer->height) return 0;
870 if (wrap)
871 end = screen_buffer->data + screen_buffer->height * screen_buffer->width;
872 else
873 end = screen_buffer->data + (y+1) * screen_buffer->width;
875 switch(mode)
877 case CHAR_INFO_MODE_TEXT:
879 const WCHAR *ptr = data;
880 for (i = 0; i < size/sizeof(*ptr) && dest < end; dest++, i++) dest->ch = ptr[i];
882 break;
883 case CHAR_INFO_MODE_ATTR:
885 const unsigned short *ptr = data;
886 for (i = 0; i < size/sizeof(*ptr) && dest < end; dest++, i++) dest->attr = ptr[i];
888 break;
889 case CHAR_INFO_MODE_TEXTATTR:
891 const char_info_t *ptr = data;
892 for (i = 0; i < size/sizeof(*ptr) && dest < end; dest++, i++) *dest = ptr[i];
894 break;
895 case CHAR_INFO_MODE_TEXTSTDATTR:
897 const WCHAR *ptr = data;
898 for (i = 0; i < size/sizeof(*ptr) && dest < end; dest++, i++)
900 dest->ch = ptr[i];
901 dest->attr = screen_buffer->attr;
904 break;
905 default:
906 set_error( STATUS_INVALID_PARAMETER );
907 return 0;
910 if (i && screen_buffer == screen_buffer->input->active)
912 struct console_renderer_event evt;
913 evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
914 evt.u.update.top = y;
915 evt.u.update.bottom = (y * screen_buffer->width + x + i - 1) / screen_buffer->width;
916 console_input_events_append( screen_buffer->input->evt, &evt );
918 return i;
921 /* fill a screen buffer with uniform data */
922 static int fill_console_output( struct screen_buffer *screen_buffer, char_info_t data,
923 enum char_info_mode mode, int x, int y, int count, int wrap )
925 int i;
926 char_info_t *end, *dest = screen_buffer->data + y * screen_buffer->width + x;
928 if (y >= screen_buffer->height) return 0;
930 if (wrap)
931 end = screen_buffer->data + screen_buffer->height * screen_buffer->width;
932 else
933 end = screen_buffer->data + (y+1) * screen_buffer->width;
935 if (count > end - dest) count = end - dest;
937 switch(mode)
939 case CHAR_INFO_MODE_TEXT:
940 for (i = 0; i < count; i++) dest[i].ch = data.ch;
941 break;
942 case CHAR_INFO_MODE_ATTR:
943 for (i = 0; i < count; i++) dest[i].attr = data.attr;
944 break;
945 case CHAR_INFO_MODE_TEXTATTR:
946 for (i = 0; i < count; i++) dest[i] = data;
947 break;
948 case CHAR_INFO_MODE_TEXTSTDATTR:
949 for (i = 0; i < count; i++)
951 dest[i].ch = data.ch;
952 dest[i].attr = screen_buffer->attr;
954 break;
955 default:
956 set_error( STATUS_INVALID_PARAMETER );
957 return 0;
960 if (count && screen_buffer == screen_buffer->input->active)
962 struct console_renderer_event evt;
963 evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
964 evt.u.update.top = y;
965 evt.u.update.bottom = (y * screen_buffer->width + x + count - 1) / screen_buffer->width;
966 console_input_events_append( screen_buffer->input->evt, &evt );
968 return i;
971 /* read data from a screen buffer */
972 static void read_console_output( struct screen_buffer *screen_buffer, int x, int y,
973 enum char_info_mode mode, int wrap )
975 int i;
976 char_info_t *end, *src = screen_buffer->data + y * screen_buffer->width + x;
978 if (y >= screen_buffer->height) return;
980 if (wrap)
981 end = screen_buffer->data + screen_buffer->height * screen_buffer->width;
982 else
983 end = screen_buffer->data + (y+1) * screen_buffer->width;
985 switch(mode)
987 case CHAR_INFO_MODE_TEXT:
989 WCHAR *data;
990 int count = min( end - src, get_reply_max_size() / sizeof(*data) );
991 if ((data = set_reply_data_size( count * sizeof(*data) )))
993 for (i = 0; i < count; i++) data[i] = src[i].ch;
996 break;
997 case CHAR_INFO_MODE_ATTR:
999 unsigned short *data;
1000 int count = min( end - src, get_reply_max_size() / sizeof(*data) );
1001 if ((data = set_reply_data_size( count * sizeof(*data) )))
1003 for (i = 0; i < count; i++) data[i] = src[i].attr;
1006 break;
1007 case CHAR_INFO_MODE_TEXTATTR:
1009 char_info_t *data;
1010 int count = min( end - src, get_reply_max_size() / sizeof(*data) );
1011 if ((data = set_reply_data_size( count * sizeof(*data) )))
1013 for (i = 0; i < count; i++) data[i] = src[i];
1016 break;
1017 default:
1018 set_error( STATUS_INVALID_PARAMETER );
1019 break;
1023 /* scroll parts of a screen buffer */
1024 static void scroll_console_output( handle_t handle, int xsrc, int ysrc, int xdst, int ydst,
1025 int w, int h )
1027 struct screen_buffer *screen_buffer;
1028 int j;
1029 char_info_t *psrc, *pdst;
1030 struct console_renderer_event evt;
1032 if (!(screen_buffer = (struct screen_buffer *)get_handle_obj( current->process, handle,
1033 GENERIC_READ, &screen_buffer_ops )))
1034 return;
1035 if (xsrc < 0 || ysrc < 0 || xdst < 0 || ydst < 0 ||
1036 xsrc + w > screen_buffer->width ||
1037 xdst + w > screen_buffer->width ||
1038 ysrc + h > screen_buffer->height ||
1039 ydst + h > screen_buffer->height ||
1040 w == 0 || h == 0)
1042 set_error( STATUS_INVALID_PARAMETER );
1043 release_object( screen_buffer );
1044 return;
1047 if (ysrc < ydst)
1049 psrc = &screen_buffer->data[(ysrc + h - 1) * screen_buffer->width + xsrc];
1050 pdst = &screen_buffer->data[(ydst + h - 1) * screen_buffer->width + xdst];
1052 for (j = h; j > 0; j--)
1054 memcpy(pdst, psrc, w * sizeof(*pdst) );
1055 pdst -= screen_buffer->width;
1056 psrc -= screen_buffer->width;
1059 else
1061 psrc = &screen_buffer->data[ysrc * screen_buffer->width + xsrc];
1062 pdst = &screen_buffer->data[ydst * screen_buffer->width + xdst];
1064 for (j = 0; j < h; j++)
1066 /* we use memmove here because when psrc and pdst are the same,
1067 * copies are done on the same row, so the dst and src blocks
1068 * can overlap */
1069 memmove( pdst, psrc, w * sizeof(*pdst) );
1070 pdst += screen_buffer->width;
1071 psrc += screen_buffer->width;
1075 /* FIXME: this could be enhanced, by signalling scroll */
1076 evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
1077 evt.u.update.top = min(ysrc, ydst);
1078 evt.u.update.bottom = max(ysrc, ydst) + h - 1;
1079 console_input_events_append( screen_buffer->input->evt, &evt );
1081 release_object( screen_buffer );
1084 /* allocate a console for the renderer */
1085 DECL_HANDLER(alloc_console)
1087 handle_t in = 0;
1088 handle_t evt = 0;
1089 struct process *process;
1090 struct process *renderer = current->process;
1091 struct console_input *console;
1093 process = (req->pid) ? get_process_from_id( req->pid ) :
1094 (struct process *)grab_object( renderer->parent );
1096 reply->handle_in = 0;
1097 reply->event = 0;
1098 if (!process) return;
1099 if (process != renderer && process->console)
1101 set_error( STATUS_ACCESS_DENIED );
1102 goto the_end;
1105 if ((console = (struct console_input*)create_console_input( current )))
1107 if ((in = alloc_handle( renderer, console, req->access, req->inherit )))
1109 if ((evt = alloc_handle( renderer, console->evt,
1110 SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE, FALSE )))
1112 if (process != renderer)
1114 process->console = (struct console_input*)grab_object( console );
1115 console->num_proc++;
1117 reply->handle_in = in;
1118 reply->event = evt;
1119 release_object( console );
1120 goto the_end;
1122 close_handle( renderer, in, NULL );
1124 free_console( process );
1126 the_end:
1127 release_object( process );
1130 /* free the console of the current process */
1131 DECL_HANDLER(free_console)
1133 free_console( current->process );
1136 /* let the renderer peek the events it's waiting on */
1137 DECL_HANDLER(get_console_renderer_events)
1139 struct console_input_events *evt;
1141 evt = (struct console_input_events *)get_handle_obj( current->process, req->handle,
1142 GENERIC_WRITE, &console_input_events_ops );
1143 if (!evt) return;
1144 console_input_events_get( evt );
1145 release_object( evt );
1148 /* open a handle to the process console */
1149 DECL_HANDLER(open_console)
1151 struct object *obj = NULL;
1153 reply->handle = 0;
1154 switch (req->from)
1156 case 0:
1157 if (current->process->console && current->process->console->renderer)
1158 obj = grab_object( (struct object*)current->process->console );
1159 break;
1160 case 1:
1161 if (current->process->console && current->process->console->renderer &&
1162 current->process->console->active)
1163 obj = grab_object( (struct object*)current->process->console->active );
1164 break;
1165 default:
1166 if ((obj = get_handle_obj( current->process, (handle_t)req->from,
1167 GENERIC_READ|GENERIC_WRITE, &console_input_ops )))
1169 struct console_input* console = (struct console_input*)obj;
1170 obj = (console->active) ? grab_object( console->active ) : NULL;
1171 release_object( console );
1173 break;
1176 /* FIXME: req->share is not used (as in screen buffer creation) */
1177 if (obj)
1179 reply->handle = alloc_handle( current->process, obj, req->access, req->inherit );
1180 release_object( obj );
1182 else if (!get_error()) set_error( STATUS_ACCESS_DENIED );
1185 /* set info about a console input */
1186 DECL_HANDLER(set_console_input_info)
1188 set_console_input_info( req, get_req_data(), get_req_data_size() );
1191 /* get info about a console (output only) */
1192 DECL_HANDLER(get_console_input_info)
1194 struct console_input *console;
1196 if (!(console = console_input_get( req->handle, GENERIC_READ ))) return;
1197 if (console->title)
1199 size_t len = strlenW( console->title ) * sizeof(WCHAR);
1200 if (len > get_reply_max_size()) len = get_reply_max_size();
1201 set_reply_data( console->title, len );
1203 reply->history_mode = console->history_mode;
1204 reply->history_size = console->history_size;
1205 reply->history_index = console->history_index;
1206 release_object( console );
1209 /* get a console mode (input or output) */
1210 DECL_HANDLER(get_console_mode)
1212 reply->mode = get_console_mode( req->handle );
1215 /* set a console mode (input or output) */
1216 DECL_HANDLER(set_console_mode)
1218 set_console_mode( req->handle, req->mode );
1221 /* add input records to a console input queue */
1222 DECL_HANDLER(write_console_input)
1224 struct console_input *console;
1226 reply->written = 0;
1227 if (!(console = (struct console_input *)get_handle_obj( current->process, req->handle,
1228 GENERIC_WRITE, &console_input_ops )))
1229 return;
1230 reply->written = write_console_input( console, get_req_data_size() / sizeof(INPUT_RECORD),
1231 get_req_data() );
1232 release_object( console );
1235 /* fetch input records from a console input queue */
1236 DECL_HANDLER(read_console_input)
1238 int count = get_reply_max_size() / sizeof(INPUT_RECORD);
1239 reply->read = read_console_input( req->handle, count, req->flush );
1242 /* appends a string to console's history */
1243 DECL_HANDLER(append_console_input_history)
1245 struct console_input *console;
1247 if (!(console = console_input_get( req->handle, GENERIC_WRITE ))) return;
1248 console_input_append_hist( console, get_req_data(), get_req_data_size() / sizeof(WCHAR) );
1249 release_object( console );
1252 /* appends a string to console's history */
1253 DECL_HANDLER(get_console_input_history)
1255 struct console_input *console;
1257 if (!(console = console_input_get( req->handle, GENERIC_WRITE ))) return;
1258 reply->total = console_input_get_hist( console, req->index );
1259 release_object( console );
1262 /* creates a screen buffer */
1263 DECL_HANDLER(create_console_output)
1265 struct console_input* console;
1266 struct screen_buffer* screen_buffer;
1268 if (!(console = console_input_get( req->handle_in, GENERIC_WRITE))) return;
1270 screen_buffer = create_console_output( console );
1271 if (screen_buffer)
1273 /* FIXME: should store sharing and test it when opening the CONOUT$ device
1274 * see file.c on how this could be done */
1275 reply->handle_out = alloc_handle( current->process, screen_buffer,
1276 req->access, req->inherit );
1277 release_object( screen_buffer );
1279 release_object( console );
1282 /* set info about a console screen buffer */
1283 DECL_HANDLER(set_console_output_info)
1285 struct screen_buffer *screen_buffer;
1287 if ((screen_buffer = (struct screen_buffer*)get_handle_obj( current->process, req->handle,
1288 GENERIC_WRITE, &screen_buffer_ops)))
1290 set_console_output_info( screen_buffer, req );
1291 release_object( screen_buffer );
1295 /* get info about a console screen buffer */
1296 DECL_HANDLER(get_console_output_info)
1298 struct screen_buffer *screen_buffer;
1300 if ((screen_buffer = (struct screen_buffer *)get_handle_obj( current->process, req->handle,
1301 GENERIC_READ, &screen_buffer_ops)))
1303 reply->cursor_size = screen_buffer->cursor_size;
1304 reply->cursor_visible = screen_buffer->cursor_visible;
1305 reply->cursor_x = screen_buffer->cursor_x;
1306 reply->cursor_y = screen_buffer->cursor_y;
1307 reply->width = screen_buffer->width;
1308 reply->height = screen_buffer->height;
1309 reply->attr = screen_buffer->attr;
1310 reply->win_left = screen_buffer->win.left;
1311 reply->win_top = screen_buffer->win.top;
1312 reply->win_right = screen_buffer->win.right;
1313 reply->win_bottom = screen_buffer->win.bottom;
1314 reply->max_width = screen_buffer->max_width;
1315 reply->max_height = screen_buffer->max_height;
1316 release_object( screen_buffer );
1320 /* read data (chars & attrs) from a screen buffer */
1321 DECL_HANDLER(read_console_output)
1323 struct screen_buffer *screen_buffer;
1325 if ((screen_buffer = (struct screen_buffer*)get_handle_obj( current->process, req->handle,
1326 GENERIC_READ, &screen_buffer_ops )))
1328 read_console_output( screen_buffer, req->x, req->y, req->mode, req->wrap );
1329 reply->width = screen_buffer->width;
1330 reply->height = screen_buffer->height;
1331 release_object( screen_buffer );
1335 /* write data (char and/or attrs) to a screen buffer */
1336 DECL_HANDLER(write_console_output)
1338 struct screen_buffer *screen_buffer;
1340 if ((screen_buffer = (struct screen_buffer*)get_handle_obj( current->process, req->handle,
1341 GENERIC_WRITE, &screen_buffer_ops)))
1343 reply->written = write_console_output( screen_buffer, get_req_data_size(), get_req_data(),
1344 req->mode, req->x, req->y, req->wrap );
1345 reply->width = screen_buffer->width;
1346 reply->height = screen_buffer->height;
1347 release_object( screen_buffer );
1351 /* fill a screen buffer with constant data (chars and/or attributes) */
1352 DECL_HANDLER(fill_console_output)
1354 struct screen_buffer *screen_buffer;
1356 if ((screen_buffer = (struct screen_buffer*)get_handle_obj( current->process, req->handle,
1357 GENERIC_WRITE, &screen_buffer_ops)))
1359 reply->written = fill_console_output( screen_buffer, req->data, req->mode,
1360 req->x, req->y, req->count, req->wrap );
1361 release_object( screen_buffer );
1365 /* move a rect of data in a screen buffer */
1366 DECL_HANDLER(move_console_output)
1368 scroll_console_output( req->handle, req->x_src, req->y_src, req->x_dst, req->y_dst,
1369 req->w, req->h );