- implement screenbuffer resizing(required for console scrolling support)
[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 HWND hVScrollBar;
36 HWND hHScrollBar;
37 WCHAR FontName[LF_FACESIZE];
38 DWORD FontSize;
39 DWORD FontWeight;
40 DWORD HistoryNoDup;
41 DWORD FullScreen;
42 DWORD QuickEdit;
43 DWORD InsertMode;
44 DWORD NumberOfHistoryBuffers;
45 DWORD HistoryBufferSize;
46 DWORD WindowPosition;
47 DWORD ScreenBufferSize;
48 DWORD UseRasterFonts;
49 COLORREF ScreenText;
50 COLORREF ScreenBackground;
51 COLORREF PopupBackground;
52 COLORREF PopupText;
53 COLORREF Colors[16];
54 WCHAR szProcessName[MAX_PATH];
55 } GUI_CONSOLE_DATA, *PGUI_CONSOLE_DATA;
56
57 #ifndef WM_APP
58 #define WM_APP 0x8000
59 #endif
60 #define PM_CREATE_CONSOLE (WM_APP + 1)
61 #define PM_DESTROY_CONSOLE (WM_APP + 2)
62
63 #define CURSOR_BLINK_TIME 500
64 #define DEFAULT_ATTRIB (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY)
65
66 static BOOL ConsInitialized = FALSE;
67 static HWND NotifyWnd;
68
69 typedef struct _GUICONSOLE_MENUITEM
70 {
71 UINT uID;
72 const struct _GUICONSOLE_MENUITEM *SubMenu;
73 WORD wCmdID;
74 } GUICONSOLE_MENUITEM, *PGUICONSOLE_MENUITEM;
75
76 static const GUICONSOLE_MENUITEM GuiConsoleEditMenuItems[] =
77 {
78 { IDS_MARK, NULL, ID_SYSTEM_EDIT_MARK },
79 { IDS_COPY, NULL, ID_SYSTEM_EDIT_COPY },
80 { IDS_PASTE, NULL, ID_SYSTEM_EDIT_PASTE },
81 { IDS_SELECTALL, NULL, ID_SYSTEM_EDIT_SELECTALL },
82 { IDS_SCROLL, NULL, ID_SYSTEM_EDIT_SCROLL },
83 { IDS_FIND, NULL, ID_SYSTEM_EDIT_FIND },
84
85 { 0, NULL, 0 } /* End of list */
86 };
87
88 static const GUICONSOLE_MENUITEM GuiConsoleMainMenuItems[] =
89 {
90 { (UINT)-1, NULL, 0 }, /* Separator */
91 { IDS_EDIT, GuiConsoleEditMenuItems, 0 },
92 { IDS_DEFAULTS, NULL, ID_SYSTEM_DEFAULTS },
93 { IDS_PROPERTIES, NULL, ID_SYSTEM_PROPERTIES },
94
95 { 0, NULL, 0 } /* End of list */
96 };
97
98 static const COLORREF s_Colors[] =
99 {
100 RGB(0, 0, 0),
101 RGB(0, 0, 128),
102 RGB(0, 128, 0),
103 RGB(0, 128, 128),
104 RGB(128, 0, 0),
105 RGB(128, 0, 128),
106 RGB(128, 128, 0),
107 RGB(192, 192, 192),
108 RGB(128, 128, 128),
109 RGB(0, 0, 255),
110 RGB(0, 255, 0),
111 RGB(0, 255, 255),
112 RGB(255, 0, 0),
113 RGB(255, 0, 255),
114 RGB(255, 255, 0),
115 RGB(255, 255, 255)
116 };
117
118 /* FUNCTIONS *****************************************************************/
119
120 static VOID FASTCALL
121 GuiConsoleAppendMenuItems(HMENU hMenu,
122 const GUICONSOLE_MENUITEM *Items)
123 {
124 UINT i = 0;
125 WCHAR szMenuString[255];
126 HMENU hSubMenu;
127 HINSTANCE hInst = GetModuleHandleW(L"win32csr");
128
129 do
130 {
131 if (Items[i].uID != (UINT)-1)
132 {
133 if (LoadStringW(hInst,
134 Items[i].uID,
135 szMenuString,
136 sizeof(szMenuString) / sizeof(szMenuString[0])) > 0)
137 {
138 if (Items[i].SubMenu != NULL)
139 {
140 hSubMenu = CreatePopupMenu();
141 if (hSubMenu != NULL)
142 {
143 GuiConsoleAppendMenuItems(hSubMenu,
144 Items[i].SubMenu);
145
146 if (!AppendMenuW(hMenu,
147 MF_STRING | MF_POPUP,
148 (UINT_PTR)hSubMenu,
149 szMenuString))
150 {
151 DestroyMenu(hSubMenu);
152 }
153 }
154 }
155 else
156 {
157 AppendMenuW(hMenu,
158 MF_STRING,
159 Items[i].wCmdID,
160 szMenuString);
161 }
162 }
163 }
164 else
165 {
166 AppendMenuW(hMenu,
167 MF_SEPARATOR,
168 0,
169 NULL);
170 }
171 i++;
172 }while(!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].wCmdID == 0));
173 }
174
175 static VOID FASTCALL
176 GuiConsoleCreateSysMenu(PCSRSS_CONSOLE Console)
177 {
178 HMENU hMenu;
179 hMenu = GetSystemMenu(Console->hWindow,
180 FALSE);
181 if (hMenu != NULL)
182 {
183 GuiConsoleAppendMenuItems(hMenu,
184 GuiConsoleMainMenuItems);
185 DrawMenuBar(Console->hWindow);
186 }
187 }
188
189 static VOID FASTCALL
190 GuiConsoleGetDataPointers(HWND hWnd, PCSRSS_CONSOLE *Console, PGUI_CONSOLE_DATA *GuiData)
191 {
192 *Console = (PCSRSS_CONSOLE) GetWindowLongPtrW(hWnd, GWL_USERDATA);
193 *GuiData = (NULL == *Console ? NULL : (*Console)->PrivateData);
194 }
195
196 static BOOL FASTCALL
197 GuiConsoleOpenUserRegistryPathPerProcessId(DWORD ProcessId, PHANDLE hProcHandle, PHKEY hResult, REGSAM samDesired)
198 {
199 HANDLE hProcessToken = NULL;
200 HANDLE hProcess;
201
202 BYTE Buffer[256];
203 DWORD Length = 0;
204 UNICODE_STRING SidName;
205 LONG res;
206 PTOKEN_USER TokUser;
207
208 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | READ_CONTROL, FALSE, ProcessId);
209 if (!hProcess)
210 {
211 DPRINT("Error: OpenProcess failed(0x%x)\n", GetLastError());
212 return FALSE;
213 }
214
215 if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hProcessToken))
216 {
217 DPRINT("Error: OpenProcessToken failed(0x%x)\n", GetLastError());
218 CloseHandle(hProcess);
219 return FALSE;
220 }
221
222 if (!GetTokenInformation(hProcessToken, TokenUser, (PVOID)Buffer, sizeof(Buffer), &Length))
223 {
224 DPRINT("Error: GetTokenInformation failed(0x%x)\n",GetLastError());
225 CloseHandle(hProcess);
226 CloseHandle(hProcessToken);
227 return FALSE;
228 }
229
230 TokUser = ((PTOKEN_USER)Buffer)->User.Sid;
231 if (!NT_SUCCESS(RtlConvertSidToUnicodeString(&SidName, TokUser, TRUE)))
232 {
233 DPRINT("Error: RtlConvertSidToUnicodeString failed(0x%x)\n", GetLastError());
234 return FALSE;
235 }
236
237 res = RegOpenKeyExW(HKEY_USERS, SidName.Buffer, 0, samDesired, hResult);
238 RtlFreeUnicodeString(&SidName);
239
240 CloseHandle(hProcessToken);
241 if (hProcHandle)
242 *hProcHandle = hProcess;
243 else
244 CloseHandle(hProcess);
245
246 if (res != ERROR_SUCCESS)
247 return FALSE;
248 else
249 return TRUE;
250 }
251
252 static BOOL FASTCALL
253 GuiConsoleOpenUserSettings(PGUI_CONSOLE_DATA GuiData, DWORD ProcessId, PHKEY hSubKey, REGSAM samDesired, BOOL bCreate)
254 {
255 WCHAR szProcessName[MAX_PATH];
256 WCHAR szBuffer[MAX_PATH];
257 UINT fLength, wLength;
258 DWORD dwBitmask, dwLength;
259 WCHAR CurDrive[] = { 'A',':', 0 };
260 HANDLE hProcess;
261 HKEY hKey;
262 WCHAR * ptr;
263
264 /*
265 * console properties are stored under
266 * HKCU\Console\*
267 *
268 * There are 3 ways to store console properties
269 *
270 * 1. use console title as subkey name
271 * i.e. cmd.exe
272 *
273 * 2. use application name as subkey name
274 *
275 * 3. use unexpanded path to console application.
276 * i.e. %SystemRoot%_system32_cmd.exe
277 */
278
279 DPRINT("GuiConsoleOpenUserSettings entered\n");
280
281 if (!GuiConsoleOpenUserRegistryPathPerProcessId(ProcessId, &hProcess, &hKey, samDesired))
282 {
283 DPRINT("GuiConsoleOpenUserRegistryPathPerProcessId failed\n");
284 return FALSE;
285 }
286
287 /* FIXME we do not getting the process name so no menu will be loading, why ?*/
288 fLength = GetProcessImageFileNameW(hProcess, szProcessName, sizeof(GuiData->szProcessName) / sizeof(WCHAR));
289 CloseHandle(hProcess);
290
291 //DPRINT1("szProcessName3 : %S\n",szProcessName);
292
293 if (!fLength)
294 {
295 DPRINT("GetProcessImageFileNameW failed(0x%x)ProcessId %d\n", GetLastError(),hProcess);
296 return FALSE;
297 }
298 /*
299 * try the process name as path
300 */
301
302 ptr = wcsrchr(szProcessName, L'\\');
303 wcscpy(GuiData->szProcessName, ptr);
304
305 swprintf(szBuffer, L"Console%s",ptr);
306 DPRINT("#1 Path : %S\n", szBuffer);
307
308 if (bCreate)
309 {
310 if (RegCreateKeyW(hKey, szBuffer, hSubKey) == ERROR_SUCCESS)
311 {
312 RegCloseKey(hKey);
313 return TRUE;
314 }
315 RegCloseKey(hKey);
316 return FALSE;
317 }
318
319 if (RegOpenKeyExW(hKey, szBuffer, 0, samDesired, hSubKey) == ERROR_SUCCESS)
320 {
321 RegCloseKey(hKey);
322 return TRUE;
323 }
324
325 /*
326 * try the "Shortcut to processname" as path
327 * FIXME: detect wheter the process was started as a shortcut
328 */
329
330 swprintf(szBuffer, L"Console\\Shortcut to %S", ptr);
331 DPRINT("#2 Path : %S\n", szBuffer);
332 if (RegOpenKeyExW(hKey, szBuffer, 0, samDesired, hSubKey) == ERROR_SUCCESS)
333 {
334 swprintf(GuiData->szProcessName, L"Shortcut to %S", ptr);
335 RegCloseKey(hKey);
336 return TRUE;
337 }
338
339 /*
340 * if the path contains \\Device\\HarddiskVolume1\... remove it
341 */
342
343 if (szProcessName[0] == L'\\')
344 {
345 dwBitmask = GetLogicalDrives();
346 while(dwBitmask)
347 {
348 if (dwBitmask & 0x1)
349 {
350 dwLength = QueryDosDeviceW(CurDrive, szBuffer, MAX_PATH);
351 if (dwLength)
352 {
353 if (!memcmp(szBuffer, szProcessName, (dwLength-2)*sizeof(WCHAR)))
354 {
355 wcscpy(szProcessName, CurDrive);
356 RtlMoveMemory(&szProcessName[2], &szProcessName[dwLength-1], fLength - dwLength -1);
357 break;
358 }
359 }
360 }
361 dwBitmask = (dwBitmask >> 1);
362 CurDrive[0]++;
363 }
364 }
365
366 /*
367 * last attempt: check whether the file is under %SystemRoot%
368 * and use path like Console\%SystemRoot%_dir_dir2_file.exe
369 */
370
371 wLength = GetWindowsDirectoryW(szBuffer, MAX_PATH);
372 if (wLength)
373 {
374 if (!wcsncmp(szProcessName, szBuffer, wLength))
375 {
376 /* replace slashes by underscores */
377 while((ptr = wcschr(szProcessName, L'\\')))
378 ptr[0] = L'_';
379
380 swprintf(szBuffer, L"Console\\\%SystemRoot\%%S", &szProcessName[wLength]);
381 DPRINT("#3 Path : %S\n", szBuffer);
382 if (RegOpenKeyExW(hKey, szBuffer, 0, samDesired, hSubKey) == ERROR_SUCCESS)
383 {
384 swprintf(GuiData->szProcessName, L"\%SystemRoot\%%S", &szProcessName[wLength]);
385 RegCloseKey(hKey);
386 return TRUE;
387 }
388 }
389 }
390 RegCloseKey(hKey);
391 return FALSE;
392 }
393
394 static VOID
395 GuiConsoleWriteUserSettings(PCSRSS_CONSOLE Console, PGUI_CONSOLE_DATA GuiData)
396 {
397 HKEY hKey;
398 PCSRSS_PROCESS_DATA ProcessData;
399
400 if (Console->ProcessList.Flink == &Console->ProcessList)
401 {
402 DPRINT("GuiConsoleWriteUserSettings: No Process!!!\n");
403 return;
404 }
405 ProcessData = CONTAINING_RECORD(Console->ProcessList.Flink, CSRSS_PROCESS_DATA, ProcessEntry);
406 if (!GuiConsoleOpenUserSettings(GuiData, PtrToUlong(ProcessData->ProcessId), &hKey, KEY_READ | KEY_WRITE, TRUE))
407 {
408 return;
409 }
410
411 if (Console->ActiveBuffer->CursorInfo.dwSize <= 1)
412 {
413 RegDeleteKeyW(hKey, L"CursorSize");
414 }
415 else
416 {
417 RegSetValueExW(hKey, L"CursorSize", 0, REG_DWORD, (const BYTE *)&Console->ActiveBuffer->CursorInfo.dwSize, sizeof(DWORD));
418 }
419
420 if (GuiData->NumberOfHistoryBuffers == 5)
421 {
422 RegDeleteKeyW(hKey, L"NumberOfHistoryBuffers");
423 }
424 else
425 {
426 RegSetValueExW(hKey, L"NumberOfHistoryBuffers", 0, REG_DWORD, (const BYTE *)&GuiData->NumberOfHistoryBuffers, sizeof(DWORD));
427 }
428
429 if (GuiData->HistoryBufferSize == 50)
430 {
431 RegDeleteKeyW(hKey, L"HistoryBufferSize");
432 }
433 else
434 {
435 RegSetValueExW(hKey, L"HistoryBufferSize", 0, REG_DWORD, (const BYTE *)&GuiData->HistoryBufferSize, sizeof(DWORD));
436 }
437
438 if (GuiData->FullScreen == FALSE)
439 {
440 RegDeleteKeyW(hKey, L"FullScreen");
441 }
442 else
443 {
444 RegSetValueExW(hKey, L"FullScreen", 0, REG_DWORD, (const BYTE *)&GuiData->FullScreen, sizeof(DWORD));
445 }
446
447 if ( GuiData->QuickEdit == FALSE)
448 {
449 RegDeleteKeyW(hKey, L"QuickEdit");
450 }
451 else
452 {
453 RegSetValueExW(hKey, L"QuickEdit", 0, REG_DWORD, (const BYTE *)&GuiData->QuickEdit, sizeof(DWORD));
454 }
455
456 if (GuiData->InsertMode == TRUE)
457 {
458 RegDeleteKeyW(hKey, L"InsertMode");
459 }
460 else
461 {
462 RegSetValueExW(hKey, L"InsertMode", 0, REG_DWORD, (const BYTE *)&GuiData->InsertMode, sizeof(DWORD));
463 }
464
465 if (GuiData->HistoryNoDup == FALSE)
466 {
467 RegDeleteKeyW(hKey, L"HistoryNoDup");
468 }
469 else
470 {
471 RegSetValueExW(hKey, L"HistoryNoDup", 0, REG_DWORD, (const BYTE *)&GuiData->HistoryNoDup, sizeof(DWORD));
472 }
473
474 if (GuiData->ScreenText == RGB(192, 192, 192))
475 {
476 /*
477 * MS uses console attributes instead of real color
478 */
479 RegDeleteKeyW(hKey, L"ScreenText");
480 }
481 else
482 {
483 RegSetValueExW(hKey, L"ScreenText", 0, REG_DWORD, (const BYTE *)&GuiData->ScreenText, sizeof(COLORREF));
484 }
485
486 if (GuiData->ScreenBackground == RGB(0, 0, 0))
487 {
488 RegDeleteKeyW(hKey, L"ScreenBackground");
489 }
490 else
491 {
492 RegSetValueExW(hKey, L"ScreenBackground", 0, REG_DWORD, (const BYTE *)&GuiData->ScreenBackground, sizeof(COLORREF));
493 }
494
495 RegCloseKey(hKey);
496 }
497
498 static void FASTCALL
499 GuiConsoleReadUserSettings(HKEY hKey, PCSRSS_CONSOLE Console, PGUI_CONSOLE_DATA GuiData, PCSRSS_SCREEN_BUFFER Buffer)
500 {
501 DWORD dwNumSubKeys = 0;
502 DWORD dwIndex;
503 DWORD dwValueName;
504 DWORD dwValue;
505 DWORD dwType;
506 WCHAR szValueName[MAX_PATH];
507 WCHAR szValue[MAX_PATH];
508 DWORD Value;
509
510 if (RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &dwNumSubKeys, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
511 {
512 DPRINT("GuiConsoleReadUserSettings: RegQueryInfoKey failed\n");
513 return;
514 }
515
516 DPRINT("GuiConsoleReadUserSettings entered dwNumSubKeys %d\n", dwNumSubKeys);
517
518 for (dwIndex = 0; dwIndex < dwNumSubKeys; dwIndex++)
519 {
520 dwValue = sizeof(Value);
521 dwValueName = MAX_PATH;
522
523 if (RegEnumValueW(hKey, dwIndex, szValueName, &dwValueName, NULL, &dwType, (BYTE*)&Value, &dwValue) != ERROR_SUCCESS)
524 {
525 if (dwType == REG_SZ)
526 {
527 /*
528 * retry in case of string value
529 */
530 dwValue = sizeof(szValue);
531 dwValueName = MAX_PATH;
532 if (RegEnumValueW(hKey, dwIndex, szValueName, &dwValueName, NULL, NULL, (BYTE*)szValue, &dwValue) != ERROR_SUCCESS)
533 break;
534 }
535 else
536 break;
537 }
538 if (!wcscmp(szValueName, L"CursorSize"))
539 {
540 if (Value == 0x32)
541 {
542 Buffer->CursorInfo.dwSize = Value;
543 }
544 else if (Value == 0x64)
545 {
546 Buffer->CursorInfo.dwSize = Value;
547 }
548 }
549 else if (!wcscmp(szValueName, L"ScreenText"))
550 {
551 GuiData->ScreenText = Value;
552 }
553 else if (!wcscmp(szValueName, L"ScreenBackground"))
554 {
555 GuiData->ScreenBackground = Value;
556 }
557 else if (!wcscmp(szValueName, L"FaceName"))
558 {
559 wcscpy(GuiData->FontName, szValue);
560 }
561 else if (!wcscmp(szValueName, L"FontSize"))
562 {
563 GuiData->FontSize = Value;
564 }
565 else if (!wcscmp(szValueName, L"FontWeight"))
566 {
567 GuiData->FontWeight = Value;
568 }
569 else if (!wcscmp(szValueName, L"HistoryNoDup"))
570 {
571 GuiData->HistoryNoDup = Value;
572 }
573 else if (!wcscmp(szValueName, L"WindowSize"))
574 {
575 Console->Size.X = LOWORD(Value);
576 Console->Size.Y = HIWORD(Value);
577 }
578 else if (!wcscmp(szValueName, L"ScreenBufferSize"))
579 {
580 if(Buffer)
581 {
582 Buffer->MaxX = LOWORD(Value);
583 Buffer->MaxY = HIWORD(Value);
584 }
585 }
586 else if (!wcscmp(szValueName, L"FullScreen"))
587 {
588 GuiData->FullScreen = Value;
589 }
590 else if (!wcscmp(szValueName, L"QuickEdit"))
591 {
592 GuiData->QuickEdit = Value;
593 }
594 else if (!wcscmp(szValueName, L"InsertMode"))
595 {
596 GuiData->InsertMode = Value;
597 }
598 }
599 }
600 static VOID FASTCALL
601 GuiConsoleUseDefaults(PCSRSS_CONSOLE Console, PGUI_CONSOLE_DATA GuiData, PCSRSS_SCREEN_BUFFER Buffer)
602 {
603 /*
604 * init guidata with default properties
605 */
606
607 wcscpy(GuiData->FontName, L"DejaVu Sans Mono");
608 GuiData->FontSize = 0x0008000C; // font is 8x12
609 GuiData->FontWeight = FW_NORMAL;
610 GuiData->HistoryNoDup = FALSE;
611 GuiData->FullScreen = FALSE;
612 GuiData->QuickEdit = FALSE;
613 GuiData->InsertMode = TRUE;
614 GuiData->HistoryBufferSize = 50;
615 GuiData->NumberOfHistoryBuffers = 5;
616 GuiData->ScreenText = RGB(192, 192, 192);
617 GuiData->ScreenBackground = RGB(0, 0, 0);
618 GuiData->PopupText = RGB(128, 0, 128);
619 GuiData->PopupBackground = RGB(255, 255, 255);
620 GuiData->WindowPosition = UINT_MAX;
621 GuiData->ScreenBufferSize = MAKELONG(80, 300); //FIXME
622 GuiData->UseRasterFonts = TRUE;
623 memcpy(GuiData->Colors, s_Colors, sizeof(s_Colors));
624
625 Console->Size.X = 80;
626 Console->Size.Y = 25;
627
628 if (Buffer)
629 {
630 Buffer->MaxX = 80;
631 Buffer->MaxY = 25;
632 Buffer->CursorInfo.bVisible = TRUE;
633 Buffer->CursorInfo.dwSize = 5;
634 }
635 }
636
637
638
639 static BOOL FASTCALL
640 GuiConsoleHandleNcCreate(HWND hWnd, CREATESTRUCTW *Create)
641 {
642 RECT Rect;
643 PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) Create->lpCreateParams;
644 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)Console->PrivateData;
645 HDC Dc;
646 HFONT OldFont;
647 TEXTMETRICW Metrics;
648 PCSRSS_PROCESS_DATA ProcessData;
649 HKEY hKey;
650
651 Console->hWindow = hWnd;
652
653 if (NULL == GuiData)
654 {
655 DPRINT1("GuiConsoleNcCreate: HeapAlloc failed\n");
656 return FALSE;
657 }
658
659 GuiConsoleUseDefaults(Console, GuiData, Console->ActiveBuffer);
660 if (Console->ProcessList.Flink != &Console->ProcessList)
661 {
662 ProcessData = CONTAINING_RECORD(Console->ProcessList.Flink, CSRSS_PROCESS_DATA, ProcessEntry);
663 if (GuiConsoleOpenUserSettings(GuiData, PtrToUlong(ProcessData->ProcessId), &hKey, KEY_READ, FALSE))
664 {
665 GuiConsoleReadUserSettings(hKey, Console, GuiData, Console->ActiveBuffer);
666 RegCloseKey(hKey);
667 }
668 }
669
670 InitializeCriticalSection(&GuiData->Lock);
671
672 GuiData->LineBuffer = (PWCHAR)HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY,
673 Console->Size.X * sizeof(WCHAR));
674
675 GuiData->Font = CreateFontW(LOWORD(GuiData->FontSize),
676 0, //HIWORD(GuiData->FontSize),
677 0,
678 TA_BASELINE,
679 GuiData->FontWeight,
680 FALSE,
681 FALSE,
682 FALSE,
683 OEM_CHARSET,
684 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
685 NONANTIALIASED_QUALITY, FIXED_PITCH | FF_DONTCARE,
686 GuiData->FontName);
687 if (NULL == GuiData->Font)
688 {
689 DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
690 DeleteCriticalSection(&GuiData->Lock);
691 HeapFree(Win32CsrApiHeap, 0, GuiData);
692 return FALSE;
693 }
694 Dc = GetDC(hWnd);
695 if (NULL == Dc)
696 {
697 DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
698 DeleteObject(GuiData->Font);
699 DeleteCriticalSection(&GuiData->Lock);
700 HeapFree(Win32CsrApiHeap, 0, GuiData);
701 return FALSE;
702 }
703 OldFont = SelectObject(Dc, GuiData->Font);
704 if (NULL == OldFont)
705 {
706 DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
707 ReleaseDC(hWnd, Dc);
708 DeleteObject(GuiData->Font);
709 DeleteCriticalSection(&GuiData->Lock);
710 HeapFree(Win32CsrApiHeap, 0, GuiData);
711 return FALSE;
712 }
713 if (! GetTextMetricsW(Dc, &Metrics))
714 {
715 DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
716 SelectObject(Dc, OldFont);
717 ReleaseDC(hWnd, Dc);
718 DeleteObject(GuiData->Font);
719 DeleteCriticalSection(&GuiData->Lock);
720 HeapFree(Win32CsrApiHeap, 0, GuiData);
721 return FALSE;
722 }
723 GuiData->CharWidth = Metrics.tmMaxCharWidth;
724 GuiData->CharHeight = Metrics.tmHeight + Metrics.tmExternalLeading;
725 SelectObject(Dc, OldFont);
726
727 ReleaseDC(hWnd, Dc);
728 GuiData->CursorBlinkOn = TRUE;
729 GuiData->ForceCursorOff = FALSE;
730
731 GuiData->Selection.left = -1;
732 DPRINT("Console %p GuiData %p\n", Console, GuiData);
733 Console->PrivateData = GuiData;
734 SetWindowLongPtrW(hWnd, GWL_USERDATA, (DWORD_PTR) Console);
735
736 GetWindowRect(hWnd, &Rect);
737 Rect.right = Rect.left + Console->Size.X * GuiData->CharWidth +
738 2 * GetSystemMetrics(SM_CXFIXEDFRAME);
739 Rect.bottom = Rect.top + Console->Size.Y * GuiData->CharHeight +
740 2 * GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYCAPTION);
741 MoveWindow(hWnd, Rect.left, Rect.top, Rect.right - Rect.left,
742 Rect.bottom - Rect.top, FALSE);
743
744 SetTimer(hWnd, 1, CURSOR_BLINK_TIME, NULL);
745 GuiConsoleCreateSysMenu(Console);
746 SetEvent(GuiData->hGuiInitEvent);
747
748 return (BOOL) DefWindowProcW(hWnd, WM_NCCREATE, 0, (LPARAM) Create);
749 }
750
751 static COLORREF FASTCALL
752 GuiConsoleRGBFromAttribute(BYTE Attribute)
753 {
754 int Red = (Attribute & 0x04 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);
755 int Green = (Attribute & 0x02 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);
756 int Blue = (Attribute & 0x01 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);
757
758 return RGB(Red, Green, Blue);
759 }
760
761 static VOID FASTCALL
762 GuiConsoleSetTextColors(HDC Dc, BYTE Attribute, PCSRSS_SCREEN_BUFFER Buff, COLORREF TextColor, COLORREF BkColor)
763 {
764 if (Attribute != Buff->DefaultAttrib)
765 {
766 SetTextColor(Dc, GuiConsoleRGBFromAttribute(Attribute & 0x0f));
767 SetBkColor(Dc, GuiConsoleRGBFromAttribute((Attribute & 0xf0) >> 4));
768 }
769 else
770 {
771 SetTextColor(Dc, TextColor);
772 SetBkColor(Dc, BkColor);
773 }
774 }
775
776 static VOID FASTCALL
777 GuiConsoleGetLogicalCursorPos(PCSRSS_SCREEN_BUFFER Buff, ULONG *CursorX, ULONG *CursorY)
778 {
779 *CursorX = Buff->CurrentX;
780 if (Buff->CurrentY < Buff->ShowY)
781 {
782 *CursorY = Buff->MaxY - Buff->ShowY + Buff->CurrentY;
783 }
784 else
785 {
786 *CursorY = Buff->CurrentY - Buff->ShowY;
787 }
788 }
789
790
791 static VOID FASTCALL
792 GuiConsoleUpdateSelection(HWND hWnd, PRECT rc, PGUI_CONSOLE_DATA GuiData)
793 {
794 RECT oldRect = GuiData->Selection;
795
796 if(rc != NULL)
797 {
798 RECT changeRect = *rc;
799
800 GuiData->Selection = *rc;
801
802 changeRect.left *= GuiData->CharWidth;
803 changeRect.top *= GuiData->CharHeight;
804 changeRect.right *= GuiData->CharWidth;
805 changeRect.bottom *= GuiData->CharHeight;
806
807 if(rc->left != oldRect.left ||
808 rc->top != oldRect.top ||
809 rc->right != oldRect.right ||
810 rc->bottom != oldRect.bottom)
811 {
812 if(oldRect.left != -1)
813 {
814 HRGN rgn1, rgn2;
815
816 oldRect.left *= GuiData->CharWidth;
817 oldRect.top *= GuiData->CharHeight;
818 oldRect.right *= GuiData->CharWidth;
819 oldRect.bottom *= GuiData->CharHeight;
820
821 /* calculate the region that needs to be updated */
822 if((rgn1 = CreateRectRgnIndirect(&oldRect)))
823 {
824 if((rgn2 = CreateRectRgnIndirect(&changeRect)))
825 {
826 if(CombineRgn(rgn1, rgn2, rgn1, RGN_XOR) != ERROR)
827 {
828 InvalidateRgn(hWnd, rgn1, FALSE);
829 }
830
831 DeleteObject(rgn2);
832 }
833 DeleteObject(rgn1);
834 }
835 }
836 else
837 {
838 InvalidateRect(hWnd, &changeRect, FALSE);
839 }
840 }
841 }
842 else if(oldRect.left != -1)
843 {
844 /* clear the selection */
845 GuiData->Selection.left = -1;
846 oldRect.left *= GuiData->CharWidth;
847 oldRect.top *= GuiData->CharHeight;
848 oldRect.right *= GuiData->CharWidth;
849 oldRect.bottom *= GuiData->CharHeight;
850 InvalidateRect(hWnd, &oldRect, FALSE);
851 }
852 }
853
854
855 static VOID FASTCALL
856 GuiConsolePaint(PCSRSS_CONSOLE Console,
857 PGUI_CONSOLE_DATA GuiData,
858 HDC hDC,
859 PRECT rc)
860 {
861 PCSRSS_SCREEN_BUFFER Buff;
862 ULONG TopLine, BottomLine, LeftChar, RightChar;
863 ULONG Line, Char, Start;
864 PBYTE From;
865 PWCHAR To;
866 BYTE LastAttribute, Attribute;
867 ULONG CursorX, CursorY, CursorHeight;
868 HBRUSH CursorBrush, OldBrush, BackgroundBrush;
869 HFONT OldFont;
870
871 Buff = Console->ActiveBuffer;
872
873 TopLine = rc->top / GuiData->CharHeight;
874 BottomLine = (rc->bottom + (GuiData->CharHeight - 1)) / GuiData->CharHeight - 1;
875 LeftChar = rc->left / GuiData->CharWidth;
876 RightChar = (rc->right + (GuiData->CharWidth - 1)) / GuiData->CharWidth - 1;
877 LastAttribute = Buff->Buffer[(TopLine * Buff->MaxX + LeftChar) * 2 + 1];
878
879 GuiConsoleSetTextColors(hDC,
880 LastAttribute,
881 Buff,
882 GuiData->ScreenText,
883 GuiData->ScreenBackground);
884
885 EnterCriticalSection(&Buff->Header.Lock);
886
887 OldFont = SelectObject(hDC,
888 GuiData->Font);
889
890 BackgroundBrush = CreateSolidBrush(GuiData->ScreenBackground);
891 FillRect(hDC, rc, BackgroundBrush);
892 DeleteObject(BackgroundBrush);
893
894 for (Line = TopLine; Line <= BottomLine; Line++)
895 {
896 if (Line + Buff->ShowY < Buff->MaxY)
897 {
898 From = Buff->Buffer + ((Line + Buff->ShowY) * Buff->MaxX + LeftChar) * 2;
899 }
900 else
901 {
902 From = Buff->Buffer +
903 ((Line - (Buff->MaxY - Buff->ShowY)) * Buff->MaxX + LeftChar) * 2;
904 }
905 Start = LeftChar;
906 To = GuiData->LineBuffer;
907
908 for (Char = LeftChar; Char <= RightChar; Char++)
909 {
910 if (*(From + 1) != LastAttribute)
911 {
912 TextOutW(hDC,
913 Start * GuiData->CharWidth,
914 Line * GuiData->CharHeight,
915 GuiData->LineBuffer,
916 Char - Start);
917 Start = Char;
918 To = GuiData->LineBuffer;
919 Attribute = *(From + 1);
920 if (Attribute != LastAttribute)
921 {
922 GuiConsoleSetTextColors(hDC,
923 Attribute,
924 Buff,
925 GuiData->ScreenText,
926 GuiData->ScreenBackground);
927 LastAttribute = Attribute;
928 }
929 }
930
931 MultiByteToWideChar(Console->OutputCodePage,
932 0,
933 (PCHAR)From,
934 1,
935 To,
936 1);
937 To++;
938 From += 2;
939 }
940
941 TextOutW(hDC,
942 Start * GuiData->CharWidth,
943 Line * GuiData->CharHeight,
944 GuiData->LineBuffer,
945 RightChar - Start + 1);
946 }
947
948 if (Buff->CursorInfo.bVisible && GuiData->CursorBlinkOn &&
949 !GuiData->ForceCursorOff)
950 {
951 GuiConsoleGetLogicalCursorPos(Buff,
952 &CursorX,
953 &CursorY);
954 if (LeftChar <= CursorX && CursorX <= RightChar &&
955 TopLine <= CursorY && CursorY <= BottomLine)
956 {
957 CursorHeight = (GuiData->CharHeight * Buff->CursorInfo.dwSize) / 100;
958 if (CursorHeight < 1)
959 {
960 CursorHeight = 1;
961 }
962 From = Buff->Buffer + (Buff->CurrentY * Buff->MaxX + Buff->CurrentX) * 2 + 1;
963
964 if (*From != DEFAULT_ATTRIB)
965 {
966 CursorBrush = CreateSolidBrush(GuiConsoleRGBFromAttribute(*From));
967 }
968 else
969 {
970 CursorBrush = CreateSolidBrush(GuiData->ScreenText);
971 }
972
973 OldBrush = SelectObject(hDC,
974 CursorBrush);
975 PatBlt(hDC,
976 CursorX * GuiData->CharWidth,
977 CursorY * GuiData->CharHeight + (GuiData->CharHeight - CursorHeight),
978 GuiData->CharWidth,
979 CursorHeight,
980 PATCOPY);
981 SelectObject(hDC,
982 OldBrush);
983 DeleteObject(CursorBrush);
984 }
985 }
986
987 LeaveCriticalSection(&Buff->Header.Lock);
988
989 SelectObject(hDC,
990 OldFont);
991 }
992
993 static VOID FASTCALL
994 GuiConsoleHandlePaint(HWND hWnd, HDC hDCPaint)
995 {
996 HDC hDC;
997 PAINTSTRUCT ps;
998 PCSRSS_CONSOLE Console;
999 PGUI_CONSOLE_DATA GuiData;
1000
1001 hDC = BeginPaint(hWnd, &ps);
1002 if (hDC != NULL &&
1003 ps.rcPaint.left < ps.rcPaint.right &&
1004 ps.rcPaint.top < ps.rcPaint.bottom)
1005 {
1006 GuiConsoleGetDataPointers(hWnd,
1007 &Console,
1008 &GuiData);
1009 if (Console != NULL && GuiData != NULL &&
1010 Console->ActiveBuffer != NULL)
1011 {
1012 if (Console->ActiveBuffer->Buffer != NULL)
1013 {
1014 EnterCriticalSection(&GuiData->Lock);
1015
1016 GuiConsolePaint(Console,
1017 GuiData,
1018 hDC,
1019 &ps.rcPaint);
1020
1021 if (GuiData->Selection.left != -1)
1022 {
1023 RECT rc = GuiData->Selection;
1024
1025 rc.left *= GuiData->CharWidth;
1026 rc.top *= GuiData->CharHeight;
1027 rc.right *= GuiData->CharWidth;
1028 rc.bottom *= GuiData->CharHeight;
1029
1030 /* invert the selection */
1031 if (IntersectRect(&rc,
1032 &ps.rcPaint,
1033 &rc))
1034 {
1035 PatBlt(hDC,
1036 rc.left,
1037 rc.top,
1038 rc.right - rc.left,
1039 rc.bottom - rc.top,
1040 DSTINVERT);
1041 }
1042 }
1043
1044 LeaveCriticalSection(&GuiData->Lock);
1045 }
1046 }
1047
1048 EndPaint(hWnd, &ps);
1049 }
1050 }
1051
1052 static VOID FASTCALL
1053 GuiConsoleHandleKey(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1054 {
1055 PCSRSS_CONSOLE Console;
1056 PGUI_CONSOLE_DATA GuiData;
1057 MSG Message;
1058
1059 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1060 Message.hwnd = hWnd;
1061 Message.message = msg;
1062 Message.wParam = wParam;
1063 Message.lParam = lParam;
1064
1065 if(msg == WM_CHAR || msg == WM_SYSKEYDOWN)
1066 {
1067 /* clear the selection */
1068 GuiConsoleUpdateSelection(hWnd, NULL, GuiData);
1069 }
1070
1071 ConioProcessKey(&Message, Console, FALSE);
1072 }
1073
1074 static VOID FASTCALL
1075 GuiIntDrawRegion(PGUI_CONSOLE_DATA GuiData, HWND Wnd, RECT *Region)
1076 {
1077 RECT RegionRect;
1078
1079 RegionRect.left = Region->left * GuiData->CharWidth;
1080 RegionRect.top = Region->top * GuiData->CharHeight;
1081 RegionRect.right = (Region->right + 1) * GuiData->CharWidth;
1082 RegionRect.bottom = (Region->bottom + 1) * GuiData->CharHeight;
1083
1084 InvalidateRect(Wnd, &RegionRect, FALSE);
1085 }
1086
1087 static VOID STDCALL
1088 GuiDrawRegion(PCSRSS_CONSOLE Console, RECT *Region)
1089 {
1090 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA) Console->PrivateData;
1091
1092 if (NULL != Console->hWindow && NULL != GuiData)
1093 {
1094 GuiIntDrawRegion(GuiData, Console->hWindow, Region);
1095 }
1096 }
1097
1098 static VOID FASTCALL
1099 GuiInvalidateCell(PGUI_CONSOLE_DATA GuiData, HWND Wnd, UINT x, UINT y)
1100 {
1101 RECT CellRect;
1102
1103 CellRect.left = x;
1104 CellRect.top = y;
1105 CellRect.right = x;
1106 CellRect.bottom = y;
1107
1108 GuiIntDrawRegion(GuiData, Wnd, &CellRect);
1109 }
1110
1111 static VOID STDCALL
1112 GuiWriteStream(PCSRSS_CONSOLE Console, RECT *Region, LONG CursorStartX, LONG CursorStartY,
1113 UINT ScrolledLines, CHAR *Buffer, UINT Length)
1114 {
1115 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA) Console->PrivateData;
1116 PCSRSS_SCREEN_BUFFER Buff = Console->ActiveBuffer;
1117 LONG CursorEndX, CursorEndY;
1118 RECT ScrollRect;
1119
1120 if (NULL == Console->hWindow || NULL == GuiData)
1121 {
1122 return;
1123 }
1124
1125 if (0 != ScrolledLines)
1126 {
1127 ScrollRect.left = 0;
1128 ScrollRect.top = 0;
1129 ScrollRect.right = Console->Size.X * GuiData->CharWidth;
1130 ScrollRect.bottom = Region->top * GuiData->CharHeight;
1131
1132 if (GuiData->Selection.left != -1)
1133 {
1134 /* scroll the selection */
1135 if (GuiData->Selection.top > ScrolledLines)
1136 {
1137 GuiData->Selection.top -= ScrolledLines;
1138 GuiData->Selection.bottom -= ScrolledLines;
1139 }
1140 else if (GuiData->Selection.bottom < ScrolledLines)
1141 {
1142 GuiData->Selection.left = -1;
1143 }
1144 else
1145 {
1146 GuiData->Selection.top = 0;
1147 GuiData->Selection.bottom -= ScrolledLines;
1148 }
1149 }
1150
1151 ScrollWindowEx(Console->hWindow,
1152 0,
1153 -(ScrolledLines * GuiData->CharHeight),
1154 &ScrollRect,
1155 NULL,
1156 NULL,
1157 NULL,
1158 SW_INVALIDATE);
1159 }
1160
1161 GuiIntDrawRegion(GuiData, Console->hWindow, Region);
1162
1163 if (CursorStartX < Region->left || Region->right < CursorStartX
1164 || CursorStartY < Region->top || Region->bottom < CursorStartY)
1165 {
1166 GuiInvalidateCell(GuiData, Console->hWindow, CursorStartX, CursorStartY);
1167 }
1168
1169 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY,
1170 &CursorEndX, &CursorEndY);
1171 if ((CursorEndX < Region->left || Region->right < CursorEndX
1172 || CursorEndY < Region->top || Region->bottom < CursorEndY)
1173 && (CursorEndX != CursorStartX || CursorEndY != CursorStartY))
1174 {
1175 GuiInvalidateCell(GuiData, Console->hWindow, CursorEndX, CursorEndY);
1176 }
1177 }
1178
1179 static BOOL STDCALL
1180 GuiSetCursorInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff)
1181 {
1182 RECT UpdateRect;
1183
1184 if (Console->ActiveBuffer == Buff)
1185 {
1186 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY,
1187 &UpdateRect.left, &UpdateRect.top);
1188 UpdateRect.right = UpdateRect.left;
1189 UpdateRect.bottom = UpdateRect.top;
1190 ConioDrawRegion(Console, &UpdateRect);
1191 }
1192
1193 return TRUE;
1194 }
1195
1196 static BOOL STDCALL
1197 GuiSetScreenInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff, UINT OldCursorX, UINT OldCursorY)
1198 {
1199 RECT UpdateRect;
1200
1201 if (Console->ActiveBuffer == Buff)
1202 {
1203 /* Redraw char at old position (removes cursor) */
1204 UpdateRect.left = OldCursorX;
1205 UpdateRect.top = OldCursorY;
1206 UpdateRect.right = OldCursorX;
1207 UpdateRect.bottom = OldCursorY;
1208 ConioDrawRegion(Console, &UpdateRect);
1209 /* Redraw char at new position (shows cursor) */
1210 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY,
1211 &(UpdateRect.left), &(UpdateRect.top));
1212 UpdateRect.right = UpdateRect.left;
1213 UpdateRect.bottom = UpdateRect.top;
1214 ConioDrawRegion(Console, &UpdateRect);
1215 }
1216
1217 return TRUE;
1218 }
1219
1220 static VOID FASTCALL
1221 GuiConsoleHandleTimer(HWND hWnd)
1222 {
1223 PCSRSS_CONSOLE Console;
1224 PGUI_CONSOLE_DATA GuiData;
1225 RECT CursorRect;
1226 ULONG CursorX, CursorY;
1227
1228 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1229 GuiData->CursorBlinkOn = ! GuiData->CursorBlinkOn;
1230
1231 GuiConsoleGetLogicalCursorPos(Console->ActiveBuffer, &CursorX, &CursorY);
1232 CursorRect.left = CursorX;
1233 CursorRect.top = CursorY;
1234 CursorRect.right = CursorX;
1235 CursorRect.bottom = CursorY;
1236 GuiDrawRegion(Console, &CursorRect);
1237 }
1238
1239 static VOID FASTCALL
1240 GuiConsoleHandleClose(HWND hWnd)
1241 {
1242 PCSRSS_CONSOLE Console;
1243 PGUI_CONSOLE_DATA GuiData;
1244 PLIST_ENTRY current_entry;
1245 PCSRSS_PROCESS_DATA current;
1246
1247 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1248
1249 EnterCriticalSection(&Console->Header.Lock);
1250
1251 current_entry = Console->ProcessList.Flink;
1252 while (current_entry != &Console->ProcessList)
1253 {
1254 current = CONTAINING_RECORD(current_entry, CSRSS_PROCESS_DATA, ProcessEntry);
1255 current_entry = current_entry->Flink;
1256
1257 ConioConsoleCtrlEvent(CTRL_CLOSE_EVENT, current);
1258 }
1259
1260 LeaveCriticalSection(&Console->Header.Lock);
1261 }
1262
1263 static VOID FASTCALL
1264 GuiConsoleHandleNcDestroy(HWND hWnd)
1265 {
1266 PCSRSS_CONSOLE Console;
1267 PGUI_CONSOLE_DATA GuiData;
1268
1269
1270 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1271 KillTimer(hWnd, 1);
1272 Console->PrivateData = NULL;
1273 DeleteCriticalSection(&GuiData->Lock);
1274 GetSystemMenu(hWnd, TRUE);
1275 if (GuiData->ConsoleLibrary)
1276 FreeLibrary(GuiData->ConsoleLibrary);
1277
1278 HeapFree(Win32CsrApiHeap, 0, GuiData);
1279 }
1280
1281 static VOID FASTCALL
1282 GuiConsoleLeftMouseDown(HWND hWnd, LPARAM lParam)
1283 {
1284 PCSRSS_CONSOLE Console;
1285 PGUI_CONSOLE_DATA GuiData;
1286 POINTS pt;
1287 RECT rc;
1288
1289 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1290 if (Console == NULL || GuiData == NULL) return;
1291
1292 pt = MAKEPOINTS(lParam);
1293
1294 rc.left = pt.x / GuiData->CharWidth;
1295 rc.top = pt.y / GuiData->CharHeight;
1296 rc.right = rc.left + 1;
1297 rc.bottom = rc.top + 1;
1298
1299 GuiData->SelectionStart.x = rc.left;
1300 GuiData->SelectionStart.y = rc.top;
1301
1302 SetCapture(hWnd);
1303
1304 GuiData->MouseDown = TRUE;
1305
1306 GuiConsoleUpdateSelection(hWnd, &rc, GuiData);
1307 }
1308
1309 static VOID FASTCALL
1310 GuiConsoleLeftMouseUp(HWND hWnd, LPARAM lParam)
1311 {
1312 PCSRSS_CONSOLE Console;
1313 PGUI_CONSOLE_DATA GuiData;
1314 RECT rc;
1315 POINTS pt;
1316
1317 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1318 if (Console == NULL || GuiData == NULL) return;
1319 if (GuiData->Selection.left == -1 || !GuiData->MouseDown) return;
1320
1321 pt = MAKEPOINTS(lParam);
1322
1323 rc.left = GuiData->SelectionStart.x;
1324 rc.top = GuiData->SelectionStart.y;
1325 rc.right = (pt.x >= 0 ? (pt.x / GuiData->CharWidth) + 1 : 0);
1326 rc.bottom = (pt.y >= 0 ? (pt.y / GuiData->CharHeight) + 1 : 0);
1327
1328 /* exchange left/top with right/bottom if required */
1329 if(rc.left >= rc.right)
1330 {
1331 LONG tmp;
1332 tmp = rc.left;
1333 rc.left = max(rc.right - 1, 0);
1334 rc.right = tmp + 1;
1335 }
1336 if(rc.top >= rc.bottom)
1337 {
1338 LONG tmp;
1339 tmp = rc.top;
1340 rc.top = max(rc.bottom - 1, 0);
1341 rc.bottom = tmp + 1;
1342 }
1343
1344 GuiData->MouseDown = FALSE;
1345
1346 GuiConsoleUpdateSelection(hWnd, &rc, GuiData);
1347
1348 ReleaseCapture();
1349 }
1350
1351 static VOID FASTCALL
1352 GuiConsoleMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam)
1353 {
1354 PCSRSS_CONSOLE Console;
1355 PGUI_CONSOLE_DATA GuiData;
1356 RECT rc;
1357 POINTS pt;
1358
1359 if (!(wParam & MK_LBUTTON)) return;
1360
1361 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1362 if (Console == NULL || GuiData == NULL || !GuiData->MouseDown) return;
1363
1364 pt = MAKEPOINTS(lParam);
1365
1366 rc.left = GuiData->SelectionStart.x;
1367 rc.top = GuiData->SelectionStart.y;
1368 rc.right = (pt.x >= 0 ? (pt.x / GuiData->CharWidth) + 1 : 0);
1369 if (Console->Size.X < rc.right)
1370 {
1371 rc.right = Console->Size.X;
1372 }
1373 rc.bottom = (pt.y >= 0 ? (pt.y / GuiData->CharHeight) + 1 : 0);
1374 if (Console->Size.Y < rc.bottom)
1375 {
1376 rc.bottom = Console->Size.Y;
1377 }
1378
1379 /* exchange left/top with right/bottom if required */
1380 if(rc.left >= rc.right)
1381 {
1382 LONG tmp;
1383 tmp = rc.left;
1384 rc.left = max(rc.right - 1, 0);
1385 rc.right = tmp + 1;
1386 }
1387 if(rc.top >= rc.bottom)
1388 {
1389 LONG tmp;
1390 tmp = rc.top;
1391 rc.top = max(rc.bottom - 1, 0);
1392 rc.bottom = tmp + 1;
1393 }
1394
1395 GuiConsoleUpdateSelection(hWnd, &rc, GuiData);
1396 }
1397
1398 static VOID FASTCALL
1399 GuiConsoleRightMouseDown(HWND hWnd)
1400 {
1401 PCSRSS_CONSOLE Console;
1402 PGUI_CONSOLE_DATA GuiData;
1403
1404 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1405 if (Console == NULL || GuiData == NULL) return;
1406
1407 if (GuiData->Selection.left == -1)
1408 {
1409 /* FIXME - paste text from clipboard */
1410 }
1411 else
1412 {
1413 /* FIXME - copy selection to clipboard */
1414
1415 GuiConsoleUpdateSelection(hWnd, NULL, GuiData);
1416 }
1417
1418 }
1419
1420
1421 static VOID
1422 GuiConsoleShowConsoleProperties(HWND hWnd, BOOL Defaults, PGUI_CONSOLE_DATA GuiData)
1423 {
1424 PCSRSS_CONSOLE Console;
1425 APPLET_PROC CPLFunc;
1426 TCHAR szBuffer[MAX_PATH];
1427 ConsoleInfo SharedInfo;
1428
1429 DPRINT("GuiConsoleShowConsoleProperties entered\n");
1430
1431 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1432
1433 if (GuiData == NULL)
1434 {
1435 DPRINT("GuiConsoleGetDataPointers failed\n");
1436 return;
1437 }
1438
1439 if (GuiData->ConsoleLibrary == NULL)
1440 {
1441 GetWindowsDirectory(szBuffer,MAX_PATH);
1442 _tcscat(szBuffer, _T("\\system32\\console.dll"));
1443 GuiData->ConsoleLibrary = LoadLibrary(szBuffer);
1444
1445 if (GuiData->ConsoleLibrary == NULL)
1446 {
1447 DPRINT1("failed to load console.dll");
1448 return;
1449 }
1450 }
1451
1452 CPLFunc = (APPLET_PROC) GetProcAddress(GuiData->ConsoleLibrary, _T("CPlApplet"));
1453 if (!CPLFunc)
1454 {
1455 DPRINT("Error: Console.dll misses CPlApplet export\n");
1456 return;
1457 }
1458
1459 /* setup struct */
1460 SharedInfo.InsertMode = GuiData->InsertMode;
1461 SharedInfo.HistoryBufferSize = GuiData->HistoryBufferSize;
1462 SharedInfo.NumberOfHistoryBuffers = GuiData->NumberOfHistoryBuffers;
1463 SharedInfo.ScreenText = GuiData->ScreenText;
1464 SharedInfo.ScreenBackground = GuiData->ScreenBackground;
1465 SharedInfo.PopupText = GuiData->PopupText;
1466 SharedInfo.PopupBackground = GuiData->PopupBackground;
1467 SharedInfo.WindowSize = (DWORD)MAKELONG(Console->Size.X, Console->Size.Y);
1468 SharedInfo.WindowPosition = GuiData->WindowPosition;
1469 SharedInfo.ScreenBuffer = GuiData->ScreenBufferSize;
1470 SharedInfo.UseRasterFonts = GuiData->UseRasterFonts;
1471 SharedInfo.FontSize = (DWORD)GuiData->FontSize;
1472 SharedInfo.FontWeight = GuiData->FontWeight;
1473 SharedInfo.CursorSize = Console->ActiveBuffer->CursorInfo.dwSize;
1474 SharedInfo.HistoryNoDup = GuiData->HistoryNoDup;
1475 SharedInfo.FullScreen = GuiData->FullScreen;
1476 SharedInfo.QuickEdit = GuiData->QuickEdit;
1477 memcpy(&SharedInfo.Colors[0], GuiData->Colors, sizeof(s_Colors));
1478
1479 if (!CPLFunc(hWnd, CPL_INIT, 0, 0))
1480 {
1481 DPRINT("Error: failed to initialize console.dll\n");
1482 return;
1483 }
1484
1485 if (CPLFunc(hWnd, CPL_GETCOUNT, 0, 0) != 1)
1486 {
1487 DPRINT("Error: console.dll returned unexpected CPL count\n");
1488 return;
1489 }
1490
1491 CPLFunc(hWnd, CPL_DBLCLK, (LPARAM)&SharedInfo, Defaults);
1492 }
1493 static LRESULT FASTCALL
1494 GuiConsoleHandleSysMenuCommand(HWND hWnd, WPARAM wParam, LPARAM lParam, PGUI_CONSOLE_DATA GuiData)
1495 {
1496 LRESULT Ret = TRUE;
1497
1498 switch(wParam)
1499 {
1500 case ID_SYSTEM_EDIT_MARK:
1501 case ID_SYSTEM_EDIT_COPY:
1502 case ID_SYSTEM_EDIT_PASTE:
1503 case ID_SYSTEM_EDIT_SELECTALL:
1504 case ID_SYSTEM_EDIT_SCROLL:
1505 case ID_SYSTEM_EDIT_FIND:
1506 break;
1507
1508 case ID_SYSTEM_DEFAULTS:
1509 GuiConsoleShowConsoleProperties(hWnd, TRUE, GuiData);
1510 break;
1511
1512 case ID_SYSTEM_PROPERTIES:
1513 GuiConsoleShowConsoleProperties(hWnd, FALSE, GuiData);
1514 break;
1515
1516 default:
1517 Ret = DefWindowProcW(hWnd, WM_SYSCOMMAND, wParam, lParam);
1518 break;
1519 }
1520 return Ret;
1521 }
1522
1523 static VOID FASTCALL
1524 GuiConsoleResize(HWND hWnd, WPARAM wParam, LPARAM lParam)
1525 {
1526 PCSRSS_CONSOLE Console;
1527 PGUI_CONSOLE_DATA GuiData;
1528
1529 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1530 if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED || wParam == SIZE_MINIMIZED)
1531 {
1532 DPRINT1("GuiConsoleResize X %d Y %d\n", LOWORD(lParam), HIWORD(lParam));
1533 }
1534 }
1535
1536 VOID FASTCALL
1537 GuiConsoleCreateScrollBar(PCSRSS_CONSOLE Console, PGUI_CONSOLE_DATA GuiData, HWND NewWindow)
1538 {
1539 HMENU hMenu;
1540 HWND hVScrollBar;
1541 HWND hHScrollBar;
1542 SCROLLINFO sInfo;
1543
1544 hMenu = CreatePopupMenu();
1545 if (hMenu == NULL)
1546 {
1547 DPRINT("CreatePopupMenu failed\n");
1548 return;
1549 }
1550
1551 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLHERE);
1552 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1553 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLTOP);
1554 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLBOTTOM);
1555 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1556 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_UP);
1557 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_DOWN);
1558 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1559 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLUP);
1560 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLDOWN);
1561
1562 hVScrollBar = CreateWindowExW(0L,
1563 L"ScrollBar",
1564 (LPWSTR)NULL,
1565 WS_CHILD | WS_VSCROLL,
1566 0,
1567 0,
1568 200,
1569 50,
1570 NewWindow,
1571 NULL, //hMenu,
1572 GetModuleHandleW(NULL),
1573 (LPVOID)GuiData);
1574
1575 if (hVScrollBar)
1576 {
1577
1578 /* set scrollbar sizes */
1579 sInfo.cbSize = sizeof(SCROLLINFO);
1580 sInfo.fMask = SIF_RANGE | SIF_POS;
1581 sInfo.nMin = 0;
1582 sInfo.nMax = Console->ActiveBuffer->MaxY;
1583 sInfo.nPos = 0;
1584 SetScrollInfo(hVScrollBar, SB_CTL, &sInfo, TRUE);
1585 ShowScrollBar(NewWindow, SB_CTL, TRUE);
1586 GuiData->hVScrollBar = hVScrollBar;
1587 }
1588
1589 if (Console->ActiveBuffer->MaxX > Console->Size.X)
1590 {
1591 hHScrollBar = CreateWindowExW(0L,
1592 L"ScrollBar",
1593 (LPWSTR)NULL,
1594 WS_CHILD | WS_HSCROLL,
1595 0,
1596 0,
1597 200,
1598 CW_USEDEFAULT,
1599 NewWindow,
1600 hMenu,
1601 GetModuleHandleW(NULL),
1602 (LPVOID)GuiData);
1603 if (hHScrollBar)
1604 {
1605 sInfo.nMax = Console->ActiveBuffer->MaxX;
1606 SetScrollInfo(hHScrollBar, SB_CTL, &sInfo, TRUE);
1607 GuiData->hHScrollBar = hHScrollBar;
1608 }
1609 }
1610 }
1611
1612 static VOID FASTCALL
1613 GuiApplyUserSettings(PCSRSS_CONSOLE Console, PGUI_CONSOLE_DATA GuiData, PConsoleInfo pConInfo)
1614 {
1615 DWORD windx, windy;
1616 RECT rect;
1617
1618 /* apply text / background color */
1619 GuiData->ScreenText = pConInfo->ScreenText;
1620 GuiData->ScreenBackground = pConInfo->ScreenBackground;
1621
1622 /* apply cursor size */
1623 Console->ActiveBuffer->CursorInfo.dwSize = max(min(pConInfo->CursorSize, 1), 100);
1624
1625 windx = LOWORD(pConInfo->ScreenBuffer);
1626 windy = HIWORD(pConInfo->ScreenBuffer);
1627
1628 if (windx != Console->ActiveBuffer->MaxX || windy != Console->ActiveBuffer->MaxY)
1629 {
1630 BYTE * Buffer = HeapAlloc(Win32CsrApiHeap, 0, windx * windy * 2);
1631 if (Buffer)
1632 {
1633 DWORD Offset = 0;
1634 DWORD BufferOffset = 0;
1635 USHORT CurrentY;
1636 BYTE * OldBuffer;
1637 DWORD diff;
1638 DWORD value = ((((DWORD)Console->ActiveBuffer->DefaultAttrib) << 16) | 0x20);
1639
1640 OldBuffer = Console->ActiveBuffer->Buffer;
1641
1642 for (CurrentY = 0; CurrentY < min(Console->ActiveBuffer->MaxY, windy); CurrentY++)
1643 {
1644 if (windx < Console->ActiveBuffer->MaxX)
1645 {
1646 /* reduce size */
1647 RtlCopyMemory(&Buffer[Offset], &OldBuffer[BufferOffset], windx * 2);
1648 Offset += (windx * 2);
1649 BufferOffset += (Console->ActiveBuffer->MaxX * 2);
1650 }
1651 else
1652 {
1653 /* enlarge size */
1654 diff = windx - Console->ActiveBuffer->MaxX;
1655
1656 RtlCopyMemory(&Buffer[Offset], &OldBuffer[BufferOffset], Console->ActiveBuffer->MaxX * 2);
1657 Offset += (Console->ActiveBuffer->MaxX * 2);
1658 /* zero new part of it */
1659 memset(&Buffer[Offset], value, (diff * 2));
1660 Offset += (diff * 2);
1661 BufferOffset += (Console->ActiveBuffer->MaxX * 2);
1662 }
1663 }
1664
1665 if (windy > Console->ActiveBuffer->MaxY)
1666 {
1667 diff = windy - Console->ActiveBuffer->MaxX;
1668 memset(&Buffer[Offset], value, diff * 2 * windx);
1669 }
1670 (void)InterlockedExchangePointer((PVOID volatile *)Console->ActiveBuffer->Buffer, Buffer);
1671 HeapFree(Win32CsrApiHeap, 0, OldBuffer);
1672 Console->ActiveBuffer->MaxX = windx;
1673 Console->ActiveBuffer->MaxY = windy;
1674 }
1675 }
1676
1677 windx = LOWORD(pConInfo->WindowSize);
1678 windy = HIWORD(pConInfo->WindowSize);
1679
1680 if (windx != Console->Size.X || windy != Console->Size.Y)
1681 {
1682 /* resize window */
1683 Console->Size.X = windx;
1684 Console->Size.Y = windy;
1685
1686 GetWindowRect(pConInfo->hConsoleWindow, &rect);
1687
1688 rect.right = rect.left + Console->Size.X * GuiData->CharWidth + 2 * GetSystemMetrics(SM_CXFIXEDFRAME);
1689 rect.bottom = rect.top + Console->Size.Y * GuiData->CharHeight + 2 * GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYCAPTION);
1690
1691 MoveWindow(pConInfo->hConsoleWindow, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, FALSE);
1692
1693 if (Console->Size.X < Console->ActiveBuffer->MaxX)
1694 {
1695 /* show scrollbar when window becomes smaller than active screen buffer */
1696 //ShowScrollBar(GuiData->hHScrollBar, SB_CTL, TRUE);
1697 }
1698 else
1699 {
1700 /* hide scrollbar */
1701 //ShowScrollBar(GuiData->hHScrollBar, SB_CTL, FALSE);
1702 }
1703 }
1704 /* repaint window */
1705 InvalidateRect(pConInfo->hConsoleWindow, NULL, TRUE);
1706 }
1707
1708 static LRESULT CALLBACK
1709 GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1710 {
1711 LRESULT Result = 0;
1712 PGUI_CONSOLE_DATA GuiData = NULL;
1713 PCSRSS_CONSOLE Console = NULL;
1714
1715 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1716
1717 switch(msg)
1718 {
1719 case WM_NCCREATE:
1720 Result = (LRESULT) GuiConsoleHandleNcCreate(hWnd, (CREATESTRUCTW *) lParam);
1721 break;
1722 case WM_PAINT:
1723 GuiConsoleHandlePaint(hWnd, (HDC)wParam);
1724 break;
1725 case WM_KEYDOWN:
1726 case WM_KEYUP:
1727 case WM_SYSKEYDOWN:
1728 case WM_SYSKEYUP:
1729 case WM_CHAR:
1730 GuiConsoleHandleKey(hWnd, msg, wParam, lParam);
1731 break;
1732 case WM_TIMER:
1733 GuiConsoleHandleTimer(hWnd);
1734 break;
1735 case WM_CLOSE:
1736 GuiConsoleHandleClose(hWnd);
1737 break;
1738 case WM_NCDESTROY:
1739 GuiConsoleHandleNcDestroy(hWnd);
1740 break;
1741 case WM_LBUTTONDOWN:
1742 GuiConsoleLeftMouseDown(hWnd, lParam);
1743 break;
1744 case WM_LBUTTONUP:
1745 GuiConsoleLeftMouseUp(hWnd, lParam);
1746 break;
1747 case WM_RBUTTONDOWN:
1748 GuiConsoleRightMouseDown(hWnd);
1749 break;
1750 case WM_MOUSEMOVE:
1751 GuiConsoleMouseMove(hWnd, wParam, lParam);
1752 break;
1753 case WM_SYSCOMMAND:
1754 Result = GuiConsoleHandleSysMenuCommand(hWnd, wParam, lParam, GuiData);
1755 break;
1756 case WM_SIZE:
1757 GuiConsoleResize(hWnd, wParam, lParam);
1758 break;
1759 case PM_APPLY_CONSOLE_INFO:
1760 GuiApplyUserSettings(Console, GuiData, (PConsoleInfo)wParam);
1761 if (lParam)
1762 {
1763 GuiConsoleWriteUserSettings(Console, GuiData);
1764 }
1765 break;
1766 default:
1767 Result = DefWindowProcW(hWnd, msg, wParam, lParam);
1768 break;
1769 }
1770
1771 return Result;
1772 }
1773
1774 static LRESULT CALLBACK
1775 GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1776 {
1777 HWND NewWindow;
1778 LONG WindowCount;
1779 MSG Msg;
1780 PWCHAR Buffer, Title;
1781 PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) lParam;
1782
1783
1784
1785 switch(msg)
1786 {
1787 case WM_CREATE:
1788 SetWindowLongW(hWnd, GWL_USERDATA, 0);
1789 return 0;
1790 case PM_CREATE_CONSOLE:
1791 Buffer = HeapAlloc(Win32CsrApiHeap, 0,
1792 Console->Title.Length + sizeof(WCHAR));
1793 if (NULL != Buffer)
1794 {
1795 memcpy(Buffer, Console->Title.Buffer, Console->Title.Length);
1796 Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0';
1797 Title = Buffer;
1798 }
1799 else
1800 {
1801 Title = L"";
1802 }
1803 NewWindow = CreateWindowW(L"ConsoleWindowClass",
1804 Title,
1805 WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, //WS_OVERLAPPEDWINDOW
1806 CW_USEDEFAULT,
1807 CW_USEDEFAULT,
1808 CW_USEDEFAULT,
1809 CW_USEDEFAULT,
1810 NULL,
1811 NULL,
1812 (HINSTANCE) GetModuleHandleW(NULL),
1813 (PVOID) Console);
1814 if (NULL != Buffer)
1815 {
1816 HeapFree(Win32CsrApiHeap, 0, Buffer);
1817 }
1818 if (NULL != NewWindow)
1819 {
1820 // scrollbar support
1821 //GuiConsoleCreateScrollBar(Console, (PGUI_CONSOLE_DATA)Console->PrivateData, NewWindow);
1822 SetWindowLongW(hWnd, GWL_USERDATA, GetWindowLongW(hWnd, GWL_USERDATA) + 1);
1823 ShowWindow(NewWindow, SW_SHOW);
1824 }
1825 return (LRESULT) NewWindow;
1826 case PM_DESTROY_CONSOLE:
1827 /* Window creation is done using a PostMessage(), so it's possible that the
1828 * window that we want to destroy doesn't exist yet. So first empty the message
1829 * queue */
1830 while(PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
1831 {
1832 TranslateMessage(&Msg);
1833 DispatchMessageW(&Msg);
1834 }
1835 DestroyWindow(Console->hWindow);
1836 Console->hWindow = NULL;
1837 WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
1838 WindowCount--;
1839 SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
1840 if (0 == WindowCount)
1841 {
1842 NotifyWnd = NULL;
1843 DestroyWindow(hWnd);
1844 PrivateCsrssManualGuiCheck(-1);
1845 PostQuitMessage(0);
1846 }
1847 return 0;
1848 default:
1849 return DefWindowProcW(hWnd, msg, wParam, lParam);
1850 }
1851 }
1852
1853 static DWORD STDCALL
1854 GuiConsoleGuiThread(PVOID Data)
1855 {
1856 MSG msg;
1857 PHANDLE GraphicsStartupEvent = (PHANDLE) Data;
1858
1859 NotifyWnd = CreateWindowW(L"Win32CsrCreateNotify",
1860 L"",
1861 WS_OVERLAPPEDWINDOW,
1862 CW_USEDEFAULT,
1863 CW_USEDEFAULT,
1864 CW_USEDEFAULT,
1865 CW_USEDEFAULT,
1866 NULL,
1867 NULL,
1868 (HINSTANCE) GetModuleHandleW(NULL),
1869 NULL);
1870 if (NULL == NotifyWnd)
1871 {
1872 PrivateCsrssManualGuiCheck(-1);
1873 SetEvent(*GraphicsStartupEvent);
1874 return 1;
1875 }
1876
1877 SetEvent(*GraphicsStartupEvent);
1878
1879 while(GetMessageW(&msg, NULL, 0, 0))
1880 {
1881 TranslateMessage(&msg);
1882 DispatchMessageW(&msg);
1883 }
1884
1885 return 1;
1886 }
1887
1888 static BOOL FASTCALL
1889 GuiInit(VOID)
1890 {
1891 WNDCLASSEXW wc;
1892
1893 if (NULL == NotifyWnd)
1894 {
1895 PrivateCsrssManualGuiCheck(+1);
1896 }
1897
1898 wc.cbSize = sizeof(WNDCLASSEXW);
1899 wc.lpszClassName = L"Win32CsrCreateNotify";
1900 wc.lpfnWndProc = GuiConsoleNotifyWndProc;
1901 wc.style = 0;
1902 wc.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
1903 wc.hIcon = NULL;
1904 wc.hCursor = NULL;
1905 wc.hbrBackground = NULL;
1906 wc.lpszMenuName = NULL;
1907 wc.cbClsExtra = 0;
1908 wc.cbWndExtra = 0;
1909 wc.hIconSm = NULL;
1910 if (RegisterClassExW(&wc) == 0)
1911 {
1912 DPRINT1("Failed to register notify wndproc\n");
1913 return FALSE;
1914 }
1915
1916 wc.cbSize = sizeof(WNDCLASSEXW);
1917 wc.lpszClassName = L"ConsoleWindowClass";
1918 wc.lpfnWndProc = GuiConsoleWndProc;
1919 wc.style = 0;
1920 wc.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
1921 wc.hIcon = LoadIconW(GetModuleHandleW(L"win32csr"), MAKEINTRESOURCEW(1));
1922 wc.hCursor = LoadCursorW(NULL, (LPCWSTR) IDC_ARROW);
1923 wc.hbrBackground = NULL;
1924 wc.lpszMenuName = NULL;
1925 wc.cbClsExtra = 0;
1926 wc.cbWndExtra = 0;
1927 wc.hIconSm = LoadImageW(GetModuleHandleW(L"win32csr"), MAKEINTRESOURCEW(1), IMAGE_ICON,
1928 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
1929 LR_SHARED);
1930 if (RegisterClassExW(&wc) == 0)
1931 {
1932 DPRINT1("Failed to register console wndproc\n");
1933 return FALSE;
1934 }
1935
1936 return TRUE;
1937 }
1938
1939 static VOID STDCALL
1940 GuiInitScreenBuffer(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buffer)
1941 {
1942 Buffer->DefaultAttrib = DEFAULT_ATTRIB;
1943 }
1944
1945 static BOOL STDCALL
1946 GuiChangeTitle(PCSRSS_CONSOLE Console)
1947 {
1948 PWCHAR Buffer, Title;
1949
1950 Buffer = HeapAlloc(Win32CsrApiHeap, 0,
1951 Console->Title.Length + sizeof(WCHAR));
1952 if (NULL != Buffer)
1953 {
1954 memcpy(Buffer, Console->Title.Buffer, Console->Title.Length);
1955 Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0';
1956 Title = Buffer;
1957 }
1958 else
1959 {
1960 Title = L"";
1961 }
1962
1963 SendMessageW(Console->hWindow, WM_SETTEXT, 0, (LPARAM) Title);
1964
1965 if (NULL != Buffer)
1966 {
1967 HeapFree(Win32CsrApiHeap, 0, Buffer);
1968 }
1969
1970 return TRUE;
1971 }
1972
1973 static BOOL STDCALL
1974 GuiChangeIcon(PCSRSS_CONSOLE Console)
1975 {
1976 SendMessageW(Console->hWindow, WM_SETICON, ICON_BIG, (LPARAM)Console->hWindowIcon);
1977 SendMessageW(Console->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)Console->hWindowIcon);
1978
1979 return TRUE;
1980 }
1981
1982 static VOID STDCALL
1983 GuiCleanupConsole(PCSRSS_CONSOLE Console)
1984 {
1985 SendMessageW(NotifyWnd, PM_DESTROY_CONSOLE, 0, (LPARAM) Console);
1986 }
1987
1988 static CSRSS_CONSOLE_VTBL GuiVtbl =
1989 {
1990 GuiInitScreenBuffer,
1991 GuiWriteStream,
1992 GuiDrawRegion,
1993 GuiSetCursorInfo,
1994 GuiSetScreenInfo,
1995 GuiChangeTitle,
1996 GuiCleanupConsole,
1997 GuiChangeIcon
1998 };
1999
2000 NTSTATUS FASTCALL
2001 GuiInitConsole(PCSRSS_CONSOLE Console)
2002 {
2003 HANDLE GraphicsStartupEvent;
2004 HANDLE ThreadHandle;
2005 PGUI_CONSOLE_DATA GuiData;
2006
2007 if (! ConsInitialized)
2008 {
2009 ConsInitialized = TRUE;
2010 if (! GuiInit())
2011 {
2012 ConsInitialized = FALSE;
2013 return STATUS_UNSUCCESSFUL;
2014 }
2015 }
2016
2017 Console->Vtbl = &GuiVtbl;
2018 if (NULL == NotifyWnd)
2019 {
2020 GraphicsStartupEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
2021 if (NULL == GraphicsStartupEvent)
2022 {
2023 return STATUS_UNSUCCESSFUL;
2024 }
2025
2026 ThreadHandle = CreateThread(NULL,
2027 0,
2028 GuiConsoleGuiThread,
2029 (PVOID) &GraphicsStartupEvent,
2030 0,
2031 NULL);
2032 if (NULL == ThreadHandle)
2033 {
2034 NtClose(GraphicsStartupEvent);
2035 DPRINT1("Win32Csr: Failed to create graphics console thread. Expect problems\n");
2036 return STATUS_UNSUCCESSFUL;
2037 }
2038 SetThreadPriority(ThreadHandle, THREAD_PRIORITY_HIGHEST);
2039 CloseHandle(ThreadHandle);
2040
2041 WaitForSingleObject(GraphicsStartupEvent, INFINITE);
2042 CloseHandle(GraphicsStartupEvent);
2043
2044 if (NULL == NotifyWnd)
2045 {
2046 DPRINT1("Win32Csr: Failed to create notification window.\n");
2047 return STATUS_UNSUCCESSFUL;
2048 }
2049 }
2050 GuiData = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY,
2051 sizeof(GUI_CONSOLE_DATA));
2052 if (!GuiData)
2053 {
2054 DPRINT1("Win32Csr: Failed to create GUI_CONSOLE_DATA\n");
2055 return STATUS_UNSUCCESSFUL;
2056 }
2057
2058 Console->PrivateData = (PVOID) GuiData;
2059 /*
2060 * we need to wait untill the GUI has been fully initialized
2061 * to retrieve custom settings i.e. WindowSize etc..
2062 * Ideally we could use SendNotifyMessage for this but its not
2063 * yet implemented.
2064 *
2065 */
2066 GuiData->hGuiInitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
2067 /* create console */
2068 PostMessageW(NotifyWnd, PM_CREATE_CONSOLE, 0, (LPARAM) Console);
2069
2070 /* wait untill initialization has finished */
2071 WaitForSingleObject(GuiData->hGuiInitEvent, INFINITE);
2072 DPRINT1("received event Console %p GuiData %p X %d Y %d\n", Console, Console->PrivateData, Console->Size.X, Console->Size.Y);
2073 CloseHandle(GuiData->hGuiInitEvent);
2074 GuiData->hGuiInitEvent = NULL;
2075
2076 return STATUS_SUCCESS;
2077 }
2078
2079 /* EOF */