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