- add hActiveBuffer member to struct to ensure that modifying the screenbuffer is...
[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 PCSRSS_SCREEN_BUFFER ActiveBuffer;
1618 PCSRSS_PROCESS_DATA ProcessData = NULL;
1619
1620 if (Console->ProcessList.Flink != &Console->ProcessList)
1621 {
1622 ProcessData = CONTAINING_RECORD(Console->ProcessList.Flink, CSRSS_PROCESS_DATA, ProcessEntry);
1623 ConioLockScreenBuffer(ProcessData, Console->hActiveBuffer, (Object_t **)&ActiveBuffer);
1624 }
1625
1626 /* apply text / background color */
1627 GuiData->ScreenText = pConInfo->ScreenText;
1628 GuiData->ScreenBackground = pConInfo->ScreenBackground;
1629
1630 /* apply cursor size */
1631 Console->ActiveBuffer->CursorInfo.dwSize = max(min(pConInfo->CursorSize, 1), 100);
1632
1633 windx = LOWORD(pConInfo->ScreenBuffer);
1634 windy = HIWORD(pConInfo->ScreenBuffer);
1635
1636 if (windx != ActiveBuffer->MaxX || windy != ActiveBuffer->MaxY)
1637 {
1638 BYTE * Buffer = HeapAlloc(Win32CsrApiHeap, 0, windx * windy * 2);
1639
1640 if (Buffer)
1641 {
1642 DWORD Offset = 0;
1643 DWORD BufferOffset = 0;
1644 USHORT CurrentY;
1645 BYTE * OldBuffer;
1646 USHORT value;
1647 DWORD diff;
1648 DWORD i;
1649
1650 value = MAKEWORD(' ', ActiveBuffer->DefaultAttrib);
1651
1652 DPRINT("MaxX %d MaxY %d windx %d windy %d value %04x DefaultAttrib %d\n",ActiveBuffer->MaxX, ActiveBuffer->MaxY, windx, windy, value, ActiveBuffer->DefaultAttrib);
1653 OldBuffer = ActiveBuffer->Buffer;
1654
1655 for (CurrentY = 0; CurrentY < min(ActiveBuffer->MaxY, windy); CurrentY++)
1656 {
1657 if (windx <= ActiveBuffer->MaxX)
1658 {
1659 /* reduce size */
1660 RtlCopyMemory(&Buffer[Offset], &OldBuffer[BufferOffset], windx * 2);
1661 Offset += (windx * 2);
1662 BufferOffset += (ActiveBuffer->MaxX * 2);
1663 }
1664 else
1665 {
1666 /* enlarge size */
1667 RtlCopyMemory(&Buffer[Offset], &OldBuffer[BufferOffset], ActiveBuffer->MaxX * 2);
1668 Offset += (ActiveBuffer->MaxX * 2);
1669
1670 diff = windx - ActiveBuffer->MaxX;
1671 /* zero new part of it */
1672 #if HAVE_WMEMSET
1673 wmemset((WCHAR*)&Buffer[Offset], value, diff);
1674 #else
1675 for (i = 0; i < diff * 2; i++)
1676 {
1677 Buffer[Offset * 2] = ' ';
1678 Buffer[Offset * 2 + 1] = ActiveBuffer->DefaultAttrib;
1679 }
1680 #endif
1681 Offset += (diff * 2);
1682 BufferOffset += (Console->ActiveBuffer->MaxX * 2);
1683 }
1684 }
1685
1686 if (windy > Console->ActiveBuffer->MaxY)
1687 {
1688 diff = windy - Console->ActiveBuffer->MaxX;
1689 #if HAVE_WMEMSET
1690 wmemset((WCHAR*)&Buffer[Offset], value, diff * windx);
1691 #else
1692 for (i = 0; i < diff * 2; i++)
1693 {
1694 Buffer[Offset * 2] = ' ';
1695 Buffer[Offset * 2 + 1] = ActiveBuffer->DefaultAttrib;
1696 }
1697 #endif
1698 }
1699
1700 (void)InterlockedExchangePointer((PVOID volatile *)&Console->ActiveBuffer->Buffer, Buffer);
1701 HeapFree(Win32CsrApiHeap, 0, OldBuffer);
1702 Console->ActiveBuffer->MaxX = windx;
1703 Console->ActiveBuffer->MaxY = windy;
1704 InvalidateRect(pConInfo->hConsoleWindow, NULL, TRUE);
1705 }
1706 else
1707 {
1708 if (ProcessData)
1709 {
1710 ConioUnlockScreenBuffer(ActiveBuffer);
1711 }
1712 return;
1713 }
1714 }
1715
1716 windx = LOWORD(pConInfo->WindowSize);
1717 windy = HIWORD(pConInfo->WindowSize);
1718
1719 if (windx > Console->Size.X)
1720 {
1721 PWCHAR LineBuffer = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY, windx * sizeof(WCHAR));
1722 if (LineBuffer)
1723 {
1724 HeapFree(Win32CsrApiHeap, 0, GuiData->LineBuffer);
1725 GuiData->LineBuffer = LineBuffer;
1726 }
1727 else
1728 {
1729 if (ProcessData)
1730 {
1731 ConioUnlockScreenBuffer(ActiveBuffer);
1732 }
1733 return;
1734 }
1735 }
1736
1737
1738 if (windx != Console->Size.X || windy != Console->Size.Y)
1739 {
1740 /* resize window */
1741 Console->Size.X = windx;
1742 Console->Size.Y = windy;
1743
1744 GetWindowRect(pConInfo->hConsoleWindow, &rect);
1745
1746 rect.right = rect.left + Console->Size.X * GuiData->CharWidth + 2 * GetSystemMetrics(SM_CXFIXEDFRAME);
1747 rect.bottom = rect.top + Console->Size.Y * GuiData->CharHeight + 2 * GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYCAPTION);
1748
1749 MoveWindow(pConInfo->hConsoleWindow, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, FALSE);
1750
1751 if (Console->Size.X < Console->ActiveBuffer->MaxX)
1752 {
1753 /* show scrollbar when window becomes smaller than active screen buffer */
1754 //ShowScrollBar(GuiData->hHScrollBar, SB_CTL, TRUE);
1755 }
1756 else
1757 {
1758 /* hide scrollbar */
1759 //ShowScrollBar(GuiData->hHScrollBar, SB_CTL, FALSE);
1760 }
1761 }
1762 if (ProcessData)
1763 {
1764 ConioUnlockScreenBuffer(ActiveBuffer);
1765 }
1766 InvalidateRect(pConInfo->hConsoleWindow, NULL, TRUE);
1767 }
1768
1769 static LRESULT CALLBACK
1770 GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1771 {
1772 LRESULT Result = 0;
1773 PGUI_CONSOLE_DATA GuiData = NULL;
1774 PCSRSS_CONSOLE Console = NULL;
1775
1776 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1777
1778 switch(msg)
1779 {
1780 case WM_NCCREATE:
1781 Result = (LRESULT) GuiConsoleHandleNcCreate(hWnd, (CREATESTRUCTW *) lParam);
1782 break;
1783 case WM_PAINT:
1784 GuiConsoleHandlePaint(hWnd, (HDC)wParam);
1785 break;
1786 case WM_KEYDOWN:
1787 case WM_KEYUP:
1788 case WM_SYSKEYDOWN:
1789 case WM_SYSKEYUP:
1790 case WM_CHAR:
1791 GuiConsoleHandleKey(hWnd, msg, wParam, lParam);
1792 break;
1793 case WM_TIMER:
1794 GuiConsoleHandleTimer(hWnd);
1795 break;
1796 case WM_CLOSE:
1797 GuiConsoleHandleClose(hWnd);
1798 break;
1799 case WM_NCDESTROY:
1800 GuiConsoleHandleNcDestroy(hWnd);
1801 break;
1802 case WM_LBUTTONDOWN:
1803 GuiConsoleLeftMouseDown(hWnd, lParam);
1804 break;
1805 case WM_LBUTTONUP:
1806 GuiConsoleLeftMouseUp(hWnd, lParam);
1807 break;
1808 case WM_RBUTTONDOWN:
1809 GuiConsoleRightMouseDown(hWnd);
1810 break;
1811 case WM_MOUSEMOVE:
1812 GuiConsoleMouseMove(hWnd, wParam, lParam);
1813 break;
1814 case WM_SYSCOMMAND:
1815 Result = GuiConsoleHandleSysMenuCommand(hWnd, wParam, lParam, GuiData);
1816 break;
1817 case WM_SIZE:
1818 GuiConsoleResize(hWnd, wParam, lParam);
1819 break;
1820 case PM_APPLY_CONSOLE_INFO:
1821 GuiApplyUserSettings(Console, GuiData, (PConsoleInfo)wParam);
1822 if (lParam)
1823 {
1824 GuiConsoleWriteUserSettings(Console, GuiData);
1825 }
1826 break;
1827 default:
1828 Result = DefWindowProcW(hWnd, msg, wParam, lParam);
1829 break;
1830 }
1831
1832 return Result;
1833 }
1834
1835 static LRESULT CALLBACK
1836 GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1837 {
1838 HWND NewWindow;
1839 LONG WindowCount;
1840 MSG Msg;
1841 PWCHAR Buffer, Title;
1842 PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) lParam;
1843
1844
1845
1846 switch(msg)
1847 {
1848 case WM_CREATE:
1849 SetWindowLongW(hWnd, GWL_USERDATA, 0);
1850 return 0;
1851 case PM_CREATE_CONSOLE:
1852 Buffer = HeapAlloc(Win32CsrApiHeap, 0,
1853 Console->Title.Length + sizeof(WCHAR));
1854 if (NULL != Buffer)
1855 {
1856 memcpy(Buffer, Console->Title.Buffer, Console->Title.Length);
1857 Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0';
1858 Title = Buffer;
1859 }
1860 else
1861 {
1862 Title = L"";
1863 }
1864 NewWindow = CreateWindowW(L"ConsoleWindowClass",
1865 Title,
1866 WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, //WS_OVERLAPPEDWINDOW
1867 CW_USEDEFAULT,
1868 CW_USEDEFAULT,
1869 CW_USEDEFAULT,
1870 CW_USEDEFAULT,
1871 NULL,
1872 NULL,
1873 (HINSTANCE) GetModuleHandleW(NULL),
1874 (PVOID) Console);
1875 if (NULL != Buffer)
1876 {
1877 HeapFree(Win32CsrApiHeap, 0, Buffer);
1878 }
1879 if (NULL != NewWindow)
1880 {
1881 // scrollbar support
1882 //GuiConsoleCreateScrollBar(Console, (PGUI_CONSOLE_DATA)Console->PrivateData, NewWindow);
1883 SetWindowLongW(hWnd, GWL_USERDATA, GetWindowLongW(hWnd, GWL_USERDATA) + 1);
1884 ShowWindow(NewWindow, SW_SHOW);
1885 }
1886 return (LRESULT) NewWindow;
1887 case PM_DESTROY_CONSOLE:
1888 /* Window creation is done using a PostMessage(), so it's possible that the
1889 * window that we want to destroy doesn't exist yet. So first empty the message
1890 * queue */
1891 while(PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
1892 {
1893 TranslateMessage(&Msg);
1894 DispatchMessageW(&Msg);
1895 }
1896 DestroyWindow(Console->hWindow);
1897 Console->hWindow = NULL;
1898 WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
1899 WindowCount--;
1900 SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
1901 if (0 == WindowCount)
1902 {
1903 NotifyWnd = NULL;
1904 DestroyWindow(hWnd);
1905 PrivateCsrssManualGuiCheck(-1);
1906 PostQuitMessage(0);
1907 }
1908 return 0;
1909 default:
1910 return DefWindowProcW(hWnd, msg, wParam, lParam);
1911 }
1912 }
1913
1914 static DWORD STDCALL
1915 GuiConsoleGuiThread(PVOID Data)
1916 {
1917 MSG msg;
1918 PHANDLE GraphicsStartupEvent = (PHANDLE) Data;
1919
1920 NotifyWnd = CreateWindowW(L"Win32CsrCreateNotify",
1921 L"",
1922 WS_OVERLAPPEDWINDOW,
1923 CW_USEDEFAULT,
1924 CW_USEDEFAULT,
1925 CW_USEDEFAULT,
1926 CW_USEDEFAULT,
1927 NULL,
1928 NULL,
1929 (HINSTANCE) GetModuleHandleW(NULL),
1930 NULL);
1931 if (NULL == NotifyWnd)
1932 {
1933 PrivateCsrssManualGuiCheck(-1);
1934 SetEvent(*GraphicsStartupEvent);
1935 return 1;
1936 }
1937
1938 SetEvent(*GraphicsStartupEvent);
1939
1940 while(GetMessageW(&msg, NULL, 0, 0))
1941 {
1942 TranslateMessage(&msg);
1943 DispatchMessageW(&msg);
1944 }
1945
1946 return 1;
1947 }
1948
1949 static BOOL FASTCALL
1950 GuiInit(VOID)
1951 {
1952 WNDCLASSEXW wc;
1953
1954 if (NULL == NotifyWnd)
1955 {
1956 PrivateCsrssManualGuiCheck(+1);
1957 }
1958
1959 wc.cbSize = sizeof(WNDCLASSEXW);
1960 wc.lpszClassName = L"Win32CsrCreateNotify";
1961 wc.lpfnWndProc = GuiConsoleNotifyWndProc;
1962 wc.style = 0;
1963 wc.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
1964 wc.hIcon = NULL;
1965 wc.hCursor = NULL;
1966 wc.hbrBackground = NULL;
1967 wc.lpszMenuName = NULL;
1968 wc.cbClsExtra = 0;
1969 wc.cbWndExtra = 0;
1970 wc.hIconSm = NULL;
1971 if (RegisterClassExW(&wc) == 0)
1972 {
1973 DPRINT1("Failed to register notify wndproc\n");
1974 return FALSE;
1975 }
1976
1977 wc.cbSize = sizeof(WNDCLASSEXW);
1978 wc.lpszClassName = L"ConsoleWindowClass";
1979 wc.lpfnWndProc = GuiConsoleWndProc;
1980 wc.style = 0;
1981 wc.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
1982 wc.hIcon = LoadIconW(GetModuleHandleW(L"win32csr"), MAKEINTRESOURCEW(1));
1983 wc.hCursor = LoadCursorW(NULL, (LPCWSTR) IDC_ARROW);
1984 wc.hbrBackground = NULL;
1985 wc.lpszMenuName = NULL;
1986 wc.cbClsExtra = 0;
1987 wc.cbWndExtra = 0;
1988 wc.hIconSm = LoadImageW(GetModuleHandleW(L"win32csr"), MAKEINTRESOURCEW(1), IMAGE_ICON,
1989 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
1990 LR_SHARED);
1991 if (RegisterClassExW(&wc) == 0)
1992 {
1993 DPRINT1("Failed to register console wndproc\n");
1994 return FALSE;
1995 }
1996
1997 return TRUE;
1998 }
1999
2000 static VOID STDCALL
2001 GuiInitScreenBuffer(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buffer)
2002 {
2003 Buffer->DefaultAttrib = DEFAULT_ATTRIB;
2004 }
2005
2006 static BOOL STDCALL
2007 GuiChangeTitle(PCSRSS_CONSOLE Console)
2008 {
2009 PWCHAR Buffer, Title;
2010
2011 Buffer = HeapAlloc(Win32CsrApiHeap, 0,
2012 Console->Title.Length + sizeof(WCHAR));
2013 if (NULL != Buffer)
2014 {
2015 memcpy(Buffer, Console->Title.Buffer, Console->Title.Length);
2016 Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0';
2017 Title = Buffer;
2018 }
2019 else
2020 {
2021 Title = L"";
2022 }
2023
2024 SendMessageW(Console->hWindow, WM_SETTEXT, 0, (LPARAM) Title);
2025
2026 if (NULL != Buffer)
2027 {
2028 HeapFree(Win32CsrApiHeap, 0, Buffer);
2029 }
2030
2031 return TRUE;
2032 }
2033
2034 static BOOL STDCALL
2035 GuiChangeIcon(PCSRSS_CONSOLE Console)
2036 {
2037 SendMessageW(Console->hWindow, WM_SETICON, ICON_BIG, (LPARAM)Console->hWindowIcon);
2038 SendMessageW(Console->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)Console->hWindowIcon);
2039
2040 return TRUE;
2041 }
2042
2043 static VOID STDCALL
2044 GuiCleanupConsole(PCSRSS_CONSOLE Console)
2045 {
2046 SendMessageW(NotifyWnd, PM_DESTROY_CONSOLE, 0, (LPARAM) Console);
2047 }
2048
2049 static CSRSS_CONSOLE_VTBL GuiVtbl =
2050 {
2051 GuiInitScreenBuffer,
2052 GuiWriteStream,
2053 GuiDrawRegion,
2054 GuiSetCursorInfo,
2055 GuiSetScreenInfo,
2056 GuiChangeTitle,
2057 GuiCleanupConsole,
2058 GuiChangeIcon
2059 };
2060
2061 NTSTATUS FASTCALL
2062 GuiInitConsole(PCSRSS_CONSOLE Console)
2063 {
2064 HANDLE GraphicsStartupEvent;
2065 HANDLE ThreadHandle;
2066 PGUI_CONSOLE_DATA GuiData;
2067
2068 if (! ConsInitialized)
2069 {
2070 ConsInitialized = TRUE;
2071 if (! GuiInit())
2072 {
2073 ConsInitialized = FALSE;
2074 return STATUS_UNSUCCESSFUL;
2075 }
2076 }
2077
2078 Console->Vtbl = &GuiVtbl;
2079 if (NULL == NotifyWnd)
2080 {
2081 GraphicsStartupEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
2082 if (NULL == GraphicsStartupEvent)
2083 {
2084 return STATUS_UNSUCCESSFUL;
2085 }
2086
2087 ThreadHandle = CreateThread(NULL,
2088 0,
2089 GuiConsoleGuiThread,
2090 (PVOID) &GraphicsStartupEvent,
2091 0,
2092 NULL);
2093 if (NULL == ThreadHandle)
2094 {
2095 NtClose(GraphicsStartupEvent);
2096 DPRINT1("Win32Csr: Failed to create graphics console thread. Expect problems\n");
2097 return STATUS_UNSUCCESSFUL;
2098 }
2099 SetThreadPriority(ThreadHandle, THREAD_PRIORITY_HIGHEST);
2100 CloseHandle(ThreadHandle);
2101
2102 WaitForSingleObject(GraphicsStartupEvent, INFINITE);
2103 CloseHandle(GraphicsStartupEvent);
2104
2105 if (NULL == NotifyWnd)
2106 {
2107 DPRINT1("Win32Csr: Failed to create notification window.\n");
2108 return STATUS_UNSUCCESSFUL;
2109 }
2110 }
2111 GuiData = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY,
2112 sizeof(GUI_CONSOLE_DATA));
2113 if (!GuiData)
2114 {
2115 DPRINT1("Win32Csr: Failed to create GUI_CONSOLE_DATA\n");
2116 return STATUS_UNSUCCESSFUL;
2117 }
2118
2119 Console->PrivateData = (PVOID) GuiData;
2120 /*
2121 * we need to wait untill the GUI has been fully initialized
2122 * to retrieve custom settings i.e. WindowSize etc..
2123 * Ideally we could use SendNotifyMessage for this but its not
2124 * yet implemented.
2125 *
2126 */
2127 GuiData->hGuiInitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
2128 /* create console */
2129 PostMessageW(NotifyWnd, PM_CREATE_CONSOLE, 0, (LPARAM) Console);
2130
2131 /* wait untill initialization has finished */
2132 WaitForSingleObject(GuiData->hGuiInitEvent, INFINITE);
2133 DPRINT1("received event Console %p GuiData %p X %d Y %d\n", Console, Console->PrivateData, Console->Size.X, Console->Size.Y);
2134 CloseHandle(GuiData->hGuiInitEvent);
2135 GuiData->hGuiInitEvent = NULL;
2136
2137 return STATUS_SUCCESS;
2138 }
2139
2140 /* EOF */