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