Fixed read-overflow spotted by valgrind.
[wine] / server / console.c
1 /*
2  * Server-side console management
3  *
4  * Copyright (C) 1998 Alexandre Julliard
5  *               2001 Eric Pouech
6  *
7  *
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.
12  *
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.
17  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <assert.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <signal.h>
31
32 #include "handle.h"
33 #include "process.h"
34 #include "request.h"
35 #include "unicode.h"
36 #include "console.h"
37
38
39 static void console_input_dump( struct object *obj, int verbose );
40 static void console_input_destroy( struct object *obj );
41 static int console_input_signaled( struct object *obj, struct thread *thread );
42
43 static const struct object_ops console_input_ops =
44 {
45     sizeof(struct console_input),     /* size */
46     console_input_dump,               /* dump */
47     add_queue,                        /* add_queue */
48     remove_queue,                     /* remove_queue */
49     console_input_signaled,           /* signaled */
50     no_satisfied,                     /* satisfied */
51     no_get_fd,                        /* get_fd */
52     console_input_destroy             /* destroy */
53 };
54
55 static void console_input_events_dump( struct object *obj, int verbose );
56 static void console_input_events_destroy( struct object *obj );
57 static int  console_input_events_signaled( struct object *obj, struct thread *thread );
58
59 struct console_input_events
60 {
61     struct object         obj;         /* object header */
62     int                   num_alloc;   /* number of allocated events */
63     int                   num_used;    /* number of actually used events */
64     struct console_renderer_event*      events;
65 };
66
67 static const struct object_ops console_input_events_ops =
68 {
69     sizeof(struct console_input_events), /* size */
70     console_input_events_dump,        /* dump */
71     add_queue,                        /* add_queue */
72     remove_queue,                     /* remove_queue */
73     console_input_events_signaled,    /* signaled */
74     no_satisfied,                     /* satisfied */
75     no_get_fd,                        /* get_fd */
76     console_input_events_destroy      /* destroy */
77 };
78
79 struct screen_buffer
80 {
81     struct object         obj;           /* object header */
82     struct screen_buffer *next;          /* linked list of all screen buffers */
83     struct screen_buffer *prev;
84     struct console_input *input;         /* associated console input */
85     int                   mode;          /* output mode */
86     int                   cursor_size;   /* size of cursor (percentage filled) */
87     int                   cursor_visible;/* cursor visibility flag */
88     int                   cursor_x;      /* position of cursor */
89     int                   cursor_y;      /* position of cursor */
90     int                   width;         /* size (w-h) of the screen buffer */
91     int                   height;
92     int                   max_width;     /* size (w-h) of the window given font size */
93     int                   max_height;
94     char_info_t          *data;          /* the data for each cell - a width x height matrix */
95     unsigned short        attr;          /* default attribute for screen buffer */
96     rectangle_t           win;           /* current visible window on the screen buffer *
97                                           * as seen in wineconsole */
98 };
99
100 static void screen_buffer_dump( struct object *obj, int verbose );
101 static void screen_buffer_destroy( struct object *obj );
102
103 static const struct object_ops screen_buffer_ops =
104 {
105     sizeof(struct screen_buffer),     /* size */
106     screen_buffer_dump,               /* dump */
107     no_add_queue,                     /* add_queue */
108     NULL,                             /* remove_queue */
109     NULL,                             /* signaled */
110     NULL,                             /* satisfied */
111     no_get_fd,                        /* get_fd */
112     screen_buffer_destroy             /* destroy */
113 };
114
115 static struct screen_buffer *screen_buffer_list;
116
117 static const char_info_t empty_char_info = { ' ', 0x000f };  /* white on black space */
118
119 /* dumps the renderer events of a console */
120 static void console_input_events_dump( struct object *obj, int verbose )
121 {
122     struct console_input_events *evts = (struct console_input_events *)obj;
123     assert( obj->ops == &console_input_events_ops );
124     fprintf( stderr, "Console input events: %d/%d events\n",
125              evts->num_used, evts->num_alloc );
126 }
127
128 /* destroys the renderer events of a console */
129 static void console_input_events_destroy( struct object *obj )
130 {
131     struct console_input_events *evts = (struct console_input_events *)obj;
132     assert( obj->ops == &console_input_events_ops );
133     free( evts->events );
134 }
135
136 /* the renderer events list is signaled when it's not empty */
137 static int console_input_events_signaled( struct object *obj, struct thread *thread )
138 {
139     struct console_input_events *evts = (struct console_input_events *)obj;
140     assert( obj->ops == &console_input_events_ops );
141     return (evts->num_used != 0);
142 }
143
144 /* add an event to the console's renderer events list */
145 static void console_input_events_append( struct console_input_events* evts,
146                                          struct console_renderer_event* evt)
147 {
148     int collapsed = FALSE;
149
150     /* to be done even when evt has been generated by the rendere ? */
151
152     /* try to collapse evt into current queue's events */
153     if (evts->num_used)
154     {
155         struct console_renderer_event* last = &evts->events[evts->num_used - 1];
156
157         if (last->event == CONSOLE_RENDERER_UPDATE_EVENT &&
158             evt->event == CONSOLE_RENDERER_UPDATE_EVENT)
159         {
160             /* if two update events overlap, collapse them into a single one */
161             if (last->u.update.bottom + 1 >= evt->u.update.top &&
162                 evt->u.update.bottom + 1 >= last->u.update.top)
163             {
164                 last->u.update.top = min(last->u.update.top, evt->u.update.top);
165                 last->u.update.bottom = max(last->u.update.bottom, evt->u.update.bottom);
166                 collapsed = TRUE;
167             }
168         }
169     }
170     if (!collapsed)
171     {
172         if (evts->num_used == evts->num_alloc)
173         {
174             evts->num_alloc += 16;
175             evts->events = realloc( evts->events, evts->num_alloc * sizeof(*evt) );
176             assert(evts->events);
177         }
178         evts->events[evts->num_used++] = *evt;
179     }
180     wake_up( &evts->obj, 0 );
181 }
182
183 /* retrieves events from the console's renderer events list */
184 static void console_input_events_get( struct console_input_events* evts )
185 {
186     size_t num = get_reply_max_size() / sizeof(evts->events[0]);
187
188     if (num > evts->num_used) num = evts->num_used;
189     set_reply_data( evts->events, num * sizeof(evts->events[0]) );
190     if (num < evts->num_used)
191     {
192         memmove( &evts->events[0], &evts->events[num],
193                  (evts->num_used - num) * sizeof(evts->events[0]) );
194     }
195     evts->num_used -= num;
196 }
197
198 static struct console_input_events *create_console_input_events(void)
199 {
200     struct console_input_events*        evt;
201
202     if (!(evt = alloc_object( &console_input_events_ops ))) return NULL;
203     evt->num_alloc = evt->num_used = 0;
204     evt->events = NULL;
205     return evt;
206 }
207
208 static struct object *create_console_input( struct thread* renderer )
209 {
210     struct console_input *console_input;
211
212     if (!(console_input = alloc_object( &console_input_ops ))) return NULL;
213     console_input->renderer      = renderer;
214     console_input->mode          = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
215                                    ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
216     console_input->num_proc      = 0;
217     console_input->active        = NULL;
218     console_input->recnum        = 0;
219     console_input->records       = NULL;
220     console_input->evt           = create_console_input_events();
221     console_input->title         = NULL;
222     console_input->history_size  = 50;
223     console_input->history       = calloc( console_input->history_size, sizeof(WCHAR*) );
224     console_input->history_index = 0;
225     console_input->history_mode  = 0;
226     console_input->edition_mode  = 0;
227
228     if (!console_input->history || !console_input->evt)
229     {
230         release_object( console_input );
231         return NULL;
232     }
233     return &console_input->obj;
234 }
235
236 static struct screen_buffer *create_console_output( struct console_input *console_input )
237 {
238     struct screen_buffer *screen_buffer;
239     struct console_renderer_event evt;
240     int i;
241
242     if (!(screen_buffer = alloc_object( &screen_buffer_ops ))) return NULL;
243     screen_buffer->mode           = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
244     screen_buffer->input          = console_input;
245     screen_buffer->cursor_size    = 100;
246     screen_buffer->cursor_visible = 1;
247     screen_buffer->width          = 80;
248     screen_buffer->height         = 150;
249     screen_buffer->max_width      = 80;
250     screen_buffer->max_height     = 25;
251     screen_buffer->cursor_x       = 0;
252     screen_buffer->cursor_y       = 0;
253     screen_buffer->attr           = 0x0F;
254     screen_buffer->win.left       = 0;
255     screen_buffer->win.right      = screen_buffer->max_width - 1;
256     screen_buffer->win.top        = 0;
257     screen_buffer->win.bottom     = screen_buffer->max_height - 1;
258
259     if ((screen_buffer->next = screen_buffer_list)) screen_buffer->next->prev = screen_buffer;
260     screen_buffer->prev = NULL;
261     screen_buffer_list = screen_buffer;
262
263     if (!(screen_buffer->data = malloc( screen_buffer->width * screen_buffer->height *
264                                         sizeof(*screen_buffer->data) )))
265     {
266         release_object( screen_buffer );
267         return NULL;
268     }
269     /* clear the first row */
270     for (i = 0; i < screen_buffer->width; i++) screen_buffer->data[i] = empty_char_info;
271     /* and copy it to all other rows */
272     for (i = 1; i < screen_buffer->height; i++)
273         memcpy( &screen_buffer->data[i * screen_buffer->width], screen_buffer->data,
274                 screen_buffer->width * sizeof(char_info_t) );
275
276     if (!console_input->active)
277     {
278         console_input->active = (struct screen_buffer*)grab_object( screen_buffer );
279
280         /* generate the initial events */
281         evt.event = CONSOLE_RENDERER_ACTIVE_SB_EVENT;
282         console_input_events_append( console_input->evt, &evt );
283
284         evt.event = CONSOLE_RENDERER_SB_RESIZE_EVENT;
285         evt.u.resize.width  = screen_buffer->width;
286         evt.u.resize.height = screen_buffer->height;
287         console_input_events_append( console_input->evt, &evt );
288
289         evt.event = CONSOLE_RENDERER_DISPLAY_EVENT;
290         evt.u.display.left   = screen_buffer->win.left;
291         evt.u.display.top    = screen_buffer->win.top;
292         evt.u.display.width  = screen_buffer->win.right - screen_buffer->win.left + 1;
293         evt.u.display.height = screen_buffer->win.bottom - screen_buffer->win.top + 1;
294         console_input_events_append( console_input->evt, &evt );
295
296         evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
297         evt.u.update.top    = 0;
298         evt.u.update.bottom = screen_buffer->height - 1;
299         console_input_events_append( console_input->evt, &evt );
300
301         evt.event = CONSOLE_RENDERER_CURSOR_GEOM_EVENT;
302         evt.u.cursor_geom.size    = screen_buffer->cursor_size;
303         evt.u.cursor_geom.visible = screen_buffer->cursor_visible;
304         console_input_events_append( console_input->evt, &evt );
305
306         evt.event = CONSOLE_RENDERER_CURSOR_POS_EVENT;
307         evt.u.cursor_pos.x = screen_buffer->cursor_x;
308         evt.u.cursor_pos.y = screen_buffer->cursor_y;
309         console_input_events_append( console_input->evt, &evt );
310     }
311     return screen_buffer;
312 }
313
314 /* free the console for this process */
315 int free_console( struct process *process )
316 {
317     struct console_input* console = process->console;
318
319     if (!console || !console->renderer) return 0;
320
321     process->console = NULL;
322     if (--console->num_proc == 0)
323     {
324         /* all processes have terminated... tell the renderer to terminate too */
325         struct console_renderer_event evt;
326         evt.event = CONSOLE_RENDERER_EXIT_EVENT;
327         console_input_events_append( console->evt, &evt );
328     }
329     release_object( console );
330
331     return 1;
332 }
333
334 /* let process inherit the console from parent... this handle two cases :
335  *      1/ generic console inheritance
336  *      2/ parent is a renderer which launches process, and process should attach to the console
337  *         renderered by parent
338  */
339 void inherit_console(struct thread *parent_thread, struct process *process, obj_handle_t hconin)
340 {
341     int done = 0;
342     struct process* parent = parent_thread->process;
343
344     /* if parent is a renderer, then attach current process to its console
345      * a bit hacky....
346      */
347     if (hconin)
348     {
349         struct console_input* console;
350
351         if ((console = (struct console_input*)get_handle_obj( parent, hconin, 0, NULL )))
352         {
353             if (console->renderer == parent_thread)
354             {
355                 process->console = (struct console_input*)grab_object( console );
356                 process->console->num_proc++;
357                 done = 1;
358             }
359             release_object( console );
360         }
361     }
362     /* otherwise, if parent has a console, attach child to this console */
363     if (!done && parent->console)
364     {
365         assert(parent->console->renderer);
366         process->console = (struct console_input*)grab_object( parent->console );
367         process->console->num_proc++;
368     }
369 }
370
371 int is_console_object( struct object *obj )
372 {
373     return (obj->ops == &console_input_ops || obj->ops == &screen_buffer_ops);
374 }
375
376 static struct console_input* console_input_get( obj_handle_t handle, unsigned access )
377 {
378     struct console_input*       console = 0;
379
380     if (handle)
381         console = (struct console_input *)get_handle_obj( current->process, handle,
382                                                           access, &console_input_ops );
383     else if (current->process->console)
384     {
385         assert( current->process->console->renderer );
386         console = (struct console_input *)grab_object( current->process->console );
387     }
388
389     if (!console && !get_error()) set_error(STATUS_INVALID_PARAMETER);
390     return console;
391 }
392
393 /* check if a console input is signaled: yes if non read input records */
394 static int console_input_signaled( struct object *obj, struct thread *thread )
395 {
396     struct console_input *console = (struct console_input *)obj;
397     assert( obj->ops == &console_input_ops );
398     return console->recnum ? 1 : 0;
399 }
400
401 struct console_signal_info {
402     struct console_input        *console;
403     process_id_t                 group;
404     int                          signal;
405 };
406
407 static int propagate_console_signal_cb(struct process *process, void *user)
408 {
409     struct console_signal_info* csi = (struct console_signal_info*)user;
410
411     if (process->console == csi->console && process->running_threads &&
412         (!csi->group || process->group_id == csi->group))
413     {
414         struct thread *thread = process->thread_list;
415
416         while (thread)
417         {
418             struct thread *next = thread->proc_next;
419             kill( thread->unix_pid, csi->signal );
420             thread = next;
421         }
422     }
423     return FALSE;
424 }
425
426 static void propagate_console_signal( struct console_input *console,
427                                       int sig, process_id_t group_id )
428 {
429     struct console_signal_info csi;
430
431     if (!console)
432     {
433         set_error( STATUS_INVALID_PARAMETER );
434         return;
435     }
436     /* FIXME: should support the other events (like CTRL_BREAK) */
437     if (sig != CTRL_C_EVENT)
438     {
439         set_error( STATUS_NOT_IMPLEMENTED );
440         return;
441     }
442     csi.console = console;
443     csi.signal  = SIGINT;
444     csi.group   = group_id;
445
446     enum_processes(propagate_console_signal_cb, &csi);
447 }
448
449 static int get_console_mode( obj_handle_t handle )
450 {
451     struct object *obj;
452     int ret = 0;
453
454     if ((obj = get_handle_obj( current->process, handle, GENERIC_READ, NULL )))
455     {
456         if (obj->ops == &console_input_ops)
457             ret = ((struct console_input *)obj)->mode;
458         else if (obj->ops == &screen_buffer_ops)
459             ret = ((struct screen_buffer *)obj)->mode;
460         else
461             set_error( STATUS_OBJECT_TYPE_MISMATCH );
462         release_object( obj );
463     }
464     return ret;
465 }
466
467 /* changes the mode of either a console input or a screen buffer */
468 static int set_console_mode( obj_handle_t handle, int mode )
469 {
470     struct object *obj;
471     int ret = 0;
472
473     if (!(obj = get_handle_obj( current->process, handle, GENERIC_WRITE, NULL )))
474         return 0;
475     if (obj->ops == &console_input_ops)
476     {
477         /* FIXME: if we remove the edit mode bits, we need (???) to clean up the history */
478         ((struct console_input *)obj)->mode = mode;
479         ret = 1;
480     }
481     else if (obj->ops == &screen_buffer_ops)
482     {
483         ((struct screen_buffer *)obj)->mode = mode;
484         ret = 1;
485     }
486     else set_error( STATUS_OBJECT_TYPE_MISMATCH );
487     release_object( obj );
488     return ret;
489 }
490
491 /* add input events to a console input queue */
492 static int write_console_input( struct console_input* console, int count,
493                                 const INPUT_RECORD *records )
494 {
495     INPUT_RECORD *new_rec;
496
497     if (!count) return 0;
498     if (!(new_rec = realloc( console->records,
499                              (console->recnum + count) * sizeof(INPUT_RECORD) )))
500     {
501         set_error( STATUS_NO_MEMORY );
502         release_object( console );
503         return -1;
504     }
505     console->records = new_rec;
506     memcpy( new_rec + console->recnum, records, count * sizeof(INPUT_RECORD) );
507
508     if (console->mode & ENABLE_PROCESSED_INPUT)
509     {
510         int i = 0;
511         while (i < count)
512         {
513             if (records[i].EventType == KEY_EVENT &&
514                 records[i].Event.KeyEvent.uChar.UnicodeChar == 'C' - 64 &&
515                 !(records[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY))
516             {
517                 if (i != count - 1)
518                     memcpy( &console->records[console->recnum + i],
519                             &console->records[console->recnum + i + 1],
520                             (count - i - 1) * sizeof(INPUT_RECORD) );
521                 count--;
522                 if (records[i].Event.KeyEvent.bKeyDown)
523                 {
524                     /* send SIGINT to all processes attached to this console */
525                     propagate_console_signal( console, CTRL_C_EVENT, 0 );
526                 }
527             }
528             else i++;
529         }
530     }
531     console->recnum += count;
532     /* wake up all waiters */
533     wake_up( &console->obj, 0 );
534     return count;
535 }
536
537 /* retrieve a pointer to the console input records */
538 static int read_console_input( obj_handle_t handle, int count, int flush )
539 {
540     struct console_input *console;
541
542     if (!(console = (struct console_input *)get_handle_obj( current->process, handle,
543                                                             GENERIC_READ, &console_input_ops )))
544         return -1;
545
546     if (!count)
547     {
548         /* special case: do not retrieve anything, but return
549          * the total number of records available */
550         count = console->recnum;
551     }
552     else
553     {
554         if (count > console->recnum) count = console->recnum;
555         set_reply_data( console->records, count * sizeof(INPUT_RECORD) );
556     }
557     if (flush)
558     {
559         int i;
560         for (i = count; i < console->recnum; i++)
561             console->records[i-count] = console->records[i];
562         if ((console->recnum -= count) > 0)
563         {
564             INPUT_RECORD *new_rec = realloc( console->records,
565                                              console->recnum * sizeof(INPUT_RECORD) );
566             if (new_rec) console->records = new_rec;
567         }
568         else
569         {
570             free( console->records );
571             console->records = NULL;
572         }
573     }
574     release_object( console );
575     return count;
576 }
577
578 /* set misc console input information */
579 static int set_console_input_info( const struct set_console_input_info_request *req,
580                                    const WCHAR *title, size_t len )
581 {
582     struct console_input *console;
583     struct console_renderer_event evt;
584
585     if (!(console = console_input_get( req->handle, GENERIC_WRITE ))) goto error;
586
587     if (req->mask & SET_CONSOLE_INPUT_INFO_ACTIVE_SB)
588     {
589         struct screen_buffer *screen_buffer;
590
591         screen_buffer = (struct screen_buffer *)get_handle_obj( current->process, req->active_sb,
592                                                                 GENERIC_READ, &screen_buffer_ops );
593         if (!screen_buffer || screen_buffer->input != console)
594         {
595             set_error( STATUS_INVALID_PARAMETER );
596             if (screen_buffer) release_object( screen_buffer );
597             goto error;
598         }
599
600         if (screen_buffer != console->active)
601         {
602             if (console->active) release_object( console->active );
603             console->active = screen_buffer;
604             evt.event = CONSOLE_RENDERER_ACTIVE_SB_EVENT;
605             console_input_events_append( console->evt, &evt );
606         }
607         else
608             release_object( screen_buffer );
609     }
610     if (req->mask & SET_CONSOLE_INPUT_INFO_TITLE)
611     {
612         WCHAR *new_title = mem_alloc( len + sizeof(WCHAR) );
613         if (new_title)
614         {
615             memcpy( new_title, title, len );
616             new_title[len / sizeof(WCHAR)] = 0;
617             if (console->title) free( console->title );
618             console->title = new_title;
619             evt.event = CONSOLE_RENDERER_TITLE_EVENT;
620             console_input_events_append( console->evt, &evt );
621         }
622     }
623     if (req->mask & SET_CONSOLE_INPUT_INFO_HISTORY_MODE)
624     {
625         console->history_mode = req->history_mode;
626     }
627     if ((req->mask & SET_CONSOLE_INPUT_INFO_HISTORY_SIZE) &&
628         console->history_size != req->history_size)
629     {
630         WCHAR** mem = NULL;
631         int     i;
632         int     delta;
633
634         if (req->history_size)
635         {
636             mem = mem_alloc( req->history_size * sizeof(WCHAR*) );
637             if (!mem) goto error;
638             memset( mem, 0, req->history_size * sizeof(WCHAR*) );
639         }
640
641         delta = (console->history_index > req->history_size) ?
642             (console->history_index - req->history_size) : 0;
643
644         for (i = delta; i < console->history_index; i++)
645         {
646             mem[i - delta] = console->history[i];
647             console->history[i] = NULL;
648         }
649         console->history_index -= delta;
650
651         for (i = 0; i < console->history_size; i++)
652             if (console->history[i]) free( console->history[i] );
653         free( console->history );
654         console->history = mem;
655         console->history_size = req->history_size;
656     }
657     if (req->mask & SET_CONSOLE_INPUT_INFO_EDITION_MODE)
658     {
659         console->edition_mode = req->edition_mode;
660     }
661     release_object( console );
662     return 1;
663  error:
664     if (console) release_object( console );
665     return 0;
666 }
667
668 /* resize a screen buffer */
669 static int change_screen_buffer_size( struct screen_buffer *screen_buffer,
670                                       int new_width, int new_height )
671 {
672     int i, old_width, old_height, copy_width, copy_height;
673     char_info_t *new_data;
674
675     if (!(new_data = malloc( new_width * new_height * sizeof(*new_data) )))
676     {
677         set_error( STATUS_NO_MEMORY );
678         return 0;
679     }
680     old_width = screen_buffer->width;
681     old_height = screen_buffer->height;
682     copy_width = min( old_width, new_width );
683     copy_height = min( old_height, new_height );
684
685     /* copy all the rows */
686     for (i = 0; i < copy_height; i++)
687     {
688         memcpy( &new_data[i * new_width], &screen_buffer->data[i * old_width],
689                 copy_width * sizeof(char_info_t) );
690     }
691
692     /* clear the end of each row */
693     if (new_width > old_width)
694     {
695         /* fill first row */
696         for (i = old_width; i < new_width; i++) new_data[i] = empty_char_info;
697         /* and blast it to the other rows */
698         for (i = 1; i < copy_height; i++)
699             memcpy( &new_data[i * new_width + old_width], &new_data[old_width],
700                     (new_width - old_width) * sizeof(char_info_t) );
701     }
702
703     /* clear remaining rows */
704     if (new_height > old_height)
705     {
706         /* fill first row */
707         for (i = 0; i < new_width; i++) new_data[old_height * new_width + i] = empty_char_info;
708         /* and blast it to the other rows */
709         for (i = old_height+1; i < new_height; i++)
710             memcpy( &new_data[i * new_width], &new_data[old_height * new_width],
711                     new_width * sizeof(char_info_t) );
712     }
713     free( screen_buffer->data );
714     screen_buffer->data = new_data;
715     screen_buffer->width = new_width;
716     screen_buffer->height = new_height;
717     return 1;
718 }
719
720 /* set misc screen buffer information */
721 static int set_console_output_info( struct screen_buffer *screen_buffer,
722                                     const struct set_console_output_info_request *req )
723 {
724     struct console_renderer_event evt;
725
726     if (req->mask & SET_CONSOLE_OUTPUT_INFO_CURSOR_GEOM)
727     {
728         if (req->cursor_size < 1 || req->cursor_size > 100)
729         {
730             set_error( STATUS_INVALID_PARAMETER );
731             return 0;
732         }
733         if (screen_buffer->cursor_size != req->cursor_size ||
734             screen_buffer->cursor_visible != req->cursor_visible)
735         {
736             screen_buffer->cursor_size    = req->cursor_size;
737             screen_buffer->cursor_visible = req->cursor_visible;
738             evt.event = CONSOLE_RENDERER_CURSOR_GEOM_EVENT;
739             evt.u.cursor_geom.size    = req->cursor_size;
740             evt.u.cursor_geom.visible = req->cursor_visible;
741             console_input_events_append( screen_buffer->input->evt, &evt );
742         }
743     }
744     if (req->mask & SET_CONSOLE_OUTPUT_INFO_CURSOR_POS)
745     {
746         if (req->cursor_x < 0 || req->cursor_x >= screen_buffer->width ||
747             req->cursor_y < 0 || req->cursor_y >= screen_buffer->height)
748         {
749             set_error( STATUS_INVALID_PARAMETER );
750             return 0;
751         }
752         if (screen_buffer->cursor_x != req->cursor_x || screen_buffer->cursor_y != req->cursor_y)
753         {
754             screen_buffer->cursor_x       = req->cursor_x;
755             screen_buffer->cursor_y       = req->cursor_y;
756             evt.event = CONSOLE_RENDERER_CURSOR_POS_EVENT;
757             evt.u.cursor_pos.x = req->cursor_x;
758             evt.u.cursor_pos.y = req->cursor_y;
759             console_input_events_append( screen_buffer->input->evt, &evt );
760         }
761     }
762     if (req->mask & SET_CONSOLE_OUTPUT_INFO_SIZE)
763     {
764         unsigned cc;
765
766         /* new screen-buffer cannot be smaller than actual window */
767         if (req->width < screen_buffer->win.right - screen_buffer->win.left + 1 ||
768             req->height < screen_buffer->win.bottom - screen_buffer->win.top + 1)
769         {
770             set_error( STATUS_INVALID_PARAMETER );
771             return 0;
772         }
773         /* FIXME: there are also some basic minimum and max size to deal with */
774         if (!change_screen_buffer_size( screen_buffer, req->width, req->height )) return 0;
775
776         evt.event = CONSOLE_RENDERER_SB_RESIZE_EVENT;
777         evt.u.resize.width  = req->width;
778         evt.u.resize.height = req->height;
779         console_input_events_append( screen_buffer->input->evt, &evt );
780
781         evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
782         evt.u.update.top    = 0;
783         evt.u.update.bottom = screen_buffer->height - 1;
784         console_input_events_append( screen_buffer->input->evt, &evt );
785
786         /* scroll window to display sb */
787         if (screen_buffer->win.right >= req->width)
788         {       
789             screen_buffer->win.right -= screen_buffer->win.left;
790             screen_buffer->win.left = 0;
791         }
792         if (screen_buffer->win.bottom >= req->height)
793         {       
794             screen_buffer->win.bottom -= screen_buffer->win.top;
795             screen_buffer->win.top = 0;
796         }
797         /* reset cursor if needed (normally, if cursor was outside of new sb, the
798          * window has been shifted so that the new position of the cursor will be 
799          * visible */
800         cc = 0;
801         if (screen_buffer->cursor_x >= req->width)
802         {
803             screen_buffer->cursor_x = req->width - 1;
804             cc++;
805         }
806         if (screen_buffer->cursor_y >= req->height)
807         {
808             screen_buffer->cursor_y = req->height - 1;
809             cc++;
810         }
811         if (cc)
812         {
813             evt.event = CONSOLE_RENDERER_CURSOR_POS_EVENT;
814             evt.u.cursor_pos.x = req->cursor_x;
815             evt.u.cursor_pos.y = req->cursor_y;
816             console_input_events_append( screen_buffer->input->evt, &evt );
817         }
818
819         if (screen_buffer == screen_buffer->input->active &&
820             screen_buffer->input->mode & ENABLE_WINDOW_INPUT)
821         {
822             INPUT_RECORD        ir;
823             ir.EventType = WINDOW_BUFFER_SIZE_EVENT;
824             ir.Event.WindowBufferSizeEvent.dwSize.X = req->width;
825             ir.Event.WindowBufferSizeEvent.dwSize.Y = req->height;
826             write_console_input( screen_buffer->input, 1, &ir );
827         }
828     }
829     if (req->mask & SET_CONSOLE_OUTPUT_INFO_ATTR)
830     {
831         screen_buffer->attr = req->attr;
832     }
833     if (req->mask & SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW)
834     {
835         if (req->win_left < 0 || req->win_left > req->win_right ||
836             req->win_right >= screen_buffer->width ||
837             req->win_top < 0  || req->win_top > req->win_bottom ||
838             req->win_bottom >= screen_buffer->height)
839         {
840             set_error( STATUS_INVALID_PARAMETER );
841             return 0;
842         }
843         if (screen_buffer->win.left != req->win_left || screen_buffer->win.top != req->win_top ||
844             screen_buffer->win.right != req->win_right || screen_buffer->win.bottom != req->win_bottom)
845         {
846             screen_buffer->win.left   = req->win_left;
847             screen_buffer->win.top    = req->win_top;
848             screen_buffer->win.right  = req->win_right;
849             screen_buffer->win.bottom = req->win_bottom;
850             evt.event = CONSOLE_RENDERER_DISPLAY_EVENT;
851             evt.u.display.left   = req->win_left;
852             evt.u.display.top    = req->win_top;
853             evt.u.display.width  = req->win_right - req->win_left + 1;
854             evt.u.display.height = req->win_bottom - req->win_top + 1;
855             console_input_events_append( screen_buffer->input->evt, &evt );
856         }
857     }
858     if (req->mask & SET_CONSOLE_OUTPUT_INFO_MAX_SIZE)
859     {
860         /* can only be done by renderer */
861         if (current->process->console != screen_buffer->input)
862         {
863             set_error( STATUS_INVALID_PARAMETER );
864             return 0;
865         }
866
867         screen_buffer->max_width  = req->max_width;
868         screen_buffer->max_height = req->max_height;
869     }
870
871     return 1;
872 }
873
874 /* appends a new line to history (history is a fixed size array) */
875 static void console_input_append_hist( struct console_input* console, const WCHAR* buf, size_t len )
876 {
877     WCHAR*      ptr = mem_alloc( (len + 1) * sizeof(WCHAR) );
878
879     if (!ptr)
880     {
881         set_error( STATUS_NO_MEMORY );
882         return;
883     }
884     if (!console || !console->history_size)
885     {
886         set_error( STATUS_INVALID_PARAMETER ); /* FIXME */
887         return;
888     }
889
890     memcpy( ptr, buf, len * sizeof(WCHAR) );
891     ptr[len] = 0;
892
893     if (console->history_mode && console->history_index &&
894         strncmpW( console->history[console->history_index - 1], ptr, len * sizeof(WCHAR) ) == 0)
895     {
896         /* ok, mode ask us to not use twice the same string...
897          * so just free mem and returns
898          */
899         set_error( STATUS_ALIAS_EXISTS );
900         free(ptr);
901         return;
902     }
903
904     if (console->history_index < console->history_size)
905     {
906         console->history[console->history_index++] = ptr;
907     }
908     else
909     {
910         free( console->history[0]) ;
911         memmove( &console->history[0], &console->history[1],
912                  (console->history_size - 1) * sizeof(WCHAR*) );
913         console->history[console->history_size - 1] = ptr;
914     }
915 }
916
917 /* returns a line from the cache */
918 static size_t console_input_get_hist( struct console_input *console, int index )
919 {
920     size_t ret = 0;
921
922     if (index >= console->history_index) set_error( STATUS_INVALID_PARAMETER );
923     else
924     {
925         ret = strlenW( console->history[index] ) * sizeof(WCHAR);
926         set_reply_data( console->history[index], min( ret, get_reply_max_size() ));
927     }
928     return ret;
929 }
930
931 /* dumb dump */
932 static void console_input_dump( struct object *obj, int verbose )
933 {
934     struct console_input *console = (struct console_input *)obj;
935     assert( obj->ops == &console_input_ops );
936     fprintf( stderr, "Console input active=%p evt=%p\n",
937              console->active, console->evt );
938 }
939
940 static void console_input_destroy( struct object *obj )
941 {
942     struct console_input*       console_in = (struct console_input *)obj;
943     struct screen_buffer*       curr;
944     int                         i;
945
946     assert( obj->ops == &console_input_ops );
947     if (console_in->title) free( console_in->title );
948     if (console_in->records) free( console_in->records );
949
950     if (console_in->active)     release_object( console_in->active );
951     console_in->active = NULL;
952
953     for (curr = screen_buffer_list; curr; curr = curr->next)
954     {
955         if (curr->input == console_in) curr->input = NULL;
956     }
957
958     release_object( console_in->evt );
959     console_in->evt = NULL;
960
961     for (i = 0; i < console_in->history_size; i++)
962         if (console_in->history[i]) free( console_in->history[i] );
963     if (console_in->history) free( console_in->history );
964 }
965
966 static void screen_buffer_dump( struct object *obj, int verbose )
967 {
968     struct screen_buffer *screen_buffer = (struct screen_buffer *)obj;
969     assert( obj->ops == &screen_buffer_ops );
970
971     fprintf(stderr, "Console screen buffer input=%p\n", screen_buffer->input );
972 }
973
974 static void screen_buffer_destroy( struct object *obj )
975 {
976     struct screen_buffer *screen_buffer = (struct screen_buffer *)obj;
977
978     assert( obj->ops == &screen_buffer_ops );
979
980     if (screen_buffer->next) screen_buffer->next->prev = screen_buffer->prev;
981     if (screen_buffer->prev) screen_buffer->prev->next = screen_buffer->next;
982     else screen_buffer_list = screen_buffer->next;
983
984     if (screen_buffer->input && screen_buffer->input->active == screen_buffer)
985     {
986         struct screen_buffer*   sb;
987         for (sb = screen_buffer_list; sb && sb->input != screen_buffer->input; sb = sb->next);
988         screen_buffer->input->active = sb;
989     }
990     if (screen_buffer->data) free( screen_buffer->data );
991 }
992
993 /* write data into a screen buffer */
994 static int write_console_output( struct screen_buffer *screen_buffer, size_t size,
995                                  const void* data, enum char_info_mode mode,
996                                  int x, int y, int wrap )
997 {
998     int i;
999     char_info_t *end, *dest = screen_buffer->data + y * screen_buffer->width + x;
1000
1001     if (y >= screen_buffer->height) return 0;
1002
1003     if (wrap)
1004         end = screen_buffer->data + screen_buffer->height * screen_buffer->width;
1005     else
1006         end = screen_buffer->data + (y+1) * screen_buffer->width;
1007
1008     switch(mode)
1009     {
1010     case CHAR_INFO_MODE_TEXT:
1011         {
1012             const WCHAR *ptr = data;
1013             for (i = 0; i < size/sizeof(*ptr) && dest < end; dest++, i++) dest->ch = ptr[i];
1014         }
1015         break;
1016     case CHAR_INFO_MODE_ATTR:
1017         {
1018             const unsigned short *ptr = data;
1019             for (i = 0; i < size/sizeof(*ptr) && dest < end; dest++, i++) dest->attr = ptr[i];
1020         }
1021         break;
1022     case CHAR_INFO_MODE_TEXTATTR:
1023         {
1024             const char_info_t *ptr = data;
1025             for (i = 0; i < size/sizeof(*ptr) && dest < end; dest++, i++) *dest = ptr[i];
1026         }
1027         break;
1028     case CHAR_INFO_MODE_TEXTSTDATTR:
1029         {
1030             const WCHAR *ptr = data;
1031             for (i = 0; i < size/sizeof(*ptr) && dest < end; dest++, i++)
1032             {
1033                 dest->ch   = ptr[i];
1034                 dest->attr = screen_buffer->attr;
1035             }
1036         }
1037         break;
1038     default:
1039         set_error( STATUS_INVALID_PARAMETER );
1040         return 0;
1041     }
1042
1043     if (i && screen_buffer == screen_buffer->input->active)
1044     {
1045         struct console_renderer_event evt;
1046         evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
1047         evt.u.update.top    = y + x / screen_buffer->width;
1048         evt.u.update.bottom = y + (x + i - 1) / screen_buffer->width;
1049         console_input_events_append( screen_buffer->input->evt, &evt );
1050     }
1051     return i;
1052 }
1053
1054 /* fill a screen buffer with uniform data */
1055 static int fill_console_output( struct screen_buffer *screen_buffer, char_info_t data,
1056                                 enum char_info_mode mode, int x, int y, int count, int wrap )
1057 {
1058     int i;
1059     char_info_t *end, *dest = screen_buffer->data + y * screen_buffer->width + x;
1060
1061     if (y >= screen_buffer->height) return 0;
1062
1063     if (wrap)
1064         end = screen_buffer->data + screen_buffer->height * screen_buffer->width;
1065     else
1066         end = screen_buffer->data + (y+1) * screen_buffer->width;
1067
1068     if (count > end - dest) count = end - dest;
1069
1070     switch(mode)
1071     {
1072     case CHAR_INFO_MODE_TEXT:
1073         for (i = 0; i < count; i++) dest[i].ch = data.ch;
1074         break;
1075     case CHAR_INFO_MODE_ATTR:
1076         for (i = 0; i < count; i++) dest[i].attr = data.attr;
1077         break;
1078     case CHAR_INFO_MODE_TEXTATTR:
1079         for (i = 0; i < count; i++) dest[i] = data;
1080         break;
1081     case CHAR_INFO_MODE_TEXTSTDATTR:
1082         for (i = 0; i < count; i++)
1083         {
1084             dest[i].ch   = data.ch;
1085             dest[i].attr = screen_buffer->attr;
1086         }
1087         break;
1088     default:
1089         set_error( STATUS_INVALID_PARAMETER );
1090         return 0;
1091     }
1092
1093     if (count && screen_buffer == screen_buffer->input->active)
1094     {
1095         struct console_renderer_event evt;
1096         evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
1097         evt.u.update.top    = y;
1098         evt.u.update.bottom = (y * screen_buffer->width + x + count - 1) / screen_buffer->width;
1099         console_input_events_append( screen_buffer->input->evt, &evt );
1100     }
1101     return i;
1102 }
1103
1104 /* read data from a screen buffer */
1105 static void read_console_output( struct screen_buffer *screen_buffer, int x, int y,
1106                                  enum char_info_mode mode, int wrap )
1107 {
1108     int i;
1109     char_info_t *end, *src = screen_buffer->data + y * screen_buffer->width + x;
1110
1111     if (y >= screen_buffer->height) return;
1112
1113     if (wrap)
1114         end = screen_buffer->data + screen_buffer->height * screen_buffer->width;
1115     else
1116         end = screen_buffer->data + (y+1) * screen_buffer->width;
1117
1118     switch(mode)
1119     {
1120     case CHAR_INFO_MODE_TEXT:
1121         {
1122             WCHAR *data;
1123             int count = min( end - src, get_reply_max_size() / sizeof(*data) );
1124             if ((data = set_reply_data_size( count * sizeof(*data) )))
1125             {
1126                 for (i = 0; i < count; i++) data[i] = src[i].ch;
1127             }
1128         }
1129         break;
1130     case CHAR_INFO_MODE_ATTR:
1131         {
1132             unsigned short *data;
1133             int count = min( end - src, get_reply_max_size() / sizeof(*data) );
1134             if ((data = set_reply_data_size( count * sizeof(*data) )))
1135             {
1136                 for (i = 0; i < count; i++) data[i] = src[i].attr;
1137             }
1138         }
1139         break;
1140     case CHAR_INFO_MODE_TEXTATTR:
1141         {
1142             char_info_t *data;
1143             int count = min( end - src, get_reply_max_size() / sizeof(*data) );
1144             if ((data = set_reply_data_size( count * sizeof(*data) )))
1145             {
1146                 for (i = 0; i < count; i++) data[i] = src[i];
1147             }
1148         }
1149         break;
1150     default:
1151         set_error( STATUS_INVALID_PARAMETER );
1152         break;
1153     }
1154 }
1155
1156 /* scroll parts of a screen buffer */
1157 static void scroll_console_output( obj_handle_t handle, int xsrc, int ysrc, int xdst, int ydst,
1158                                    int w, int h )
1159 {
1160     struct screen_buffer *screen_buffer;
1161     int                         j;
1162     char_info_t *psrc, *pdst;
1163     struct console_renderer_event evt;
1164
1165     if (!(screen_buffer = (struct screen_buffer *)get_handle_obj( current->process, handle,
1166                                                                   GENERIC_READ, &screen_buffer_ops )))
1167         return;
1168     if (xsrc < 0 || ysrc < 0 || xdst < 0 || ydst < 0 ||
1169         xsrc + w > screen_buffer->width  ||
1170         xdst + w > screen_buffer->width  ||
1171         ysrc + h > screen_buffer->height ||
1172         ydst + h > screen_buffer->height ||
1173         w == 0 || h == 0)
1174     {
1175         set_error( STATUS_INVALID_PARAMETER );
1176         release_object( screen_buffer );
1177         return;
1178     }
1179
1180     if (ysrc < ydst)
1181     {
1182         psrc = &screen_buffer->data[(ysrc + h - 1) * screen_buffer->width + xsrc];
1183         pdst = &screen_buffer->data[(ydst + h - 1) * screen_buffer->width + xdst];
1184
1185         for (j = h; j > 0; j--)
1186         {
1187             memcpy(pdst, psrc, w * sizeof(*pdst) );
1188             pdst -= screen_buffer->width;
1189             psrc -= screen_buffer->width;
1190         }
1191     }
1192     else
1193     {
1194         psrc = &screen_buffer->data[ysrc * screen_buffer->width + xsrc];
1195         pdst = &screen_buffer->data[ydst * screen_buffer->width + xdst];
1196
1197         for (j = 0; j < h; j++)
1198         {
1199             /* we use memmove here because when psrc and pdst are the same,
1200              * copies are done on the same row, so the dst and src blocks
1201              * can overlap */
1202             memmove( pdst, psrc, w * sizeof(*pdst) );
1203             pdst += screen_buffer->width;
1204             psrc += screen_buffer->width;
1205         }
1206     }
1207
1208     /* FIXME: this could be enhanced, by signalling scroll */
1209     evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
1210     evt.u.update.top    = min(ysrc, ydst);
1211     evt.u.update.bottom = max(ysrc, ydst) + h - 1;
1212     console_input_events_append( screen_buffer->input->evt, &evt );
1213
1214     release_object( screen_buffer );
1215 }
1216
1217 /* allocate a console for the renderer */
1218 DECL_HANDLER(alloc_console)
1219 {
1220     obj_handle_t in = 0;
1221     obj_handle_t evt = 0;
1222     struct process *process;
1223     struct process *renderer = current->process;
1224     struct console_input *console;
1225
1226     process = (req->pid) ? get_process_from_id( req->pid ) :
1227               (struct process *)grab_object( renderer->parent );
1228
1229     reply->handle_in = 0;
1230     reply->event = 0;
1231     if (!process) return;
1232     if (process != renderer && process->console)
1233     {
1234         set_error( STATUS_ACCESS_DENIED );
1235         goto the_end;
1236     }
1237
1238     if ((console = (struct console_input*)create_console_input( current )))
1239     {
1240         if ((in = alloc_handle( renderer, console, req->access, req->inherit )))
1241         {
1242             if ((evt = alloc_handle( renderer, console->evt,
1243                                      SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE, FALSE )))
1244             {
1245                 if (process != renderer)
1246                 {
1247                     process->console = (struct console_input*)grab_object( console );
1248                     console->num_proc++;
1249                 }
1250                 reply->handle_in = in;
1251                 reply->event = evt;
1252                 release_object( console );
1253                 goto the_end;
1254             }
1255             close_handle( renderer, in, NULL );
1256         }
1257         free_console( process );
1258     }
1259  the_end:
1260     release_object( process );
1261 }
1262
1263 /* free the console of the current process */
1264 DECL_HANDLER(free_console)
1265 {
1266     free_console( current->process );
1267 }
1268
1269 /* let the renderer peek the events it's waiting on */
1270 DECL_HANDLER(get_console_renderer_events)
1271 {
1272     struct console_input_events *evt;
1273
1274     evt = (struct console_input_events *)get_handle_obj( current->process, req->handle,
1275                                                          GENERIC_WRITE, &console_input_events_ops );
1276     if (!evt) return;
1277     console_input_events_get( evt );
1278     release_object( evt );
1279 }
1280
1281 /* open a handle to the process console */
1282 DECL_HANDLER(open_console)
1283 {
1284     struct object      *obj = NULL;
1285
1286     reply->handle = 0;
1287     switch (req->from)
1288     {
1289     case 0:
1290         if (current->process->console && current->process->console->renderer)
1291             obj = grab_object( (struct object*)current->process->console );
1292         break;
1293     case 1:
1294          if (current->process->console && current->process->console->renderer &&
1295              current->process->console->active)
1296              obj = grab_object( (struct object*)current->process->console->active );
1297         break;
1298     default:
1299         if ((obj = get_handle_obj( current->process, (obj_handle_t)req->from,
1300                                    GENERIC_READ|GENERIC_WRITE, &console_input_ops )))
1301         {
1302             struct console_input* console = (struct console_input*)obj;
1303             obj = (console->active) ? grab_object( console->active ) : NULL;
1304             release_object( console );
1305         }
1306         break;
1307     }
1308
1309     /* FIXME: req->share is not used (as in screen buffer creation)  */
1310     if (obj)
1311     {
1312         reply->handle = alloc_handle( current->process, obj, req->access, req->inherit );
1313         release_object( obj );
1314     }
1315     else if (!get_error()) set_error( STATUS_ACCESS_DENIED );
1316 }
1317
1318 /* set info about a console input */
1319 DECL_HANDLER(set_console_input_info)
1320 {
1321     set_console_input_info( req, get_req_data(), get_req_data_size() );
1322 }
1323
1324 /* get info about a console (output only) */
1325 DECL_HANDLER(get_console_input_info)
1326 {
1327     struct console_input *console;
1328
1329     if (!(console = console_input_get( req->handle, GENERIC_READ ))) return;
1330     if (console->title)
1331     {
1332         size_t len = strlenW( console->title ) * sizeof(WCHAR);
1333         if (len > get_reply_max_size()) len = get_reply_max_size();
1334         set_reply_data( console->title, len );
1335     }
1336     reply->history_mode  = console->history_mode;
1337     reply->history_size  = console->history_size;
1338     reply->history_index = console->history_index;
1339     reply->edition_mode  = console->edition_mode;
1340
1341     release_object( console );
1342 }
1343
1344 /* get a console mode (input or output) */
1345 DECL_HANDLER(get_console_mode)
1346 {
1347     reply->mode = get_console_mode( req->handle );
1348 }
1349
1350 /* set a console mode (input or output) */
1351 DECL_HANDLER(set_console_mode)
1352 {
1353     set_console_mode( req->handle, req->mode );
1354 }
1355
1356 /* add input records to a console input queue */
1357 DECL_HANDLER(write_console_input)
1358 {
1359     struct console_input *console;
1360
1361     reply->written = 0;
1362     if (!(console = (struct console_input *)get_handle_obj( current->process, req->handle,
1363                                                             GENERIC_WRITE, &console_input_ops )))
1364         return;
1365     reply->written = write_console_input( console, get_req_data_size() / sizeof(INPUT_RECORD),
1366                                           get_req_data() );
1367     release_object( console );
1368 }
1369
1370 /* fetch input records from a console input queue */
1371 DECL_HANDLER(read_console_input)
1372 {
1373     int count = get_reply_max_size() / sizeof(INPUT_RECORD);
1374     reply->read = read_console_input( req->handle, count, req->flush );
1375 }
1376
1377 /* appends a string to console's history */
1378 DECL_HANDLER(append_console_input_history)
1379 {
1380     struct console_input *console;
1381
1382     if (!(console = console_input_get( req->handle, GENERIC_WRITE ))) return;
1383     console_input_append_hist( console, get_req_data(), get_req_data_size() / sizeof(WCHAR) );
1384     release_object( console );
1385 }
1386
1387 /* appends a string to console's history */
1388 DECL_HANDLER(get_console_input_history)
1389 {
1390     struct console_input *console;
1391
1392     if (!(console = console_input_get( req->handle, GENERIC_WRITE ))) return;
1393     reply->total = console_input_get_hist( console, req->index );
1394     release_object( console );
1395 }
1396
1397 /* creates a screen buffer */
1398 DECL_HANDLER(create_console_output)
1399 {
1400     struct console_input*       console;
1401     struct screen_buffer*       screen_buffer;
1402
1403     if (!(console = console_input_get( req->handle_in, GENERIC_WRITE))) return;
1404
1405     screen_buffer = create_console_output( console );
1406     if (screen_buffer)
1407     {
1408         /* FIXME: should store sharing and test it when opening the CONOUT$ device
1409          * see file.c on how this could be done */
1410         reply->handle_out = alloc_handle( current->process, screen_buffer,
1411                                           req->access, req->inherit );
1412         release_object( screen_buffer );
1413     }
1414     release_object( console );
1415 }
1416
1417 /* set info about a console screen buffer */
1418 DECL_HANDLER(set_console_output_info)
1419 {
1420     struct screen_buffer *screen_buffer;
1421
1422     if ((screen_buffer = (struct screen_buffer*)get_handle_obj( current->process, req->handle,
1423                                                                 GENERIC_WRITE, &screen_buffer_ops)))
1424     {
1425         set_console_output_info( screen_buffer, req );
1426         release_object( screen_buffer );
1427     }
1428 }
1429
1430 /* get info about a console screen buffer */
1431 DECL_HANDLER(get_console_output_info)
1432 {
1433     struct screen_buffer *screen_buffer;
1434
1435     if ((screen_buffer = (struct screen_buffer *)get_handle_obj( current->process, req->handle,
1436                                                                  GENERIC_READ, &screen_buffer_ops)))
1437     {
1438         reply->cursor_size    = screen_buffer->cursor_size;
1439         reply->cursor_visible = screen_buffer->cursor_visible;
1440         reply->cursor_x       = screen_buffer->cursor_x;
1441         reply->cursor_y       = screen_buffer->cursor_y;
1442         reply->width          = screen_buffer->width;
1443         reply->height         = screen_buffer->height;
1444         reply->attr           = screen_buffer->attr;
1445         reply->win_left       = screen_buffer->win.left;
1446         reply->win_top        = screen_buffer->win.top;
1447         reply->win_right      = screen_buffer->win.right;
1448         reply->win_bottom     = screen_buffer->win.bottom;
1449         reply->max_width      = screen_buffer->max_width;
1450         reply->max_height     = screen_buffer->max_height;
1451         release_object( screen_buffer );
1452     }
1453 }
1454
1455 /* read data (chars & attrs) from a screen buffer */
1456 DECL_HANDLER(read_console_output)
1457 {
1458     struct screen_buffer *screen_buffer;
1459
1460     if ((screen_buffer = (struct screen_buffer*)get_handle_obj( current->process, req->handle,
1461                                                                 GENERIC_READ, &screen_buffer_ops )))
1462     {
1463         read_console_output( screen_buffer, req->x, req->y, req->mode, req->wrap );
1464         reply->width  = screen_buffer->width;
1465         reply->height = screen_buffer->height;
1466         release_object( screen_buffer );
1467     }
1468 }
1469
1470 /* write data (char and/or attrs) to a screen buffer */
1471 DECL_HANDLER(write_console_output)
1472 {
1473     struct screen_buffer *screen_buffer;
1474
1475     if ((screen_buffer = (struct screen_buffer*)get_handle_obj( current->process, req->handle,
1476                                                                 GENERIC_WRITE, &screen_buffer_ops)))
1477     {
1478         reply->written = write_console_output( screen_buffer, get_req_data_size(), get_req_data(),
1479                                                req->mode, req->x, req->y, req->wrap );
1480         reply->width  = screen_buffer->width;
1481         reply->height = screen_buffer->height;
1482         release_object( screen_buffer );
1483     }
1484 }
1485
1486 /* fill a screen buffer with constant data (chars and/or attributes) */
1487 DECL_HANDLER(fill_console_output)
1488 {
1489     struct screen_buffer *screen_buffer;
1490
1491     if ((screen_buffer = (struct screen_buffer*)get_handle_obj( current->process, req->handle,
1492                                                                 GENERIC_WRITE, &screen_buffer_ops)))
1493     {
1494         reply->written = fill_console_output( screen_buffer, req->data, req->mode,
1495                                               req->x, req->y, req->count, req->wrap );
1496         release_object( screen_buffer );
1497     }
1498 }
1499
1500 /* move a rect of data in a screen buffer */
1501 DECL_HANDLER(move_console_output)
1502 {
1503     scroll_console_output( req->handle, req->x_src, req->y_src, req->x_dst, req->y_dst,
1504                            req->w, req->h );
1505 }
1506
1507 /* sends a signal to a console (process, group...) */
1508 DECL_HANDLER(send_console_signal)
1509 {
1510     process_id_t group;
1511
1512     group = req->group_id ? req->group_id : current->process->group_id;
1513
1514     if (!group)
1515         set_error( STATUS_INVALID_PARAMETER);
1516     else
1517         propagate_console_signal( current->process->console, req->signal, group );
1518 }