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