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