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