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