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