[CSRSRV]
[reactos.git] / win32ss / user / consrv / frontends / gui / guiterm.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/consrv/frontends/gui/guiterm.c
5 * PURPOSE: GUI Terminal Front-End
6 * PROGRAMMERS:
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "consrv.h"
12 #include "conio.h"
13 #include "console.h"
14 #include "settings.h"
15 #include "guiterm.h"
16 #include "guisettings.h"
17 #include "resource.h"
18
19 #include <windowsx.h>
20
21 #define NDEBUG
22 #include <debug.h>
23
24 /*
25 // Define wmemset(...)
26 #include <wchar.h>
27 #define HAVE_WMEMSET
28 */
29
30 /* GUI Console Window Class name */
31 #define GUI_CONSOLE_WINDOW_CLASS L"ConsoleWindowClass"
32
33 #ifndef WM_APP
34 #define WM_APP 0x8000
35 #endif
36 #define PM_CREATE_CONSOLE (WM_APP + 1)
37 #define PM_DESTROY_CONSOLE (WM_APP + 2)
38 #define PM_CONSOLE_BEEP (WM_APP + 3)
39 #define PM_CONSOLE_SET_TITLE (WM_APP + 4)
40
41
42 /* Not defined in any header file */
43 // extern VOID WINAPI PrivateCsrssManualGuiCheck(LONG Check);
44 // From win32ss/user/win32csr/dllmain.c
45 VOID
46 WINAPI
47 PrivateCsrssManualGuiCheck(LONG Check)
48 {
49 NtUserCallOneParam(Check, ONEPARAM_ROUTINE_CSRSS_GUICHECK);
50 }
51
52 /* GLOBALS ********************************************************************/
53
54 /**************************************************************\
55 \** Define the Console Leader Process for the console window **/
56 #define GWLP_CONSOLEWND_ALLOC (2 * sizeof(LONG_PTR))
57 #define GWLP_CONSOLE_LEADER_PID 0
58 #define GWLP_CONSOLE_LEADER_TID 4
59
60 #define SetConsoleWndConsoleLeaderCID(GuiData) \
61 do { \
62 PCONSOLE_PROCESS_DATA ProcessData; \
63 CLIENT_ID ConsoleLeaderCID; \
64 ProcessData = CONTAINING_RECORD((GuiData)->Console->ProcessList.Blink, \
65 CONSOLE_PROCESS_DATA, \
66 ConsoleLink); \
67 ConsoleLeaderCID = ProcessData->Process->ClientId; \
68 SetWindowLongPtrW((GuiData)->hWindow, GWLP_CONSOLE_LEADER_PID, (LONG_PTR)(ConsoleLeaderCID.UniqueProcess)); \
69 SetWindowLongPtrW((GuiData)->hWindow, GWLP_CONSOLE_LEADER_TID, (LONG_PTR)(ConsoleLeaderCID.UniqueThread )); \
70 } while(0)
71 /**************************************************************/
72
73 static BOOL ConsInitialized = FALSE;
74 static HICON ghDefaultIcon = NULL;
75 static HICON ghDefaultIconSm = NULL;
76 static HCURSOR ghDefaultCursor = NULL;
77 static HWND NotifyWnd = NULL;
78
79 typedef struct _GUICONSOLE_MENUITEM
80 {
81 UINT uID;
82 const struct _GUICONSOLE_MENUITEM *SubMenu;
83 WORD wCmdID;
84 } GUICONSOLE_MENUITEM, *PGUICONSOLE_MENUITEM;
85
86 static const GUICONSOLE_MENUITEM GuiConsoleEditMenuItems[] =
87 {
88 { IDS_MARK, NULL, ID_SYSTEM_EDIT_MARK },
89 { IDS_COPY, NULL, ID_SYSTEM_EDIT_COPY },
90 { IDS_PASTE, NULL, ID_SYSTEM_EDIT_PASTE },
91 { IDS_SELECTALL, NULL, ID_SYSTEM_EDIT_SELECTALL },
92 { IDS_SCROLL, NULL, ID_SYSTEM_EDIT_SCROLL },
93 { IDS_FIND, NULL, ID_SYSTEM_EDIT_FIND },
94
95 { 0, NULL, 0 } /* End of list */
96 };
97
98 static const GUICONSOLE_MENUITEM GuiConsoleMainMenuItems[] =
99 {
100 { IDS_EDIT, GuiConsoleEditMenuItems, 0 },
101 { IDS_DEFAULTS, NULL, ID_SYSTEM_DEFAULTS },
102 { IDS_PROPERTIES, NULL, ID_SYSTEM_PROPERTIES },
103
104 { 0, NULL, 0 } /* End of list */
105 };
106
107 /*
108 * Default 16-color palette for foreground and background
109 * (corresponding flags in comments).
110 */
111 const COLORREF s_Colors[16] =
112 {
113 RGB(0, 0, 0), // (Black)
114 RGB(0, 0, 128), // BLUE
115 RGB(0, 128, 0), // GREEN
116 RGB(0, 128, 128), // BLUE | GREEN
117 RGB(128, 0, 0), // RED
118 RGB(128, 0, 128), // BLUE | RED
119 RGB(128, 128, 0), // GREEN | RED
120 RGB(192, 192, 192), // BLUE | GREEN | RED
121
122 RGB(128, 128, 128), // (Grey) INTENSITY
123 RGB(0, 0, 255), // BLUE | INTENSITY
124 RGB(0, 255, 0), // GREEN | INTENSITY
125 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
126 RGB(255, 0, 0), // RED | INTENSITY
127 RGB(255, 0, 255), // BLUE | RED | INTENSITY
128 RGB(255, 255, 0), // GREEN | RED | INTENSITY
129 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
130 };
131
132 /* FUNCTIONS ******************************************************************/
133
134 static VOID
135 GuiConsoleAppendMenuItems(HMENU hMenu,
136 const GUICONSOLE_MENUITEM *Items)
137 {
138 UINT i = 0;
139 WCHAR szMenuString[255];
140 HMENU hSubMenu;
141
142 do
143 {
144 if (Items[i].uID != (UINT)-1)
145 {
146 if (LoadStringW(ConSrvDllInstance,
147 Items[i].uID,
148 szMenuString,
149 sizeof(szMenuString) / sizeof(szMenuString[0])) > 0)
150 {
151 if (Items[i].SubMenu != NULL)
152 {
153 hSubMenu = CreatePopupMenu();
154 if (hSubMenu != NULL)
155 {
156 GuiConsoleAppendMenuItems(hSubMenu,
157 Items[i].SubMenu);
158
159 if (!AppendMenuW(hMenu,
160 MF_STRING | MF_POPUP,
161 (UINT_PTR)hSubMenu,
162 szMenuString))
163 {
164 DestroyMenu(hSubMenu);
165 }
166 }
167 }
168 else
169 {
170 AppendMenuW(hMenu,
171 MF_STRING,
172 Items[i].wCmdID,
173 szMenuString);
174 }
175 }
176 }
177 else
178 {
179 AppendMenuW(hMenu,
180 MF_SEPARATOR,
181 0,
182 NULL);
183 }
184 i++;
185 } while(!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].wCmdID == 0));
186 }
187
188 static VOID
189 GuiConsoleCreateSysMenu(HWND hWnd)
190 {
191 HMENU hMenu;
192 hMenu = GetSystemMenu(hWnd, FALSE);
193 if (hMenu != NULL)
194 {
195 GuiConsoleAppendMenuItems(hMenu, GuiConsoleMainMenuItems);
196 DrawMenuBar(hWnd);
197 }
198 }
199
200
201 static VOID
202 GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData);
203 static VOID
204 GuiConsolePaste(PGUI_CONSOLE_DATA GuiData);
205 static VOID
206 GuiConsoleUpdateSelection(PCONSOLE Console, PCOORD coord);
207 static VOID WINAPI
208 GuiDrawRegion(PCONSOLE Console, SMALL_RECT* Region);
209 static NTSTATUS WINAPI
210 GuiResizeBuffer(PCONSOLE Console, PCONSOLE_SCREEN_BUFFER ScreenBuffer, COORD Size);
211 static VOID
212 GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData);
213
214
215 static LRESULT
216 GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
217 {
218 LRESULT Ret = TRUE;
219 PCONSOLE Console = GuiData->Console;
220
221 if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
222 {
223 Ret = FALSE;
224 goto Quit;
225 }
226
227 switch (wParam)
228 {
229 case ID_SYSTEM_EDIT_MARK:
230 {
231 LPWSTR WindowTitle = NULL;
232 SIZE_T Length = 0;
233
234 Console->dwSelectionCursor = (COORD){0, 0};
235 Console->Selection.dwSelectionAnchor = Console->dwSelectionCursor;
236 Console->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS;
237 GuiConsoleUpdateSelection(Console, &Console->Selection.dwSelectionAnchor);
238
239 Length = Console->Title.Length + sizeof(L"Mark - ")/sizeof(WCHAR) + 1;
240 WindowTitle = RtlAllocateHeap(ConSrvHeap, 0, Length * sizeof(WCHAR));
241 wcscpy(WindowTitle, L"Mark - ");
242 wcscat(WindowTitle, Console->Title.Buffer);
243 SetWindowText(GuiData->hWindow, WindowTitle);
244 RtlFreeHeap(ConSrvHeap, 0, WindowTitle);
245
246 break;
247 }
248
249 case ID_SYSTEM_EDIT_COPY:
250 GuiConsoleCopy(GuiData);
251 break;
252
253 case ID_SYSTEM_EDIT_PASTE:
254 GuiConsolePaste(GuiData);
255 break;
256
257 case ID_SYSTEM_EDIT_SELECTALL:
258 {
259 Console->Selection.dwSelectionAnchor = (COORD){0, 0};
260 Console->dwSelectionCursor.X = Console->ConsoleSize.X - 1;
261 Console->dwSelectionCursor.Y = Console->ConsoleSize.Y - 1;
262 GuiConsoleUpdateSelection(Console, &Console->dwSelectionCursor);
263 break;
264 }
265
266 case ID_SYSTEM_EDIT_SCROLL:
267 DPRINT1("Scrolling is not handled yet\n");
268 break;
269
270 case ID_SYSTEM_EDIT_FIND:
271 DPRINT1("Finding is not handled yet\n");
272 break;
273
274 case ID_SYSTEM_DEFAULTS:
275 GuiConsoleShowConsoleProperties(GuiData, TRUE);
276 break;
277
278 case ID_SYSTEM_PROPERTIES:
279 GuiConsoleShowConsoleProperties(GuiData, FALSE);
280 break;
281
282 default:
283 Ret = FALSE;
284 break;
285 }
286
287 LeaveCriticalSection(&Console->Lock);
288
289 Quit:
290 if (!Ret)
291 Ret = DefWindowProcW(GuiData->hWindow, WM_SYSCOMMAND, wParam, lParam);
292
293 return Ret;
294 }
295
296 static PGUI_CONSOLE_DATA
297 GuiGetGuiData(HWND hWnd)
298 {
299 /* This function ensures that the console pointer is not NULL */
300 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
301 return ( ((GuiData == NULL) || (GuiData->hWindow == hWnd && GuiData->Console != NULL)) ? GuiData : NULL );
302 }
303
304 VOID
305 GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData)
306 {
307 /* Move the window if needed (not positioned by the system) */
308 if (!GuiData->GuiInfo.AutoPosition)
309 {
310 SetWindowPos(GuiData->hWindow,
311 NULL,
312 GuiData->GuiInfo.WindowOrigin.x,
313 GuiData->GuiInfo.WindowOrigin.y,
314 0,
315 0,
316 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
317 }
318 }
319
320 static VOID
321 GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData)
322 {
323 PCONSOLE Console = GuiData->Console;
324 SCROLLINFO sInfo;
325
326 DWORD Width = Console->ConsoleSize.X * GuiData->CharWidth +
327 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
328 DWORD Height = Console->ConsoleSize.Y * GuiData->CharHeight +
329 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
330
331 /* Set scrollbar sizes */
332 sInfo.cbSize = sizeof(SCROLLINFO);
333 sInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
334 sInfo.nMin = 0;
335 if (Console->ActiveBuffer->ScreenBufferSize.Y > Console->ConsoleSize.Y)
336 {
337 sInfo.nMax = Console->ActiveBuffer->ScreenBufferSize.Y - 1;
338 sInfo.nPage = Console->ConsoleSize.Y;
339 sInfo.nPos = Console->ActiveBuffer->ShowY;
340 SetScrollInfo(GuiData->hWindow, SB_VERT, &sInfo, TRUE);
341 Width += GetSystemMetrics(SM_CXVSCROLL);
342 ShowScrollBar(GuiData->hWindow, SB_VERT, TRUE);
343 }
344 else
345 {
346 ShowScrollBar(GuiData->hWindow, SB_VERT, FALSE);
347 }
348
349 if (Console->ActiveBuffer->ScreenBufferSize.X > Console->ConsoleSize.X)
350 {
351 sInfo.nMax = Console->ActiveBuffer->ScreenBufferSize.X - 1;
352 sInfo.nPage = Console->ConsoleSize.X;
353 sInfo.nPos = Console->ActiveBuffer->ShowX;
354 SetScrollInfo(GuiData->hWindow, SB_HORZ, &sInfo, TRUE);
355 Height += GetSystemMetrics(SM_CYHSCROLL);
356 ShowScrollBar(GuiData->hWindow, SB_HORZ, TRUE);
357 }
358 else
359 {
360 ShowScrollBar(GuiData->hWindow, SB_HORZ, FALSE);
361 }
362
363 /* Resize the window */
364 SetWindowPos(GuiData->hWindow, NULL, 0, 0, Width, Height,
365 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
366 }
367
368 static BOOL
369 GuiConsoleHandleNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
370 {
371 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)Create->lpCreateParams;
372 PCONSOLE Console;
373 HDC Dc;
374 HFONT OldFont;
375 TEXTMETRICW Metrics;
376 SIZE CharSize;
377
378 DPRINT1("GuiConsoleHandleNcCreate\n");
379
380 if (NULL == GuiData)
381 {
382 DPRINT1("GuiConsoleNcCreate: No GUI data\n");
383 return FALSE;
384 }
385
386 Console = GuiData->Console;
387
388 GuiData->hWindow = hWnd;
389
390 GuiData->Font = CreateFontW(LOWORD(GuiData->GuiInfo.FontSize),
391 0, // HIWORD(GuiData->GuiInfo.FontSize),
392 0,
393 TA_BASELINE,
394 GuiData->GuiInfo.FontWeight,
395 FALSE,
396 FALSE,
397 FALSE,
398 OEM_CHARSET,
399 OUT_DEFAULT_PRECIS,
400 CLIP_DEFAULT_PRECIS,
401 NONANTIALIASED_QUALITY,
402 FIXED_PITCH | GuiData->GuiInfo.FontFamily /* FF_DONTCARE */,
403 GuiData->GuiInfo.FaceName);
404
405 if (NULL == GuiData->Font)
406 {
407 DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
408 GuiData->hWindow = NULL;
409 SetEvent(GuiData->hGuiInitEvent);
410 return FALSE;
411 }
412 Dc = GetDC(GuiData->hWindow);
413 if (NULL == Dc)
414 {
415 DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
416 DeleteObject(GuiData->Font);
417 GuiData->hWindow = NULL;
418 SetEvent(GuiData->hGuiInitEvent);
419 return FALSE;
420 }
421 OldFont = SelectObject(Dc, GuiData->Font);
422 if (NULL == OldFont)
423 {
424 DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
425 ReleaseDC(GuiData->hWindow, Dc);
426 DeleteObject(GuiData->Font);
427 GuiData->hWindow = NULL;
428 SetEvent(GuiData->hGuiInitEvent);
429 return FALSE;
430 }
431 if (!GetTextMetricsW(Dc, &Metrics))
432 {
433 DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
434 SelectObject(Dc, OldFont);
435 ReleaseDC(GuiData->hWindow, Dc);
436 DeleteObject(GuiData->Font);
437 GuiData->hWindow = NULL;
438 SetEvent(GuiData->hGuiInitEvent);
439 return FALSE;
440 }
441 GuiData->CharWidth = Metrics.tmMaxCharWidth;
442 GuiData->CharHeight = Metrics.tmHeight + Metrics.tmExternalLeading;
443
444 /* Measure real char width more precisely if possible. */
445 if (GetTextExtentPoint32W(Dc, L"R", 1, &CharSize))
446 GuiData->CharWidth = CharSize.cx;
447
448 SelectObject(Dc, OldFont);
449
450 ReleaseDC(GuiData->hWindow, Dc);
451
452 // FIXME: Keep these instructions here ? ///////////////////////////////////
453 Console->ActiveBuffer->CursorBlinkOn = TRUE;
454 Console->ActiveBuffer->ForceCursorOff = FALSE;
455 ////////////////////////////////////////////////////////////////////////////
456
457 SetWindowLongPtrW(GuiData->hWindow, GWLP_USERDATA, (DWORD_PTR)GuiData);
458
459 SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
460 GuiConsoleCreateSysMenu(GuiData->hWindow);
461
462 DPRINT1("GuiConsoleHandleNcCreate - setting start event\n");
463 SetEvent(GuiData->hGuiInitEvent);
464
465 return (BOOL)DefWindowProcW(GuiData->hWindow, WM_NCCREATE, 0, (LPARAM)Create);
466 }
467
468 static VOID
469 SmallRectToRect(PGUI_CONSOLE_DATA GuiData, PRECT Rect, PSMALL_RECT SmallRect)
470 {
471 PCONSOLE Console = GuiData->Console;
472 PCONSOLE_SCREEN_BUFFER Buffer = Console->ActiveBuffer;
473
474 Rect->left = (SmallRect->Left - Buffer->ShowX) * GuiData->CharWidth;
475 Rect->top = (SmallRect->Top - Buffer->ShowY) * GuiData->CharHeight;
476 Rect->right = (SmallRect->Right + 1 - Buffer->ShowX) * GuiData->CharWidth;
477 Rect->bottom = (SmallRect->Bottom + 1 - Buffer->ShowY) * GuiData->CharHeight;
478 }
479
480 static VOID
481 GuiConsoleUpdateSelection(PCONSOLE Console, PCOORD coord)
482 {
483 PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data;
484 RECT oldRect, newRect;
485
486 SmallRectToRect(GuiData, &oldRect, &Console->Selection.srSelection);
487
488 if (coord != NULL)
489 {
490 SMALL_RECT rc;
491 /* exchange left/top with right/bottom if required */
492 rc.Left = min(Console->Selection.dwSelectionAnchor.X, coord->X);
493 rc.Top = min(Console->Selection.dwSelectionAnchor.Y, coord->Y);
494 rc.Right = max(Console->Selection.dwSelectionAnchor.X, coord->X);
495 rc.Bottom = max(Console->Selection.dwSelectionAnchor.Y, coord->Y);
496
497 SmallRectToRect(GuiData, &newRect, &rc);
498
499 if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
500 {
501 if (memcmp(&rc, &Console->Selection.srSelection, sizeof(SMALL_RECT)) != 0)
502 {
503 HRGN rgn1, rgn2;
504
505 /* calculate the region that needs to be updated */
506 if ((rgn1 = CreateRectRgnIndirect(&oldRect)))
507 {
508 if ((rgn2 = CreateRectRgnIndirect(&newRect)))
509 {
510 if(CombineRgn(rgn1, rgn2, rgn1, RGN_XOR) != ERROR)
511 {
512 InvalidateRgn(GuiData->hWindow, rgn1, FALSE);
513 }
514 DeleteObject(rgn2);
515 }
516 DeleteObject(rgn1);
517 }
518 }
519 }
520 else
521 {
522 InvalidateRect(GuiData->hWindow, &newRect, FALSE);
523 }
524 Console->Selection.dwFlags |= CONSOLE_SELECTION_NOT_EMPTY;
525 Console->Selection.srSelection = rc;
526 Console->dwSelectionCursor = *coord;
527 ConioPause(Console, PAUSED_FROM_SELECTION);
528 }
529 else
530 {
531 /* clear the selection */
532 if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
533 {
534 InvalidateRect(GuiData->hWindow, &oldRect, FALSE);
535 }
536 Console->Selection.dwFlags = CONSOLE_NO_SELECTION;
537 ConioUnpause(Console, PAUSED_FROM_SELECTION);
538 }
539 }
540
541 static VOID
542 GuiConsolePaint(PCONSOLE Console,
543 PGUI_CONSOLE_DATA GuiData,
544 HDC hDC,
545 PRECT rc)
546 {
547 PCONSOLE_SCREEN_BUFFER Buff;
548 ULONG TopLine, BottomLine, LeftChar, RightChar;
549 ULONG Line, Char, Start;
550 PBYTE From;
551 PWCHAR To;
552 BYTE LastAttribute, Attribute;
553 ULONG CursorX, CursorY, CursorHeight;
554 HBRUSH CursorBrush, OldBrush;
555 HFONT OldFont;
556
557 Buff = Console->ActiveBuffer;
558
559 TopLine = rc->top / GuiData->CharHeight + Buff->ShowY;
560 BottomLine = (rc->bottom + (GuiData->CharHeight - 1)) / GuiData->CharHeight - 1 + Buff->ShowY;
561 LeftChar = rc->left / GuiData->CharWidth + Buff->ShowX;
562 RightChar = (rc->right + (GuiData->CharWidth - 1)) / GuiData->CharWidth - 1 + Buff->ShowX;
563 LastAttribute = ConioCoordToPointer(Buff, LeftChar, TopLine)[1];
564
565 SetTextColor(hDC, RGBFromAttrib(Console, TextAttribFromAttrib(LastAttribute)));
566 SetBkColor(hDC, RGBFromAttrib(Console, BkgdAttribFromAttrib(LastAttribute)));
567
568 if (BottomLine >= Buff->ScreenBufferSize.Y) BottomLine = Buff->ScreenBufferSize.Y - 1;
569 if (RightChar >= Buff->ScreenBufferSize.X) RightChar = Buff->ScreenBufferSize.X - 1;
570
571 OldFont = SelectObject(hDC, GuiData->Font);
572
573 for (Line = TopLine; Line <= BottomLine; Line++)
574 {
575 WCHAR LineBuffer[80];
576 From = ConioCoordToPointer(Buff, LeftChar, Line);
577 Start = LeftChar;
578 To = LineBuffer;
579
580 for (Char = LeftChar; Char <= RightChar; Char++)
581 {
582 if (*(From + 1) != LastAttribute || (Char - Start == sizeof(LineBuffer) / sizeof(WCHAR)))
583 {
584 TextOutW(hDC,
585 (Start - Buff->ShowX) * GuiData->CharWidth,
586 (Line - Buff->ShowY) * GuiData->CharHeight,
587 LineBuffer,
588 Char - Start);
589 Start = Char;
590 To = LineBuffer;
591 Attribute = *(From + 1);
592 if (Attribute != LastAttribute)
593 {
594 SetTextColor(hDC, RGBFromAttrib(Console, TextAttribFromAttrib(Attribute)));
595 SetBkColor(hDC, RGBFromAttrib(Console, BkgdAttribFromAttrib(Attribute)));
596 LastAttribute = Attribute;
597 }
598 }
599
600 MultiByteToWideChar(Console->OutputCodePage,
601 0,
602 (PCHAR)From,
603 1,
604 To,
605 1);
606 To++;
607 From += 2;
608 }
609
610 TextOutW(hDC,
611 (Start - Buff->ShowX) * GuiData->CharWidth,
612 (Line - Buff->ShowY) * GuiData->CharHeight,
613 LineBuffer,
614 RightChar - Start + 1);
615 }
616
617 if (Buff->CursorInfo.bVisible && Buff->CursorBlinkOn &&
618 !Buff->ForceCursorOff)
619 {
620 CursorX = Buff->CursorPosition.X;
621 CursorY = Buff->CursorPosition.Y;
622 if (LeftChar <= CursorX && CursorX <= RightChar &&
623 TopLine <= CursorY && CursorY <= BottomLine)
624 {
625 CursorHeight = ConioEffectiveCursorSize(Console, GuiData->CharHeight);
626 From = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y) + 1;
627
628 if (*From != DEFAULT_SCREEN_ATTRIB)
629 {
630 CursorBrush = CreateSolidBrush(RGBFromAttrib(Console, *From));
631 }
632 else
633 {
634 CursorBrush = CreateSolidBrush(RGBFromAttrib(Console, Buff->ScreenDefaultAttrib));
635 }
636
637 OldBrush = SelectObject(hDC, CursorBrush);
638 PatBlt(hDC,
639 (CursorX - Buff->ShowX) * GuiData->CharWidth,
640 (CursorY - Buff->ShowY) * GuiData->CharHeight + (GuiData->CharHeight - CursorHeight),
641 GuiData->CharWidth,
642 CursorHeight,
643 PATCOPY);
644 SelectObject(hDC, OldBrush);
645 DeleteObject(CursorBrush);
646 }
647 }
648
649 SelectObject(hDC, OldFont);
650 }
651
652 static VOID
653 GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData)
654 {
655 BOOL Success = TRUE;
656 PCONSOLE Console = GuiData->Console;
657 HDC hDC;
658 PAINTSTRUCT ps;
659
660 if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
661 {
662 Success = FALSE;
663 goto Quit;
664 }
665
666 if (Console->ActiveBuffer == NULL ||
667 Console->ActiveBuffer->Buffer == NULL)
668 {
669 goto Quit;
670 }
671
672 hDC = BeginPaint(GuiData->hWindow, &ps);
673 if (hDC != NULL &&
674 ps.rcPaint.left < ps.rcPaint.right &&
675 ps.rcPaint.top < ps.rcPaint.bottom)
676 {
677 EnterCriticalSection(&GuiData->Lock);
678
679 GuiConsolePaint(Console,
680 GuiData,
681 hDC,
682 &ps.rcPaint);
683
684 if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
685 {
686 RECT rc;
687 SmallRectToRect(GuiData, &rc, &Console->Selection.srSelection);
688
689 /* invert the selection */
690 if (IntersectRect(&rc,
691 &ps.rcPaint,
692 &rc))
693 {
694 PatBlt(hDC,
695 rc.left,
696 rc.top,
697 rc.right - rc.left,
698 rc.bottom - rc.top,
699 DSTINVERT);
700 }
701 }
702
703 LeaveCriticalSection(&GuiData->Lock);
704 }
705 EndPaint(GuiData->hWindow, &ps);
706
707 Quit:
708 if (Success)
709 LeaveCriticalSection(&Console->Lock);
710 else
711 DefWindowProcW(GuiData->hWindow, WM_PAINT, 0, 0);
712
713 return;
714 }
715
716 static VOID
717 GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
718 {
719 PCONSOLE Console = GuiData->Console;
720 MSG Message;
721
722 if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
723
724 if ( (Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) &&
725 ((Console->Selection.dwFlags & CONSOLE_MOUSE_SELECTION) == 0) &&
726 (Console->ActiveBuffer) )
727 {
728 BOOL Interpreted = FALSE;
729
730 /* Selection with keyboard */
731 if (msg == WM_KEYDOWN)
732 {
733 BOOL MajPressed = (GetKeyState(VK_SHIFT) & 0x8000);
734
735 switch (wParam)
736 {
737 case VK_LEFT:
738 {
739 Interpreted = TRUE;
740 if (Console->dwSelectionCursor.X > 0)
741 Console->dwSelectionCursor.X--;
742
743 break;
744 }
745
746 case VK_RIGHT:
747 {
748 Interpreted = TRUE;
749 if (Console->dwSelectionCursor.X < Console->ActiveBuffer->ScreenBufferSize.X - 1)
750 Console->dwSelectionCursor.X++;
751
752 break;
753 }
754
755 case VK_UP:
756 {
757 Interpreted = TRUE;
758 if (Console->dwSelectionCursor.Y > 0)
759 Console->dwSelectionCursor.Y--;
760
761 break;
762 }
763
764 case VK_DOWN:
765 {
766 Interpreted = TRUE;
767 if (Console->dwSelectionCursor.Y < Console->ActiveBuffer->ScreenBufferSize.Y - 1)
768 Console->dwSelectionCursor.Y++;
769
770 break;
771 }
772
773 case VK_HOME:
774 {
775 Interpreted = TRUE;
776 Console->dwSelectionCursor = (COORD){0, 0};
777 break;
778 }
779
780 case VK_END:
781 {
782 Interpreted = TRUE;
783 Console->dwSelectionCursor.Y = Console->ActiveBuffer->ScreenBufferSize.Y - 1;
784 break;
785 }
786
787 case VK_PRIOR:
788 {
789 Interpreted = TRUE;
790 Console->dwSelectionCursor.Y -= Console->ConsoleSize.Y;
791 if (Console->dwSelectionCursor.Y < 0)
792 Console->dwSelectionCursor.Y = 0;
793
794 break;
795 }
796
797 case VK_NEXT:
798 {
799 Interpreted = TRUE;
800 Console->dwSelectionCursor.Y += Console->ConsoleSize.Y;
801 if (Console->dwSelectionCursor.Y >= Console->ActiveBuffer->ScreenBufferSize.Y)
802 Console->dwSelectionCursor.Y = Console->ActiveBuffer->ScreenBufferSize.Y - 1;
803
804 break;
805 }
806
807 default:
808 break;
809 }
810
811 if (Interpreted)
812 {
813 if (!MajPressed)
814 Console->Selection.dwSelectionAnchor = Console->dwSelectionCursor;
815
816 GuiConsoleUpdateSelection(Console, &Console->dwSelectionCursor);
817 }
818 }
819 }
820 else
821 {
822 Message.hwnd = GuiData->hWindow;
823 Message.message = msg;
824 Message.wParam = wParam;
825 Message.lParam = lParam;
826
827 if (msg == WM_KEYDOWN)
828 {
829 /* If we are in selection mode (with mouse), clear the selection */
830 GuiConsoleUpdateSelection(Console, NULL);
831 SetWindowText(GuiData->hWindow, Console->Title.Buffer);
832 }
833
834 ConioProcessKey(Console, &Message);
835 }
836
837 LeaveCriticalSection(&Console->Lock);
838 }
839
840 static VOID
841 GuiInvalidateCell(PCONSOLE Console, UINT x, UINT y)
842 {
843 SMALL_RECT CellRect = { x, y, x, y };
844 GuiDrawRegion(Console, &CellRect);
845 }
846
847 static VOID
848 GuiConsoleHandleTimer(PGUI_CONSOLE_DATA GuiData)
849 {
850 PCONSOLE Console = GuiData->Console;
851 PCONSOLE_SCREEN_BUFFER Buff;
852
853 SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CURSOR_BLINK_TIME, NULL);
854
855 if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
856
857 Buff = Console->ActiveBuffer;
858 GuiInvalidateCell(Console, Buff->CursorPosition.X, Buff->CursorPosition.Y);
859 Buff->CursorBlinkOn = !Buff->CursorBlinkOn;
860
861 if((GuiData->OldCursor.x != Buff->CursorPosition.X) || (GuiData->OldCursor.y != Buff->CursorPosition.Y))
862 {
863 SCROLLINFO xScroll;
864 int OldScrollX = -1, OldScrollY = -1;
865 int NewScrollX = -1, NewScrollY = -1;
866
867 xScroll.cbSize = sizeof(SCROLLINFO);
868 xScroll.fMask = SIF_POS;
869 // Capture the original position of the scroll bars and save them.
870 if(GetScrollInfo(GuiData->hWindow, SB_HORZ, &xScroll))OldScrollX = xScroll.nPos;
871 if(GetScrollInfo(GuiData->hWindow, SB_VERT, &xScroll))OldScrollY = xScroll.nPos;
872
873 // If we successfully got the info for the horizontal scrollbar
874 if(OldScrollX >= 0)
875 {
876 if((Buff->CursorPosition.X < Buff->ShowX)||(Buff->CursorPosition.X >= (Buff->ShowX + Console->ConsoleSize.X)))
877 {
878 // Handle the horizontal scroll bar
879 if(Buff->CursorPosition.X >= Console->ConsoleSize.X) NewScrollX = Buff->CursorPosition.X - Console->ConsoleSize.X + 1;
880 else NewScrollX = 0;
881 }
882 else
883 {
884 NewScrollX = OldScrollX;
885 }
886 }
887 // If we successfully got the info for the vertical scrollbar
888 if(OldScrollY >= 0)
889 {
890 if((Buff->CursorPosition.Y < Buff->ShowY) || (Buff->CursorPosition.Y >= (Buff->ShowY + Console->ConsoleSize.Y)))
891 {
892 // Handle the vertical scroll bar
893 if(Buff->CursorPosition.Y >= Console->ConsoleSize.Y) NewScrollY = Buff->CursorPosition.Y - Console->ConsoleSize.Y + 1;
894 else NewScrollY = 0;
895 }
896 else
897 {
898 NewScrollY = OldScrollY;
899 }
900 }
901
902 // Adjust scroll bars and refresh the window if the cursor has moved outside the visible area
903 // NOTE: OldScroll# and NewScroll# will both be -1 (initial value) if the info for the respective scrollbar
904 // was not obtained successfully in the previous steps. This means their difference is 0 (no scrolling)
905 // and their associated scrollbar is left alone.
906 if((OldScrollX != NewScrollX) || (OldScrollY != NewScrollY))
907 {
908 Buff->ShowX = NewScrollX;
909 Buff->ShowY = NewScrollY;
910 ScrollWindowEx(GuiData->hWindow,
911 (OldScrollX - NewScrollX) * GuiData->CharWidth,
912 (OldScrollY - NewScrollY) * GuiData->CharHeight,
913 NULL,
914 NULL,
915 NULL,
916 NULL,
917 SW_INVALIDATE);
918 if(NewScrollX >= 0)
919 {
920 xScroll.nPos = NewScrollX;
921 SetScrollInfo(GuiData->hWindow, SB_HORZ, &xScroll, TRUE);
922 }
923 if(NewScrollY >= 0)
924 {
925 xScroll.nPos = NewScrollY;
926 SetScrollInfo(GuiData->hWindow, SB_VERT, &xScroll, TRUE);
927 }
928 UpdateWindow(GuiData->hWindow);
929 GuiData->OldCursor.x = Buff->CursorPosition.X;
930 GuiData->OldCursor.y = Buff->CursorPosition.Y;
931 }
932 }
933
934 LeaveCriticalSection(&Console->Lock);
935 }
936
937 static VOID
938 GuiConsoleHandleClose(PGUI_CONSOLE_DATA GuiData)
939 {
940 PCONSOLE Console = GuiData->Console;
941 if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
942
943 /*
944 * FIXME: Windows will wait up to 5 seconds for the thread to exit.
945 * We shouldn't wait here, though, since the console lock is entered.
946 * A copy of the thread list probably needs to be made.
947 */
948 ConSrvConsoleProcessCtrlEvent(Console, 0, CTRL_CLOSE_EVENT);
949
950 LeaveCriticalSection(&Console->Lock);
951 }
952
953 static LRESULT
954 GuiConsoleHandleNcDestroy(HWND hWnd)
955 {
956 // PGUI_CONSOLE_DATA GuiData;
957
958 KillTimer(hWnd, CONGUI_UPDATE_TIMER);
959 GetSystemMenu(hWnd, TRUE);
960
961 /* Free the GuiData registration */
962 SetWindowLongPtrW(hWnd, GWLP_USERDATA, (DWORD_PTR)NULL);
963 // GuiData->hWindow = NULL;
964
965 // return 0;
966 return DefWindowProcW(hWnd, WM_NCDESTROY, 0, 0);
967 }
968
969 static COORD
970 PointToCoord(PGUI_CONSOLE_DATA GuiData, LPARAM lParam)
971 {
972 PCONSOLE Console = GuiData->Console;
973 PCONSOLE_SCREEN_BUFFER Buffer = Console->ActiveBuffer;
974 COORD Coord;
975
976 Coord.X = Buffer->ShowX + ((short)LOWORD(lParam) / (int)GuiData->CharWidth);
977 Coord.Y = Buffer->ShowY + ((short)HIWORD(lParam) / (int)GuiData->CharHeight);
978
979 /* Clip coordinate to ensure it's inside buffer */
980 if (Coord.X < 0)
981 Coord.X = 0;
982 else if (Coord.X >= Buffer->ScreenBufferSize.X)
983 Coord.X = Buffer->ScreenBufferSize.X - 1;
984
985 if (Coord.Y < 0)
986 Coord.Y = 0;
987 else if (Coord.Y >= Buffer->ScreenBufferSize.Y)
988 Coord.Y = Buffer->ScreenBufferSize.Y - 1;
989
990 return Coord;
991 }
992
993 static LRESULT
994 GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
995 {
996 BOOL Err = FALSE;
997 PCONSOLE Console = GuiData->Console;
998
999 if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
1000 {
1001 Err = TRUE;
1002 goto Quit;
1003 }
1004
1005 if ( (Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) ||
1006 (Console->QuickEdit) )
1007 {
1008 switch (msg)
1009 {
1010 case WM_LBUTTONDOWN:
1011 {
1012 LPWSTR WindowTitle = NULL;
1013 SIZE_T Length = 0;
1014
1015 Console->Selection.dwSelectionAnchor = PointToCoord(GuiData, lParam);
1016 SetCapture(GuiData->hWindow);
1017 Console->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS | CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
1018 GuiConsoleUpdateSelection(Console, &Console->Selection.dwSelectionAnchor);
1019
1020 Length = Console->Title.Length + sizeof(L"Selection - ")/sizeof(WCHAR) + 1;
1021 WindowTitle = RtlAllocateHeap(ConSrvHeap, 0, Length * sizeof(WCHAR));
1022 wcscpy(WindowTitle, L"Selection - ");
1023 wcscat(WindowTitle, Console->Title.Buffer);
1024 SetWindowText(GuiData->hWindow, WindowTitle);
1025 RtlFreeHeap(ConSrvHeap, 0, WindowTitle);
1026
1027 break;
1028 }
1029
1030 case WM_LBUTTONUP:
1031 {
1032 COORD c;
1033
1034 if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
1035
1036 c = PointToCoord(GuiData, lParam);
1037 Console->Selection.dwFlags &= ~CONSOLE_MOUSE_DOWN;
1038 GuiConsoleUpdateSelection(Console, &c);
1039 ReleaseCapture();
1040
1041 break;
1042 }
1043
1044 case WM_RBUTTONDOWN:
1045 {
1046 if (!(Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY))
1047 {
1048 GuiConsolePaste(GuiData);
1049 }
1050 else
1051 {
1052 GuiConsoleCopy(GuiData);
1053
1054 /* Clear the selection */
1055 GuiConsoleUpdateSelection(Console, NULL);
1056 SetWindowText(GuiData->hWindow, Console->Title.Buffer);
1057 }
1058
1059 break;
1060 }
1061
1062 case WM_MOUSEMOVE:
1063 {
1064 COORD c;
1065
1066 if (!(wParam & MK_LBUTTON)) break;
1067 if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
1068
1069 c = PointToCoord(GuiData, lParam); /* TODO: Scroll buffer to bring c into view */
1070 GuiConsoleUpdateSelection(Console, &c);
1071
1072 break;
1073 }
1074
1075 default:
1076 Err = TRUE;
1077 break;
1078 }
1079 }
1080 else if (Console->InputBuffer.Mode & ENABLE_MOUSE_INPUT)
1081 {
1082 INPUT_RECORD er;
1083 WORD wKeyState = GET_KEYSTATE_WPARAM(wParam);
1084 DWORD dwButtonState = 0;
1085 DWORD dwControlKeyState = 0;
1086 DWORD dwEventFlags = 0;
1087
1088 switch (msg)
1089 {
1090 case WM_LBUTTONDOWN:
1091 SetCapture(GuiData->hWindow);
1092 dwButtonState = FROM_LEFT_1ST_BUTTON_PRESSED;
1093 dwEventFlags = 0;
1094 break;
1095
1096 case WM_MBUTTONDOWN:
1097 SetCapture(GuiData->hWindow);
1098 dwButtonState = FROM_LEFT_2ND_BUTTON_PRESSED;
1099 dwEventFlags = 0;
1100 break;
1101
1102 case WM_RBUTTONDOWN:
1103 SetCapture(GuiData->hWindow);
1104 dwButtonState = RIGHTMOST_BUTTON_PRESSED;
1105 dwEventFlags = 0;
1106 break;
1107
1108 case WM_LBUTTONUP:
1109 ReleaseCapture();
1110 dwButtonState = 0;
1111 dwEventFlags = 0;
1112 break;
1113
1114 case WM_MBUTTONUP:
1115 ReleaseCapture();
1116 dwButtonState = 0;
1117 dwEventFlags = 0;
1118 break;
1119
1120 case WM_RBUTTONUP:
1121 ReleaseCapture();
1122 dwButtonState = 0;
1123 dwEventFlags = 0;
1124 break;
1125
1126 case WM_LBUTTONDBLCLK:
1127 dwButtonState = FROM_LEFT_1ST_BUTTON_PRESSED;
1128 dwEventFlags = DOUBLE_CLICK;
1129 break;
1130
1131 case WM_MBUTTONDBLCLK:
1132 dwButtonState = FROM_LEFT_2ND_BUTTON_PRESSED;
1133 dwEventFlags = DOUBLE_CLICK;
1134 break;
1135
1136 case WM_RBUTTONDBLCLK:
1137 dwButtonState = RIGHTMOST_BUTTON_PRESSED;
1138 dwEventFlags = DOUBLE_CLICK;
1139 break;
1140
1141 case WM_MOUSEMOVE:
1142 dwButtonState = 0;
1143 dwEventFlags = MOUSE_MOVED;
1144 break;
1145
1146 case WM_MOUSEWHEEL:
1147 dwButtonState = GET_WHEEL_DELTA_WPARAM(wParam) << 16;
1148 dwEventFlags = MOUSE_WHEELED;
1149 break;
1150
1151 case WM_MOUSEHWHEEL:
1152 dwButtonState = GET_WHEEL_DELTA_WPARAM(wParam) << 16;
1153 dwEventFlags = MOUSE_HWHEELED;
1154 break;
1155
1156 default:
1157 Err = TRUE;
1158 break;
1159 }
1160
1161 if (!Err)
1162 {
1163 if (wKeyState & MK_LBUTTON)
1164 dwButtonState |= FROM_LEFT_1ST_BUTTON_PRESSED;
1165 if (wKeyState & MK_MBUTTON)
1166 dwButtonState |= FROM_LEFT_2ND_BUTTON_PRESSED;
1167 if (wKeyState & MK_RBUTTON)
1168 dwButtonState |= RIGHTMOST_BUTTON_PRESSED;
1169
1170 if (GetKeyState(VK_RMENU) & 0x8000)
1171 dwControlKeyState |= RIGHT_ALT_PRESSED;
1172 if (GetKeyState(VK_LMENU) & 0x8000)
1173 dwControlKeyState |= LEFT_ALT_PRESSED;
1174 if (GetKeyState(VK_RCONTROL) & 0x8000)
1175 dwControlKeyState |= RIGHT_CTRL_PRESSED;
1176 if (GetKeyState(VK_LCONTROL) & 0x8000)
1177 dwControlKeyState |= LEFT_CTRL_PRESSED;
1178 if (GetKeyState(VK_SHIFT) & 0x8000)
1179 dwControlKeyState |= SHIFT_PRESSED;
1180 if (GetKeyState(VK_NUMLOCK) & 0x0001)
1181 dwControlKeyState |= NUMLOCK_ON;
1182 if (GetKeyState(VK_SCROLL) & 0x0001)
1183 dwControlKeyState |= SCROLLLOCK_ON;
1184 if (GetKeyState(VK_CAPITAL) & 0x0001)
1185 dwControlKeyState |= CAPSLOCK_ON;
1186 /* See WM_CHAR MSDN documentation for instance */
1187 if (lParam & 0x01000000)
1188 dwControlKeyState |= ENHANCED_KEY;
1189
1190 er.EventType = MOUSE_EVENT;
1191 er.Event.MouseEvent.dwMousePosition = PointToCoord(GuiData, lParam);
1192 er.Event.MouseEvent.dwButtonState = dwButtonState;
1193 er.Event.MouseEvent.dwControlKeyState = dwControlKeyState;
1194 er.Event.MouseEvent.dwEventFlags = dwEventFlags;
1195
1196 ConioProcessInputEvent(Console, &er);
1197 }
1198 }
1199 else
1200 {
1201 Err = TRUE;
1202 }
1203
1204 LeaveCriticalSection(&Console->Lock);
1205
1206 Quit:
1207 if (Err)
1208 return DefWindowProcW(GuiData->hWindow, msg, wParam, lParam);
1209 else
1210 return 0;
1211 }
1212
1213 static VOID
1214 GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData)
1215 {
1216 PCONSOLE Console = GuiData->Console;
1217
1218 if (OpenClipboard(GuiData->hWindow) == TRUE)
1219 {
1220 HANDLE hData;
1221 PBYTE ptr;
1222 LPSTR data, dstPos;
1223 ULONG selWidth, selHeight;
1224 ULONG xPos, yPos, size;
1225
1226 selWidth = Console->Selection.srSelection.Right - Console->Selection.srSelection.Left + 1;
1227 selHeight = Console->Selection.srSelection.Bottom - Console->Selection.srSelection.Top + 1;
1228 DPRINT("Selection is (%d|%d) to (%d|%d)\n",
1229 Console->Selection.srSelection.Left,
1230 Console->Selection.srSelection.Top,
1231 Console->Selection.srSelection.Right,
1232 Console->Selection.srSelection.Bottom);
1233
1234 /* Basic size for one line and termination */
1235 size = selWidth + 1;
1236 if (selHeight > 0)
1237 {
1238 /* Multiple line selections have to get \r\n appended */
1239 size += ((selWidth + 2) * (selHeight - 1));
1240 }
1241
1242 /* Allocate memory, it will be passed to the system and may not be freed here */
1243 hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, size);
1244 if (hData == NULL)
1245 {
1246 CloseClipboard();
1247 return;
1248 }
1249 data = GlobalLock(hData);
1250 if (data == NULL)
1251 {
1252 CloseClipboard();
1253 return;
1254 }
1255
1256 DPRINT("Copying %dx%d selection\n", selWidth, selHeight);
1257 dstPos = data;
1258
1259 for (yPos = 0; yPos < selHeight; yPos++)
1260 {
1261 ptr = ConioCoordToPointer(Console->ActiveBuffer,
1262 Console->Selection.srSelection.Left,
1263 yPos + Console->Selection.srSelection.Top);
1264 /* Copy only the characters, leave attributes alone */
1265 for (xPos = 0; xPos < selWidth; xPos++)
1266 {
1267 dstPos[xPos] = ptr[xPos * 2];
1268 }
1269 dstPos += selWidth;
1270 if (yPos != (selHeight - 1))
1271 {
1272 strcat(data, "\r\n");
1273 dstPos += 2;
1274 }
1275 }
1276
1277 DPRINT("Setting data <%s> to clipboard\n", data);
1278 GlobalUnlock(hData);
1279
1280 EmptyClipboard();
1281 SetClipboardData(CF_TEXT, hData);
1282 CloseClipboard();
1283 }
1284 }
1285
1286 static VOID
1287 GuiConsolePaste(PGUI_CONSOLE_DATA GuiData)
1288 {
1289 PCONSOLE Console = GuiData->Console;
1290
1291 if (OpenClipboard(GuiData->hWindow) == TRUE)
1292 {
1293 HANDLE hData;
1294 LPSTR str;
1295 size_t len;
1296
1297 hData = GetClipboardData(CF_TEXT);
1298 if (hData == NULL)
1299 {
1300 CloseClipboard();
1301 return;
1302 }
1303
1304 str = GlobalLock(hData);
1305 if (str == NULL)
1306 {
1307 CloseClipboard();
1308 return;
1309 }
1310 DPRINT("Got data <%s> from clipboard\n", str);
1311 len = strlen(str);
1312
1313 // TODO: Push the text into the input buffer.
1314 ConioWriteConsole(Console, Console->ActiveBuffer, str, len, TRUE);
1315
1316 GlobalUnlock(hData);
1317 CloseClipboard();
1318 }
1319 }
1320
1321 static VOID
1322 GuiConsoleGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData, PMINMAXINFO minMaxInfo)
1323 {
1324 PCONSOLE Console = GuiData->Console;
1325 DWORD windx, windy;
1326
1327 if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
1328
1329 windx = CONGUI_MIN_WIDTH * GuiData->CharWidth + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
1330 windy = CONGUI_MIN_HEIGHT * GuiData->CharHeight + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
1331
1332 minMaxInfo->ptMinTrackSize.x = windx;
1333 minMaxInfo->ptMinTrackSize.y = windy;
1334
1335 windx = (Console->ActiveBuffer->ScreenBufferSize.X) * GuiData->CharWidth + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
1336 windy = (Console->ActiveBuffer->ScreenBufferSize.Y) * GuiData->CharHeight + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
1337
1338 if(Console->ConsoleSize.X < Console->ActiveBuffer->ScreenBufferSize.X) windy += GetSystemMetrics(SM_CYHSCROLL); // window currently has a horizontal scrollbar
1339 if(Console->ConsoleSize.Y < Console->ActiveBuffer->ScreenBufferSize.Y) windx += GetSystemMetrics(SM_CXVSCROLL); // window currently has a vertical scrollbar
1340
1341 minMaxInfo->ptMaxTrackSize.x = windx;
1342 minMaxInfo->ptMaxTrackSize.y = windy;
1343
1344 LeaveCriticalSection(&Console->Lock);
1345 }
1346
1347 static VOID
1348 GuiConsoleResize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
1349 {
1350 PCONSOLE Console = GuiData->Console;
1351
1352 if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
1353
1354 if ((GuiData->WindowSizeLock == FALSE) &&
1355 (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED || wParam == SIZE_MINIMIZED))
1356 {
1357 PCONSOLE_SCREEN_BUFFER Buff = Console->ActiveBuffer;
1358 DWORD windx, windy, charx, chary;
1359
1360 GuiData->WindowSizeLock = TRUE;
1361
1362 windx = LOWORD(lParam);
1363 windy = HIWORD(lParam);
1364
1365 // Compensate for existing scroll bars (because lParam values do not accommodate scroll bar)
1366 if(Console->ConsoleSize.X < Buff->ScreenBufferSize.X) windy += GetSystemMetrics(SM_CYHSCROLL); // window currently has a horizontal scrollbar
1367 if(Console->ConsoleSize.Y < Buff->ScreenBufferSize.Y) windx += GetSystemMetrics(SM_CXVSCROLL); // window currently has a vertical scrollbar
1368
1369 charx = windx / GuiData->CharWidth;
1370 chary = windy / GuiData->CharHeight;
1371
1372 // Character alignment (round size up or down)
1373 if((windx % GuiData->CharWidth) >= (GuiData->CharWidth / 2)) ++charx;
1374 if((windy % GuiData->CharHeight) >= (GuiData->CharHeight / 2)) ++chary;
1375
1376 // Compensate for added scroll bars in new window
1377 if(charx < Buff->ScreenBufferSize.X)windy -= GetSystemMetrics(SM_CYHSCROLL); // new window will have a horizontal scroll bar
1378 if(chary < Buff->ScreenBufferSize.Y)windx -= GetSystemMetrics(SM_CXVSCROLL); // new window will have a vertical scroll bar
1379
1380 charx = windx / GuiData->CharWidth;
1381 chary = windy / GuiData->CharHeight;
1382
1383 // Character alignment (round size up or down)
1384 if((windx % GuiData->CharWidth) >= (GuiData->CharWidth / 2)) ++charx;
1385 if((windy % GuiData->CharHeight) >= (GuiData->CharHeight / 2)) ++chary;
1386
1387 // Resize window
1388 if((charx != Console->ConsoleSize.X) || (chary != Console->ConsoleSize.Y))
1389 {
1390 Console->ConsoleSize.X = (charx <= Buff->ScreenBufferSize.X) ? charx : Buff->ScreenBufferSize.X;
1391 Console->ConsoleSize.Y = (chary <= Buff->ScreenBufferSize.Y) ? chary : Buff->ScreenBufferSize.Y;
1392 }
1393
1394 GuiConsoleResizeWindow(GuiData);
1395
1396 // Adjust the start of the visible area if we are attempting to show nonexistent areas
1397 if((Buff->ScreenBufferSize.X - Buff->ShowX) < Console->ConsoleSize.X) Buff->ShowX = Buff->ScreenBufferSize.X - Console->ConsoleSize.X;
1398 if((Buff->ScreenBufferSize.Y - Buff->ShowY) < Console->ConsoleSize.Y) Buff->ShowY = Buff->ScreenBufferSize.Y - Console->ConsoleSize.Y;
1399 InvalidateRect(GuiData->hWindow, NULL, TRUE);
1400
1401 GuiData->WindowSizeLock = FALSE;
1402 }
1403
1404 LeaveCriticalSection(&Console->Lock);
1405 }
1406
1407 /*
1408 // HACK: This functionality is standard for general scrollbars. Don't add it by hand.
1409
1410 VOID
1411 FASTCALL
1412 GuiConsoleHandleScrollbarMenu(VOID)
1413 {
1414 HMENU hMenu;
1415
1416 hMenu = CreatePopupMenu();
1417 if (hMenu == NULL)
1418 {
1419 DPRINT("CreatePopupMenu failed\n");
1420 return;
1421 }
1422
1423 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLHERE);
1424 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1425 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLTOP);
1426 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLBOTTOM);
1427 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1428 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_UP);
1429 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_DOWN);
1430 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1431 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLUP);
1432 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLDOWN);
1433 }
1434 */
1435
1436 static LRESULT
1437 GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam)
1438 {
1439 PCONSOLE Console = GuiData->Console;
1440 PCONSOLE_SCREEN_BUFFER Buff;
1441 SCROLLINFO sInfo;
1442 int fnBar;
1443 int old_pos, Maximum;
1444 PUSHORT pShowXY;
1445
1446 if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return 0;
1447
1448 Buff = Console->ActiveBuffer;
1449
1450 if (uMsg == WM_HSCROLL)
1451 {
1452 fnBar = SB_HORZ;
1453 Maximum = Buff->ScreenBufferSize.X - Console->ConsoleSize.X;
1454 pShowXY = &Buff->ShowX;
1455 }
1456 else
1457 {
1458 fnBar = SB_VERT;
1459 Maximum = Buff->ScreenBufferSize.Y - Console->ConsoleSize.Y;
1460 pShowXY = &Buff->ShowY;
1461 }
1462
1463 /* set scrollbar sizes */
1464 sInfo.cbSize = sizeof(SCROLLINFO);
1465 sInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE | SIF_TRACKPOS;
1466
1467 if (!GetScrollInfo(GuiData->hWindow, fnBar, &sInfo)) goto Quit;
1468
1469 old_pos = sInfo.nPos;
1470
1471 switch (LOWORD(wParam))
1472 {
1473 case SB_LINELEFT:
1474 sInfo.nPos -= 1;
1475 break;
1476
1477 case SB_LINERIGHT:
1478 sInfo.nPos += 1;
1479 break;
1480
1481 case SB_PAGELEFT:
1482 sInfo.nPos -= sInfo.nPage;
1483 break;
1484
1485 case SB_PAGERIGHT:
1486 sInfo.nPos += sInfo.nPage;
1487 break;
1488
1489 case SB_THUMBTRACK:
1490 sInfo.nPos = sInfo.nTrackPos;
1491 ConioPause(Console, PAUSED_FROM_SCROLLBAR);
1492 break;
1493
1494 case SB_THUMBPOSITION:
1495 ConioUnpause(Console, PAUSED_FROM_SCROLLBAR);
1496 break;
1497
1498 case SB_TOP:
1499 sInfo.nPos = sInfo.nMin;
1500 break;
1501
1502 case SB_BOTTOM:
1503 sInfo.nPos = sInfo.nMax;
1504 break;
1505
1506 default:
1507 break;
1508 }
1509
1510 sInfo.nPos = max(sInfo.nPos, 0);
1511 sInfo.nPos = min(sInfo.nPos, Maximum);
1512
1513 if (old_pos != sInfo.nPos)
1514 {
1515 USHORT OldX = Buff->ShowX;
1516 USHORT OldY = Buff->ShowY;
1517 *pShowXY = sInfo.nPos;
1518
1519 ScrollWindowEx(GuiData->hWindow,
1520 (OldX - Buff->ShowX) * GuiData->CharWidth,
1521 (OldY - Buff->ShowY) * GuiData->CharHeight,
1522 NULL,
1523 NULL,
1524 NULL,
1525 NULL,
1526 SW_INVALIDATE);
1527
1528 sInfo.fMask = SIF_POS;
1529 SetScrollInfo(GuiData->hWindow, fnBar, &sInfo, TRUE);
1530
1531 UpdateWindow(GuiData->hWindow);
1532 }
1533
1534 Quit:
1535 LeaveCriticalSection(&Console->Lock);
1536 return 0;
1537 }
1538
1539 static LRESULT CALLBACK
1540 GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1541 {
1542 LRESULT Result = 0;
1543 PGUI_CONSOLE_DATA GuiData = NULL;
1544 PCONSOLE Console = NULL;
1545
1546 /*
1547 * - If it's the first time we create a window for the terminal,
1548 * just initialize it and return.
1549 *
1550 * - If we are destroying the window, just do it and return.
1551 */
1552 if (msg == WM_NCCREATE)
1553 {
1554 return (LRESULT)GuiConsoleHandleNcCreate(hWnd, (LPCREATESTRUCTW)lParam);
1555 }
1556 else if (msg == WM_NCDESTROY)
1557 {
1558 return GuiConsoleHandleNcDestroy(hWnd);
1559 }
1560
1561 /*
1562 * Now the terminal window is initialized.
1563 * Get the terminal data via the window's data.
1564 * If there is no data, just go away.
1565 */
1566 GuiData = GuiGetGuiData(hWnd);
1567 if (GuiData == NULL) return 0;
1568
1569 /*
1570 * Each helper function which needs the console
1571 * has to validate and lock it.
1572 */
1573
1574 /* We have a console, start message dispatching */
1575 switch (msg)
1576 {
1577 case WM_CLOSE:
1578 GuiConsoleHandleClose(GuiData);
1579 break;
1580
1581 case WM_PAINT:
1582 GuiConsoleHandlePaint(GuiData);
1583 break;
1584
1585 case WM_KEYDOWN:
1586 case WM_KEYUP:
1587 case WM_SYSKEYDOWN:
1588 case WM_SYSKEYUP:
1589 case WM_CHAR:
1590 {
1591 GuiConsoleHandleKey(GuiData, msg, wParam, lParam);
1592 break;
1593 }
1594
1595 case WM_TIMER:
1596 GuiConsoleHandleTimer(GuiData);
1597 break;
1598
1599 case WM_LBUTTONDOWN:
1600 case WM_MBUTTONDOWN:
1601 case WM_RBUTTONDOWN:
1602 case WM_LBUTTONUP:
1603 case WM_MBUTTONUP:
1604 case WM_RBUTTONUP:
1605 case WM_LBUTTONDBLCLK:
1606 case WM_MBUTTONDBLCLK:
1607 case WM_RBUTTONDBLCLK:
1608 case WM_MOUSEMOVE:
1609 case WM_MOUSEWHEEL:
1610 case WM_MOUSEHWHEEL:
1611 {
1612 Result = GuiConsoleHandleMouse(GuiData, msg, wParam, lParam);
1613 break;
1614 }
1615
1616 case WM_NCRBUTTONDOWN:
1617 {
1618 DPRINT("WM_NCRBUTTONDOWN\n");
1619 /*
1620 * HACK: !! Because, when we deal with WM_RBUTTON* and we do not
1621 * call after that DefWindowProc, on ReactOS, right-clicks on the
1622 * (non-client) application title-bar does not display the system
1623 * menu and does not trigger a WM_NCRBUTTONUP message too.
1624 * See: http://git.reactos.org/?p=reactos.git;a=blob;f=reactos/win32ss/user/user32/windows/defwnd.c;hb=HEAD#l1103
1625 * and line 1135 too.
1626 */
1627 if (DefWindowProcW(hWnd, WM_NCHITTEST, 0, lParam) == HTCAPTION)
1628 return DefWindowProcW(hWnd, WM_CONTEXTMENU, wParam, lParam);
1629 else
1630 goto Default;
1631 }
1632 // case WM_NCRBUTTONUP:
1633 // DPRINT1("WM_NCRBUTTONUP\n");
1634 // goto Default;
1635
1636 case WM_CONTEXTMENU:
1637 {
1638 if (DefWindowProcW(hWnd /*GuiData->hWindow*/, WM_NCHITTEST, 0, lParam) == HTCLIENT)
1639 {
1640 HMENU hMenu = CreatePopupMenu();
1641 if (hMenu != NULL)
1642 {
1643 GuiConsoleAppendMenuItems(hMenu, GuiConsoleEditMenuItems);
1644 TrackPopupMenuEx(hMenu,
1645 TPM_RIGHTBUTTON,
1646 GET_X_LPARAM(lParam),
1647 GET_Y_LPARAM(lParam),
1648 hWnd,
1649 NULL);
1650 DestroyMenu(hMenu);
1651 }
1652 break;
1653 }
1654 else
1655 {
1656 goto Default;
1657 }
1658 }
1659
1660 case WM_COMMAND:
1661 case WM_SYSCOMMAND:
1662 {
1663 Result = GuiConsoleHandleSysMenuCommand(GuiData, wParam, lParam);
1664 break;
1665 }
1666
1667 case WM_HSCROLL:
1668 case WM_VSCROLL:
1669 {
1670 Result = GuiConsoleHandleScroll(GuiData, msg, wParam);
1671 break;
1672 }
1673
1674 case WM_SETFOCUS:
1675 case WM_KILLFOCUS:
1676 {
1677 Console = GuiData->Console; // Not NULL because checked in GuiGetGuiData.
1678 if (ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
1679 {
1680 INPUT_RECORD er;
1681 er.EventType = FOCUS_EVENT;
1682 er.Event.FocusEvent.bSetFocus = (msg == WM_SETFOCUS);
1683 ConioProcessInputEvent(Console, &er);
1684
1685 LeaveCriticalSection(&Console->Lock);
1686 }
1687 break;
1688 }
1689
1690 case WM_GETMINMAXINFO:
1691 GuiConsoleGetMinMaxInfo(GuiData, (PMINMAXINFO)lParam);
1692 break;
1693
1694 case WM_SIZE:
1695 GuiConsoleResize(GuiData, wParam, lParam);
1696 break;
1697
1698 case PM_APPLY_CONSOLE_INFO:
1699 {
1700 Console = GuiData->Console; // Not NULL because checked in GuiGetGuiData.
1701 if (ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
1702 {
1703 GuiApplyUserSettings(GuiData, (HANDLE)wParam, (BOOL)lParam);
1704 LeaveCriticalSection(&Console->Lock);
1705 }
1706 break;
1707 }
1708
1709 case PM_CONSOLE_BEEP:
1710 DPRINT1("Beep !!\n");
1711 Beep(800, 200);
1712 break;
1713
1714 // case PM_CONSOLE_SET_TITLE:
1715 // SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
1716 // break;
1717
1718 default: Default:
1719 Result = DefWindowProcW(hWnd, msg, wParam, lParam);
1720 break;
1721 }
1722
1723 return Result;
1724 }
1725
1726
1727
1728 /******************************************************************************
1729 * GUI Terminal Initialization *
1730 ******************************************************************************/
1731
1732 static LRESULT CALLBACK
1733 GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1734 {
1735 HWND NewWindow;
1736 LONG WindowCount;
1737 MSG Msg;
1738
1739 switch (msg)
1740 {
1741 case WM_CREATE:
1742 {
1743 SetWindowLongW(hWnd, GWL_USERDATA, 0);
1744 return 0;
1745 }
1746
1747 case PM_CREATE_CONSOLE:
1748 {
1749 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)lParam;
1750 PCONSOLE Console = GuiData->Console;
1751
1752 NewWindow = CreateWindowExW(WS_EX_CLIENTEDGE,
1753 GUI_CONSOLE_WINDOW_CLASS,
1754 Console->Title.Buffer,
1755 WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
1756 CW_USEDEFAULT,
1757 CW_USEDEFAULT,
1758 CW_USEDEFAULT,
1759 CW_USEDEFAULT,
1760 NULL,
1761 NULL,
1762 ConSrvDllInstance,
1763 (PVOID)GuiData);
1764 if (NULL != NewWindow)
1765 {
1766 WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
1767 WindowCount++;
1768 SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
1769
1770 DPRINT1("Set icons via PM_CREATE_CONSOLE\n");
1771 if (GuiData->hIcon == NULL)
1772 {
1773 DPRINT1("Not really /o\\...\n");
1774 GuiData->hIcon = ghDefaultIcon;
1775 GuiData->hIconSm = ghDefaultIconSm;
1776 }
1777 else if (GuiData->hIcon != ghDefaultIcon)
1778 {
1779 DPRINT1("Yes \\o/\n");
1780 SendMessageW(GuiData->hWindow, WM_SETICON, ICON_BIG, (LPARAM)GuiData->hIcon);
1781 SendMessageW(GuiData->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)GuiData->hIconSm);
1782 }
1783
1784 /* Move and resize the window to the user's values */
1785 /* CAN WE DEADLOCK ?? */
1786 GuiConsoleMoveWindow(GuiData);
1787 GuiData->WindowSizeLock = TRUE;
1788 GuiConsoleResizeWindow(GuiData);
1789 GuiData->WindowSizeLock = FALSE;
1790
1791 // ShowWindow(NewWindow, (int)wParam);
1792 ShowWindowAsync(NewWindow, (int)wParam);
1793 DPRINT1("Window showed\n");
1794 }
1795
1796 return (LRESULT)NewWindow;
1797 }
1798
1799 case PM_DESTROY_CONSOLE:
1800 {
1801 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)lParam;
1802
1803 /*
1804 * Window creation is done using a PostMessage(), so it's possible
1805 * that the window that we want to destroy doesn't exist yet.
1806 * So first empty the message queue.
1807 */
1808 /*
1809 while(PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
1810 {
1811 TranslateMessage(&Msg);
1812 DispatchMessageW(&Msg);
1813 }*/
1814 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE)) ;
1815
1816 if (GuiData->hWindow != NULL) /* && DestroyWindow(GuiData->hWindow) */
1817 {
1818 DestroyWindow(GuiData->hWindow);
1819
1820 WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
1821 WindowCount--;
1822 SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
1823 if (0 == WindowCount)
1824 {
1825 NotifyWnd = NULL;
1826 DestroyWindow(hWnd);
1827 DPRINT1("CONSRV: Going to quit the Gui Thread!!\n");
1828 PostQuitMessage(0);
1829 }
1830 }
1831
1832 return 0;
1833 }
1834
1835 default:
1836 return DefWindowProcW(hWnd, msg, wParam, lParam);
1837 }
1838 }
1839
1840 static DWORD WINAPI
1841 GuiConsoleGuiThread(PVOID Data)
1842 {
1843 MSG msg;
1844 PHANDLE GraphicsStartupEvent = (PHANDLE)Data;
1845
1846 /*
1847 * This thread dispatches all the console notifications to the notify window.
1848 * It is common for all the console windows.
1849 */
1850
1851 PrivateCsrssManualGuiCheck(+1);
1852
1853 NotifyWnd = CreateWindowW(L"ConSrvCreateNotify",
1854 L"",
1855 WS_OVERLAPPEDWINDOW,
1856 CW_USEDEFAULT,
1857 CW_USEDEFAULT,
1858 CW_USEDEFAULT,
1859 CW_USEDEFAULT,
1860 NULL,
1861 NULL,
1862 ConSrvDllInstance,
1863 NULL);
1864 if (NULL == NotifyWnd)
1865 {
1866 PrivateCsrssManualGuiCheck(-1);
1867 SetEvent(*GraphicsStartupEvent);
1868 return 1;
1869 }
1870
1871 SetEvent(*GraphicsStartupEvent);
1872
1873 while(GetMessageW(&msg, NULL, 0, 0))
1874 {
1875 TranslateMessage(&msg);
1876 DispatchMessageW(&msg);
1877 }
1878
1879 DPRINT1("CONSRV: Quit the Gui Thread!!\n");
1880 PrivateCsrssManualGuiCheck(-1);
1881
1882 return 1;
1883 }
1884
1885 static BOOL
1886 GuiInit(VOID)
1887 {
1888 WNDCLASSEXW wc;
1889 ATOM ConsoleClassAtom;
1890
1891 /* Exit if we were already initialized */
1892 // if (ConsInitialized) return TRUE;
1893
1894 /*
1895 * Initialize and register the different window classes, if needed.
1896 */
1897 if (!ConsInitialized)
1898 {
1899 /* Initialize the notification window class */
1900 wc.cbSize = sizeof(WNDCLASSEXW);
1901 wc.lpszClassName = L"ConSrvCreateNotify";
1902 wc.lpfnWndProc = GuiConsoleNotifyWndProc;
1903 wc.style = 0;
1904 wc.hInstance = ConSrvDllInstance;
1905 wc.hIcon = NULL;
1906 wc.hIconSm = NULL;
1907 wc.hCursor = NULL;
1908 wc.hbrBackground = NULL;
1909 wc.lpszMenuName = NULL;
1910 wc.cbClsExtra = 0;
1911 wc.cbWndExtra = 0;
1912 if (RegisterClassExW(&wc) == 0)
1913 {
1914 DPRINT1("Failed to register GUI notify wndproc\n");
1915 return FALSE;
1916 }
1917
1918 /* Initialize the console window class */
1919 ghDefaultIcon = LoadImageW(ConSrvDllInstance, MAKEINTRESOURCEW(IDI_CONSOLE), IMAGE_ICON,
1920 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
1921 LR_SHARED);
1922 ghDefaultIconSm = LoadImageW(ConSrvDllInstance, MAKEINTRESOURCEW(IDI_CONSOLE), IMAGE_ICON,
1923 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
1924 LR_SHARED);
1925 ghDefaultCursor = LoadCursorW(NULL, IDC_ARROW);
1926 wc.cbSize = sizeof(WNDCLASSEXW);
1927 wc.lpszClassName = GUI_CONSOLE_WINDOW_CLASS;
1928 wc.lpfnWndProc = GuiConsoleWndProc;
1929 wc.style = CS_DBLCLKS /* | CS_HREDRAW | CS_VREDRAW */;
1930 wc.hInstance = ConSrvDllInstance;
1931 wc.hIcon = ghDefaultIcon;
1932 wc.hIconSm = ghDefaultIconSm;
1933 wc.hCursor = ghDefaultCursor;
1934 wc.hbrBackground = CreateSolidBrush(RGB(0,0,0)); // FIXME: Use defaults from registry.
1935 wc.lpszMenuName = NULL;
1936 wc.cbClsExtra = 0;
1937 wc.cbWndExtra = GWLP_CONSOLEWND_ALLOC;
1938
1939 ConsoleClassAtom = RegisterClassExW(&wc);
1940 if (ConsoleClassAtom == 0)
1941 {
1942 DPRINT1("Failed to register GUI console wndproc\n");
1943 return FALSE;
1944 }
1945 else
1946 {
1947 NtUserConsoleControl(GuiConsoleWndClassAtom, &ConsoleClassAtom, sizeof(ATOM));
1948 }
1949
1950 ConsInitialized = TRUE;
1951 }
1952
1953 /*
1954 * Set-up the notification window
1955 */
1956 if (NULL == NotifyWnd)
1957 {
1958 HANDLE ThreadHandle;
1959 HANDLE GraphicsStartupEvent;
1960
1961 GraphicsStartupEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1962 if (NULL == GraphicsStartupEvent) return FALSE;
1963
1964 ThreadHandle = CreateThread(NULL,
1965 0,
1966 GuiConsoleGuiThread,
1967 (PVOID)&GraphicsStartupEvent,
1968 0,
1969 NULL);
1970 if (NULL == ThreadHandle)
1971 {
1972 CloseHandle(GraphicsStartupEvent);
1973 DPRINT1("CONSRV: Failed to create graphics console thread. Expect problems\n");
1974 return FALSE;
1975 }
1976 SetThreadPriority(ThreadHandle, THREAD_PRIORITY_HIGHEST);
1977 CloseHandle(ThreadHandle);
1978
1979 WaitForSingleObject(GraphicsStartupEvent, INFINITE);
1980 CloseHandle(GraphicsStartupEvent);
1981
1982 if (NULL == NotifyWnd)
1983 {
1984 DPRINT1("CONSRV: Failed to create notification window.\n");
1985 return FALSE;
1986 }
1987 }
1988
1989 // ConsInitialized = TRUE;
1990
1991 return TRUE;
1992 }
1993
1994
1995
1996 /******************************************************************************
1997 * GUI Console Driver *
1998 ******************************************************************************/
1999
2000 static VOID WINAPI
2001 GuiCleanupConsole(PCONSOLE Console)
2002 {
2003 PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data;
2004
2005 SendMessageW(NotifyWnd, PM_DESTROY_CONSOLE, 0, (LPARAM)GuiData);
2006
2007 DPRINT1("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
2008 GuiData->hIcon, ghDefaultIcon, GuiData->hIconSm, ghDefaultIconSm);
2009 if (GuiData->hIcon != NULL && GuiData->hIcon != ghDefaultIcon)
2010 {
2011 DPRINT1("Destroy hIcon\n");
2012 DestroyIcon(GuiData->hIcon);
2013 }
2014 if (GuiData->hIconSm != NULL && GuiData->hIconSm != ghDefaultIconSm)
2015 {
2016 DPRINT1("Destroy hIconSm\n");
2017 DestroyIcon(GuiData->hIconSm);
2018 }
2019
2020 Console->TermIFace.Data = NULL;
2021 DeleteCriticalSection(&GuiData->Lock);
2022 RtlFreeHeap(ConSrvHeap, 0, GuiData);
2023
2024 DPRINT1("Quit GuiCleanupConsole\n");
2025 }
2026
2027 static VOID WINAPI
2028 GuiWriteStream(PCONSOLE Console, SMALL_RECT* Region, LONG CursorStartX, LONG CursorStartY,
2029 UINT ScrolledLines, CHAR *Buffer, UINT Length)
2030 {
2031 PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data;
2032 PCONSOLE_SCREEN_BUFFER Buff = Console->ActiveBuffer;
2033 LONG CursorEndX, CursorEndY;
2034 RECT ScrollRect;
2035
2036 if (NULL == GuiData || NULL == GuiData->hWindow)
2037 {
2038 return;
2039 }
2040
2041 if (0 != ScrolledLines)
2042 {
2043 ScrollRect.left = 0;
2044 ScrollRect.top = 0;
2045 ScrollRect.right = Console->ConsoleSize.X * GuiData->CharWidth;
2046 ScrollRect.bottom = Region->Top * GuiData->CharHeight;
2047
2048 ScrollWindowEx(GuiData->hWindow,
2049 0,
2050 -(ScrolledLines * GuiData->CharHeight),
2051 &ScrollRect,
2052 NULL,
2053 NULL,
2054 NULL,
2055 SW_INVALIDATE);
2056 }
2057
2058 GuiDrawRegion(Console, Region);
2059
2060 if (CursorStartX < Region->Left || Region->Right < CursorStartX
2061 || CursorStartY < Region->Top || Region->Bottom < CursorStartY)
2062 {
2063 GuiInvalidateCell(Console, CursorStartX, CursorStartY);
2064 }
2065
2066 CursorEndX = Buff->CursorPosition.X;
2067 CursorEndY = Buff->CursorPosition.Y;
2068 if ((CursorEndX < Region->Left || Region->Right < CursorEndX
2069 || CursorEndY < Region->Top || Region->Bottom < CursorEndY)
2070 && (CursorEndX != CursorStartX || CursorEndY != CursorStartY))
2071 {
2072 GuiInvalidateCell(Console, CursorEndX, CursorEndY);
2073 }
2074
2075 // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
2076 // repaint the window without having it just freeze up and stay on the screen permanently.
2077 Buff->CursorBlinkOn = TRUE;
2078 SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
2079 }
2080
2081 static VOID WINAPI
2082 GuiDrawRegion(PCONSOLE Console, SMALL_RECT* Region)
2083 {
2084 PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data;
2085 RECT RegionRect;
2086
2087 SmallRectToRect(GuiData, &RegionRect, Region);
2088 InvalidateRect(GuiData->hWindow, &RegionRect, FALSE);
2089 }
2090
2091 static BOOL WINAPI
2092 GuiSetCursorInfo(PCONSOLE Console, PCONSOLE_SCREEN_BUFFER Buff)
2093 {
2094 if (Console->ActiveBuffer == Buff)
2095 {
2096 GuiInvalidateCell(Console, Buff->CursorPosition.X, Buff->CursorPosition.Y);
2097 }
2098
2099 return TRUE;
2100 }
2101
2102 static BOOL WINAPI
2103 GuiSetScreenInfo(PCONSOLE Console, PCONSOLE_SCREEN_BUFFER Buff, UINT OldCursorX, UINT OldCursorY)
2104 {
2105 if (Console->ActiveBuffer == Buff)
2106 {
2107 /* Redraw char at old position (removes cursor) */
2108 GuiInvalidateCell(Console, OldCursorX, OldCursorY);
2109 /* Redraw char at new position (shows cursor) */
2110 GuiInvalidateCell(Console, Buff->CursorPosition.X, Buff->CursorPosition.Y);
2111 }
2112
2113 return TRUE;
2114 }
2115
2116 static BOOL WINAPI
2117 GuiUpdateScreenInfo(PCONSOLE Console, PCONSOLE_SCREEN_BUFFER Buff)
2118 {
2119 return TRUE;
2120 }
2121
2122 static NTSTATUS WINAPI
2123 GuiResizeBuffer(PCONSOLE Console, PCONSOLE_SCREEN_BUFFER ScreenBuffer, COORD Size)
2124 {
2125 BYTE * Buffer;
2126 DWORD Offset = 0;
2127 BYTE * OldPtr;
2128 USHORT CurrentY;
2129 BYTE * OldBuffer;
2130 #ifdef HAVE_WMEMSET
2131 USHORT value = MAKEWORD(' ', ScreenBuffer->ScreenDefaultAttrib);
2132 #else
2133 DWORD i;
2134 #endif
2135 DWORD diff;
2136
2137 /* Buffer size is not allowed to be smaller than window size */
2138 if (Size.X < Console->ConsoleSize.X || Size.Y < Console->ConsoleSize.Y)
2139 return STATUS_INVALID_PARAMETER;
2140
2141 if (Size.X == ScreenBuffer->ScreenBufferSize.X && Size.Y == ScreenBuffer->ScreenBufferSize.Y)
2142 {
2143 // FIXME: Trigger a buffer resize event ??
2144 return STATUS_SUCCESS;
2145 }
2146
2147 Buffer = RtlAllocateHeap(ConSrvHeap, 0, Size.X * Size.Y * 2);
2148 if (!Buffer)
2149 return STATUS_NO_MEMORY;
2150
2151 DPRINT1("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer->ScreenBufferSize.X, ScreenBuffer->ScreenBufferSize.Y, Size.X, Size.Y);
2152 OldBuffer = ScreenBuffer->Buffer;
2153
2154 for (CurrentY = 0; CurrentY < ScreenBuffer->ScreenBufferSize.Y && CurrentY < Size.Y; CurrentY++)
2155 {
2156 OldPtr = ConioCoordToPointer(ScreenBuffer, 0, CurrentY);
2157 if (Size.X <= ScreenBuffer->ScreenBufferSize.X)
2158 {
2159 /* reduce size */
2160 RtlCopyMemory(&Buffer[Offset], OldPtr, Size.X * 2);
2161 Offset += (Size.X * 2);
2162 }
2163 else
2164 {
2165 /* enlarge size */
2166 RtlCopyMemory(&Buffer[Offset], OldPtr, ScreenBuffer->ScreenBufferSize.X * 2);
2167 Offset += (ScreenBuffer->ScreenBufferSize.X * 2);
2168
2169 diff = Size.X - ScreenBuffer->ScreenBufferSize.X;
2170 /* zero new part of it */
2171 #ifdef HAVE_WMEMSET
2172 wmemset((PWCHAR)&Buffer[Offset], value, diff);
2173 #else
2174 for (i = 0; i < diff; i++)
2175 {
2176 Buffer[Offset++] = ' ';
2177 Buffer[Offset++] = ScreenBuffer->ScreenDefaultAttrib;
2178 }
2179 #endif
2180 }
2181 }
2182
2183 if (Size.Y > ScreenBuffer->ScreenBufferSize.Y)
2184 {
2185 diff = Size.X * (Size.Y - ScreenBuffer->ScreenBufferSize.Y);
2186 #ifdef HAVE_WMEMSET
2187 wmemset((PWCHAR)&Buffer[Offset], value, diff);
2188 #else
2189 for (i = 0; i < diff; i++)
2190 {
2191 Buffer[Offset++] = ' ';
2192 Buffer[Offset++] = ScreenBuffer->ScreenDefaultAttrib;
2193 }
2194 #endif
2195 }
2196
2197 (void)InterlockedExchangePointer((PVOID volatile*)&ScreenBuffer->Buffer, Buffer);
2198 RtlFreeHeap(ConSrvHeap, 0, OldBuffer);
2199 ScreenBuffer->ScreenBufferSize = Size;
2200 ScreenBuffer->VirtualY = 0;
2201
2202 /* Ensure cursor and window are within buffer */
2203 if (ScreenBuffer->CursorPosition.X >= Size.X)
2204 ScreenBuffer->CursorPosition.X = Size.X - 1;
2205 if (ScreenBuffer->CursorPosition.Y >= Size.Y)
2206 ScreenBuffer->CursorPosition.Y = Size.Y - 1;
2207 if (ScreenBuffer->ShowX > Size.X - Console->ConsoleSize.X)
2208 ScreenBuffer->ShowX = Size.X - Console->ConsoleSize.X;
2209 if (ScreenBuffer->ShowY > Size.Y - Console->ConsoleSize.Y)
2210 ScreenBuffer->ShowY = Size.Y - Console->ConsoleSize.Y;
2211
2212 /*
2213 * Trigger a buffer resize event
2214 */
2215 if (Console->InputBuffer.Mode & ENABLE_WINDOW_INPUT)
2216 {
2217 INPUT_RECORD er;
2218
2219 er.EventType = WINDOW_BUFFER_SIZE_EVENT;
2220 er.Event.WindowBufferSizeEvent.dwSize = ScreenBuffer->ScreenBufferSize;
2221
2222 ConioProcessInputEvent(Console, &er);
2223 }
2224
2225 /* TODO: Should update scrollbar, but can't use anything that
2226 * calls SendMessage or it could cause deadlock --> Use PostMessage */
2227 // TODO: Tell the terminal to resize its scrollbars.
2228
2229 return STATUS_SUCCESS;
2230 }
2231
2232 static VOID WINAPI
2233 GuiResizeTerminal(PCONSOLE Console)
2234 {
2235 PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data;
2236
2237 /* Resize the window to the user's values */
2238 GuiData->WindowSizeLock = TRUE;
2239 GuiConsoleResizeWindow(GuiData);
2240 GuiData->WindowSizeLock = FALSE;
2241 }
2242
2243 static BOOL WINAPI
2244 GuiProcessKeyCallback(PCONSOLE Console, MSG* msg, BYTE KeyStateMenu, DWORD ShiftState, UINT VirtualKeyCode, BOOL Down)
2245 {
2246 if ((ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED) || KeyStateMenu & 0x80) &&
2247 (VirtualKeyCode == VK_ESCAPE || VirtualKeyCode == VK_TAB || VirtualKeyCode == VK_SPACE))
2248 {
2249 DefWindowProcW(msg->hwnd, msg->message, msg->wParam, msg->lParam);
2250 return TRUE;
2251 }
2252
2253 return FALSE;
2254 }
2255
2256 static VOID WINAPI
2257 GuiRefreshInternalInfo(PCONSOLE Console)
2258 {
2259 PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data;
2260
2261 /* Update the console leader information held by the window */
2262 SetConsoleWndConsoleLeaderCID(GuiData);
2263 }
2264
2265 static VOID WINAPI
2266 GuiChangeTitle(PCONSOLE Console)
2267 {
2268 PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data;
2269 // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
2270 SetWindowText(GuiData->hWindow, Console->Title.Buffer);
2271 }
2272
2273 static BOOL WINAPI
2274 GuiChangeIcon(PCONSOLE Console, HICON hWindowIcon)
2275 {
2276 PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data;
2277 HICON hIcon, hIconSm;
2278
2279 if (hWindowIcon == NULL)
2280 {
2281 hIcon = ghDefaultIcon;
2282 hIconSm = ghDefaultIconSm;
2283 }
2284 else
2285 {
2286 hIcon = CopyIcon(hWindowIcon);
2287 hIconSm = CopyIcon(hWindowIcon);
2288 }
2289
2290 if (hIcon == NULL)
2291 {
2292 return FALSE;
2293 }
2294
2295 if (hIcon != GuiData->hIcon)
2296 {
2297 if (GuiData->hIcon != NULL && GuiData->hIcon != ghDefaultIcon)
2298 {
2299 DestroyIcon(GuiData->hIcon);
2300 }
2301 if (GuiData->hIconSm != NULL && GuiData->hIconSm != ghDefaultIconSm)
2302 {
2303 DestroyIcon(GuiData->hIconSm);
2304 }
2305
2306 GuiData->hIcon = hIcon;
2307 GuiData->hIconSm = hIconSm;
2308
2309 DPRINT1("Set icons in GuiChangeIcon\n");
2310 PostMessageW(GuiData->hWindow, WM_SETICON, ICON_BIG, (LPARAM)GuiData->hIcon);
2311 PostMessageW(GuiData->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)GuiData->hIconSm);
2312 }
2313
2314 return TRUE;
2315 }
2316
2317 static HWND WINAPI
2318 GuiGetConsoleWindowHandle(PCONSOLE Console)
2319 {
2320 PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data;
2321 return GuiData->hWindow;
2322 }
2323
2324 static FRONTEND_VTBL GuiVtbl =
2325 {
2326 GuiCleanupConsole,
2327 GuiWriteStream,
2328 GuiDrawRegion,
2329 GuiSetCursorInfo,
2330 GuiSetScreenInfo,
2331 GuiUpdateScreenInfo,
2332 GuiResizeBuffer,
2333 GuiResizeTerminal,
2334 GuiProcessKeyCallback,
2335 GuiRefreshInternalInfo,
2336 GuiChangeTitle,
2337 GuiChangeIcon,
2338 GuiGetConsoleWindowHandle
2339 };
2340
2341 NTSTATUS FASTCALL
2342 GuiInitConsole(PCONSOLE Console,
2343 /*IN*/ PCONSOLE_START_INFO ConsoleStartInfo,
2344 PCONSOLE_INFO ConsoleInfo,
2345 DWORD ProcessId,
2346 LPCWSTR IconPath,
2347 INT IconIndex)
2348 {
2349 PGUI_CONSOLE_DATA GuiData;
2350 GUI_CONSOLE_INFO TermInfo;
2351 SIZE_T Length = 0;
2352
2353 if (Console == NULL || ConsoleInfo == NULL)
2354 return STATUS_INVALID_PARAMETER;
2355
2356 /* Initialize the GUI terminal emulator */
2357 if (!GuiInit()) return STATUS_UNSUCCESSFUL;
2358
2359 /* Initialize the console */
2360 Console->TermIFace.Vtbl = &GuiVtbl;
2361
2362 GuiData = RtlAllocateHeap(ConSrvHeap, HEAP_ZERO_MEMORY,
2363 sizeof(GUI_CONSOLE_DATA));
2364 if (!GuiData)
2365 {
2366 DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
2367 return STATUS_UNSUCCESSFUL;
2368 }
2369 Console->TermIFace.Data = (PVOID)GuiData;
2370 GuiData->Console = Console;
2371 GuiData->hWindow = NULL;
2372
2373 InitializeCriticalSection(&GuiData->Lock);
2374
2375
2376 /*
2377 * Load the terminal settings
2378 */
2379
2380 /***********************************************
2381 * Adapted from ConSrvInitConsole in console.c *
2382 ***********************************************/
2383
2384 /* 1. Load the default settings */
2385 GuiConsoleGetDefaultSettings(&TermInfo, ProcessId);
2386
2387 /* 2. Load the remaining console settings via the registry. */
2388 if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
2389 {
2390 /* Load the terminal infos from the registry. */
2391 GuiConsoleReadUserSettings(&TermInfo, ConsoleInfo->ConsoleTitle, ProcessId);
2392
2393 /*
2394 * Now, update them with the properties the user might gave to us
2395 * via the STARTUPINFO structure before calling CreateProcess
2396 * (and which was transmitted via the ConsoleStartInfo structure).
2397 * We therefore overwrite the values read in the registry.
2398 */
2399 if (ConsoleStartInfo->dwStartupFlags & STARTF_USESHOWWINDOW)
2400 {
2401 TermInfo.ShowWindow = ConsoleStartInfo->ShowWindow;
2402 }
2403 if (ConsoleStartInfo->dwStartupFlags & STARTF_USEPOSITION)
2404 {
2405 TermInfo.AutoPosition = FALSE;
2406 TermInfo.WindowOrigin = ConsoleStartInfo->ConsoleWindowOrigin;
2407 }
2408 /*
2409 if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)
2410 {
2411 ConsoleInfo.FullScreen = TRUE;
2412 }
2413 */
2414 }
2415
2416
2417 /*
2418 * Set up the GUI data
2419 */
2420
2421 Length = min(wcslen(TermInfo.FaceName) + 1, LF_FACESIZE); // wcsnlen
2422 wcsncpy(GuiData->GuiInfo.FaceName, TermInfo.FaceName, LF_FACESIZE);
2423 GuiData->GuiInfo.FaceName[Length] = L'\0';
2424 GuiData->GuiInfo.FontFamily = TermInfo.FontFamily;
2425 GuiData->GuiInfo.FontSize = TermInfo.FontSize;
2426 GuiData->GuiInfo.FontWeight = TermInfo.FontWeight;
2427 GuiData->GuiInfo.UseRasterFonts = TermInfo.UseRasterFonts;
2428 GuiData->GuiInfo.ShowWindow = TermInfo.ShowWindow;
2429 GuiData->GuiInfo.AutoPosition = TermInfo.AutoPosition;
2430 GuiData->GuiInfo.WindowOrigin = TermInfo.WindowOrigin;
2431
2432 /* Initialize the icon handles to their default values */
2433 GuiData->hIcon = ghDefaultIcon;
2434 GuiData->hIconSm = ghDefaultIconSm;
2435
2436 /* Get the associated icon, if any */
2437 if (IconPath == NULL || *IconPath == L'\0')
2438 {
2439 IconPath = ConsoleStartInfo->AppPath;
2440 IconIndex = 0;
2441 }
2442 DPRINT1("IconPath = %S ; IconIndex = %lu\n", (IconPath ? IconPath : L"n/a"), IconIndex);
2443 if (IconPath)
2444 {
2445 HICON hIcon = NULL, hIconSm = NULL;
2446 PrivateExtractIconExW(IconPath,
2447 IconIndex,
2448 &hIcon,
2449 &hIconSm,
2450 1);
2451 DPRINT1("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon, hIconSm);
2452 if (hIcon != NULL)
2453 {
2454 DPRINT1("Effectively set the icons\n");
2455 GuiData->hIcon = hIcon;
2456 GuiData->hIconSm = hIconSm;
2457 }
2458 }
2459
2460 /*
2461 * We need to wait until the GUI has been fully initialized
2462 * to retrieve custom settings i.e. WindowSize etc...
2463 * Ideally we could use SendNotifyMessage for this but its not
2464 * yet implemented.
2465 */
2466 GuiData->hGuiInitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
2467
2468 /* Create the terminal window */
2469 PostMessageW(NotifyWnd, PM_CREATE_CONSOLE, GuiData->GuiInfo.ShowWindow, (LPARAM)GuiData);
2470
2471 /* Wait until initialization has finished */
2472 WaitForSingleObject(GuiData->hGuiInitEvent, INFINITE);
2473 DPRINT1("OK we created the console window\n");
2474 CloseHandle(GuiData->hGuiInitEvent);
2475 GuiData->hGuiInitEvent = NULL;
2476
2477 /* Check whether we really succeeded in initializing the terminal window */
2478 if (GuiData->hWindow == NULL)
2479 {
2480 DPRINT1("GuiInitConsole - We failed at creating a new terminal window\n");
2481 // ConioCleanupConsole(Console);
2482 GuiCleanupConsole(Console);
2483 return STATUS_UNSUCCESSFUL;
2484 }
2485
2486 return STATUS_SUCCESS;
2487 }
2488
2489 /* EOF */