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