1 /* $Id: guiconsole.c,v 1.1 2003/12/02 11:38:46 gvg Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: subsys/csrss/win32csr/dllmain.c
6 * PURPOSE: Initialization
9 /* INCLUDES ******************************************************************/
13 #include "guiconsole.h"
16 /* GLOBALS *******************************************************************/
18 typedef struct GUI_CONSOLE_DATA_TAG
26 } GUI_CONSOLE_DATA
, *PGUI_CONSOLE_DATA
;
31 #define PM_CREATE_CONSOLE (WM_APP + 1)
32 #define PM_DESTROY_CONSOLE (WM_APP + 2)
34 #define PM_COPY_REGION (WM_APP + 100)
36 #define CURSOR_BLINK_TIME 500
38 static HWND NotifyWnd
;
40 /* FUNCTIONS *****************************************************************/
43 GuiConsoleGetDataPointers(HWND hWnd
, PCSRSS_CONSOLE
*Console
, PGUI_CONSOLE_DATA
*GuiData
)
45 *Console
= (PCSRSS_CONSOLE
) GetWindowLongW(hWnd
, GWL_USERDATA
);
46 *GuiData
= (NULL
== *Console
? NULL
: (*Console
)->GuiConsoleData
);
50 GuiConsoleHandleNcCreate(HWND hWnd
, CREATESTRUCTW
*Create
)
53 PCSRSS_CONSOLE Console
= (PCSRSS_CONSOLE
) Create
->lpCreateParams
;
54 PGUI_CONSOLE_DATA GuiData
;
59 GuiData
= HeapAlloc(Win32CsrApiHeap
, 0,
60 sizeof(GUI_CONSOLE_DATA
) +
61 (Console
->Size
.X
+ 1) * sizeof(WCHAR
));
64 DbgPrint("GuiConsoleNcCreate: HeapAlloc failed\n");
67 GuiData
->LineBuffer
= (PWCHAR
)(GuiData
+ 1);
69 GuiData
->Font
= CreateFontW(12, 0, 0, TA_BASELINE
, FW_NORMAL
,
70 FALSE
, FALSE
, FALSE
, ANSI_CHARSET
,
71 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
,
72 DEFAULT_QUALITY
, FIXED_PITCH
| FF_DONTCARE
,
73 L
"Bitstream Vera Sans Mono");
74 if (NULL
== GuiData
->Font
)
76 DbgPrint("GuiConsoleNcCreate: CreateFont failed\n");
77 HeapFree(Win32CsrApiHeap
, 0, GuiData
);
83 DbgPrint("GuiConsoleNcCreate: GetDC failed\n");
84 HeapFree(Win32CsrApiHeap
, 0, GuiData
);
87 OldFont
= SelectObject(Dc
, GuiData
->Font
);
90 DbgPrint("GuiConsoleNcCreate: SelectObject failed\n");
92 HeapFree(Win32CsrApiHeap
, 0, GuiData
);
95 if (! GetTextMetricsW(Dc
, &Metrics
))
97 DbgPrint("GuiConsoleNcCreate: GetTextMetrics failed\n");
98 SelectObject(Dc
, OldFont
);
100 HeapFree(Win32CsrApiHeap
, 0, GuiData
);
103 GuiData
->CharWidth
= Metrics
.tmMaxCharWidth
;
104 GuiData
->CharHeight
= Metrics
.tmHeight
+ Metrics
.tmExternalLeading
;
105 SelectObject(Dc
, OldFont
);
107 GuiData
->CursorBlinkOn
= TRUE
;
108 GuiData
->ForceCursorOff
= FALSE
;
110 Console
->GuiConsoleData
= GuiData
;
111 SetWindowLongW(hWnd
, GWL_USERDATA
, (LONG
) Console
);
113 GetWindowRect(hWnd
, &Rect
);
114 Rect
.right
= Rect
.left
+ Console
->Size
.X
* GuiData
->CharWidth
+
115 2 * GetSystemMetrics(SM_CXFIXEDFRAME
);
116 Rect
.bottom
= Rect
.top
+ Console
->Size
.Y
* GuiData
->CharHeight
+
117 2 * GetSystemMetrics(SM_CYFIXEDFRAME
) + GetSystemMetrics(SM_CYCAPTION
);
118 MoveWindow(hWnd
, Rect
.left
, Rect
.top
, Rect
.right
- Rect
.left
,
119 Rect
.bottom
- Rect
.top
, FALSE
);
121 SetTimer(hWnd
, 1, CURSOR_BLINK_TIME
, NULL
);
123 return (BOOL
) DefWindowProcW(hWnd
, WM_NCCREATE
, 0, (LPARAM
) Create
);
126 static COLORREF FASTCALL
127 GuiConsoleRGBFromAttribute(BYTE Attribute
)
129 int Red
= (Attribute
& 0x04 ? (Attribute
& 0x08 ? 0xff : 0x80) : 0x00);
130 int Green
= (Attribute
& 0x02 ? (Attribute
& 0x08 ? 0xff : 0x80) : 0x00);
131 int Blue
= (Attribute
& 0x01 ? (Attribute
& 0x08 ? 0xff : 0x80) : 0x00);
133 return RGB(Red
, Green
, Blue
);
137 GuiConsoleSetTextColors(HDC Dc
, BYTE Attribute
)
139 SetTextColor(Dc
, GuiConsoleRGBFromAttribute(Attribute
& 0x0f));
140 SetBkColor(Dc
, GuiConsoleRGBFromAttribute((Attribute
& 0xf0) >> 4));
144 GuiConsoleGetLogicalCursorPos(PCSRSS_SCREEN_BUFFER Buff
, ULONG
*CursorX
, ULONG
*CursorY
)
146 *CursorX
= Buff
->CurrentX
;
147 if (Buff
->CurrentY
< Buff
->ShowY
)
149 *CursorY
= Buff
->MaxY
- Buff
->ShowY
+ Buff
->CurrentY
;
153 *CursorY
= Buff
->CurrentY
- Buff
->ShowY
;
158 GuiConsoleHandlePaint(HWND hWnd
)
162 PCSRSS_CONSOLE Console
;
163 PGUI_CONSOLE_DATA GuiData
;
164 PCSRSS_SCREEN_BUFFER Buff
;
165 unsigned TopLine
, BottomLine
, LeftChar
, RightChar
;
166 unsigned Line
, Char
, Start
;
170 BYTE LastAttribute
, Attribute
;
171 ULONG CursorX
, CursorY
, CursorHeight
;
172 HBRUSH CursorBrush
, OldBrush
;
174 GuiConsoleGetDataPointers(hWnd
, &Console
, &GuiData
);
175 if (NULL
!= Console
&& NULL
!= GuiData
&& NULL
!= Console
->ActiveBuffer
)
177 Buff
= Console
->ActiveBuffer
;
178 EnterCriticalSection(&(Buff
->Lock
));
180 Dc
= BeginPaint(hWnd
, &Ps
);
181 if (Ps
.rcPaint
.right
<= Ps
.rcPaint
.left
|| Ps
.rcPaint
.bottom
<= Ps
.rcPaint
.top
)
184 LeaveCriticalSection(&(Buff
->Lock
));
187 OldFont
= SelectObject(Dc
, GuiData
->Font
);
189 TopLine
= Ps
.rcPaint
.top
/ GuiData
->CharHeight
;
190 BottomLine
= (Ps
.rcPaint
.bottom
+ (GuiData
->CharHeight
- 1)) / GuiData
->CharHeight
- 1;
191 LeftChar
= Ps
.rcPaint
.left
/ GuiData
->CharWidth
;
192 RightChar
= (Ps
.rcPaint
.right
+ (GuiData
->CharWidth
- 1)) / GuiData
->CharWidth
- 1;
193 LastAttribute
= Buff
->Buffer
[(TopLine
* Buff
->MaxX
+ LeftChar
) * 2 + 1];
194 GuiConsoleSetTextColors(Dc
, LastAttribute
);
195 for (Line
= TopLine
; Line
<= BottomLine
; Line
++)
197 if (Line
+ Buff
->ShowY
< Buff
->MaxY
)
199 From
= Buff
->Buffer
+ ((Line
+ Buff
->ShowY
) * Buff
->MaxX
+ LeftChar
) * 2;
203 From
= Buff
->Buffer
+
204 ((Line
- (Buff
->MaxY
- Buff
->ShowY
)) * Buff
->MaxX
+ LeftChar
) * 2;
206 Attribute
= *(From
+ 1);
208 To
= GuiData
->LineBuffer
;
209 for (Char
= LeftChar
; Char
<= RightChar
; Char
++)
211 if (*(From
+ 1) != Attribute
)
213 TextOutW(Dc
, Start
* GuiData
->CharWidth
, Line
* GuiData
->CharHeight
,
214 GuiData
->LineBuffer
, Char
- Start
);
216 Attribute
= *(From
+ 1);
217 if (Attribute
!= LastAttribute
)
219 GuiConsoleSetTextColors(Dc
, LastAttribute
);
222 *((PBYTE
) To
) = *From
;
223 *(((PBYTE
) To
) + 1) = '\0';
227 TextOutW(Dc
, Start
* GuiData
->CharWidth
, Line
* GuiData
->CharHeight
,
228 GuiData
->LineBuffer
, RightChar
- Start
+ 1);
231 SelectObject(Dc
, OldFont
);
233 if (Buff
->CursorInfo
.bVisible
&& GuiData
->CursorBlinkOn
234 &&! GuiData
->ForceCursorOff
)
236 GuiConsoleGetLogicalCursorPos(Buff
, &CursorX
, &CursorY
);
237 if (LeftChar
<= CursorX
&& CursorX
<= RightChar
&&
238 TopLine
<= CursorY
&& CursorY
<= BottomLine
)
240 CursorHeight
= (GuiData
->CharHeight
* Buff
->CursorInfo
.dwSize
) / 100;
241 if (CursorHeight
< 1)
245 From
= Buff
->Buffer
+ (Buff
->CurrentY
* Buff
->MaxX
+ Buff
->CurrentX
) * 2 + 1;
246 CursorBrush
= CreateSolidBrush(GuiConsoleRGBFromAttribute(*From
));
247 OldBrush
= SelectObject(Dc
, CursorBrush
);
248 PatBlt(Dc
, CursorX
* GuiData
->CharWidth
,
249 CursorY
* GuiData
->CharHeight
+ (GuiData
->CharHeight
- CursorHeight
),
250 GuiData
->CharWidth
, CursorHeight
, PATCOPY
);
251 SelectObject(Dc
, OldBrush
);
252 DeleteObject(CursorBrush
);
257 LeaveCriticalSection(&(Buff
->Lock
));
261 Dc
= BeginPaint(hWnd
, &Ps
);
267 GuiConsoleHandleKey(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
269 PCSRSS_CONSOLE Console
;
270 PGUI_CONSOLE_DATA GuiData
;
273 GuiConsoleGetDataPointers(hWnd
, &Console
, &GuiData
);
275 Message
.message
= msg
;
276 Message
.wParam
= wParam
;
277 Message
.lParam
= lParam
;
279 CsrProcessKey(&Message
, Console
);
283 GuiConsoleHandleCopyRegion(HWND hWnd
, PRECT Source
, PRECT Dest
)
286 int XDest
, YDest
, Width
, Height
, XSrc
, YSrc
;
287 PCSRSS_CONSOLE Console
;
288 PGUI_CONSOLE_DATA GuiData
;
289 RECT CursorRect
, UpdateRect
;
290 DWORD CursorX
, CursorY
;
291 PCSRSS_SCREEN_BUFFER Buff
;
293 GuiConsoleGetDataPointers(hWnd
, &Console
, &GuiData
);
294 Buff
= Console
->ActiveBuffer
;
296 /* Check if the cursor is in the source rectangle and if it is,
297 * make sure it's invisible */
298 GuiConsoleGetLogicalCursorPos(Buff
, &CursorX
, &CursorY
);
299 if (Source
->left
<= CursorX
&& CursorX
<= Source
->right
&&
300 Source
->top
<= CursorY
&& CursorY
<= Source
->bottom
)
302 GuiData
->ForceCursorOff
= TRUE
;
304 CursorRect
.left
= CursorX
* GuiData
->CharWidth
;
305 CursorRect
.top
= CursorY
* GuiData
->CharHeight
;
306 CursorRect
.right
= (CursorX
+ 1) * GuiData
->CharWidth
;
307 CursorRect
.bottom
= (CursorY
+ 1) * GuiData
->CharHeight
;
309 InvalidateRect(hWnd
, &CursorRect
, FALSE
);
313 /* This is a bit tricky. We want to copy a source rectangle to
314 * a destination rectangle, but there is no guarantee that the
315 * contents of the source rectangle is valid. First let's try
316 * to make it as valid as possible by painting all outstanding
317 * updates. To do that we have to release the lock, otherwise
318 * the paint code can't acquire it */
328 XSrc
= Source
->left
* GuiData
->CharWidth
;
329 YSrc
= Source
->top
* GuiData
->CharHeight
;
330 XDest
= Dest
->left
* GuiData
->CharWidth
;
331 YDest
= Dest
->top
* GuiData
->CharHeight
;
332 Width
= (Dest
->right
- Dest
->left
+ 1) * GuiData
->CharWidth
;
333 Height
= (Dest
->bottom
- Dest
->top
+ 1) * GuiData
->CharHeight
;
335 BitBlt(Dc
, XDest
, YDest
, Width
, Height
, Dc
, XSrc
, YSrc
, SRCCOPY
);
339 /* Although we tried to make sure that the source rectangle was
340 * up-to-date, this is not guaranteed. For example, the user could
341 * have moved a window between the UpdateWindow() and the BitBlt()
342 * above, invalidating part of the window. So, we're going to
343 * check if the current update rect of the window overlaps with the
344 * source rectangle. If it does, we invalidate the corresponding
345 * part of the destination rectangle so it will eventually be
346 * repainted. Note that this is probably doesn't happen all that
347 * often and GetUpdateRect() below will usually return FALSE,
348 * indicating that the whole window is valid */
350 if (GetUpdateRect(hWnd
, &UpdateRect
, FALSE
))
352 UpdateRect
.left
= max(UpdateRect
.left
, XSrc
);
353 UpdateRect
.top
= max(UpdateRect
.top
, YSrc
);
354 UpdateRect
.right
= min(UpdateRect
.right
, XSrc
+ Width
);
355 UpdateRect
.bottom
= min(UpdateRect
.bottom
, YSrc
+ Height
);
356 if (UpdateRect
.left
< UpdateRect
.right
&& UpdateRect
.top
< UpdateRect
.bottom
)
358 UpdateRect
.left
+= XDest
- XSrc
;
359 UpdateRect
.top
+= YDest
- YSrc
;
360 UpdateRect
.right
+= XDest
- XSrc
;
361 UpdateRect
.bottom
+= YDest
- YSrc
;
363 InvalidateRect(Console
->hWindow
, &UpdateRect
, FALSE
);
367 /* Show cursor again if we made it invisible */
368 if (GuiData
->ForceCursorOff
)
370 GuiData
->ForceCursorOff
= FALSE
;
372 InvalidateRect(hWnd
, &CursorRect
, FALSE
);
377 GuiConsoleHandleTimer(HWND hWnd
)
379 PCSRSS_CONSOLE Console
;
380 PGUI_CONSOLE_DATA GuiData
;
381 SMALL_RECT CursorRect
;
382 ULONG CursorX
, CursorY
;
384 GuiConsoleGetDataPointers(hWnd
, &Console
, &GuiData
);
385 GuiData
->CursorBlinkOn
= ! GuiData
->CursorBlinkOn
;
387 GuiConsoleGetLogicalCursorPos(Console
->ActiveBuffer
, &CursorX
, &CursorY
);
388 CursorRect
.Left
= CursorX
;
389 CursorRect
.Top
= CursorY
;
390 CursorRect
.Right
= CursorX
;
391 CursorRect
.Bottom
= CursorY
;
392 GuiConsoleDrawRegion(Console
, CursorRect
);
396 GuiConsoleHandleClose(HWND hWnd
)
398 /* FIXME for now, just ignore close requests */
402 GuiConsoleHandleNcDestroy(HWND hWnd
)
404 PCSRSS_CONSOLE Console
;
405 PGUI_CONSOLE_DATA GuiData
;
407 GuiConsoleGetDataPointers(hWnd
, &Console
, &GuiData
);
409 Console
->GuiConsoleData
= NULL
;
410 HeapFree(Win32CsrApiHeap
, 0, GuiData
);
413 static LRESULT CALLBACK
414 GuiConsoleWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
421 Result
= (LRESULT
) GuiConsoleHandleNcCreate(hWnd
, (CREATESTRUCTW
*) lParam
);
424 GuiConsoleHandlePaint(hWnd
);
432 GuiConsoleHandleKey(hWnd
, msg
, wParam
, lParam
);
436 GuiConsoleHandleTimer(hWnd
);
440 GuiConsoleHandleCopyRegion(hWnd
, (PRECT
) wParam
, (PRECT
) lParam
);
443 GuiConsoleHandleClose(hWnd
);
447 GuiConsoleHandleNcDestroy(hWnd
);
451 Result
= DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
458 static LRESULT CALLBACK
459 GuiConsoleNotifyWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
463 PCSRSS_CONSOLE Console
= (PCSRSS_CONSOLE
) lParam
;
468 SetWindowLongW(hWnd
, GWL_USERDATA
, 0);
470 case PM_CREATE_CONSOLE
:
471 NewWindow
= CreateWindowW(L
"Win32CsrConsole",
472 Console
->Title
.Buffer
,
473 WS_OVERLAPPED
| WS_CAPTION
| WS_SYSMENU
| WS_MINIMIZEBOX
,
480 (HINSTANCE
) GetModuleHandleW(NULL
),
482 if (NULL
!= NewWindow
)
484 SetWindowLongW(hWnd
, GWL_USERDATA
, GetWindowLongW(hWnd
, GWL_USERDATA
) + 1);
485 ShowWindow(NewWindow
, SW_SHOW
);
487 return (LRESULT
) NewWindow
;
488 case PM_DESTROY_CONSOLE
:
489 DestroyWindow(Console
->hWindow
);
490 Console
->hWindow
= NULL
;
491 WindowCount
= GetWindowLongW(hWnd
, GWL_USERDATA
);
493 SetWindowLongW(hWnd
, GWL_USERDATA
, WindowCount
);
494 if (0 == WindowCount
)
500 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
505 GuiConsoleGuiThread(PVOID Data
)
509 PHANDLE GraphicsStartupEvent
= (PHANDLE
) Data
;
511 wc
.lpszClassName
= L
"Win32CsrCreateNotify";
512 wc
.lpfnWndProc
= GuiConsoleNotifyWndProc
;
514 wc
.hInstance
= (HINSTANCE
) GetModuleHandleW(NULL
);
517 wc
.hbrBackground
= NULL
;
518 wc
.lpszMenuName
= NULL
;
521 if (RegisterClassW(&wc
) == 0)
523 NtSetEvent(*GraphicsStartupEvent
, 0);
527 wc
.lpszClassName
= L
"Win32CsrConsole";
528 wc
.lpfnWndProc
= GuiConsoleWndProc
;
530 wc
.hInstance
= (HINSTANCE
) GetModuleHandleW(NULL
);
531 wc
.hIcon
= LoadIconW(NULL
, (LPCWSTR
) IDI_APPLICATION
);
532 wc
.hCursor
= LoadCursorW(NULL
, (LPCWSTR
) IDC_ARROW
);
533 wc
.hbrBackground
= NULL
;
534 wc
.lpszMenuName
= NULL
;
537 if (RegisterClassW(&wc
) == 0)
539 NtSetEvent(*GraphicsStartupEvent
, 0);
543 NotifyWnd
= CreateWindowW(L
"Win32CsrCreateNotify",
552 (HINSTANCE
) GetModuleHandleW(NULL
),
554 if (NULL
== NotifyWnd
)
556 NtSetEvent(*GraphicsStartupEvent
, 0);
560 NtSetEvent(*GraphicsStartupEvent
, 0);
562 while(GetMessageW(&msg
, NULL
, 0, 0))
564 TranslateMessage(&msg
);
565 DispatchMessageW(&msg
);
572 GuiConsoleInitConsoleSupport(VOID
)
575 OBJECT_ATTRIBUTES ObjectAttributes
;
576 HANDLE GraphicsStartupEvent
;
577 HWINSTA WindowStation
;
581 WindowStation
= OpenWindowStationW(L
"WinSta0", FALSE
, GENERIC_ALL
);
582 if (NULL
== WindowStation
)
584 DbgPrint("Win32Csr: failed to open window station\n");
587 if (! SetProcessWindowStation(WindowStation
))
589 DbgPrint("Win32Csr: failed to set process window station\n");
592 Desktop
= OpenDesktopW(L
"Default", 0, FALSE
, GENERIC_ALL
);
595 DbgPrint("Win32Csr: failed to open desktop\n");
598 Status
= NtSetInformationProcess(NtCurrentProcess(),
602 if (!NT_SUCCESS(Status
))
604 DbgPrint("Win32Csr: cannot set default desktop.\n");
607 if (! SetThreadDesktop(Desktop
))
609 DbgPrint("Win32Csr: failed to set thread desktop\n");
613 InitializeObjectAttributes(&ObjectAttributes
, NULL
, OBJ_INHERIT
, NULL
, NULL
);
615 Status
= NtCreateEvent(&GraphicsStartupEvent
, STANDARD_RIGHTS_ALL
, &ObjectAttributes
, FALSE
, FALSE
);
616 if( !NT_SUCCESS(Status
))
621 ThreadHandle
= CreateThread(NULL
,
624 (PVOID
) &GraphicsStartupEvent
,
627 if (NULL
== ThreadHandle
)
629 NtClose(GraphicsStartupEvent
);
630 DbgPrint("Win32Csr: Failed to create graphics console thread. Expect problems\n");
633 CloseHandle(ThreadHandle
);
635 NtWaitForSingleObject(GraphicsStartupEvent
, FALSE
, NULL
);
636 NtClose(GraphicsStartupEvent
);
638 if (NULL
== NotifyWnd
)
640 DbgPrint("Win32Csr: Failed to create notification window.\n");
646 GuiConsoleInitConsole(PCSRSS_CONSOLE Console
)
648 Console
->Size
.X
= 80;
649 Console
->Size
.Y
= 25;
650 Console
->hWindow
= (HWND
) SendMessageW(NotifyWnd
, PM_CREATE_CONSOLE
, 0, (LPARAM
) Console
);
652 return NULL
!= Console
->hWindow
;
656 GuiConsoleDrawRegion(PCSRSS_CONSOLE Console
, SMALL_RECT Region
)
658 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
) Console
->GuiConsoleData
;
661 if (NULL
== Console
->hWindow
|| NULL
== GuiData
)
666 RegionRect
.left
= Region
.Left
* GuiData
->CharWidth
;
667 RegionRect
.top
= Region
.Top
* GuiData
->CharHeight
;
668 RegionRect
.right
= (Region
.Right
+ 1) * GuiData
->CharWidth
;
669 RegionRect
.bottom
= (Region
.Bottom
+ 1) * GuiData
->CharHeight
;
671 InvalidateRect(Console
->hWindow
, &RegionRect
, FALSE
);
675 GuiConsoleCopyRegion(PCSRSS_CONSOLE Console
,
679 LeaveCriticalSection(&(Console
->ActiveBuffer
->Lock
));
680 SendMessageW(Console
->hWindow
, PM_COPY_REGION
, (WPARAM
) Source
, (LPARAM
) Dest
);
681 EnterCriticalSection(&(Console
->ActiveBuffer
->Lock
));
685 GuiConsoleChangeTitle(PCSRSS_CONSOLE Console
)
687 SendMessageW(Console
->hWindow
, WM_SETTEXT
, 0, (LPARAM
) Console
->Title
.Buffer
);
691 GuiConsoleDeleteConsole(PCSRSS_CONSOLE Console
)
693 SendMessageW(NotifyWnd
, PM_DESTROY_CONSOLE
, 0, (LPARAM
) Console
);