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