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