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