8742538a1b204f6c9684a37eb0a47780b684db21
[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 DWORD windx, windy;
1504
1505 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1506 if((Console == NULL)|| (GuiData == NULL)) return;
1507
1508 windx = CONGUI_MIN_WIDTH * GuiData->CharWidth + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
1509 windy = CONGUI_MIN_HEIGHT * GuiData->CharHeight + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
1510
1511 minMaxInfo->ptMinTrackSize.x = windx;
1512 minMaxInfo->ptMinTrackSize.y = windy;
1513
1514 windx = (Console->ActiveBuffer->MaxX) * GuiData->CharWidth + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
1515 windy = (Console->ActiveBuffer->MaxY) * GuiData->CharHeight + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
1516
1517 if(Console->Size.X < Console->ActiveBuffer->MaxX) windy += GetSystemMetrics(SM_CYHSCROLL); // window currently has a horizontal scrollbar
1518 if(Console->Size.Y < Console->ActiveBuffer->MaxY) windx += GetSystemMetrics(SM_CXVSCROLL); // window currently has a vertical scrollbar
1519
1520 minMaxInfo->ptMaxTrackSize.x = windx;
1521 minMaxInfo->ptMaxTrackSize.y = windy;
1522 }
1523 static VOID
1524 GuiConsoleResize(HWND hWnd, WPARAM wParam, LPARAM lParam)
1525 {
1526 PCSRSS_CONSOLE Console;
1527 PGUI_CONSOLE_DATA GuiData;
1528 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1529 if((Console == NULL) || (GuiData == NULL)) return;
1530
1531 if ((GuiData->WindowSizeLock == FALSE) && (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED || wParam == SIZE_MINIMIZED))
1532 {
1533 PCSRSS_SCREEN_BUFFER Buff = Console->ActiveBuffer;
1534 DWORD windx, windy, charx, chary;
1535
1536 GuiData->WindowSizeLock = TRUE;
1537
1538 windx = LOWORD(lParam);
1539 windy = HIWORD(lParam);
1540
1541 // Compensate for existing scroll bars (because lParam values do not accommodate scroll bar)
1542 if(Console->Size.X < Buff->MaxX) windy += GetSystemMetrics(SM_CYHSCROLL); // window currently has a horizontal scrollbar
1543 if(Console->Size.Y < Buff->MaxY) windx += GetSystemMetrics(SM_CXVSCROLL); // window currently has a vertical scrollbar
1544
1545 charx = windx / GuiData->CharWidth;
1546 chary = windy / GuiData->CharHeight;
1547
1548 // Character alignment (round size up or down)
1549 if((windx % GuiData->CharWidth) >= (GuiData->CharWidth / 2)) ++charx;
1550 if((windy % GuiData->CharHeight) >= (GuiData->CharHeight / 2)) ++chary;
1551
1552 // Compensate for added scroll bars in new window
1553 if(charx < Buff->MaxX)windy -= GetSystemMetrics(SM_CYHSCROLL); // new window will have a horizontal scroll bar
1554 if(chary < Buff->MaxY)windx -= GetSystemMetrics(SM_CXVSCROLL); // new window will have a vertical scroll bar
1555
1556 charx = windx / GuiData->CharWidth;
1557 chary = windy / GuiData->CharHeight;
1558
1559 // Character alignment (round size up or down)
1560 if((windx % GuiData->CharWidth) >= (GuiData->CharWidth / 2)) ++charx;
1561 if((windy % GuiData->CharHeight) >= (GuiData->CharHeight / 2)) ++chary;
1562
1563 // Resize window
1564 if((charx != Console->Size.X) || (chary != Console->Size.Y))
1565 {
1566 Console->Size.X = (charx <= Buff->MaxX) ? charx : Buff->MaxX;
1567 Console->Size.Y = (chary <= Buff->MaxY) ? chary : Buff->MaxY;
1568 }
1569
1570 GuiConsoleInitScrollbar(Console, hWnd);
1571
1572 // Adjust the start of the visible area if we are attempting to show nonexistent areas
1573 if((Buff->MaxX - Buff->ShowX) < Console->Size.X) Buff->ShowX = Buff->MaxX - Console->Size.X;
1574 if((Buff->MaxY - Buff->ShowY) < Console->Size.Y) Buff->ShowY = Buff->MaxY - Console->Size.Y;
1575 InvalidateRect(hWnd, NULL, TRUE);
1576
1577 GuiData->WindowSizeLock = FALSE;
1578 }
1579 }
1580
1581 VOID
1582 FASTCALL
1583 GuiConsoleHandleScrollbarMenu()
1584 {
1585 HMENU hMenu;
1586
1587 hMenu = CreatePopupMenu();
1588 if (hMenu == NULL)
1589 {
1590 DPRINT("CreatePopupMenu failed\n");
1591 return;
1592 }
1593 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLHERE);
1594 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1595 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLTOP);
1596 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLBOTTOM);
1597 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1598 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_UP);
1599 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_DOWN);
1600 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1601 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLUP);
1602 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLDOWN);
1603
1604 }
1605
1606 static NTSTATUS WINAPI
1607 GuiResizeBuffer(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER ScreenBuffer, COORD Size)
1608 {
1609 BYTE * Buffer;
1610 DWORD Offset = 0;
1611 BYTE * OldPtr;
1612 USHORT CurrentY;
1613 BYTE * OldBuffer;
1614 #if HAVE_WMEMSET
1615 USHORT value = MAKEWORD(' ', ScreenBuffer->DefaultAttrib);
1616 #endif
1617 DWORD diff;
1618 DWORD i;
1619
1620 /* Buffer size is not allowed to be smaller than window size */
1621 if (Size.X < Console->Size.X || Size.Y < Console->Size.Y)
1622 return STATUS_INVALID_PARAMETER;
1623
1624 if (Size.X == ScreenBuffer->MaxX && Size.Y == ScreenBuffer->MaxY)
1625 return STATUS_SUCCESS;
1626
1627 Buffer = HeapAlloc(Win32CsrApiHeap, 0, Size.X * Size.Y * 2);
1628 if (!Buffer)
1629 return STATUS_NO_MEMORY;
1630
1631 DPRINT1("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer->MaxX, ScreenBuffer->MaxY, Size.X, Size.Y);
1632 OldBuffer = ScreenBuffer->Buffer;
1633
1634 for (CurrentY = 0; CurrentY < ScreenBuffer->MaxY && CurrentY < Size.Y; CurrentY++)
1635 {
1636 OldPtr = ConioCoordToPointer(ScreenBuffer, 0, CurrentY);
1637 if (Size.X <= ScreenBuffer->MaxX)
1638 {
1639 /* reduce size */
1640 RtlCopyMemory(&Buffer[Offset], OldPtr, Size.X * 2);
1641 Offset += (Size.X * 2);
1642 }
1643 else
1644 {
1645 /* enlarge size */
1646 RtlCopyMemory(&Buffer[Offset], OldPtr, ScreenBuffer->MaxX * 2);
1647 Offset += (ScreenBuffer->MaxX * 2);
1648
1649 diff = Size.X - ScreenBuffer->MaxX;
1650 /* zero new part of it */
1651 #if HAVE_WMEMSET
1652 wmemset((WCHAR*)&Buffer[Offset], value, diff);
1653 #else
1654 for (i = 0; i < diff; i++)
1655 {
1656 Buffer[Offset++] = ' ';
1657 Buffer[Offset++] = ScreenBuffer->DefaultAttrib;
1658 }
1659 #endif
1660 }
1661 }
1662
1663 if (Size.Y > ScreenBuffer->MaxY)
1664 {
1665 diff = Size.X * (Size.Y - ScreenBuffer->MaxY);
1666 #if HAVE_WMEMSET
1667 wmemset((WCHAR*)&Buffer[Offset], value, diff);
1668 #else
1669 for (i = 0; i < diff; i++)
1670 {
1671 Buffer[Offset++] = ' ';
1672 Buffer[Offset++] = ScreenBuffer->DefaultAttrib;
1673 }
1674 #endif
1675 }
1676
1677 (void)InterlockedExchangePointer((PVOID volatile *)&ScreenBuffer->Buffer, Buffer);
1678 HeapFree(Win32CsrApiHeap, 0, OldBuffer);
1679 ScreenBuffer->MaxX = Size.X;
1680 ScreenBuffer->MaxY = Size.Y;
1681 ScreenBuffer->VirtualY = 0;
1682
1683 /* Ensure cursor and window are within buffer */
1684 if (ScreenBuffer->CurrentX >= Size.X)
1685 ScreenBuffer->CurrentX = Size.X - 1;
1686 if (ScreenBuffer->CurrentY >= Size.Y)
1687 ScreenBuffer->CurrentY = Size.Y - 1;
1688 if (ScreenBuffer->ShowX > Size.X - Console->Size.X)
1689 ScreenBuffer->ShowX = Size.X - Console->Size.X;
1690 if (ScreenBuffer->ShowY > Size.Y - Console->Size.Y)
1691 ScreenBuffer->ShowY = Size.Y - Console->Size.Y;
1692
1693 /* TODO: Should update scrollbar, but can't use anything that
1694 * calls SendMessage or it could cause deadlock */
1695
1696 return STATUS_SUCCESS;
1697 }
1698
1699 static VOID
1700 GuiApplyUserSettings(PCSRSS_CONSOLE Console, PGUI_CONSOLE_DATA GuiData, PConsoleInfo pConInfo)
1701 {
1702 DWORD windx, windy;
1703 PCSRSS_SCREEN_BUFFER ActiveBuffer = Console->ActiveBuffer;
1704 COORD BufSize;
1705 BOOL SizeChanged = FALSE;
1706
1707 EnterCriticalSection(&Console->Lock);
1708
1709 /* apply text / background color */
1710 GuiData->ScreenText = pConInfo->ScreenText;
1711 GuiData->ScreenBackground = pConInfo->ScreenBackground;
1712
1713 /* apply cursor size */
1714 ActiveBuffer->CursorInfo.dwSize = min(max(pConInfo->CursorSize, 1), 100);
1715
1716 windx = LOWORD(pConInfo->WindowSize);
1717 windy = HIWORD(pConInfo->WindowSize);
1718
1719 if (windx != Console->Size.X || windy != Console->Size.Y)
1720 {
1721 /* resize window */
1722 Console->Size.X = windx;
1723 Console->Size.Y = windy;
1724 SizeChanged = TRUE;
1725 }
1726
1727 BufSize.X = LOWORD(pConInfo->ScreenBuffer);
1728 BufSize.Y = HIWORD(pConInfo->ScreenBuffer);
1729 if (BufSize.X != ActiveBuffer->MaxX || BufSize.Y != ActiveBuffer->MaxY)
1730 {
1731 if (NT_SUCCESS(GuiResizeBuffer(Console, ActiveBuffer, BufSize)))
1732 SizeChanged = TRUE;
1733 }
1734
1735 if (SizeChanged)
1736 {
1737 GuiData->WindowSizeLock = TRUE;
1738 GuiConsoleInitScrollbar(Console, pConInfo->hConsoleWindow);
1739 GuiData->WindowSizeLock = FALSE;
1740 }
1741
1742 LeaveCriticalSection(&Console->Lock);
1743 InvalidateRect(pConInfo->hConsoleWindow, NULL, TRUE);
1744 }
1745
1746 static
1747 LRESULT
1748 GuiConsoleHandleScroll(HWND hwnd, UINT uMsg, WPARAM wParam)
1749 {
1750 PCSRSS_CONSOLE Console;
1751 PCSRSS_SCREEN_BUFFER Buff;
1752 PGUI_CONSOLE_DATA GuiData;
1753 SCROLLINFO sInfo;
1754 int fnBar;
1755 int old_pos, Maximum;
1756 PUSHORT pShowXY;
1757
1758 GuiConsoleGetDataPointers(hwnd, &Console, &GuiData);
1759 if (Console == NULL || GuiData == NULL)
1760 return FALSE;
1761 Buff = Console->ActiveBuffer;
1762
1763 if (uMsg == WM_HSCROLL)
1764 {
1765 fnBar = SB_HORZ;
1766 Maximum = Buff->MaxX - Console->Size.X;
1767 pShowXY = &Buff->ShowX;
1768 }
1769 else
1770 {
1771 fnBar = SB_VERT;
1772 Maximum = Buff->MaxY - Console->Size.Y;
1773 pShowXY = &Buff->ShowY;
1774 }
1775
1776 /* set scrollbar sizes */
1777 sInfo.cbSize = sizeof(SCROLLINFO);
1778 sInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE | SIF_TRACKPOS;
1779
1780 if (!GetScrollInfo(hwnd, fnBar, &sInfo))
1781 {
1782 return FALSE;
1783 }
1784
1785 old_pos = sInfo.nPos;
1786
1787 switch(LOWORD(wParam))
1788 {
1789 case SB_LINELEFT:
1790 sInfo.nPos -= 1;
1791 break;
1792
1793 case SB_LINERIGHT:
1794 sInfo.nPos += 1;
1795 break;
1796
1797 case SB_PAGELEFT:
1798 sInfo.nPos -= sInfo.nPage;
1799 break;
1800
1801 case SB_PAGERIGHT:
1802 sInfo.nPos += sInfo.nPage;
1803 break;
1804
1805 case SB_THUMBTRACK:
1806 sInfo.nPos = sInfo.nTrackPos;
1807 ConioPause(Console, PAUSED_FROM_SCROLLBAR);
1808 break;
1809
1810 case SB_THUMBPOSITION:
1811 ConioUnpause(Console, PAUSED_FROM_SCROLLBAR);
1812 break;
1813
1814 case SB_TOP:
1815 sInfo.nPos = sInfo.nMin;
1816 break;
1817
1818 case SB_BOTTOM:
1819 sInfo.nPos = sInfo.nMax;
1820 break;
1821
1822 default:
1823 break;
1824 }
1825
1826 sInfo.nPos = max(sInfo.nPos, 0);
1827 sInfo.nPos = min(sInfo.nPos, Maximum);
1828
1829 if (old_pos != sInfo.nPos)
1830 {
1831 USHORT OldX = Buff->ShowX;
1832 USHORT OldY = Buff->ShowY;
1833 *pShowXY = sInfo.nPos;
1834
1835 ScrollWindowEx(hwnd,
1836 (OldX - Buff->ShowX) * GuiData->CharWidth,
1837 (OldY - Buff->ShowY) * GuiData->CharHeight,
1838 NULL,
1839 NULL,
1840 NULL,
1841 NULL,
1842 SW_INVALIDATE);
1843
1844 sInfo.fMask = SIF_POS;
1845 SetScrollInfo(hwnd, fnBar, &sInfo, TRUE);
1846
1847 UpdateWindow(hwnd);
1848 }
1849 return 0;
1850 }
1851
1852 static LRESULT CALLBACK
1853 GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1854 {
1855 LRESULT Result = 0;
1856 PGUI_CONSOLE_DATA GuiData = NULL;
1857 PCSRSS_CONSOLE Console = NULL;
1858
1859 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1860
1861 switch(msg)
1862 {
1863 case WM_NCCREATE:
1864 Result = (LRESULT) GuiConsoleHandleNcCreate(hWnd, (CREATESTRUCTW *) lParam);
1865 break;
1866 case WM_PAINT:
1867 GuiConsoleHandlePaint(hWnd, (HDC)wParam);
1868 break;
1869 case WM_KEYDOWN:
1870 case WM_KEYUP:
1871 case WM_SYSKEYDOWN:
1872 case WM_SYSKEYUP:
1873 case WM_CHAR:
1874 GuiConsoleHandleKey(hWnd, msg, wParam, lParam);
1875 break;
1876 case WM_TIMER:
1877 GuiConsoleHandleTimer(hWnd);
1878 break;
1879 case WM_CLOSE:
1880 GuiConsoleHandleClose(hWnd);
1881 break;
1882 case WM_NCDESTROY:
1883 GuiConsoleHandleNcDestroy(hWnd);
1884 break;
1885 case WM_LBUTTONDOWN:
1886 GuiConsoleLeftMouseDown(hWnd, lParam);
1887 break;
1888 case WM_LBUTTONUP:
1889 GuiConsoleLeftMouseUp(hWnd, lParam);
1890 break;
1891 case WM_RBUTTONDOWN:
1892 GuiConsoleRightMouseDown(hWnd);
1893 break;
1894 case WM_MOUSEMOVE:
1895 GuiConsoleMouseMove(hWnd, wParam, lParam);
1896 break;
1897 case WM_SYSCOMMAND:
1898 Result = GuiConsoleHandleSysMenuCommand(hWnd, wParam, lParam, GuiData);
1899 break;
1900 case WM_HSCROLL:
1901 case WM_VSCROLL:
1902 Result = GuiConsoleHandleScroll(hWnd, msg, wParam);
1903 break;
1904 case WM_GETMINMAXINFO:
1905 GuiConsoleGetMinMaxInfo(hWnd, (PMINMAXINFO)lParam);
1906 break;
1907 case WM_SIZE:
1908 GuiConsoleResize(hWnd, wParam, lParam);
1909 break;
1910 case PM_APPLY_CONSOLE_INFO:
1911 GuiApplyUserSettings(Console, GuiData, (PConsoleInfo)wParam);
1912 if (lParam)
1913 {
1914 GuiConsoleWriteUserSettings(Console, GuiData);
1915 }
1916 break;
1917 default:
1918 Result = DefWindowProcW(hWnd, msg, wParam, lParam);
1919 break;
1920 }
1921
1922 return Result;
1923 }
1924
1925 static LRESULT CALLBACK
1926 GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1927 {
1928 HWND NewWindow;
1929 LONG WindowCount;
1930 MSG Msg;
1931 PWCHAR Buffer, Title;
1932 PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) lParam;
1933
1934
1935
1936 switch(msg)
1937 {
1938 case WM_CREATE:
1939 SetWindowLongW(hWnd, GWL_USERDATA, 0);
1940 return 0;
1941 case PM_CREATE_CONSOLE:
1942 Buffer = HeapAlloc(Win32CsrApiHeap, 0,
1943 Console->Title.Length + sizeof(WCHAR));
1944 if (NULL != Buffer)
1945 {
1946 memcpy(Buffer, Console->Title.Buffer, Console->Title.Length);
1947 Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0';
1948 Title = Buffer;
1949 }
1950 else
1951 {
1952 Title = L"";
1953 }
1954 NewWindow = CreateWindowExW(WS_EX_CLIENTEDGE,
1955 L"ConsoleWindowClass",
1956 Title,
1957 WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
1958 CW_USEDEFAULT,
1959 CW_USEDEFAULT,
1960 CW_USEDEFAULT,
1961 CW_USEDEFAULT,
1962 NULL,
1963 NULL,
1964 (HINSTANCE) GetModuleHandleW(NULL),
1965 (PVOID) Console);
1966 if (NULL != Buffer)
1967 {
1968 HeapFree(Win32CsrApiHeap, 0, Buffer);
1969 }
1970 if (NULL != NewWindow)
1971 {
1972 SetWindowLongW(hWnd, GWL_USERDATA, GetWindowLongW(hWnd, GWL_USERDATA) + 1);
1973 if (wParam)
1974 {
1975 ShowWindow(NewWindow, SW_SHOW);
1976 }
1977 }
1978 return (LRESULT) NewWindow;
1979 case PM_DESTROY_CONSOLE:
1980 /* Window creation is done using a PostMessage(), so it's possible that the
1981 * window that we want to destroy doesn't exist yet. So first empty the message
1982 * queue */
1983 while(PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
1984 {
1985 TranslateMessage(&Msg);
1986 DispatchMessageW(&Msg);
1987 }
1988 DestroyWindow(Console->hWindow);
1989 Console->hWindow = NULL;
1990 WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
1991 WindowCount--;
1992 SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
1993 if (0 == WindowCount)
1994 {
1995 NotifyWnd = NULL;
1996 DestroyWindow(hWnd);
1997 PrivateCsrssManualGuiCheck(-1);
1998 PostQuitMessage(0);
1999 }
2000 return 0;
2001 default:
2002 return DefWindowProcW(hWnd, msg, wParam, lParam);
2003 }
2004 }
2005
2006 static DWORD WINAPI
2007 GuiConsoleGuiThread(PVOID Data)
2008 {
2009 MSG msg;
2010 PHANDLE GraphicsStartupEvent = (PHANDLE) Data;
2011
2012 NotifyWnd = CreateWindowW(L"Win32CsrCreateNotify",
2013 L"",
2014 WS_OVERLAPPEDWINDOW,
2015 CW_USEDEFAULT,
2016 CW_USEDEFAULT,
2017 CW_USEDEFAULT,
2018 CW_USEDEFAULT,
2019 NULL,
2020 NULL,
2021 (HINSTANCE) GetModuleHandleW(NULL),
2022 NULL);
2023 if (NULL == NotifyWnd)
2024 {
2025 PrivateCsrssManualGuiCheck(-1);
2026 SetEvent(*GraphicsStartupEvent);
2027 return 1;
2028 }
2029
2030 SetEvent(*GraphicsStartupEvent);
2031
2032 while(GetMessageW(&msg, NULL, 0, 0))
2033 {
2034 TranslateMessage(&msg);
2035 DispatchMessageW(&msg);
2036 }
2037
2038 return 1;
2039 }
2040
2041 static BOOL
2042 GuiInit(VOID)
2043 {
2044 WNDCLASSEXW wc;
2045
2046 if (NULL == NotifyWnd)
2047 {
2048 PrivateCsrssManualGuiCheck(+1);
2049 }
2050
2051 wc.cbSize = sizeof(WNDCLASSEXW);
2052 wc.lpszClassName = L"Win32CsrCreateNotify";
2053 wc.lpfnWndProc = GuiConsoleNotifyWndProc;
2054 wc.style = 0;
2055 wc.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
2056 wc.hIcon = NULL;
2057 wc.hCursor = NULL;
2058 wc.hbrBackground = NULL;
2059 wc.lpszMenuName = NULL;
2060 wc.cbClsExtra = 0;
2061 wc.cbWndExtra = 0;
2062 wc.hIconSm = NULL;
2063 if (RegisterClassExW(&wc) == 0)
2064 {
2065 DPRINT1("Failed to register notify wndproc\n");
2066 return FALSE;
2067 }
2068
2069 wc.cbSize = sizeof(WNDCLASSEXW);
2070 wc.lpszClassName = L"ConsoleWindowClass";
2071 wc.lpfnWndProc = GuiConsoleWndProc;
2072 wc.style = 0;
2073 wc.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
2074 wc.hIcon = LoadIconW(GetModuleHandleW(L"win32csr"), MAKEINTRESOURCEW(1));
2075 wc.hCursor = LoadCursorW(NULL, (LPCWSTR) IDC_ARROW);
2076 wc.hbrBackground = CreateSolidBrush(RGB(0,0,0));
2077 wc.lpszMenuName = NULL;
2078 wc.cbClsExtra = 0;
2079 wc.cbWndExtra = 0;
2080 wc.hIconSm = LoadImageW(GetModuleHandleW(L"win32csr"), MAKEINTRESOURCEW(1), IMAGE_ICON,
2081 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
2082 LR_SHARED);
2083 if (RegisterClassExW(&wc) == 0)
2084 {
2085 DPRINT1("Failed to register console wndproc\n");
2086 return FALSE;
2087 }
2088
2089 return TRUE;
2090 }
2091
2092 static VOID WINAPI
2093 GuiInitScreenBuffer(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buffer)
2094 {
2095 Buffer->DefaultAttrib = DEFAULT_ATTRIB;
2096 }
2097
2098 static BOOL WINAPI
2099 GuiChangeTitle(PCSRSS_CONSOLE Console)
2100 {
2101 PWCHAR Buffer, Title;
2102
2103 Buffer = HeapAlloc(Win32CsrApiHeap, 0,
2104 Console->Title.Length + sizeof(WCHAR));
2105 if (NULL != Buffer)
2106 {
2107 memcpy(Buffer, Console->Title.Buffer, Console->Title.Length);
2108 Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0';
2109 Title = Buffer;
2110 }
2111 else
2112 {
2113 Title = L"";
2114 }
2115
2116 SendMessageW(Console->hWindow, WM_SETTEXT, 0, (LPARAM) Title);
2117
2118 if (NULL != Buffer)
2119 {
2120 HeapFree(Win32CsrApiHeap, 0, Buffer);
2121 }
2122
2123 return TRUE;
2124 }
2125
2126 static BOOL WINAPI
2127 GuiChangeIcon(PCSRSS_CONSOLE Console, HICON hWindowIcon)
2128 {
2129 SendMessageW(Console->hWindow, WM_SETICON, ICON_BIG, (LPARAM)hWindowIcon);
2130 SendMessageW(Console->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)hWindowIcon);
2131
2132 return TRUE;
2133 }
2134
2135 static VOID WINAPI
2136 GuiCleanupConsole(PCSRSS_CONSOLE Console)
2137 {
2138 SendMessageW(NotifyWnd, PM_DESTROY_CONSOLE, 0, (LPARAM) Console);
2139 }
2140
2141 static CSRSS_CONSOLE_VTBL GuiVtbl =
2142 {
2143 GuiInitScreenBuffer,
2144 GuiWriteStream,
2145 GuiDrawRegion,
2146 GuiSetCursorInfo,
2147 GuiSetScreenInfo,
2148 GuiUpdateScreenInfo,
2149 GuiChangeTitle,
2150 GuiCleanupConsole,
2151 GuiChangeIcon,
2152 GuiResizeBuffer,
2153 };
2154
2155 NTSTATUS FASTCALL
2156 GuiInitConsole(PCSRSS_CONSOLE Console, BOOL Visible)
2157 {
2158 HANDLE GraphicsStartupEvent;
2159 HANDLE ThreadHandle;
2160 PGUI_CONSOLE_DATA GuiData;
2161
2162 if (! ConsInitialized)
2163 {
2164 ConsInitialized = TRUE;
2165 if (! GuiInit())
2166 {
2167 ConsInitialized = FALSE;
2168 return STATUS_UNSUCCESSFUL;
2169 }
2170 }
2171
2172 Console->Vtbl = &GuiVtbl;
2173 if (NULL == NotifyWnd)
2174 {
2175 GraphicsStartupEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
2176 if (NULL == GraphicsStartupEvent)
2177 {
2178 return STATUS_UNSUCCESSFUL;
2179 }
2180
2181 ThreadHandle = CreateThread(NULL,
2182 0,
2183 GuiConsoleGuiThread,
2184 (PVOID) &GraphicsStartupEvent,
2185 0,
2186 NULL);
2187 if (NULL == ThreadHandle)
2188 {
2189 NtClose(GraphicsStartupEvent);
2190 DPRINT1("Win32Csr: Failed to create graphics console thread. Expect problems\n");
2191 return STATUS_UNSUCCESSFUL;
2192 }
2193 SetThreadPriority(ThreadHandle, THREAD_PRIORITY_HIGHEST);
2194 CloseHandle(ThreadHandle);
2195
2196 WaitForSingleObject(GraphicsStartupEvent, INFINITE);
2197 CloseHandle(GraphicsStartupEvent);
2198
2199 if (NULL == NotifyWnd)
2200 {
2201 DPRINT1("Win32Csr: Failed to create notification window.\n");
2202 return STATUS_UNSUCCESSFUL;
2203 }
2204 }
2205 GuiData = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY,
2206 sizeof(GUI_CONSOLE_DATA));
2207 if (!GuiData)
2208 {
2209 DPRINT1("Win32Csr: Failed to create GUI_CONSOLE_DATA\n");
2210 return STATUS_UNSUCCESSFUL;
2211 }
2212
2213 Console->PrivateData = (PVOID) GuiData;
2214 /*
2215 * we need to wait untill the GUI has been fully initialized
2216 * to retrieve custom settings i.e. WindowSize etc..
2217 * Ideally we could use SendNotifyMessage for this but its not
2218 * yet implemented.
2219 *
2220 */
2221 GuiData->hGuiInitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
2222 /* create console */
2223 PostMessageW(NotifyWnd, PM_CREATE_CONSOLE, Visible, (LPARAM) Console);
2224
2225 /* wait untill initialization has finished */
2226 WaitForSingleObject(GuiData->hGuiInitEvent, INFINITE);
2227 DPRINT("received event Console %p GuiData %p X %d Y %d\n", Console, Console->PrivateData, Console->Size.X, Console->Size.Y);
2228 CloseHandle(GuiData->hGuiInitEvent);
2229 GuiData->hGuiInitEvent = NULL;
2230
2231 return STATUS_SUCCESS;
2232 }
2233
2234 /* EOF */