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