* set FontName array to max of LF_FACESIZE
[reactos.git] / reactos / subsystems / win32 / csrss / win32csr / guiconsole.c
1 /* $Id$
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 "w32csr.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /* Not defined in any header file */
17 extern VOID STDCALL PrivateCsrssManualGuiCheck(LONG Check);
18
19 /* GLOBALS *******************************************************************/
20
21 typedef struct GUI_CONSOLE_DATA_TAG
22 {
23 HFONT Font;
24 unsigned CharWidth;
25 unsigned CharHeight;
26 PWCHAR LineBuffer;
27 BOOL CursorBlinkOn;
28 BOOL ForceCursorOff;
29 CRITICAL_SECTION Lock;
30 RECT Selection;
31 POINT SelectionStart;
32 BOOL MouseDown;
33 HMODULE ConsoleLibrary;
34 HANDLE hGuiInitEvent;
35 WCHAR FontName[LF_FACESIZE];
36 DWORD FontSize;
37 DWORD FontWeight;
38 DWORD CursorSize;
39 DWORD HistoryNoDup;
40 DWORD FullScreen;
41 DWORD QuickEdit;
42 DWORD InsertMode;
43 DWORD WindowSize;
44 } GUI_CONSOLE_DATA, *PGUI_CONSOLE_DATA;
45
46 #ifndef WM_APP
47 #define WM_APP 0x8000
48 #endif
49 #define PM_CREATE_CONSOLE (WM_APP + 1)
50 #define PM_DESTROY_CONSOLE (WM_APP + 2)
51
52 #define CURSOR_BLINK_TIME 500
53
54 static BOOL ConsInitialized = FALSE;
55 static HWND NotifyWnd;
56
57 /* FUNCTIONS *****************************************************************/
58
59 static VOID FASTCALL
60 GuiConsoleGetDataPointers(HWND hWnd, PCSRSS_CONSOLE *Console, PGUI_CONSOLE_DATA *GuiData)
61 {
62 *Console = (PCSRSS_CONSOLE) GetWindowLongPtrW(hWnd, GWL_USERDATA);
63 *GuiData = (NULL == *Console ? NULL : (*Console)->PrivateData);
64 }
65
66 static BOOL FASTCALL
67 GuiConsoleOpenUserRegistryPathPerProcessId(DWORD ProcessId, PHANDLE hProcHandle, PHKEY hResult, REGSAM samDesired)
68 {
69 HANDLE hProcessToken = NULL;
70 HANDLE hProcess;
71
72 BYTE Buffer[256];
73 DWORD Length = 0;
74 UNICODE_STRING SidName;
75 LONG res;
76 PTOKEN_USER TokUser;
77
78 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | READ_CONTROL, FALSE, ProcessId);
79 if (!hProcess)
80 {
81 DPRINT("Error: OpenProcess failed(0x%x)\n", GetLastError());
82 return FALSE;
83 }
84
85 if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hProcessToken))
86 {
87 DPRINT("Error: OpenProcessToken failed(0x%x)\n", GetLastError());
88 CloseHandle(hProcess);
89 return FALSE;
90 }
91
92 if (!GetTokenInformation(hProcessToken, TokenUser, (PVOID)Buffer, sizeof(Buffer), &Length))
93 {
94 DPRINT("Error: GetTokenInformation failed(0x%x)\n",GetLastError());
95 CloseHandle(hProcess);
96 CloseHandle(hProcessToken);
97 return FALSE;
98 }
99
100 TokUser = ((PTOKEN_USER)Buffer)->User.Sid;
101 if (!NT_SUCCESS(RtlConvertSidToUnicodeString(&SidName, TokUser, TRUE)))
102 {
103 DPRINT("Error: RtlConvertSidToUnicodeString failed(0x%x)\n", GetLastError());
104 return FALSE;
105 }
106
107 res = RegOpenKeyExW(HKEY_USERS, SidName.Buffer, 0, samDesired, hResult);
108 RtlFreeUnicodeString(&SidName);
109
110 CloseHandle(hProcessToken);
111 if (hProcHandle)
112 *hProcHandle = hProcess;
113 else
114 CloseHandle(hProcess);
115
116 if (res != ERROR_SUCCESS)
117 return FALSE;
118 else
119 return TRUE;
120 }
121
122 static BOOL FASTCALL
123 GuiConsoleOpenUserSettings(HWND hWnd, DWORD ProcessId, PHKEY hSubKey, REGSAM samDesired)
124 {
125 WCHAR szProcessName[MAX_PATH];
126 WCHAR szBuffer[MAX_PATH];
127 UINT fLength, wLength;
128 DWORD dwBitmask, dwLength;
129 WCHAR CurDrive[] = { 'A',':', 0 };
130 HANDLE hProcess;
131 HKEY hKey;
132 WCHAR * ptr, *res;
133 static const WCHAR szSystemRoot[] = { '%','S','y','s','t','e','m','R','o','o','t','%', 0 };
134
135
136 /*
137 * console properties are stored under
138 * HKCU\Console\*
139 *
140 * There are 3 ways to store console properties
141 *
142 * 1. use console title as subkey name
143 * i.e. cmd.exe
144 *
145 * 2. use application name as subkey name
146 *
147 * 3. use unexpanded path to console application.
148 * i.e. %SystemRoot%_system32_cmd.exe
149 */
150
151 if (!GuiConsoleOpenUserRegistryPathPerProcessId(ProcessId, &hProcess, &hKey, samDesired))
152 return FALSE;
153
154 fLength = GetProcessImageFileNameW(hProcess, szProcessName, MAX_PATH);
155 CloseHandle(hProcess);
156
157 if (!fLength)
158 {
159 DPRINT1("GetProcessImageFileNameW failed(0x%x)ProcessId %d\n", GetLastError(),hProcess);
160 return FALSE;
161 }
162
163
164 ptr = wcsrchr(szProcessName, L'\\');
165 swprintf(szBuffer, L"Console%s",ptr);
166
167 if (RegOpenKeyExW(hKey, szBuffer, 0, samDesired, hSubKey) == ERROR_SUCCESS)
168 {
169 RegCloseKey(hKey);
170 return TRUE;
171 }
172
173 dwBitmask = GetLogicalDrives();
174 while(dwBitmask)
175 {
176 if (dwBitmask & 0x1)
177 {
178 dwLength = QueryDosDeviceW(CurDrive, szBuffer, MAX_PATH);
179 if (dwLength)
180 {
181 if (!memcmp(szBuffer, szProcessName, (dwLength-2)*sizeof(WCHAR)))
182 {
183 wcscpy(szBuffer, CurDrive);
184 wcscat(&szBuffer[(sizeof(CurDrive)/sizeof(WCHAR))-1], &szProcessName[dwLength-2]);
185 break;
186 }
187 }
188 }
189 dwBitmask = (dwBitmask >> 1);
190 CurDrive[0]++;
191 }
192
193 wLength = GetWindowsDirectoryW(szProcessName, MAX_PATH);
194
195 if (!wcsncmp(szProcessName, szBuffer, wLength))
196 {
197 wcscpy(szProcessName, szSystemRoot);
198 wcscpy(&szProcessName[(sizeof(szSystemRoot) / sizeof(WCHAR))-1], &szBuffer[wLength]);
199 ptr = res = szProcessName;
200 }
201 else
202 {
203 ptr = res = szBuffer;
204 }
205
206 while((ptr = wcschr(szProcessName, L'\\')))
207 ptr[0] = L'_';
208
209 if (RegOpenKeyExW(hKey, res, 0, samDesired, hSubKey) == ERROR_SUCCESS)
210 {
211 RegCloseKey(hKey);
212 return TRUE;
213 }
214 RegCloseKey(hKey);
215 return FALSE;
216 }
217 static void FASTCALL
218 GuiConsoleReadUserSettings(HKEY hKey, PGUI_CONSOLE_DATA GuiData)
219 {
220 DWORD dwNumSubKeys = 0;
221 DWORD dwIndex;
222 DWORD dwValueName;
223 DWORD dwValue;
224 DWORD dwType;
225 WCHAR szValueName[MAX_PATH];
226 WCHAR szValue[MAX_PATH];
227 DWORD Value;
228
229 RegQueryInfoKey(hKey, NULL, NULL, NULL, &dwNumSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
230
231 for (dwIndex = 0; dwIndex < dwNumSubKeys; dwIndex++)
232 {
233 dwValue = sizeof(Value);
234 dwValueName = MAX_PATH;
235
236 if (RegEnumValueW(hKey, dwIndex, szValueName, &dwValueName, NULL, &dwType, (BYTE*)&Value, &dwValue) != ERROR_SUCCESS)
237 {
238 if (dwType == REG_SZ)
239 {
240 /*
241 * retry in case of string value
242 */
243 dwValue = sizeof(szValue);
244 dwValueName = MAX_PATH;
245 if (RegEnumValueW(hKey, dwIndex, szValueName, &dwValueName, NULL, NULL, (BYTE*)szValue, &dwValue) != ERROR_SUCCESS)
246 break;
247 }
248 else
249 break;
250 }
251
252 if (!wcscmp(szValueName, L"CursorSize"))
253 {
254 if (Value == 0x32)
255 GuiData->CursorSize = Value;
256 else if (Value == 0x64)
257 GuiData->CursorSize = Value;
258 }
259 else if (!wcscmp(szValueName, L"FaceName"))
260 {
261 wcscpy(GuiData->FontName, szValue);
262 }
263 else if (!wcscmp(szValueName, L"FontSize"))
264 {
265 GuiData->FontSize = Value;
266 }
267 else if (!wcscmp(szValueName, L"FontWeight"))
268 {
269 GuiData->FontWeight = Value;
270 }
271 else if (!wcscmp(szValueName, L"HistoryNoDup"))
272 {
273 GuiData->HistoryNoDup = Value;
274 }
275 else if (!wcscmp(szValueName, L"WindowSize"))
276 {
277 GuiData->WindowSize = Value;
278 }
279 else if (!wcscmp(szValueName, L"FullScreen"))
280 {
281 GuiData->FullScreen = Value;
282 }
283 else if (!wcscmp(szValueName, L"QuickEdit"))
284 {
285 GuiData->QuickEdit = Value;
286 }
287 else if (!wcscmp(szValueName, L"InsertMode"))
288 {
289 GuiData->InsertMode = Value;
290 }
291 }
292 }
293 static VOID FASTCALL
294 GuiConsoleUseDefaults(PGUI_CONSOLE_DATA GuiData)
295 {
296 /*
297 * init guidata with default properties
298 */
299
300 wcscpy(GuiData->FontName, L"Bitstream Vera Sans Mono");
301 GuiData->FontSize = 0x0008000C; // font is 8x12
302 GuiData->WindowSize = 0x00190050; // default window size is 25x80
303 GuiData->FontWeight = FW_NORMAL;
304 GuiData->CursorSize = 0;
305 GuiData->HistoryNoDup = FALSE;
306 GuiData->FullScreen = FALSE;
307 GuiData->QuickEdit = FALSE;
308 GuiData->InsertMode = TRUE;
309 }
310
311
312
313 static BOOL FASTCALL
314 GuiConsoleHandleNcCreate(HWND hWnd, CREATESTRUCTW *Create)
315 {
316 RECT Rect;
317 PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) Create->lpCreateParams;
318 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)Console->PrivateData;
319 HDC Dc;
320 HFONT OldFont;
321 TEXTMETRICW Metrics;
322 PCSRSS_PROCESS_DATA ProcessData;
323 HKEY hKey;
324
325 if (NULL == GuiData)
326 {
327 DPRINT1("GuiConsoleNcCreate: HeapAlloc failed\n");
328 return FALSE;
329 }
330
331 GuiConsoleUseDefaults(GuiData);
332 if (Console->ProcessList.Flink != &Console->ProcessList)
333 {
334 ProcessData = CONTAINING_RECORD(Console->ProcessList.Flink, CSRSS_PROCESS_DATA, ProcessEntry);
335 if (GuiConsoleOpenUserSettings(hWnd, PtrToUlong(ProcessData->ProcessId), &hKey, KEY_READ))
336 {
337 GuiConsoleReadUserSettings(hKey, GuiData);
338 RegCloseKey(hKey);
339 }
340 }
341
342 Console->Size.X = LOWORD(GuiData->WindowSize);
343 Console->Size.Y = HIWORD(GuiData->WindowSize);
344
345 InitializeCriticalSection(&GuiData->Lock);
346
347 GuiData->LineBuffer = (PWCHAR)HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY,
348 Console->Size.X * sizeof(WCHAR));
349
350 GuiData->Font = CreateFontW(LOWORD(GuiData->FontSize),
351 0, //HIWORD(GuiData->FontSize),
352 0,
353 TA_BASELINE,
354 GuiData->FontWeight,
355 FALSE,
356 FALSE,
357 FALSE,
358 OEM_CHARSET,
359 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
360 NONANTIALIASED_QUALITY, FIXED_PITCH | FF_DONTCARE,
361 GuiData->FontName);
362 if (NULL == GuiData->Font)
363 {
364 DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
365 DeleteCriticalSection(&GuiData->Lock);
366 HeapFree(Win32CsrApiHeap, 0, GuiData);
367 return FALSE;
368 }
369 Dc = GetDC(hWnd);
370 if (NULL == Dc)
371 {
372 DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
373 DeleteObject(GuiData->Font);
374 DeleteCriticalSection(&GuiData->Lock);
375 HeapFree(Win32CsrApiHeap, 0, GuiData);
376 return FALSE;
377 }
378 OldFont = SelectObject(Dc, GuiData->Font);
379 if (NULL == OldFont)
380 {
381 DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
382 ReleaseDC(hWnd, Dc);
383 DeleteObject(GuiData->Font);
384 DeleteCriticalSection(&GuiData->Lock);
385 HeapFree(Win32CsrApiHeap, 0, GuiData);
386 return FALSE;
387 }
388 if (! GetTextMetricsW(Dc, &Metrics))
389 {
390 DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
391 SelectObject(Dc, OldFont);
392 ReleaseDC(hWnd, Dc);
393 DeleteObject(GuiData->Font);
394 DeleteCriticalSection(&GuiData->Lock);
395 HeapFree(Win32CsrApiHeap, 0, GuiData);
396 return FALSE;
397 }
398 GuiData->CharWidth = Metrics.tmMaxCharWidth;
399 GuiData->CharHeight = Metrics.tmHeight + Metrics.tmExternalLeading;
400 SelectObject(Dc, OldFont);
401
402 ReleaseDC(hWnd, Dc);
403 GuiData->CursorBlinkOn = TRUE;
404 GuiData->ForceCursorOff = FALSE;
405
406 GuiData->Selection.left = -1;
407 DPRINT("Console %p GuiData %p\n", Console, GuiData);
408 Console->PrivateData = GuiData;
409 SetWindowLongPtrW(hWnd, GWL_USERDATA, (DWORD_PTR) Console);
410
411 GetWindowRect(hWnd, &Rect);
412 Rect.right = Rect.left + Console->Size.X * GuiData->CharWidth +
413 2 * GetSystemMetrics(SM_CXFIXEDFRAME);
414 Rect.bottom = Rect.top + Console->Size.Y * GuiData->CharHeight +
415 2 * GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYCAPTION);
416 MoveWindow(hWnd, Rect.left, Rect.top, Rect.right - Rect.left,
417 Rect.bottom - Rect.top, FALSE);
418
419 SetTimer(hWnd, 1, CURSOR_BLINK_TIME, NULL);
420 SetEvent(GuiData->hGuiInitEvent);
421
422 return (BOOL) DefWindowProcW(hWnd, WM_NCCREATE, 0, (LPARAM) Create);
423 }
424
425 static COLORREF FASTCALL
426 GuiConsoleRGBFromAttribute(BYTE Attribute)
427 {
428 int Red = (Attribute & 0x04 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);
429 int Green = (Attribute & 0x02 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);
430 int Blue = (Attribute & 0x01 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);
431
432 return RGB(Red, Green, Blue);
433 }
434
435 static VOID FASTCALL
436 GuiConsoleSetTextColors(HDC Dc, BYTE Attribute)
437 {
438 SetTextColor(Dc, GuiConsoleRGBFromAttribute(Attribute & 0x0f));
439 SetBkColor(Dc, GuiConsoleRGBFromAttribute((Attribute & 0xf0) >> 4));
440 }
441
442 static VOID FASTCALL
443 GuiConsoleGetLogicalCursorPos(PCSRSS_SCREEN_BUFFER Buff, ULONG *CursorX, ULONG *CursorY)
444 {
445 *CursorX = Buff->CurrentX;
446 if (Buff->CurrentY < Buff->ShowY)
447 {
448 *CursorY = Buff->MaxY - Buff->ShowY + Buff->CurrentY;
449 }
450 else
451 {
452 *CursorY = Buff->CurrentY - Buff->ShowY;
453 }
454 }
455
456
457 static VOID FASTCALL
458 GuiConsoleUpdateSelection(HWND hWnd, PRECT rc, PGUI_CONSOLE_DATA GuiData)
459 {
460 RECT oldRect = GuiData->Selection;
461
462 if(rc != NULL)
463 {
464 RECT changeRect = *rc;
465
466 GuiData->Selection = *rc;
467
468 changeRect.left *= GuiData->CharWidth;
469 changeRect.top *= GuiData->CharHeight;
470 changeRect.right *= GuiData->CharWidth;
471 changeRect.bottom *= GuiData->CharHeight;
472
473 if(rc->left != oldRect.left ||
474 rc->top != oldRect.top ||
475 rc->right != oldRect.right ||
476 rc->bottom != oldRect.bottom)
477 {
478 if(oldRect.left != -1)
479 {
480 HRGN rgn1, rgn2;
481
482 oldRect.left *= GuiData->CharWidth;
483 oldRect.top *= GuiData->CharHeight;
484 oldRect.right *= GuiData->CharWidth;
485 oldRect.bottom *= GuiData->CharHeight;
486
487 /* calculate the region that needs to be updated */
488 if((rgn1 = CreateRectRgnIndirect(&oldRect)))
489 {
490 if((rgn2 = CreateRectRgnIndirect(&changeRect)))
491 {
492 if(CombineRgn(rgn1, rgn2, rgn1, RGN_XOR) != ERROR)
493 {
494 InvalidateRgn(hWnd, rgn1, FALSE);
495 }
496
497 DeleteObject(rgn2);
498 }
499 DeleteObject(rgn1);
500 }
501 }
502 else
503 {
504 InvalidateRect(hWnd, &changeRect, FALSE);
505 }
506 }
507 }
508 else if(oldRect.left != -1)
509 {
510 /* clear the selection */
511 GuiData->Selection.left = -1;
512 oldRect.left *= GuiData->CharWidth;
513 oldRect.top *= GuiData->CharHeight;
514 oldRect.right *= GuiData->CharWidth;
515 oldRect.bottom *= GuiData->CharHeight;
516 InvalidateRect(hWnd, &oldRect, FALSE);
517 }
518 }
519
520
521 static VOID FASTCALL
522 GuiConsolePaint(PCSRSS_CONSOLE Console,
523 PGUI_CONSOLE_DATA GuiData,
524 HDC hDC,
525 PRECT rc)
526 {
527 PCSRSS_SCREEN_BUFFER Buff;
528 ULONG TopLine, BottomLine, LeftChar, RightChar;
529 ULONG Line, Char, Start;
530 PBYTE From;
531 PWCHAR To;
532 BYTE LastAttribute, Attribute;
533 ULONG CursorX, CursorY, CursorHeight;
534 HBRUSH CursorBrush, OldBrush;
535 HFONT OldFont;
536
537 Buff = Console->ActiveBuffer;
538
539 TopLine = rc->top / GuiData->CharHeight;
540 BottomLine = (rc->bottom + (GuiData->CharHeight - 1)) / GuiData->CharHeight - 1;
541 LeftChar = rc->left / GuiData->CharWidth;
542 RightChar = (rc->right + (GuiData->CharWidth - 1)) / GuiData->CharWidth - 1;
543 LastAttribute = Buff->Buffer[(TopLine * Buff->MaxX + LeftChar) * 2 + 1];
544
545 GuiConsoleSetTextColors(hDC,
546 LastAttribute);
547
548 EnterCriticalSection(&Buff->Header.Lock);
549
550 OldFont = SelectObject(hDC,
551 GuiData->Font);
552
553 for (Line = TopLine; Line <= BottomLine; Line++)
554 {
555 if (Line + Buff->ShowY < Buff->MaxY)
556 {
557 From = Buff->Buffer + ((Line + Buff->ShowY) * Buff->MaxX + LeftChar) * 2;
558 }
559 else
560 {
561 From = Buff->Buffer +
562 ((Line - (Buff->MaxY - Buff->ShowY)) * Buff->MaxX + LeftChar) * 2;
563 }
564 Start = LeftChar;
565 To = GuiData->LineBuffer;
566
567 for (Char = LeftChar; Char <= RightChar; Char++)
568 {
569 if (*(From + 1) != LastAttribute)
570 {
571 TextOutW(hDC,
572 Start * GuiData->CharWidth,
573 Line * GuiData->CharHeight,
574 GuiData->LineBuffer,
575 Char - Start);
576 Start = Char;
577 To = GuiData->LineBuffer;
578 Attribute = *(From + 1);
579 if (Attribute != LastAttribute)
580 {
581 GuiConsoleSetTextColors(hDC,
582 Attribute);
583 LastAttribute = Attribute;
584 }
585 }
586
587 MultiByteToWideChar(Console->OutputCodePage,
588 0,
589 (PCHAR)From,
590 1,
591 To,
592 1);
593 To++;
594 From += 2;
595 }
596
597 TextOutW(hDC,
598 Start * GuiData->CharWidth,
599 Line * GuiData->CharHeight,
600 GuiData->LineBuffer,
601 RightChar - Start + 1);
602 }
603
604 if (Buff->CursorInfo.bVisible && GuiData->CursorBlinkOn &&
605 !GuiData->ForceCursorOff)
606 {
607 GuiConsoleGetLogicalCursorPos(Buff,
608 &CursorX,
609 &CursorY);
610 if (LeftChar <= CursorX && CursorX <= RightChar &&
611 TopLine <= CursorY && CursorY <= BottomLine)
612 {
613 CursorHeight = (GuiData->CharHeight * Buff->CursorInfo.dwSize) / 100;
614 if (CursorHeight < 1)
615 {
616 CursorHeight = 1;
617 }
618 From = Buff->Buffer + (Buff->CurrentY * Buff->MaxX + Buff->CurrentX) * 2 + 1;
619 CursorBrush = CreateSolidBrush(GuiConsoleRGBFromAttribute(*From));
620 OldBrush = SelectObject(hDC,
621 CursorBrush);
622 PatBlt(hDC,
623 CursorX * GuiData->CharWidth,
624 CursorY * GuiData->CharHeight + (GuiData->CharHeight - CursorHeight),
625 GuiData->CharWidth,
626 CursorHeight,
627 PATCOPY);
628 SelectObject(hDC,
629 OldBrush);
630 DeleteObject(CursorBrush);
631 }
632 }
633
634 LeaveCriticalSection(&Buff->Header.Lock);
635
636 SelectObject(hDC,
637 OldFont);
638 }
639
640 static VOID FASTCALL
641 GuiConsoleHandlePaint(HWND hWnd, HDC hDCPaint)
642 {
643 HDC hDC;
644 PAINTSTRUCT ps;
645 PCSRSS_CONSOLE Console;
646 PGUI_CONSOLE_DATA GuiData;
647
648 hDC = BeginPaint(hWnd, &ps);
649 if (hDC != NULL &&
650 ps.rcPaint.left < ps.rcPaint.right &&
651 ps.rcPaint.top < ps.rcPaint.bottom)
652 {
653 GuiConsoleGetDataPointers(hWnd,
654 &Console,
655 &GuiData);
656 if (Console != NULL && GuiData != NULL &&
657 Console->ActiveBuffer != NULL)
658 {
659 EnterCriticalSection(&GuiData->Lock);
660
661 GuiConsolePaint(Console,
662 GuiData,
663 hDC,
664 &ps.rcPaint);
665
666 if (GuiData->Selection.left != -1)
667 {
668 RECT rc = GuiData->Selection;
669
670 rc.left *= GuiData->CharWidth;
671 rc.top *= GuiData->CharHeight;
672 rc.right *= GuiData->CharWidth;
673 rc.bottom *= GuiData->CharHeight;
674
675 /* invert the selection */
676 if (IntersectRect(&rc,
677 &ps.rcPaint,
678 &rc))
679 {
680 PatBlt(hDC,
681 rc.left,
682 rc.top,
683 rc.right - rc.left,
684 rc.bottom - rc.top,
685 DSTINVERT);
686 }
687 }
688
689 LeaveCriticalSection(&GuiData->Lock);
690 }
691
692 EndPaint(hWnd, &ps);
693 }
694 }
695
696 static VOID FASTCALL
697 GuiConsoleHandleKey(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
698 {
699 PCSRSS_CONSOLE Console;
700 PGUI_CONSOLE_DATA GuiData;
701 MSG Message;
702
703 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
704 Message.hwnd = hWnd;
705 Message.message = msg;
706 Message.wParam = wParam;
707 Message.lParam = lParam;
708
709 if(msg == WM_CHAR || msg == WM_SYSKEYDOWN)
710 {
711 /* clear the selection */
712 GuiConsoleUpdateSelection(hWnd, NULL, GuiData);
713 }
714
715 ConioProcessKey(&Message, Console, FALSE);
716 }
717
718 static VOID FASTCALL
719 GuiIntDrawRegion(PGUI_CONSOLE_DATA GuiData, HWND Wnd, RECT *Region)
720 {
721 RECT RegionRect;
722
723 RegionRect.left = Region->left * GuiData->CharWidth;
724 RegionRect.top = Region->top * GuiData->CharHeight;
725 RegionRect.right = (Region->right + 1) * GuiData->CharWidth;
726 RegionRect.bottom = (Region->bottom + 1) * GuiData->CharHeight;
727
728 InvalidateRect(Wnd, &RegionRect, FALSE);
729 }
730
731 static VOID STDCALL
732 GuiDrawRegion(PCSRSS_CONSOLE Console, RECT *Region)
733 {
734 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA) Console->PrivateData;
735
736 if (NULL != Console->hWindow && NULL != GuiData)
737 {
738 GuiIntDrawRegion(GuiData, Console->hWindow, Region);
739 }
740 }
741
742 static VOID FASTCALL
743 GuiInvalidateCell(PGUI_CONSOLE_DATA GuiData, HWND Wnd, UINT x, UINT y)
744 {
745 RECT CellRect;
746
747 CellRect.left = x;
748 CellRect.top = y;
749 CellRect.right = x;
750 CellRect.bottom = y;
751
752 GuiIntDrawRegion(GuiData, Wnd, &CellRect);
753 }
754
755 static VOID STDCALL
756 GuiWriteStream(PCSRSS_CONSOLE Console, RECT *Region, LONG CursorStartX, LONG CursorStartY,
757 UINT ScrolledLines, CHAR *Buffer, UINT Length)
758 {
759 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA) Console->PrivateData;
760 PCSRSS_SCREEN_BUFFER Buff = Console->ActiveBuffer;
761 LONG CursorEndX, CursorEndY;
762 RECT ScrollRect;
763
764 if (NULL == Console->hWindow || NULL == GuiData)
765 {
766 return;
767 }
768
769 if (0 != ScrolledLines)
770 {
771 ScrollRect.left = 0;
772 ScrollRect.top = 0;
773 ScrollRect.right = Console->Size.X * GuiData->CharWidth;
774 ScrollRect.bottom = Region->top * GuiData->CharHeight;
775
776 if (GuiData->Selection.left != -1)
777 {
778 /* scroll the selection */
779 if (GuiData->Selection.top > ScrolledLines)
780 {
781 GuiData->Selection.top -= ScrolledLines;
782 GuiData->Selection.bottom -= ScrolledLines;
783 }
784 else if (GuiData->Selection.bottom < ScrolledLines)
785 {
786 GuiData->Selection.left = -1;
787 }
788 else
789 {
790 GuiData->Selection.top = 0;
791 GuiData->Selection.bottom -= ScrolledLines;
792 }
793 }
794
795 ScrollWindowEx(Console->hWindow,
796 0,
797 -(ScrolledLines * GuiData->CharHeight),
798 &ScrollRect,
799 NULL,
800 NULL,
801 NULL,
802 SW_INVALIDATE);
803 }
804
805 GuiIntDrawRegion(GuiData, Console->hWindow, Region);
806
807 if (CursorStartX < Region->left || Region->right < CursorStartX
808 || CursorStartY < Region->top || Region->bottom < CursorStartY)
809 {
810 GuiInvalidateCell(GuiData, Console->hWindow, CursorStartX, CursorStartY);
811 }
812
813 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY,
814 &CursorEndX, &CursorEndY);
815 if ((CursorEndX < Region->left || Region->right < CursorEndX
816 || CursorEndY < Region->top || Region->bottom < CursorEndY)
817 && (CursorEndX != CursorStartX || CursorEndY != CursorStartY))
818 {
819 GuiInvalidateCell(GuiData, Console->hWindow, CursorEndX, CursorEndY);
820 }
821 }
822
823 static BOOL STDCALL
824 GuiSetCursorInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff)
825 {
826 RECT UpdateRect;
827
828 if (Console->ActiveBuffer == Buff)
829 {
830 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY,
831 &UpdateRect.left, &UpdateRect.top);
832 UpdateRect.right = UpdateRect.left;
833 UpdateRect.bottom = UpdateRect.top;
834 ConioDrawRegion(Console, &UpdateRect);
835 }
836
837 return TRUE;
838 }
839
840 static BOOL STDCALL
841 GuiSetScreenInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff, UINT OldCursorX, UINT OldCursorY)
842 {
843 RECT UpdateRect;
844
845 if (Console->ActiveBuffer == Buff)
846 {
847 /* Redraw char at old position (removes cursor) */
848 UpdateRect.left = OldCursorX;
849 UpdateRect.top = OldCursorY;
850 UpdateRect.right = OldCursorX;
851 UpdateRect.bottom = OldCursorY;
852 ConioDrawRegion(Console, &UpdateRect);
853 /* Redraw char at new position (shows cursor) */
854 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY,
855 &(UpdateRect.left), &(UpdateRect.top));
856 UpdateRect.right = UpdateRect.left;
857 UpdateRect.bottom = UpdateRect.top;
858 ConioDrawRegion(Console, &UpdateRect);
859 }
860
861 return TRUE;
862 }
863
864 static VOID FASTCALL
865 GuiConsoleHandleTimer(HWND hWnd)
866 {
867 PCSRSS_CONSOLE Console;
868 PGUI_CONSOLE_DATA GuiData;
869 RECT CursorRect;
870 ULONG CursorX, CursorY;
871
872 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
873 GuiData->CursorBlinkOn = ! GuiData->CursorBlinkOn;
874
875 GuiConsoleGetLogicalCursorPos(Console->ActiveBuffer, &CursorX, &CursorY);
876 CursorRect.left = CursorX;
877 CursorRect.top = CursorY;
878 CursorRect.right = CursorX;
879 CursorRect.bottom = CursorY;
880 GuiDrawRegion(Console, &CursorRect);
881 }
882
883 static VOID FASTCALL
884 GuiConsoleHandleClose(HWND hWnd)
885 {
886 PCSRSS_CONSOLE Console;
887 PGUI_CONSOLE_DATA GuiData;
888 PLIST_ENTRY current_entry;
889 PCSRSS_PROCESS_DATA current;
890
891 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
892
893 EnterCriticalSection(&Console->Header.Lock);
894
895 current_entry = Console->ProcessList.Flink;
896 while (current_entry != &Console->ProcessList)
897 {
898 current = CONTAINING_RECORD(current_entry, CSRSS_PROCESS_DATA, ProcessEntry);
899 current_entry = current_entry->Flink;
900
901 ConioConsoleCtrlEvent(CTRL_CLOSE_EVENT, current);
902 }
903
904 LeaveCriticalSection(&Console->Header.Lock);
905 }
906
907 static VOID FASTCALL
908 GuiConsoleHandleNcDestroy(HWND hWnd)
909 {
910 PCSRSS_CONSOLE Console;
911 PGUI_CONSOLE_DATA GuiData;
912
913 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
914 KillTimer(hWnd, 1);
915 Console->PrivateData = NULL;
916 DeleteCriticalSection(&GuiData->Lock);
917 GetSystemMenu(hWnd, TRUE);
918 if (GuiData->ConsoleLibrary)
919 FreeLibrary(GuiData->ConsoleLibrary);
920
921 HeapFree(Win32CsrApiHeap, 0, GuiData);
922 }
923
924 static VOID FASTCALL
925 GuiConsoleLeftMouseDown(HWND hWnd, LPARAM lParam)
926 {
927 PCSRSS_CONSOLE Console;
928 PGUI_CONSOLE_DATA GuiData;
929 POINTS pt;
930 RECT rc;
931
932 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
933 if (Console == NULL || GuiData == NULL) return;
934
935 pt = MAKEPOINTS(lParam);
936
937 rc.left = pt.x / GuiData->CharWidth;
938 rc.top = pt.y / GuiData->CharHeight;
939 rc.right = rc.left + 1;
940 rc.bottom = rc.top + 1;
941
942 GuiData->SelectionStart.x = rc.left;
943 GuiData->SelectionStart.y = rc.top;
944
945 SetCapture(hWnd);
946
947 GuiData->MouseDown = TRUE;
948
949 GuiConsoleUpdateSelection(hWnd, &rc, GuiData);
950 }
951
952 static VOID FASTCALL
953 GuiConsoleLeftMouseUp(HWND hWnd, LPARAM lParam)
954 {
955 PCSRSS_CONSOLE Console;
956 PGUI_CONSOLE_DATA GuiData;
957 RECT rc;
958 POINTS pt;
959
960 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
961 if (Console == NULL || GuiData == NULL) return;
962 if (GuiData->Selection.left == -1 || !GuiData->MouseDown) return;
963
964 pt = MAKEPOINTS(lParam);
965
966 rc.left = GuiData->SelectionStart.x;
967 rc.top = GuiData->SelectionStart.y;
968 rc.right = (pt.x >= 0 ? (pt.x / GuiData->CharWidth) + 1 : 0);
969 rc.bottom = (pt.y >= 0 ? (pt.y / GuiData->CharHeight) + 1 : 0);
970
971 /* exchange left/top with right/bottom if required */
972 if(rc.left >= rc.right)
973 {
974 LONG tmp;
975 tmp = rc.left;
976 rc.left = max(rc.right - 1, 0);
977 rc.right = tmp + 1;
978 }
979 if(rc.top >= rc.bottom)
980 {
981 LONG tmp;
982 tmp = rc.top;
983 rc.top = max(rc.bottom - 1, 0);
984 rc.bottom = tmp + 1;
985 }
986
987 GuiData->MouseDown = FALSE;
988
989 GuiConsoleUpdateSelection(hWnd, &rc, GuiData);
990
991 ReleaseCapture();
992 }
993
994 static VOID FASTCALL
995 GuiConsoleMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam)
996 {
997 PCSRSS_CONSOLE Console;
998 PGUI_CONSOLE_DATA GuiData;
999 RECT rc;
1000 POINTS pt;
1001
1002 if (!(wParam & MK_LBUTTON)) return;
1003
1004 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1005 if (Console == NULL || GuiData == NULL || !GuiData->MouseDown) return;
1006
1007 pt = MAKEPOINTS(lParam);
1008
1009 rc.left = GuiData->SelectionStart.x;
1010 rc.top = GuiData->SelectionStart.y;
1011 rc.right = (pt.x >= 0 ? (pt.x / GuiData->CharWidth) + 1 : 0);
1012 if (Console->Size.X < rc.right)
1013 {
1014 rc.right = Console->Size.X;
1015 }
1016 rc.bottom = (pt.y >= 0 ? (pt.y / GuiData->CharHeight) + 1 : 0);
1017 if (Console->Size.Y < rc.bottom)
1018 {
1019 rc.bottom = Console->Size.Y;
1020 }
1021
1022 /* exchange left/top with right/bottom if required */
1023 if(rc.left >= rc.right)
1024 {
1025 LONG tmp;
1026 tmp = rc.left;
1027 rc.left = max(rc.right - 1, 0);
1028 rc.right = tmp + 1;
1029 }
1030 if(rc.top >= rc.bottom)
1031 {
1032 LONG tmp;
1033 tmp = rc.top;
1034 rc.top = max(rc.bottom - 1, 0);
1035 rc.bottom = tmp + 1;
1036 }
1037
1038 GuiConsoleUpdateSelection(hWnd, &rc, GuiData);
1039 }
1040
1041 static VOID FASTCALL
1042 GuiConsoleRightMouseDown(HWND hWnd)
1043 {
1044 PCSRSS_CONSOLE Console;
1045 PGUI_CONSOLE_DATA GuiData;
1046
1047 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1048 if (Console == NULL || GuiData == NULL) return;
1049
1050 if (GuiData->Selection.left == -1)
1051 {
1052 /* FIXME - paste text from clipboard */
1053 }
1054 else
1055 {
1056 /* FIXME - copy selection to clipboard */
1057
1058 GuiConsoleUpdateSelection(hWnd, NULL, GuiData);
1059 }
1060
1061 }
1062
1063 static VOID
1064 GuiConsoleShowConsoleProperties(HWND hWnd, BOOL Defaults)
1065 {
1066 PCSRSS_CONSOLE Console;
1067 PGUI_CONSOLE_DATA GuiData;
1068 APPLET_PROC CPLFunc;
1069 TCHAR szBuffer[MAX_PATH];
1070
1071 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1072
1073 if (GuiData == NULL)
1074 {
1075 DPRINT1("GuiConsoleGetDataPointers failed\n");
1076 return;
1077 }
1078 if (GuiData->ConsoleLibrary == NULL)
1079 {
1080 GetWindowsDirectory(szBuffer,MAX_PATH);
1081 _tcscat(szBuffer, _T("\\system32\\console.dll"));
1082 GuiData->ConsoleLibrary = LoadLibrary(szBuffer);
1083
1084 if (GuiData->ConsoleLibrary == NULL)
1085 {
1086 DPRINT1("failed to load console.dll");
1087 return;
1088 }
1089 }
1090
1091 CPLFunc = (APPLET_PROC) GetProcAddress(GuiData->ConsoleLibrary, _T("CPlApplet"));
1092 if (!CPLFunc)
1093 {
1094 DPRINT("Error: Console.dll misses CPlApplet export\n");
1095 return;
1096 }
1097
1098 if (!CPLFunc(hWnd, CPL_INIT, 0, 0))
1099 {
1100 DPRINT("Error: failed to initialize console.dll\n");
1101 return;
1102 }
1103
1104 if (CPLFunc(hWnd, CPL_GETCOUNT, 0, 0) != 1)
1105 {
1106 DPRINT("Error: console.dll returned unexpected CPL count\n");
1107 return;
1108 }
1109
1110 CPLFunc(hWnd, CPL_DBLCLK, 0, Defaults);
1111
1112 // TODO
1113 //
1114 // read back the changes from console.dll
1115 //
1116 // if the changes are system-wide then
1117 // console.dll should have written it to
1118 // registry
1119 //
1120 // if the changes only apply to this session
1121 // then exchange this info with console.dll in
1122 // some private way
1123 }
1124 static LRESULT FASTCALL
1125 GuiConsoleHandleSysMenuCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
1126 {
1127 DPRINT1("GuiConsoleHandleSysMenuCommand entered %d\n", wParam);
1128
1129 switch(wParam)
1130 {
1131 case IDS_MARK:
1132 case IDS_COPY:
1133 case IDS_PASTE:
1134 case IDS_SELECTALL:
1135 case IDS_SCROLL:
1136 case IDS_FIND:
1137 break;
1138
1139 case IDS_DEFAULTS:
1140 GuiConsoleShowConsoleProperties(hWnd, TRUE);
1141 break;
1142 case IDS_PROPERTIES:
1143 GuiConsoleShowConsoleProperties(hWnd, FALSE);
1144 break;
1145 default:
1146 break;
1147 }
1148
1149 return 0;
1150 }
1151 static BOOLEAN FASTCALL
1152 InsertItem(HMENU hMenu, INT fType, INT fMask, INT fState, HMENU hSubMenu, INT ResourceId)
1153 {
1154 MENUITEMINFO MenuItemInfo;
1155 TCHAR szBuffer[MAX_PATH];
1156
1157 memset(&MenuItemInfo, 0x0, sizeof(MENUITEMINFO));
1158 MenuItemInfo.cbSize = sizeof (MENUITEMINFO);
1159 MenuItemInfo.fMask = fMask;
1160 MenuItemInfo.fType = fType;
1161 MenuItemInfo.fState = fState;
1162 MenuItemInfo.hSubMenu = hSubMenu;
1163 MenuItemInfo.wID = ResourceId;
1164
1165 if (fType != MFT_SEPARATOR)
1166 {
1167 MenuItemInfo.cch = LoadString(Win32CsrDllHandle, ResourceId, szBuffer, MAX_PATH);
1168 if (!MenuItemInfo.cch)
1169 {
1170 DPRINT("LoadString failed ResourceId %d Error %x\n", ResourceId, GetLastError());
1171 return FALSE;
1172 }
1173 MenuItemInfo.dwTypeData = szBuffer;
1174 }
1175
1176 if (InsertMenuItem(hMenu, ResourceId, FALSE, &MenuItemInfo))
1177 return TRUE;
1178
1179 DPRINT("InsertMenuItem failed Last error %x\n", GetLastError());
1180 return FALSE;
1181 }
1182
1183
1184
1185 static VOID FASTCALL
1186 GuiConsoleCreateSysMenu(HWND hWnd)
1187 {
1188 HMENU hMenu;
1189 HMENU hSubMenu;
1190
1191
1192 hMenu = GetSystemMenu(hWnd, FALSE);
1193 if (hMenu == NULL)
1194 {
1195 DPRINT("GetSysMenu failed\n");
1196 return;
1197 }
1198 /* insert seperator */
1199 InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1200
1201 /* create submenu */
1202 hSubMenu = CreatePopupMenu();
1203 InsertItem(hSubMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_MARK);
1204 InsertItem(hSubMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING | MIIM_STATE, MFS_GRAYED, NULL, IDS_COPY);
1205 InsertItem(hSubMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_PASTE);
1206 InsertItem(hSubMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SELECTALL);
1207 InsertItem(hSubMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLL);
1208 InsertItem(hSubMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_FIND);
1209 InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING | MIIM_SUBMENU, 0, hSubMenu, IDS_EDIT);
1210
1211 /* create default/properties item */
1212 InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_DEFAULTS);
1213 InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_PROPERTIES);
1214 DrawMenuBar(hWnd);
1215 }
1216
1217 static LRESULT CALLBACK
1218 GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1219 {
1220 LRESULT Result = 0;
1221
1222 switch(msg)
1223 {
1224 case WM_NCCREATE:
1225 Result = (LRESULT) GuiConsoleHandleNcCreate(hWnd, (CREATESTRUCTW *) lParam);
1226 break;
1227 case WM_PAINT:
1228 GuiConsoleHandlePaint(hWnd, (HDC)wParam);
1229 break;
1230 case WM_KEYDOWN:
1231 case WM_KEYUP:
1232 case WM_SYSKEYDOWN:
1233 case WM_SYSKEYUP:
1234 case WM_CHAR:
1235 GuiConsoleHandleKey(hWnd, msg, wParam, lParam);
1236 break;
1237 case WM_TIMER:
1238 GuiConsoleHandleTimer(hWnd);
1239 break;
1240 case WM_CLOSE:
1241 GuiConsoleHandleClose(hWnd);
1242 break;
1243 case WM_NCDESTROY:
1244 GuiConsoleHandleNcDestroy(hWnd);
1245 break;
1246 case WM_LBUTTONDOWN:
1247 GuiConsoleLeftMouseDown(hWnd, lParam);
1248 break;
1249 case WM_LBUTTONUP:
1250 GuiConsoleLeftMouseUp(hWnd, lParam);
1251 break;
1252 case WM_RBUTTONDOWN:
1253 GuiConsoleRightMouseDown(hWnd);
1254 break;
1255 case WM_MOUSEMOVE:
1256 GuiConsoleMouseMove(hWnd, wParam, lParam);
1257 break;
1258 case WM_SYSCOMMAND:
1259 return GuiConsoleHandleSysMenuCommand(hWnd, wParam, lParam);
1260 default:
1261 Result = DefWindowProcW(hWnd, msg, wParam, lParam);
1262 break;
1263 }
1264
1265 return Result;
1266 }
1267
1268 static LRESULT CALLBACK
1269 GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1270 {
1271 HWND NewWindow;
1272 LONG WindowCount;
1273 MSG Msg;
1274 PWCHAR Buffer, Title;
1275 PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) lParam;
1276
1277
1278
1279 switch(msg)
1280 {
1281 case WM_CREATE:
1282 SetWindowLongW(hWnd, GWL_USERDATA, 0);
1283 return 0;
1284 case PM_CREATE_CONSOLE:
1285 Buffer = HeapAlloc(Win32CsrApiHeap, 0,
1286 Console->Title.Length + sizeof(WCHAR));
1287 if (NULL != Buffer)
1288 {
1289 memcpy(Buffer, Console->Title.Buffer, Console->Title.Length);
1290 Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0';
1291 Title = Buffer;
1292 }
1293 else
1294 {
1295 Title = L"";
1296 }
1297 NewWindow = CreateWindowW(L"ConsoleWindowClass",
1298 Title,
1299 WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, // | WS_HSCROLL | WS_VSCROLL,
1300 CW_USEDEFAULT,
1301 CW_USEDEFAULT,
1302 CW_USEDEFAULT,
1303 CW_USEDEFAULT,
1304 NULL,
1305 NULL,
1306 (HINSTANCE) GetModuleHandleW(NULL),
1307 (PVOID) Console);
1308 if (NULL != Buffer)
1309 {
1310 HeapFree(Win32CsrApiHeap, 0, Buffer);
1311 }
1312 Console->hWindow = NewWindow;
1313 if (NULL != NewWindow)
1314 {
1315 GuiConsoleCreateSysMenu(NewWindow);
1316 //ShowScrollBar(NewWindow, SB_VERT, FALSE);
1317 //ShowScrollBar(NewWindow, SB_HORZ, FALSE);
1318 SetWindowLongW(hWnd, GWL_USERDATA, GetWindowLongW(hWnd, GWL_USERDATA) + 1);
1319 ShowWindow(NewWindow, SW_SHOW);
1320 }
1321 return (LRESULT) NewWindow;
1322 case PM_DESTROY_CONSOLE:
1323 /* Window creation is done using a PostMessage(), so it's possible that the
1324 * window that we want to destroy doesn't exist yet. So first empty the message
1325 * queue */
1326 while(PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
1327 {
1328 TranslateMessage(&Msg);
1329 DispatchMessageW(&Msg);
1330 }
1331 DestroyWindow(Console->hWindow);
1332 Console->hWindow = NULL;
1333 WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
1334 WindowCount--;
1335 SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
1336 if (0 == WindowCount)
1337 {
1338 NotifyWnd = NULL;
1339 DestroyWindow(hWnd);
1340 PrivateCsrssManualGuiCheck(-1);
1341 PostQuitMessage(0);
1342 }
1343 return 0;
1344 default:
1345 return DefWindowProcW(hWnd, msg, wParam, lParam);
1346 }
1347 }
1348
1349 static DWORD STDCALL
1350 GuiConsoleGuiThread(PVOID Data)
1351 {
1352 MSG msg;
1353 PHANDLE GraphicsStartupEvent = (PHANDLE) Data;
1354
1355 NotifyWnd = CreateWindowW(L"Win32CsrCreateNotify",
1356 L"",
1357 WS_OVERLAPPEDWINDOW,
1358 CW_USEDEFAULT,
1359 CW_USEDEFAULT,
1360 CW_USEDEFAULT,
1361 CW_USEDEFAULT,
1362 NULL,
1363 NULL,
1364 (HINSTANCE) GetModuleHandleW(NULL),
1365 NULL);
1366 if (NULL == NotifyWnd)
1367 {
1368 PrivateCsrssManualGuiCheck(-1);
1369 SetEvent(*GraphicsStartupEvent);
1370 return 1;
1371 }
1372
1373 SetEvent(*GraphicsStartupEvent);
1374
1375 while(GetMessageW(&msg, NULL, 0, 0))
1376 {
1377 TranslateMessage(&msg);
1378 DispatchMessageW(&msg);
1379 }
1380
1381 return 1;
1382 }
1383
1384 static BOOL FASTCALL
1385 GuiInit(VOID)
1386 {
1387 WNDCLASSEXW wc;
1388
1389 if (NULL == NotifyWnd)
1390 {
1391 PrivateCsrssManualGuiCheck(+1);
1392 }
1393
1394 wc.cbSize = sizeof(WNDCLASSEXW);
1395 wc.lpszClassName = L"Win32CsrCreateNotify";
1396 wc.lpfnWndProc = GuiConsoleNotifyWndProc;
1397 wc.style = 0;
1398 wc.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
1399 wc.hIcon = NULL;
1400 wc.hCursor = NULL;
1401 wc.hbrBackground = NULL;
1402 wc.lpszMenuName = NULL;
1403 wc.cbClsExtra = 0;
1404 wc.cbWndExtra = 0;
1405 wc.hIconSm = NULL;
1406 if (RegisterClassExW(&wc) == 0)
1407 {
1408 DPRINT1("Failed to register notify wndproc\n");
1409 return FALSE;
1410 }
1411
1412 wc.cbSize = sizeof(WNDCLASSEXW);
1413 wc.lpszClassName = L"ConsoleWindowClass";
1414 wc.lpfnWndProc = GuiConsoleWndProc;
1415 wc.style = 0;
1416 wc.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
1417 wc.hIcon = LoadIconW(Win32CsrDllHandle, MAKEINTRESOURCEW(1));
1418 wc.hCursor = LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_ARROW));
1419 wc.hbrBackground = NULL;
1420 wc.lpszMenuName = NULL;
1421 wc.cbClsExtra = 0;
1422 wc.cbWndExtra = 0;
1423 wc.hIconSm = LoadImageW(Win32CsrDllHandle, MAKEINTRESOURCEW(1), IMAGE_ICON,
1424 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
1425 LR_SHARED);
1426 if (RegisterClassExW(&wc) == 0)
1427 {
1428 DPRINT1("Failed to register console wndproc\n");
1429 return FALSE;
1430 }
1431
1432 return TRUE;
1433 }
1434
1435 static VOID STDCALL
1436 GuiInitScreenBuffer(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buffer)
1437 {
1438 Buffer->DefaultAttrib = 0x0f;
1439 }
1440
1441 static BOOL STDCALL
1442 GuiChangeTitle(PCSRSS_CONSOLE Console)
1443 {
1444 PWCHAR Buffer, Title;
1445
1446 Buffer = HeapAlloc(Win32CsrApiHeap, 0,
1447 Console->Title.Length + sizeof(WCHAR));
1448 if (NULL != Buffer)
1449 {
1450 memcpy(Buffer, Console->Title.Buffer, Console->Title.Length);
1451 Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0';
1452 Title = Buffer;
1453 }
1454 else
1455 {
1456 Title = L"";
1457 }
1458 SendMessageW(Console->hWindow, WM_SETTEXT, 0, (LPARAM) Title);
1459 if (NULL != Buffer)
1460 {
1461 HeapFree(Win32CsrApiHeap, 0, Buffer);
1462 }
1463
1464 return TRUE;
1465 }
1466
1467 static BOOL STDCALL
1468 GuiChangeIcon(PCSRSS_CONSOLE Console)
1469 {
1470 SendMessageW(Console->hWindow, WM_SETICON, ICON_BIG, (LPARAM)Console->hWindowIcon);
1471 SendMessageW(Console->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)Console->hWindowIcon);
1472
1473 return TRUE;
1474 }
1475
1476 static VOID STDCALL
1477 GuiCleanupConsole(PCSRSS_CONSOLE Console)
1478 {
1479 SendMessageW(NotifyWnd, PM_DESTROY_CONSOLE, 0, (LPARAM) Console);
1480 }
1481
1482 static CSRSS_CONSOLE_VTBL GuiVtbl =
1483 {
1484 GuiInitScreenBuffer,
1485 GuiWriteStream,
1486 GuiDrawRegion,
1487 GuiSetCursorInfo,
1488 GuiSetScreenInfo,
1489 GuiChangeTitle,
1490 GuiCleanupConsole,
1491 GuiChangeIcon
1492 };
1493
1494 NTSTATUS FASTCALL
1495 GuiInitConsole(PCSRSS_CONSOLE Console)
1496 {
1497 HANDLE GraphicsStartupEvent;
1498 HANDLE ThreadHandle;
1499 PGUI_CONSOLE_DATA GuiData;
1500
1501 if (! ConsInitialized)
1502 {
1503 ConsInitialized = TRUE;
1504 if (! GuiInit())
1505 {
1506 ConsInitialized = FALSE;
1507 return STATUS_UNSUCCESSFUL;
1508 }
1509 }
1510
1511 Console->Vtbl = &GuiVtbl;
1512 if (NULL == NotifyWnd)
1513 {
1514 GraphicsStartupEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1515 if (NULL == GraphicsStartupEvent)
1516 {
1517 return STATUS_UNSUCCESSFUL;
1518 }
1519
1520 ThreadHandle = CreateThread(NULL,
1521 0,
1522 GuiConsoleGuiThread,
1523 (PVOID) &GraphicsStartupEvent,
1524 0,
1525 NULL);
1526 if (NULL == ThreadHandle)
1527 {
1528 NtClose(GraphicsStartupEvent);
1529 DPRINT1("Win32Csr: Failed to create graphics console thread. Expect problems\n");
1530 return STATUS_UNSUCCESSFUL;
1531 }
1532 SetThreadPriority(ThreadHandle, THREAD_PRIORITY_HIGHEST);
1533 CloseHandle(ThreadHandle);
1534
1535 WaitForSingleObject(GraphicsStartupEvent, INFINITE);
1536 CloseHandle(GraphicsStartupEvent);
1537
1538 if (NULL == NotifyWnd)
1539 {
1540 DPRINT1("Win32Csr: Failed to create notification window.\n");
1541 return STATUS_UNSUCCESSFUL;
1542 }
1543 }
1544 GuiData = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY,
1545 sizeof(GUI_CONSOLE_DATA));
1546 if (!GuiData)
1547 {
1548 DPRINT1("Win32Csr: Failed to create GUI_CONSOLE_DATA\n");
1549 return STATUS_UNSUCCESSFUL;
1550 }
1551
1552 Console->PrivateData = (PVOID) GuiData;
1553 /*
1554 * we need to wait untill the GUI has been fully initialized
1555 * to retrieve custom settings i.e. WindowSize etc..
1556 * Ideally we could use SendNotifyMessage for this but its not
1557 * yet implemented.
1558 *
1559 */
1560 GuiData->hGuiInitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1561 /* create console */
1562 PostMessageW(NotifyWnd, PM_CREATE_CONSOLE, 0, (LPARAM) Console);
1563
1564 /* wait untill initialization has finished */
1565 WaitForSingleObject(GuiData->hGuiInitEvent, INFINITE);
1566 DPRINT("received event Console %p GuiData %p X %d Y %d\n", Console, Console->PrivateData, Console->Size.X, Console->Size.Y);
1567 CloseHandle(GuiData->hGuiInitEvent);
1568 GuiData->hGuiInitEvent = NULL;
1569
1570 return STATUS_SUCCESS;
1571 }
1572
1573 /* EOF */