Be more strict and verbose while testing
[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 static void console_input_dump( struct object *obj, int verbose );
39 static void console_input_destroy( struct object *obj );
40
41 static const struct object_ops console_input_ops =
42 {
43     sizeof(struct console_input),     /* size */
44     console_input_dump,               /* dump */
45     no_add_queue,                     /* add_queue */
46     NULL,                             /* remove_queue */
47     NULL,                             /* signaled */
48     no_satisfied,                     /* satisfied */
49     no_signal,                        /* signal */
50     no_get_fd,                        /* get_fd */
51     no_lookup_name,                   /* lookup_name */
52     no_close_handle,                  /* close_handle */
53     console_input_destroy             /* destroy */
54 };
55
56 static void console_input_events_dump( struct object *obj, int verbose );
57 static void console_input_events_destroy( struct object *obj );
58 static int  console_input_events_signaled( struct object *obj, struct thread *thread );
59
60 struct console_input_events
61 {
62     struct object         obj;         /* object header */
63     int                   num_alloc;   /* number of allocated events */
64     int                   num_used;    /* number of actually used events */
65     struct console_renderer_event*      events;
66 };
67
68 static const struct object_ops console_input_events_ops =
69 {
70     sizeof(struct console_input_events), /* size */
71     console_input_events_dump,        /* dump */
72     add_queue,                        /* add_queue */
73     remove_queue,                     /* remove_queue */
74     console_input_events_signaled,    /* signaled */
75     no_satisfied,                     /* satisfied */
76     no_signal,                        /* signal */
77     no_get_fd,                        /* get_fd */
78     no_lookup_name,                   /* lookup_name */
79     no_close_handle,                  /* close_handle */
80     console_input_events_destroy      /* destroy */
81 };
82
83 struct screen_buffer
84 {
85     struct object         obj;           /* object header */
86     struct list           entry;         /* entry in list of all screen buffers */
87     struct console_input *input;         /* associated console input */
88     int                   mode;          /* output mode */
89     int                   cursor_size;   /* size of cursor (percentage filled) */
90     int                   cursor_visible;/* cursor visibility flag */
91     int                   cursor_x;      /* position of cursor */
92     int                   cursor_y;      /* position of cursor */
93     int                   width;         /* size (w-h) of the screen buffer */
94     int                   height;
95     int                   max_width;     /* size (w-h) of the window given font size */
96     int                   max_height;
97     char_info_t          *data;          /* the data for each cell - a width x height matrix */
98     unsigned short        attr;          /* default attribute for screen buffer */
99     rectangle_t           win;           /* current visible window on the screen buffer *
100                                           * as seen in wineconsole */
101 };
102
103 static void screen_buffer_dump( struct object *obj, int verbose );
104 static void screen_buffer_destroy( struct object *obj );
105
106 static const struct object_ops screen_buffer_ops =
107 {
108     sizeof(struct screen_buffer),     /* size */
109     screen_buffer_dump,               /* dump */
110     no_add_queue,                     /* add_queue */
111     NULL,                             /* remove_queue */
112     NULL,                             /* signaled */
113     NULL,                             /* satisfied */
114     no_signal,                        /* signal */
115     no_get_fd,                        /* get_fd */
116     no_lookup_name,                   /* lookup_name */
117     no_close_handle,                  /* close_handle */
118     screen_buffer_destroy             /* destroy */
119 };
120
121 static struct list screen_buffer_list = LIST_INIT(screen_buffer_list);
122
123 static const char_info_t empty_char_info = { ' ', 0x000f };  /* white on black space */
124
125 /* dumps the renderer events of a console */
126 static void console_input_events_dump( struct object *obj, int verbose )
127 {
128     struct console_input_events *evts = (struct console_input_events *)obj;
129     assert( obj->ops == &console_input_events_ops );
130     fprintf( stderr, "Console input events: %d/%d events\n",
131              evts->num_used, evts->num_alloc );
132 }
133
134 /* destroys the renderer events of a console */
135 static void console_input_events_destroy( struct object *obj )
136 {
137     struct console_input_events *evts = (struct console_input_events *)obj;
138     assert( obj->ops == &console_input_events_ops );
139     free( evts->events );
140 }
141
142 /* the renderer events list is signaled when it's not empty */
143 static int console_input_events_signaled( struct object *obj, struct thread *thread )
144 {
145     struct console_input_events *evts = (struct console_input_events *)obj;
146     assert( obj->ops == &console_input_events_ops );
147     return (evts->num_used != 0);
148 }
149
150 /* add an event to the console's renderer events list */
151 static void console_input_events_append( struct console_input_events* evts,
152                                          struct console_renderer_event* evt)
153 {
154     int collapsed = FALSE;
155
156     /* to be done even when evt has been generated by the rendere ? */
157
158     /* try to collapse evt into current queue's events */
159     if (evts->num_used)
160     {
161         struct console_renderer_event* last = &evts->events[evts->num_used - 1];
162
163         if (last->event == CONSOLE_RENDERER_UPDATE_EVENT &&
164             evt->event == CONSOLE_RENDERER_UPDATE_EVENT)
165         {
166             /* if two update events overlap, collapse them into a single one */
167             if (last->u.update.bottom + 1 >= evt->u.update.top &&
168                 evt->u.update.bottom + 1 >= last->u.update.top)
169             {
170                 last->u.update.top = min(last->u.update.top, evt->u.update.top);
171                 last->u.update.bottom = max(last->u.update.bottom, evt->u.update.bottom);
172                 collapsed = TRUE;
173             }
174         }
175     }
176     if (!collapsed)
177     {
178         if (evts->num_used == evts->num_alloc)
179         {
180             evts->num_alloc += 16;
181             evts->events = realloc( evts->events, evts->num_alloc * sizeof(*evt) );
182             assert(evts->events);
183         }
184         evts->events[evts->num_used++] = *evt;
185     }
186     wake_up( &evts->obj, 0 );
187 }
188
189 /* retrieves events from the console's renderer events list */
190 static void console_input_events_get( struct console_input_events* evts )
191 {
192     size_t num = get_reply_max_size() / sizeof(evts->events[0]);
193
194     if (num > evts->num_used) num = evts->num_used;
195     set_reply_data( evts->events, num * sizeof(evts->events[0]) );
196     if (num < evts->num_used)
197     {
198         memmove( &evts->events[0], &evts->events[num],
199                  (evts->num_used - num) * sizeof(evts->events[0]) );
200     }
201     evts->num_used -= num;
202 }
203
204 static struct console_input_events *create_console_input_events(void)
205 {
206     struct console_input_events*        evt;
207
208     if (!(evt = alloc_object( &console_input_events_ops ))) return NULL;
209     evt->num_alloc = evt->num_used = 0;
210     evt->events = NULL;
211     return evt;
212 }
213
214 static struct object *create_console_input( struct thread* renderer )
215 {
216     struct console_input *console_input;
217
218     if (!(console_input = alloc_object( &console_input_ops ))) return NULL;
219     console_input->renderer      = renderer;
220     console_input->mode          = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
221                                    ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
222     console_input->num_proc      = 0;
223     console_input->active        = NULL;
224     console_input->recnum        = 0;
225     console_input->records       = NULL;
226     console_input->evt           = create_console_input_events();
227     console_input->title         = NULL;
228     console_input->history_size  = 50;
229     console_input->history       = calloc( console_input->history_size, sizeof(WCHAR*) );
230     console_input->history_index = 0;
231     console_input->history_mode  = 0;
232     console_input->edition_mode  = 0;
233     console_input->event         = create_event( NULL, 0, 1, 0 );
234
235     if (!console_input->history || !console_input->evt)
236     {
237         release_object( console_input );
238         return NULL;
239     }
240     return &console_input->obj;
241 }
242
243 static struct screen_buffer *create_console_output( struct console_input *console_input )
244 {
245     struct screen_buffer *screen_buffer;
246     struct console_renderer_event evt;
247     int i;
248
249     if (!(screen_buffer = alloc_object( &screen_buffer_ops ))) return NULL;
250     screen_buffer->mode           = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
251     screen_buffer->input          = console_input;
252     screen_buffer->cursor_size    = 100;
253     screen_buffer->cursor_visible = 1;
254     screen_buffer->width          = 80;
255     screen_buffer->height         = 150;
256     screen_buffer->max_width      = 80;
257     screen_buffer->max_height     = 25;
258     screen_buffer->cursor_x       = 0;
259     screen_buffer->cursor_y       = 0;
260     screen_buffer->attr           = 0x0F;
261     screen_buffer->win.left       = 0;
262     screen_buffer->win.right      = screen_buffer->max_width - 1;
263     screen_buffer->win.top        = 0;
264     screen_buffer->win.bottom     = screen_buffer->max_height - 1;
265
266     list_add_head( &screen_buffer_list, &screen_buffer->entry );
267
268     if (!(screen_buffer->data = malloc( screen_buffer->width * screen_buffer->height *
269                                         sizeof(*screen_buffer->data) )))
270     {
271         release_object( screen_buffer );
272         return NULL;
273     }
274     /* clear the first row */
275     for (i = 0; i < screen_buffer->width; i++) screen_buffer->data[i] = empty_char_info;
276     /* and copy it to all other rows */
277     for (i = 1; i < screen_buffer->height; i++)
278         memcpy( &screen_buffer->data[i * screen_buffer->width], screen_buffer->data,
279                 screen_buffer->width * sizeof(char_info_t) );
280
281     if (!console_input->active)
282     {
283         console_input->active = (struct screen_buffer*)grab_object( screen_buffer );
284
285         /* generate the initial events */
286         evt.event = CONSOLE_RENDERER_ACTIVE_SB_EVENT;
287         console_input_events_append( console_input->evt, &evt );
288
289         evt.event = CONSOLE_RENDERER_SB_RESIZE_EVENT;
290         evt.u.resize.width  = screen_buffer->width;
291         evt.u.resize.height = screen_buffer->height;
292         console_input_events_append( console_input->evt, &evt );
293
294         evt.event = CONSOLE_RENDERER_DISPLAY_EVENT;
295         evt.u.display.left   = screen_buffer->win.left;
296         evt.u.display.top    = screen_buffer->win.top;
297         evt.u.display.width  = screen_buffer->win.right - screen_buffer->win.left + 1;
298         evt.u.display.height = screen_buffer->win.bottom - screen_buffer->win.top + 1;
299         console_input_events_append( console_input->evt, &evt );
300
301         evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
302         evt.u.update.top    = 0;
303         evt.u.update.bottom = screen_buffer->height - 1;
304         console_input_events_append( console_input->evt, &evt );
305
306         evt.event = CONSOLE_RENDERER_CURSOR_GEOM_EVENT;
307         evt.u.cursor_geom.size    = screen_buffer->cursor_size;
308         evt.u.cursor_geom.visible = screen_buffer->cursor_visible;
309         console_input_events_append( console_input->evt, &evt );
310
311         evt.event = CONSOLE_RENDERER_CURSOR_POS_EVENT;
312         evt.u.cursor_pos.x = screen_buffer->cursor_x;
313         evt.u.cursor_pos.y = screen_buffer->cursor_y;
314         console_input_events_append( console_input->evt, &evt );
315     }
316     return screen_buffer;
317 }
318
319 /* free the console for this process */
320 int free_console( struct process *process )
321 {
322     struct console_input* console = process->console;
323
324     if (!console || !console->renderer) return 0;
325
326     process->console = NULL;
327     if (--console->num_proc == 0)
328     {
329         /* all processes have terminated... tell the renderer to terminate too */
330         struct console_renderer_event evt;
331         evt.event = CONSOLE_RENDERER_EXIT_EVENT;
332         console_input_events_append( console->evt, &evt );
333     }
334     release_object( console );
335
336     return 1;
337 }
338
339 /* let process inherit the console from parent... this handle two cases :
340  *      1/ generic console inheritance
341  *      2/ parent is a renderer which launches process, and process should attach to the console
342  *         renderered by parent
343  */
344 void inherit_console(struct thread *parent_thread, struct process *process, obj_handle_t hconin)
345 {
346     int done = 0;
347     struct process* parent = parent_thread->process;
348
349     /* if parent is a renderer, then attach current process to its console
350      * a bit hacky....
351      */
352     if (hconin)
353     {
354         struct console_input* console;
355
356         /* FIXME: should we check some access rights ? */
357         if ((console = (struct console_input*)get_handle_obj( parent, hconin,
358                                                               0, &console_input_ops )))
359         {
360             if (console->renderer == parent_thread)
361             {
362                 process->console = (struct console_input*)grab_object( console );
363                 process->console->num_proc++;
364                 done = 1;
365             }
366             release_object( console );
367         }
368         else clear_error();  /* ignore error */
369     }
370     /* otherwise, if parent has a console, attach child to this console */
371     if (!done && parent->console)
372     {
373         assert(parent->console->renderer);
374         process->console = (struct console_input*)grab_object( parent->console );
375         process->console->num_proc++;
376     }
377 }
378
379 static struct console_input* console_input_get( obj_handle_t handle, unsigned access )
380 {
381     struct console_input*       console = NULL;
382
383     if (handle)
384         console = (struct console_input *)get_handle_obj( current->process, handle,
385                                                           access, &console_input_ops );
386     else if (current->process->console)
387     {
388         assert( current->process->console->renderer );
389         console = (struct console_input *)grab_object( current->process->console );
390     }
391
392     if (!console && !get_error()) set_error(STATUS_INVALID_PARAMETER);
393     return console;
394 }
395
396 struct console_signal_info
397 {
398     struct console_input        *console;
399     process_id_t                 group;
400     int                          signal;
401 };
402
403 static int propagate_console_signal_cb(struct process *process, void *user)
404 {
405     struct console_signal_info* csi = (struct console_signal_info*)user;
406
407     if (process->console == csi->console && process->running_threads &&
408         (!csi->group || process->group_id == csi->group))
409     {
410         /* find a suitable thread to signal */
411         struct thread *thread;
412         LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry )
413         {
414             if (send_thread_signal( thread, csi->signal )) break;
415         }
416     }
417     return FALSE;
418 }
419
420 static void propagate_console_signal( struct console_input *console,
421                                       int sig, process_id_t group_id )
422 {
423     struct console_signal_info csi;
424
425     if (!console)
426     {
427         set_error( STATUS_INVALID_PARAMETER );
428         return;
429     }
430     /* FIXME: should support the other events (like CTRL_BREAK) */
431     if (sig != CTRL_C_EVENT)
432     {
433         set_error( STATUS_NOT_IMPLEMENTED );
434         return;
435     }
436     csi.console = console;
437     csi.signal  = SIGINT;
438     csi.group   = group_id;
439
440     enum_processes(propagate_console_signal_cb, &csi);
441 }
442
443 static int get_console_mode( obj_handle_t handle )
444 {
445     struct object *obj;
446     int ret = 0;
447
448     if ((obj = get_handle_obj( current->process, handle, GENERIC_READ, NULL )))
449     {
450         if (obj->ops == &console_input_ops)
451             ret = ((struct console_input *)obj)->mode;
452         else if (obj->ops == &screen_buffer_ops)
453             ret = ((struct screen_buffer *)obj)->mode;
454         else
455             set_error( STATUS_OBJECT_TYPE_MISMATCH );
456         release_object( obj );
457     }
458     return ret;
459 }
460
461 /* changes the mode of either a console input or a screen buffer */
462 static int set_console_mode( obj_handle_t handle, int mode )
463 {
464     struct object *obj;
465     int ret = 0;
466
467     if (!(obj = get_handle_obj( current->process, handle, GENERIC_WRITE, NULL )))
468         return 0;
469     if (obj->ops == &console_input_ops)
470     {
471         /* FIXME: if we remove the edit mode bits, we need (???) to clean up the history */
472         ((struct console_input *)obj)->mode = mode;
473         ret = 1;
474     }
475     else if (obj->ops == &screen_buffer_ops)
476     {
477         ((struct screen_buffer *)obj)->mode = mode;
478         ret = 1;
479     }
480     else set_error( STATUS_OBJECT_TYPE_MISMATCH );
481     release_object( obj );
482     return ret;
483 }
484
485 /* add input events to a console input queue */
486 static int write_console_input( struct console_input* console, int count,
487                                 const INPUT_RECORD *records )
488 {
489     INPUT_RECORD *new_rec;
490
491     if (!count) return 0;
492     if (!(new_rec = realloc( console->records,
493                              (console->recnum + count) * sizeof(INPUT_RECORD) )))
494     {
495         set_error( STATUS_NO_MEMORY );
496         release_object( console );
497         return -1;
498     }
499     console->records = new_rec;
500     memcpy( new_rec + console->recnum, records, count * sizeof(INPUT_RECORD) );
501
502     if (console->mode & ENABLE_PROCESSED_INPUT)
503     {
504         int i = 0;
505         while (i < count)
506         {
507             if (records[i].EventType == KEY_EVENT &&
508                 records[i].Event.KeyEvent.uChar.UnicodeChar == 'C' - 64 &&
509                 !(records[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY))
510             {
511                 if (i != count - 1)
512                     memcpy( &console->records[console->recnum + i],
513                             &console->records[console->recnum + i + 1],
514                             (count - i - 1) * sizeof(INPUT_RECORD) );
515                 count--;
516                 if (records[i].Event.KeyEvent.bKeyDown)
517                 {
518                     /* send SIGINT to all processes attached to this console */
519                     propagate_console_signal( console, CTRL_C_EVENT, 0 );
520                 }
521             }
522             else i++;
523         }
524     }
525     if (!console->recnum && count) set_event( console->event );
526     console->recnum += count;
527     return count;
528 }
529
530 /* retrieve a pointer to the console input records */
531 static int read_console_input( obj_handle_t handle, int count, int flush )
532 {
533     struct console_input *console;
534
535     if (!(console = (struct console_input *)get_handle_obj( current->process, handle,
536                                                             GENERIC_READ, &console_input_ops )))
537         return -1;
538
539     if (!count)
540     {
541         /* special case: do not retrieve anything, but return
542          * the total number of records available */
543         count = console->recnum;
544     }
545     else
546     {
547         if (count > console->recnum) count = console->recnum;
548         set_reply_data( console->records, count * sizeof(INPUT_RECORD) );
549     }
550     if (flush)
551     {
552         int i;
553         for (i = count; i < console->recnum; i++)
554             console->records[i-count] = console->records[i];
555         if ((console->recnum -= count) > 0)
556         {
557             INPUT_RECORD *new_rec = realloc( console->records,
558                                              console->recnum * sizeof(INPUT_RECORD) );
559             if (new_rec) console->records = new_rec;
560         }
561         else
562         {
563             free( console->records );
564             console->records = NULL;
565             reset_event( console->event );
566         }
567     }
568     release_object( console );
569     return count;
570 }
571
572 /* set misc console input information */
573 static int set_console_input_info( const struct set_console_input_info_request *req,
574                                    const WCHAR *title, size_t len )
575 {
576     struct console_input *console;
577     struct console_renderer_event evt;
578
579     if (!(console = console_input_get( req->handle, GENERIC_WRITE ))) goto error;
580
581     if (req->mask & SET_CONSOLE_INPUT_INFO_ACTIVE_SB)
582     {
583         struct screen_buffer *screen_buffer;
584
585         screen_buffer = (struct screen_buffer *)get_handle_obj( current->process, req->active_sb,
586                                                                 GENERIC_READ, &screen_buffer_ops );
587         if (!screen_buffer || screen_buffer->input != console)
588         {
589             set_error( STATUS_INVALID_PARAMETER );
590             if (screen_buffer) release_object( screen_buffer );
591             goto error;
592         }
593
594         if (screen_buffer != console->active)
595         {
596             if (console->active) release_object( console->active );
597             console->active = screen_buffer;
598             evt.event = CONSOLE_RENDERER_ACTIVE_SB_EVENT;
599             console_input_events_append( console->evt, &evt );
600         }
601         else
602             release_object( screen_buffer );
603     }
604     if (req->mask & SET_CONSOLE_INPUT_INFO_TITLE)
605     {
606         WCHAR *new_title = mem_alloc( len + sizeof(WCHAR) );
607         if (new_title)
608         {
609             memcpy( new_title, title, len );
610             new_title[len / sizeof(WCHAR)] = 0;
611             if (console->title) free( console->title );
612             console->title = new_title;
613             evt.event = CONSOLE_RENDERER_TITLE_EVENT;
614             console_input_events_append( console->evt, &evt );
615         }
616     }
617     if (req->mask & SET_CONSOLE_INPUT_INFO_HISTORY_MODE)
618     {
619         console->history_mode = req->history_mode;
620     }
621     if ((req->mask & SET_CONSOLE_INPUT_INFO_HISTORY_SIZE) &&
622         console->history_size != req->history_size)
623     {
624         WCHAR** mem = NULL;
625         int     i;
626         int     delta;
627
628         if (req->history_size)
629         {
630             mem = mem_alloc( req->history_size * sizeof(WCHAR*) );
631             if (!mem) goto error;
632             memset( mem, 0, req->history_size * sizeof(WCHAR*) );
633         }
634
635         delta = (console->history_index > req->history_size) ?
636             (console->history_index - req->history_size) : 0;
637
638         for (i = delta; i < console->history_index; i++)
639         {
640             mem[i - delta] = console->history[i];
641             console->history[i] = NULL;
642         }
643         console->history_index -= delta;
644
645         for (i = 0; i < console->history_size; i++)
646             if (console->history[i]) free( console->history[i] );
647         free( console->history );
648         console->history = mem;
649         console->history_size = req->history_size;
650     }
651     if (req->mask & SET_CONSOLE_INPUT_INFO_EDITION_MODE)
652     {
653         console->edition_mode = req->edition_mode;
654     }
655     release_object( console );
656     return 1;
657  error:
658     if (console) release_object( console );
659     return 0;
660 }
661
662 /* resize a screen buffer */
663 static int change_screen_buffer_size( struct screen_buffer *screen_buffer,
664                                       int new_width, int new_height )
665 {
666     int i, old_width, old_height, copy_width, copy_height;
667     char_info_t *new_data;
668
669     if (!(new_data = malloc( new_width * new_height * sizeof(*new_data) )))
670     {
671         set_error( STATUS_NO_MEMORY );
672         return 0;
673     }
674     old_width = screen_buffer->width;
675     old_height = screen_buffer->height;
676     copy_width = min( old_width, new_width );
677     copy_height = min( old_height, new_height );
678
679     /* copy all the rows */
680     for (i = 0; i < copy_height; i++)
681     {
682         memcpy( &new_data[i * new_width], &screen_buffer->data[i * old_width],
683                 copy_width * sizeof(char_info_t) );
684     }
685
686     /* clear the end of each row */
687     if (new_width > old_width)
688     {
689         /* fill first row */
690         for (i = old_width; i < new_width; i++) new_data[i] = empty_char_info;
691         /* and blast it to the other rows */
692         for (i = 1; i < copy_height; i++)
693             memcpy( &new_data[i * new_width + old_width], &new_data[old_width],
694                     (new_width - old_width) * sizeof(char_info_t) );
695     }
696
697     /* clear remaining rows */
698     if (new_height > old_height)
699     {
700         /* fill first row */
701         for (i = 0; i < new_width; i++) new_data[old_height * new_width + i] = empty_char_info;
702         /* and blast it to the other rows */
703         for (i = old_height+1; i < new_height; i++)
704             memcpy( &new_data[i * new_width], &new_data[old_height * new_width],
705                     new_width * sizeof(char_info_t) );
706     }
707     free( screen_buffer->data );
708     screen_buffer->data = new_data;
709     screen_buffer->width = new_width;
710     screen_buffer->height = new_height;
711     return 1;
712 }
713
714 /* set misc screen buffer information */
715 static int set_console_output_info( struct screen_buffer *screen_buffer,
716                                     const struct set_console_output_info_request *req )
717 {
718     struct console_renderer_event evt;
719
720     if (req->mask & SET_CONSOLE_OUTPUT_INFO_CURSOR_GEOM)
721     {
722         if (req->cursor_size < 1 || req->cursor_size > 100)
723         {
724             set_error( STATUS_INVALID_PARAMETER );
725             return 0;
726         }
727         if (screen_buffer->cursor_size != req->cursor_size ||
728             screen_buffer->cursor_visible != req->cursor_visible)
729         {
730             screen_buffer->cursor_size    = req->cursor_size;
731             screen_buffer->cursor_visible = req->cursor_visible;
732             evt.event = CONSOLE_RENDERER_CURSOR_GEOM_EVENT;
733             evt.u.cursor_geom.size    = req->cursor_size;
734             evt.u.cursor_geom.visible = req->cursor_visible;
735             console_input_events_append( screen_buffer->input->evt, &evt );
736         }
737     }
738     if (req->mask & SET_CONSOLE_OUTPUT_INFO_CURSOR_POS)
739     {
740         if (req->cursor_x < 0 || req->cursor_x >= screen_buffer->width ||
741             req->cursor_y < 0 || req->cursor_y >= screen_buffer->height)
742         {
743             set_error( STATUS_INVALID_PARAMETER );
744             return 0;
745         }
746         if (screen_buffer->cursor_x != req->cursor_x || screen_buffer->cursor_y != req->cursor_y)
747         {
748             screen_buffer->cursor_x       = req->cursor_x;
749             screen_buffer->cursor_y       = req->cursor_y;
750             evt.event = CONSOLE_RENDERER_CURSOR_POS_EVENT;
751             evt.u.cursor_pos.x = req->cursor_x;
752             evt.u.cursor_pos.y = req->cursor_y;
753             console_input_events_append( screen_buffer->input->evt, &evt );
754         }
755     }
756     if (req->mask & SET_CONSOLE_OUTPUT_INFO_SIZE)
757     {
758         unsigned cc;
759
760         /* new screen-buffer cannot be smaller than actual window */
761         if (req->width < screen_buffer->win.right - screen_buffer->win.left + 1 ||
762             req->height < screen_buffer->win.bottom - screen_buffer->win.top + 1)
763         {
764             set_error( STATUS_INVALID_PARAMETER );
765             return 0;
766         }
767         /* FIXME: there are also some basic minimum and max size to deal with */
768         if (!change_screen_buffer_size( screen_buffer, req->width, req->height )) return 0;
769
770         evt.event = CONSOLE_RENDERER_SB_RESIZE_EVENT;
771         evt.u.resize.width  = req->width;
772         evt.u.resize.height = req->height;
773         console_input_events_append( screen_buffer->input->evt, &evt );
774
775         evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
776         evt.u.update.top    = 0;
777         evt.u.update.bottom = screen_buffer->height - 1;
778         console_input_events_append( screen_buffer->input->evt, &evt );
779
780         /* scroll window to display sb */
781         if (screen_buffer->win.right >= req->width)
782         {       
783             screen_buffer->win.right -= screen_buffer->win.left;
784             screen_buffer->win.left = 0;
785         }
786         if (screen_buffer->win.bottom >= req->height)
787         {       
788             screen_buffer->win.bottom -= screen_buffer->win.top;
789             screen_buffer->win.top = 0;
790         }
791         /* reset cursor if needed (normally, if cursor was outside of new sb, the
792          * window has been shifted so that the new position of the cursor will be 
793          * visible */
794         cc = 0;
795         if (screen_buffer->cursor_x >= req->width)
796         {
797             screen_buffer->cursor_x = req->width - 1;
798             cc++;
799         }
800         if (screen_buffer->cursor_y >= req->height)
801         {
802             screen_buffer->cursor_y = req->height - 1;
803             cc++;
804         }
805         if (cc)
806         {
807             evt.event = CONSOLE_RENDERER_CURSOR_POS_EVENT;
808             evt.u.cursor_pos.x = req->cursor_x;
809             evt.u.cursor_pos.y = req->cursor_y;
810             console_input_events_append( screen_buffer->input->evt, &evt );
811         }
812
813         if (screen_buffer == screen_buffer->input->active &&
814             screen_buffer->input->mode & ENABLE_WINDOW_INPUT)
815         {
816             INPUT_RECORD        ir;
817             ir.EventType = WINDOW_BUFFER_SIZE_EVENT;
818             ir.Event.WindowBufferSizeEvent.dwSize.X = req->width;
819             ir.Event.WindowBufferSizeEvent.dwSize.Y = req->height;
820             write_console_input( screen_buffer->input, 1, &ir );
821         }
822     }
823     if (req->mask & SET_CONSOLE_OUTPUT_INFO_ATTR)
824     {
825         screen_buffer->attr = req->attr;
826     }
827     if (req->mask & SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW)
828     {
829         if (req->win_left < 0 || req->win_left > req->win_right ||
830             req->win_right >= screen_buffer->width ||
831             req->win_top < 0  || req->win_top > req->win_bottom ||
832             req->win_bottom >= screen_buffer->height)
833         {
834             set_error( STATUS_INVALID_PARAMETER );
835             return 0;
836         }
837         if (screen_buffer->win.left != req->win_left || screen_buffer->win.top != req->win_top ||
838             screen_buffer->win.right != req->win_right || screen_buffer->win.bottom != req->win_bottom)
839         {
840             screen_buffer->win.left   = req->win_left;
841             screen_buffer->win.top    = req->win_top;
842             screen_buffer->win.right  = req->win_right;
843             screen_buffer->win.bottom = req->win_bottom;
844             evt.event = CONSOLE_RENDERER_DISPLAY_EVENT;
845             evt.u.display.left   = req->win_left;
846             evt.u.display.top    = req->win_top;
847             evt.u.display.width  = req->win_right - req->win_left + 1;
848             evt.u.display.height = req->win_bottom - req->win_top + 1;
849             console_input_events_append( screen_buffer->input->evt, &evt );
850         }
851     }
852     if (req->mask & SET_CONSOLE_OUTPUT_INFO_MAX_SIZE)
853     {
854         /* can only be done by renderer */
855         if (current->process->console != screen_buffer->input)
856         {
857             set_error( STATUS_INVALID_PARAMETER );
858             return 0;
859         }
860
861         screen_buffer->max_width  = req->max_width;
862         screen_buffer->max_height = req->max_height;
863     }
864
865     return 1;
866 }
867
868 /* appends a new line to history (history is a fixed size array) */
869 static void console_input_append_hist( struct console_input* console, const WCHAR* buf, size_t len )
870 {
871     WCHAR*      ptr = mem_alloc( (len + 1) * sizeof(WCHAR) );
872
873     if (!ptr)
874     {
875         set_error( STATUS_NO_MEMORY );
876         return;
877     }
878     if (!console || !console->history_size)
879     {
880         set_error( STATUS_INVALID_PARAMETER ); /* FIXME */
881         return;
882     }
883
884     memcpy( ptr, buf, len * sizeof(WCHAR) );
885     ptr[len] = 0;
886
887     if (console->history_mode && console->history_index &&
888         strncmpW( console->history[console->history_index - 1], ptr, len * sizeof(WCHAR) ) == 0)
889     {
890         /* ok, mode ask us to not use twice the same string...
891          * so just free mem and returns
892          */
893         set_error( STATUS_ALIAS_EXISTS );
894         free(ptr);
895         return;
896     }
897
898     if (console->history_index < console->history_size)
899     {
900         console->history[console->history_index++] = ptr;
901     }
902     else
903     {
904         free( console->history[0]) ;
905         memmove( &console->history[0], &console->history[1],
906                  (console->history_size - 1) * sizeof(WCHAR*) );
907         console->history[console->history_size - 1] = ptr;
908     }
909 }
910
911 /* returns a line from the cache */
912 static size_t console_input_get_hist( struct console_input *console, int index )
913 {
914     size_t ret = 0;
915
916     if (index >= console->history_index) set_error( STATUS_INVALID_PARAMETER );
917     else
918     {
919         ret = strlenW( console->history[index] ) * sizeof(WCHAR);
920         set_reply_data( console->history[index], min( ret, get_reply_max_size() ));
921     }
922     return ret;
923 }
924
925 /* dumb dump */
926 static void console_input_dump( struct object *obj, int verbose )
927 {
928     struct console_input *console = (struct console_input *)obj;
929     assert( obj->ops == &console_input_ops );
930     fprintf( stderr, "Console input active=%p evt=%p\n",
931              console->active, console->evt );
932 }
933
934 static void console_input_destroy( struct object *obj )
935 {
936     struct console_input*       console_in = (struct console_input *)obj;
937     struct screen_buffer*       curr;
938     int                         i;
939
940     assert( obj->ops == &console_input_ops );
941     if (console_in->title) free( console_in->title );
942     if (console_in->records) free( console_in->records );
943
944     if (console_in->active) release_object( console_in->active );
945     console_in->active = NULL;
946
947     LIST_FOR_EACH_ENTRY( curr, &screen_buffer_list, struct screen_buffer, entry )
948     {
949         if (curr->input == console_in) curr->input = NULL;
950     }
951
952     release_object( console_in->evt );
953     console_in->evt = NULL;
954     release_object( console_in->event );
955
956     for (i = 0; i < console_in->history_size; i++)
957         if (console_in->history[i]) free( console_in->history[i] );
958     if (console_in->history) free( console_in->history );
959 }
960
961 static void screen_buffer_dump( struct object *obj, int verbose )
962 {
963     struct screen_buffer *screen_buffer = (struct screen_buffer *)obj;
964     assert( obj->ops == &screen_buffer_ops );
965
966     fprintf(stderr, "Console screen buffer input=%p\n", screen_buffer->input );
967 }
968
969 static void screen_buffer_destroy( struct object *obj )
970 {
971     struct screen_buffer *screen_buffer = (struct screen_buffer *)obj;
972
973     assert( obj->ops == &screen_buffer_ops );
974
975     list_remove( &screen_buffer->entry );
976
977     if (screen_buffer->input && screen_buffer->input->active == screen_buffer)
978     {
979         struct screen_buffer *sb;
980
981         screen_buffer->input->active = NULL;
982         LIST_FOR_EACH_ENTRY( sb, &screen_buffer_list, struct screen_buffer, entry )
983         {
984             if (sb->input == screen_buffer->input)
985             {
986                 sb->input->active = sb;
987                 break;
988             }
989         }
990     }
991     if (screen_buffer->data) free( screen_buffer->data );
992 }
993
994 /* write data into a screen buffer */
995 static int write_console_output( struct screen_buffer *screen_buffer, size_t size,
996                                  const void* data, enum char_info_mode mode,
997                                  int x, int y, int wrap )
998 {
999     int i;
1000     char_info_t *end, *dest = screen_buffer->data + y * screen_buffer->width + x;
1001
1002     if (y >= screen_buffer->height) return 0;
1003
1004     if (wrap)
1005         end = screen_buffer->data + screen_buffer->height * screen_buffer->width;
1006     else
1007         end = screen_buffer->data + (y+1) * screen_buffer->width;
1008
1009     switch(mode)
1010     {
1011     case CHAR_INFO_MODE_TEXT:
1012         {
1013             const WCHAR *ptr = data;
1014             for (i = 0; i < size/sizeof(*ptr) && dest < end; dest++, i++) dest->ch = ptr[i];
1015         }
1016         break;
1017     case CHAR_INFO_MODE_ATTR:
1018         {
1019             const unsigned short *ptr = data;
1020             for (i = 0; i < size/sizeof(*ptr) && dest < end; dest++, i++) dest->attr = ptr[i];
1021         }
1022         break;
1023     case CHAR_INFO_MODE_TEXTATTR:
1024         {
1025             const char_info_t *ptr = data;
1026             for (i = 0; i < size/sizeof(*ptr) && dest < end; dest++, i++) *dest = ptr[i];
1027         }
1028         break;
1029     case CHAR_INFO_MODE_TEXTSTDATTR:
1030         {
1031             const WCHAR *ptr = data;
1032             for (i = 0; i < size/sizeof(*ptr) && dest < end; dest++, i++)
1033             {
1034                 dest->ch   = ptr[i];
1035                 dest->attr = screen_buffer->attr;
1036             }
1037         }
1038         break;
1039     default:
1040         set_error( STATUS_INVALID_PARAMETER );
1041         return 0;
1042     }
1043
1044     if (i && screen_buffer == screen_buffer->input->active)
1045     {
1046         struct console_renderer_event evt;
1047         evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
1048         evt.u.update.top    = y + x / screen_buffer->width;
1049         evt.u.update.bottom = y + (x + i - 1) / screen_buffer->width;
1050         console_input_events_append( screen_buffer->input->evt, &evt );
1051     }
1052     return i;
1053 }
1054
1055 /* fill a screen buffer with uniform data */
1056 static int fill_console_output( struct screen_buffer *screen_buffer, char_info_t data,
1057                                 enum char_info_mode mode, int x, int y, int count, int wrap )
1058 {
1059     int i;
1060     char_info_t *end, *dest = screen_buffer->data + y * screen_buffer->width + x;
1061
1062     if (y >= screen_buffer->height) return 0;
1063
1064     if (wrap)
1065         end = screen_buffer->data + screen_buffer->height * screen_buffer->width;
1066     else
1067         end = screen_buffer->data + (y+1) * screen_buffer->width;
1068
1069     if (count > end - dest) count = end - dest;
1070
1071     switch(mode)
1072     {
1073     case CHAR_INFO_MODE_TEXT:
1074         for (i = 0; i < count; i++) dest[i].ch = data.ch;
1075         break;
1076     case CHAR_INFO_MODE_ATTR:
1077         for (i = 0; i < count; i++) dest[i].attr = data.attr;
1078         break;
1079     case CHAR_INFO_MODE_TEXTATTR:
1080         for (i = 0; i < count; i++) dest[i] = data;
1081         break;
1082     case CHAR_INFO_MODE_TEXTSTDATTR:
1083         for (i = 0; i < count; i++)
1084         {
1085             dest[i].ch   = data.ch;
1086             dest[i].attr = screen_buffer->attr;
1087         }
1088         break;
1089     default:
1090         set_error( STATUS_INVALID_PARAMETER );
1091         return 0;
1092     }
1093
1094     if (count && screen_buffer == screen_buffer->input->active)
1095     {
1096         struct console_renderer_event evt;
1097         evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
1098         evt.u.update.top    = y;
1099         evt.u.update.bottom = (y * screen_buffer->width + x + count - 1) / screen_buffer->width;
1100         console_input_events_append( screen_buffer->input->evt, &evt );
1101     }
1102     return i;
1103 }
1104
1105 /* read data from a screen buffer */
1106 static void read_console_output( struct screen_buffer *screen_buffer, int x, int y,
1107                                  enum char_info_mode mode, int wrap )
1108 {
1109     int i;
1110     char_info_t *end, *src = screen_buffer->data + y * screen_buffer->width + x;
1111
1112     if (y >= screen_buffer->height) return;
1113
1114     if (wrap)
1115         end = screen_buffer->data + screen_buffer->height * screen_buffer->width;
1116     else
1117         end = screen_buffer->data + (y+1) * screen_buffer->width;
1118
1119     switch(mode)
1120     {
1121     case CHAR_INFO_MODE_TEXT:
1122         {
1123             WCHAR *data;
1124             int count = min( end - src, get_reply_max_size() / sizeof(*data) );
1125             if ((data = set_reply_data_size( count * sizeof(*data) )))
1126             {
1127                 for (i = 0; i < count; i++) data[i] = src[i].ch;
1128             }
1129         }
1130         break;
1131     case CHAR_INFO_MODE_ATTR:
1132         {
1133             unsigned short *data;
1134             int count = min( end - src, get_reply_max_size() / sizeof(*data) );
1135             if ((data = set_reply_data_size( count * sizeof(*data) )))
1136             {
1137                 for (i = 0; i < count; i++) data[i] = src[i].attr;
1138             }
1139         }
1140         break;
1141     case CHAR_INFO_MODE_TEXTATTR:
1142         {
1143             char_info_t *data;
1144             int count = min( end - src, get_reply_max_size() / sizeof(*data) );
1145             if ((data = set_reply_data_size( count * sizeof(*data) )))
1146             {
1147                 for (i = 0; i < count; i++) data[i] = src[i];
1148             }
1149         }
1150         break;
1151     default:
1152         set_error( STATUS_INVALID_PARAMETER );
1153         break;
1154     }
1155 }
1156
1157 /* scroll parts of a screen buffer */
1158 static void scroll_console_output( obj_handle_t handle, int xsrc, int ysrc, int xdst, int ydst,
1159                                    int w, int h )
1160 {
1161     struct screen_buffer *screen_buffer;
1162     int                         j;
1163     char_info_t *psrc, *pdst;
1164     struct console_renderer_event evt;
1165
1166     if (!(screen_buffer = (struct screen_buffer *)get_handle_obj( current->process, handle,
1167                                                                   GENERIC_READ, &screen_buffer_ops )))
1168         return;
1169     if (xsrc < 0 || ysrc < 0 || xdst < 0 || ydst < 0 ||
1170         xsrc + w > screen_buffer->width  ||
1171         xdst + w > screen_buffer->width  ||
1172         ysrc + h > screen_buffer->height ||
1173         ydst + h > screen_buffer->height ||
1174         w == 0 || h == 0)
1175     {
1176         set_error( STATUS_INVALID_PARAMETER );
1177         release_object( screen_buffer );
1178         return;
1179     }
1180
1181     if (ysrc < ydst)
1182     {
1183         psrc = &screen_buffer->data[(ysrc + h - 1) * screen_buffer->width + xsrc];
1184         pdst = &screen_buffer->data[(ydst + h - 1) * screen_buffer->width + xdst];
1185
1186         for (j = h; j > 0; j--)
1187         {
1188             memcpy(pdst, psrc, w * sizeof(*pdst) );
1189             pdst -= screen_buffer->width;
1190             psrc -= screen_buffer->width;
1191         }
1192     }
1193     else
1194     {
1195         psrc = &screen_buffer->data[ysrc * screen_buffer->width + xsrc];
1196         pdst = &screen_buffer->data[ydst * screen_buffer->width + xdst];
1197
1198         for (j = 0; j < h; j++)
1199         {
1200             /* we use memmove here because when psrc and pdst are the same,
1201              * copies are done on the same row, so the dst and src blocks
1202              * can overlap */
1203             memmove( pdst, psrc, w * sizeof(*pdst) );
1204             pdst += screen_buffer->width;
1205             psrc += screen_buffer->width;
1206         }
1207     }
1208
1209     /* FIXME: this could be enhanced, by signalling scroll */
1210     evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
1211     evt.u.update.top    = min(ysrc, ydst);
1212     evt.u.update.bottom = max(ysrc, ydst) + h - 1;
1213     console_input_events_append( screen_buffer->input->evt, &evt );
1214
1215     release_object( screen_buffer );
1216 }
1217
1218 /* allocate a console for the renderer */
1219 DECL_HANDLER(alloc_console)
1220 {
1221     obj_handle_t in = 0;
1222     obj_handle_t evt = 0;
1223     struct process *process;
1224     struct process *renderer = current->process;
1225     struct console_input *console;
1226
1227     process = (req->pid) ? get_process_from_id( req->pid ) :
1228               (struct process *)grab_object( renderer->parent );
1229
1230     reply->handle_in = 0;
1231     reply->event = 0;
1232     if (!process) return;
1233     if (process != renderer && process->console)
1234     {
1235         set_error( STATUS_ACCESS_DENIED );
1236         goto the_end;
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 }
1519
1520 /* get console which renderer is 'current' */
1521 static int cgwe_enum( struct process* process, void* user)
1522 {
1523     if (process->console && process->console->renderer == current)
1524     {
1525         *(struct console_input**)user = process->console;
1526         return 1;
1527     }
1528     return 0;
1529 }
1530
1531 DECL_HANDLER(get_console_wait_event)
1532 {
1533     struct console_input* console = NULL;
1534
1535     if (current->process->console && current->process->console->renderer)
1536         console = (struct console_input*)grab_object( (struct object*)current->process->console );
1537     else enum_processes(cgwe_enum, &console);
1538
1539     if (console)
1540     {
1541         reply->handle = alloc_handle( current->process, console->event, 
1542                                       EVENT_ALL_ACCESS, FALSE);
1543         release_object( console );
1544     }
1545     else set_error( STATUS_INVALID_PARAMETER );
1546 }