Bug fixes against uninitizlied variables and support for tree-wide optimization ...
[reactos.git] / reactos / subsys / 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 <windows.h>
12 #include "conio.h"
13 #include "guiconsole.h"
14 #include "win32csr.h"
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* Not defined in any header file */
20 extern VOID STDCALL PrivateCsrssManualGuiCheck(LONG Check);
21
22 /* GLOBALS *******************************************************************/
23
24 typedef struct GUI_CONSOLE_DATA_TAG
25 {
26 HFONT Font;
27 unsigned CharWidth;
28 unsigned CharHeight;
29 PWCHAR LineBuffer;
30 BOOL CursorBlinkOn;
31 BOOL ForceCursorOff;
32 CRITICAL_SECTION Lock;
33 HDC MemoryDC;
34 HBITMAP MemoryBitmap;
35 RECT Selection;
36 POINT SelectionStart;
37 BOOL MouseDown;
38 } GUI_CONSOLE_DATA, *PGUI_CONSOLE_DATA;
39
40 #ifndef WM_APP
41 #define WM_APP 0x8000
42 #endif
43 #define PM_CREATE_CONSOLE (WM_APP + 1)
44 #define PM_DESTROY_CONSOLE (WM_APP + 2)
45
46 #define CURSOR_BLINK_TIME 500
47
48 static BOOL Initialized = FALSE;
49 static HWND NotifyWnd;
50
51 /* FUNCTIONS *****************************************************************/
52
53 static VOID FASTCALL
54 GuiConsoleGetDataPointers(HWND hWnd, PCSRSS_CONSOLE *Console, PGUI_CONSOLE_DATA *GuiData)
55 {
56 *Console = (PCSRSS_CONSOLE) GetWindowLongPtrW(hWnd, GWL_USERDATA);
57 *GuiData = (NULL == *Console ? NULL : (*Console)->PrivateData);
58 }
59
60 static BOOL FASTCALL
61 GuiConsoleHandleNcCreate(HWND hWnd, CREATESTRUCTW *Create)
62 {
63 RECT Rect;
64 PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) Create->lpCreateParams;
65 PGUI_CONSOLE_DATA GuiData;
66 HDC Dc;
67 HFONT OldFont;
68 TEXTMETRICW Metrics;
69
70 GuiData = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY,
71 sizeof(GUI_CONSOLE_DATA) +
72 (Console->Size.X + 1) * sizeof(WCHAR));
73 if (NULL == GuiData)
74 {
75 DPRINT1("GuiConsoleNcCreate: HeapAlloc failed\n");
76 return FALSE;
77 }
78
79 InitializeCriticalSection(&GuiData->Lock);
80
81 GuiData->LineBuffer = (PWCHAR)(GuiData + 1);
82
83 GuiData->Font = CreateFontW(12, 0, 0, TA_BASELINE, FW_NORMAL,
84 FALSE, FALSE, FALSE, OEM_CHARSET,
85 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
86 NONANTIALIASED_QUALITY, FIXED_PITCH | FF_DONTCARE,
87 L"Bitstream Vera Sans Mono");
88 if (NULL == GuiData->Font)
89 {
90 DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
91 DeleteCriticalSection(&GuiData->Lock);
92 HeapFree(Win32CsrApiHeap, 0, GuiData);
93 return FALSE;
94 }
95 Dc = GetDC(hWnd);
96 if (NULL == Dc)
97 {
98 DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
99 DeleteObject(GuiData->Font);
100 DeleteCriticalSection(&GuiData->Lock);
101 HeapFree(Win32CsrApiHeap, 0, GuiData);
102 return FALSE;
103 }
104 OldFont = SelectObject(Dc, GuiData->Font);
105 if (NULL == OldFont)
106 {
107 DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
108 ReleaseDC(hWnd, Dc);
109 DeleteObject(GuiData->Font);
110 DeleteCriticalSection(&GuiData->Lock);
111 HeapFree(Win32CsrApiHeap, 0, GuiData);
112 return FALSE;
113 }
114 if (! GetTextMetricsW(Dc, &Metrics))
115 {
116 DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
117 SelectObject(Dc, OldFont);
118 ReleaseDC(hWnd, Dc);
119 DeleteObject(GuiData->Font);
120 DeleteCriticalSection(&GuiData->Lock);
121 HeapFree(Win32CsrApiHeap, 0, GuiData);
122 return FALSE;
123 }
124 GuiData->CharWidth = Metrics.tmMaxCharWidth;
125 GuiData->CharHeight = Metrics.tmHeight + Metrics.tmExternalLeading;
126 SelectObject(Dc, OldFont);
127
128 GuiData->MemoryDC = CreateCompatibleDC(Dc);
129 GuiData->MemoryBitmap = CreateCompatibleBitmap(Dc,
130 Console->Size.X * GuiData->CharWidth,
131 Console->Size.Y * GuiData->CharHeight);
132 /* NOTE: Don't delete the "first bitmap", it's done in DeleteDC. */
133 SelectObject(GuiData->MemoryDC, GuiData->MemoryBitmap);
134 /* NOTE: Don't delete stock font. */
135 SelectObject(GuiData->MemoryDC, GuiData->Font);
136
137 ReleaseDC(hWnd, Dc);
138 GuiData->CursorBlinkOn = TRUE;
139 GuiData->ForceCursorOff = FALSE;
140
141 GuiData->Selection.left = -1;
142
143 Console->PrivateData = GuiData;
144 SetWindowLongPtrW(hWnd, GWL_USERDATA, (DWORD_PTR) Console);
145
146 GetWindowRect(hWnd, &Rect);
147 Rect.right = Rect.left + Console->Size.X * GuiData->CharWidth +
148 2 * GetSystemMetrics(SM_CXFIXEDFRAME);
149 Rect.bottom = Rect.top + Console->Size.Y * GuiData->CharHeight +
150 2 * GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYCAPTION);
151 MoveWindow(hWnd, Rect.left, Rect.top, Rect.right - Rect.left,
152 Rect.bottom - Rect.top, FALSE);
153
154 SetTimer(hWnd, 1, CURSOR_BLINK_TIME, NULL);
155
156 return (BOOL) DefWindowProcW(hWnd, WM_NCCREATE, 0, (LPARAM) Create);
157 }
158
159 static COLORREF FASTCALL
160 GuiConsoleRGBFromAttribute(BYTE Attribute)
161 {
162 int Red = (Attribute & 0x04 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);
163 int Green = (Attribute & 0x02 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);
164 int Blue = (Attribute & 0x01 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);
165
166 return RGB(Red, Green, Blue);
167 }
168
169 static VOID FASTCALL
170 GuiConsoleSetTextColors(HDC Dc, BYTE Attribute)
171 {
172 SetTextColor(Dc, GuiConsoleRGBFromAttribute(Attribute & 0x0f));
173 SetBkColor(Dc, GuiConsoleRGBFromAttribute((Attribute & 0xf0) >> 4));
174 }
175
176 static VOID FASTCALL
177 GuiConsoleGetLogicalCursorPos(PCSRSS_SCREEN_BUFFER Buff, ULONG *CursorX, ULONG *CursorY)
178 {
179 *CursorX = Buff->CurrentX;
180 if (Buff->CurrentY < Buff->ShowY)
181 {
182 *CursorY = Buff->MaxY - Buff->ShowY + Buff->CurrentY;
183 }
184 else
185 {
186 *CursorY = Buff->CurrentY - Buff->ShowY;
187 }
188 }
189
190
191 static VOID FASTCALL
192 GuiConsoleUpdateSelection(HWND hWnd, PRECT rc, PGUI_CONSOLE_DATA GuiData)
193 {
194 RECT oldRect = GuiData->Selection;
195
196 if(rc != NULL)
197 {
198 RECT changeRect = *rc;
199
200 GuiData->Selection = *rc;
201
202 changeRect.left *= GuiData->CharWidth;
203 changeRect.top *= GuiData->CharHeight;
204 changeRect.right *= GuiData->CharWidth;
205 changeRect.bottom *= GuiData->CharHeight;
206
207 if(rc->left != oldRect.left ||
208 rc->top != oldRect.top ||
209 rc->right != oldRect.right ||
210 rc->bottom != oldRect.bottom)
211 {
212 if(oldRect.left != -1)
213 {
214 HRGN rgn1, rgn2;
215
216 oldRect.left *= GuiData->CharWidth;
217 oldRect.top *= GuiData->CharHeight;
218 oldRect.right *= GuiData->CharWidth;
219 oldRect.bottom *= GuiData->CharHeight;
220
221 /* calculate the region that needs to be updated */
222 if((rgn1 = CreateRectRgnIndirect(&oldRect)))
223 {
224 if((rgn2 = CreateRectRgnIndirect(&changeRect)))
225 {
226 if(CombineRgn(rgn1, rgn2, rgn1, RGN_XOR) != ERROR)
227 {
228 InvalidateRgn(hWnd, rgn1, FALSE);
229 }
230
231 DeleteObject(rgn2);
232 }
233 DeleteObject(rgn1);
234 }
235 }
236 else
237 {
238 InvalidateRect(hWnd, &changeRect, FALSE);
239 }
240 }
241 }
242 else if(oldRect.left != -1)
243 {
244 /* clear the selection */
245 GuiData->Selection.left = -1;
246 oldRect.left *= GuiData->CharWidth;
247 oldRect.top *= GuiData->CharHeight;
248 oldRect.right *= GuiData->CharWidth;
249 oldRect.bottom *= GuiData->CharHeight;
250 InvalidateRect(hWnd, &oldRect, FALSE);
251 }
252 }
253
254
255 VOID FASTCALL
256 GuiConsoleUpdateBitmap(HWND hWnd, RECT rc)
257 {
258 PCSRSS_CONSOLE Console;
259 PGUI_CONSOLE_DATA GuiData;
260 PCSRSS_SCREEN_BUFFER Buff;
261 HDC Dc;
262 ULONG TopLine, BottomLine, LeftChar, RightChar;
263 ULONG Line, Char, Start;
264 PBYTE From;
265 PWCHAR To;
266 BYTE LastAttribute, Attribute;
267 ULONG CursorX, CursorY, CursorHeight;
268 HBRUSH CursorBrush, OldBrush;
269
270 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
271 if (NULL != Console && NULL != GuiData && NULL != Console->ActiveBuffer)
272 {
273 Buff = Console->ActiveBuffer;
274 EnterCriticalSection(&Buff->Header.Lock);
275 Dc = GetDC(hWnd);
276 if (rc.right <= rc.left || rc.bottom <= rc.top)
277 {
278 ReleaseDC(hWnd, Dc);
279 LeaveCriticalSection(&Buff->Header.Lock);
280 return;
281 }
282
283 EnterCriticalSection(&GuiData->Lock);
284
285 TopLine = rc.top / GuiData->CharHeight;
286 BottomLine = (rc.bottom + (GuiData->CharHeight - 1)) / GuiData->CharHeight - 1;
287 LeftChar = rc.left / GuiData->CharWidth;
288 RightChar = (rc.right + (GuiData->CharWidth - 1)) / GuiData->CharWidth - 1;
289 LastAttribute = Buff->Buffer[(TopLine * Buff->MaxX + LeftChar) * 2 + 1];
290 GuiConsoleSetTextColors(GuiData->MemoryDC, LastAttribute);
291
292 for (Line = TopLine; Line <= BottomLine; Line++)
293 {
294 if (Line + Buff->ShowY < Buff->MaxY)
295 {
296 From = Buff->Buffer + ((Line + Buff->ShowY) * Buff->MaxX + LeftChar) * 2;
297 }
298 else
299 {
300 From = Buff->Buffer +
301 ((Line - (Buff->MaxY - Buff->ShowY)) * Buff->MaxX + LeftChar) * 2;
302 }
303 Start = LeftChar;
304 To = GuiData->LineBuffer;
305 for (Char = LeftChar; Char <= RightChar; Char++)
306 {
307 if (*(From + 1) != LastAttribute)
308 {
309 TextOutW(GuiData->MemoryDC, Start * GuiData->CharWidth, Line * GuiData->CharHeight,
310 GuiData->LineBuffer, Char - Start);
311 Start = Char;
312 To = GuiData->LineBuffer;
313 Attribute = *(From + 1);
314 if (Attribute != LastAttribute)
315 {
316 GuiConsoleSetTextColors(GuiData->MemoryDC, Attribute);
317 LastAttribute = Attribute;
318 }
319 }
320 MultiByteToWideChar(Console->OutputCodePage, 0, (PCHAR)From, 1, To, 1);
321 To++;
322 From += 2;
323 }
324 TextOutW(GuiData->MemoryDC, Start * GuiData->CharWidth, Line * GuiData->CharHeight,
325 GuiData->LineBuffer, RightChar - Start + 1);
326 }
327
328 if (Buff->CursorInfo.bVisible && GuiData->CursorBlinkOn
329 &&! GuiData->ForceCursorOff)
330 {
331 GuiConsoleGetLogicalCursorPos(Buff, &CursorX, &CursorY);
332 if (LeftChar <= CursorX && CursorX <= RightChar &&
333 TopLine <= CursorY && CursorY <= BottomLine)
334 {
335 CursorHeight = (GuiData->CharHeight * Buff->CursorInfo.dwSize) / 100;
336 if (CursorHeight < 1)
337 {
338 CursorHeight = 1;
339 }
340 From = Buff->Buffer + (Buff->CurrentY * Buff->MaxX + Buff->CurrentX) * 2 + 1;
341 CursorBrush = CreateSolidBrush(GuiConsoleRGBFromAttribute(*From));
342 OldBrush = SelectObject(GuiData->MemoryDC, CursorBrush);
343 PatBlt(GuiData->MemoryDC, CursorX * GuiData->CharWidth,
344 CursorY * GuiData->CharHeight + (GuiData->CharHeight - CursorHeight),
345 GuiData->CharWidth, CursorHeight, PATCOPY);
346 SelectObject(GuiData->MemoryDC, OldBrush);
347 DeleteObject(CursorBrush);
348 }
349 }
350
351 LeaveCriticalSection(&GuiData->Lock);
352 ReleaseDC(hWnd, Dc);
353 LeaveCriticalSection(&Buff->Header.Lock);
354 InvalidateRect(hWnd, &rc, FALSE);
355 }
356 }
357
358 VOID FASTCALL
359 GuiConsoleHandlePaint(HWND hWnd)
360 {
361 PAINTSTRUCT Ps;
362 HDC Dc;
363 PCSRSS_CONSOLE Console;
364 PGUI_CONSOLE_DATA GuiData;
365
366 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
367 if (NULL != Console && NULL != GuiData)
368 {
369 EnterCriticalSection(&GuiData->Lock);
370 Dc = BeginPaint (hWnd, &Ps);
371 BitBlt(Dc, Ps.rcPaint.left, Ps.rcPaint.top,
372 Ps.rcPaint.right - Ps.rcPaint.left + 1,
373 Ps.rcPaint.bottom - Ps.rcPaint.top + 1, GuiData->MemoryDC,
374 Ps.rcPaint.left, Ps.rcPaint.top, SRCCOPY);
375
376 if (GuiData->Selection.left != -1)
377 {
378 RECT rc = GuiData->Selection;
379
380 rc.left *= GuiData->CharWidth;
381 rc.top *= GuiData->CharHeight;
382 rc.right *= GuiData->CharWidth;
383 rc.bottom *= GuiData->CharHeight;
384
385 if (IntersectRect(&rc, &Ps.rcPaint, &rc))
386 {
387 PatBlt(Dc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, DSTINVERT);
388 }
389 }
390
391 EndPaint (hWnd, &Ps);
392 LeaveCriticalSection(&GuiData->Lock);
393 }
394 else
395 {
396 Dc = BeginPaint (hWnd, &Ps);
397 EndPaint (hWnd, &Ps);
398 }
399 }
400
401 static VOID FASTCALL
402 GuiConsoleHandleKey(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
403 {
404 PCSRSS_CONSOLE Console;
405 PGUI_CONSOLE_DATA GuiData;
406 MSG Message;
407
408 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
409 Message.hwnd = hWnd;
410 Message.message = msg;
411 Message.wParam = wParam;
412 Message.lParam = lParam;
413
414 if(msg == WM_CHAR || msg == WM_SYSKEYDOWN)
415 {
416 /* clear the selection */
417 GuiConsoleUpdateSelection(hWnd, NULL, GuiData);
418 }
419
420 ConioProcessKey(&Message, Console, FALSE);
421 }
422
423 static VOID FASTCALL
424 GuiIntDrawRegion(PGUI_CONSOLE_DATA GuiData, HWND Wnd, RECT *Region)
425 {
426 RECT RegionRect;
427
428 RegionRect.left = Region->left * GuiData->CharWidth;
429 RegionRect.top = Region->top * GuiData->CharHeight;
430 RegionRect.right = (Region->right + 1) * GuiData->CharWidth;
431 RegionRect.bottom = (Region->bottom + 1) * GuiData->CharHeight;
432
433 GuiConsoleUpdateBitmap(Wnd, RegionRect);
434 }
435
436 static VOID STDCALL
437 GuiDrawRegion(PCSRSS_CONSOLE Console, RECT *Region)
438 {
439 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA) Console->PrivateData;
440
441 if (NULL == Console->hWindow || NULL == GuiData)
442 {
443 return;
444 }
445
446 GuiIntDrawRegion(GuiData, Console->hWindow, Region);
447 }
448
449 static VOID FASTCALL
450 GuiInvalidateCell(PGUI_CONSOLE_DATA GuiData, HWND Wnd, UINT x, UINT y)
451 {
452 RECT CellRect;
453
454 CellRect.left = x;
455 CellRect.top = y;
456 CellRect.right = x;
457 CellRect.bottom = y;
458
459 GuiIntDrawRegion(GuiData, Wnd, &CellRect);
460 }
461
462 static VOID STDCALL
463 GuiWriteStream(PCSRSS_CONSOLE Console, RECT *Region, UINT CursorStartX, UINT CursorStartY,
464 UINT ScrolledLines, CHAR *Buffer, UINT Length)
465 {
466 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA) Console->PrivateData;
467 PCSRSS_SCREEN_BUFFER Buff = Console->ActiveBuffer;
468 LONG CursorEndX, CursorEndY;
469 RECT Source, Dest;
470
471 if (NULL == Console->hWindow || NULL == GuiData)
472 {
473 return;
474 }
475
476 if (0 != ScrolledLines)
477 {
478 Source.left = 0;
479 Source.top = ScrolledLines;
480 Source.right = Console->Size.X - 1;
481 Source.bottom = ScrolledLines + Region->top - 1;
482 Dest.left = 0;
483 Dest.top = 0;
484 Dest.right = Console->Size.X - 1;
485 Dest.bottom = Region->top - 1;
486
487 GuiConsoleCopyRegion(Console->hWindow, &Source, &Dest);
488 }
489
490 GuiIntDrawRegion(GuiData, Console->hWindow, Region);
491
492 if (CursorStartX < Region->left || Region->right < CursorStartX
493 || CursorStartY < Region->top || Region->bottom < CursorStartY)
494 {
495 GuiInvalidateCell(GuiData, Console->hWindow, CursorStartX, CursorStartY);
496 }
497
498 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY,
499 &CursorEndX, &CursorEndY);
500 if ((CursorEndX < Region->left || Region->right < CursorEndX
501 || CursorEndY < Region->top || Region->bottom < CursorEndY)
502 && (CursorEndX != CursorStartX || CursorEndY != CursorStartY))
503 {
504 GuiInvalidateCell(GuiData, Console->hWindow, CursorEndX, CursorEndY);
505 }
506 }
507
508 static BOOL STDCALL
509 GuiSetCursorInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff)
510 {
511 RECT UpdateRect;
512
513 if (Console->ActiveBuffer == Buff)
514 {
515 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY,
516 &UpdateRect.left, &UpdateRect.top);
517 UpdateRect.right = UpdateRect.left;
518 UpdateRect.bottom = UpdateRect.top;
519 ConioDrawRegion(Console, &UpdateRect);
520 }
521
522 return TRUE;
523 }
524
525 static BOOL STDCALL
526 GuiSetScreenInfo(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff, UINT OldCursorX, UINT OldCursorY)
527 {
528 RECT UpdateRect;
529
530 if (Console->ActiveBuffer == Buff)
531 {
532 /* Redraw char at old position (removes cursor) */
533 UpdateRect.left = OldCursorX;
534 UpdateRect.top = OldCursorY;
535 UpdateRect.right = OldCursorX;
536 UpdateRect.bottom = OldCursorY;
537 ConioDrawRegion(Console, &UpdateRect);
538 /* Redraw char at new position (shows cursor) */
539 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY,
540 &(UpdateRect.left), &(UpdateRect.top));
541 UpdateRect.right = UpdateRect.left;
542 UpdateRect.bottom = UpdateRect.top;
543 ConioDrawRegion(Console, &UpdateRect);
544 }
545
546 return TRUE;
547 }
548
549 static VOID FASTCALL
550 GuiConsoleHandleTimer(HWND hWnd)
551 {
552 PCSRSS_CONSOLE Console;
553 PGUI_CONSOLE_DATA GuiData;
554 RECT CursorRect;
555 ULONG CursorX, CursorY;
556
557 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
558 GuiData->CursorBlinkOn = ! GuiData->CursorBlinkOn;
559
560 GuiConsoleGetLogicalCursorPos(Console->ActiveBuffer, &CursorX, &CursorY);
561 CursorRect.left = CursorX;
562 CursorRect.top = CursorY;
563 CursorRect.right = CursorX;
564 CursorRect.bottom = CursorY;
565 GuiDrawRegion(Console, &CursorRect);
566 }
567
568 static VOID FASTCALL
569 GuiConsoleHandleClose(HWND hWnd)
570 {
571 PCSRSS_CONSOLE Console;
572 PGUI_CONSOLE_DATA GuiData;
573 PLIST_ENTRY current_entry;
574 PCSRSS_PROCESS_DATA current;
575
576 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
577
578 EnterCriticalSection(&Console->Header.Lock);
579
580 current_entry = Console->ProcessList.Flink;
581 while (current_entry != &Console->ProcessList)
582 {
583 current = CONTAINING_RECORD(current_entry, CSRSS_PROCESS_DATA, ProcessEntry);
584 current_entry = current_entry->Flink;
585
586 ConioConsoleCtrlEvent(CTRL_CLOSE_EVENT, current);
587 }
588
589 LeaveCriticalSection(&Console->Header.Lock);
590 }
591
592 static VOID FASTCALL
593 GuiConsoleHandleNcDestroy(HWND hWnd)
594 {
595 PCSRSS_CONSOLE Console;
596 PGUI_CONSOLE_DATA GuiData;
597
598 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
599 KillTimer(hWnd, 1);
600 Console->PrivateData = NULL;
601 DeleteDC(GuiData->MemoryDC);
602 DeleteCriticalSection(&GuiData->Lock);
603 HeapFree(Win32CsrApiHeap, 0, GuiData);
604 }
605
606 static VOID FASTCALL
607 GuiConsoleLeftMouseDown(HWND hWnd, LPARAM lParam)
608 {
609 PCSRSS_CONSOLE Console;
610 PGUI_CONSOLE_DATA GuiData;
611 POINTS pt;
612 RECT rc;
613
614 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
615 if (Console == NULL || GuiData == NULL) return;
616
617 pt = MAKEPOINTS(lParam);
618
619 rc.left = pt.x / GuiData->CharWidth;
620 rc.top = pt.y / GuiData->CharHeight;
621 rc.right = rc.left + 1;
622 rc.bottom = rc.top + 1;
623
624 GuiData->SelectionStart.x = rc.left;
625 GuiData->SelectionStart.y = rc.top;
626
627 SetCapture(hWnd);
628
629 GuiData->MouseDown = TRUE;
630
631 GuiConsoleUpdateSelection(hWnd, &rc, GuiData);
632 }
633
634 static VOID FASTCALL
635 GuiConsoleLeftMouseUp(HWND hWnd, LPARAM lParam)
636 {
637 PCSRSS_CONSOLE Console;
638 PGUI_CONSOLE_DATA GuiData;
639 RECT rc;
640 POINTS pt;
641
642 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
643 if (Console == NULL || GuiData == NULL) return;
644 if (GuiData->Selection.left == -1 || !GuiData->MouseDown) return;
645
646 pt = MAKEPOINTS(lParam);
647
648 rc.left = GuiData->SelectionStart.x;
649 rc.top = GuiData->SelectionStart.y;
650 rc.right = (pt.x >= 0 ? (pt.x / GuiData->CharWidth) + 1 : 0);
651 rc.bottom = (pt.y >= 0 ? (pt.y / GuiData->CharHeight) + 1 : 0);
652
653 /* exchange left/top with right/bottom if required */
654 if(rc.left >= rc.right)
655 {
656 LONG tmp;
657 tmp = rc.left;
658 rc.left = max(rc.right - 1, 0);
659 rc.right = tmp + 1;
660 }
661 if(rc.top >= rc.bottom)
662 {
663 LONG tmp;
664 tmp = rc.top;
665 rc.top = max(rc.bottom - 1, 0);
666 rc.bottom = tmp + 1;
667 }
668
669 GuiData->MouseDown = FALSE;
670
671 GuiConsoleUpdateSelection(hWnd, &rc, GuiData);
672
673 ReleaseCapture();
674 }
675
676 static VOID FASTCALL
677 GuiConsoleMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam)
678 {
679 PCSRSS_CONSOLE Console;
680 PGUI_CONSOLE_DATA GuiData;
681 RECT rc;
682 POINTS pt;
683
684 if (!(wParam & MK_LBUTTON)) return;
685
686 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
687 if (Console == NULL || GuiData == NULL || !GuiData->MouseDown) return;
688
689 pt = MAKEPOINTS(lParam);
690
691 rc.left = GuiData->SelectionStart.x;
692 rc.top = GuiData->SelectionStart.y;
693 rc.right = (pt.x >= 0 ? (pt.x / GuiData->CharWidth) + 1 : 0);
694 rc.bottom = (pt.y >= 0 ? (pt.y / GuiData->CharHeight) + 1 : 0);
695
696 /* exchange left/top with right/bottom if required */
697 if(rc.left >= rc.right)
698 {
699 LONG tmp;
700 tmp = rc.left;
701 rc.left = max(rc.right - 1, 0);
702 rc.right = tmp + 1;
703 }
704 if(rc.top >= rc.bottom)
705 {
706 LONG tmp;
707 tmp = rc.top;
708 rc.top = max(rc.bottom - 1, 0);
709 rc.bottom = tmp + 1;
710 }
711
712 GuiConsoleUpdateSelection(hWnd, &rc, GuiData);
713 }
714
715 static VOID FASTCALL
716 GuiConsoleRightMouseDown(HWND hWnd)
717 {
718 PCSRSS_CONSOLE Console;
719 PGUI_CONSOLE_DATA GuiData;
720
721 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
722 if (Console == NULL || GuiData == NULL) return;
723
724 if (GuiData->Selection.left == -1)
725 {
726 /* FIXME - paste text from clipboard */
727 }
728 else
729 {
730 /* FIXME - copy selection to clipboard */
731
732 GuiConsoleUpdateSelection(hWnd, NULL, GuiData);
733 }
734
735 }
736
737 static LRESULT CALLBACK
738 GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
739 {
740 LRESULT Result = 0;
741
742 switch(msg)
743 {
744 case WM_NCCREATE:
745 Result = (LRESULT) GuiConsoleHandleNcCreate(hWnd, (CREATESTRUCTW *) lParam);
746 break;
747 case WM_PAINT:
748 GuiConsoleHandlePaint(hWnd);
749 break;
750 case WM_KEYDOWN:
751 case WM_KEYUP:
752 case WM_SYSKEYDOWN:
753 case WM_SYSKEYUP:
754 case WM_CHAR:
755 GuiConsoleHandleKey(hWnd, msg, wParam, lParam);
756 break;
757 case WM_TIMER:
758 GuiConsoleHandleTimer(hWnd);
759 break;
760 case WM_CLOSE:
761 GuiConsoleHandleClose(hWnd);
762 break;
763 case WM_NCDESTROY:
764 GuiConsoleHandleNcDestroy(hWnd);
765 break;
766 case WM_LBUTTONDOWN:
767 GuiConsoleLeftMouseDown(hWnd, lParam);
768 break;
769 case WM_LBUTTONUP:
770 GuiConsoleLeftMouseUp(hWnd, lParam);
771 break;
772 case WM_RBUTTONDOWN:
773 GuiConsoleRightMouseDown(hWnd);
774 break;
775 case WM_MOUSEMOVE:
776 GuiConsoleMouseMove(hWnd, wParam, lParam);
777 break;
778 default:
779 Result = DefWindowProcW(hWnd, msg, wParam, lParam);
780 break;
781 }
782
783 return Result;
784 }
785
786 static LRESULT CALLBACK
787 GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
788 {
789 HWND NewWindow;
790 LONG WindowCount;
791 MSG Msg;
792 PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) lParam;
793
794 switch(msg)
795 {
796 case WM_CREATE:
797 SetWindowLongW(hWnd, GWL_USERDATA, 0);
798 return 0;
799 case PM_CREATE_CONSOLE:
800 NewWindow = CreateWindowW(L"ConsoleWindowClass",
801 Console->Title.Buffer,
802 WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
803 CW_USEDEFAULT,
804 CW_USEDEFAULT,
805 CW_USEDEFAULT,
806 CW_USEDEFAULT,
807 NULL,
808 NULL,
809 (HINSTANCE) GetModuleHandleW(NULL),
810 (PVOID) Console);
811 Console->hWindow = NewWindow;
812 if (NULL != NewWindow)
813 {
814 SetWindowLongW(hWnd, GWL_USERDATA, GetWindowLongW(hWnd, GWL_USERDATA) + 1);
815 ShowWindow(NewWindow, SW_SHOW);
816 }
817 return (LRESULT) NewWindow;
818 case PM_DESTROY_CONSOLE:
819 /* Window creation is done using a PostMessage(), so it's possible that the
820 * window that we want to destroy doesn't exist yet. So first empty the message
821 * queue */
822 while(PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
823 {
824 TranslateMessage(&Msg);
825 DispatchMessageW(&Msg);
826 }
827 DestroyWindow(Console->hWindow);
828 Console->hWindow = NULL;
829 WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
830 WindowCount--;
831 SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
832 if (0 == WindowCount)
833 {
834 NotifyWnd = NULL;
835 DestroyWindow(hWnd);
836 PrivateCsrssManualGuiCheck(-1);
837 PostQuitMessage(0);
838 }
839 return 0;
840 default:
841 return DefWindowProcW(hWnd, msg, wParam, lParam);
842 }
843 }
844
845 static DWORD STDCALL
846 GuiConsoleGuiThread(PVOID Data)
847 {
848 MSG msg;
849 PHANDLE GraphicsStartupEvent = (PHANDLE) Data;
850
851 NotifyWnd = CreateWindowW(L"Win32CsrCreateNotify",
852 L"",
853 WS_OVERLAPPEDWINDOW,
854 CW_USEDEFAULT,
855 CW_USEDEFAULT,
856 CW_USEDEFAULT,
857 CW_USEDEFAULT,
858 NULL,
859 NULL,
860 (HINSTANCE) GetModuleHandleW(NULL),
861 NULL);
862 if (NULL == NotifyWnd)
863 {
864 PrivateCsrssManualGuiCheck(-1);
865 SetEvent(*GraphicsStartupEvent);
866 return 1;
867 }
868
869 SetEvent(*GraphicsStartupEvent);
870
871 while(GetMessageW(&msg, NULL, 0, 0))
872 {
873 TranslateMessage(&msg);
874 DispatchMessageW(&msg);
875 }
876
877 return 1;
878 }
879
880 static BOOL FASTCALL
881 GuiInit(VOID)
882 {
883 WNDCLASSEXW wc;
884
885 if (NULL == NotifyWnd)
886 {
887 PrivateCsrssManualGuiCheck(+1);
888 }
889
890 wc.cbSize = sizeof(WNDCLASSEXW);
891 wc.lpszClassName = L"Win32CsrCreateNotify";
892 wc.lpfnWndProc = GuiConsoleNotifyWndProc;
893 wc.style = 0;
894 wc.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
895 wc.hIcon = NULL;
896 wc.hCursor = NULL;
897 wc.hbrBackground = NULL;
898 wc.lpszMenuName = NULL;
899 wc.cbClsExtra = 0;
900 wc.cbWndExtra = 0;
901 wc.hIconSm = NULL;
902 if (RegisterClassExW(&wc) == 0)
903 {
904 DPRINT1("Failed to register notify wndproc\n");
905 return FALSE;
906 }
907
908 wc.cbSize = sizeof(WNDCLASSEXW);
909 wc.lpszClassName = L"ConsoleWindowClass";
910 wc.lpfnWndProc = GuiConsoleWndProc;
911 wc.style = 0;
912 wc.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
913 wc.hIcon = LoadIconW(Win32CsrDllHandle, MAKEINTRESOURCEW(1));
914 wc.hCursor = LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_ARROW));
915 wc.hbrBackground = NULL;
916 wc.lpszMenuName = NULL;
917 wc.cbClsExtra = 0;
918 wc.cbWndExtra = 0;
919 wc.hIconSm = LoadImageW(Win32CsrDllHandle, MAKEINTRESOURCEW(1), IMAGE_ICON,
920 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
921 LR_SHARED);
922 if (RegisterClassExW(&wc) == 0)
923 {
924 DPRINT1("Failed to register console wndproc\n");
925 return FALSE;
926 }
927
928 return TRUE;
929 }
930
931 static VOID STDCALL
932 GuiInitScreenBuffer(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buffer)
933 {
934 Buffer->DefaultAttrib = 0x0f;
935 }
936
937 STATIC BOOL STDCALL
938 GuiChangeTitle(PCSRSS_CONSOLE Console)
939 {
940 SendMessageW(Console->hWindow, WM_SETTEXT, 0, (LPARAM) Console->Title.Buffer);
941
942 return TRUE;
943 }
944
945 STATIC BOOL STDCALL
946 GuiChangeIcon(PCSRSS_CONSOLE Console)
947 {
948 SendMessageW(Console->hWindow, WM_SETICON, ICON_BIG, (LPARAM)Console->hWindowIcon);
949 SendMessageW(Console->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)Console->hWindowIcon);
950
951 return TRUE;
952 }
953
954 static VOID STDCALL
955 GuiCleanupConsole(PCSRSS_CONSOLE Console)
956 {
957 SendMessageW(NotifyWnd, PM_DESTROY_CONSOLE, 0, (LPARAM) Console);
958 }
959
960 static CSRSS_CONSOLE_VTBL GuiVtbl =
961 {
962 GuiInitScreenBuffer,
963 GuiWriteStream,
964 GuiDrawRegion,
965 GuiSetCursorInfo,
966 GuiSetScreenInfo,
967 GuiChangeTitle,
968 GuiCleanupConsole,
969 GuiChangeIcon
970 };
971
972 NTSTATUS FASTCALL
973 GuiInitConsole(PCSRSS_CONSOLE Console)
974 {
975 HANDLE GraphicsStartupEvent;
976 HANDLE ThreadHandle;
977
978 if (! Initialized)
979 {
980 Initialized = TRUE;
981 if (! GuiInit())
982 {
983 Initialized = FALSE;
984 return STATUS_UNSUCCESSFUL;
985 }
986 }
987
988 Console->Vtbl = &GuiVtbl;
989 Console->Size.X = 80;
990 Console->Size.Y = 25;
991 if (NULL == NotifyWnd)
992 {
993 GraphicsStartupEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
994 if (NULL == GraphicsStartupEvent)
995 {
996 return STATUS_UNSUCCESSFUL;
997 }
998
999 ThreadHandle = CreateThread(NULL,
1000 0,
1001 GuiConsoleGuiThread,
1002 (PVOID) &GraphicsStartupEvent,
1003 0,
1004 NULL);
1005 if (NULL == ThreadHandle)
1006 {
1007 NtClose(GraphicsStartupEvent);
1008 DPRINT1("Win32Csr: Failed to create graphics console thread. Expect problems\n");
1009 return STATUS_UNSUCCESSFUL;
1010 }
1011 SetThreadPriority(ThreadHandle, THREAD_PRIORITY_HIGHEST);
1012 CloseHandle(ThreadHandle);
1013
1014 WaitForSingleObject(GraphicsStartupEvent, INFINITE);
1015 CloseHandle(GraphicsStartupEvent);
1016
1017 if (NULL == NotifyWnd)
1018 {
1019 DPRINT1("Win32Csr: Failed to create notification window.\n");
1020 return STATUS_UNSUCCESSFUL;
1021 }
1022 }
1023
1024 PostMessageW(NotifyWnd, PM_CREATE_CONSOLE, 0, (LPARAM) Console);
1025
1026 return STATUS_SUCCESS;
1027 }
1028
1029 VOID STDCALL
1030 GuiConsoleCopyRegion(HWND hWnd,
1031 RECT *Source,
1032 RECT *Dest)
1033 {
1034 RECT ScrollRect;
1035 PGUI_CONSOLE_DATA GuiData;
1036 PCSRSS_CONSOLE Console;
1037
1038
1039 GuiConsoleGetDataPointers(hWnd, &Console, &GuiData);
1040
1041 ScrollRect.left = Dest->left * GuiData->CharWidth;
1042 ScrollRect.right = (Dest->right + 1) * GuiData->CharWidth;
1043 ScrollRect.top = Dest->top * GuiData->CharHeight;
1044 ScrollRect.bottom = (Dest->bottom + 1) * GuiData->CharHeight;
1045 EnterCriticalSection(&GuiData->Lock);
1046 BitBlt(GuiData->MemoryDC, ScrollRect.left, ScrollRect.top,
1047 ScrollRect.right - ScrollRect.left, ScrollRect.bottom - ScrollRect.top,
1048 GuiData->MemoryDC, Source->left * GuiData->CharWidth, Source->top * GuiData->CharHeight, SRCCOPY);
1049
1050 LeaveCriticalSection(&GuiData->Lock);
1051
1052 InvalidateRect(hWnd, &ScrollRect, FALSE);
1053 }
1054
1055 /* EOF */