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