Third partial merge of the condrv_restructure branch, including reverse video (rev...
[reactos.git] / reactos / win32ss / user / winsrv / consrv / condrv / text.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Driver DLL
4 * FILE: win32ss/user/winsrv/consrv/condrv/text.c
5 * PURPOSE: Console Output Functions for text-mode screen-buffers
6 * PROGRAMMERS: Jeffrey Morlan
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <consrv.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS ********************************************************************/
18
19 #define TAB_WIDTH 8
20
21 /* PRIVATE FUNCTIONS **********************************************************/
22
23 CONSOLE_IO_OBJECT_TYPE
24 TEXTMODE_BUFFER_GetType(PCONSOLE_SCREEN_BUFFER This)
25 {
26 // return This->Header.Type;
27 return TEXTMODE_BUFFER;
28 }
29
30 static CONSOLE_SCREEN_BUFFER_VTBL TextVtbl =
31 {
32 TEXTMODE_BUFFER_GetType,
33 };
34
35
36 static VOID
37 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff);
38
39
40 NTSTATUS
41 CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
42 IN OUT PCONSOLE Console,
43 IN PCONSOLE_SCREEN_BUFFER_VTBL Vtbl,
44 IN SIZE_T Size);
45 VOID
46 CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer);
47
48
49 NTSTATUS
50 TEXTMODE_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
51 IN OUT PCONSOLE Console,
52 IN PTEXTMODE_BUFFER_INFO TextModeInfo)
53 {
54 NTSTATUS Status = STATUS_SUCCESS;
55 PTEXTMODE_SCREEN_BUFFER NewBuffer = NULL;
56
57 if (Console == NULL || Buffer == NULL || TextModeInfo == NULL)
58 return STATUS_INVALID_PARAMETER;
59
60 *Buffer = NULL;
61
62 Status = CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER*)&NewBuffer,
63 Console,
64 &TextVtbl,
65 sizeof(TEXTMODE_SCREEN_BUFFER));
66 if (!NT_SUCCESS(Status)) return Status;
67 NewBuffer->Header.Type = TEXTMODE_BUFFER;
68
69 NewBuffer->Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
70 TextModeInfo->ScreenBufferSize.X *
71 TextModeInfo->ScreenBufferSize.Y *
72 sizeof(CHAR_INFO));
73 if (NewBuffer->Buffer == NULL)
74 {
75 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer);
76 return STATUS_INSUFFICIENT_RESOURCES;
77 }
78
79 NewBuffer->ScreenBufferSize = NewBuffer->OldScreenBufferSize
80 = TextModeInfo->ScreenBufferSize;
81 NewBuffer->ViewSize = NewBuffer->OldViewSize
82 = Console->ConsoleSize;
83
84 NewBuffer->ViewOrigin.X = NewBuffer->ViewOrigin.Y = 0;
85 NewBuffer->VirtualY = 0;
86
87 NewBuffer->CursorBlinkOn = NewBuffer->ForceCursorOff = FALSE;
88 NewBuffer->CursorInfo.bVisible = (TextModeInfo->IsCursorVisible && (TextModeInfo->CursorSize != 0));
89 NewBuffer->CursorInfo.dwSize = min(max(TextModeInfo->CursorSize, 0), 100);
90
91 NewBuffer->ScreenDefaultAttrib = TextModeInfo->ScreenAttrib;
92 NewBuffer->PopupDefaultAttrib = TextModeInfo->PopupAttrib;
93
94 /* Initialize buffer to be empty with default attributes */
95 for (NewBuffer->CursorPosition.Y = 0 ; NewBuffer->CursorPosition.Y < NewBuffer->ScreenBufferSize.Y; NewBuffer->CursorPosition.Y++)
96 {
97 ClearLineBuffer(NewBuffer);
98 }
99 NewBuffer->CursorPosition.X = NewBuffer->CursorPosition.Y = 0;
100
101 NewBuffer->Mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
102
103 *Buffer = (PCONSOLE_SCREEN_BUFFER)NewBuffer;
104 return STATUS_SUCCESS;
105 }
106
107 VOID
108 TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer)
109 {
110 PTEXTMODE_SCREEN_BUFFER Buff = (PTEXTMODE_SCREEN_BUFFER)Buffer;
111
112 /*
113 * IMPORTANT !! Reinitialize the type so that we don't enter a recursive
114 * infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy.
115 */
116 Buffer->Header.Type = SCREEN_BUFFER;
117
118 ConsoleFreeHeap(Buff->Buffer);
119
120 CONSOLE_SCREEN_BUFFER_Destroy(Buffer);
121 }
122
123
124 PCHAR_INFO
125 ConioCoordToPointer(PTEXTMODE_SCREEN_BUFFER Buff, ULONG X, ULONG Y)
126 {
127 return &Buff->Buffer[((Y + Buff->VirtualY) % Buff->ScreenBufferSize.Y) * Buff->ScreenBufferSize.X + X];
128 }
129
130 static VOID
131 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff)
132 {
133 PCHAR_INFO Ptr = ConioCoordToPointer(Buff, 0, Buff->CursorPosition.Y);
134 SHORT Pos;
135
136 for (Pos = 0; Pos < Buff->ScreenBufferSize.X; Pos++, Ptr++)
137 {
138 /* Fill the cell */
139 Ptr->Char.UnicodeChar = L' ';
140 Ptr->Attributes = Buff->ScreenDefaultAttrib;
141 }
142 }
143
144 static VOID
145 ConioComputeUpdateRect(IN PTEXTMODE_SCREEN_BUFFER Buff,
146 IN OUT PSMALL_RECT UpdateRect,
147 IN PCOORD Start,
148 IN UINT Length)
149 {
150 if (Buff->ScreenBufferSize.X <= Start->X + Length)
151 {
152 UpdateRect->Left = 0;
153 }
154 else
155 {
156 UpdateRect->Left = Start->X;
157 }
158 if (Buff->ScreenBufferSize.X <= Start->X + Length)
159 {
160 UpdateRect->Right = Buff->ScreenBufferSize.X - 1;
161 }
162 else
163 {
164 UpdateRect->Right = Start->X + Length - 1;
165 }
166 UpdateRect->Top = Start->Y;
167 UpdateRect->Bottom = Start->Y + (Start->X + Length - 1) / Buff->ScreenBufferSize.X;
168 if (Buff->ScreenBufferSize.Y <= UpdateRect->Bottom)
169 {
170 UpdateRect->Bottom = Buff->ScreenBufferSize.Y - 1;
171 }
172 }
173
174 /*
175 * Move from one rectangle to another. We must be careful about the order that
176 * this is done, to avoid overwriting parts of the source before they are moved.
177 */
178 static VOID
179 ConioMoveRegion(PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
180 PSMALL_RECT SrcRegion,
181 PSMALL_RECT DstRegion,
182 PSMALL_RECT ClipRegion,
183 CHAR_INFO FillChar)
184 {
185 int Width = ConioRectWidth(SrcRegion);
186 int Height = ConioRectHeight(SrcRegion);
187 int SX, SY;
188 int DX, DY;
189 int XDelta, YDelta;
190 int i, j;
191
192 SY = SrcRegion->Top;
193 DY = DstRegion->Top;
194 YDelta = 1;
195 if (SY < DY)
196 {
197 /* Moving down: work from bottom up */
198 SY = SrcRegion->Bottom;
199 DY = DstRegion->Bottom;
200 YDelta = -1;
201 }
202 for (i = 0; i < Height; i++)
203 {
204 PCHAR_INFO SRow = ConioCoordToPointer(ScreenBuffer, 0, SY);
205 PCHAR_INFO DRow = ConioCoordToPointer(ScreenBuffer, 0, DY);
206
207 SX = SrcRegion->Left;
208 DX = DstRegion->Left;
209 XDelta = 1;
210 if (SX < DX)
211 {
212 /* Moving right: work from right to left */
213 SX = SrcRegion->Right;
214 DX = DstRegion->Right;
215 XDelta = -1;
216 }
217 for (j = 0; j < Width; j++)
218 {
219 CHAR_INFO Cell = SRow[SX];
220 if (SX >= ClipRegion->Left && SX <= ClipRegion->Right &&
221 SY >= ClipRegion->Top && SY <= ClipRegion->Bottom)
222 {
223 SRow[SX] = FillChar;
224 }
225 if (DX >= ClipRegion->Left && DX <= ClipRegion->Right &&
226 DY >= ClipRegion->Top && DY <= ClipRegion->Bottom)
227 {
228 DRow[DX] = Cell;
229 }
230 SX += XDelta;
231 DX += XDelta;
232 }
233 SY += YDelta;
234 DY += YDelta;
235 }
236 }
237
238 NTSTATUS
239 ConioResizeBuffer(PCONSOLE Console,
240 PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
241 COORD Size)
242 {
243 PCHAR_INFO Buffer;
244 DWORD Offset = 0;
245 PCHAR_INFO ptr;
246 WORD CurrentAttribute;
247 USHORT CurrentY;
248 PCHAR_INFO OldBuffer;
249 DWORD i;
250 DWORD diff;
251
252 /* Buffer size is not allowed to be smaller than the view size */
253 if (Size.X < ScreenBuffer->ViewSize.X || Size.Y < ScreenBuffer->ViewSize.Y)
254 return STATUS_INVALID_PARAMETER;
255
256 if (Size.X == ScreenBuffer->ScreenBufferSize.X && Size.Y == ScreenBuffer->ScreenBufferSize.Y)
257 {
258 // FIXME: Trigger a buffer resize event ??
259 return STATUS_SUCCESS;
260 }
261
262 if (Console->FixedSize)
263 {
264 /*
265 * The console is in fixed-size mode, so we cannot resize anything
266 * at the moment. However, keep those settings somewhere so that
267 * we can try to set them up when we will be allowed to do so.
268 */
269 ScreenBuffer->OldScreenBufferSize = Size;
270 return STATUS_NOT_SUPPORTED; // STATUS_SUCCESS
271 }
272
273 Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size.X * Size.Y * sizeof(CHAR_INFO));
274 if (!Buffer) return STATUS_NO_MEMORY;
275
276 DPRINT1("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer->ScreenBufferSize.X, ScreenBuffer->ScreenBufferSize.Y, Size.X, Size.Y);
277 OldBuffer = ScreenBuffer->Buffer;
278
279 for (CurrentY = 0; CurrentY < ScreenBuffer->ScreenBufferSize.Y && CurrentY < Size.Y; CurrentY++)
280 {
281 ptr = ConioCoordToPointer(ScreenBuffer, 0, CurrentY);
282 if (Size.X <= ScreenBuffer->ScreenBufferSize.X)
283 {
284 /* Reduce size */
285 RtlCopyMemory(Buffer + Offset, ptr, Size.X * sizeof(CHAR_INFO));
286 Offset += Size.X;
287 }
288 else
289 {
290 /* Enlarge size */
291 RtlCopyMemory(Buffer + Offset, ptr, ScreenBuffer->ScreenBufferSize.X * sizeof(CHAR_INFO));
292 Offset += ScreenBuffer->ScreenBufferSize.X;
293
294 /* The attribute to be used is the one of the last cell of the current line */
295 CurrentAttribute = ConioCoordToPointer(ScreenBuffer,
296 ScreenBuffer->ScreenBufferSize.X - 1,
297 CurrentY)->Attributes;
298
299 diff = Size.X - ScreenBuffer->ScreenBufferSize.X;
300
301 /* Zero-out the new part of the buffer */
302 for (i = 0; i < diff; i++)
303 {
304 ptr = Buffer + Offset;
305 ptr->Char.UnicodeChar = L' ';
306 ptr->Attributes = CurrentAttribute;
307 ++Offset;
308 }
309 }
310 }
311
312 if (Size.Y > ScreenBuffer->ScreenBufferSize.Y)
313 {
314 diff = Size.X * (Size.Y - ScreenBuffer->ScreenBufferSize.Y);
315
316 /* Zero-out the new part of the buffer */
317 for (i = 0; i < diff; i++)
318 {
319 ptr = Buffer + Offset;
320 ptr->Char.UnicodeChar = L' ';
321 ptr->Attributes = ScreenBuffer->ScreenDefaultAttrib;
322 ++Offset;
323 }
324 }
325
326 (void)InterlockedExchangePointer((PVOID volatile*)&ScreenBuffer->Buffer, Buffer);
327 ConsoleFreeHeap(OldBuffer);
328 ScreenBuffer->ScreenBufferSize = ScreenBuffer->OldScreenBufferSize = Size;
329 ScreenBuffer->VirtualY = 0;
330
331 /* Ensure cursor and window are within buffer */
332 if (ScreenBuffer->CursorPosition.X >= Size.X)
333 ScreenBuffer->CursorPosition.X = Size.X - 1;
334 if (ScreenBuffer->CursorPosition.Y >= Size.Y)
335 ScreenBuffer->CursorPosition.Y = Size.Y - 1;
336 if (ScreenBuffer->ViewOrigin.X > Size.X - ScreenBuffer->ViewSize.X)
337 ScreenBuffer->ViewOrigin.X = Size.X - ScreenBuffer->ViewSize.X;
338 if (ScreenBuffer->ViewOrigin.Y > Size.Y - ScreenBuffer->ViewSize.Y)
339 ScreenBuffer->ViewOrigin.Y = Size.Y - ScreenBuffer->ViewSize.Y;
340
341 /*
342 * Trigger a buffer resize event
343 */
344 if (Console->InputBuffer.Mode & ENABLE_WINDOW_INPUT)
345 {
346 INPUT_RECORD er;
347
348 er.EventType = WINDOW_BUFFER_SIZE_EVENT;
349 er.Event.WindowBufferSizeEvent.dwSize = ScreenBuffer->ScreenBufferSize;
350
351 ConioProcessInputEvent(Console, &er);
352 }
353
354 return STATUS_SUCCESS;
355 }
356
357 static VOID
358 ConioNextLine(PTEXTMODE_SCREEN_BUFFER Buff, PSMALL_RECT UpdateRect, PUINT ScrolledLines)
359 {
360 /* If we hit bottom, slide the viewable screen */
361 if (++Buff->CursorPosition.Y == Buff->ScreenBufferSize.Y)
362 {
363 Buff->CursorPosition.Y--;
364 if (++Buff->VirtualY == Buff->ScreenBufferSize.Y)
365 {
366 Buff->VirtualY = 0;
367 }
368 (*ScrolledLines)++;
369 ClearLineBuffer(Buff);
370 if (UpdateRect->Top != 0)
371 {
372 UpdateRect->Top--;
373 }
374 }
375 UpdateRect->Left = 0;
376 UpdateRect->Right = Buff->ScreenBufferSize.X - 1;
377 UpdateRect->Bottom = Buff->CursorPosition.Y;
378 }
379
380 NTSTATUS
381 ConioWriteConsole(PCONSOLE Console,
382 PTEXTMODE_SCREEN_BUFFER Buff,
383 PWCHAR Buffer,
384 DWORD Length,
385 BOOL Attrib)
386 {
387 UINT i;
388 PCHAR_INFO Ptr;
389 SMALL_RECT UpdateRect;
390 SHORT CursorStartX, CursorStartY;
391 UINT ScrolledLines;
392
393 CursorStartX = Buff->CursorPosition.X;
394 CursorStartY = Buff->CursorPosition.Y;
395 UpdateRect.Left = Buff->ScreenBufferSize.X;
396 UpdateRect.Top = Buff->CursorPosition.Y;
397 UpdateRect.Right = -1;
398 UpdateRect.Bottom = Buff->CursorPosition.Y;
399 ScrolledLines = 0;
400
401 for (i = 0; i < Length; i++)
402 {
403 /*
404 * If we are in processed mode, interpret special characters and
405 * display them correctly. Otherwise, just put them into the buffer.
406 */
407 if (Buff->Mode & ENABLE_PROCESSED_OUTPUT)
408 {
409 /* --- CR --- */
410 if (Buffer[i] == L'\r')
411 {
412 Buff->CursorPosition.X = 0;
413 UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X);
414 UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
415 continue;
416 }
417 /* --- LF --- */
418 else if (Buffer[i] == L'\n')
419 {
420 Buff->CursorPosition.X = 0;
421 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
422 continue;
423 }
424 /* --- BS --- */
425 else if (Buffer[i] == L'\b')
426 {
427 /* Only handle BS if we're not on the first pos of the first line */
428 if (0 != Buff->CursorPosition.X || 0 != Buff->CursorPosition.Y)
429 {
430 if (0 == Buff->CursorPosition.X)
431 {
432 /* slide virtual position up */
433 Buff->CursorPosition.X = Buff->ScreenBufferSize.X - 1;
434 Buff->CursorPosition.Y--;
435 UpdateRect.Top = min(UpdateRect.Top, Buff->CursorPosition.Y);
436 }
437 else
438 {
439 Buff->CursorPosition.X--;
440 }
441 Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
442 Ptr->Char.UnicodeChar = L' ';
443 Ptr->Attributes = Buff->ScreenDefaultAttrib;
444 UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X);
445 UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
446 }
447 continue;
448 }
449 /* --- TAB --- */
450 else if (Buffer[i] == L'\t')
451 {
452 UINT EndX;
453
454 UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X);
455 EndX = (Buff->CursorPosition.X + TAB_WIDTH) & ~(TAB_WIDTH - 1);
456 EndX = min(EndX, (UINT)Buff->ScreenBufferSize.X);
457 Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
458 while (Buff->CursorPosition.X < EndX)
459 {
460 Ptr->Char.UnicodeChar = L' ';
461 Ptr->Attributes = Buff->ScreenDefaultAttrib;
462 ++Ptr;
463 Buff->CursorPosition.X++;
464 }
465 UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X - 1);
466 if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X)
467 {
468 if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
469 {
470 Buff->CursorPosition.X = 0;
471 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
472 }
473 else
474 {
475 Buff->CursorPosition.X--;
476 }
477 }
478 continue;
479 }
480 // /* --- BEL ---*/
481 // else if (Buffer[i] == L'\a')
482 // {
483 // // FIXME: This MUST BE moved to the terminal emulator frontend!!
484 // DPRINT1("Bell\n");
485 // // SendNotifyMessage(Console->hWindow, PM_CONSOLE_BEEP, 0, 0);
486 // continue;
487 // }
488 }
489 UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X);
490 UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
491
492 Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
493 Ptr->Char.UnicodeChar = Buffer[i];
494 if (Attrib) Ptr->Attributes = Buff->ScreenDefaultAttrib;
495
496 Buff->CursorPosition.X++;
497 if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X)
498 {
499 if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
500 {
501 Buff->CursorPosition.X = 0;
502 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
503 }
504 else
505 {
506 Buff->CursorPosition.X = CursorStartX;
507 }
508 }
509 }
510
511 if (!ConioIsRectEmpty(&UpdateRect) && (PCONSOLE_SCREEN_BUFFER)Buff == Console->ActiveBuffer)
512 {
513 TermWriteStream(Console, &UpdateRect, CursorStartX, CursorStartY,
514 ScrolledLines, Buffer, Length);
515 }
516
517 return STATUS_SUCCESS;
518 }
519
520 NTSTATUS NTAPI
521 ConDrvChangeScreenBufferAttributes(IN PCONSOLE Console,
522 IN PTEXTMODE_SCREEN_BUFFER Buffer,
523 IN USHORT NewScreenAttrib,
524 IN USHORT NewPopupAttrib)
525 {
526 DWORD X, Y, Length;
527 PCHAR_INFO Ptr;
528
529 COORD TopLeft = {0};
530 ULONG NumCodesToWrite;
531 USHORT OldScreenAttrib;
532
533 if (Console == NULL || Buffer == NULL)
534 {
535 return STATUS_INVALID_PARAMETER;
536 }
537
538 /* Validity check */
539 ASSERT(Console == Buffer->Header.Console);
540
541 NumCodesToWrite = Buffer->ScreenBufferSize.X * Buffer->ScreenBufferSize.Y;
542 OldScreenAttrib = Buffer->ScreenDefaultAttrib;
543
544 X = TopLeft.X;
545 Y = (TopLeft.Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
546 Length = NumCodesToWrite;
547
548 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
549 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
550
551 while (Length--)
552 {
553 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
554 Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X];
555
556 /*
557 * Change the current colors only if they are the old ones.
558 */
559
560 /* Foreground color */
561 if ((Ptr->Attributes & 0x0F) == (OldScreenAttrib & 0x0F))
562 Ptr->Attributes = (Ptr->Attributes & 0xFFF0) | (NewScreenAttrib & 0x0F);
563
564 /* Background color */
565 if ((Ptr->Attributes & 0xF0) == (OldScreenAttrib & 0xF0))
566 Ptr->Attributes = (Ptr->Attributes & 0xFF0F) | (NewScreenAttrib & 0xF0);
567
568 // ++Ptr;
569
570 if (++X == Buffer->ScreenBufferSize.X)
571 {
572 X = 0;
573
574 if (++Y == Buffer->ScreenBufferSize.Y)
575 {
576 Y = 0;
577 }
578 }
579 }
580
581 /* Save foreground and background colors for both screen and popup */
582 Buffer->ScreenDefaultAttrib = (NewScreenAttrib & 0x00FF);
583 Buffer->PopupDefaultAttrib = (NewPopupAttrib & 0x00FF);
584
585 /* Refresh the display if needed */
586 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
587 {
588 SMALL_RECT UpdateRect;
589 ConioComputeUpdateRect(Buffer, &UpdateRect, &TopLeft, NumCodesToWrite);
590 TermDrawRegion(Console, &UpdateRect);
591 }
592
593 return STATUS_SUCCESS;
594 }
595
596
597 /* PUBLIC DRIVER APIS *********************************************************/
598
599 NTSTATUS NTAPI
600 ConDrvReadConsoleOutput(IN PCONSOLE Console,
601 IN PTEXTMODE_SCREEN_BUFFER Buffer,
602 IN BOOLEAN Unicode,
603 OUT PCHAR_INFO CharInfo/*Buffer*/,
604 IN OUT PSMALL_RECT ReadRegion)
605 {
606 SHORT X, Y;
607 SMALL_RECT ScreenBuffer;
608 PCHAR_INFO CurCharInfo;
609 SMALL_RECT CapturedReadRegion;
610 PCHAR_INFO Ptr;
611
612 if (Console == NULL || Buffer == NULL || CharInfo == NULL || ReadRegion == NULL)
613 {
614 return STATUS_INVALID_PARAMETER;
615 }
616
617 /* Validity check */
618 ASSERT(Console == Buffer->Header.Console);
619
620 CapturedReadRegion = *ReadRegion;
621
622 /* Make sure ReadRegion is inside the screen buffer */
623 ConioInitRect(&ScreenBuffer, 0, 0,
624 Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1);
625 if (!ConioGetIntersection(&CapturedReadRegion, &ScreenBuffer, &CapturedReadRegion))
626 {
627 /*
628 * It is okay to have a ReadRegion completely outside
629 * the screen buffer. No data is read then.
630 */
631 return STATUS_SUCCESS;
632 }
633
634 CurCharInfo = CharInfo;
635
636 for (Y = CapturedReadRegion.Top; Y <= CapturedReadRegion.Bottom; ++Y)
637 {
638 Ptr = ConioCoordToPointer(Buffer, CapturedReadRegion.Left, Y);
639 for (X = CapturedReadRegion.Left; X <= CapturedReadRegion.Right; ++X)
640 {
641 if (Unicode)
642 {
643 CurCharInfo->Char.UnicodeChar = Ptr->Char.UnicodeChar;
644 }
645 else
646 {
647 // ConsoleUnicodeCharToAnsiChar(Console, &CurCharInfo->Char.AsciiChar, &Ptr->Char.UnicodeChar);
648 WideCharToMultiByte(Console->OutputCodePage, 0, &Ptr->Char.UnicodeChar, 1,
649 &CurCharInfo->Char.AsciiChar, 1, NULL, NULL);
650 }
651 CurCharInfo->Attributes = Ptr->Attributes;
652 ++Ptr;
653 ++CurCharInfo;
654 }
655 }
656
657 *ReadRegion = CapturedReadRegion;
658
659 return STATUS_SUCCESS;
660 }
661
662 NTSTATUS NTAPI
663 ConDrvWriteConsoleOutput(IN PCONSOLE Console,
664 IN PTEXTMODE_SCREEN_BUFFER Buffer,
665 IN BOOLEAN Unicode,
666 IN PCHAR_INFO CharInfo/*Buffer*/,
667 IN OUT PSMALL_RECT WriteRegion)
668 {
669 SHORT X, Y;
670 SMALL_RECT ScreenBuffer;
671 PCHAR_INFO CurCharInfo;
672 SMALL_RECT CapturedWriteRegion;
673 PCHAR_INFO Ptr;
674
675 if (Console == NULL || Buffer == NULL || CharInfo == NULL || WriteRegion == NULL)
676 {
677 return STATUS_INVALID_PARAMETER;
678 }
679
680 /* Validity check */
681 ASSERT(Console == Buffer->Header.Console);
682
683 CapturedWriteRegion = *WriteRegion;
684
685 /* Make sure WriteRegion is inside the screen buffer */
686 ConioInitRect(&ScreenBuffer, 0, 0,
687 Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1);
688 if (!ConioGetIntersection(&CapturedWriteRegion, &ScreenBuffer, &CapturedWriteRegion))
689 {
690 /*
691 * It is okay to have a WriteRegion completely outside
692 * the screen buffer. No data is written then.
693 */
694 return STATUS_SUCCESS;
695 }
696
697 CurCharInfo = CharInfo;
698
699 for (Y = CapturedWriteRegion.Top; Y <= CapturedWriteRegion.Bottom; ++Y)
700 {
701 Ptr = ConioCoordToPointer(Buffer, CapturedWriteRegion.Left, Y);
702 for (X = CapturedWriteRegion.Left; X <= CapturedWriteRegion.Right; ++X)
703 {
704 if (Unicode)
705 {
706 Ptr->Char.UnicodeChar = CurCharInfo->Char.UnicodeChar;
707 }
708 else
709 {
710 ConsoleAnsiCharToUnicodeChar(Console, &Ptr->Char.UnicodeChar, &CurCharInfo->Char.AsciiChar);
711 }
712 Ptr->Attributes = CurCharInfo->Attributes;
713 ++Ptr;
714 ++CurCharInfo;
715 }
716 }
717
718 TermDrawRegion(Console, &CapturedWriteRegion);
719
720 *WriteRegion = CapturedWriteRegion;
721
722 return STATUS_SUCCESS;
723 }
724
725 /*
726 * NOTE: This function is strongly inspired by ConDrvWriteConsoleOutput...
727 */
728 NTSTATUS NTAPI
729 ConDrvWriteConsoleOutputVDM(IN PCONSOLE Console,
730 IN PTEXTMODE_SCREEN_BUFFER Buffer,
731 IN PCHAR_CELL CharInfo/*Buffer*/,
732 IN COORD CharInfoSize,
733 IN OUT PSMALL_RECT WriteRegion,
734 IN BOOLEAN DrawRegion)
735 {
736 SHORT X, Y;
737 SMALL_RECT ScreenBuffer;
738 PCHAR_CELL CurCharInfo;
739 SMALL_RECT CapturedWriteRegion;
740 PCHAR_INFO Ptr;
741
742 if (Console == NULL || Buffer == NULL || CharInfo == NULL || WriteRegion == NULL)
743 {
744 return STATUS_INVALID_PARAMETER;
745 }
746
747 /* Validity check */
748 ASSERT(Console == Buffer->Header.Console);
749
750 CapturedWriteRegion = *WriteRegion;
751
752 /* Make sure WriteRegion is inside the screen buffer */
753 ConioInitRect(&ScreenBuffer, 0, 0,
754 Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1);
755 if (!ConioGetIntersection(&CapturedWriteRegion, &ScreenBuffer, &CapturedWriteRegion))
756 {
757 /*
758 * It is okay to have a WriteRegion completely outside
759 * the screen buffer. No data is written then.
760 */
761 return STATUS_SUCCESS;
762 }
763
764 // CurCharInfo = CharInfo;
765
766 for (Y = CapturedWriteRegion.Top; Y <= CapturedWriteRegion.Bottom; ++Y)
767 {
768 /**/CurCharInfo = CharInfo + Y * CharInfoSize.X + CapturedWriteRegion.Left;/**/
769
770 Ptr = ConioCoordToPointer(Buffer, CapturedWriteRegion.Left, Y);
771 for (X = CapturedWriteRegion.Left; X <= CapturedWriteRegion.Right; ++X)
772 {
773 ConsoleAnsiCharToUnicodeChar(Console, &Ptr->Char.UnicodeChar, &CurCharInfo->Char);
774 Ptr->Attributes = CurCharInfo->Attributes;
775 ++Ptr;
776 ++CurCharInfo;
777 }
778 }
779
780 if (DrawRegion) TermDrawRegion(Console, &CapturedWriteRegion);
781
782 *WriteRegion = CapturedWriteRegion;
783
784 return STATUS_SUCCESS;
785 }
786
787 NTSTATUS NTAPI
788 ConDrvWriteConsole(IN PCONSOLE Console,
789 IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
790 IN BOOLEAN Unicode,
791 IN PVOID StringBuffer,
792 IN ULONG NumCharsToWrite,
793 OUT PULONG NumCharsWritten OPTIONAL)
794 {
795 NTSTATUS Status = STATUS_SUCCESS;
796 PWCHAR Buffer = NULL;
797 ULONG Written = 0;
798 ULONG Length;
799
800 if (Console == NULL || ScreenBuffer == NULL /* || StringBuffer == NULL */)
801 return STATUS_INVALID_PARAMETER;
802
803 /* Validity checks */
804 ASSERT(Console == ScreenBuffer->Header.Console);
805 ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCharsToWrite == 0));
806
807 /* Stop here if the console is paused */
808 if (Console->UnpauseEvent != NULL) return STATUS_PENDING;
809
810 if (Unicode)
811 {
812 Buffer = StringBuffer;
813 }
814 else
815 {
816 Length = MultiByteToWideChar(Console->OutputCodePage, 0,
817 (PCHAR)StringBuffer,
818 NumCharsToWrite,
819 NULL, 0);
820 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
821 if (Buffer)
822 {
823 MultiByteToWideChar(Console->OutputCodePage, 0,
824 (PCHAR)StringBuffer,
825 NumCharsToWrite,
826 (PWCHAR)Buffer, Length);
827 }
828 else
829 {
830 Status = STATUS_NO_MEMORY;
831 }
832 }
833
834 if (Buffer)
835 {
836 if (NT_SUCCESS(Status))
837 {
838 Status = ConioWriteConsole(Console,
839 ScreenBuffer,
840 Buffer,
841 NumCharsToWrite,
842 TRUE);
843 if (NT_SUCCESS(Status))
844 {
845 Written = NumCharsToWrite;
846 }
847 }
848
849 if (!Unicode) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
850 }
851
852 if (NumCharsWritten) *NumCharsWritten = Written;
853
854 return Status;
855 }
856
857 NTSTATUS NTAPI
858 ConDrvReadConsoleOutputString(IN PCONSOLE Console,
859 IN PTEXTMODE_SCREEN_BUFFER Buffer,
860 IN CODE_TYPE CodeType,
861 OUT PVOID StringBuffer,
862 IN ULONG NumCodesToRead,
863 IN PCOORD ReadCoord,
864 // OUT PCOORD EndCoord,
865 OUT PULONG NumCodesRead OPTIONAL)
866 {
867 SHORT Xpos, Ypos;
868 PVOID ReadBuffer;
869 ULONG i;
870 ULONG CodeSize;
871 PCHAR_INFO Ptr;
872
873 if (Console == NULL || Buffer == NULL || ReadCoord == NULL /* || EndCoord == NULL */)
874 {
875 return STATUS_INVALID_PARAMETER;
876 }
877
878 /* Validity checks */
879 ASSERT(Console == Buffer->Header.Console);
880 ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCodesToRead == 0));
881
882 if (NumCodesRead) *NumCodesRead = 0;
883
884 switch (CodeType)
885 {
886 case CODE_ASCII:
887 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
888 break;
889
890 case CODE_UNICODE:
891 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
892 break;
893
894 case CODE_ATTRIBUTE:
895 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
896 break;
897
898 default:
899 return STATUS_INVALID_PARAMETER;
900 }
901
902 ReadBuffer = StringBuffer;
903 Xpos = ReadCoord->X;
904 Ypos = (ReadCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
905
906 /*
907 * MSDN (ReadConsoleOutputAttribute and ReadConsoleOutputCharacter) :
908 *
909 * If the number of attributes (resp. characters) to be read from extends
910 * beyond the end of the specified screen buffer row, attributes (resp.
911 * characters) are read from the next row. If the number of attributes
912 * (resp. characters) to be read from extends beyond the end of the console
913 * screen buffer, attributes (resp. characters) up to the end of the console
914 * screen buffer are read.
915 *
916 * TODO: Do NOT loop up to NumCodesToRead, but stop before
917 * if we are going to overflow...
918 */
919 // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work
920 for (i = 0; i < min(NumCodesToRead, Buffer->ScreenBufferSize.X * Buffer->ScreenBufferSize.Y); ++i)
921 {
922 // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work either
923 Ptr = &Buffer->Buffer[Xpos + Ypos * Buffer->ScreenBufferSize.X];
924
925 switch (CodeType)
926 {
927 case CODE_ASCII:
928 ConsoleUnicodeCharToAnsiChar(Console, (PCHAR)ReadBuffer, &Ptr->Char.UnicodeChar);
929 break;
930
931 case CODE_UNICODE:
932 *(PWCHAR)ReadBuffer = Ptr->Char.UnicodeChar;
933 break;
934
935 case CODE_ATTRIBUTE:
936 *(PWORD)ReadBuffer = Ptr->Attributes;
937 break;
938 }
939 ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize);
940 // ++Ptr;
941
942 Xpos++;
943
944 if (Xpos == Buffer->ScreenBufferSize.X)
945 {
946 Xpos = 0;
947 Ypos++;
948
949 if (Ypos == Buffer->ScreenBufferSize.Y)
950 {
951 Ypos = 0;
952 }
953 }
954 }
955
956 // EndCoord->X = Xpos;
957 // EndCoord->Y = (Ypos - Buffer->VirtualY + Buffer->ScreenBufferSize.Y) % Buffer->ScreenBufferSize.Y;
958
959 if (NumCodesRead)
960 *NumCodesRead = (ULONG)((ULONG_PTR)ReadBuffer - (ULONG_PTR)StringBuffer) / CodeSize;
961 // <= NumCodesToRead
962
963 return STATUS_SUCCESS;
964 }
965
966 NTSTATUS NTAPI
967 ConDrvWriteConsoleOutputString(IN PCONSOLE Console,
968 IN PTEXTMODE_SCREEN_BUFFER Buffer,
969 IN CODE_TYPE CodeType,
970 IN PVOID StringBuffer,
971 IN ULONG NumCodesToWrite,
972 IN PCOORD WriteCoord,
973 // OUT PCOORD EndCoord,
974 OUT PULONG NumCodesWritten OPTIONAL)
975 {
976 NTSTATUS Status = STATUS_SUCCESS;
977 PVOID WriteBuffer = NULL;
978 PWCHAR tmpString = NULL;
979 DWORD X, Y, Length; // , Written = 0;
980 ULONG CodeSize;
981 PCHAR_INFO Ptr;
982
983 if (Console == NULL || Buffer == NULL || WriteCoord == NULL /* || EndCoord == NULL */)
984 {
985 return STATUS_INVALID_PARAMETER;
986 }
987
988 /* Validity checks */
989 ASSERT(Console == Buffer->Header.Console);
990 ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCodesToWrite == 0));
991
992 if (NumCodesWritten) *NumCodesWritten = 0;
993
994 switch (CodeType)
995 {
996 case CODE_ASCII:
997 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
998 break;
999
1000 case CODE_UNICODE:
1001 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
1002 break;
1003
1004 case CODE_ATTRIBUTE:
1005 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
1006 break;
1007
1008 default:
1009 return STATUS_INVALID_PARAMETER;
1010 }
1011
1012 if (CodeType == CODE_ASCII)
1013 {
1014 /* Convert the ASCII string into Unicode before writing it to the console */
1015 Length = MultiByteToWideChar(Console->OutputCodePage, 0,
1016 (PCHAR)StringBuffer,
1017 NumCodesToWrite,
1018 NULL, 0);
1019 tmpString = WriteBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
1020 if (WriteBuffer)
1021 {
1022 MultiByteToWideChar(Console->OutputCodePage, 0,
1023 (PCHAR)StringBuffer,
1024 NumCodesToWrite,
1025 (PWCHAR)WriteBuffer, Length);
1026 }
1027 else
1028 {
1029 Status = STATUS_NO_MEMORY;
1030 }
1031
1032 // FIXME: Quick fix: fix the CodeType and CodeSize since the
1033 // ASCII string was converted into UNICODE.
1034 // A proper fix needs to be written.
1035 CodeType = CODE_UNICODE;
1036 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
1037 }
1038 else
1039 {
1040 /* For CODE_UNICODE or CODE_ATTRIBUTE, we are already OK */
1041 WriteBuffer = StringBuffer;
1042 }
1043
1044 if (WriteBuffer == NULL || !NT_SUCCESS(Status)) goto Cleanup;
1045
1046 X = WriteCoord->X;
1047 Y = (WriteCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
1048 Length = NumCodesToWrite;
1049 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
1050 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
1051
1052 while (Length--)
1053 {
1054 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
1055 Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X];
1056
1057 switch (CodeType)
1058 {
1059 case CODE_ASCII:
1060 case CODE_UNICODE:
1061 Ptr->Char.UnicodeChar = *(PWCHAR)WriteBuffer;
1062 break;
1063
1064 case CODE_ATTRIBUTE:
1065 Ptr->Attributes = *(PWORD)WriteBuffer;
1066 break;
1067 }
1068 WriteBuffer = (PVOID)((ULONG_PTR)WriteBuffer + CodeSize);
1069 // ++Ptr;
1070
1071 // Written++;
1072 if (++X == Buffer->ScreenBufferSize.X)
1073 {
1074 X = 0;
1075
1076 if (++Y == Buffer->ScreenBufferSize.Y)
1077 {
1078 Y = 0;
1079 }
1080 }
1081 }
1082
1083 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
1084 {
1085 SMALL_RECT UpdateRect;
1086 ConioComputeUpdateRect(Buffer, &UpdateRect, WriteCoord, NumCodesToWrite);
1087 TermDrawRegion(Console, &UpdateRect);
1088 }
1089
1090 // EndCoord->X = X;
1091 // EndCoord->Y = (Y + Buffer->ScreenBufferSize.Y - Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
1092
1093 Cleanup:
1094 if (tmpString) RtlFreeHeap(RtlGetProcessHeap(), 0, tmpString);
1095
1096 if (NumCodesWritten) *NumCodesWritten = NumCodesToWrite; // Written;
1097 return Status;
1098 }
1099
1100 NTSTATUS NTAPI
1101 ConDrvFillConsoleOutput(IN PCONSOLE Console,
1102 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1103 IN CODE_TYPE CodeType,
1104 IN CODE_ELEMENT Code,
1105 IN ULONG NumCodesToWrite,
1106 IN PCOORD WriteCoord,
1107 OUT PULONG NumCodesWritten OPTIONAL)
1108 {
1109 DWORD X, Y, Length; // , Written = 0;
1110 PCHAR_INFO Ptr;
1111
1112 if (Console == NULL || Buffer == NULL || WriteCoord == NULL)
1113 {
1114 return STATUS_INVALID_PARAMETER;
1115 }
1116
1117 /* Validity check */
1118 ASSERT(Console == Buffer->Header.Console);
1119
1120 if (NumCodesWritten) *NumCodesWritten = 0;
1121
1122 if (CodeType == CODE_ASCII)
1123 {
1124 /* Conversion from the ASCII char to the UNICODE char */
1125 CODE_ELEMENT tmp;
1126 ConsoleAnsiCharToUnicodeChar(Console, &tmp.UnicodeChar, &Code.AsciiChar);
1127 Code = tmp;
1128 }
1129
1130 X = WriteCoord->X;
1131 Y = (WriteCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
1132 Length = NumCodesToWrite;
1133 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
1134 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
1135
1136 while (Length--)
1137 {
1138 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
1139 Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X];
1140
1141 switch (CodeType)
1142 {
1143 case CODE_ASCII:
1144 case CODE_UNICODE:
1145 Ptr->Char.UnicodeChar = Code.UnicodeChar;
1146 break;
1147
1148 case CODE_ATTRIBUTE:
1149 Ptr->Attributes = Code.Attribute;
1150 break;
1151 }
1152 // ++Ptr;
1153
1154 // Written++;
1155 if (++X == Buffer->ScreenBufferSize.X)
1156 {
1157 X = 0;
1158
1159 if (++Y == Buffer->ScreenBufferSize.Y)
1160 {
1161 Y = 0;
1162 }
1163 }
1164 }
1165
1166 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
1167 {
1168 SMALL_RECT UpdateRect;
1169 ConioComputeUpdateRect(Buffer, &UpdateRect, WriteCoord, NumCodesToWrite);
1170 TermDrawRegion(Console, &UpdateRect);
1171 }
1172
1173 if (NumCodesWritten) *NumCodesWritten = NumCodesToWrite; // Written;
1174 return STATUS_SUCCESS;
1175 }
1176
1177 NTSTATUS NTAPI
1178 ConDrvGetConsoleScreenBufferInfo(IN PCONSOLE Console,
1179 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1180 OUT PCOORD ScreenBufferSize,
1181 OUT PCOORD CursorPosition,
1182 OUT PCOORD ViewOrigin,
1183 OUT PCOORD ViewSize,
1184 OUT PCOORD MaximumViewSize,
1185 OUT PWORD Attributes)
1186 {
1187 if (Console == NULL || Buffer == NULL || ScreenBufferSize == NULL ||
1188 CursorPosition == NULL || ViewOrigin == NULL || ViewSize == NULL ||
1189 MaximumViewSize == NULL || Attributes == NULL)
1190 {
1191 return STATUS_INVALID_PARAMETER;
1192 }
1193
1194 /* Validity check */
1195 ASSERT(Console == Buffer->Header.Console);
1196
1197 *ScreenBufferSize = Buffer->ScreenBufferSize;
1198 *CursorPosition = Buffer->CursorPosition;
1199 *ViewOrigin = Buffer->ViewOrigin;
1200 *ViewSize = Buffer->ViewSize;
1201 *Attributes = Buffer->ScreenDefaultAttrib;
1202
1203 // FIXME: Refine the computation
1204 *MaximumViewSize = Buffer->ScreenBufferSize;
1205
1206 return STATUS_SUCCESS;
1207 }
1208
1209 NTSTATUS NTAPI
1210 ConDrvSetConsoleTextAttribute(IN PCONSOLE Console,
1211 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1212 IN WORD Attributes)
1213 {
1214 if (Console == NULL || Buffer == NULL)
1215 return STATUS_INVALID_PARAMETER;
1216
1217 /* Validity check */
1218 ASSERT(Console == Buffer->Header.Console);
1219
1220 Buffer->ScreenDefaultAttrib = Attributes;
1221 return STATUS_SUCCESS;
1222 }
1223
1224 NTSTATUS NTAPI
1225 ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console,
1226 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1227 IN PCOORD Size)
1228 {
1229 NTSTATUS Status;
1230
1231 if (Console == NULL || Buffer == NULL || Size == NULL)
1232 return STATUS_INVALID_PARAMETER;
1233
1234 /* Validity check */
1235 ASSERT(Console == Buffer->Header.Console);
1236
1237 Status = ConioResizeBuffer(Console, Buffer, *Size);
1238 if (NT_SUCCESS(Status)) TermResizeTerminal(Console);
1239
1240 return Status;
1241 }
1242
1243 NTSTATUS NTAPI
1244 ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
1245 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1246 IN BOOLEAN Unicode,
1247 IN PSMALL_RECT ScrollRectangle,
1248 IN BOOLEAN UseClipRectangle,
1249 IN PSMALL_RECT ClipRectangle OPTIONAL,
1250 IN PCOORD DestinationOrigin,
1251 IN CHAR_INFO FillChar)
1252 {
1253 COORD CapturedDestinationOrigin;
1254 SMALL_RECT ScreenBuffer;
1255 SMALL_RECT SrcRegion;
1256 SMALL_RECT DstRegion;
1257 SMALL_RECT UpdateRegion;
1258 SMALL_RECT CapturedClipRectangle;
1259
1260 if (Console == NULL || Buffer == NULL || ScrollRectangle == NULL ||
1261 (UseClipRectangle ? ClipRectangle == NULL : FALSE) || DestinationOrigin == NULL)
1262 {
1263 return STATUS_INVALID_PARAMETER;
1264 }
1265
1266 /* Validity check */
1267 ASSERT(Console == Buffer->Header.Console);
1268
1269 CapturedDestinationOrigin = *DestinationOrigin;
1270
1271 /* Make sure the source rectangle is inside the screen buffer */
1272 ConioInitRect(&ScreenBuffer, 0, 0,
1273 Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1);
1274 if (!ConioGetIntersection(&SrcRegion, &ScreenBuffer, ScrollRectangle))
1275 {
1276 return STATUS_SUCCESS;
1277 }
1278
1279 /* If the source was clipped on the left or top, adjust the destination accordingly */
1280 if (ScrollRectangle->Left < 0)
1281 {
1282 CapturedDestinationOrigin.X -= ScrollRectangle->Left;
1283 }
1284 if (ScrollRectangle->Top < 0)
1285 {
1286 CapturedDestinationOrigin.Y -= ScrollRectangle->Top;
1287 }
1288
1289 if (UseClipRectangle)
1290 {
1291 CapturedClipRectangle = *ClipRectangle;
1292 if (!ConioGetIntersection(&CapturedClipRectangle, &CapturedClipRectangle, &ScreenBuffer))
1293 {
1294 return STATUS_SUCCESS;
1295 }
1296 }
1297 else
1298 {
1299 CapturedClipRectangle = ScreenBuffer;
1300 }
1301
1302 ConioInitRect(&DstRegion,
1303 CapturedDestinationOrigin.Y,
1304 CapturedDestinationOrigin.X,
1305 CapturedDestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1,
1306 CapturedDestinationOrigin.X + ConioRectWidth(&SrcRegion ) - 1);
1307
1308 if (!Unicode)
1309 {
1310 WCHAR tmp;
1311 ConsoleAnsiCharToUnicodeChar(Console, &tmp, &FillChar.Char.AsciiChar);
1312 FillChar.Char.UnicodeChar = tmp;
1313 }
1314
1315 ConioMoveRegion(Buffer, &SrcRegion, &DstRegion, &CapturedClipRectangle, FillChar);
1316
1317 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
1318 {
1319 ConioGetUnion(&UpdateRegion, &SrcRegion, &DstRegion);
1320 if (ConioGetIntersection(&UpdateRegion, &UpdateRegion, &CapturedClipRectangle))
1321 {
1322 /* Draw update region */
1323 TermDrawRegion(Console, &UpdateRegion);
1324 }
1325 }
1326
1327 return STATUS_SUCCESS;
1328 }
1329
1330 NTSTATUS NTAPI
1331 ConDrvSetConsoleWindowInfo(IN PCONSOLE Console,
1332 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1333 IN BOOLEAN Absolute,
1334 IN PSMALL_RECT WindowRect)
1335 {
1336 SMALL_RECT CapturedWindowRect;
1337
1338 if (Console == NULL || Buffer == NULL || WindowRect == NULL)
1339 return STATUS_INVALID_PARAMETER;
1340
1341 /* Validity check */
1342 ASSERT(Console == Buffer->Header.Console);
1343
1344 CapturedWindowRect = *WindowRect;
1345
1346 if (Absolute == FALSE)
1347 {
1348 /* Relative positions given. Transform them to absolute ones */
1349 CapturedWindowRect.Left += Buffer->ViewOrigin.X;
1350 CapturedWindowRect.Top += Buffer->ViewOrigin.Y;
1351 CapturedWindowRect.Right += Buffer->ViewOrigin.X + Buffer->ViewSize.X - 1;
1352 CapturedWindowRect.Bottom += Buffer->ViewOrigin.Y + Buffer->ViewSize.Y - 1;
1353 }
1354
1355 /* See MSDN documentation on SetConsoleWindowInfo about the performed checks */
1356 if ( (CapturedWindowRect.Left < 0) || (CapturedWindowRect.Top < 0) ||
1357 (CapturedWindowRect.Right >= Buffer->ScreenBufferSize.X) ||
1358 (CapturedWindowRect.Bottom >= Buffer->ScreenBufferSize.Y) ||
1359 (CapturedWindowRect.Right <= CapturedWindowRect.Left) ||
1360 (CapturedWindowRect.Bottom <= CapturedWindowRect.Top) )
1361 {
1362 return STATUS_INVALID_PARAMETER;
1363 }
1364
1365 Buffer->ViewOrigin.X = CapturedWindowRect.Left;
1366 Buffer->ViewOrigin.Y = CapturedWindowRect.Top;
1367
1368 Buffer->ViewSize.X = CapturedWindowRect.Right - CapturedWindowRect.Left + 1;
1369 Buffer->ViewSize.Y = CapturedWindowRect.Bottom - CapturedWindowRect.Top + 1;
1370
1371 // TermResizeTerminal(Console);
1372
1373 return STATUS_SUCCESS;
1374 }
1375
1376 /* EOF */