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