Fix creating the console system menu items
[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 CursorSize;
39 DWORD HistoryNoDup;
40 DWORD FullScreen;
41 DWORD QuickEdit;
42 DWORD InsertMode;
43 } GUI_CONSOLE_DATA, *PGUI_CONSOLE_DATA;
44
45 #ifndef WM_APP
46 #define WM_APP 0x8000
47 #endif
48 #define PM_CREATE_CONSOLE (WM_APP + 1)
49 #define PM_DESTROY_CONSOLE (WM_APP + 2)
50
51 #define CURSOR_BLINK_TIME 500
52
53 static BOOL ConsInitialized = FALSE;
54 static HWND NotifyWnd;
55
56 typedef struct _GUICONSOLE_MENUITEM
57 {
58 UINT uID;
59 const struct _GUICONSOLE_MENUITEM *SubMenu;
60 WORD wCmdID;
61 } GUICONSOLE_MENUITEM, *PGUICONSOLE_MENUITEM;
62
63 static const GUICONSOLE_MENUITEM GuiConsoleEditMenuItems[] =
64 {
65 { IDS_MARK, NULL, ID_SYSTEM_EDIT_MARK },
66 { IDS_COPY, NULL, ID_SYSTEM_EDIT_COPY },
67 { IDS_PASTE, NULL, ID_SYSTEM_EDIT_PASTE },
68 { IDS_SELECTALL, NULL, ID_SYSTEM_EDIT_SELECTALL },
69 { IDS_SCROLL, NULL, ID_SYSTEM_EDIT_SCROLL },
70 { IDS_FIND, NULL, ID_SYSTEM_EDIT_FIND },
71
72 { 0, NULL, 0 } /* End of list */
73 };
74
75 static const GUICONSOLE_MENUITEM GuiConsoleMainMenuItems[] =
76 {
77 { (UINT)-1, NULL, 0 }, /* Separator */
78 { IDS_EDIT, GuiConsoleEditMenuItems, 0 },
79 { IDS_DEFAULTS, NULL, ID_SYSTEM_DEFAULTS },
80 { IDS_PROPERTIES, NULL, ID_SYSTEM_PROPERTIES },
81
82 { 0, NULL, 0 } /* End of list */
83 };
84
85 /* FUNCTIONS *****************************************************************/
86
87 static VOID FASTCALL
88 GuiConsoleAppendMenuItems(HMENU hMenu,
89 const GUICONSOLE_MENUITEM *Items)
90 {
91 UINT i;
92 WCHAR szMenuString[255];
93 HMENU hSubMenu;
94
95 for (i = 0; Items[i].uID != 0; i++)
96 {
97 if (Items[i].uID != (UINT)-1)
98 {
99 if (LoadStringW(Win32CsrDllHandle,
100 Items[i].uID,
101 szMenuString,
102 sizeof(szMenuString) / sizeof(szMenuString[0])) > 0)
103 {
104 if (Items[i].SubMenu != NULL)
105 {
106 hSubMenu = CreatePopupMenu();
107 if (hSubMenu != NULL)
108 {
109 GuiConsoleAppendMenuItems(hSubMenu,
110 Items[i].SubMenu);
111
112 if (!AppendMenuW(hMenu,
113 MF_STRING | MF_POPUP,
114 (UINT_PTR)hSubMenu,
115 szMenuString))
116 {
117 DestroyMenu(hSubMenu);
118 }
119 }
120 }
121 else
122 {
123 AppendMenuW(hMenu,
124 MF_STRING,
125 Items[i].wCmdID,
126 szMenuString);
127 }
128 }
129 }
130 else
131 {
132 AppendMenuW(hMenu,
133 MF_SEPARATOR,
134 0,
135 NULL);
136 }
137 }
138 }
139
140 static VOID FASTCALL
141 GuiConsoleCreateSysMenu(PCSRSS_CONSOLE Console)
142 {
143 HMENU hMenu;
144
145 hMenu = GetSystemMenu(Console->hWindow,
146 FALSE);
147 if (hMenu != NULL)
148 {
149 GuiConsoleAppendMenuItems(hMenu,
150 GuiConsoleMainMenuItems);
151 }
152 }
153
154 static VOID FASTCALL
155 GuiConsoleGetDataPointers(HWND hWnd, PCSRSS_CONSOLE *Console, PGUI_CONSOLE_DATA *GuiData)
156 {
157 *Console = (PCSRSS_CONSOLE) GetWindowLongPtrW(hWnd, GWL_USERDATA);
158 *GuiData = (NULL == *Console ? NULL : (*Console)->PrivateData);
159 }
160
161 static BOOL FASTCALL
162 GuiConsoleOpenUserRegistryPathPerProcessId(DWORD ProcessId, PHANDLE hProcHandle, PHKEY hResult, REGSAM samDesired)
163 {
164 HANDLE hProcessToken = NULL;
165 HANDLE hProcess;
166
167 BYTE Buffer[256];
168 DWORD Length = 0;
169 UNICODE_STRING SidName;
170 LONG res;
171 PTOKEN_USER TokUser;
172
173 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | READ_CONTROL, FALSE, ProcessId);
174 if (!hProcess)
175 {
176 DPRINT("Error: OpenProcess failed(0x%x)\n", GetLastError());
177 return FALSE;
178 }
179
180 if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hProcessToken))
181 {
182 DPRINT("Error: OpenProcessToken failed(0x%x)\n", GetLastError());
183 CloseHandle(hProcess);
184 return FALSE;
185 }
186
187 if (!GetTokenInformation(hProcessToken, TokenUser, (PVOID)Buffer, sizeof(Buffer), &Length))
188 {
189 DPRINT("Error: GetTokenInformation failed(0x%x)\n",GetLastError());
190 CloseHandle(hProcess);
191 CloseHandle(hProcessToken);
192 return FALSE;
193 }
194
195 TokUser = ((PTOKEN_USER)Buffer)->User.Sid;
196 if (!NT_SUCCESS(RtlConvertSidToUnicodeString(&SidName, TokUser, TRUE)))
197 {
198 DPRINT("Error: RtlConvertSidToUnicodeString failed(0x%x)\n", GetLastError());
199 return FALSE;
200 }
201
202 res = RegOpenKeyExW(HKEY_USERS, SidName.Buffer, 0, samDesired, hResult);
203 RtlFreeUnicodeString(&SidName);
204
205 CloseHandle(hProcessToken);
206 if (hProcHandle)
207 *hProcHandle = hProcess;
208 else
209 CloseHandle(hProcess);
210
211 if (res != ERROR_SUCCESS)
212 return FALSE;
213 else
214 return TRUE;
215 }
216
217 static BOOL FASTCALL
218 GuiConsoleOpenUserSettings(HWND hWnd, DWORD ProcessId, PHKEY hSubKey, REGSAM samDesired)
219 {
220 WCHAR szProcessName[MAX_PATH];
221 WCHAR szBuffer[MAX_PATH];
222 UINT fLength, wLength;
223 DWORD dwBitmask, dwLength;
224 WCHAR CurDrive[] = { 'A',':', 0 };
225 HANDLE hProcess;
226 HKEY hKey;
227 WCHAR * ptr, *res;
228 static const WCHAR szSystemRoot[] = { '%','S','y','s','t','e','m','R','o','o','t','%', 0 };
229
230
231 /*
232 * console properties are stored under
233 * HKCU\Console\*
234 *
235 * There are 3 ways to store console properties
236 *
237 * 1. use console title as subkey name
238 * i.e. cmd.exe
239 *
240 * 2. use application name as subkey name
241 *
242 * 3. use unexpanded path to console application.
243 * i.e. %SystemRoot%_system32_cmd.exe
244 */
245
246 if (!GuiConsoleOpenUserRegistryPathPerProcessId(ProcessId, &hProcess, &hKey, samDesired))
247 return FALSE;
248
249 fLength = GetProcessImageFileNameW(hProcess, szProcessName, MAX_PATH);
250 CloseHandle(hProcess);
251
252 if (!fLength)
253 {
254 DPRINT1("GetProcessImageFileNameW failed(0x%x)ProcessId %d\n", GetLastError(),hProcess);
255 return FALSE;
256 }
257
258
259 ptr = wcsrchr(szProcessName, L'\\');
260 swprintf(szBuffer, L"Console%s",ptr);
261
262 if (RegOpenKeyExW(hKey, szBuffer, 0, samDesired, hSubKey) == ERROR_SUCCESS)
263 {
264 RegCloseKey(hKey);
265 return TRUE;
266 }
267
268 dwBitmask = GetLogicalDrives();
269 while(dwBitmask)
270 {
271 if (dwBitmask & 0x1)
272 {
273 dwLength = QueryDosDeviceW(CurDrive, szBuffer, MAX_PATH);
274 if (dwLength)
275 {
276 if (!memcmp(szBuffer, szProcessName, (dwLength-2)*sizeof(WCHAR)))
277 {
278 wcscpy(szBuffer, CurDrive);
279 wcscat(&szBuffer[(sizeof(CurDrive)/sizeof(WCHAR))-1], &szProcessName[dwLength-2]);
280 break;
281 }
282 }
283 }
284 dwBitmask = (dwBitmask >> 1);
285 CurDrive[0]++;
286 }
287
288 wLength = GetWindowsDirectoryW(szProcessName, MAX_PATH);
289
290 if (!wcsncmp(szProcessName, szBuffer, wLength))
291 {
292 wcscpy(szProcessName, szSystemRoot);
293 wcscpy(&szProcessName[(sizeof(szSystemRoot) / sizeof(WCHAR))-1], &szBuffer[wLength]);
294 ptr = res = szProcessName;
295 }
296 else
297 {
298 ptr = res = szBuffer;
299 }
300
301 while((ptr = wcschr(szProcessName, L'\\')))
302 ptr[0] = L'_';
303
304 if (RegOpenKeyExW(hKey, res, 0, samDesired, hSubKey) == ERROR_SUCCESS)
305 {
306 RegCloseKey(hKey);
307 return TRUE;
308 }
309 RegCloseKey(hKey);
310 return FALSE;
311 }
312 static void FASTCALL
313 GuiConsoleReadUserSettings(HKEY hKey, PCSRSS_CONSOLE Console, PGUI_CONSOLE_DATA GuiData, PCSRSS_SCREEN_BUFFER Buffer)
314 {
315 DWORD dwNumSubKeys = 0;
316 DWORD dwIndex;
317 DWORD dwValueName;
318 DWORD dwValue;
319 DWORD dwType;
320 WCHAR szValueName[MAX_PATH];
321 WCHAR szValue[MAX_PATH];
322 DWORD Value;
323
324 RegQueryInfoKey(hKey, NULL, NULL, NULL, &dwNumSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
325
326 for (dwIndex = 0; dwIndex < dwNumSubKeys; dwIndex++)
327 {
328 dwValue = sizeof(Value);
329 dwValueName = MAX_PATH;
330
331 if (RegEnumValueW(hKey, dwIndex, szValueName, &dwValueName, NULL, &dwType, (BYTE*)&Value, &dwValue) != ERROR_SUCCESS)
332 {
333 if (dwType == REG_SZ)
334 {
335 /*
336 * retry in case of string value
337 */
338 dwValue = sizeof(szValue);
339 dwValueName = MAX_PATH;
340 if (RegEnumValueW(hKey, dwIndex, szValueName, &dwValueName, NULL, NULL, (BYTE*)szValue, &dwValue) != ERROR_SUCCESS)
341 break;
342 }
343 else
344 break;
345 }
346
347 if (!wcscmp(szValueName, L"CursorSize"))
348 {
349 if (Value == 0x32)
350 GuiData->CursorSize = Value;
351 else if (Value == 0x64)
352 GuiData->CursorSize = Value;
353 }
354 else if (!wcscmp(szValueName, L"FaceName"))
355 {
356 wcscpy(GuiData->FontName, szValue);
357 }
358 else if (!wcscmp(szValueName, L"FontSize"))
359 {
360 GuiData->FontSize = Value;
361 }
362 else if (!wcscmp(szValueName, L"FontWeight"))
363 {
364 GuiData->FontWeight = Value;
365 }
366 else if (!wcscmp(szValueName, L"HistoryNoDup"))
367 {
368 GuiData->HistoryNoDup = Value;
369 }
370 else if (!wcscmp(szValueName, L"WindowSize"))
371 {
372 Console->Size.X = LOWORD(Value);
373 Console->Size.Y = HIWORD(Value);
374 }
375 else if (!wcscmp(szValueName, L"ScreenBufferSize"))
376 {
377 if( Buffer)
378 {
379 Buffer->MaxX = LOWORD(Value);
380 Buffer->MaxY = HIWORD(Value);
381 }
382 }
383 else if (!wcscmp(szValueName, L"FullScreen"))
384 {
385 GuiData->FullScreen = Value;
386 }
387 else if (!wcscmp(szValueName, L"QuickEdit"))
388 {
389 GuiData->QuickEdit = Value;
390 }
391 else if (!wcscmp(szValueName, L"InsertMode"))
392 {
393 GuiData->InsertMode = Value;
394 }
395 }
396 }
397 static VOID FASTCALL
398 GuiConsoleUseDefaults(PCSRSS_CONSOLE Console, PGUI_CONSOLE_DATA GuiData, PCSRSS_SCREEN_BUFFER Buffer)
399 {
400 /*
401 * init guidata with default properties
402 */
403
404 wcscpy(GuiData->FontName, L"Bitstream Vera Sans Mono");
405 GuiData->FontSize = 0x0008000C; // font is 8x12
406 GuiData->FontWeight = FW_NORMAL;
407 GuiData->CursorSize = 0;
408 GuiData->HistoryNoDup = FALSE;
409 GuiData->FullScreen = FALSE;
410 GuiData->QuickEdit = FALSE;
411 GuiData->InsertMode = TRUE;
412
413 Console->Size.X = 80;
414 Console->Size.Y = 25;
415
416 if (Buffer)
417 {
418 Buffer->MaxX = 80;
419 Buffer->MaxY = 25;
420 }
421 }
422
423
424
425 static BOOL FASTCALL
426 GuiConsoleHandleNcCreate(HWND hWnd, CREATESTRUCTW *Create)
427 {
428 RECT Rect;
429 PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) Create->lpCreateParams;
430 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)Console->PrivateData;
431 HDC Dc;
432 HFONT OldFont;
433 TEXTMETRICW Metrics;
434 PCSRSS_PROCESS_DATA ProcessData;
435 HKEY hKey;
436
437 Console->hWindow = hWnd;
438
439 if (NULL == GuiData)
440 {
441 DPRINT1("GuiConsoleNcCreate: HeapAlloc failed\n");
442 return FALSE;
443 }
444
445 GuiConsoleUseDefaults(Console, GuiData, Console->ActiveBuffer);
446 if (Console->ProcessList.Flink != &Console->ProcessList)
447 {
448 ProcessData = CONTAINING_RECORD(Console->ProcessList.Flink, CSRSS_PROCESS_DATA, ProcessEntry);
449 if (GuiConsoleOpenUserSettings(hWnd, PtrToUlong(ProcessData->ProcessId), &hKey, KEY_READ))
450 {
451 GuiConsoleReadUserSettings(hKey, Console, GuiData, Console->ActiveBuffer);
452 RegCloseKey(hKey);
453 }
454 }
455
456 InitializeCriticalSection(&GuiData->Lock);
457
458 GuiData->LineBuffer = (PWCHAR)HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY,
459 Console->Size.X * sizeof(WCHAR));
460
461 GuiData->Font = CreateFontW(LOWORD(GuiData->FontSize),
462 0, //HIWORD(GuiData->FontSize),
463 0,
464 TA_BASELINE,
465 GuiData->FontWeight,
466 FALSE,
467 FALSE,
468 FALSE,
469 OEM_CHARSET,
470 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
471 NONANTIALIASED_QUALITY, FIXED_PITCH | FF_DONTCARE,
472 GuiData->FontName);
473 if (NULL == GuiData->Font)
474 {
475 DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
476 DeleteCriticalSection(&GuiData->Lock);
477 HeapFree(Win32CsrApiHeap, 0, GuiData);
478 return FALSE;
479 }
480 Dc = GetDC(hWnd);
481 if (NULL == Dc)
482 {
483 DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
484 DeleteObject(GuiData->Font);
485 DeleteCriticalSection(&GuiData->Lock);
486 HeapFree(Win32CsrApiHeap, 0, GuiData);
487 return FALSE;
488 }
489 OldFont = SelectObject(Dc, GuiData->Font);
490 if (NULL == OldFont)
491 {
492 DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
493 ReleaseDC(hWnd, Dc);
494 DeleteObject(GuiData->Font);
495 DeleteCriticalSection(&GuiData->Lock);
496 HeapFree(Win32CsrApiHeap, 0, GuiData);
497 return FALSE;
498 }
499 if (! GetTextMetricsW(Dc, &Metrics))
500 {
501 DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
502 SelectObject(Dc, OldFont);
503 ReleaseDC(hWnd, Dc);
504 DeleteObject(GuiData->Font);
505 DeleteCriticalSection(&GuiData->Lock);
506 HeapFree(Win32CsrApiHeap, 0, GuiData);
507 return FALSE;
508 }
509 GuiData->CharWidth = Metrics.tmMaxCharWidth;
510 GuiData->CharHeight = Metrics.tmHeight + Metrics.tmExternalLeading;
511 SelectObject(Dc, OldFont);
512
513 ReleaseDC(hWnd, Dc);
514 GuiData->CursorBlinkOn = TRUE;
515 GuiData->ForceCursorOff = FALSE;
516
517 GuiData->Selection.left = -1;
518 DPRINT("Console %p GuiData %p\n", Console, GuiData);
519 Console->PrivateData = GuiData;
520 SetWindowLongPtrW(hWnd, GWL_USERDATA, (DWORD_PTR) Console);
521
522 GetWindowRect(hWnd, &Rect);
523 Rect.right = Rect.left + Console->Size.X * GuiData->CharWidth +
524 2 * GetSystemMetrics(SM_CXFIXEDFRAME);
525 Rect.bottom = Rect.top + Console->Size.Y * GuiData->CharHeight +
526 2 * GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYCAPTION);
527 MoveWindow(hWnd, Rect.left, Rect.top, Rect.right - Rect.left,
528 Rect.bottom - Rect.top, FALSE);
529
530 SetTimer(hWnd, 1, CURSOR_BLINK_TIME, NULL);
531 SetEvent(GuiData->hGuiInitEvent);
532
533 GuiConsoleCreateSysMenu(Console);
534
535 return (BOOL) DefWindowProcW(hWnd, WM_NCCREATE, 0, (LPARAM) Create);
536 }
537
538 static COLORREF FASTCALL
539 GuiConsoleRGBFromAttribute(BYTE Attribute)
540 {
541 int Red = (Attribute & 0x04 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);
542 int Green = (Attribute & 0x02 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);
543 int Blue = (Attribute & 0x01 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);
544
545 return RGB(Red, Green, Blue);
546 }
547
548 static VOID FASTCALL
549 GuiConsoleSetTextColors(HDC Dc, BYTE Attribute)
550 {
551 SetTextColor(Dc, GuiConsoleRGBFromAttribute(Attribute & 0x0f));
552 SetBkColor(Dc, GuiConsoleRGBFromAttribute((Attribute & 0xf0) >> 4));
553 }
554
555 static VOID FASTCALL
556 GuiConsoleGetLogicalCursorPos(PCSRSS_SCREEN_BUFFER Buff, ULONG *CursorX, ULONG *CursorY)
557 {
558 *CursorX = Buff->CurrentX;
559 if (Buff->CurrentY < Buff->ShowY)
560 {
561 *CursorY = Buff->MaxY - Buff->ShowY + Buff->CurrentY;
562 }
563 else
564 {
565 *CursorY = Buff->CurrentY - Buff->ShowY;
566 }
567 }
568
569
570 static VOID FASTCALL
571 GuiConsoleUpdateSelection(HWND hWnd, PRECT rc, PGUI_CONSOLE_DATA GuiData)
572 {
573 RECT oldRect = GuiData->Selection;
574
575 if(rc != NULL)
576 {
577 RECT changeRect = *rc;
578
579 GuiData->Selection = *rc;
580
581 changeRect.left *= GuiData->CharWidth;
582 changeRect.top *= GuiData->CharHeight;
583 changeRect.right *= GuiData->CharWidth;
584 changeRect.bottom *= GuiData->CharHeight;
585
586 if(rc->left != oldRect.left ||
587 rc->top != oldRect.top ||
588 rc->right != oldRect.right ||
589 rc->bottom != oldRect.bottom)
590 {
591 if(oldRect.left != -1)
592 {
593 HRGN rgn1, rgn2;
594
595 oldRect.left *= GuiData->CharWidth;
596 oldRect.top *= GuiData->CharHeight;
597 oldRect.right *= GuiData->CharWidth;
598 oldRect.bottom *= GuiData->CharHeight;
599
600 /* calculate the region that needs to be updated */
601 if((rgn1 = CreateRectRgnIndirect(&oldRect)))
602 {
603 if((rgn2 = CreateRectRgnIndirect(&changeRect)))
604 {
605 if(CombineRgn(rgn1, rgn2, rgn1, RGN_XOR) != ERROR)
606 {
607 InvalidateRgn(hWnd, rgn1, FALSE);
608 }
609
610 DeleteObject(rgn2);
611 }
612 DeleteObject(rgn1);
613 }
614 }
615 else
616 {
617 InvalidateRect(hWnd, &changeRect, FALSE);
618 }
619 }
620 }
621 else if(oldRect.left != -1)
622 {
623 /* clear the selection */
624 GuiData->Selection.left = -1;
625 oldRect.left *= GuiData->CharWidth;
626 oldRect.top *= GuiData->CharHeight;
627 oldRect.right *= GuiData->CharWidth;
628 oldRect.bottom *= GuiData->CharHeight;
629 InvalidateRect(hWnd, &oldRect, FALSE);
630 }
631 }
632
633
634 static VOID FASTCALL
635 GuiConsolePaint(PCSRSS_CONSOLE Console,
636 PGUI_CONSOLE_DATA GuiData,
637 HDC hDC,
638 PRECT rc)
639 {
640 PCSRSS_SCREEN_BUFFER Buff;
641 ULONG TopLine, BottomLine, LeftChar, RightChar;
642 ULONG Line, Char, Start;
643 PBYTE From;
644 PWCHAR To;
645 BYTE LastAttribute, Attribute;
646 ULONG CursorX, CursorY, CursorHeight;
647 HBRUSH CursorBrush, OldBrush;
648 HFONT OldFont;
649
650 Buff = Console->ActiveBuffer;
651
652 TopLine = rc->top / GuiData->CharHeight;
653 BottomLine = (rc->bottom + (GuiData->CharHeight - 1)) / GuiData->CharHeight - 1;
654 LeftChar = rc->left / GuiData->CharWidth;
655 RightChar = (rc->right + (GuiData->CharWidth - 1)) / GuiData->CharWidth - 1;
656 LastAttribute = Buff->Buffer[(TopLine * Buff->MaxX + LeftChar) * 2 + 1];
657
658 GuiConsoleSetTextColors(hDC,
659 LastAttribute);
660
661 EnterCriticalSection(&Buff->Header.Lock);
662
663 OldFont = SelectObject(hDC,
664 GuiData->Font);
665
666 for (Line = TopLine; Line <= BottomLine; Line++)
667 {
668 if (Line + Buff->ShowY < Buff->MaxY)
669 {
670 From = Buff->Buffer + ((Line + Buff->ShowY) * Buff->MaxX + LeftChar) * 2;
671 }
672 else
673 {
674 From = Buff->Buffer +
675 ((Line - (Buff->MaxY - Buff->ShowY)) * Buff->MaxX + LeftChar) * 2;
676 }
677 Start = LeftChar;
678 To = GuiData->LineBuffer;
679
680 for (Char = LeftChar; Char <= RightChar; Char++)
681 {
682 if (*(From + 1) != LastAttribute)
683 {
684 TextOutW(hDC,
685 Start * GuiData->CharWidth,
686 Line * GuiData->CharHeight,
687 GuiData->LineBuffer,
688 Char - Start);
689 Start = Char;
690 To = GuiData->LineBuffer;
691 Attribute = *(From + 1);
692 if (Attribute != LastAttribute)
693 {
694 GuiConsoleSetTextColors(hDC,
695 Attribute);
696 LastAttribute = Attribute;
697 }
698 }
699
700 MultiByteToWideChar(Console->OutputCodePage,
701 0,
702 (PCHAR)From,
703 1,
704 To,
705 1);
706 To++;
707 From += 2;
708 }
709
710 TextOutW(hDC,
711 Start * GuiData->CharWidth,
712 Line * GuiData->CharHeight,
713 GuiData->LineBuffer,
714 RightChar - Start + 1);
715 }
716
717 if (Buff->CursorInfo.bVisible && GuiData->CursorBlinkOn &&
718 !GuiData->ForceCursorOff)
719 {
720 GuiConsoleGetLogicalCursorPos(Buff,
721 &CursorX,
722 &CursorY);
723 if (LeftChar <= CursorX && CursorX <= RightChar &&
724 TopLine <= CursorY && CursorY <= BottomLine)
725 {
726 CursorHeight = (GuiData->CharHeight * Buff->CursorInfo.dwSize) / 100;
727 if (CursorHeight < 1)
728 {
729 CursorHeight = 1;
730 }
731 From = Buff->Buffer + (Buff->CurrentY * Buff->MaxX + Buff->CurrentX) * 2 + 1;
732 CursorBrush = CreateSolidBrush(GuiConsoleRGBFromAttribute(*From));
733 OldBrush = SelectObject(hDC,
734 CursorBrush);
735 PatBlt(hDC,
736 CursorX * GuiData->CharWidth,
737 CursorY * GuiData->CharHeight + (GuiData->CharHeight - CursorHeight),
738 GuiData->CharWidth,
739 CursorHeight,
740 PATCOPY);
741 SelectObject(hDC,
742 OldBrush);
743 DeleteObject(CursorBrush);
744 }
745 }
746
747 LeaveCriticalSection(&Buff->Header.Lock);
748
749 SelectObject(hDC,
750 OldFont);
751 }
752
753 static VOID FASTCALL
754 GuiConsoleHandlePaint(HWND hWnd, HDC hDCPaint)
755 {
756 HDC hDC;
757 PAINTSTRUCT ps;
758 PCSRSS_CONSOLE Console;
759 PGUI_CONSOLE_DATA GuiData;
760
761 hDC = BeginPaint(hWnd, &ps);
762 if (hDC != NULL &&
763 ps.rcPaint.left < ps.rcPaint.right &&
764 ps.rcPaint.top < ps.rcPaint.bottom)
765 {
766 GuiConsoleGetDataPointers(hWnd,
767 &Console,
768 &GuiData);
769 if (Console != NULL && GuiData != NULL &&
770 Console->ActiveBuffer != NULL)
771 {
772 if (Console->ActiveBuffer->Buffer != NULL)
773 {
774 EnterCriticalSection(&GuiData->Lock);
775
776 GuiConsolePaint(Console,
777 GuiData,
778 hDC,
779 &ps.rcPaint);
780
781 if (GuiData->Selection.left != -1)
782 {
783 RECT rc = GuiData->Selection;
784
785 rc.left *= GuiData->CharWidth;
786 rc.top *= GuiData->CharHeight;
787 rc.right *= GuiData->CharWidth;
788 rc.bottom *= GuiData->CharHeight;
789
790 /* invert the selection */
791 if (IntersectRect(&rc,
792 &ps.rcPaint,
793 &rc))
794 {
795 PatBlt(hDC,
796 rc.left,
797 rc.top,
798 rc.right - rc.left,
799 rc.bottom - rc.top,
800 DSTINVERT);
801 }
802 }
803
804 LeaveCriticalSection(&GuiData->Lock);
805 }
806 }
807
808 EndPaint(hWnd, &ps);
809 }
810 }
811
812 static VOID FASTCALL
813 GuiConsoleHandleKey(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
814 {
815 PCSRSS_CONSOLE Console;
816 PGUI_CONSOLE_DATA GuiData;
817 MSG Message;
818
819 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
820 Message.hwnd = hWnd;
821 Message.message = msg;
822 Message.wParam = wParam;
823 Message.lParam = lParam;
824
825 if(msg == WM_CHAR || msg == WM_SYSKEYDOWN)
826 {
827 /* clear the selection */
828 GuiConsoleUpdateSelection(hWnd, NULL, GuiData);
829 }
830
831 ConioProcessKey(&Message, Console, FALSE);
832 }
833
834 static VOID FASTCALL
835 GuiIntDrawRegion(PGUI_CONSOLE_DATA GuiData, HWND Wnd, RECT *Region)
836 {
837 RECT RegionRect;
838
839 RegionRect.left = Region->left * GuiData->CharWidth;
840 RegionRect.top = Region->top * GuiData->CharHeight;
841 RegionRect.right = (Region->right + 1) * GuiData->CharWidth;
842 RegionRect.bottom = (Region->bottom + 1) * GuiData->CharHeight;
843
844 InvalidateRect(Wnd, &RegionRect, FALSE);
845 }
846
847 static VOID STDCALL
848 GuiDrawRegion(PCSRSS_CONSOLE Console, RECT *Region)
849 {
850 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA) Console->PrivateData;
851
852 if (NULL != Console->hWindow && NULL != GuiData)
853 {
854 GuiIntDrawRegion(GuiData, Console->hWindow, Region);
855 }
856 }
857
858 static VOID FASTCALL
859 GuiInvalidateCell(PGUI_CONSOLE_DATA GuiData, HWND Wnd, UINT x, UINT y)
860 {
861 RECT CellRect;
862
863 CellRect.left = x;
864 CellRect.top = y;
865 CellRect.right = x;
866 CellRect.bottom = y;
867
868 GuiIntDrawRegion(GuiData, Wnd, &CellRect);
869 }
870
871 static VOID STDCALL
872 GuiWriteStream(PCSRSS_CONSOLE Console, RECT *Region, LONG CursorStartX, LONG CursorStartY,
873 UINT ScrolledLines, CHAR *Buffer, UINT Length)
874 {
875 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA) Console->PrivateData;
876 PCSRSS_SCREEN_BUFFER Buff = Console->ActiveBuffer;
877 LONG CursorEndX, CursorEndY;
878 RECT ScrollRect;
879
880 if (NULL == Console->hWindow || NULL == GuiData)
881 {
882 return;
883 }
884
885 if (0 != ScrolledLines)
886 {
887 ScrollRect.left = 0;
888 ScrollRect.top = 0;
889 ScrollRect.right = Console->Size.X * GuiData->CharWidth;
890 ScrollRect.bottom = Region->top * GuiData->CharHeight;
891
892 if (GuiData->Selection.left != -1)
893 {
894 /* scroll the selection */
895 if (GuiData->Selection.top > ScrolledLines)
896 {
897 GuiData->Selection.top -= ScrolledLines;
898 GuiData->Selection.bottom -= ScrolledLines;
899 }
900 else if (GuiData->Selection.bottom < ScrolledLines)
901 {
902 GuiData->Selection.left = -1;
903 }
904 else
905 {
906 GuiData->Selection.top = 0;
907 GuiData->Selection.bottom -= ScrolledLines;
908 }
909 }
910
911 ScrollWindowEx(Console->hWindow,
912 0,
913 -(ScrolledLines * GuiData->CharHeight),
914 &ScrollRect,
915 NULL,
916 NULL,
917 NULL,
918 SW_INVALIDATE);
919 }
920
921 GuiIntDrawRegion(GuiData, Console->hWindow, Region);
922
923 if (CursorStartX < Region->left || Region->right < CursorStartX
924 || CursorStartY < Region->top || Region->bottom < CursorStartY)
925 {
926 GuiInvalidateCell(GuiData, Console->hWindow, CursorStartX, CursorStartY);
927 }
928
929 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY,
930 &CursorEndX, &CursorEndY);
931 if ((CursorEndX < Region->left || Region->right < CursorEndX
932 || CursorEndY < Region->top || Region->bottom < CursorEndY)
933 && (CursorEndX != CursorStartX || CursorEndY != CursorStartY))
934 {
935 GuiInvalidateCell(GuiData, Console->hWindow, CursorEndX, CursorEndY);
936 }
937 }
938
939 static BOOL STDCALL
940 GuiSetCursorInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff)
941 {
942 RECT UpdateRect;
943
944 if (Console->ActiveBuffer == Buff)
945 {
946 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY,
947 &UpdateRect.left, &UpdateRect.top);
948 UpdateRect.right = UpdateRect.left;
949 UpdateRect.bottom = UpdateRect.top;
950 ConioDrawRegion(Console, &UpdateRect);
951 }
952
953 return TRUE;
954 }
955
956 static BOOL STDCALL
957 GuiSetScreenInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff, UINT OldCursorX, UINT OldCursorY)
958 {
959 RECT UpdateRect;
960
961 if (Console->ActiveBuffer == Buff)
962 {
963 /* Redraw char at old position (removes cursor) */
964 UpdateRect.left = OldCursorX;
965 UpdateRect.top = OldCursorY;
966 UpdateRect.right = OldCursorX;
967 UpdateRect.bottom = OldCursorY;
968 ConioDrawRegion(Console, &UpdateRect);
969 /* Redraw char at new position (shows cursor) */
970 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY,
971 &(UpdateRect.left), &(UpdateRect.top));
972 UpdateRect.right = UpdateRect.left;
973 UpdateRect.bottom = UpdateRect.top;
974 ConioDrawRegion(Console, &UpdateRect);
975 }
976
977 return TRUE;
978 }
979
980 static VOID FASTCALL
981 GuiConsoleHandleTimer(HWND hWnd)
982 {
983 PCSRSS_CONSOLE Console;
984 PGUI_CONSOLE_DATA GuiData;
985 RECT CursorRect;
986 ULONG CursorX, CursorY;
987
988 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
989 GuiData->CursorBlinkOn = ! GuiData->CursorBlinkOn;
990
991 GuiConsoleGetLogicalCursorPos(Console->ActiveBuffer, &CursorX, &CursorY);
992 CursorRect.left = CursorX;
993 CursorRect.top = CursorY;
994 CursorRect.right = CursorX;
995 CursorRect.bottom = CursorY;
996 GuiDrawRegion(Console, &CursorRect);
997 }
998
999 static VOID FASTCALL
1000 GuiConsoleHandleClose(HWND hWnd)
1001 {
1002 PCSRSS_CONSOLE Console;
1003 PGUI_CONSOLE_DATA GuiData;
1004 PLIST_ENTRY current_entry;
1005 PCSRSS_PROCESS_DATA current;
1006
1007 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1008
1009 EnterCriticalSection(&Console->Header.Lock);
1010
1011 current_entry = Console->ProcessList.Flink;
1012 while (current_entry != &Console->ProcessList)
1013 {
1014 current = CONTAINING_RECORD(current_entry, CSRSS_PROCESS_DATA, ProcessEntry);
1015 current_entry = current_entry->Flink;
1016
1017 ConioConsoleCtrlEvent(CTRL_CLOSE_EVENT, current);
1018 }
1019
1020 LeaveCriticalSection(&Console->Header.Lock);
1021 }
1022
1023 static VOID FASTCALL
1024 GuiConsoleHandleNcDestroy(HWND hWnd)
1025 {
1026 PCSRSS_CONSOLE Console;
1027 PGUI_CONSOLE_DATA GuiData;
1028
1029 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1030 KillTimer(hWnd, 1);
1031 Console->PrivateData = NULL;
1032 DeleteCriticalSection(&GuiData->Lock);
1033 GetSystemMenu(hWnd, TRUE);
1034 if (GuiData->ConsoleLibrary)
1035 FreeLibrary(GuiData->ConsoleLibrary);
1036
1037 HeapFree(Win32CsrApiHeap, 0, GuiData);
1038 }
1039
1040 static VOID FASTCALL
1041 GuiConsoleLeftMouseDown(HWND hWnd, LPARAM lParam)
1042 {
1043 PCSRSS_CONSOLE Console;
1044 PGUI_CONSOLE_DATA GuiData;
1045 POINTS pt;
1046 RECT rc;
1047
1048 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1049 if (Console == NULL || GuiData == NULL) return;
1050
1051 pt = MAKEPOINTS(lParam);
1052
1053 rc.left = pt.x / GuiData->CharWidth;
1054 rc.top = pt.y / GuiData->CharHeight;
1055 rc.right = rc.left + 1;
1056 rc.bottom = rc.top + 1;
1057
1058 GuiData->SelectionStart.x = rc.left;
1059 GuiData->SelectionStart.y = rc.top;
1060
1061 SetCapture(hWnd);
1062
1063 GuiData->MouseDown = TRUE;
1064
1065 GuiConsoleUpdateSelection(hWnd, &rc, GuiData);
1066 }
1067
1068 static VOID FASTCALL
1069 GuiConsoleLeftMouseUp(HWND hWnd, LPARAM lParam)
1070 {
1071 PCSRSS_CONSOLE Console;
1072 PGUI_CONSOLE_DATA GuiData;
1073 RECT rc;
1074 POINTS pt;
1075
1076 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1077 if (Console == NULL || GuiData == NULL) return;
1078 if (GuiData->Selection.left == -1 || !GuiData->MouseDown) return;
1079
1080 pt = MAKEPOINTS(lParam);
1081
1082 rc.left = GuiData->SelectionStart.x;
1083 rc.top = GuiData->SelectionStart.y;
1084 rc.right = (pt.x >= 0 ? (pt.x / GuiData->CharWidth) + 1 : 0);
1085 rc.bottom = (pt.y >= 0 ? (pt.y / GuiData->CharHeight) + 1 : 0);
1086
1087 /* exchange left/top with right/bottom if required */
1088 if(rc.left >= rc.right)
1089 {
1090 LONG tmp;
1091 tmp = rc.left;
1092 rc.left = max(rc.right - 1, 0);
1093 rc.right = tmp + 1;
1094 }
1095 if(rc.top >= rc.bottom)
1096 {
1097 LONG tmp;
1098 tmp = rc.top;
1099 rc.top = max(rc.bottom - 1, 0);
1100 rc.bottom = tmp + 1;
1101 }
1102
1103 GuiData->MouseDown = FALSE;
1104
1105 GuiConsoleUpdateSelection(hWnd, &rc, GuiData);
1106
1107 ReleaseCapture();
1108 }
1109
1110 static VOID FASTCALL
1111 GuiConsoleMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam)
1112 {
1113 PCSRSS_CONSOLE Console;
1114 PGUI_CONSOLE_DATA GuiData;
1115 RECT rc;
1116 POINTS pt;
1117
1118 if (!(wParam & MK_LBUTTON)) return;
1119
1120 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1121 if (Console == NULL || GuiData == NULL || !GuiData->MouseDown) return;
1122
1123 pt = MAKEPOINTS(lParam);
1124
1125 rc.left = GuiData->SelectionStart.x;
1126 rc.top = GuiData->SelectionStart.y;
1127 rc.right = (pt.x >= 0 ? (pt.x / GuiData->CharWidth) + 1 : 0);
1128 if (Console->Size.X < rc.right)
1129 {
1130 rc.right = Console->Size.X;
1131 }
1132 rc.bottom = (pt.y >= 0 ? (pt.y / GuiData->CharHeight) + 1 : 0);
1133 if (Console->Size.Y < rc.bottom)
1134 {
1135 rc.bottom = Console->Size.Y;
1136 }
1137
1138 /* exchange left/top with right/bottom if required */
1139 if(rc.left >= rc.right)
1140 {
1141 LONG tmp;
1142 tmp = rc.left;
1143 rc.left = max(rc.right - 1, 0);
1144 rc.right = tmp + 1;
1145 }
1146 if(rc.top >= rc.bottom)
1147 {
1148 LONG tmp;
1149 tmp = rc.top;
1150 rc.top = max(rc.bottom - 1, 0);
1151 rc.bottom = tmp + 1;
1152 }
1153
1154 GuiConsoleUpdateSelection(hWnd, &rc, GuiData);
1155 }
1156
1157 static VOID FASTCALL
1158 GuiConsoleRightMouseDown(HWND hWnd)
1159 {
1160 PCSRSS_CONSOLE Console;
1161 PGUI_CONSOLE_DATA GuiData;
1162
1163 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1164 if (Console == NULL || GuiData == NULL) return;
1165
1166 if (GuiData->Selection.left == -1)
1167 {
1168 /* FIXME - paste text from clipboard */
1169 }
1170 else
1171 {
1172 /* FIXME - copy selection to clipboard */
1173
1174 GuiConsoleUpdateSelection(hWnd, NULL, GuiData);
1175 }
1176
1177 }
1178
1179 static VOID
1180 GuiConsoleShowConsoleProperties(HWND hWnd, BOOL Defaults)
1181 {
1182 PCSRSS_CONSOLE Console;
1183 PGUI_CONSOLE_DATA GuiData;
1184 APPLET_PROC CPLFunc;
1185 TCHAR szBuffer[MAX_PATH];
1186
1187 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1188
1189 if (GuiData == NULL)
1190 {
1191 DPRINT1("GuiConsoleGetDataPointers failed\n");
1192 return;
1193 }
1194 if (GuiData->ConsoleLibrary == NULL)
1195 {
1196 GetWindowsDirectory(szBuffer,MAX_PATH);
1197 _tcscat(szBuffer, _T("\\system32\\console.dll"));
1198 GuiData->ConsoleLibrary = LoadLibrary(szBuffer);
1199
1200 if (GuiData->ConsoleLibrary == NULL)
1201 {
1202 DPRINT1("failed to load console.dll");
1203 return;
1204 }
1205 }
1206
1207 CPLFunc = (APPLET_PROC) GetProcAddress(GuiData->ConsoleLibrary, _T("CPlApplet"));
1208 if (!CPLFunc)
1209 {
1210 DPRINT("Error: Console.dll misses CPlApplet export\n");
1211 return;
1212 }
1213
1214 if (!CPLFunc(hWnd, CPL_INIT, 0, 0))
1215 {
1216 DPRINT("Error: failed to initialize console.dll\n");
1217 return;
1218 }
1219
1220 if (CPLFunc(hWnd, CPL_GETCOUNT, 0, 0) != 1)
1221 {
1222 DPRINT("Error: console.dll returned unexpected CPL count\n");
1223 return;
1224 }
1225
1226 CPLFunc(hWnd, CPL_DBLCLK, 0, Defaults);
1227
1228 // TODO
1229 //
1230 // read back the changes from console.dll
1231 //
1232 // if the changes are system-wide then
1233 // console.dll should have written it to
1234 // registry
1235 //
1236 // if the changes only apply to this session
1237 // then exchange this info with console.dll in
1238 // some private way
1239 }
1240 static BOOL FASTCALL
1241 GuiConsoleHandleSysMenuCommand(HWND hWnd, WPARAM wParam)
1242 {
1243 BOOL Ret = TRUE;
1244
1245 switch(wParam)
1246 {
1247 case ID_SYSTEM_EDIT_MARK:
1248 case ID_SYSTEM_EDIT_COPY:
1249 case ID_SYSTEM_EDIT_PASTE:
1250 case ID_SYSTEM_EDIT_SELECTALL:
1251 case ID_SYSTEM_EDIT_SCROLL:
1252 case ID_SYSTEM_EDIT_FIND:
1253 break;
1254
1255 case ID_SYSTEM_DEFAULTS:
1256 GuiConsoleShowConsoleProperties(hWnd, TRUE);
1257 break;
1258
1259 case ID_SYSTEM_PROPERTIES:
1260 GuiConsoleShowConsoleProperties(hWnd, FALSE);
1261 break;
1262
1263 default:
1264 Ret = FALSE;
1265 break;
1266 }
1267
1268 return Ret;
1269 }
1270
1271 static LRESULT CALLBACK
1272 GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1273 {
1274 LRESULT Result = 0;
1275
1276 switch(msg)
1277 {
1278 case WM_NCCREATE:
1279 Result = (LRESULT) GuiConsoleHandleNcCreate(hWnd, (CREATESTRUCTW *) lParam);
1280 break;
1281 case WM_PAINT:
1282 GuiConsoleHandlePaint(hWnd, (HDC)wParam);
1283 break;
1284 case WM_KEYDOWN:
1285 case WM_KEYUP:
1286 case WM_SYSKEYDOWN:
1287 case WM_SYSKEYUP:
1288 case WM_CHAR:
1289 GuiConsoleHandleKey(hWnd, msg, wParam, lParam);
1290 break;
1291 case WM_TIMER:
1292 GuiConsoleHandleTimer(hWnd);
1293 break;
1294 case WM_CLOSE:
1295 GuiConsoleHandleClose(hWnd);
1296 break;
1297 case WM_NCDESTROY:
1298 GuiConsoleHandleNcDestroy(hWnd);
1299 break;
1300 case WM_LBUTTONDOWN:
1301 GuiConsoleLeftMouseDown(hWnd, lParam);
1302 break;
1303 case WM_LBUTTONUP:
1304 GuiConsoleLeftMouseUp(hWnd, lParam);
1305 break;
1306 case WM_RBUTTONDOWN:
1307 GuiConsoleRightMouseDown(hWnd);
1308 break;
1309 case WM_MOUSEMOVE:
1310 GuiConsoleMouseMove(hWnd, wParam, lParam);
1311 break;
1312 case WM_SYSCOMMAND:
1313 if (!GuiConsoleHandleSysMenuCommand(hWnd, wParam))
1314 Result = DefWindowProcW(hWnd, msg, wParam, lParam);
1315 break;
1316 default:
1317 Result = DefWindowProcW(hWnd, msg, wParam, lParam);
1318 break;
1319 }
1320
1321 return Result;
1322 }
1323
1324 static LRESULT CALLBACK
1325 GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1326 {
1327 HWND NewWindow;
1328 LONG WindowCount;
1329 MSG Msg;
1330 PWCHAR Buffer, Title;
1331 PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) lParam;
1332
1333
1334
1335 switch(msg)
1336 {
1337 case WM_CREATE:
1338 SetWindowLongW(hWnd, GWL_USERDATA, 0);
1339 return 0;
1340 case PM_CREATE_CONSOLE:
1341 Buffer = HeapAlloc(Win32CsrApiHeap, 0,
1342 Console->Title.Length + sizeof(WCHAR));
1343 if (NULL != Buffer)
1344 {
1345 memcpy(Buffer, Console->Title.Buffer, Console->Title.Length);
1346 Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0';
1347 Title = Buffer;
1348 }
1349 else
1350 {
1351 Title = L"";
1352 }
1353 NewWindow = CreateWindowW(L"ConsoleWindowClass",
1354 Title,
1355 WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, // | WS_HSCROLL | WS_VSCROLL,
1356 CW_USEDEFAULT,
1357 CW_USEDEFAULT,
1358 CW_USEDEFAULT,
1359 CW_USEDEFAULT,
1360 NULL,
1361 NULL,
1362 (HINSTANCE) GetModuleHandleW(NULL),
1363 (PVOID) Console);
1364 if (NULL != Buffer)
1365 {
1366 HeapFree(Win32CsrApiHeap, 0, Buffer);
1367 }
1368 if (NULL != NewWindow)
1369 {
1370 //ShowScrollBar(NewWindow, SB_VERT, FALSE);
1371 //ShowScrollBar(NewWindow, SB_HORZ, FALSE);
1372 SetWindowLongW(hWnd, GWL_USERDATA, GetWindowLongW(hWnd, GWL_USERDATA) + 1);
1373 ShowWindow(NewWindow, SW_SHOW);
1374 }
1375 return (LRESULT) NewWindow;
1376 case PM_DESTROY_CONSOLE:
1377 /* Window creation is done using a PostMessage(), so it's possible that the
1378 * window that we want to destroy doesn't exist yet. So first empty the message
1379 * queue */
1380 while(PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
1381 {
1382 TranslateMessage(&Msg);
1383 DispatchMessageW(&Msg);
1384 }
1385 DestroyWindow(Console->hWindow);
1386 Console->hWindow = NULL;
1387 WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
1388 WindowCount--;
1389 SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
1390 if (0 == WindowCount)
1391 {
1392 NotifyWnd = NULL;
1393 DestroyWindow(hWnd);
1394 PrivateCsrssManualGuiCheck(-1);
1395 PostQuitMessage(0);
1396 }
1397 return 0;
1398 default:
1399 return DefWindowProcW(hWnd, msg, wParam, lParam);
1400 }
1401 }
1402
1403 static DWORD STDCALL
1404 GuiConsoleGuiThread(PVOID Data)
1405 {
1406 MSG msg;
1407 PHANDLE GraphicsStartupEvent = (PHANDLE) Data;
1408
1409 NotifyWnd = CreateWindowW(L"Win32CsrCreateNotify",
1410 L"",
1411 WS_OVERLAPPEDWINDOW,
1412 CW_USEDEFAULT,
1413 CW_USEDEFAULT,
1414 CW_USEDEFAULT,
1415 CW_USEDEFAULT,
1416 NULL,
1417 NULL,
1418 (HINSTANCE) GetModuleHandleW(NULL),
1419 NULL);
1420 if (NULL == NotifyWnd)
1421 {
1422 PrivateCsrssManualGuiCheck(-1);
1423 SetEvent(*GraphicsStartupEvent);
1424 return 1;
1425 }
1426
1427 SetEvent(*GraphicsStartupEvent);
1428
1429 while(GetMessageW(&msg, NULL, 0, 0))
1430 {
1431 TranslateMessage(&msg);
1432 DispatchMessageW(&msg);
1433 }
1434
1435 return 1;
1436 }
1437
1438 static BOOL FASTCALL
1439 GuiInit(VOID)
1440 {
1441 WNDCLASSEXW wc;
1442
1443 if (NULL == NotifyWnd)
1444 {
1445 PrivateCsrssManualGuiCheck(+1);
1446 }
1447
1448 wc.cbSize = sizeof(WNDCLASSEXW);
1449 wc.lpszClassName = L"Win32CsrCreateNotify";
1450 wc.lpfnWndProc = GuiConsoleNotifyWndProc;
1451 wc.style = 0;
1452 wc.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
1453 wc.hIcon = NULL;
1454 wc.hCursor = NULL;
1455 wc.hbrBackground = NULL;
1456 wc.lpszMenuName = NULL;
1457 wc.cbClsExtra = 0;
1458 wc.cbWndExtra = 0;
1459 wc.hIconSm = NULL;
1460 if (RegisterClassExW(&wc) == 0)
1461 {
1462 DPRINT1("Failed to register notify wndproc\n");
1463 return FALSE;
1464 }
1465
1466 wc.cbSize = sizeof(WNDCLASSEXW);
1467 wc.lpszClassName = L"ConsoleWindowClass";
1468 wc.lpfnWndProc = GuiConsoleWndProc;
1469 wc.style = 0;
1470 wc.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
1471 wc.hIcon = LoadIconW(Win32CsrDllHandle, MAKEINTRESOURCEW(1));
1472 wc.hCursor = LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_ARROW));
1473 wc.hbrBackground = NULL;
1474 wc.lpszMenuName = NULL;
1475 wc.cbClsExtra = 0;
1476 wc.cbWndExtra = 0;
1477 wc.hIconSm = LoadImageW(Win32CsrDllHandle, MAKEINTRESOURCEW(1), IMAGE_ICON,
1478 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
1479 LR_SHARED);
1480 if (RegisterClassExW(&wc) == 0)
1481 {
1482 DPRINT1("Failed to register console wndproc\n");
1483 return FALSE;
1484 }
1485
1486 return TRUE;
1487 }
1488
1489 static VOID STDCALL
1490 GuiInitScreenBuffer(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buffer)
1491 {
1492 Buffer->DefaultAttrib = 0x0f;
1493 }
1494
1495 static BOOL STDCALL
1496 GuiChangeTitle(PCSRSS_CONSOLE Console)
1497 {
1498 PWCHAR Buffer, Title;
1499
1500 Buffer = HeapAlloc(Win32CsrApiHeap, 0,
1501 Console->Title.Length + sizeof(WCHAR));
1502 if (NULL != Buffer)
1503 {
1504 memcpy(Buffer, Console->Title.Buffer, Console->Title.Length);
1505 Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0';
1506 Title = Buffer;
1507 }
1508 else
1509 {
1510 Title = L"";
1511 }
1512 SendMessageW(Console->hWindow, WM_SETTEXT, 0, (LPARAM) Title);
1513 if (NULL != Buffer)
1514 {
1515 HeapFree(Win32CsrApiHeap, 0, Buffer);
1516 }
1517
1518 return TRUE;
1519 }
1520
1521 static BOOL STDCALL
1522 GuiChangeIcon(PCSRSS_CONSOLE Console)
1523 {
1524 SendMessageW(Console->hWindow, WM_SETICON, ICON_BIG, (LPARAM)Console->hWindowIcon);
1525 SendMessageW(Console->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)Console->hWindowIcon);
1526
1527 return TRUE;
1528 }
1529
1530 static VOID STDCALL
1531 GuiCleanupConsole(PCSRSS_CONSOLE Console)
1532 {
1533 SendMessageW(NotifyWnd, PM_DESTROY_CONSOLE, 0, (LPARAM) Console);
1534 }
1535
1536 static CSRSS_CONSOLE_VTBL GuiVtbl =
1537 {
1538 GuiInitScreenBuffer,
1539 GuiWriteStream,
1540 GuiDrawRegion,
1541 GuiSetCursorInfo,
1542 GuiSetScreenInfo,
1543 GuiChangeTitle,
1544 GuiCleanupConsole,
1545 GuiChangeIcon
1546 };
1547
1548 NTSTATUS FASTCALL
1549 GuiInitConsole(PCSRSS_CONSOLE Console)
1550 {
1551 HANDLE GraphicsStartupEvent;
1552 HANDLE ThreadHandle;
1553 PGUI_CONSOLE_DATA GuiData;
1554
1555 if (! ConsInitialized)
1556 {
1557 ConsInitialized = TRUE;
1558 if (! GuiInit())
1559 {
1560 ConsInitialized = FALSE;
1561 return STATUS_UNSUCCESSFUL;
1562 }
1563 }
1564
1565 Console->Vtbl = &GuiVtbl;
1566 if (NULL == NotifyWnd)
1567 {
1568 GraphicsStartupEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1569 if (NULL == GraphicsStartupEvent)
1570 {
1571 return STATUS_UNSUCCESSFUL;
1572 }
1573
1574 ThreadHandle = CreateThread(NULL,
1575 0,
1576 GuiConsoleGuiThread,
1577 (PVOID) &GraphicsStartupEvent,
1578 0,
1579 NULL);
1580 if (NULL == ThreadHandle)
1581 {
1582 NtClose(GraphicsStartupEvent);
1583 DPRINT1("Win32Csr: Failed to create graphics console thread. Expect problems\n");
1584 return STATUS_UNSUCCESSFUL;
1585 }
1586 SetThreadPriority(ThreadHandle, THREAD_PRIORITY_HIGHEST);
1587 CloseHandle(ThreadHandle);
1588
1589 WaitForSingleObject(GraphicsStartupEvent, INFINITE);
1590 CloseHandle(GraphicsStartupEvent);
1591
1592 if (NULL == NotifyWnd)
1593 {
1594 DPRINT1("Win32Csr: Failed to create notification window.\n");
1595 return STATUS_UNSUCCESSFUL;
1596 }
1597 }
1598 GuiData = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY,
1599 sizeof(GUI_CONSOLE_DATA));
1600 if (!GuiData)
1601 {
1602 DPRINT1("Win32Csr: Failed to create GUI_CONSOLE_DATA\n");
1603 return STATUS_UNSUCCESSFUL;
1604 }
1605
1606 Console->PrivateData = (PVOID) GuiData;
1607 /*
1608 * we need to wait untill the GUI has been fully initialized
1609 * to retrieve custom settings i.e. WindowSize etc..
1610 * Ideally we could use SendNotifyMessage for this but its not
1611 * yet implemented.
1612 *
1613 */
1614 GuiData->hGuiInitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1615 /* create console */
1616 PostMessageW(NotifyWnd, PM_CREATE_CONSOLE, 0, (LPARAM) Console);
1617
1618 /* wait untill initialization has finished */
1619 WaitForSingleObject(GuiData->hGuiInitEvent, INFINITE);
1620 DPRINT1("received event Console %p GuiData %p X %d Y %d\n", Console, Console->PrivateData, Console->Size.X, Console->Size.Y);
1621 CloseHandle(GuiData->hGuiInitEvent);
1622 GuiData->hGuiInitEvent = NULL;
1623
1624 return STATUS_SUCCESS;
1625 }
1626
1627 /* EOF */