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