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