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