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
9 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
12 /* INCLUDES *******************************************************************/
25 // HACK!! Remove it when the hack in GuiWriteStream is fixed
26 #define CONGUI_UPDATE_TIME 0
27 #define CONGUI_UPDATE_TIMER 1
29 #define PM_CREATE_CONSOLE (WM_APP + 1)
30 #define PM_DESTROY_CONSOLE (WM_APP + 2)
33 /* Not defined in any header file */
34 extern VOID NTAPI
PrivateCsrssManualGuiCheck(LONG Check
);
35 // See winsrv/usersrv/init.c line 234
38 /* GLOBALS ********************************************************************/
40 typedef struct _GUI_INIT_INFO
42 PCONSOLE_INFO ConsoleInfo
;
43 PCONSOLE_START_INFO ConsoleStartInfo
;
45 } GUI_INIT_INFO
, *PGUI_INIT_INFO
;
47 static BOOL ConsInitialized
= FALSE
;
48 static HWND NotifyWnd
= NULL
;
50 extern HICON ghDefaultIcon
;
51 extern HICON ghDefaultIconSm
;
52 extern HCURSOR ghDefaultCursor
;
55 SetConWndConsoleLeaderCID(IN PGUI_CONSOLE_DATA GuiData
);
57 RegisterConWndClass(IN HINSTANCE hInstance
);
59 UnRegisterConWndClass(HINSTANCE hInstance
);
61 /* FUNCTIONS ******************************************************************/
64 GetScreenBufferSizeUnits(IN PCONSOLE_SCREEN_BUFFER Buffer
,
65 IN PGUI_CONSOLE_DATA GuiData
,
69 if (Buffer
== NULL
|| GuiData
== NULL
||
70 WidthUnit
== NULL
|| HeightUnit
== NULL
)
75 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
77 *WidthUnit
= GuiData
->CharWidth
;
78 *HeightUnit
= GuiData
->CharHeight
;
80 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
88 GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData
)
90 /* Move the window if needed (not positioned by the system) */
91 if (!GuiData
->GuiInfo
.AutoPosition
)
93 SetWindowPos(GuiData
->hWindow
,
95 GuiData
->GuiInfo
.WindowOrigin
.x
,
96 GuiData
->GuiInfo
.WindowOrigin
.y
,
98 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
103 SmallRectToRect(PGUI_CONSOLE_DATA GuiData
, PRECT Rect
, PSMALL_RECT SmallRect
)
105 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
106 UINT WidthUnit
, HeightUnit
;
108 GetScreenBufferSizeUnits(Buffer
, GuiData
, &WidthUnit
, &HeightUnit
);
110 Rect
->left
= (SmallRect
->Left
- Buffer
->ViewOrigin
.X
) * WidthUnit
;
111 Rect
->top
= (SmallRect
->Top
- Buffer
->ViewOrigin
.Y
) * HeightUnit
;
112 Rect
->right
= (SmallRect
->Right
+ 1 - Buffer
->ViewOrigin
.X
) * WidthUnit
;
113 Rect
->bottom
= (SmallRect
->Bottom
+ 1 - Buffer
->ViewOrigin
.Y
) * HeightUnit
;
117 DrawRegion(PGUI_CONSOLE_DATA GuiData
,
122 SmallRectToRect(GuiData
, &RegionRect
, Region
);
123 /* Do not erase the background: it speeds up redrawing and reduce flickering */
124 InvalidateRect(GuiData
->hWindow
, &RegionRect
, FALSE
);
125 /**UpdateWindow(GuiData->hWindow);**/
129 InvalidateCell(PGUI_CONSOLE_DATA GuiData
,
132 SMALL_RECT CellRect
= { x
, y
, x
, y
};
133 DrawRegion(GuiData
, &CellRect
);
137 /******************************************************************************
138 * GUI Terminal Initialization *
139 ******************************************************************************/
142 SwitchFullScreen(PGUI_CONSOLE_DATA GuiData
, BOOL FullScreen
);
144 CreateSysMenu(HWND hWnd
);
145 static LRESULT CALLBACK
146 GuiConsoleNotifyWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
156 SetWindowLongW(hWnd
, GWL_USERDATA
, 0);
160 case PM_CREATE_CONSOLE
:
162 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)lParam
;
163 PCONSOLE Console
= GuiData
->Console
;
166 DPRINT("PM_CREATE_CONSOLE -- creating window\n");
168 NewWindow
= CreateWindowExW(WS_EX_CLIENTEDGE
,
170 Console
->Title
.Buffer
,
171 WS_OVERLAPPEDWINDOW
| WS_HSCROLL
| WS_VSCROLL
,
180 if (NULL
!= NewWindow
)
182 ASSERT(NewWindow
== GuiData
->hWindow
);
184 WindowCount
= GetWindowLongW(hWnd
, GWL_USERDATA
);
186 SetWindowLongW(hWnd
, GWL_USERDATA
, WindowCount
);
189 // FIXME: TODO: Move everything there into conwnd.c!OnNcCreate()
192 /* Retrieve our real position */
193 // See conwnd.c!OnMove()
194 GetWindowRect(GuiData
->hWindow
, &rcWnd
);
195 GuiData
->GuiInfo
.WindowOrigin
.x
= rcWnd
.left
;
196 GuiData
->GuiInfo
.WindowOrigin
.y
= rcWnd
.top
;
198 /* Move and resize the window to the user's values */
199 /* CAN WE DEADLOCK ?? */
200 GuiConsoleMoveWindow(GuiData
); // FIXME: This MUST be done via the CreateWindowExW call.
201 SendMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
203 CreateSysMenu(GuiData
->hWindow
);
205 /* Switch to full-screen mode if necessary */
206 // FIXME: Move elsewhere, it cause misdrawings of the window.
207 if (GuiData
->GuiInfo
.FullScreen
) SwitchFullScreen(GuiData
, TRUE
);
209 DPRINT("PM_CREATE_CONSOLE -- showing window\n");
210 // ShowWindow(NewWindow, (int)wParam);
211 ShowWindowAsync(NewWindow
, (int)wParam
);
212 DPRINT("Window showed\n");
215 return (LRESULT
)NewWindow
;
218 case PM_DESTROY_CONSOLE
:
220 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)lParam
;
222 /* Exit the full screen mode if it was already set */
223 // LeaveFullScreen(GuiData);
226 * Window creation is done using a PostMessage(), so it's possible
227 * that the window that we want to destroy doesn't exist yet.
228 * So first empty the message queue.
231 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
233 TranslateMessage(&Msg);
234 DispatchMessageW(&Msg);
236 while (PeekMessageW(&Msg
, NULL
, 0, 0, PM_REMOVE
)) ;
238 if (GuiData
->hWindow
!= NULL
) /* && DestroyWindow(GuiData->hWindow) */
240 DestroyWindow(GuiData
->hWindow
);
242 WindowCount
= GetWindowLongW(hWnd
, GWL_USERDATA
);
244 SetWindowLongW(hWnd
, GWL_USERDATA
, WindowCount
);
245 if (0 == WindowCount
)
249 DPRINT("CONSRV: Going to quit the Gui Thread!!\n");
258 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
263 GuiConsoleGuiThread(PVOID Data
)
266 PHANDLE GraphicsStartupEvent
= (PHANDLE
)Data
;
269 * This thread dispatches all the console notifications to the notify window.
270 * It is common for all the console windows.
273 PrivateCsrssManualGuiCheck(+1);
275 NotifyWnd
= CreateWindowW(L
"ConSrvCreateNotify",
286 if (NULL
== NotifyWnd
)
288 PrivateCsrssManualGuiCheck(-1);
289 SetEvent(*GraphicsStartupEvent
);
293 SetEvent(*GraphicsStartupEvent
);
295 while (GetMessageW(&msg
, NULL
, 0, 0))
297 TranslateMessage(&msg
);
298 DispatchMessageW(&msg
);
301 DPRINT("CONSRV: Quit the Gui Thread!!\n");
302 PrivateCsrssManualGuiCheck(-1);
312 /* Exit if we were already initialized */
313 // if (ConsInitialized) return TRUE;
316 * Initialize and register the different window classes, if needed.
318 if (!ConsInitialized
)
320 /* Initialize the notification window class */
321 wc
.cbSize
= sizeof(WNDCLASSEXW
);
322 wc
.lpszClassName
= L
"ConSrvCreateNotify";
323 wc
.lpfnWndProc
= GuiConsoleNotifyWndProc
;
325 wc
.hInstance
= ConSrvDllInstance
;
329 wc
.hbrBackground
= NULL
;
330 wc
.lpszMenuName
= NULL
;
333 if (RegisterClassExW(&wc
) == 0)
335 DPRINT1("Failed to register GUI notify wndproc\n");
339 /* Initialize the console window class */
340 if (!RegisterConWndClass(ConSrvDllInstance
))
343 ConsInitialized
= TRUE
;
347 * Set-up the notification window
349 if (NULL
== NotifyWnd
)
352 HANDLE GraphicsStartupEvent
;
354 GraphicsStartupEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
355 if (NULL
== GraphicsStartupEvent
) return FALSE
;
357 ThreadHandle
= CreateThread(NULL
,
360 (PVOID
)&GraphicsStartupEvent
,
363 if (NULL
== ThreadHandle
)
365 CloseHandle(GraphicsStartupEvent
);
366 DPRINT1("CONSRV: Failed to create graphics console thread. Expect problems\n");
369 SetThreadPriority(ThreadHandle
, THREAD_PRIORITY_HIGHEST
);
370 CloseHandle(ThreadHandle
);
372 WaitForSingleObject(GraphicsStartupEvent
, INFINITE
);
373 CloseHandle(GraphicsStartupEvent
);
375 if (NULL
== NotifyWnd
)
377 DPRINT1("CONSRV: Failed to create notification window.\n");
382 // ConsInitialized = TRUE;
389 /******************************************************************************
390 * GUI Console Driver *
391 ******************************************************************************/
394 GuiDeinitFrontEnd(IN OUT PFRONTEND This
);
397 GuiInitFrontEnd(IN OUT PFRONTEND This
,
400 PGUI_INIT_INFO GuiInitInfo
;
401 PCONSOLE_INFO ConsoleInfo
;
402 PCONSOLE_START_INFO ConsoleStartInfo
;
404 PGUI_CONSOLE_DATA GuiData
;
405 GUI_CONSOLE_INFO TermInfo
;
408 LPWSTR IconPath
= NULL
;
411 if (This
== NULL
|| Console
== NULL
|| This
->OldData
== NULL
)
412 return STATUS_INVALID_PARAMETER
;
414 ASSERT(This
->Console
== Console
);
416 GuiInitInfo
= This
->OldData
;
418 if (GuiInitInfo
->ConsoleInfo
== NULL
|| GuiInitInfo
->ConsoleStartInfo
== NULL
)
419 return STATUS_INVALID_PARAMETER
;
421 ConsoleInfo
= GuiInitInfo
->ConsoleInfo
;
422 ConsoleStartInfo
= GuiInitInfo
->ConsoleStartInfo
;
424 IconPath
= ConsoleStartInfo
->IconPath
;
425 IconIndex
= ConsoleStartInfo
->IconIndex
;
428 /* Terminal data allocation */
429 GuiData
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_CONSOLE_DATA
));
432 DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
433 return STATUS_UNSUCCESSFUL
;
435 ///// /* HACK */ Console->TermIFace.Data = (PVOID)GuiData; /* HACK */
436 GuiData
->Console
= Console
;
437 GuiData
->ActiveBuffer
= Console
->ActiveBuffer
;
438 GuiData
->hWindow
= NULL
;
440 /* The console can be resized */
441 Console
->FixedSize
= FALSE
;
443 InitializeCriticalSection(&GuiData
->Lock
);
447 * Load terminal settings
450 /* 1. Load the default settings */
451 GuiConsoleGetDefaultSettings(&TermInfo
, GuiInitInfo
->ProcessId
);
453 /* 3. Load the remaining console settings via the registry. */
454 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
456 /* Load the terminal infos from the registry. */
457 GuiConsoleReadUserSettings(&TermInfo
,
458 ConsoleInfo
->ConsoleTitle
,
459 GuiInitInfo
->ProcessId
);
462 * Now, update them with the properties the user might gave to us
463 * via the STARTUPINFO structure before calling CreateProcess
464 * (and which was transmitted via the ConsoleStartInfo structure).
465 * We therefore overwrite the values read in the registry.
467 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USESHOWWINDOW
)
469 TermInfo
.ShowWindow
= ConsoleStartInfo
->wShowWindow
;
471 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USEPOSITION
)
473 TermInfo
.AutoPosition
= FALSE
;
474 TermInfo
.WindowOrigin
.x
= ConsoleStartInfo
->dwWindowOrigin
.X
;
475 TermInfo
.WindowOrigin
.y
= ConsoleStartInfo
->dwWindowOrigin
.Y
;
477 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_RUNFULLSCREEN
)
479 TermInfo
.FullScreen
= TRUE
;
488 Length
= min(wcslen(TermInfo
.FaceName
) + 1, LF_FACESIZE
); // wcsnlen
489 wcsncpy(GuiData
->GuiInfo
.FaceName
, TermInfo
.FaceName
, LF_FACESIZE
);
490 GuiData
->GuiInfo
.FaceName
[Length
] = L
'\0';
491 GuiData
->GuiInfo
.FontFamily
= TermInfo
.FontFamily
;
492 GuiData
->GuiInfo
.FontSize
= TermInfo
.FontSize
;
493 GuiData
->GuiInfo
.FontWeight
= TermInfo
.FontWeight
;
494 GuiData
->GuiInfo
.UseRasterFonts
= TermInfo
.UseRasterFonts
;
495 GuiData
->GuiInfo
.FullScreen
= TermInfo
.FullScreen
;
496 GuiData
->GuiInfo
.ShowWindow
= TermInfo
.ShowWindow
;
497 GuiData
->GuiInfo
.AutoPosition
= TermInfo
.AutoPosition
;
498 GuiData
->GuiInfo
.WindowOrigin
= TermInfo
.WindowOrigin
;
500 /* Initialize the icon handles to their default values */
501 GuiData
->hIcon
= ghDefaultIcon
;
502 GuiData
->hIconSm
= ghDefaultIconSm
;
504 /* Get the associated icon, if any */
505 if (IconPath
== NULL
|| IconPath
[0] == L
'\0')
507 IconPath
= ConsoleStartInfo
->AppPath
;
510 DPRINT("IconPath = %S ; IconIndex = %lu\n", (IconPath
? IconPath
: L
"n/a"), IconIndex
);
511 if (IconPath
&& IconPath
[0] != L
'\0')
513 HICON hIcon
= NULL
, hIconSm
= NULL
;
514 PrivateExtractIconExW(IconPath
,
519 DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon
, hIconSm
);
520 if (hIcon
!= NULL
) GuiData
->hIcon
= hIcon
;
521 if (hIconSm
!= NULL
) GuiData
->hIconSm
= hIconSm
;
523 ASSERT(GuiData
->hIcon
&& GuiData
->hIconSm
);
525 /* Mouse is shown by default with its default cursor shape */
526 GuiData
->hCursor
= ghDefaultCursor
;
527 GuiData
->MouseCursorRefCount
= 0;
529 /* A priori don't ignore mouse signals */
530 GuiData
->IgnoreNextMouseSignal
= FALSE
;
532 /* Close button and the corresponding system menu item are enabled by default */
533 GuiData
->IsCloseButtonEnabled
= TRUE
;
535 /* There is no user-reserved menu id range by default */
536 GuiData
->CmdIdLow
= GuiData
->CmdIdHigh
= 0;
538 /* Initialize the selection */
539 RtlZeroMemory(&GuiData
->Selection
, sizeof(GuiData
->Selection
));
540 GuiData
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
541 RtlZeroMemory(&GuiData
->dwSelectionCursor
, sizeof(GuiData
->dwSelectionCursor
));
542 GuiData
->LineSelection
= FALSE
; // Default to block selection
543 // TODO: Retrieve the selection mode via the registry.
546 * We need to wait until the GUI has been fully initialized
547 * to retrieve custom settings i.e. WindowSize etc...
548 * Ideally we could use SendNotifyMessage for this but its not
551 GuiData
->hGuiInitEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
553 DPRINT("GUI - Checkpoint\n");
555 /* Create the terminal window */
556 PostMessageW(NotifyWnd
, PM_CREATE_CONSOLE
, GuiData
->GuiInfo
.ShowWindow
, (LPARAM
)GuiData
);
558 /* Wait until initialization has finished */
559 WaitForSingleObject(GuiData
->hGuiInitEvent
, INFINITE
);
560 DPRINT("OK we created the console window\n");
561 CloseHandle(GuiData
->hGuiInitEvent
);
562 GuiData
->hGuiInitEvent
= NULL
;
564 /* Check whether we really succeeded in initializing the terminal window */
565 if (GuiData
->hWindow
== NULL
)
567 DPRINT("GuiInitConsole - We failed at creating a new terminal window\n");
568 GuiDeinitFrontEnd(This
);
569 return STATUS_UNSUCCESSFUL
;
572 /* Finally, finish to initialize the frontend structure */
573 This
->Data
= GuiData
;
574 if (This
->OldData
) ConsoleFreeHeap(This
->OldData
);
575 This
->OldData
= NULL
;
577 return STATUS_SUCCESS
;
581 GuiDeinitFrontEnd(IN OUT PFRONTEND This
)
583 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
585 SendMessageW(NotifyWnd
, PM_DESTROY_CONSOLE
, 0, (LPARAM
)GuiData
);
587 DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
588 GuiData
->hIcon
, ghDefaultIcon
, GuiData
->hIconSm
, ghDefaultIconSm
);
589 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
591 DPRINT("Destroy hIcon\n");
592 DestroyIcon(GuiData
->hIcon
);
594 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
596 DPRINT("Destroy hIconSm\n");
597 DestroyIcon(GuiData
->hIconSm
);
601 DeleteCriticalSection(&GuiData
->Lock
);
602 ConsoleFreeHeap(GuiData
);
604 DPRINT("Quit GuiDeinitFrontEnd\n");
608 GuiDrawRegion(IN OUT PFRONTEND This
,
611 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
612 DrawRegion(GuiData
, Region
);
616 GuiWriteStream(IN OUT PFRONTEND This
,
624 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
625 PCONSOLE_SCREEN_BUFFER Buff
;
626 SHORT CursorEndX
, CursorEndY
;
629 if (NULL
== GuiData
|| NULL
== GuiData
->hWindow
) return;
631 Buff
= GuiData
->ActiveBuffer
;
632 if (GetType(Buff
) != TEXTMODE_BUFFER
) return;
634 if (0 != ScrolledLines
)
638 ScrollRect
.right
= Buff
->ViewSize
.X
* GuiData
->CharWidth
;
639 ScrollRect
.bottom
= Region
->Top
* GuiData
->CharHeight
;
641 ScrollWindowEx(GuiData
->hWindow
,
643 -(int)(ScrolledLines
* GuiData
->CharHeight
),
651 DrawRegion(GuiData
, Region
);
653 if (CursorStartX
< Region
->Left
|| Region
->Right
< CursorStartX
654 || CursorStartY
< Region
->Top
|| Region
->Bottom
< CursorStartY
)
656 InvalidateCell(GuiData
, CursorStartX
, CursorStartY
);
659 CursorEndX
= Buff
->CursorPosition
.X
;
660 CursorEndY
= Buff
->CursorPosition
.Y
;
661 if ((CursorEndX
< Region
->Left
|| Region
->Right
< CursorEndX
662 || CursorEndY
< Region
->Top
|| Region
->Bottom
< CursorEndY
)
663 && (CursorEndX
!= CursorStartX
|| CursorEndY
!= CursorStartY
))
665 InvalidateCell(GuiData
, CursorEndX
, CursorEndY
);
669 // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
670 // repaint the window without having it just freeze up and stay on the screen permanently.
671 Buff
->CursorBlinkOn
= TRUE
;
672 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
676 GuiSetCursorInfo(IN OUT PFRONTEND This
,
677 PCONSOLE_SCREEN_BUFFER Buff
)
679 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
681 if (GuiData
->ActiveBuffer
== Buff
)
683 InvalidateCell(GuiData
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
690 GuiSetScreenInfo(IN OUT PFRONTEND This
,
691 PCONSOLE_SCREEN_BUFFER Buff
,
695 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
697 if (GuiData
->ActiveBuffer
== Buff
)
699 /* Redraw char at old position (remove cursor) */
700 InvalidateCell(GuiData
, OldCursorX
, OldCursorY
);
701 /* Redraw char at new position (show cursor) */
702 InvalidateCell(GuiData
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
709 GuiResizeTerminal(IN OUT PFRONTEND This
)
711 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
713 /* Resize the window to the user's values */
714 PostMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
718 GuiSetActiveScreenBuffer(IN OUT PFRONTEND This
)
720 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
721 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
724 EnterCriticalSection(&GuiData
->Lock
);
725 GuiData
->WindowSizeLock
= TRUE
;
727 InterlockedExchangePointer(&GuiData
->ActiveBuffer
,
728 ConDrvGetActiveScreenBuffer(GuiData
->Console
));
730 GuiData
->WindowSizeLock
= FALSE
;
731 LeaveCriticalSection(&GuiData
->Lock
);
733 ActiveBuffer
= GuiData
->ActiveBuffer
;
735 /* Change the current palette */
736 if (ActiveBuffer
->PaletteHandle
== NULL
)
738 hPalette
= GuiData
->hSysPalette
;
742 hPalette
= ActiveBuffer
->PaletteHandle
;
745 DPRINT1("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette
);
747 /* Set the new palette for the framebuffer */
748 SelectPalette(GuiData
->hMemDC
, hPalette
, FALSE
);
750 /* Specify the use of the system palette for the framebuffer */
751 SetSystemPaletteUse(GuiData
->hMemDC
, ActiveBuffer
->PaletteUsage
);
753 /* Realize the (logical) palette */
754 RealizePalette(GuiData
->hMemDC
);
756 GuiResizeTerminal(This
);
757 // ConioDrawConsole(Console);
761 GuiReleaseScreenBuffer(IN OUT PFRONTEND This
,
762 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer
)
764 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
767 * If we were notified to release a screen buffer that is not actually
768 * ours, then just ignore the notification...
770 if (ScreenBuffer
!= GuiData
->ActiveBuffer
) return;
773 * ... else, we must release our active buffer. Two cases are present:
774 * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console
775 * active screen buffer, then we can safely switch to it.
776 * - If ScreenBuffer IS the console active screen buffer, we must release
780 /* Release the old active palette and set the default one */
781 if (GetCurrentObject(GuiData
->hMemDC
, OBJ_PAL
) == ScreenBuffer
->PaletteHandle
)
783 /* Set the new palette */
784 SelectPalette(GuiData
->hMemDC
, GuiData
->hSysPalette
, FALSE
);
787 /* Set the adequate active screen buffer */
788 if (ScreenBuffer
!= GuiData
->Console
->ActiveBuffer
)
790 GuiSetActiveScreenBuffer(This
);
794 EnterCriticalSection(&GuiData
->Lock
);
795 GuiData
->WindowSizeLock
= TRUE
;
797 InterlockedExchangePointer(&GuiData
->ActiveBuffer
, NULL
);
799 GuiData
->WindowSizeLock
= FALSE
;
800 LeaveCriticalSection(&GuiData
->Lock
);
805 GuiProcessKeyCallback(IN OUT PFRONTEND This
,
812 if ((ShiftState
& (RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
) || KeyStateMenu
& 0x80) &&
813 (VirtualKeyCode
== VK_ESCAPE
|| VirtualKeyCode
== VK_TAB
|| VirtualKeyCode
== VK_SPACE
))
815 DPRINT1("GuiProcessKeyCallback\n");
816 //DefWindowProcW(msg->hwnd, msg->message, msg->wParam, msg->lParam);
824 GuiSetMouseCursor(IN OUT PFRONTEND This
,
825 HCURSOR CursorHandle
);
828 GuiRefreshInternalInfo(IN OUT PFRONTEND This
)
830 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
832 /* Update the console leader information held by the window */
833 SetConWndConsoleLeaderCID(GuiData
);
837 * We reset the cursor here so that, when a console app quits, we reset
838 * the cursor to the default one. It's quite a hack since it doesn't proceed
839 * per - console process... This must be fixed.
841 * See GuiInitConsole(...) for more information.
844 /* Mouse is shown by default with its default cursor shape */
845 GuiData
->MouseCursorRefCount
= 0; // Reinitialize the reference counter
846 GuiSetMouseCursor(This
, NULL
);
850 GuiChangeTitle(IN OUT PFRONTEND This
)
852 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
853 // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
854 SetWindowText(GuiData
->hWindow
, GuiData
->Console
->Title
.Buffer
);
858 GuiChangeIcon(IN OUT PFRONTEND This
,
861 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
862 HICON hIcon
, hIconSm
;
864 if (IconHandle
== NULL
)
866 hIcon
= ghDefaultIcon
;
867 hIconSm
= ghDefaultIconSm
;
871 hIcon
= CopyIcon(IconHandle
);
872 hIconSm
= CopyIcon(IconHandle
);
880 if (hIcon
!= GuiData
->hIcon
)
882 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
884 DestroyIcon(GuiData
->hIcon
);
886 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
888 DestroyIcon(GuiData
->hIconSm
);
891 GuiData
->hIcon
= hIcon
;
892 GuiData
->hIconSm
= hIconSm
;
894 DPRINT("Set icons in GuiChangeIcon\n");
895 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
896 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
903 GuiGetConsoleWindowHandle(IN OUT PFRONTEND This
)
905 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
906 return GuiData
->hWindow
;
910 GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This
,
913 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
914 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
917 UINT WidthUnit
, HeightUnit
;
921 if (!SystemParametersInfoW(SPI_GETWORKAREA
, 0, &WorkArea
, 0))
923 DPRINT1("SystemParametersInfoW failed - What to do ??\n");
927 ActiveBuffer
= GuiData
->ActiveBuffer
;
930 GetScreenBufferSizeUnits(ActiveBuffer
, GuiData
, &WidthUnit
, &HeightUnit
);
934 /* Default: text mode */
935 WidthUnit
= GuiData
->CharWidth
;
936 HeightUnit
= GuiData
->CharHeight
;
939 width
= WorkArea
.right
;
940 height
= WorkArea
.bottom
;
942 width
-= (2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
)));
943 height
-= (2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
));
945 if (width
< 0) width
= 0;
946 if (height
< 0) height
= 0;
948 pSize
->X
= (SHORT
)(width
/ (int)WidthUnit
) /* HACK */ + 2;
949 pSize
->Y
= (SHORT
)(height
/ (int)HeightUnit
) /* HACK */ + 1;
953 GuiGetSelectionInfo(IN OUT PFRONTEND This
,
954 PCONSOLE_SELECTION_INFO pSelectionInfo
)
956 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
958 if (pSelectionInfo
== NULL
) return FALSE
;
960 ZeroMemory(pSelectionInfo
, sizeof(CONSOLE_SELECTION_INFO
));
961 if (GuiData
->Selection
.dwFlags
!= CONSOLE_NO_SELECTION
)
962 RtlCopyMemory(pSelectionInfo
, &GuiData
->Selection
, sizeof(CONSOLE_SELECTION_INFO
));
968 GuiSetPalette(IN OUT PFRONTEND This
,
969 HPALETTE PaletteHandle
,
972 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
975 // if (GetType(GuiData->ActiveBuffer) != GRAPHICS_BUFFER) return FALSE;
976 if (PaletteHandle
== NULL
) return FALSE
;
978 /* Set the new palette for the framebuffer */
979 OldPalette
= SelectPalette(GuiData
->hMemDC
, PaletteHandle
, FALSE
);
980 if (OldPalette
== NULL
) return FALSE
;
982 /* Specify the use of the system palette for the framebuffer */
983 SetSystemPaletteUse(GuiData
->hMemDC
, PaletteUsage
);
985 /* Realize the (logical) palette */
986 RealizePalette(GuiData
->hMemDC
);
988 /* Save the original system palette handle */
989 if (GuiData
->hSysPalette
== NULL
) GuiData
->hSysPalette
= OldPalette
;
995 GuiGetDisplayMode(IN OUT PFRONTEND This
)
997 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
998 ULONG DisplayMode
= 0;
1000 if (GuiData
->GuiInfo
.FullScreen
)
1001 DisplayMode
|= CONSOLE_FULLSCREEN_HARDWARE
; // CONSOLE_FULLSCREEN
1003 DisplayMode
|= CONSOLE_WINDOWED
;
1009 GuiSetDisplayMode(IN OUT PFRONTEND This
,
1012 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1015 if (NewMode
& ~(CONSOLE_FULLSCREEN_MODE
| CONSOLE_WINDOWED_MODE
))
1018 FullScreen
= ((NewMode
& CONSOLE_FULLSCREEN_MODE
) != 0);
1020 if (FullScreen
!= GuiData
->GuiInfo
.FullScreen
)
1022 SwitchFullScreen(GuiData
, FullScreen
);
1029 GuiShowMouseCursor(IN OUT PFRONTEND This
,
1032 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1034 /* Set the reference count */
1035 if (Show
) ++GuiData
->MouseCursorRefCount
;
1036 else --GuiData
->MouseCursorRefCount
;
1038 /* Effectively show (or hide) the cursor (use special values for (w|l)Param) */
1039 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
1041 return GuiData
->MouseCursorRefCount
;
1045 GuiSetMouseCursor(IN OUT PFRONTEND This
,
1046 HCURSOR CursorHandle
)
1048 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1051 * Set the cursor's handle. If the given handle is NULL,
1052 * then restore the default cursor.
1054 GuiData
->hCursor
= (CursorHandle
? CursorHandle
: ghDefaultCursor
);
1056 /* Effectively modify the shape of the cursor (use special values for (w|l)Param) */
1057 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
1063 GuiMenuControl(IN OUT PFRONTEND This
,
1067 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1069 GuiData
->CmdIdLow
= CmdIdLow
;
1070 GuiData
->CmdIdHigh
= CmdIdHigh
;
1072 return GetSystemMenu(GuiData
->hWindow
, FALSE
);
1076 GuiSetMenuClose(IN OUT PFRONTEND This
,
1080 * NOTE: See http://www.mail-archive.com/harbour@harbour-project.org/msg27509.html
1081 * or http://harbour-devel.1590103.n2.nabble.com/Question-about-hb-gt-win-CtrlHandler-usage-td4670862i20.html
1082 * for more information.
1085 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1086 HMENU hSysMenu
= GetSystemMenu(GuiData
->hWindow
, FALSE
);
1088 if (hSysMenu
== NULL
) return FALSE
;
1090 GuiData
->IsCloseButtonEnabled
= Enable
;
1091 EnableMenuItem(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
| (Enable
? MF_ENABLED
: MF_GRAYED
));
1096 static FRONTEND_VTBL GuiVtbl
=
1105 GuiSetActiveScreenBuffer
,
1106 GuiReleaseScreenBuffer
,
1107 GuiProcessKeyCallback
,
1108 GuiRefreshInternalInfo
,
1111 GuiGetConsoleWindowHandle
,
1112 GuiGetLargestConsoleWindowSize
,
1113 GuiGetSelectionInfo
,
1125 LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo
,
1126 IN OUT PCONSOLE_INFO ConsoleInfo
)
1128 #define PATH_SEPARATOR L'\\'
1130 BOOL RetVal
= FALSE
;
1131 HRESULT hRes
= S_OK
;
1132 LPWSTR LinkName
= NULL
;
1135 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
1138 ConsoleStartInfo
->IconPath
[0] = L
'\0';
1139 ConsoleStartInfo
->IconIndex
= 0;
1141 /* 1- Find the last path separator if any */
1142 LinkName
= wcsrchr(ConsoleStartInfo
->ConsoleTitle
, PATH_SEPARATOR
);
1143 if (LinkName
== NULL
)
1145 LinkName
= ConsoleStartInfo
->ConsoleTitle
;
1149 /* Skip the path separator */
1153 /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
1154 Length
= wcslen(LinkName
);
1155 if ( (Length
<= 4) || (wcsicmp(LinkName
+ (Length
- 4), L
".lnk") != 0) )
1158 /* 3- It may be a link. Try to retrieve some properties */
1159 hRes
= CoInitialize(NULL
);
1160 if (SUCCEEDED(hRes
))
1162 /* Get a pointer to the IShellLink interface */
1163 IShellLinkW
* pshl
= NULL
;
1164 hRes
= CoCreateInstance(&CLSID_ShellLink
,
1166 CLSCTX_INPROC_SERVER
,
1169 if (SUCCEEDED(hRes
))
1171 /* Get a pointer to the IPersistFile interface */
1172 IPersistFile
* ppf
= NULL
;
1173 hRes
= IPersistFile_QueryInterface(pshl
, &IID_IPersistFile
, (LPVOID
*)&ppf
);
1174 if (SUCCEEDED(hRes
))
1176 /* Load the shortcut */
1177 hRes
= IPersistFile_Load(ppf
, ConsoleStartInfo
->ConsoleTitle
, STGM_READ
);
1178 if (SUCCEEDED(hRes
))
1181 * Finally we can get the properties !
1182 * Update the old ones if needed.
1187 /* Reset the name of the console with the name of the shortcut */
1188 Length
= min(/*Length*/ Length
- 4, // 4 == len(".lnk")
1189 sizeof(ConsoleInfo
->ConsoleTitle
) / sizeof(ConsoleInfo
->ConsoleTitle
[0]) - 1);
1190 wcsncpy(ConsoleInfo
->ConsoleTitle
, LinkName
, Length
);
1191 ConsoleInfo
->ConsoleTitle
[Length
] = L
'\0';
1193 /* Get the window showing command */
1194 hRes
= IShellLinkW_GetShowCmd(pshl
, &ShowCmd
);
1195 if (SUCCEEDED(hRes
)) ConsoleStartInfo
->wShowWindow
= (WORD
)ShowCmd
;
1197 /* Get the hotkey */
1198 // hRes = pshl->GetHotkey(&ShowCmd);
1199 // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey;
1201 /* Get the icon location, if any */
1203 hRes
= IShellLinkW_GetIconLocation(pshl
,
1204 ConsoleStartInfo
->IconPath
,
1205 sizeof(ConsoleStartInfo
->IconPath
)/sizeof(ConsoleStartInfo
->IconPath
[0]) - 1, // == MAX_PATH
1206 &ConsoleStartInfo
->IconIndex
);
1207 if (!SUCCEEDED(hRes
))
1209 ConsoleStartInfo
->IconPath
[0] = L
'\0';
1210 ConsoleStartInfo
->IconIndex
= 0;
1213 // FIXME: Since we still don't load console properties from the shortcut,
1214 // return false. When this will be done, we will return true instead.
1217 IPersistFile_Release(ppf
);
1219 IShellLinkW_Release(pshl
);
1228 GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd
,
1229 IN OUT PCONSOLE_INFO ConsoleInfo
,
1230 IN OUT PVOID ExtraConsoleInfo
,
1233 PCONSOLE_START_INFO ConsoleStartInfo
= ExtraConsoleInfo
;
1234 PGUI_INIT_INFO GuiInitInfo
;
1236 if (FrontEnd
== NULL
|| ConsoleInfo
== NULL
|| ConsoleStartInfo
== NULL
)
1237 return STATUS_INVALID_PARAMETER
;
1239 /* Initialize GUI terminal emulator common functionalities */
1240 if (!GuiInit()) return STATUS_UNSUCCESSFUL
;
1243 * Load per-application terminal settings.
1245 * Check whether the process creating the console was launched via
1246 * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the
1247 * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too.
1249 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
)
1251 if (!LoadShellLinkConsoleInfo(ConsoleStartInfo
, ConsoleInfo
))
1253 ConsoleStartInfo
->dwStartupFlags
&= ~STARTF_TITLEISLINKNAME
;
1258 * Initialize a private initialization info structure for later use.
1259 * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd.
1261 GuiInitInfo
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_INIT_INFO
));
1262 if (GuiInitInfo
== NULL
) return STATUS_NO_MEMORY
;
1264 // HACK: We suppose that the pointers will be valid in GuiInitFrontEnd...
1265 GuiInitInfo
->ConsoleInfo
= ConsoleInfo
;
1266 GuiInitInfo
->ConsoleStartInfo
= ConsoleStartInfo
;
1267 GuiInitInfo
->ProcessId
= ProcessId
;
1269 /* Finally, initialize the frontend structure */
1270 FrontEnd
->Vtbl
= &GuiVtbl
;
1271 FrontEnd
->Data
= NULL
;
1272 FrontEnd
->OldData
= GuiInitInfo
;
1274 return STATUS_SUCCESS
;
1278 GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd
)
1280 if (FrontEnd
== NULL
) return STATUS_INVALID_PARAMETER
;
1282 if (FrontEnd
->Data
) GuiDeinitFrontEnd(FrontEnd
);
1283 if (FrontEnd
->OldData
) ConsoleFreeHeap(FrontEnd
->OldData
);
1285 return STATUS_SUCCESS
;