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