- Implemented double buffering for a console windows. Currently the second buffer
[reactos.git] / reactos / subsys / csrss / win32csr / guiconsole.c
1 /* $Id: guiconsole.c,v 1.11 2004/03/07 21:00:11 hbirr Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: subsys/csrss/win32csr/guiconsole.c
6 * PURPOSE: Implementation of gui-mode consoles
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <windows.h>
12 #include "conio.h"
13 #include "guiconsole.h"
14 #include "win32csr.h"
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* Not defined in any header file */
20 extern VOID STDCALL PrivateCsrssManualGuiCheck(LONG Check);
21
22 /* GLOBALS *******************************************************************/
23
24 typedef struct GUI_CONSOLE_DATA_TAG
25 {
26 HFONT Font;
27 unsigned CharWidth;
28 unsigned CharHeight;
29 PWCHAR LineBuffer;
30 BOOL CursorBlinkOn;
31 BOOL ForceCursorOff;
32 CRITICAL_SECTION Lock;
33 HDC MemoryDC;
34 HBITMAP MemoryBitmap;
35 } GUI_CONSOLE_DATA, *PGUI_CONSOLE_DATA;
36
37 #ifndef WM_APP
38 #define WM_APP 0x8000
39 #endif
40 #define PM_CREATE_CONSOLE (WM_APP + 1)
41 #define PM_DESTROY_CONSOLE (WM_APP + 2)
42
43 #define CURSOR_BLINK_TIME 500
44
45 static BOOL Initialized = FALSE;
46 static HWND NotifyWnd;
47
48 /* FUNCTIONS *****************************************************************/
49
50 static VOID FASTCALL
51 GuiConsoleGetDataPointers(HWND hWnd, PCSRSS_CONSOLE *Console, PGUI_CONSOLE_DATA *GuiData)
52 {
53 *Console = (PCSRSS_CONSOLE) GetWindowLongW(hWnd, GWL_USERDATA);
54 *GuiData = (NULL == *Console ? NULL : (*Console)->PrivateData);
55 }
56
57 static BOOL FASTCALL
58 GuiConsoleHandleNcCreate(HWND hWnd, CREATESTRUCTW *Create)
59 {
60 RECT Rect;
61 PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) Create->lpCreateParams;
62 PGUI_CONSOLE_DATA GuiData;
63 HDC Dc;
64 HFONT OldFont;
65 TEXTMETRICW Metrics;
66 NTSTATUS Status;
67
68 GuiData = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY,
69 sizeof(GUI_CONSOLE_DATA) +
70 (Console->Size.X + 1) * sizeof(WCHAR));
71 if (NULL == GuiData)
72 {
73 DPRINT1("GuiConsoleNcCreate: HeapAlloc failed\n");
74 return FALSE;
75 }
76
77 Status = RtlInitializeCriticalSection(&GuiData->Lock);
78 if (!NT_SUCCESS(Status))
79 {
80 DPRINT1("RtlInitializeCriticalSection failed, Status=%x\n", Status);
81 HeapFree(Win32CsrApiHeap, 0, GuiData);
82 return FALSE;
83 }
84
85 GuiData->LineBuffer = (PWCHAR)(GuiData + 1);
86
87 GuiData->Font = CreateFontW(12, 0, 0, TA_BASELINE, FW_NORMAL,
88 FALSE, FALSE, FALSE, ANSI_CHARSET,
89 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
90 DEFAULT_QUALITY, FIXED_PITCH | FF_DONTCARE,
91 L"Bitstream Vera Sans Mono");
92 if (NULL == GuiData->Font)
93 {
94 DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
95 RtlDeleteCriticalSection(&GuiData->Lock);
96 HeapFree(Win32CsrApiHeap, 0, GuiData);
97 return FALSE;
98 }
99 Dc = GetDC(hWnd);
100 if (NULL == Dc)
101 {
102 DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
103 DeleteObject(GuiData->Font);
104 RtlDeleteCriticalSection(&GuiData->Lock);
105 HeapFree(Win32CsrApiHeap, 0, GuiData);
106 return FALSE;
107 }
108 OldFont = SelectObject(Dc, GuiData->Font);
109 if (NULL == OldFont)
110 {
111 DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
112 ReleaseDC(hWnd, Dc);
113 DeleteObject(GuiData->Font);
114 RtlDeleteCriticalSection(&GuiData->Lock);
115 HeapFree(Win32CsrApiHeap, 0, GuiData);
116 return FALSE;
117 }
118 if (! GetTextMetricsW(Dc, &Metrics))
119 {
120 DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
121 SelectObject(Dc, OldFont);
122 ReleaseDC(hWnd, Dc);
123 DeleteObject(GuiData->Font);
124 RtlDeleteCriticalSection(&GuiData->Lock);
125 HeapFree(Win32CsrApiHeap, 0, GuiData);
126 return FALSE;
127 }
128 GuiData->CharWidth = Metrics.tmMaxCharWidth;
129 GuiData->CharHeight = Metrics.tmHeight + Metrics.tmExternalLeading;
130 SelectObject(Dc, OldFont);
131
132 GuiData->MemoryDC = CreateCompatibleDC(Dc);
133 GuiData->MemoryBitmap = CreateCompatibleBitmap(Dc,
134 Console->Size.X * GuiData->CharWidth,
135 Console->Size.Y * GuiData->CharHeight);
136 DeleteObject(SelectObject(GuiData->MemoryDC, GuiData->MemoryBitmap));
137 DeleteObject(SelectObject(GuiData->MemoryDC, GuiData->Font));
138
139
140 ReleaseDC(hWnd, Dc);
141 GuiData->CursorBlinkOn = TRUE;
142 GuiData->ForceCursorOff = FALSE;
143
144 Console->PrivateData = GuiData;
145 SetWindowLongW(hWnd, GWL_USERDATA, (LONG) Console);
146
147 GetWindowRect(hWnd, &Rect);
148 Rect.right = Rect.left + Console->Size.X * GuiData->CharWidth +
149 2 * GetSystemMetrics(SM_CXFIXEDFRAME);
150 Rect.bottom = Rect.top + Console->Size.Y * GuiData->CharHeight +
151 2 * GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYCAPTION);
152 MoveWindow(hWnd, Rect.left, Rect.top, Rect.right - Rect.left,
153 Rect.bottom - Rect.top, FALSE);
154
155 SetTimer(hWnd, 1, CURSOR_BLINK_TIME, NULL);
156
157 return (BOOL) DefWindowProcW(hWnd, WM_NCCREATE, 0, (LPARAM) Create);
158 }
159
160 static COLORREF FASTCALL
161 GuiConsoleRGBFromAttribute(BYTE Attribute)
162 {
163 int Red = (Attribute & 0x04 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);
164 int Green = (Attribute & 0x02 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);
165 int Blue = (Attribute & 0x01 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);
166
167 return RGB(Red, Green, Blue);
168 }
169
170 static VOID FASTCALL
171 GuiConsoleSetTextColors(HDC Dc, BYTE Attribute)
172 {
173 SetTextColor(Dc, GuiConsoleRGBFromAttribute(Attribute & 0x0f));
174 SetBkColor(Dc, GuiConsoleRGBFromAttribute((Attribute & 0xf0) >> 4));
175 }
176
177 static VOID FASTCALL
178 GuiConsoleGetLogicalCursorPos(PCSRSS_SCREEN_BUFFER Buff, ULONG *CursorX, ULONG *CursorY)
179 {
180 *CursorX = Buff->CurrentX;
181 if (Buff->CurrentY < Buff->ShowY)
182 {
183 *CursorY = Buff->MaxY - Buff->ShowY + Buff->CurrentY;
184 }
185 else
186 {
187 *CursorY = Buff->CurrentY - Buff->ShowY;
188 }
189 }
190
191 VOID FASTCALL
192 GuiConsoleUpdateBitmap(HWND hWnd, RECT rc)
193 {
194 PCSRSS_CONSOLE Console;
195 PGUI_CONSOLE_DATA GuiData;
196 PCSRSS_SCREEN_BUFFER Buff;
197 HDC Dc;
198 ULONG TopLine, BottomLine, LeftChar, RightChar;
199 ULONG Line, Char, Start;
200 PBYTE From;
201 PWCHAR To;
202 BYTE LastAttribute, Attribute;
203 ULONG CursorX, CursorY, CursorHeight;
204 HBRUSH CursorBrush, OldBrush;
205
206 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
207 if (NULL != Console && NULL != GuiData && NULL != Console->ActiveBuffer)
208 {
209 Buff = Console->ActiveBuffer;
210 EnterCriticalSection(&Buff->Header.Lock);
211 Dc = GetDC(hWnd);
212 if (rc.right <= rc.left || rc.bottom <= rc.top)
213 {
214 ReleaseDC(hWnd, Dc);
215 LeaveCriticalSection(&Buff->Header.Lock);
216 return;
217 }
218
219 EnterCriticalSection(&GuiData->Lock);
220
221 TopLine = rc.top / GuiData->CharHeight;
222 BottomLine = (rc.bottom + (GuiData->CharHeight - 1)) / GuiData->CharHeight - 1;
223 LeftChar = rc.left / GuiData->CharWidth;
224 RightChar = (rc.right + (GuiData->CharWidth - 1)) / GuiData->CharWidth - 1;
225 LastAttribute = Buff->Buffer[(TopLine * Buff->MaxX + LeftChar) * 2 + 1];
226 GuiConsoleSetTextColors(GuiData->MemoryDC, LastAttribute);
227
228 for (Line = TopLine; Line <= BottomLine; Line++)
229 {
230 if (Line + Buff->ShowY < Buff->MaxY)
231 {
232 From = Buff->Buffer + ((Line + Buff->ShowY) * Buff->MaxX + LeftChar) * 2;
233 }
234 else
235 {
236 From = Buff->Buffer +
237 ((Line - (Buff->MaxY - Buff->ShowY)) * Buff->MaxX + LeftChar) * 2;
238 }
239 Attribute = *(From + 1);
240 Start = LeftChar;
241 To = GuiData->LineBuffer;
242 for (Char = LeftChar; Char <= RightChar; Char++)
243 {
244 if (*(From + 1) != Attribute)
245 {
246 TextOutW(GuiData->MemoryDC, Start * GuiData->CharWidth, Line * GuiData->CharHeight,
247 GuiData->LineBuffer, Char - Start);
248 Start = Char;
249 To = GuiData->LineBuffer;
250 Attribute = *(From + 1);
251 if (Attribute != LastAttribute)
252 {
253 GuiConsoleSetTextColors(GuiData->MemoryDC, Attribute);
254 LastAttribute = Attribute;
255 }
256 }
257 *((PBYTE) To) = *From;
258 *(((PBYTE) To) + 1) = '\0';
259 To++;
260 From += 2;
261 }
262 TextOutW(GuiData->MemoryDC, Start * GuiData->CharWidth, Line * GuiData->CharHeight,
263 GuiData->LineBuffer, RightChar - Start + 1);
264 }
265
266 if (Buff->CursorInfo.bVisible && GuiData->CursorBlinkOn
267 &&! GuiData->ForceCursorOff)
268 {
269 GuiConsoleGetLogicalCursorPos(Buff, &CursorX, &CursorY);
270 if (LeftChar <= CursorX && CursorX <= RightChar &&
271 TopLine <= CursorY && CursorY <= BottomLine)
272 {
273 CursorHeight = (GuiData->CharHeight * Buff->CursorInfo.dwSize) / 100;
274 if (CursorHeight < 1)
275 {
276 CursorHeight = 1;
277 }
278 From = Buff->Buffer + (Buff->CurrentY * Buff->MaxX + Buff->CurrentX) * 2 + 1;
279 CursorBrush = CreateSolidBrush(GuiConsoleRGBFromAttribute(*From));
280 OldBrush = SelectObject(GuiData->MemoryDC, CursorBrush);
281 PatBlt(GuiData->MemoryDC, CursorX * GuiData->CharWidth,
282 CursorY * GuiData->CharHeight + (GuiData->CharHeight - CursorHeight),
283 GuiData->CharWidth, CursorHeight, PATCOPY);
284 SelectObject(GuiData->MemoryDC, OldBrush);
285 DeleteObject(CursorBrush);
286 }
287 }
288
289 LeaveCriticalSection(&GuiData->Lock);
290 ReleaseDC(hWnd, Dc);
291 LeaveCriticalSection(&Buff->Header.Lock);
292 InvalidateRect(hWnd, &rc, FALSE);
293 }
294
295 }
296
297 VOID FASTCALL
298 GuiConsoleHandlePaint(HWND hWnd)
299 {
300 PAINTSTRUCT Ps;
301 HDC Dc;
302 PCSRSS_CONSOLE Console;
303 PGUI_CONSOLE_DATA GuiData;
304
305 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
306 if (NULL != Console && NULL != GuiData)
307 {
308 EnterCriticalSection(&GuiData->Lock);
309 Dc = BeginPaint (hWnd, &Ps);
310 BitBlt(Dc, Ps.rcPaint.left, Ps.rcPaint.top,
311 Ps.rcPaint.right - Ps.rcPaint.left + 1,
312 Ps.rcPaint.bottom - Ps.rcPaint.top + 1, GuiData->MemoryDC,
313 Ps.rcPaint.left, Ps.rcPaint.top, SRCCOPY);
314 EndPaint (hWnd, &Ps);
315 LeaveCriticalSection(&GuiData->Lock);
316 }
317 else
318 {
319 Dc = BeginPaint (hWnd, &Ps);
320 EndPaint (hWnd, &Ps);
321 }
322 }
323
324 static VOID FASTCALL
325 GuiConsoleHandleKey(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
326 {
327 PCSRSS_CONSOLE Console;
328 PGUI_CONSOLE_DATA GuiData;
329 MSG Message;
330
331 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
332 Message.hwnd = hWnd;
333 Message.message = msg;
334 Message.wParam = wParam;
335 Message.lParam = lParam;
336
337 ConioProcessKey(&Message, Console, FALSE);
338 }
339
340 static VOID FASTCALL
341 GuiIntDrawRegion(PGUI_CONSOLE_DATA GuiData, HWND Wnd, RECT *Region)
342 {
343 RECT RegionRect;
344
345 RegionRect.left = Region->left * GuiData->CharWidth;
346 RegionRect.top = Region->top * GuiData->CharHeight;
347 RegionRect.right = (Region->right + 1) * GuiData->CharWidth;
348 RegionRect.bottom = (Region->bottom + 1) * GuiData->CharHeight;
349
350 GuiConsoleUpdateBitmap(Wnd, RegionRect);
351 }
352
353 static VOID STDCALL
354 GuiDrawRegion(PCSRSS_CONSOLE Console, RECT *Region)
355 {
356 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA) Console->PrivateData;
357
358 if (NULL == Console->hWindow || NULL == GuiData)
359 {
360 return;
361 }
362
363 GuiIntDrawRegion(GuiData, Console->hWindow, Region);
364 }
365
366 static VOID FASTCALL
367 GuiInvalidateCell(PGUI_CONSOLE_DATA GuiData, HWND Wnd, UINT x, UINT y)
368 {
369 RECT CellRect;
370
371 CellRect.left = x;
372 CellRect.top = y;
373 CellRect.right = x;
374 CellRect.bottom = y;
375
376 GuiIntDrawRegion(GuiData, Wnd, &CellRect);
377 }
378
379 static VOID STDCALL
380 GuiWriteStream(PCSRSS_CONSOLE Console, RECT *Region, UINT CursorStartX, UINT CursorStartY,
381 UINT ScrolledLines, CHAR *Buffer, UINT Length)
382 {
383 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA) Console->PrivateData;
384 PCSRSS_SCREEN_BUFFER Buff = Console->ActiveBuffer;
385 LONG CursorEndX, CursorEndY;
386 RECT Source, Dest;
387
388 if (NULL == Console->hWindow || NULL == GuiData)
389 {
390 return;
391 }
392
393 if (0 != ScrolledLines)
394 {
395 Source.left = 0;
396 Source.top = ScrolledLines;
397 Source.right = Console->Size.X - 1;
398 Source.bottom = ScrolledLines + Region->top - 1;
399 Dest.left = 0;
400 Dest.top = 0;
401 Dest.right = Console->Size.X - 1;
402 Dest.bottom = Region->top - 1;
403
404 GuiConsoleCopyRegion(Console->hWindow, &Source, &Dest);
405 }
406
407 GuiIntDrawRegion(GuiData, Console->hWindow, Region);
408
409 if (CursorStartX < Region->left || Region->right < CursorStartX
410 || CursorStartY < Region->top || Region->bottom < CursorStartY)
411 {
412 GuiInvalidateCell(GuiData, Console->hWindow, CursorStartX, CursorStartY);
413 }
414
415 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY,
416 &CursorEndX, &CursorEndY);
417 if ((CursorEndX < Region->left || Region->right < CursorEndX
418 || CursorEndY < Region->top || Region->bottom < CursorEndY)
419 && (CursorEndX != CursorStartX || CursorEndY != CursorStartY))
420 {
421 GuiInvalidateCell(GuiData, Console->hWindow, CursorEndX, CursorEndY);
422 }
423 }
424
425 static BOOL STDCALL
426 GuiSetCursorInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff)
427 {
428 RECT UpdateRect;
429
430 if (Console->ActiveBuffer == Buff)
431 {
432 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY,
433 &UpdateRect.left, &UpdateRect.top);
434 UpdateRect.right = UpdateRect.left;
435 UpdateRect.bottom = UpdateRect.top;
436 ConioDrawRegion(Console, &UpdateRect);
437 }
438
439 return TRUE;
440 }
441
442 static BOOL STDCALL
443 GuiSetScreenInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff, UINT OldCursorX, UINT OldCursorY)
444 {
445 RECT UpdateRect;
446
447 if (Console->ActiveBuffer == Buff)
448 {
449 /* Redraw char at old position (removes cursor) */
450 UpdateRect.left = OldCursorX;
451 UpdateRect.top = OldCursorY;
452 UpdateRect.right = OldCursorX;
453 UpdateRect.bottom = OldCursorY;
454 ConioDrawRegion(Console, &UpdateRect);
455 /* Redraw char at new position (shows cursor) */
456 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY,
457 &(UpdateRect.left), &(UpdateRect.top));
458 UpdateRect.right = UpdateRect.left;
459 UpdateRect.bottom = UpdateRect.top;
460 ConioDrawRegion(Console, &UpdateRect);
461 }
462
463 return TRUE;
464 }
465
466 static VOID FASTCALL
467 GuiConsoleHandleTimer(HWND hWnd)
468 {
469 PCSRSS_CONSOLE Console;
470 PGUI_CONSOLE_DATA GuiData;
471 RECT CursorRect;
472 ULONG CursorX, CursorY;
473
474 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
475 GuiData->CursorBlinkOn = ! GuiData->CursorBlinkOn;
476
477 GuiConsoleGetLogicalCursorPos(Console->ActiveBuffer, &CursorX, &CursorY);
478 CursorRect.left = CursorX;
479 CursorRect.top = CursorY;
480 CursorRect.right = CursorX;
481 CursorRect.bottom = CursorY;
482 GuiDrawRegion(Console, &CursorRect);
483 }
484
485 static VOID FASTCALL
486 GuiConsoleHandleClose(HWND hWnd)
487 {
488 /* FIXME for now, just ignore close requests */
489 }
490
491 static VOID FASTCALL
492 GuiConsoleHandleNcDestroy(HWND hWnd)
493 {
494 PCSRSS_CONSOLE Console;
495 PGUI_CONSOLE_DATA GuiData;
496
497 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
498 KillTimer(hWnd, 1);
499 Console->PrivateData = NULL;
500 DeleteDC(GuiData->MemoryDC);
501 RtlDeleteCriticalSection(&GuiData->Lock);
502 HeapFree(Win32CsrApiHeap, 0, GuiData);
503 }
504
505 static LRESULT CALLBACK
506 GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
507 {
508 LRESULT Result;
509
510 switch(msg)
511 {
512 case WM_NCCREATE:
513 Result = (LRESULT) GuiConsoleHandleNcCreate(hWnd, (CREATESTRUCTW *) lParam);
514 break;
515 case WM_PAINT:
516 GuiConsoleHandlePaint(hWnd);
517 Result = 0;
518 break;
519 case WM_KEYDOWN:
520 case WM_KEYUP:
521 case WM_SYSKEYDOWN:
522 case WM_SYSKEYUP:
523 case WM_CHAR:
524 GuiConsoleHandleKey(hWnd, msg, wParam, lParam);
525 Result = 0;
526 break;
527 case WM_TIMER:
528 GuiConsoleHandleTimer(hWnd);
529 Result = 0;
530 break;
531 case WM_CLOSE:
532 GuiConsoleHandleClose(hWnd);
533 Result = 0;
534 break;
535 case WM_NCDESTROY:
536 GuiConsoleHandleNcDestroy(hWnd);
537 Result = 0;
538 break;
539 default:
540 Result = DefWindowProcW(hWnd, msg, wParam, lParam);
541 break;
542 }
543
544 return Result;
545 }
546
547 static LRESULT CALLBACK
548 GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
549 {
550 HWND NewWindow;
551 LONG WindowCount;
552 PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) lParam;
553
554 switch(msg)
555 {
556 case WM_CREATE:
557 SetWindowLongW(hWnd, GWL_USERDATA, 0);
558 return 0;
559 case PM_CREATE_CONSOLE:
560 NewWindow = CreateWindowW(L"Win32CsrConsole",
561 Console->Title.Buffer,
562 WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
563 CW_USEDEFAULT,
564 CW_USEDEFAULT,
565 CW_USEDEFAULT,
566 CW_USEDEFAULT,
567 NULL,
568 NULL,
569 (HINSTANCE) GetModuleHandleW(NULL),
570 (PVOID) Console);
571 Console->hWindow = NewWindow;
572 if (NULL != NewWindow)
573 {
574 SetWindowLongW(hWnd, GWL_USERDATA, GetWindowLongW(hWnd, GWL_USERDATA) + 1);
575 ShowWindow(NewWindow, SW_SHOW);
576 }
577 return (LRESULT) NewWindow;
578 case PM_DESTROY_CONSOLE:
579 DestroyWindow(Console->hWindow);
580 Console->hWindow = NULL;
581 WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
582 WindowCount--;
583 SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
584 if (0 == WindowCount)
585 {
586 NotifyWnd = NULL;
587 DestroyWindow(hWnd);
588 PrivateCsrssManualGuiCheck(-1);
589 PostQuitMessage(0);
590 }
591 return 0;
592 default:
593 return DefWindowProcW(hWnd, msg, wParam, lParam);
594 }
595 }
596
597 static DWORD STDCALL
598 GuiConsoleGuiThread(PVOID Data)
599 {
600 MSG msg;
601 PHANDLE GraphicsStartupEvent = (PHANDLE) Data;
602
603 NotifyWnd = CreateWindowW(L"Win32CsrCreateNotify",
604 L"",
605 WS_OVERLAPPEDWINDOW,
606 CW_USEDEFAULT,
607 CW_USEDEFAULT,
608 CW_USEDEFAULT,
609 CW_USEDEFAULT,
610 NULL,
611 NULL,
612 (HINSTANCE) GetModuleHandleW(NULL),
613 NULL);
614 if (NULL == NotifyWnd)
615 {
616 PrivateCsrssManualGuiCheck(-1);
617 SetEvent(*GraphicsStartupEvent);
618 return 1;
619 }
620
621 SetEvent(*GraphicsStartupEvent);
622
623 while(GetMessageW(&msg, NULL, 0, 0))
624 {
625 TranslateMessage(&msg);
626 DispatchMessageW(&msg);
627 }
628
629 return 1;
630 }
631
632 static BOOL FASTCALL
633 GuiInit(VOID)
634 {
635 HDESK Desktop;
636 NTSTATUS Status;
637 WNDCLASSEXW wc;
638
639 Desktop = OpenDesktopW(L"Default", 0, FALSE, GENERIC_ALL);
640 if (NULL == Desktop)
641 {
642 DPRINT1("Failed to open desktop\n");
643 return FALSE;
644 }
645 Status = NtSetInformationProcess(NtCurrentProcess(),
646 ProcessDesktop,
647 &Desktop,
648 sizeof(Desktop));
649 if (!NT_SUCCESS(Status))
650 {
651 DPRINT1("Cannot set default desktop.\n");
652 return FALSE;
653 }
654 if (! SetThreadDesktop(Desktop))
655 {
656 DPRINT1("Failed to set thread desktop\n");
657 return FALSE;
658 }
659
660 if (NULL == NotifyWnd)
661 {
662 PrivateCsrssManualGuiCheck(+1);
663 }
664
665 wc.cbSize = sizeof(WNDCLASSEXW);
666 wc.lpszClassName = L"Win32CsrCreateNotify";
667 wc.lpfnWndProc = GuiConsoleNotifyWndProc;
668 wc.style = 0;
669 wc.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
670 wc.hIcon = NULL;
671 wc.hCursor = NULL;
672 wc.hbrBackground = NULL;
673 wc.lpszMenuName = NULL;
674 wc.cbClsExtra = 0;
675 wc.cbWndExtra = 0;
676 wc.hIconSm = NULL;
677 if (RegisterClassExW(&wc) == 0)
678 {
679 DPRINT1("Failed to register notify wndproc\n");
680 return FALSE;
681 }
682
683 wc.cbSize = sizeof(WNDCLASSEXW);
684 wc.lpszClassName = L"Win32CsrConsole";
685 wc.lpfnWndProc = GuiConsoleWndProc;
686 wc.style = 0;
687 wc.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
688 wc.hIcon = LoadIconW(Win32CsrDllHandle, MAKEINTRESOURCEW(1));
689 wc.hCursor = LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_ARROW));
690 wc.hbrBackground = NULL;
691 wc.lpszMenuName = NULL;
692 wc.cbClsExtra = 0;
693 wc.cbWndExtra = 0;
694 wc.hIconSm = LoadImageW(Win32CsrDllHandle, MAKEINTRESOURCEW(1), IMAGE_ICON,
695 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
696 LR_SHARED);
697 if (RegisterClassExW(&wc) == 0)
698 {
699 DPRINT1("Failed to register console wndproc\n");
700 return FALSE;
701 }
702
703 return TRUE;
704 }
705
706 static VOID STDCALL
707 GuiInitScreenBuffer(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buffer)
708 {
709 Buffer->DefaultAttrib = 0x0f;
710 }
711
712 STATIC BOOL STDCALL
713 GuiChangeTitle(PCSRSS_CONSOLE Console)
714 {
715 SendMessageW(Console->hWindow, WM_SETTEXT, 0, (LPARAM) Console->Title.Buffer);
716
717 return TRUE;
718 }
719
720 static VOID STDCALL
721 GuiCleanupConsole(PCSRSS_CONSOLE Console)
722 {
723 SendMessageW(NotifyWnd, PM_DESTROY_CONSOLE, 0, (LPARAM) Console);
724 }
725
726 static CSRSS_CONSOLE_VTBL GuiVtbl =
727 {
728 GuiInitScreenBuffer,
729 GuiWriteStream,
730 GuiDrawRegion,
731 GuiSetCursorInfo,
732 GuiSetScreenInfo,
733 GuiChangeTitle,
734 GuiCleanupConsole
735 };
736
737 NTSTATUS FASTCALL
738 GuiInitConsole(PCSRSS_CONSOLE Console)
739 {
740 HANDLE GraphicsStartupEvent;
741 HANDLE ThreadHandle;
742
743 if (! Initialized)
744 {
745 Initialized = TRUE;
746 if (! GuiInit())
747 {
748 Initialized = FALSE;
749 return STATUS_UNSUCCESSFUL;
750 }
751 }
752
753 Console->Vtbl = &GuiVtbl;
754 Console->Size.X = 80;
755 Console->Size.Y = 25;
756 if (NULL == NotifyWnd)
757 {
758 GraphicsStartupEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
759 if (NULL == GraphicsStartupEvent)
760 {
761 return STATUS_UNSUCCESSFUL;
762 }
763
764 ThreadHandle = CreateThread(NULL,
765 0,
766 GuiConsoleGuiThread,
767 (PVOID) &GraphicsStartupEvent,
768 0,
769 NULL);
770 if (NULL == ThreadHandle)
771 {
772 NtClose(GraphicsStartupEvent);
773 DPRINT1("Win32Csr: Failed to create graphics console thread. Expect problems\n");
774 return STATUS_UNSUCCESSFUL;
775 }
776 SetThreadPriority(ThreadHandle, THREAD_PRIORITY_HIGHEST);
777 CloseHandle(ThreadHandle);
778
779 WaitForSingleObject(GraphicsStartupEvent, INFINITE);
780 CloseHandle(GraphicsStartupEvent);
781
782 if (NULL == NotifyWnd)
783 {
784 DPRINT1("Win32Csr: Failed to create notification window.\n");
785 return STATUS_UNSUCCESSFUL;
786 }
787 }
788
789 PostMessageW(NotifyWnd, PM_CREATE_CONSOLE, 0, (LPARAM) Console);
790
791 return STATUS_SUCCESS;
792 }
793
794 VOID STDCALL
795 GuiConsoleCopyRegion(HWND hWnd,
796 RECT *Source,
797 RECT *Dest)
798 {
799 RECT ScrollRect;
800 PGUI_CONSOLE_DATA GuiData;
801 PCSRSS_CONSOLE Console;
802
803
804 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
805
806 ScrollRect.left = Dest->left * GuiData->CharWidth;
807 ScrollRect.right = (Dest->right + 1) * GuiData->CharWidth;
808 ScrollRect.top = Dest->top * GuiData->CharHeight;
809 ScrollRect.bottom = (Dest->bottom + 1) * GuiData->CharHeight;
810 EnterCriticalSection(&GuiData->Lock);
811 BitBlt(GuiData->MemoryDC, ScrollRect.left, ScrollRect.top,
812 ScrollRect.right - ScrollRect.left, ScrollRect.bottom - ScrollRect.top,
813 GuiData->MemoryDC, Source->left * GuiData->CharWidth, Source->top * GuiData->CharHeight, SRCCOPY);
814
815 LeaveCriticalSection(&GuiData->Lock);
816
817 InvalidateRect(hWnd, &ScrollRect, FALSE);
818 }
819
820 /* EOF */