740fc43a0000ef0b57009c3035bb9dbb7747e466
[reactos.git] / reactos / win32ss / user / winsrv / 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/winsrv/consrv/frontends/gui/guiterm.c
5 * PURPOSE: GUI Terminal Front-End
6 * PROGRAMMERS: Gé van Geldorp
7 * Johannes Anderwald
8 * Jeffrey Morlan
9 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
10 */
11
12 /* INCLUDES *******************************************************************/
13
14 #define COBJMACROS
15 #define NONAMELESSUNION
16
17 #include "consrv.h"
18 #include "include/conio.h"
19 #include "include/console.h"
20 #include "include/settings.h"
21 #include "conoutput.h"
22 #include "guiterm.h"
23 #include "guisettings.h"
24 #include "resource.h"
25
26 #include <windowsx.h>
27
28 #include <shlwapi.h>
29 #include <shlobj.h>
30
31 #define NDEBUG
32 #include <debug.h>
33
34 /* GUI Console Window Class name */
35 #define GUI_CONSOLE_WINDOW_CLASS L"ConsoleWindowClass"
36
37 #ifndef WM_APP
38 #define WM_APP 0x8000
39 #endif
40 #define PM_CREATE_CONSOLE (WM_APP + 1)
41 #define PM_DESTROY_CONSOLE (WM_APP + 2)
42 #define PM_RESIZE_TERMINAL (WM_APP + 3)
43 #define PM_CONSOLE_BEEP (WM_APP + 4)
44 #define PM_CONSOLE_SET_TITLE (WM_APP + 5)
45
46
47 /* Not defined in any header file */
48 extern VOID WINAPI PrivateCsrssManualGuiCheck(LONG Check);
49 // See winsrv/usersrv/init.c line 234
50
51
52 /* GLOBALS ********************************************************************/
53
54 typedef struct _GUI_INIT_INFO
55 {
56 PCONSOLE_INFO ConsoleInfo;
57 PCONSOLE_START_INFO ConsoleStartInfo;
58 ULONG ProcessId;
59 } GUI_INIT_INFO, *PGUI_INIT_INFO;
60
61 /**************************************************************\
62 \** Define the Console Leader Process for the console window **/
63 #define GWLP_CONSOLEWND_ALLOC (2 * sizeof(LONG_PTR))
64 #define GWLP_CONSOLE_LEADER_PID 0
65 #define GWLP_CONSOLE_LEADER_TID 4
66
67 #define SetConsoleWndConsoleLeaderCID(GuiData) \
68 do { \
69 PCONSOLE_PROCESS_DATA ProcessData; \
70 CLIENT_ID ConsoleLeaderCID; \
71 ProcessData = CONTAINING_RECORD((GuiData)->Console->ProcessList.Blink, \
72 CONSOLE_PROCESS_DATA, \
73 ConsoleLink); \
74 ConsoleLeaderCID = ProcessData->Process->ClientId; \
75 SetWindowLongPtrW((GuiData)->hWindow, GWLP_CONSOLE_LEADER_PID, \
76 (LONG_PTR)(ConsoleLeaderCID.UniqueProcess)); \
77 SetWindowLongPtrW((GuiData)->hWindow, GWLP_CONSOLE_LEADER_TID, \
78 (LONG_PTR)(ConsoleLeaderCID.UniqueThread )); \
79 } while (0)
80 /**************************************************************/
81
82 static BOOL ConsInitialized = FALSE;
83 static HICON ghDefaultIcon = NULL;
84 static HICON ghDefaultIconSm = NULL;
85 static HCURSOR ghDefaultCursor = NULL;
86 static HWND NotifyWnd = NULL;
87
88 typedef struct _GUICONSOLE_MENUITEM
89 {
90 UINT uID;
91 const struct _GUICONSOLE_MENUITEM *SubMenu;
92 WORD wCmdID;
93 } GUICONSOLE_MENUITEM, *PGUICONSOLE_MENUITEM;
94
95 static const GUICONSOLE_MENUITEM GuiConsoleEditMenuItems[] =
96 {
97 { IDS_MARK, NULL, ID_SYSTEM_EDIT_MARK },
98 { IDS_COPY, NULL, ID_SYSTEM_EDIT_COPY },
99 { IDS_PASTE, NULL, ID_SYSTEM_EDIT_PASTE },
100 { IDS_SELECTALL, NULL, ID_SYSTEM_EDIT_SELECTALL },
101 { IDS_SCROLL, NULL, ID_SYSTEM_EDIT_SCROLL },
102 { IDS_FIND, NULL, ID_SYSTEM_EDIT_FIND },
103
104 { 0, NULL, 0 } /* End of list */
105 };
106
107 static const GUICONSOLE_MENUITEM GuiConsoleMainMenuItems[] =
108 {
109 { IDS_EDIT, GuiConsoleEditMenuItems, 0 },
110 { IDS_DEFAULTS, NULL, ID_SYSTEM_DEFAULTS },
111 { IDS_PROPERTIES, NULL, ID_SYSTEM_PROPERTIES },
112
113 { 0, NULL, 0 } /* End of list */
114 };
115
116 /*
117 * Default 16-color palette for foreground and background
118 * (corresponding flags in comments).
119 */
120 const COLORREF s_Colors[16] =
121 {
122 RGB(0, 0, 0), // (Black)
123 RGB(0, 0, 128), // BLUE
124 RGB(0, 128, 0), // GREEN
125 RGB(0, 128, 128), // BLUE | GREEN
126 RGB(128, 0, 0), // RED
127 RGB(128, 0, 128), // BLUE | RED
128 RGB(128, 128, 0), // GREEN | RED
129 RGB(192, 192, 192), // BLUE | GREEN | RED
130
131 RGB(128, 128, 128), // (Grey) INTENSITY
132 RGB(0, 0, 255), // BLUE | INTENSITY
133 RGB(0, 255, 0), // GREEN | INTENSITY
134 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
135 RGB(255, 0, 0), // RED | INTENSITY
136 RGB(255, 0, 255), // BLUE | RED | INTENSITY
137 RGB(255, 255, 0), // GREEN | RED | INTENSITY
138 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
139 };
140
141 /* FUNCTIONS ******************************************************************/
142
143 static VOID
144 GetScreenBufferSizeUnits(IN PCONSOLE_SCREEN_BUFFER Buffer,
145 IN PGUI_CONSOLE_DATA GuiData,
146 OUT PUINT WidthUnit,
147 OUT PUINT HeightUnit)
148 {
149 if (Buffer == NULL || GuiData == NULL ||
150 WidthUnit == NULL || HeightUnit == NULL)
151 {
152 return;
153 }
154
155 if (GetType(Buffer) == TEXTMODE_BUFFER)
156 {
157 *WidthUnit = GuiData->CharWidth ;
158 *HeightUnit = GuiData->CharHeight;
159 }
160 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
161 {
162 *WidthUnit = 1;
163 *HeightUnit = 1;
164 }
165 }
166
167
168
169 static VOID
170 GuiConsoleAppendMenuItems(HMENU hMenu,
171 const GUICONSOLE_MENUITEM *Items)
172 {
173 UINT i = 0;
174 WCHAR szMenuString[255];
175 HMENU hSubMenu;
176
177 do
178 {
179 if (Items[i].uID != (UINT)-1)
180 {
181 if (LoadStringW(ConSrvDllInstance,
182 Items[i].uID,
183 szMenuString,
184 sizeof(szMenuString) / sizeof(szMenuString[0])) > 0)
185 {
186 if (Items[i].SubMenu != NULL)
187 {
188 hSubMenu = CreatePopupMenu();
189 if (hSubMenu != NULL)
190 {
191 GuiConsoleAppendMenuItems(hSubMenu,
192 Items[i].SubMenu);
193
194 if (!AppendMenuW(hMenu,
195 MF_STRING | MF_POPUP,
196 (UINT_PTR)hSubMenu,
197 szMenuString))
198 {
199 DestroyMenu(hSubMenu);
200 }
201 }
202 }
203 else
204 {
205 AppendMenuW(hMenu,
206 MF_STRING,
207 Items[i].wCmdID,
208 szMenuString);
209 }
210 }
211 }
212 else
213 {
214 AppendMenuW(hMenu,
215 MF_SEPARATOR,
216 0,
217 NULL);
218 }
219 i++;
220 } while (!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].wCmdID == 0));
221 }
222
223 static VOID
224 GuiConsoleCreateSysMenu(HWND hWnd)
225 {
226 HMENU hMenu = GetSystemMenu(hWnd, FALSE);
227 if (hMenu != NULL)
228 {
229 GuiConsoleAppendMenuItems(hMenu, GuiConsoleMainMenuItems);
230 DrawMenuBar(hWnd);
231 }
232 }
233
234 static VOID
235 GuiSendMenuEvent(PCONSOLE Console, UINT CmdId)
236 {
237 INPUT_RECORD er;
238
239 er.EventType = MENU_EVENT;
240 er.Event.MenuEvent.dwCommandId = CmdId;
241
242 ConioProcessInputEvent(Console, &er);
243 }
244
245 static VOID
246 GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData);
247 static VOID
248 GuiConsolePaste(PGUI_CONSOLE_DATA GuiData);
249 static VOID
250 GuiConsoleUpdateSelection(PCONSOLE Console, PCOORD coord);
251 static VOID WINAPI
252 GuiDrawRegion(IN OUT PFRONTEND This, SMALL_RECT* Region);
253 static VOID
254 GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData);
255
256
257 static LRESULT
258 GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
259 {
260 LRESULT Ret = TRUE;
261 PCONSOLE Console = GuiData->Console;
262 PCONSOLE_SCREEN_BUFFER ActiveBuffer;
263
264 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
265 {
266 Ret = FALSE;
267 goto Quit;
268 }
269 // ActiveBuffer = ConDrvGetActiveScreenBuffer(Console);
270 ActiveBuffer = GuiData->ActiveBuffer;
271
272 /*
273 * In case the selected menu item belongs to the user-reserved menu id range,
274 * send to him a menu event and return directly. The user must handle those
275 * reserved menu commands...
276 */
277 if (GuiData->cmdIdLow <= (UINT)wParam && (UINT)wParam <= GuiData->cmdIdHigh)
278 {
279 GuiSendMenuEvent(Console, (UINT)wParam);
280 goto Unlock_Quit;
281 }
282
283 /* ... otherwise, perform actions. */
284 switch (wParam)
285 {
286 case ID_SYSTEM_EDIT_MARK:
287 {
288 LPWSTR WindowTitle = NULL;
289 SIZE_T Length = 0;
290
291 Console->dwSelectionCursor.X = ActiveBuffer->ViewOrigin.X;
292 Console->dwSelectionCursor.Y = ActiveBuffer->ViewOrigin.Y;
293 Console->Selection.dwSelectionAnchor = Console->dwSelectionCursor;
294 Console->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS;
295 GuiConsoleUpdateSelection(Console, &Console->Selection.dwSelectionAnchor);
296
297 Length = Console->Title.Length + sizeof(L"Mark - ")/sizeof(WCHAR) + 1;
298 WindowTitle = ConsoleAllocHeap(0, Length * sizeof(WCHAR));
299 wcscpy(WindowTitle, L"Mark - ");
300 wcscat(WindowTitle, Console->Title.Buffer);
301 SetWindowText(GuiData->hWindow, WindowTitle);
302 ConsoleFreeHeap(WindowTitle);
303
304 break;
305 }
306
307 case ID_SYSTEM_EDIT_COPY:
308 GuiConsoleCopy(GuiData);
309 break;
310
311 case ID_SYSTEM_EDIT_PASTE:
312 GuiConsolePaste(GuiData);
313 break;
314
315 case ID_SYSTEM_EDIT_SELECTALL:
316 {
317 LPWSTR WindowTitle = NULL;
318 SIZE_T Length = 0;
319
320 /*
321 * We select all the characters from line 1 to
322 * the line where the cursor is positioned.
323 */
324 Console->Selection.dwSelectionAnchor.X = 0;
325 Console->Selection.dwSelectionAnchor.Y = 0;
326 Console->dwSelectionCursor.X = ActiveBuffer->ViewSize.X - 1;
327 Console->dwSelectionCursor.Y = ActiveBuffer->CursorPosition.Y;
328 Console->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS | CONSOLE_MOUSE_SELECTION;
329 GuiConsoleUpdateSelection(Console, &Console->dwSelectionCursor);
330
331 Length = Console->Title.Length + sizeof(L"Selection - ")/sizeof(WCHAR) + 1;
332 WindowTitle = ConsoleAllocHeap(0, Length * sizeof(WCHAR));
333 wcscpy(WindowTitle, L"Selection - ");
334 wcscat(WindowTitle, Console->Title.Buffer);
335 SetWindowText(GuiData->hWindow, WindowTitle);
336 ConsoleFreeHeap(WindowTitle);
337
338 break;
339 }
340
341 case ID_SYSTEM_EDIT_SCROLL:
342 DPRINT1("Scrolling is not handled yet\n");
343 break;
344
345 case ID_SYSTEM_EDIT_FIND:
346 DPRINT1("Finding is not handled yet\n");
347 break;
348
349 case ID_SYSTEM_DEFAULTS:
350 GuiConsoleShowConsoleProperties(GuiData, TRUE);
351 break;
352
353 case ID_SYSTEM_PROPERTIES:
354 GuiConsoleShowConsoleProperties(GuiData, FALSE);
355 break;
356
357 default:
358 Ret = FALSE;
359 break;
360 }
361
362 Unlock_Quit:
363 LeaveCriticalSection(&Console->Lock);
364 Quit:
365 if (!Ret)
366 Ret = DefWindowProcW(GuiData->hWindow, WM_SYSCOMMAND, wParam, lParam);
367
368 return Ret;
369 }
370
371 static PGUI_CONSOLE_DATA
372 GuiGetGuiData(HWND hWnd)
373 {
374 /* This function ensures that the console pointer is not NULL */
375 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
376 return ( ((GuiData == NULL) || (GuiData->hWindow == hWnd && GuiData->Console != NULL)) ? GuiData : NULL );
377 }
378
379 VOID
380 GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData)
381 {
382 /* Move the window if needed (not positioned by the system) */
383 if (!GuiData->GuiInfo.AutoPosition)
384 {
385 SetWindowPos(GuiData->hWindow,
386 NULL,
387 GuiData->GuiInfo.WindowOrigin.x,
388 GuiData->GuiInfo.WindowOrigin.y,
389 0,
390 0,
391 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
392 }
393 }
394
395 static VOID
396 GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData)
397 {
398 // PCONSOLE Console = GuiData->Console;
399 PCONSOLE_SCREEN_BUFFER Buff = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(Console);
400 SCROLLINFO sInfo;
401
402 DWORD Width, Height;
403 UINT WidthUnit, HeightUnit;
404
405 GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit);
406
407 Width = Buff->ViewSize.X * WidthUnit +
408 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
409 Height = Buff->ViewSize.Y * HeightUnit +
410 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
411
412 /* Set scrollbar sizes */
413 sInfo.cbSize = sizeof(SCROLLINFO);
414 sInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
415 sInfo.nMin = 0;
416 if (Buff->ScreenBufferSize.Y > Buff->ViewSize.Y)
417 {
418 sInfo.nMax = Buff->ScreenBufferSize.Y - 1;
419 sInfo.nPage = Buff->ViewSize.Y;
420 sInfo.nPos = Buff->ViewOrigin.Y;
421 SetScrollInfo(GuiData->hWindow, SB_VERT, &sInfo, TRUE);
422 Width += GetSystemMetrics(SM_CXVSCROLL);
423 ShowScrollBar(GuiData->hWindow, SB_VERT, TRUE);
424 }
425 else
426 {
427 ShowScrollBar(GuiData->hWindow, SB_VERT, FALSE);
428 }
429
430 if (Buff->ScreenBufferSize.X > Buff->ViewSize.X)
431 {
432 sInfo.nMax = Buff->ScreenBufferSize.X - 1;
433 sInfo.nPage = Buff->ViewSize.X;
434 sInfo.nPos = Buff->ViewOrigin.X;
435 SetScrollInfo(GuiData->hWindow, SB_HORZ, &sInfo, TRUE);
436 Height += GetSystemMetrics(SM_CYHSCROLL);
437 ShowScrollBar(GuiData->hWindow, SB_HORZ, TRUE);
438 }
439 else
440 {
441 ShowScrollBar(GuiData->hWindow, SB_HORZ, FALSE);
442 }
443
444 /* Resize the window */
445 SetWindowPos(GuiData->hWindow, NULL, 0, 0, Width, Height,
446 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOCOPYBITS);
447 // NOTE: The SWP_NOCOPYBITS flag can be replaced by a subsequent call
448 // to: InvalidateRect(GuiData->hWindow, NULL, TRUE);
449 }
450
451 static VOID
452 GuiConsoleSwitchFullScreen(PGUI_CONSOLE_DATA GuiData)
453 {
454 PCONSOLE Console = GuiData->Console;
455 // DEVMODE dmScreenSettings;
456
457 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
458
459 /* Switch to full-screen or to windowed mode */
460 GuiData->GuiInfo.FullScreen = !GuiData->GuiInfo.FullScreen;
461 DPRINT1("GuiConsoleSwitchFullScreen - Switch to %s ...\n",
462 (GuiData->GuiInfo.FullScreen ? "full-screen" : "windowed mode"));
463
464 // TODO: Change window appearance.
465 // See:
466 // http://stackoverflow.com/questions/2382464/win32-full-screen-and-hiding-taskbar
467 // http://stackoverflow.com/questions/3549148/fullscreen-management-with-winapi
468 // http://blogs.msdn.com/b/oldnewthing/archive/2010/04/12/9994016.aspx
469 // http://stackoverflow.com/questions/1400654/how-do-i-put-my-opengl-app-into-fullscreen-mode
470 // http://nehe.gamedev.net/tutorial/creating_an_opengl_window_win32/13001/
471 #if 0
472 if (GuiData->GuiInfo.FullScreen)
473 {
474 memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
475 dmScreenSettings.dmSize = sizeof(dmScreenSettings);
476 dmScreenSettings.dmDisplayFixedOutput = DMDFO_CENTER; // DMDFO_STRETCH // DMDFO_DEFAULT
477 dmScreenSettings.dmPelsWidth = 640; // GuiData->ActiveBuffer->ViewSize.X * GuiData->CharWidth;
478 dmScreenSettings.dmPelsHeight = 480; // GuiData->ActiveBuffer->ViewSize.Y * GuiData->CharHeight;
479 dmScreenSettings.dmBitsPerPel = 32;
480 dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
481 ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
482 }
483 else
484 {
485 }
486 #endif
487
488 LeaveCriticalSection(&Console->Lock);
489 }
490
491 static BOOL
492 GuiConsoleHandleNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
493 {
494 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)Create->lpCreateParams;
495 PCONSOLE Console;
496 HDC Dc;
497 HFONT OldFont;
498 TEXTMETRICW Metrics;
499 SIZE CharSize;
500
501 DPRINT("GuiConsoleHandleNcCreate\n");
502
503 if (NULL == GuiData)
504 {
505 DPRINT1("GuiConsoleNcCreate: No GUI data\n");
506 return FALSE;
507 }
508
509 Console = GuiData->Console;
510
511 GuiData->hWindow = hWnd;
512
513 GuiData->Font = CreateFontW(LOWORD(GuiData->GuiInfo.FontSize),
514 0, // HIWORD(GuiData->GuiInfo.FontSize),
515 0,
516 TA_BASELINE,
517 GuiData->GuiInfo.FontWeight,
518 FALSE,
519 FALSE,
520 FALSE,
521 OEM_CHARSET,
522 OUT_DEFAULT_PRECIS,
523 CLIP_DEFAULT_PRECIS,
524 NONANTIALIASED_QUALITY,
525 FIXED_PITCH | GuiData->GuiInfo.FontFamily /* FF_DONTCARE */,
526 GuiData->GuiInfo.FaceName);
527
528 if (NULL == GuiData->Font)
529 {
530 DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
531 GuiData->hWindow = NULL;
532 SetEvent(GuiData->hGuiInitEvent);
533 return FALSE;
534 }
535 Dc = GetDC(GuiData->hWindow);
536 if (NULL == Dc)
537 {
538 DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
539 DeleteObject(GuiData->Font);
540 GuiData->hWindow = NULL;
541 SetEvent(GuiData->hGuiInitEvent);
542 return FALSE;
543 }
544 OldFont = SelectObject(Dc, GuiData->Font);
545 if (NULL == OldFont)
546 {
547 DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
548 ReleaseDC(GuiData->hWindow, Dc);
549 DeleteObject(GuiData->Font);
550 GuiData->hWindow = NULL;
551 SetEvent(GuiData->hGuiInitEvent);
552 return FALSE;
553 }
554 if (!GetTextMetricsW(Dc, &Metrics))
555 {
556 DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
557 SelectObject(Dc, OldFont);
558 ReleaseDC(GuiData->hWindow, Dc);
559 DeleteObject(GuiData->Font);
560 GuiData->hWindow = NULL;
561 SetEvent(GuiData->hGuiInitEvent);
562 return FALSE;
563 }
564 GuiData->CharWidth = Metrics.tmMaxCharWidth;
565 GuiData->CharHeight = Metrics.tmHeight + Metrics.tmExternalLeading;
566
567 /* Measure real char width more precisely if possible. */
568 if (GetTextExtentPoint32W(Dc, L"R", 1, &CharSize))
569 GuiData->CharWidth = CharSize.cx;
570
571 SelectObject(Dc, OldFont);
572
573 ReleaseDC(GuiData->hWindow, Dc);
574
575 // FIXME: Keep these instructions here ? ///////////////////////////////////
576 Console->ActiveBuffer->CursorBlinkOn = TRUE;
577 Console->ActiveBuffer->ForceCursorOff = FALSE;
578 ////////////////////////////////////////////////////////////////////////////
579
580 SetWindowLongPtrW(GuiData->hWindow, GWLP_USERDATA, (DWORD_PTR)GuiData);
581
582 SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
583 GuiConsoleCreateSysMenu(GuiData->hWindow);
584
585 DPRINT("GuiConsoleHandleNcCreate - setting start event\n");
586 SetEvent(GuiData->hGuiInitEvent);
587
588 return (BOOL)DefWindowProcW(GuiData->hWindow, WM_NCCREATE, 0, (LPARAM)Create);
589 }
590
591 static VOID
592 SmallRectToRect(PGUI_CONSOLE_DATA GuiData, PRECT Rect, PSMALL_RECT SmallRect)
593 {
594 // PCONSOLE Console = GuiData->Console;
595 PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(Console);
596 UINT WidthUnit, HeightUnit;
597
598 GetScreenBufferSizeUnits(Buffer, GuiData, &WidthUnit, &HeightUnit);
599
600 Rect->left = (SmallRect->Left - Buffer->ViewOrigin.X) * WidthUnit ;
601 Rect->top = (SmallRect->Top - Buffer->ViewOrigin.Y) * HeightUnit;
602 Rect->right = (SmallRect->Right + 1 - Buffer->ViewOrigin.X) * WidthUnit ;
603 Rect->bottom = (SmallRect->Bottom + 1 - Buffer->ViewOrigin.Y) * HeightUnit;
604 }
605
606 static VOID
607 GuiConsoleUpdateSelection(PCONSOLE Console, PCOORD coord)
608 {
609 PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data;
610 RECT oldRect, newRect;
611
612 SmallRectToRect(GuiData, &oldRect, &Console->Selection.srSelection);
613
614 if (coord != NULL)
615 {
616 SMALL_RECT rc;
617 /* exchange left/top with right/bottom if required */
618 rc.Left = min(Console->Selection.dwSelectionAnchor.X, coord->X);
619 rc.Top = min(Console->Selection.dwSelectionAnchor.Y, coord->Y);
620 rc.Right = max(Console->Selection.dwSelectionAnchor.X, coord->X);
621 rc.Bottom = max(Console->Selection.dwSelectionAnchor.Y, coord->Y);
622
623 SmallRectToRect(GuiData, &newRect, &rc);
624
625 if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
626 {
627 if (memcmp(&rc, &Console->Selection.srSelection, sizeof(SMALL_RECT)) != 0)
628 {
629 HRGN rgn1, rgn2;
630
631 /* calculate the region that needs to be updated */
632 if ((rgn1 = CreateRectRgnIndirect(&oldRect)))
633 {
634 if ((rgn2 = CreateRectRgnIndirect(&newRect)))
635 {
636 if (CombineRgn(rgn1, rgn2, rgn1, RGN_XOR) != ERROR)
637 {
638 InvalidateRgn(GuiData->hWindow, rgn1, FALSE);
639 }
640 DeleteObject(rgn2);
641 }
642 DeleteObject(rgn1);
643 }
644 }
645 }
646 else
647 {
648 InvalidateRect(GuiData->hWindow, &newRect, FALSE);
649 }
650 Console->Selection.dwFlags |= CONSOLE_SELECTION_NOT_EMPTY;
651 Console->Selection.srSelection = rc;
652 Console->dwSelectionCursor = *coord;
653 ConioPause(Console, PAUSED_FROM_SELECTION);
654 }
655 else
656 {
657 /* clear the selection */
658 if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
659 {
660 InvalidateRect(GuiData->hWindow, &oldRect, FALSE);
661 }
662 Console->Selection.dwFlags = CONSOLE_NO_SELECTION;
663 ConioUnpause(Console, PAUSED_FROM_SELECTION);
664 }
665 }
666
667
668 VOID
669 GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
670 PGUI_CONSOLE_DATA GuiData,
671 HDC hDC,
672 PRECT rc);
673 VOID
674 GuiPaintGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer,
675 PGUI_CONSOLE_DATA GuiData,
676 HDC hDC,
677 PRECT rc);
678
679 static VOID
680 GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData)
681 {
682 BOOL Success = TRUE;
683 PCONSOLE Console = GuiData->Console;
684 PCONSOLE_SCREEN_BUFFER ActiveBuffer;
685 HDC hDC;
686 PAINTSTRUCT ps;
687
688 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
689 {
690 Success = FALSE;
691 goto Quit;
692 }
693 // ActiveBuffer = ConDrvGetActiveScreenBuffer(Console);
694 ActiveBuffer = GuiData->ActiveBuffer;
695
696 hDC = BeginPaint(GuiData->hWindow, &ps);
697 if (hDC != NULL &&
698 ps.rcPaint.left < ps.rcPaint.right &&
699 ps.rcPaint.top < ps.rcPaint.bottom)
700 {
701 EnterCriticalSection(&GuiData->Lock);
702
703 if (GetType(ActiveBuffer) == TEXTMODE_BUFFER)
704 {
705 GuiPaintTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)ActiveBuffer,
706 GuiData, hDC, &ps.rcPaint);
707 }
708 else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
709 {
710 GuiPaintGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)ActiveBuffer,
711 GuiData, hDC, &ps.rcPaint);
712 }
713
714 if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
715 {
716 RECT rc;
717 SmallRectToRect(GuiData, &rc, &Console->Selection.srSelection);
718
719 /* invert the selection */
720 if (IntersectRect(&rc, &ps.rcPaint, &rc))
721 {
722 PatBlt(hDC,
723 rc.left,
724 rc.top,
725 rc.right - rc.left,
726 rc.bottom - rc.top,
727 DSTINVERT);
728 }
729 }
730
731 LeaveCriticalSection(&GuiData->Lock);
732 }
733 EndPaint(GuiData->hWindow, &ps);
734
735 Quit:
736 if (Success)
737 LeaveCriticalSection(&Console->Lock);
738 else
739 DefWindowProcW(GuiData->hWindow, WM_PAINT, 0, 0);
740
741 return;
742 }
743
744 static BOOL
745 IsSystemKey(WORD VirtualKeyCode)
746 {
747 switch (VirtualKeyCode)
748 {
749 /* From MSDN, "Virtual-Key Codes" */
750 case VK_RETURN:
751 case VK_SHIFT:
752 case VK_CONTROL:
753 case VK_MENU:
754 case VK_PAUSE:
755 case VK_CAPITAL:
756 case VK_ESCAPE:
757 case VK_LWIN:
758 case VK_RWIN:
759 case VK_NUMLOCK:
760 case VK_SCROLL:
761 return TRUE;
762 default:
763 return FALSE;
764 }
765 }
766
767 static VOID
768 GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
769 {
770 PCONSOLE Console = GuiData->Console;
771 PCONSOLE_SCREEN_BUFFER ActiveBuffer;
772
773 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
774
775 // ActiveBuffer = ConDrvGetActiveScreenBuffer(Console);
776 ActiveBuffer = GuiData->ActiveBuffer;
777
778 if (Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS)
779 {
780 WORD VirtualKeyCode = LOWORD(wParam);
781
782 if (msg != WM_KEYDOWN) goto Quit;
783
784 if (VirtualKeyCode == VK_RETURN)
785 {
786 /* Copy (and clear) selection if ENTER is pressed */
787 GuiConsoleCopy(GuiData);
788 goto Quit;
789 }
790 else if ( VirtualKeyCode == VK_ESCAPE ||
791 (VirtualKeyCode == 'C' && GetKeyState(VK_CONTROL) & 0x8000) )
792 {
793 /* Cancel selection if ESC or Ctrl-C are pressed */
794 GuiConsoleUpdateSelection(Console, NULL);
795 SetWindowText(GuiData->hWindow, Console->Title.Buffer);
796
797 goto Quit;
798 }
799
800 if ((Console->Selection.dwFlags & CONSOLE_MOUSE_SELECTION) == 0)
801 {
802 /* Keyboard selection mode */
803 BOOL Interpreted = FALSE;
804 BOOL MajPressed = (GetKeyState(VK_SHIFT) & 0x8000);
805
806 switch (VirtualKeyCode)
807 {
808 case VK_LEFT:
809 {
810 Interpreted = TRUE;
811 if (Console->dwSelectionCursor.X > 0)
812 Console->dwSelectionCursor.X--;
813
814 break;
815 }
816
817 case VK_RIGHT:
818 {
819 Interpreted = TRUE;
820 if (Console->dwSelectionCursor.X < ActiveBuffer->ScreenBufferSize.X - 1)
821 Console->dwSelectionCursor.X++;
822
823 break;
824 }
825
826 case VK_UP:
827 {
828 Interpreted = TRUE;
829 if (Console->dwSelectionCursor.Y > 0)
830 Console->dwSelectionCursor.Y--;
831
832 break;
833 }
834
835 case VK_DOWN:
836 {
837 Interpreted = TRUE;
838 if (Console->dwSelectionCursor.Y < ActiveBuffer->ScreenBufferSize.Y - 1)
839 Console->dwSelectionCursor.Y++;
840
841 break;
842 }
843
844 case VK_HOME:
845 {
846 Interpreted = TRUE;
847 Console->dwSelectionCursor.X = 0;
848 Console->dwSelectionCursor.Y = 0;
849 break;
850 }
851
852 case VK_END:
853 {
854 Interpreted = TRUE;
855 Console->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1;
856 break;
857 }
858
859 case VK_PRIOR:
860 {
861 Interpreted = TRUE;
862 Console->dwSelectionCursor.Y -= ActiveBuffer->ViewSize.Y;
863 if (Console->dwSelectionCursor.Y < 0)
864 Console->dwSelectionCursor.Y = 0;
865
866 break;
867 }
868
869 case VK_NEXT:
870 {
871 Interpreted = TRUE;
872 Console->dwSelectionCursor.Y += ActiveBuffer->ViewSize.Y;
873 if (Console->dwSelectionCursor.Y >= ActiveBuffer->ScreenBufferSize.Y)
874 Console->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1;
875
876 break;
877 }
878
879 default:
880 break;
881 }
882
883 if (Interpreted)
884 {
885 if (!MajPressed)
886 Console->Selection.dwSelectionAnchor = Console->dwSelectionCursor;
887
888 GuiConsoleUpdateSelection(Console, &Console->dwSelectionCursor);
889 }
890 else if (!IsSystemKey(VirtualKeyCode))
891 {
892 /* Emit an error beep sound */
893 SendNotifyMessage(GuiData->hWindow, PM_CONSOLE_BEEP, 0, 0);
894 }
895
896 goto Quit;
897 }
898 else
899 {
900 /* Mouse selection mode */
901
902 if (!IsSystemKey(VirtualKeyCode))
903 {
904 /* Clear the selection and send the key into the input buffer */
905 GuiConsoleUpdateSelection(Console, NULL);
906 SetWindowText(GuiData->hWindow, Console->Title.Buffer);
907 }
908 else
909 {
910 goto Quit;
911 }
912 }
913 }
914
915 if ((Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) == 0)
916 {
917 MSG Message;
918
919 Message.hwnd = GuiData->hWindow;
920 Message.message = msg;
921 Message.wParam = wParam;
922 Message.lParam = lParam;
923
924 ConioProcessKey(Console, &Message);
925 }
926
927 Quit:
928 LeaveCriticalSection(&Console->Lock);
929 }
930
931 static VOID
932 GuiInvalidateCell(IN OUT PFRONTEND This, SHORT x, SHORT y)
933 {
934 SMALL_RECT CellRect = { x, y, x, y };
935 GuiDrawRegion(This, &CellRect);
936 }
937
938 static VOID
939 GuiConsoleHandleTimer(PGUI_CONSOLE_DATA GuiData)
940 {
941 PCONSOLE Console = GuiData->Console;
942 PCONSOLE_SCREEN_BUFFER Buff;
943
944 SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CURSOR_BLINK_TIME, NULL);
945
946 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
947
948 Buff = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(Console);
949
950 if (GetType(Buff) == TEXTMODE_BUFFER)
951 {
952 GuiInvalidateCell(&Console->TermIFace, Buff->CursorPosition.X, Buff->CursorPosition.Y);
953 Buff->CursorBlinkOn = !Buff->CursorBlinkOn;
954
955 if ((GuiData->OldCursor.x != Buff->CursorPosition.X) || (GuiData->OldCursor.y != Buff->CursorPosition.Y))
956 {
957 SCROLLINFO xScroll;
958 int OldScrollX = -1, OldScrollY = -1;
959 int NewScrollX = -1, NewScrollY = -1;
960
961 xScroll.cbSize = sizeof(SCROLLINFO);
962 xScroll.fMask = SIF_POS;
963 // Capture the original position of the scroll bars and save them.
964 if (GetScrollInfo(GuiData->hWindow, SB_HORZ, &xScroll)) OldScrollX = xScroll.nPos;
965 if (GetScrollInfo(GuiData->hWindow, SB_VERT, &xScroll)) OldScrollY = xScroll.nPos;
966
967 // If we successfully got the info for the horizontal scrollbar
968 if (OldScrollX >= 0)
969 {
970 if ((Buff->CursorPosition.X < Buff->ViewOrigin.X) || (Buff->CursorPosition.X >= (Buff->ViewOrigin.X + Buff->ViewSize.X)))
971 {
972 // Handle the horizontal scroll bar
973 if (Buff->CursorPosition.X >= Buff->ViewSize.X) NewScrollX = Buff->CursorPosition.X - Buff->ViewSize.X + 1;
974 else NewScrollX = 0;
975 }
976 else
977 {
978 NewScrollX = OldScrollX;
979 }
980 }
981 // If we successfully got the info for the vertical scrollbar
982 if (OldScrollY >= 0)
983 {
984 if ((Buff->CursorPosition.Y < Buff->ViewOrigin.Y) || (Buff->CursorPosition.Y >= (Buff->ViewOrigin.Y + Buff->ViewSize.Y)))
985 {
986 // Handle the vertical scroll bar
987 if (Buff->CursorPosition.Y >= Buff->ViewSize.Y) NewScrollY = Buff->CursorPosition.Y - Buff->ViewSize.Y + 1;
988 else NewScrollY = 0;
989 }
990 else
991 {
992 NewScrollY = OldScrollY;
993 }
994 }
995
996 // Adjust scroll bars and refresh the window if the cursor has moved outside the visible area
997 // NOTE: OldScroll# and NewScroll# will both be -1 (initial value) if the info for the respective scrollbar
998 // was not obtained successfully in the previous steps. This means their difference is 0 (no scrolling)
999 // and their associated scrollbar is left alone.
1000 if ((OldScrollX != NewScrollX) || (OldScrollY != NewScrollY))
1001 {
1002 Buff->ViewOrigin.X = NewScrollX;
1003 Buff->ViewOrigin.Y = NewScrollY;
1004 ScrollWindowEx(GuiData->hWindow,
1005 (OldScrollX - NewScrollX) * GuiData->CharWidth,
1006 (OldScrollY - NewScrollY) * GuiData->CharHeight,
1007 NULL,
1008 NULL,
1009 NULL,
1010 NULL,
1011 SW_INVALIDATE);
1012 if (NewScrollX >= 0)
1013 {
1014 xScroll.nPos = NewScrollX;
1015 SetScrollInfo(GuiData->hWindow, SB_HORZ, &xScroll, TRUE);
1016 }
1017 if (NewScrollY >= 0)
1018 {
1019 xScroll.nPos = NewScrollY;
1020 SetScrollInfo(GuiData->hWindow, SB_VERT, &xScroll, TRUE);
1021 }
1022 UpdateWindow(GuiData->hWindow);
1023 GuiData->OldCursor.x = Buff->CursorPosition.X;
1024 GuiData->OldCursor.y = Buff->CursorPosition.Y;
1025 }
1026 }
1027 }
1028 else /* if (GetType(Buff) == GRAPHICS_BUFFER) */
1029 {
1030 }
1031
1032 LeaveCriticalSection(&Console->Lock);
1033 }
1034
1035 static BOOL
1036 GuiConsoleHandleClose(PGUI_CONSOLE_DATA GuiData)
1037 {
1038 PCONSOLE Console = GuiData->Console;
1039
1040 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
1041 return TRUE;
1042
1043 // TODO: Prompt for termination ? (Warn the user about possible apps running in this console)
1044
1045 /*
1046 * FIXME: Windows will wait up to 5 seconds for the thread to exit.
1047 * We shouldn't wait here, though, since the console lock is entered.
1048 * A copy of the thread list probably needs to be made.
1049 */
1050 ConDrvConsoleProcessCtrlEvent(Console, 0, CTRL_CLOSE_EVENT);
1051
1052 LeaveCriticalSection(&Console->Lock);
1053 return FALSE;
1054 }
1055
1056 static LRESULT
1057 GuiConsoleHandleNcDestroy(HWND hWnd)
1058 {
1059 KillTimer(hWnd, CONGUI_UPDATE_TIMER);
1060 GetSystemMenu(hWnd, TRUE);
1061
1062 /* Free the GuiData registration */
1063 SetWindowLongPtrW(hWnd, GWLP_USERDATA, (DWORD_PTR)NULL);
1064
1065 return DefWindowProcW(hWnd, WM_NCDESTROY, 0, 0);
1066 }
1067
1068 static COORD
1069 PointToCoord(PGUI_CONSOLE_DATA GuiData, LPARAM lParam)
1070 {
1071 // PCONSOLE Console = GuiData->Console;
1072 PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(Console);
1073 COORD Coord;
1074 UINT WidthUnit, HeightUnit;
1075
1076 GetScreenBufferSizeUnits(Buffer, GuiData, &WidthUnit, &HeightUnit);
1077
1078 Coord.X = Buffer->ViewOrigin.X + ((SHORT)LOWORD(lParam) / (int)WidthUnit );
1079 Coord.Y = Buffer->ViewOrigin.Y + ((SHORT)HIWORD(lParam) / (int)HeightUnit);
1080
1081 /* Clip coordinate to ensure it's inside buffer */
1082 if (Coord.X < 0)
1083 Coord.X = 0;
1084 else if (Coord.X >= Buffer->ScreenBufferSize.X)
1085 Coord.X = Buffer->ScreenBufferSize.X - 1;
1086
1087 if (Coord.Y < 0)
1088 Coord.Y = 0;
1089 else if (Coord.Y >= Buffer->ScreenBufferSize.Y)
1090 Coord.Y = Buffer->ScreenBufferSize.Y - 1;
1091
1092 return Coord;
1093 }
1094
1095 static LRESULT
1096 GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
1097 {
1098 BOOL Err = FALSE;
1099 PCONSOLE Console = GuiData->Console;
1100
1101 if (GuiData->IgnoreNextMouseSignal)
1102 {
1103 if (msg != WM_LBUTTONDOWN &&
1104 msg != WM_MBUTTONDOWN &&
1105 msg != WM_RBUTTONDOWN)
1106 {
1107 /*
1108 * If this mouse signal is not a button-down action,
1109 * then it is the last signal being ignored.
1110 */
1111 GuiData->IgnoreNextMouseSignal = FALSE;
1112 }
1113 else
1114 {
1115 /*
1116 * This mouse signal is a button-down action.
1117 * Ignore it and perform default action.
1118 */
1119 Err = TRUE;
1120 }
1121 goto Quit;
1122 }
1123
1124 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
1125 {
1126 Err = TRUE;
1127 goto Quit;
1128 }
1129
1130 if ( (Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) ||
1131 (Console->QuickEdit) )
1132 {
1133 switch (msg)
1134 {
1135 case WM_LBUTTONDOWN:
1136 {
1137 LPWSTR WindowTitle = NULL;
1138 SIZE_T Length = 0;
1139
1140 Console->Selection.dwSelectionAnchor = PointToCoord(GuiData, lParam);
1141 SetCapture(GuiData->hWindow);
1142 Console->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS | CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
1143 GuiConsoleUpdateSelection(Console, &Console->Selection.dwSelectionAnchor);
1144
1145 Length = Console->Title.Length + sizeof(L"Selection - ")/sizeof(WCHAR) + 1;
1146 WindowTitle = ConsoleAllocHeap(0, Length * sizeof(WCHAR));
1147 wcscpy(WindowTitle, L"Selection - ");
1148 wcscat(WindowTitle, Console->Title.Buffer);
1149 SetWindowText(GuiData->hWindow, WindowTitle);
1150 ConsoleFreeHeap(WindowTitle);
1151
1152 break;
1153 }
1154
1155 case WM_LBUTTONUP:
1156 {
1157 COORD c;
1158
1159 if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
1160
1161 c = PointToCoord(GuiData, lParam);
1162 Console->Selection.dwFlags &= ~CONSOLE_MOUSE_DOWN;
1163 GuiConsoleUpdateSelection(Console, &c);
1164 ReleaseCapture();
1165
1166 break;
1167 }
1168
1169 case WM_LBUTTONDBLCLK:
1170 {
1171 DPRINT1("Handle left-double-click for selecting a word\n");
1172 break;
1173 }
1174
1175 case WM_RBUTTONDOWN:
1176 case WM_RBUTTONDBLCLK:
1177 {
1178 if (!(Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY))
1179 {
1180 GuiConsolePaste(GuiData);
1181 }
1182 else
1183 {
1184 GuiConsoleCopy(GuiData);
1185 }
1186
1187 GuiData->IgnoreNextMouseSignal = TRUE;
1188 break;
1189 }
1190
1191 case WM_MOUSEMOVE:
1192 {
1193 COORD c;
1194
1195 if (!(wParam & MK_LBUTTON)) break;
1196 if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
1197
1198 c = PointToCoord(GuiData, lParam); /* TODO: Scroll buffer to bring c into view */
1199 GuiConsoleUpdateSelection(Console, &c);
1200
1201 break;
1202 }
1203
1204 default:
1205 Err = FALSE; // TRUE;
1206 break;
1207 }
1208 }
1209 else if (Console->InputBuffer.Mode & ENABLE_MOUSE_INPUT)
1210 {
1211 INPUT_RECORD er;
1212 WORD wKeyState = GET_KEYSTATE_WPARAM(wParam);
1213 DWORD dwButtonState = 0;
1214 DWORD dwControlKeyState = 0;
1215 DWORD dwEventFlags = 0;
1216
1217 switch (msg)
1218 {
1219 case WM_LBUTTONDOWN:
1220 SetCapture(GuiData->hWindow);
1221 dwButtonState = FROM_LEFT_1ST_BUTTON_PRESSED;
1222 dwEventFlags = 0;
1223 break;
1224
1225 case WM_MBUTTONDOWN:
1226 SetCapture(GuiData->hWindow);
1227 dwButtonState = FROM_LEFT_2ND_BUTTON_PRESSED;
1228 dwEventFlags = 0;
1229 break;
1230
1231 case WM_RBUTTONDOWN:
1232 SetCapture(GuiData->hWindow);
1233 dwButtonState = RIGHTMOST_BUTTON_PRESSED;
1234 dwEventFlags = 0;
1235 break;
1236
1237 case WM_LBUTTONUP:
1238 ReleaseCapture();
1239 dwButtonState = 0;
1240 dwEventFlags = 0;
1241 break;
1242
1243 case WM_MBUTTONUP:
1244 ReleaseCapture();
1245 dwButtonState = 0;
1246 dwEventFlags = 0;
1247 break;
1248
1249 case WM_RBUTTONUP:
1250 ReleaseCapture();
1251 dwButtonState = 0;
1252 dwEventFlags = 0;
1253 break;
1254
1255 case WM_LBUTTONDBLCLK:
1256 dwButtonState = FROM_LEFT_1ST_BUTTON_PRESSED;
1257 dwEventFlags = DOUBLE_CLICK;
1258 break;
1259
1260 case WM_MBUTTONDBLCLK:
1261 dwButtonState = FROM_LEFT_2ND_BUTTON_PRESSED;
1262 dwEventFlags = DOUBLE_CLICK;
1263 break;
1264
1265 case WM_RBUTTONDBLCLK:
1266 dwButtonState = RIGHTMOST_BUTTON_PRESSED;
1267 dwEventFlags = DOUBLE_CLICK;
1268 break;
1269
1270 case WM_MOUSEMOVE:
1271 dwButtonState = 0;
1272 dwEventFlags = MOUSE_MOVED;
1273 break;
1274
1275 case WM_MOUSEWHEEL:
1276 dwButtonState = GET_WHEEL_DELTA_WPARAM(wParam) << 16;
1277 dwEventFlags = MOUSE_WHEELED;
1278 break;
1279
1280 case WM_MOUSEHWHEEL:
1281 dwButtonState = GET_WHEEL_DELTA_WPARAM(wParam) << 16;
1282 dwEventFlags = MOUSE_HWHEELED;
1283 break;
1284
1285 default:
1286 Err = TRUE;
1287 break;
1288 }
1289
1290 if (!Err)
1291 {
1292 if (wKeyState & MK_LBUTTON)
1293 dwButtonState |= FROM_LEFT_1ST_BUTTON_PRESSED;
1294 if (wKeyState & MK_MBUTTON)
1295 dwButtonState |= FROM_LEFT_2ND_BUTTON_PRESSED;
1296 if (wKeyState & MK_RBUTTON)
1297 dwButtonState |= RIGHTMOST_BUTTON_PRESSED;
1298
1299 if (GetKeyState(VK_RMENU) & 0x8000)
1300 dwControlKeyState |= RIGHT_ALT_PRESSED;
1301 if (GetKeyState(VK_LMENU) & 0x8000)
1302 dwControlKeyState |= LEFT_ALT_PRESSED;
1303 if (GetKeyState(VK_RCONTROL) & 0x8000)
1304 dwControlKeyState |= RIGHT_CTRL_PRESSED;
1305 if (GetKeyState(VK_LCONTROL) & 0x8000)
1306 dwControlKeyState |= LEFT_CTRL_PRESSED;
1307 if (GetKeyState(VK_SHIFT) & 0x8000)
1308 dwControlKeyState |= SHIFT_PRESSED;
1309 if (GetKeyState(VK_NUMLOCK) & 0x0001)
1310 dwControlKeyState |= NUMLOCK_ON;
1311 if (GetKeyState(VK_SCROLL) & 0x0001)
1312 dwControlKeyState |= SCROLLLOCK_ON;
1313 if (GetKeyState(VK_CAPITAL) & 0x0001)
1314 dwControlKeyState |= CAPSLOCK_ON;
1315 /* See WM_CHAR MSDN documentation for instance */
1316 if (lParam & 0x01000000)
1317 dwControlKeyState |= ENHANCED_KEY;
1318
1319 er.EventType = MOUSE_EVENT;
1320 er.Event.MouseEvent.dwMousePosition = PointToCoord(GuiData, lParam);
1321 er.Event.MouseEvent.dwButtonState = dwButtonState;
1322 er.Event.MouseEvent.dwControlKeyState = dwControlKeyState;
1323 er.Event.MouseEvent.dwEventFlags = dwEventFlags;
1324
1325 ConioProcessInputEvent(Console, &er);
1326 }
1327 }
1328 else
1329 {
1330 Err = TRUE;
1331 }
1332
1333 LeaveCriticalSection(&Console->Lock);
1334
1335 Quit:
1336 if (Err)
1337 return DefWindowProcW(GuiData->hWindow, msg, wParam, lParam);
1338 else
1339 return 0;
1340 }
1341
1342 VOID GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer);
1343 VOID GuiCopyFromGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer);
1344
1345 static VOID
1346 GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData)
1347 {
1348 if (OpenClipboard(GuiData->hWindow) == TRUE)
1349 {
1350 PCONSOLE Console = GuiData->Console;
1351 PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(Console);
1352
1353 if (GetType(Buffer) == TEXTMODE_BUFFER)
1354 {
1355 GuiCopyFromTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)Buffer);
1356 }
1357 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
1358 {
1359 GuiCopyFromGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)Buffer);
1360 }
1361
1362 CloseClipboard();
1363
1364 /* Clear the selection */
1365 GuiConsoleUpdateSelection(Console, NULL);
1366 SetWindowText(GuiData->hWindow, Console->Title.Buffer);
1367 }
1368 }
1369
1370 VOID GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer);
1371 VOID GuiPasteToGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer);
1372
1373 static VOID
1374 GuiConsolePaste(PGUI_CONSOLE_DATA GuiData)
1375 {
1376 if (OpenClipboard(GuiData->hWindow) == TRUE)
1377 {
1378 // PCONSOLE Console = GuiData->Console;
1379 PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(Console);
1380
1381 if (GetType(Buffer) == TEXTMODE_BUFFER)
1382 {
1383 GuiPasteToTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)Buffer);
1384 }
1385 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
1386 {
1387 GuiPasteToGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)Buffer);
1388 }
1389
1390 CloseClipboard();
1391 }
1392 }
1393
1394 static VOID
1395 GuiConsoleGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData, PMINMAXINFO minMaxInfo)
1396 {
1397 PCONSOLE Console = GuiData->Console;
1398 PCONSOLE_SCREEN_BUFFER ActiveBuffer;
1399 DWORD windx, windy;
1400 UINT WidthUnit, HeightUnit;
1401
1402 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
1403
1404 // ActiveBuffer = ConDrvGetActiveScreenBuffer(Console);
1405 ActiveBuffer = GuiData->ActiveBuffer;
1406
1407 GetScreenBufferSizeUnits(ActiveBuffer, GuiData, &WidthUnit, &HeightUnit);
1408
1409 windx = CONGUI_MIN_WIDTH * WidthUnit + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
1410 windy = CONGUI_MIN_HEIGHT * HeightUnit + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
1411
1412 minMaxInfo->ptMinTrackSize.x = windx;
1413 minMaxInfo->ptMinTrackSize.y = windy;
1414
1415 windx = (ActiveBuffer->ScreenBufferSize.X) * WidthUnit + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
1416 windy = (ActiveBuffer->ScreenBufferSize.Y) * HeightUnit + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
1417
1418 if (ActiveBuffer->ViewSize.X < ActiveBuffer->ScreenBufferSize.X) windy += GetSystemMetrics(SM_CYHSCROLL); // window currently has a horizontal scrollbar
1419 if (ActiveBuffer->ViewSize.Y < ActiveBuffer->ScreenBufferSize.Y) windx += GetSystemMetrics(SM_CXVSCROLL); // window currently has a vertical scrollbar
1420
1421 minMaxInfo->ptMaxTrackSize.x = windx;
1422 minMaxInfo->ptMaxTrackSize.y = windy;
1423
1424 LeaveCriticalSection(&Console->Lock);
1425 }
1426
1427 static VOID
1428 GuiConsoleResize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
1429 {
1430 PCONSOLE Console = GuiData->Console;
1431
1432 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
1433
1434 if ((GuiData->WindowSizeLock == FALSE) &&
1435 (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED || wParam == SIZE_MINIMIZED))
1436 {
1437 PCONSOLE_SCREEN_BUFFER Buff = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(Console);
1438 DWORD windx, windy, charx, chary;
1439 UINT WidthUnit, HeightUnit;
1440
1441 GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit);
1442
1443 GuiData->WindowSizeLock = TRUE;
1444
1445 windx = LOWORD(lParam);
1446 windy = HIWORD(lParam);
1447
1448 // Compensate for existing scroll bars (because lParam values do not accommodate scroll bar)
1449 if (Buff->ViewSize.X < Buff->ScreenBufferSize.X) windy += GetSystemMetrics(SM_CYHSCROLL); // window currently has a horizontal scrollbar
1450 if (Buff->ViewSize.Y < Buff->ScreenBufferSize.Y) windx += GetSystemMetrics(SM_CXVSCROLL); // window currently has a vertical scrollbar
1451
1452 charx = windx / (int)WidthUnit ;
1453 chary = windy / (int)HeightUnit;
1454
1455 // Character alignment (round size up or down)
1456 if ((windx % WidthUnit ) >= (WidthUnit / 2)) ++charx;
1457 if ((windy % HeightUnit) >= (HeightUnit / 2)) ++chary;
1458
1459 // Compensate for added scroll bars in new window
1460 if (charx < Buff->ScreenBufferSize.X) windy -= GetSystemMetrics(SM_CYHSCROLL); // new window will have a horizontal scroll bar
1461 if (chary < Buff->ScreenBufferSize.Y) windx -= GetSystemMetrics(SM_CXVSCROLL); // new window will have a vertical scroll bar
1462
1463 charx = windx / (int)WidthUnit ;
1464 chary = windy / (int)HeightUnit;
1465
1466 // Character alignment (round size up or down)
1467 if ((windx % WidthUnit ) >= (WidthUnit / 2)) ++charx;
1468 if ((windy % HeightUnit) >= (HeightUnit / 2)) ++chary;
1469
1470 // Resize window
1471 if ((charx != Buff->ViewSize.X) || (chary != Buff->ViewSize.Y))
1472 {
1473 Buff->ViewSize.X = (charx <= Buff->ScreenBufferSize.X) ? charx : Buff->ScreenBufferSize.X;
1474 Buff->ViewSize.Y = (chary <= Buff->ScreenBufferSize.Y) ? chary : Buff->ScreenBufferSize.Y;
1475 }
1476
1477 GuiConsoleResizeWindow(GuiData);
1478
1479 // Adjust the start of the visible area if we are attempting to show nonexistent areas
1480 if ((Buff->ScreenBufferSize.X - Buff->ViewOrigin.X) < Buff->ViewSize.X) Buff->ViewOrigin.X = Buff->ScreenBufferSize.X - Buff->ViewSize.X;
1481 if ((Buff->ScreenBufferSize.Y - Buff->ViewOrigin.Y) < Buff->ViewSize.Y) Buff->ViewOrigin.Y = Buff->ScreenBufferSize.Y - Buff->ViewSize.Y;
1482 InvalidateRect(GuiData->hWindow, NULL, TRUE);
1483
1484 GuiData->WindowSizeLock = FALSE;
1485 }
1486
1487 LeaveCriticalSection(&Console->Lock);
1488 }
1489
1490 /*
1491 // HACK: This functionality is standard for general scrollbars. Don't add it by hand.
1492
1493 VOID
1494 FASTCALL
1495 GuiConsoleHandleScrollbarMenu(VOID)
1496 {
1497 HMENU hMenu;
1498
1499 hMenu = CreatePopupMenu();
1500 if (hMenu == NULL)
1501 {
1502 DPRINT("CreatePopupMenu failed\n");
1503 return;
1504 }
1505
1506 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLHERE);
1507 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1508 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLTOP);
1509 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLBOTTOM);
1510 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1511 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_UP);
1512 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_DOWN);
1513 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1514 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLUP);
1515 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLDOWN);
1516 }
1517 */
1518
1519 static LRESULT
1520 GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam)
1521 {
1522 PCONSOLE Console = GuiData->Console;
1523 PCONSOLE_SCREEN_BUFFER Buff;
1524 SCROLLINFO sInfo;
1525 int fnBar;
1526 int old_pos, Maximum;
1527 PSHORT pShowXY;
1528
1529 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return 0;
1530
1531 Buff = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(Console);
1532
1533 if (uMsg == WM_HSCROLL)
1534 {
1535 fnBar = SB_HORZ;
1536 Maximum = Buff->ScreenBufferSize.X - Buff->ViewSize.X;
1537 pShowXY = &Buff->ViewOrigin.X;
1538 }
1539 else
1540 {
1541 fnBar = SB_VERT;
1542 Maximum = Buff->ScreenBufferSize.Y - Buff->ViewSize.Y;
1543 pShowXY = &Buff->ViewOrigin.Y;
1544 }
1545
1546 /* set scrollbar sizes */
1547 sInfo.cbSize = sizeof(SCROLLINFO);
1548 sInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE | SIF_TRACKPOS;
1549
1550 if (!GetScrollInfo(GuiData->hWindow, fnBar, &sInfo)) goto Quit;
1551
1552 old_pos = sInfo.nPos;
1553
1554 switch (LOWORD(wParam))
1555 {
1556 case SB_LINELEFT:
1557 sInfo.nPos -= 1;
1558 break;
1559
1560 case SB_LINERIGHT:
1561 sInfo.nPos += 1;
1562 break;
1563
1564 case SB_PAGELEFT:
1565 sInfo.nPos -= sInfo.nPage;
1566 break;
1567
1568 case SB_PAGERIGHT:
1569 sInfo.nPos += sInfo.nPage;
1570 break;
1571
1572 case SB_THUMBTRACK:
1573 sInfo.nPos = sInfo.nTrackPos;
1574 ConioPause(Console, PAUSED_FROM_SCROLLBAR);
1575 break;
1576
1577 case SB_THUMBPOSITION:
1578 ConioUnpause(Console, PAUSED_FROM_SCROLLBAR);
1579 break;
1580
1581 case SB_TOP:
1582 sInfo.nPos = sInfo.nMin;
1583 break;
1584
1585 case SB_BOTTOM:
1586 sInfo.nPos = sInfo.nMax;
1587 break;
1588
1589 default:
1590 break;
1591 }
1592
1593 sInfo.nPos = max(sInfo.nPos, 0);
1594 sInfo.nPos = min(sInfo.nPos, Maximum);
1595
1596 if (old_pos != sInfo.nPos)
1597 {
1598 USHORT OldX = Buff->ViewOrigin.X;
1599 USHORT OldY = Buff->ViewOrigin.Y;
1600 UINT WidthUnit, HeightUnit;
1601
1602 *pShowXY = sInfo.nPos;
1603
1604 GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit);
1605
1606 ScrollWindowEx(GuiData->hWindow,
1607 (OldX - Buff->ViewOrigin.X) * WidthUnit ,
1608 (OldY - Buff->ViewOrigin.Y) * HeightUnit,
1609 NULL,
1610 NULL,
1611 NULL,
1612 NULL,
1613 SW_INVALIDATE);
1614
1615 sInfo.fMask = SIF_POS;
1616 SetScrollInfo(GuiData->hWindow, fnBar, &sInfo, TRUE);
1617
1618 UpdateWindow(GuiData->hWindow);
1619 }
1620
1621 Quit:
1622 LeaveCriticalSection(&Console->Lock);
1623 return 0;
1624 }
1625
1626 static LRESULT CALLBACK
1627 GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1628 {
1629 LRESULT Result = 0;
1630 PGUI_CONSOLE_DATA GuiData = NULL;
1631 PCONSOLE Console = NULL;
1632
1633 /*
1634 * - If it's the first time we create a window for the terminal,
1635 * just initialize it and return.
1636 *
1637 * - If we are destroying the window, just do it and return.
1638 */
1639 if (msg == WM_NCCREATE)
1640 {
1641 return (LRESULT)GuiConsoleHandleNcCreate(hWnd, (LPCREATESTRUCTW)lParam);
1642 }
1643 else if (msg == WM_NCDESTROY)
1644 {
1645 return GuiConsoleHandleNcDestroy(hWnd);
1646 }
1647
1648 /*
1649 * Now the terminal window is initialized.
1650 * Get the terminal data via the window's data.
1651 * If there is no data, just go away.
1652 */
1653 GuiData = GuiGetGuiData(hWnd);
1654 if (GuiData == NULL) return DefWindowProcW(hWnd, msg, wParam, lParam);
1655
1656 // TEMPORARY HACK until all of the functions can deal with a NULL GuiData->ActiveBuffer ...
1657 if (GuiData->ActiveBuffer == NULL) return DefWindowProcW(hWnd, msg, wParam, lParam);
1658
1659 /*
1660 * Just retrieve a pointer to the console in case somebody needs it.
1661 * It is not NULL because it was checked in GuiGetGuiData.
1662 * Each helper function which needs the console has to validate and lock it.
1663 */
1664 Console = GuiData->Console;
1665
1666 /* We have a console, start message dispatching */
1667 switch (msg)
1668 {
1669 case WM_ACTIVATE:
1670 {
1671 if (LOWORD(wParam) == WA_CLICKACTIVE) GuiData->IgnoreNextMouseSignal = TRUE;
1672 break;
1673 }
1674
1675 case WM_CLOSE:
1676 if (GuiConsoleHandleClose(GuiData)) goto Default;
1677 break;
1678
1679 case WM_PAINT:
1680 GuiConsoleHandlePaint(GuiData);
1681 break;
1682
1683 case WM_KEYDOWN:
1684 case WM_KEYUP:
1685 case WM_CHAR:
1686 case WM_DEADCHAR:
1687 case WM_SYSKEYDOWN:
1688 case WM_SYSKEYUP:
1689 case WM_SYSCHAR:
1690 case WM_SYSDEADCHAR:
1691 {
1692 /* Detect Alt-Enter presses and switch back and forth to fullscreen mode */
1693 if (msg == WM_SYSKEYDOWN && (HIWORD(lParam) & KF_ALTDOWN) && wParam == VK_RETURN)
1694 {
1695 /* Switch only at first Alt-Enter press, and ignore subsequent key repetitions */
1696 if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) != KF_REPEAT) GuiConsoleSwitchFullScreen(GuiData);
1697 break;
1698 }
1699
1700 GuiConsoleHandleKey(GuiData, msg, wParam, lParam);
1701 break;
1702 }
1703
1704 case WM_TIMER:
1705 GuiConsoleHandleTimer(GuiData);
1706 break;
1707
1708 case WM_SETCURSOR:
1709 {
1710 /*
1711 * The message was sent because we are manually triggering a change.
1712 * Check whether the mouse is indeed present on this console window
1713 * and take appropriate decisions.
1714 */
1715 if (wParam == -1 && lParam == -1)
1716 {
1717 POINT mouseCoords;
1718 HWND hWndHit;
1719
1720 /* Get the placement of the mouse */
1721 GetCursorPos(&mouseCoords);
1722
1723 /* On which window is placed the mouse ? */
1724 hWndHit = WindowFromPoint(mouseCoords);
1725
1726 /* It's our window. Perform the hit-test to be used later on. */
1727 if (hWndHit == hWnd)
1728 {
1729 wParam = (WPARAM)hWnd;
1730 lParam = DefWindowProcW(hWndHit, WM_NCHITTEST, 0,
1731 MAKELPARAM(mouseCoords.x, mouseCoords.y));
1732 }
1733 }
1734
1735 /* Set the mouse cursor only when we are in the client area */
1736 if ((HWND)wParam == hWnd && LOWORD(lParam) == HTCLIENT)
1737 {
1738 if (GuiData->MouseCursorRefCount >= 0)
1739 {
1740 /* Show the cursor */
1741 SetCursor(GuiData->hCursor);
1742 }
1743 else
1744 {
1745 /* Hide the cursor if the reference count is negative */
1746 SetCursor(NULL);
1747 }
1748 return TRUE;
1749 }
1750 else
1751 {
1752 goto Default;
1753 }
1754 }
1755
1756 case WM_LBUTTONDOWN:
1757 case WM_MBUTTONDOWN:
1758 case WM_RBUTTONDOWN:
1759 case WM_LBUTTONUP:
1760 case WM_MBUTTONUP:
1761 case WM_RBUTTONUP:
1762 case WM_LBUTTONDBLCLK:
1763 case WM_MBUTTONDBLCLK:
1764 case WM_RBUTTONDBLCLK:
1765 case WM_MOUSEMOVE:
1766 case WM_MOUSEWHEEL:
1767 case WM_MOUSEHWHEEL:
1768 {
1769 Result = GuiConsoleHandleMouse(GuiData, msg, wParam, lParam);
1770 break;
1771 }
1772
1773 case WM_HSCROLL:
1774 case WM_VSCROLL:
1775 {
1776 Result = GuiConsoleHandleScroll(GuiData, msg, wParam);
1777 break;
1778 }
1779
1780 case WM_NCRBUTTONDOWN:
1781 {
1782 DPRINT1("WM_NCRBUTTONDOWN\n");
1783 /*
1784 * HACK: !! Because, when we deal with WM_RBUTTON* and we do not
1785 * call after that DefWindowProc, on ReactOS, right-clicks on the
1786 * (non-client) application title-bar does not display the system
1787 * menu and does not trigger a WM_NCRBUTTONUP message too.
1788 * See: http://git.reactos.org/?p=reactos.git;a=blob;f=reactos/win32ss/user/user32/windows/defwnd.c;hb=HEAD#l1103
1789 * and line 1135 too.
1790 */
1791 if (DefWindowProcW(hWnd, WM_NCHITTEST, 0, lParam) == HTCAPTION)
1792 {
1793 /* Call DefWindowProcW with the WM_CONTEXTMENU message */
1794 msg = WM_CONTEXTMENU;
1795 }
1796 goto Default;
1797 }
1798 // case WM_NCRBUTTONUP:
1799 // DPRINT1("WM_NCRBUTTONUP\n");
1800 // goto Default;
1801
1802 case WM_CONTEXTMENU:
1803 {
1804 if (DefWindowProcW(hWnd /*GuiData->hWindow*/, WM_NCHITTEST, 0, lParam) == HTCLIENT)
1805 {
1806 HMENU hMenu = CreatePopupMenu();
1807 if (hMenu != NULL)
1808 {
1809 GuiConsoleAppendMenuItems(hMenu, GuiConsoleEditMenuItems);
1810 TrackPopupMenuEx(hMenu,
1811 TPM_RIGHTBUTTON,
1812 GET_X_LPARAM(lParam),
1813 GET_Y_LPARAM(lParam),
1814 hWnd,
1815 NULL);
1816 DestroyMenu(hMenu);
1817 }
1818 break;
1819 }
1820 else
1821 {
1822 goto Default;
1823 }
1824 }
1825
1826 case WM_INITMENU:
1827 {
1828 HMENU hMenu = (HMENU)wParam;
1829 if (hMenu != NULL)
1830 {
1831 /* Enable or disable the Close menu item */
1832 EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND |
1833 (GuiData->IsCloseButtonEnabled ? MF_ENABLED : MF_GRAYED));
1834
1835 /* Enable or disable the Copy and Paste items */
1836 EnableMenuItem(hMenu, ID_SYSTEM_EDIT_COPY , MF_BYCOMMAND |
1837 ((Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) &&
1838 (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY) ? MF_ENABLED : MF_GRAYED));
1839 EnableMenuItem(hMenu, ID_SYSTEM_EDIT_PASTE, MF_BYCOMMAND |
1840 (!(Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) &&
1841 IsClipboardFormatAvailable(CF_UNICODETEXT) ? MF_ENABLED : MF_GRAYED));
1842 }
1843
1844 if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
1845 {
1846 GuiSendMenuEvent(Console, WM_INITMENU);
1847 LeaveCriticalSection(&Console->Lock);
1848 }
1849 break;
1850 }
1851
1852 case WM_MENUSELECT:
1853 {
1854 if (HIWORD(wParam) == 0xFFFF) // Allow all the menu flags
1855 {
1856 if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
1857 {
1858 GuiSendMenuEvent(Console, WM_MENUSELECT);
1859 LeaveCriticalSection(&Console->Lock);
1860 }
1861 }
1862 break;
1863 }
1864
1865 case WM_COMMAND:
1866 case WM_SYSCOMMAND:
1867 {
1868 Result = GuiConsoleHandleSysMenuCommand(GuiData, wParam, lParam);
1869 break;
1870 }
1871
1872 case WM_SETFOCUS:
1873 case WM_KILLFOCUS:
1874 {
1875 if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
1876 {
1877 BOOL SetFocus = (msg == WM_SETFOCUS);
1878 INPUT_RECORD er;
1879
1880 er.EventType = FOCUS_EVENT;
1881 er.Event.FocusEvent.bSetFocus = SetFocus;
1882 ConioProcessInputEvent(Console, &er);
1883
1884 if (SetFocus)
1885 DPRINT1("TODO: Create console caret\n");
1886 else
1887 DPRINT1("TODO: Destroy console caret\n");
1888
1889 LeaveCriticalSection(&Console->Lock);
1890 }
1891 break;
1892 }
1893
1894 case WM_GETMINMAXINFO:
1895 GuiConsoleGetMinMaxInfo(GuiData, (PMINMAXINFO)lParam);
1896 break;
1897
1898 case WM_SIZE:
1899 GuiConsoleResize(GuiData, wParam, lParam);
1900 break;
1901
1902 case PM_RESIZE_TERMINAL:
1903 {
1904 /* Resize the window to the user's values */
1905 GuiData->WindowSizeLock = TRUE;
1906 GuiConsoleResizeWindow(GuiData);
1907 GuiData->WindowSizeLock = FALSE;
1908 break;
1909 }
1910
1911 case PM_APPLY_CONSOLE_INFO:
1912 {
1913 if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
1914 {
1915 GuiApplyUserSettings(GuiData, (HANDLE)wParam, (BOOL)lParam);
1916 LeaveCriticalSection(&Console->Lock);
1917 }
1918 break;
1919 }
1920
1921 case PM_CONSOLE_BEEP:
1922 DPRINT1("Beep !!\n");
1923 Beep(800, 200);
1924 break;
1925
1926 // case PM_CONSOLE_SET_TITLE:
1927 // SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
1928 // break;
1929
1930 default: Default:
1931 Result = DefWindowProcW(hWnd, msg, wParam, lParam);
1932 break;
1933 }
1934
1935 return Result;
1936 }
1937
1938
1939
1940 /******************************************************************************
1941 * GUI Terminal Initialization *
1942 ******************************************************************************/
1943
1944 static LRESULT CALLBACK
1945 GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1946 {
1947 HWND NewWindow;
1948 LONG WindowCount;
1949 MSG Msg;
1950
1951 switch (msg)
1952 {
1953 case WM_CREATE:
1954 {
1955 SetWindowLongW(hWnd, GWL_USERDATA, 0);
1956 return 0;
1957 }
1958
1959 case PM_CREATE_CONSOLE:
1960 {
1961 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)lParam;
1962 PCONSOLE Console = GuiData->Console;
1963
1964 NewWindow = CreateWindowExW(WS_EX_CLIENTEDGE,
1965 GUI_CONSOLE_WINDOW_CLASS,
1966 Console->Title.Buffer,
1967 WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
1968 CW_USEDEFAULT,
1969 CW_USEDEFAULT,
1970 CW_USEDEFAULT,
1971 CW_USEDEFAULT,
1972 NULL,
1973 NULL,
1974 ConSrvDllInstance,
1975 (PVOID)GuiData);
1976 if (NULL != NewWindow)
1977 {
1978 WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
1979 WindowCount++;
1980 SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
1981
1982 DPRINT("Set icons via PM_CREATE_CONSOLE\n");
1983 if (GuiData->hIcon == NULL)
1984 {
1985 DPRINT("Not really /o\\...\n");
1986 GuiData->hIcon = ghDefaultIcon;
1987 GuiData->hIconSm = ghDefaultIconSm;
1988 }
1989 else if (GuiData->hIcon != ghDefaultIcon)
1990 {
1991 DPRINT("Yes \\o/\n");
1992 SendMessageW(GuiData->hWindow, WM_SETICON, ICON_BIG, (LPARAM)GuiData->hIcon);
1993 SendMessageW(GuiData->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)GuiData->hIconSm);
1994 }
1995
1996 /* Move and resize the window to the user's values */
1997 /* CAN WE DEADLOCK ?? */
1998 GuiConsoleMoveWindow(GuiData);
1999 GuiData->WindowSizeLock = TRUE;
2000 GuiConsoleResizeWindow(GuiData);
2001 GuiData->WindowSizeLock = FALSE;
2002
2003 // ShowWindow(NewWindow, (int)wParam);
2004 ShowWindowAsync(NewWindow, (int)wParam);
2005 DPRINT("Window showed\n");
2006 }
2007
2008 return (LRESULT)NewWindow;
2009 }
2010
2011 case PM_DESTROY_CONSOLE:
2012 {
2013 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)lParam;
2014
2015 /*
2016 * Window creation is done using a PostMessage(), so it's possible
2017 * that the window that we want to destroy doesn't exist yet.
2018 * So first empty the message queue.
2019 */
2020 /*
2021 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
2022 {
2023 TranslateMessage(&Msg);
2024 DispatchMessageW(&Msg);
2025 }*/
2026 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE)) ;
2027
2028 if (GuiData->hWindow != NULL) /* && DestroyWindow(GuiData->hWindow) */
2029 {
2030 DestroyWindow(GuiData->hWindow);
2031
2032 WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
2033 WindowCount--;
2034 SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
2035 if (0 == WindowCount)
2036 {
2037 NotifyWnd = NULL;
2038 DestroyWindow(hWnd);
2039 DPRINT("CONSRV: Going to quit the Gui Thread!!\n");
2040 PostQuitMessage(0);
2041 }
2042 }
2043
2044 return 0;
2045 }
2046
2047 default:
2048 return DefWindowProcW(hWnd, msg, wParam, lParam);
2049 }
2050 }
2051
2052 static DWORD WINAPI
2053 GuiConsoleGuiThread(PVOID Data)
2054 {
2055 MSG msg;
2056 PHANDLE GraphicsStartupEvent = (PHANDLE)Data;
2057
2058 /*
2059 * This thread dispatches all the console notifications to the notify window.
2060 * It is common for all the console windows.
2061 */
2062
2063 PrivateCsrssManualGuiCheck(+1);
2064
2065 NotifyWnd = CreateWindowW(L"ConSrvCreateNotify",
2066 L"",
2067 WS_OVERLAPPEDWINDOW,
2068 CW_USEDEFAULT,
2069 CW_USEDEFAULT,
2070 CW_USEDEFAULT,
2071 CW_USEDEFAULT,
2072 NULL,
2073 NULL,
2074 ConSrvDllInstance,
2075 NULL);
2076 if (NULL == NotifyWnd)
2077 {
2078 PrivateCsrssManualGuiCheck(-1);
2079 SetEvent(*GraphicsStartupEvent);
2080 return 1;
2081 }
2082
2083 SetEvent(*GraphicsStartupEvent);
2084
2085 while (GetMessageW(&msg, NULL, 0, 0))
2086 {
2087 TranslateMessage(&msg);
2088 DispatchMessageW(&msg);
2089 }
2090
2091 DPRINT("CONSRV: Quit the Gui Thread!!\n");
2092 PrivateCsrssManualGuiCheck(-1);
2093
2094 return 1;
2095 }
2096
2097 static BOOL
2098 GuiInit(VOID)
2099 {
2100 WNDCLASSEXW wc;
2101 ATOM ConsoleClassAtom;
2102
2103 /* Exit if we were already initialized */
2104 // if (ConsInitialized) return TRUE;
2105
2106 /*
2107 * Initialize and register the different window classes, if needed.
2108 */
2109 if (!ConsInitialized)
2110 {
2111 /* Initialize the notification window class */
2112 wc.cbSize = sizeof(WNDCLASSEXW);
2113 wc.lpszClassName = L"ConSrvCreateNotify";
2114 wc.lpfnWndProc = GuiConsoleNotifyWndProc;
2115 wc.style = 0;
2116 wc.hInstance = ConSrvDllInstance;
2117 wc.hIcon = NULL;
2118 wc.hIconSm = NULL;
2119 wc.hCursor = NULL;
2120 wc.hbrBackground = NULL;
2121 wc.lpszMenuName = NULL;
2122 wc.cbClsExtra = 0;
2123 wc.cbWndExtra = 0;
2124 if (RegisterClassExW(&wc) == 0)
2125 {
2126 DPRINT1("Failed to register GUI notify wndproc\n");
2127 return FALSE;
2128 }
2129
2130 /* Initialize the console window class */
2131 ghDefaultIcon = LoadImageW(ConSrvDllInstance,
2132 MAKEINTRESOURCEW(IDI_TERMINAL),
2133 IMAGE_ICON,
2134 GetSystemMetrics(SM_CXICON),
2135 GetSystemMetrics(SM_CYICON),
2136 LR_SHARED);
2137 ghDefaultIconSm = LoadImageW(ConSrvDllInstance,
2138 MAKEINTRESOURCEW(IDI_TERMINAL),
2139 IMAGE_ICON,
2140 GetSystemMetrics(SM_CXSMICON),
2141 GetSystemMetrics(SM_CYSMICON),
2142 LR_SHARED);
2143 ghDefaultCursor = LoadCursorW(NULL, IDC_ARROW);
2144 wc.cbSize = sizeof(WNDCLASSEXW);
2145 wc.lpszClassName = GUI_CONSOLE_WINDOW_CLASS;
2146 wc.lpfnWndProc = GuiConsoleWndProc;
2147 wc.style = CS_DBLCLKS /* | CS_HREDRAW | CS_VREDRAW */;
2148 wc.hInstance = ConSrvDllInstance;
2149 wc.hIcon = ghDefaultIcon;
2150 wc.hIconSm = ghDefaultIconSm;
2151 wc.hCursor = ghDefaultCursor;
2152 wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); // The color of a terminal when it is switch off.
2153 wc.lpszMenuName = NULL;
2154 wc.cbClsExtra = 0;
2155 wc.cbWndExtra = GWLP_CONSOLEWND_ALLOC;
2156
2157 ConsoleClassAtom = RegisterClassExW(&wc);
2158 if (ConsoleClassAtom == 0)
2159 {
2160 DPRINT1("Failed to register GUI console wndproc\n");
2161 return FALSE;
2162 }
2163 else
2164 {
2165 NtUserConsoleControl(GuiConsoleWndClassAtom, &ConsoleClassAtom, sizeof(ATOM));
2166 }
2167
2168 ConsInitialized = TRUE;
2169 }
2170
2171 /*
2172 * Set-up the notification window
2173 */
2174 if (NULL == NotifyWnd)
2175 {
2176 HANDLE ThreadHandle;
2177 HANDLE GraphicsStartupEvent;
2178
2179 GraphicsStartupEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
2180 if (NULL == GraphicsStartupEvent) return FALSE;
2181
2182 ThreadHandle = CreateThread(NULL,
2183 0,
2184 GuiConsoleGuiThread,
2185 (PVOID)&GraphicsStartupEvent,
2186 0,
2187 NULL);
2188 if (NULL == ThreadHandle)
2189 {
2190 CloseHandle(GraphicsStartupEvent);
2191 DPRINT1("CONSRV: Failed to create graphics console thread. Expect problems\n");
2192 return FALSE;
2193 }
2194 SetThreadPriority(ThreadHandle, THREAD_PRIORITY_HIGHEST);
2195 CloseHandle(ThreadHandle);
2196
2197 WaitForSingleObject(GraphicsStartupEvent, INFINITE);
2198 CloseHandle(GraphicsStartupEvent);
2199
2200 if (NULL == NotifyWnd)
2201 {
2202 DPRINT1("CONSRV: Failed to create notification window.\n");
2203 return FALSE;
2204 }
2205 }
2206
2207 // ConsInitialized = TRUE;
2208
2209 return TRUE;
2210 }
2211
2212
2213
2214 /******************************************************************************
2215 * GUI Console Driver *
2216 ******************************************************************************/
2217
2218 static VOID WINAPI
2219 GuiDeinitFrontEnd(IN OUT PFRONTEND This);
2220
2221 NTSTATUS NTAPI
2222 GuiInitFrontEnd(IN OUT PFRONTEND This,
2223 IN PCONSOLE Console)
2224 {
2225 PGUI_INIT_INFO GuiInitInfo;
2226 PCONSOLE_INFO ConsoleInfo;
2227 PCONSOLE_START_INFO ConsoleStartInfo;
2228
2229 PGUI_CONSOLE_DATA GuiData;
2230 GUI_CONSOLE_INFO TermInfo;
2231
2232 SIZE_T Length = 0;
2233 LPWSTR IconPath = NULL;
2234 INT IconIndex = 0;
2235
2236 if (This == NULL || Console == NULL || This->OldData == NULL)
2237 return STATUS_INVALID_PARAMETER;
2238
2239 ASSERT(This->Console == Console);
2240
2241 GuiInitInfo = This->OldData;
2242
2243 if (GuiInitInfo->ConsoleInfo == NULL || GuiInitInfo->ConsoleStartInfo == NULL)
2244 return STATUS_INVALID_PARAMETER;
2245
2246 ConsoleInfo = GuiInitInfo->ConsoleInfo;
2247 ConsoleStartInfo = GuiInitInfo->ConsoleStartInfo;
2248
2249 IconPath = ConsoleStartInfo->IconPath;
2250 IconIndex = ConsoleStartInfo->IconIndex;
2251
2252
2253 /* Terminal data allocation */
2254 GuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(GUI_CONSOLE_DATA));
2255 if (!GuiData)
2256 {
2257 DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
2258 return STATUS_UNSUCCESSFUL;
2259 }
2260 /* HACK */ Console->TermIFace.Data = (PVOID)GuiData; /* HACK */
2261 GuiData->Console = Console;
2262 GuiData->ActiveBuffer = Console->ActiveBuffer;
2263 GuiData->hWindow = NULL;
2264
2265 /* The console can be resized */
2266 Console->FixedSize = FALSE;
2267
2268 InitializeCriticalSection(&GuiData->Lock);
2269
2270
2271 /*
2272 * Load terminal settings
2273 */
2274
2275 /* 1. Load the default settings */
2276 GuiConsoleGetDefaultSettings(&TermInfo, GuiInitInfo->ProcessId);
2277
2278 /* 3. Load the remaining console settings via the registry. */
2279 if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
2280 {
2281 /* Load the terminal infos from the registry. */
2282 GuiConsoleReadUserSettings(&TermInfo,
2283 ConsoleInfo->ConsoleTitle,
2284 GuiInitInfo->ProcessId);
2285
2286 /*
2287 * Now, update them with the properties the user might gave to us
2288 * via the STARTUPINFO structure before calling CreateProcess
2289 * (and which was transmitted via the ConsoleStartInfo structure).
2290 * We therefore overwrite the values read in the registry.
2291 */
2292 if (ConsoleStartInfo->dwStartupFlags & STARTF_USESHOWWINDOW)
2293 {
2294 TermInfo.ShowWindow = ConsoleStartInfo->wShowWindow;
2295 }
2296 if (ConsoleStartInfo->dwStartupFlags & STARTF_USEPOSITION)
2297 {
2298 TermInfo.AutoPosition = FALSE;
2299 TermInfo.WindowOrigin.x = ConsoleStartInfo->dwWindowOrigin.X;
2300 TermInfo.WindowOrigin.y = ConsoleStartInfo->dwWindowOrigin.Y;
2301 }
2302 if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)
2303 {
2304 TermInfo.FullScreen = TRUE;
2305 }
2306 }
2307
2308
2309 /*
2310 * Set up GUI data
2311 */
2312
2313 Length = min(wcslen(TermInfo.FaceName) + 1, LF_FACESIZE); // wcsnlen
2314 wcsncpy(GuiData->GuiInfo.FaceName, TermInfo.FaceName, LF_FACESIZE);
2315 GuiData->GuiInfo.FaceName[Length] = L'\0';
2316 GuiData->GuiInfo.FontFamily = TermInfo.FontFamily;
2317 GuiData->GuiInfo.FontSize = TermInfo.FontSize;
2318 GuiData->GuiInfo.FontWeight = TermInfo.FontWeight;
2319 GuiData->GuiInfo.UseRasterFonts = TermInfo.UseRasterFonts;
2320 GuiData->GuiInfo.FullScreen = TermInfo.FullScreen;
2321 GuiData->GuiInfo.ShowWindow = TermInfo.ShowWindow;
2322 GuiData->GuiInfo.AutoPosition = TermInfo.AutoPosition;
2323 GuiData->GuiInfo.WindowOrigin = TermInfo.WindowOrigin;
2324
2325 /* Initialize the icon handles to their default values */
2326 GuiData->hIcon = ghDefaultIcon;
2327 GuiData->hIconSm = ghDefaultIconSm;
2328
2329 /* Get the associated icon, if any */
2330 if (IconPath == NULL || IconPath[0] == L'\0')
2331 {
2332 IconPath = ConsoleStartInfo->AppPath;
2333 IconIndex = 0;
2334 }
2335 DPRINT("IconPath = %S ; IconIndex = %lu\n", (IconPath ? IconPath : L"n/a"), IconIndex);
2336 if (IconPath && IconPath[0] != L'\0')
2337 {
2338 HICON hIcon = NULL, hIconSm = NULL;
2339 PrivateExtractIconExW(IconPath,
2340 IconIndex,
2341 &hIcon,
2342 &hIconSm,
2343 1);
2344 DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon, hIconSm);
2345 if (hIcon != NULL)
2346 {
2347 DPRINT("Effectively set the icons\n");
2348 GuiData->hIcon = hIcon;
2349 GuiData->hIconSm = hIconSm;
2350 }
2351 }
2352
2353 /* Mouse is shown by default with its default cursor shape */
2354 GuiData->hCursor = ghDefaultCursor;
2355 GuiData->MouseCursorRefCount = 0;
2356
2357 /* A priori don't ignore mouse signals */
2358 GuiData->IgnoreNextMouseSignal = FALSE;
2359
2360 /* Close button and the corresponding system menu item are enabled by default */
2361 GuiData->IsCloseButtonEnabled = TRUE;
2362
2363 /* There is no user-reserved menu id range by default */
2364 GuiData->cmdIdLow = GuiData->cmdIdHigh = 0;
2365
2366 /*
2367 * We need to wait until the GUI has been fully initialized
2368 * to retrieve custom settings i.e. WindowSize etc...
2369 * Ideally we could use SendNotifyMessage for this but its not
2370 * yet implemented.
2371 */
2372 GuiData->hGuiInitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
2373
2374 DPRINT("GUI - Checkpoint\n");
2375
2376 /* Create the terminal window */
2377 PostMessageW(NotifyWnd, PM_CREATE_CONSOLE, GuiData->GuiInfo.ShowWindow, (LPARAM)GuiData);
2378
2379 /* Wait until initialization has finished */
2380 WaitForSingleObject(GuiData->hGuiInitEvent, INFINITE);
2381 DPRINT("OK we created the console window\n");
2382 CloseHandle(GuiData->hGuiInitEvent);
2383 GuiData->hGuiInitEvent = NULL;
2384
2385 /* Check whether we really succeeded in initializing the terminal window */
2386 if (GuiData->hWindow == NULL)
2387 {
2388 DPRINT("GuiInitConsole - We failed at creating a new terminal window\n");
2389 GuiDeinitFrontEnd(This);
2390 return STATUS_UNSUCCESSFUL;
2391 }
2392
2393 /* Finally, finish to initialize the frontend structure */
2394 This->Data = GuiData;
2395 if (This->OldData) ConsoleFreeHeap(This->OldData);
2396 This->OldData = NULL;
2397
2398 return STATUS_SUCCESS;
2399 }
2400
2401 static VOID WINAPI
2402 GuiDeinitFrontEnd(IN OUT PFRONTEND This)
2403 {
2404 PGUI_CONSOLE_DATA GuiData = This->Data;
2405
2406 SendMessageW(NotifyWnd, PM_DESTROY_CONSOLE, 0, (LPARAM)GuiData);
2407
2408 DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
2409 GuiData->hIcon, ghDefaultIcon, GuiData->hIconSm, ghDefaultIconSm);
2410 if (GuiData->hIcon != NULL && GuiData->hIcon != ghDefaultIcon)
2411 {
2412 DPRINT("Destroy hIcon\n");
2413 DestroyIcon(GuiData->hIcon);
2414 }
2415 if (GuiData->hIconSm != NULL && GuiData->hIconSm != ghDefaultIconSm)
2416 {
2417 DPRINT("Destroy hIconSm\n");
2418 DestroyIcon(GuiData->hIconSm);
2419 }
2420
2421 This->Data = NULL;
2422 DeleteCriticalSection(&GuiData->Lock);
2423 ConsoleFreeHeap(GuiData);
2424
2425 DPRINT("Quit GuiDeinitFrontEnd\n");
2426 }
2427
2428 static VOID WINAPI
2429 GuiDrawRegion(IN OUT PFRONTEND This,
2430 SMALL_RECT* Region)
2431 {
2432 PGUI_CONSOLE_DATA GuiData = This->Data;
2433 RECT RegionRect;
2434
2435 SmallRectToRect(GuiData, &RegionRect, Region);
2436 /* Do not erase the background: it speeds up redrawing and reduce flickering */
2437 InvalidateRect(GuiData->hWindow, &RegionRect, FALSE);
2438 }
2439
2440 static VOID WINAPI
2441 GuiWriteStream(IN OUT PFRONTEND This,
2442 SMALL_RECT* Region,
2443 SHORT CursorStartX,
2444 SHORT CursorStartY,
2445 UINT ScrolledLines,
2446 PWCHAR Buffer,
2447 UINT Length)
2448 {
2449 PGUI_CONSOLE_DATA GuiData = This->Data;
2450 PCONSOLE_SCREEN_BUFFER Buff;
2451 SHORT CursorEndX, CursorEndY;
2452 RECT ScrollRect;
2453
2454 if (NULL == GuiData || NULL == GuiData->hWindow) return;
2455
2456 Buff = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(GuiData->Console);
2457 if (GetType(Buff) != TEXTMODE_BUFFER) return;
2458
2459 if (0 != ScrolledLines)
2460 {
2461 ScrollRect.left = 0;
2462 ScrollRect.top = 0;
2463 ScrollRect.right = Buff->ViewSize.X * GuiData->CharWidth;
2464 ScrollRect.bottom = Region->Top * GuiData->CharHeight;
2465
2466 ScrollWindowEx(GuiData->hWindow,
2467 0,
2468 -(int)(ScrolledLines * GuiData->CharHeight),
2469 &ScrollRect,
2470 NULL,
2471 NULL,
2472 NULL,
2473 SW_INVALIDATE);
2474 }
2475
2476 GuiDrawRegion(This, Region);
2477
2478 if (CursorStartX < Region->Left || Region->Right < CursorStartX
2479 || CursorStartY < Region->Top || Region->Bottom < CursorStartY)
2480 {
2481 GuiInvalidateCell(This, CursorStartX, CursorStartY);
2482 }
2483
2484 CursorEndX = Buff->CursorPosition.X;
2485 CursorEndY = Buff->CursorPosition.Y;
2486 if ((CursorEndX < Region->Left || Region->Right < CursorEndX
2487 || CursorEndY < Region->Top || Region->Bottom < CursorEndY)
2488 && (CursorEndX != CursorStartX || CursorEndY != CursorStartY))
2489 {
2490 GuiInvalidateCell(This, CursorEndX, CursorEndY);
2491 }
2492
2493 // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
2494 // repaint the window without having it just freeze up and stay on the screen permanently.
2495 Buff->CursorBlinkOn = TRUE;
2496 SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
2497 }
2498
2499 static BOOL WINAPI
2500 GuiSetCursorInfo(IN OUT PFRONTEND This,
2501 PCONSOLE_SCREEN_BUFFER Buff)
2502 {
2503 PGUI_CONSOLE_DATA GuiData = This->Data;
2504
2505 if (/*ConDrvGetActiveScreenBuffer(GuiData->Console)*/GuiData->ActiveBuffer == Buff)
2506 {
2507 GuiInvalidateCell(This, Buff->CursorPosition.X, Buff->CursorPosition.Y);
2508 }
2509
2510 return TRUE;
2511 }
2512
2513 static BOOL WINAPI
2514 GuiSetScreenInfo(IN OUT PFRONTEND This,
2515 PCONSOLE_SCREEN_BUFFER Buff,
2516 SHORT OldCursorX,
2517 SHORT OldCursorY)
2518 {
2519 PGUI_CONSOLE_DATA GuiData = This->Data;
2520
2521 if (/*ConDrvGetActiveScreenBuffer(GuiData->Console)*/GuiData->ActiveBuffer == Buff)
2522 {
2523 /* Redraw char at old position (remove cursor) */
2524 GuiInvalidateCell(This, OldCursorX, OldCursorY);
2525 /* Redraw char at new position (show cursor) */
2526 GuiInvalidateCell(This, Buff->CursorPosition.X, Buff->CursorPosition.Y);
2527 }
2528
2529 return TRUE;
2530 }
2531
2532 static VOID WINAPI
2533 GuiResizeTerminal(IN OUT PFRONTEND This)
2534 {
2535 PGUI_CONSOLE_DATA GuiData = This->Data;
2536
2537 /* Resize the window to the user's values */
2538 // GuiData->WindowSizeLock = TRUE;
2539 // GuiConsoleResizeWindow(GuiData);
2540 // GuiData->WindowSizeLock = FALSE;
2541 // NOTE: This code ^^ causes deadlocks...
2542
2543 PostMessageW(GuiData->hWindow, PM_RESIZE_TERMINAL, 0, 0);
2544 }
2545
2546 static VOID WINAPI
2547 GuiSetActiveScreenBuffer(IN OUT PFRONTEND This)
2548 {
2549 PGUI_CONSOLE_DATA GuiData = This->Data;
2550
2551 EnterCriticalSection(&GuiData->Lock);
2552 GuiData->WindowSizeLock = TRUE;
2553
2554 InterlockedExchangePointer(&GuiData->ActiveBuffer,
2555 GuiData->Console->ActiveBuffer);
2556
2557 GuiData->WindowSizeLock = FALSE;
2558 LeaveCriticalSection(&GuiData->Lock);
2559
2560 GuiResizeTerminal(This);
2561 // ConioDrawConsole(Console);
2562
2563 // FIXME: Change the palette.
2564 }
2565
2566 static VOID WINAPI
2567 GuiReleaseScreenBuffer(IN OUT PFRONTEND This,
2568 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer)
2569 {
2570 PGUI_CONSOLE_DATA GuiData = This->Data;
2571
2572 /*
2573 * If we were notified to release a screen buffer that is not actually
2574 * ours, then just ignore the notification...
2575 */
2576 if (ScreenBuffer != GuiData->ActiveBuffer) return;
2577
2578 /*
2579 * ... else, we must release our active buffer. Two cases are present:
2580 * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console
2581 * active screen buffer, then we can safely switch to it.
2582 * - If ScreenBuffer IS the console active screen buffer, we must release
2583 * it BUT and that's all.
2584 */
2585
2586 if (ScreenBuffer != GuiData->Console->ActiveBuffer)
2587 {
2588 GuiSetActiveScreenBuffer(This);
2589 }
2590 else
2591 {
2592 EnterCriticalSection(&GuiData->Lock);
2593 GuiData->WindowSizeLock = TRUE;
2594
2595 InterlockedExchangePointer(&GuiData->ActiveBuffer, NULL);
2596
2597 GuiData->WindowSizeLock = FALSE;
2598 LeaveCriticalSection(&GuiData->Lock);
2599 }
2600 }
2601
2602 static BOOL WINAPI
2603 GuiProcessKeyCallback(IN OUT PFRONTEND This,
2604 MSG* msg,
2605 BYTE KeyStateMenu,
2606 DWORD ShiftState,
2607 UINT VirtualKeyCode,
2608 BOOL Down)
2609 {
2610 if ((ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED) || KeyStateMenu & 0x80) &&
2611 (VirtualKeyCode == VK_ESCAPE || VirtualKeyCode == VK_TAB || VirtualKeyCode == VK_SPACE))
2612 {
2613 DefWindowProcW(msg->hwnd, msg->message, msg->wParam, msg->lParam);
2614 return TRUE;
2615 }
2616
2617 return FALSE;
2618 }
2619
2620 static BOOL WINAPI
2621 GuiSetMouseCursor(IN OUT PFRONTEND This,
2622 HCURSOR hCursor);
2623
2624 static VOID WINAPI
2625 GuiRefreshInternalInfo(IN OUT PFRONTEND This)
2626 {
2627 PGUI_CONSOLE_DATA GuiData = This->Data;
2628
2629 /* Update the console leader information held by the window */
2630 SetConsoleWndConsoleLeaderCID(GuiData);
2631
2632 /*
2633 * HACK:
2634 * We reset the cursor here so that, when a console app quits, we reset
2635 * the cursor to the default one. It's quite a hack since it doesn't proceed
2636 * per - console process... This must be fixed.
2637 *
2638 * See GuiInitConsole(...) for more information.
2639 */
2640
2641 /* Mouse is shown by default with its default cursor shape */
2642 GuiData->MouseCursorRefCount = 0; // Reinitialize the reference counter
2643 GuiSetMouseCursor(This, NULL);
2644 }
2645
2646 static VOID WINAPI
2647 GuiChangeTitle(IN OUT PFRONTEND This)
2648 {
2649 PGUI_CONSOLE_DATA GuiData = This->Data;
2650 // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
2651 SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
2652 }
2653
2654 static BOOL WINAPI
2655 GuiChangeIcon(IN OUT PFRONTEND This,
2656 HICON hWindowIcon)
2657 {
2658 PGUI_CONSOLE_DATA GuiData = This->Data;
2659 HICON hIcon, hIconSm;
2660
2661 if (hWindowIcon == NULL)
2662 {
2663 hIcon = ghDefaultIcon;
2664 hIconSm = ghDefaultIconSm;
2665 }
2666 else
2667 {
2668 hIcon = CopyIcon(hWindowIcon);
2669 hIconSm = CopyIcon(hWindowIcon);
2670 }
2671
2672 if (hIcon == NULL)
2673 {
2674 return FALSE;
2675 }
2676
2677 if (hIcon != GuiData->hIcon)
2678 {
2679 if (GuiData->hIcon != NULL && GuiData->hIcon != ghDefaultIcon)
2680 {
2681 DestroyIcon(GuiData->hIcon);
2682 }
2683 if (GuiData->hIconSm != NULL && GuiData->hIconSm != ghDefaultIconSm)
2684 {
2685 DestroyIcon(GuiData->hIconSm);
2686 }
2687
2688 GuiData->hIcon = hIcon;
2689 GuiData->hIconSm = hIconSm;
2690
2691 DPRINT("Set icons in GuiChangeIcon\n");
2692 PostMessageW(GuiData->hWindow, WM_SETICON, ICON_BIG, (LPARAM)GuiData->hIcon);
2693 PostMessageW(GuiData->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)GuiData->hIconSm);
2694 }
2695
2696 return TRUE;
2697 }
2698
2699 static HWND WINAPI
2700 GuiGetConsoleWindowHandle(IN OUT PFRONTEND This)
2701 {
2702 PGUI_CONSOLE_DATA GuiData = This->Data;
2703 return GuiData->hWindow;
2704 }
2705
2706 static VOID WINAPI
2707 GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This,
2708 PCOORD pSize)
2709 {
2710 PGUI_CONSOLE_DATA GuiData = This->Data;
2711 PCONSOLE_SCREEN_BUFFER ActiveBuffer;
2712 RECT WorkArea;
2713 LONG width, height;
2714 UINT WidthUnit, HeightUnit;
2715
2716 if (!pSize) return;
2717
2718 if (!SystemParametersInfoW(SPI_GETWORKAREA, 0, &WorkArea, 0))
2719 {
2720 DPRINT1("SystemParametersInfoW failed - What to do ??\n");
2721 return;
2722 }
2723
2724 // ActiveBuffer = ConDrvGetActiveScreenBuffer(GuiData->Console);
2725 ActiveBuffer = GuiData->ActiveBuffer;
2726 if (ActiveBuffer)
2727 {
2728 GetScreenBufferSizeUnits(ActiveBuffer, GuiData, &WidthUnit, &HeightUnit);
2729 }
2730 else
2731 {
2732 /* Default: text mode */
2733 WidthUnit = GuiData->CharWidth ;
2734 HeightUnit = GuiData->CharHeight;
2735 }
2736
2737 width = WorkArea.right;
2738 height = WorkArea.bottom;
2739
2740 width -= (2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE)));
2741 height -= (2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION));
2742
2743 if (width < 0) width = 0;
2744 if (height < 0) height = 0;
2745
2746 pSize->X = (SHORT)(width / (int)WidthUnit ) /* HACK */ + 2;
2747 pSize->Y = (SHORT)(height / (int)HeightUnit) /* HACK */ + 1;
2748 }
2749
2750 static ULONG WINAPI
2751 GuiGetDisplayMode(IN OUT PFRONTEND This)
2752 {
2753 PGUI_CONSOLE_DATA GuiData = This->Data;
2754 ULONG DisplayMode = 0;
2755
2756 if (GuiData->GuiInfo.FullScreen)
2757 DisplayMode |= CONSOLE_FULLSCREEN_HARDWARE; // CONSOLE_FULLSCREEN
2758 else
2759 DisplayMode |= CONSOLE_WINDOWED;
2760
2761 return DisplayMode;
2762 }
2763
2764 static BOOL WINAPI
2765 GuiSetDisplayMode(IN OUT PFRONTEND This,
2766 ULONG NewMode)
2767 {
2768 PGUI_CONSOLE_DATA GuiData = This->Data;
2769
2770 if (NewMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE))
2771 return FALSE;
2772
2773 GuiData->GuiInfo.FullScreen = (NewMode & CONSOLE_FULLSCREEN_MODE);
2774 // TODO: Change the display mode
2775 return TRUE;
2776 }
2777
2778 static INT WINAPI
2779 GuiShowMouseCursor(IN OUT PFRONTEND This,
2780 BOOL Show)
2781 {
2782 PGUI_CONSOLE_DATA GuiData = This->Data;
2783
2784 /* Set the reference count */
2785 if (Show) ++GuiData->MouseCursorRefCount;
2786 else --GuiData->MouseCursorRefCount;
2787
2788 /* Effectively show (or hide) the cursor (use special values for (w|l)Param) */
2789 PostMessageW(GuiData->hWindow, WM_SETCURSOR, -1, -1);
2790
2791 return GuiData->MouseCursorRefCount;
2792 }
2793
2794 static BOOL WINAPI
2795 GuiSetMouseCursor(IN OUT PFRONTEND This,
2796 HCURSOR hCursor)
2797 {
2798 PGUI_CONSOLE_DATA GuiData = This->Data;
2799
2800 /*
2801 * Set the cursor's handle. If the given handle is NULL,
2802 * then restore the default cursor.
2803 */
2804 GuiData->hCursor = (hCursor ? hCursor : ghDefaultCursor);
2805
2806 /* Effectively modify the shape of the cursor (use special values for (w|l)Param) */
2807 PostMessageW(GuiData->hWindow, WM_SETCURSOR, -1, -1);
2808
2809 return TRUE;
2810 }
2811
2812 static HMENU WINAPI
2813 GuiMenuControl(IN OUT PFRONTEND This,
2814 UINT cmdIdLow,
2815 UINT cmdIdHigh)
2816 {
2817 PGUI_CONSOLE_DATA GuiData = This->Data;
2818
2819 GuiData->cmdIdLow = cmdIdLow ;
2820 GuiData->cmdIdHigh = cmdIdHigh;
2821
2822 return GetSystemMenu(GuiData->hWindow, FALSE);
2823 }
2824
2825 static BOOL WINAPI
2826 GuiSetMenuClose(IN OUT PFRONTEND This,
2827 BOOL Enable)
2828 {
2829 /*
2830 * NOTE: See http://www.mail-archive.com/harbour@harbour-project.org/msg27509.html
2831 * or http://harbour-devel.1590103.n2.nabble.com/Question-about-hb-gt-win-CtrlHandler-usage-td4670862i20.html
2832 * for more information.
2833 */
2834
2835 PGUI_CONSOLE_DATA GuiData = This->Data;
2836 HMENU hSysMenu = GetSystemMenu(GuiData->hWindow, FALSE);
2837
2838 if (hSysMenu == NULL) return FALSE;
2839
2840 GuiData->IsCloseButtonEnabled = Enable;
2841 EnableMenuItem(hSysMenu, SC_CLOSE, MF_BYCOMMAND | (Enable ? MF_ENABLED : MF_GRAYED));
2842
2843 return TRUE;
2844 }
2845
2846 static FRONTEND_VTBL GuiVtbl =
2847 {
2848 GuiInitFrontEnd,
2849 GuiDeinitFrontEnd,
2850 GuiDrawRegion,
2851 GuiWriteStream,
2852 GuiSetCursorInfo,
2853 GuiSetScreenInfo,
2854 GuiResizeTerminal,
2855 GuiSetActiveScreenBuffer,
2856 GuiReleaseScreenBuffer,
2857 GuiProcessKeyCallback,
2858 GuiRefreshInternalInfo,
2859 GuiChangeTitle,
2860 GuiChangeIcon,
2861 GuiGetConsoleWindowHandle,
2862 GuiGetLargestConsoleWindowSize,
2863 GuiGetDisplayMode,
2864 GuiSetDisplayMode,
2865 GuiShowMouseCursor,
2866 GuiSetMouseCursor,
2867 GuiMenuControl,
2868 GuiSetMenuClose,
2869 };
2870
2871
2872 static BOOL
2873 LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
2874 IN OUT PCONSOLE_INFO ConsoleInfo)
2875 {
2876 #define PATH_SEPARATOR L'\\'
2877
2878 BOOL RetVal = FALSE;
2879 HRESULT hRes = S_OK;
2880 LPWSTR LinkName = NULL;
2881 SIZE_T Length = 0;
2882
2883 if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
2884 return FALSE;
2885
2886 ConsoleStartInfo->IconPath[0] = L'\0';
2887 ConsoleStartInfo->IconIndex = 0;
2888
2889 /* 1- Find the last path separator if any */
2890 LinkName = wcsrchr(ConsoleStartInfo->ConsoleTitle, PATH_SEPARATOR);
2891 if (LinkName == NULL)
2892 {
2893 LinkName = ConsoleStartInfo->ConsoleTitle;
2894 }
2895 else
2896 {
2897 /* Skip the path separator */
2898 ++LinkName;
2899 }
2900
2901 /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
2902 Length = wcslen(LinkName);
2903 if ( (Length <= 4) || (wcsicmp(LinkName + (Length - 4), L".lnk") != 0) )
2904 return FALSE;
2905
2906 /* 3- It may be a link. Try to retrieve some properties */
2907 hRes = CoInitialize(NULL);
2908 if (SUCCEEDED(hRes))
2909 {
2910 /* Get a pointer to the IShellLink interface */
2911 IShellLinkW* pshl = NULL;
2912 hRes = CoCreateInstance(&CLSID_ShellLink,
2913 NULL,
2914 CLSCTX_INPROC_SERVER,
2915 &IID_IShellLinkW,
2916 (LPVOID*)&pshl);
2917 if (SUCCEEDED(hRes))
2918 {
2919 /* Get a pointer to the IPersistFile interface */
2920 IPersistFile* ppf = NULL;
2921 hRes = IPersistFile_QueryInterface(pshl, &IID_IPersistFile, (LPVOID*)&ppf);
2922 if (SUCCEEDED(hRes))
2923 {
2924 /* Load the shortcut */
2925 hRes = IPersistFile_Load(ppf, ConsoleStartInfo->ConsoleTitle, STGM_READ);
2926 if (SUCCEEDED(hRes))
2927 {
2928 /*
2929 * Finally we can get the properties !
2930 * Update the old ones if needed.
2931 */
2932 INT ShowCmd = 0;
2933 // WORD HotKey = 0;
2934
2935 /* Reset the name of the console with the name of the shortcut */
2936 Length = min(/*Length*/ Length - 4, // 4 == len(".lnk")
2937 sizeof(ConsoleInfo->ConsoleTitle) / sizeof(ConsoleInfo->ConsoleTitle[0]) - 1);
2938 wcsncpy(ConsoleInfo->ConsoleTitle, LinkName, Length);
2939 ConsoleInfo->ConsoleTitle[Length] = L'\0';
2940
2941 /* Get the window showing command */
2942 hRes = IShellLinkW_GetShowCmd(pshl, &ShowCmd);
2943 if (SUCCEEDED(hRes)) ConsoleStartInfo->wShowWindow = (WORD)ShowCmd;
2944
2945 /* Get the hotkey */
2946 // hRes = pshl->GetHotkey(&ShowCmd);
2947 // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey;
2948
2949 /* Get the icon location, if any */
2950
2951 hRes = IShellLinkW_GetIconLocation(pshl,
2952 ConsoleStartInfo->IconPath,
2953 sizeof(ConsoleStartInfo->IconPath)/sizeof(ConsoleStartInfo->IconPath[0]) - 1, // == MAX_PATH
2954 &ConsoleStartInfo->IconIndex);
2955 if (!SUCCEEDED(hRes))
2956 {
2957 ConsoleStartInfo->IconPath[0] = L'\0';
2958 ConsoleStartInfo->IconIndex = 0;
2959 }
2960
2961 // FIXME: Since we still don't load console properties from the shortcut,
2962 // return false. When this will be done, we will return true instead.
2963 RetVal = FALSE;
2964 }
2965 IPersistFile_Release(ppf);
2966 }
2967 IShellLinkW_Release(pshl);
2968 }
2969 }
2970 CoUninitialize();
2971
2972 return RetVal;
2973 }
2974
2975 NTSTATUS NTAPI
2976 GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
2977 IN OUT PCONSOLE_INFO ConsoleInfo,
2978 IN OUT PVOID ExtraConsoleInfo,
2979 IN ULONG ProcessId)
2980 {
2981 PCONSOLE_START_INFO ConsoleStartInfo = ExtraConsoleInfo;
2982 PGUI_INIT_INFO GuiInitInfo;
2983
2984 if (FrontEnd == NULL || ConsoleInfo == NULL || ConsoleStartInfo == NULL)
2985 return STATUS_INVALID_PARAMETER;
2986
2987 /* Initialize GUI terminal emulator common functionalities */
2988 if (!GuiInit()) return STATUS_UNSUCCESSFUL;
2989
2990 /*
2991 * Load per-application terminal settings.
2992 *
2993 * Check whether the process creating the console was launched via
2994 * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the
2995 * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too.
2996 */
2997 if (ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME)
2998 {
2999 if (!LoadShellLinkConsoleInfo(ConsoleStartInfo, ConsoleInfo))
3000 {
3001 ConsoleStartInfo->dwStartupFlags &= ~STARTF_TITLEISLINKNAME;
3002 }
3003 }
3004
3005 /*
3006 * Initialize a private initialization info structure for later use.
3007 * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd.
3008 */
3009 GuiInitInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(GUI_INIT_INFO));
3010 if (GuiInitInfo == NULL) return STATUS_NO_MEMORY;
3011
3012 // HACK: We suppose that the pointers will be valid in GuiInitFrontEnd...
3013 GuiInitInfo->ConsoleInfo = ConsoleInfo;
3014 GuiInitInfo->ConsoleStartInfo = ConsoleStartInfo;
3015 GuiInitInfo->ProcessId = ProcessId;
3016
3017 /* Finally, initialize the frontend structure */
3018 FrontEnd->Vtbl = &GuiVtbl;
3019 FrontEnd->Data = NULL;
3020 FrontEnd->OldData = GuiInitInfo;
3021
3022 return STATUS_SUCCESS;
3023 }
3024
3025 NTSTATUS NTAPI
3026 GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd)
3027 {
3028 if (FrontEnd == NULL) return STATUS_INVALID_PARAMETER;
3029
3030 if (FrontEnd->Data) GuiDeinitFrontEnd(FrontEnd);
3031 if (FrontEnd->OldData) ConsoleFreeHeap(FrontEnd->OldData);
3032
3033 return STATUS_SUCCESS;
3034 }
3035
3036 /* EOF */