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