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