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