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