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 *******************************************************************/
22 // HACK!! Remove it when the hack in GuiWriteStream is fixed
23 #define CONGUI_UPDATE_TIME 0
24 #define CONGUI_UPDATE_TIMER 1
26 #define PM_CREATE_CONSOLE (WM_APP + 1)
27 #define PM_DESTROY_CONSOLE (WM_APP + 2)
30 /* GLOBALS ********************************************************************/
32 typedef struct _GUI_INIT_INFO
34 PCONSOLE_INFO ConsoleInfo
;
35 PCONSOLE_START_INFO ConsoleStartInfo
;
37 BOOLEAN IsWindowVisible
;
38 } GUI_INIT_INFO
, *PGUI_INIT_INFO
;
40 static BOOL ConsInitialized
= FALSE
;
41 static HANDLE hInputThread
= NULL
;
42 static DWORD dwInputThreadId
= 0;
44 extern HICON ghDefaultIcon
;
45 extern HICON ghDefaultIconSm
;
46 extern HCURSOR ghDefaultCursor
;
49 SetConWndConsoleLeaderCID(IN PGUI_CONSOLE_DATA GuiData
);
51 RegisterConWndClass(IN HINSTANCE hInstance
);
53 UnRegisterConWndClass(HINSTANCE hInstance
);
55 /* FUNCTIONS ******************************************************************/
58 GetScreenBufferSizeUnits(IN PCONSOLE_SCREEN_BUFFER Buffer
,
59 IN PGUI_CONSOLE_DATA GuiData
,
63 if (Buffer
== NULL
|| GuiData
== NULL
||
64 WidthUnit
== NULL
|| HeightUnit
== NULL
)
69 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
71 *WidthUnit
= GuiData
->CharWidth
;
72 *HeightUnit
= GuiData
->CharHeight
;
74 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
82 GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData
)
84 /* Move the window if needed (not positioned by the system) */
85 if (!GuiData
->GuiInfo
.AutoPosition
)
87 SetWindowPos(GuiData
->hWindow
,
89 GuiData
->GuiInfo
.WindowOrigin
.x
,
90 GuiData
->GuiInfo
.WindowOrigin
.y
,
92 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
97 SmallRectToRect(PGUI_CONSOLE_DATA GuiData
, PRECT Rect
, PSMALL_RECT SmallRect
)
99 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
100 UINT WidthUnit
, HeightUnit
;
102 GetScreenBufferSizeUnits(Buffer
, GuiData
, &WidthUnit
, &HeightUnit
);
104 Rect
->left
= (SmallRect
->Left
- Buffer
->ViewOrigin
.X
) * WidthUnit
;
105 Rect
->top
= (SmallRect
->Top
- Buffer
->ViewOrigin
.Y
) * HeightUnit
;
106 Rect
->right
= (SmallRect
->Right
+ 1 - Buffer
->ViewOrigin
.X
) * WidthUnit
;
107 Rect
->bottom
= (SmallRect
->Bottom
+ 1 - Buffer
->ViewOrigin
.Y
) * HeightUnit
;
111 DrawRegion(PGUI_CONSOLE_DATA GuiData
,
116 SmallRectToRect(GuiData
, &RegionRect
, Region
);
117 /* Do not erase the background: it speeds up redrawing and reduce flickering */
118 InvalidateRect(GuiData
->hWindow
, &RegionRect
, FALSE
);
119 /**UpdateWindow(GuiData->hWindow);**/
123 InvalidateCell(PGUI_CONSOLE_DATA GuiData
,
126 SMALL_RECT CellRect
= { x
, y
, x
, y
};
127 DrawRegion(GuiData
, &CellRect
);
131 /******************************************************************************
132 * GUI Terminal Initialization *
133 ******************************************************************************/
136 SwitchFullScreen(PGUI_CONSOLE_DATA GuiData
, BOOL FullScreen
);
138 CreateSysMenu(HWND hWnd
);
141 GuiConsoleInputThread(PVOID Param
)
143 PHANDLE GraphicsStartupEvent
= (PHANDLE
)Param
;
144 LONG WindowCount
= 0;
148 * This thread dispatches all the console notifications to the
149 * notification window. It is common for all the console windows.
152 /* The thread has been initialized, set the event */
153 NtSetEvent(*GraphicsStartupEvent
, NULL
);
155 while (GetMessageW(&msg
, NULL
, 0, 0))
159 case PM_CREATE_CONSOLE
:
161 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)msg
.lParam
;
162 PCONSRV_CONSOLE 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
,
176 GuiData
->IsWindowVisible
? HWND_DESKTOP
: HWND_MESSAGE
,
180 if (NewWindow
== NULL
)
182 DPRINT1("Failed to create a new console window\n");
186 ASSERT(NewWindow
== GuiData
->hWindow
);
188 InterlockedIncrement(&WindowCount
);
191 // FIXME: TODO: Move everything there into conwnd.c!OnNcCreate()
194 /* Retrieve our real position */
195 // See conwnd.c!OnMove()
196 GetWindowRect(GuiData
->hWindow
, &rcWnd
);
197 GuiData
->GuiInfo
.WindowOrigin
.x
= rcWnd
.left
;
198 GuiData
->GuiInfo
.WindowOrigin
.y
= rcWnd
.top
;
200 if (GuiData
->IsWindowVisible
)
202 /* Move and resize the window to the user's values */
203 /* CAN WE DEADLOCK ?? */
204 GuiConsoleMoveWindow(GuiData
); // FIXME: This MUST be done via the CreateWindowExW call.
205 SendMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
208 // FIXME: HACK: Potential HACK for CORE-8129; see revision 63595.
209 CreateSysMenu(GuiData
->hWindow
);
211 if (GuiData
->IsWindowVisible
)
213 /* Switch to full-screen mode if necessary */
214 // FIXME: Move elsewhere, it cause misdrawings of the window.
215 if (GuiData
->GuiInfo
.FullScreen
) SwitchFullScreen(GuiData
, TRUE
);
217 DPRINT("PM_CREATE_CONSOLE -- showing window\n");
218 // ShowWindow(NewWindow, (int)GuiData->GuiInfo.ShowWindow);
219 ShowWindowAsync(NewWindow
, (int)GuiData
->GuiInfo
.ShowWindow
);
220 DPRINT("Window showed\n");
224 DPRINT("PM_CREATE_CONSOLE -- hidden window\n");
225 ShowWindowAsync(NewWindow
, SW_HIDE
);
231 case PM_DESTROY_CONSOLE
:
233 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)msg
.lParam
;
236 /* Exit the full screen mode if it was already set */
237 // LeaveFullScreen(GuiData);
240 * Window creation is done using a PostMessage(), so it's possible
241 * that the window that we want to destroy doesn't exist yet.
242 * So first empty the message queue.
245 while (PeekMessageW(&TempMsg, NULL, 0, 0, PM_REMOVE))
247 TranslateMessage(&TempMsg);
248 DispatchMessageW(&TempMsg);
250 while (PeekMessageW(&TempMsg
, NULL
, 0, 0, PM_REMOVE
)) ;
252 if (GuiData
->hWindow
== NULL
) continue;
254 DestroyWindow(GuiData
->hWindow
);
256 NtSetEvent(GuiData
->hGuiTermEvent
, NULL
);
258 if (InterlockedDecrement(&WindowCount
) == 0)
260 DPRINT("CONSRV: Going to quit the Input Thread!!\n");
268 TranslateMessage(&msg
);
269 DispatchMessageW(&msg
);
273 DPRINT("CONSRV: Quit the Input Thread!!\n");
284 /* Exit if we were already initialized */
285 // if (ConsInitialized) return TRUE;
288 * Initialize and register the console window class, if needed.
290 if (!ConsInitialized
)
292 if (!RegisterConWndClass(ConSrvDllInstance
)) return FALSE
;
293 ConsInitialized
= TRUE
;
297 * Set-up the console input thread
299 if (hInputThread
== NULL
)
301 HANDLE GraphicsStartupEvent
;
304 Status
= NtCreateEvent(&GraphicsStartupEvent
, EVENT_ALL_ACCESS
,
305 NULL
, SynchronizationEvent
, FALSE
);
306 if (!NT_SUCCESS(Status
)) return FALSE
;
308 hInputThread
= CreateThread(NULL
,
310 GuiConsoleInputThread
,
311 (PVOID
)&GraphicsStartupEvent
,
314 if (hInputThread
== NULL
)
316 NtClose(GraphicsStartupEvent
);
317 DPRINT1("CONSRV: Failed to create graphics console thread.\n");
320 SetThreadPriority(hInputThread
, THREAD_PRIORITY_HIGHEST
);
321 CloseHandle(hInputThread
);
323 WaitForSingleObject(GraphicsStartupEvent
, INFINITE
);
324 NtClose(GraphicsStartupEvent
);
327 // ConsInitialized = TRUE;
333 /******************************************************************************
334 * GUI Console Driver *
335 ******************************************************************************/
338 GuiDeinitFrontEnd(IN OUT PFRONTEND This
);
340 static NTSTATUS NTAPI
341 GuiInitFrontEnd(IN OUT PFRONTEND This
,
342 IN PCONSRV_CONSOLE Console
)
344 PGUI_INIT_INFO GuiInitInfo
;
345 PCONSOLE_INFO ConsoleInfo
;
346 PCONSOLE_START_INFO ConsoleStartInfo
;
348 PGUI_CONSOLE_DATA GuiData
;
349 GUI_CONSOLE_INFO TermInfo
;
351 if (This
== NULL
|| Console
== NULL
|| This
->Context2
== NULL
)
352 return STATUS_INVALID_PARAMETER
;
354 ASSERT(This
->Console
== Console
);
356 GuiInitInfo
= This
->Context2
;
358 if (GuiInitInfo
->ConsoleInfo
== NULL
|| GuiInitInfo
->ConsoleStartInfo
== NULL
)
359 return STATUS_INVALID_PARAMETER
;
361 ConsoleInfo
= GuiInitInfo
->ConsoleInfo
;
362 ConsoleStartInfo
= GuiInitInfo
->ConsoleStartInfo
;
364 /* Terminal data allocation */
365 GuiData
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_CONSOLE_DATA
));
368 DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
369 return STATUS_UNSUCCESSFUL
;
371 ///// /* HACK */ Console->FrontEndIFace.Context = (PVOID)GuiData; /* HACK */
372 GuiData
->Console
= Console
;
373 GuiData
->ActiveBuffer
= Console
->ActiveBuffer
;
374 GuiData
->hWindow
= NULL
;
375 GuiData
->IsWindowVisible
= GuiInitInfo
->IsWindowVisible
;
377 /* The console can be resized */
378 Console
->FixedSize
= FALSE
;
380 InitializeCriticalSection(&GuiData
->Lock
);
384 * Load terminal settings
387 /* 1. Load the default settings */
388 GuiConsoleGetDefaultSettings(&TermInfo
, GuiInitInfo
->ProcessId
);
390 if (GuiData
->IsWindowVisible
)
392 /* 2. Load the remaining console settings via the registry */
393 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
395 /* Load the terminal infos from the registry */
396 GuiConsoleReadUserSettings(&TermInfo
,
397 ConsoleInfo
->ConsoleTitle
,
398 GuiInitInfo
->ProcessId
);
401 * Now, update them with the properties the user might gave to us
402 * via the STARTUPINFO structure before calling CreateProcess
403 * (and which was transmitted via the ConsoleStartInfo structure).
404 * We therefore overwrite the values read in the registry.
406 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USESHOWWINDOW
)
408 TermInfo
.ShowWindow
= ConsoleStartInfo
->wShowWindow
;
410 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USEPOSITION
)
412 TermInfo
.AutoPosition
= FALSE
;
413 TermInfo
.WindowOrigin
.x
= ConsoleStartInfo
->dwWindowOrigin
.X
;
414 TermInfo
.WindowOrigin
.y
= ConsoleStartInfo
->dwWindowOrigin
.Y
;
416 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_RUNFULLSCREEN
)
418 TermInfo
.FullScreen
= TRUE
;
429 wcsncpy(GuiData
->GuiInfo
.FaceName
, TermInfo
.FaceName
, LF_FACESIZE
);
430 GuiData
->GuiInfo
.FaceName
[LF_FACESIZE
- 1] = UNICODE_NULL
;
431 GuiData
->GuiInfo
.FontFamily
= TermInfo
.FontFamily
;
432 GuiData
->GuiInfo
.FontSize
= TermInfo
.FontSize
;
433 GuiData
->GuiInfo
.FontWeight
= TermInfo
.FontWeight
;
436 GuiData
->GuiInfo
.FullScreen
= TermInfo
.FullScreen
;
437 GuiData
->GuiInfo
.ShowWindow
= TermInfo
.ShowWindow
;
438 GuiData
->GuiInfo
.AutoPosition
= TermInfo
.AutoPosition
;
439 GuiData
->GuiInfo
.WindowOrigin
= TermInfo
.WindowOrigin
;
441 /* Initialize the icon handles */
442 if (ConsoleStartInfo
->hIcon
!= NULL
)
443 GuiData
->hIcon
= ConsoleStartInfo
->hIcon
;
445 GuiData
->hIcon
= ghDefaultIcon
;
447 if (ConsoleStartInfo
->hIconSm
!= NULL
)
448 GuiData
->hIconSm
= ConsoleStartInfo
->hIconSm
;
450 GuiData
->hIconSm
= ghDefaultIconSm
;
452 ASSERT(GuiData
->hIcon
&& GuiData
->hIconSm
);
454 /* Mouse is shown by default with its default cursor shape */
455 GuiData
->hCursor
= ghDefaultCursor
;
456 GuiData
->MouseCursorRefCount
= 0;
458 /* A priori don't ignore mouse signals */
459 GuiData
->IgnoreNextMouseSignal
= FALSE
;
461 /* Close button and the corresponding system menu item are enabled by default */
462 GuiData
->IsCloseButtonEnabled
= TRUE
;
464 /* There is no user-reserved menu id range by default */
465 GuiData
->CmdIdLow
= GuiData
->CmdIdHigh
= 0;
467 /* Initialize the selection */
468 RtlZeroMemory(&GuiData
->Selection
, sizeof(GuiData
->Selection
));
469 GuiData
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
470 RtlZeroMemory(&GuiData
->dwSelectionCursor
, sizeof(GuiData
->dwSelectionCursor
));
471 GuiData
->LineSelection
= FALSE
; // Default to block selection
472 // TODO: Retrieve the selection mode via the registry.
474 /* Finally, finish to initialize the frontend structure */
475 This
->Context
= GuiData
;
476 if (This
->Context2
) ConsoleFreeHeap(This
->Context2
);
477 This
->Context2
= NULL
;
480 * We need to wait until the GUI has been fully initialized
481 * to retrieve custom settings i.e. WindowSize etc...
482 * Ideally we could use SendNotifyMessage for this but its not
485 NtCreateEvent(&GuiData
->hGuiInitEvent
, EVENT_ALL_ACCESS
,
486 NULL
, SynchronizationEvent
, FALSE
);
487 NtCreateEvent(&GuiData
->hGuiTermEvent
, EVENT_ALL_ACCESS
,
488 NULL
, SynchronizationEvent
, FALSE
);
490 DPRINT("GUI - Checkpoint\n");
492 /* Create the terminal window */
493 PostThreadMessageW(dwInputThreadId
, PM_CREATE_CONSOLE
, 0, (LPARAM
)GuiData
);
495 /* Wait until initialization has finished */
496 WaitForSingleObject(GuiData
->hGuiInitEvent
, INFINITE
);
497 DPRINT("OK we created the console window\n");
498 NtClose(GuiData
->hGuiInitEvent
);
499 GuiData
->hGuiInitEvent
= NULL
;
501 /* Check whether we really succeeded in initializing the terminal window */
502 if (GuiData
->hWindow
== NULL
)
504 DPRINT("GuiInitConsole - We failed at creating a new terminal window\n");
505 GuiDeinitFrontEnd(This
);
506 return STATUS_UNSUCCESSFUL
;
509 return STATUS_SUCCESS
;
513 GuiDeinitFrontEnd(IN OUT PFRONTEND This
)
515 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
517 DPRINT("Send PM_DESTROY_CONSOLE message and wait on hGuiTermEvent...\n");
518 PostThreadMessageW(dwInputThreadId
, PM_DESTROY_CONSOLE
, 0, (LPARAM
)GuiData
);
519 WaitForSingleObject(GuiData
->hGuiTermEvent
, INFINITE
);
520 DPRINT("hGuiTermEvent set\n");
521 NtClose(GuiData
->hGuiTermEvent
);
522 GuiData
->hGuiTermEvent
= NULL
;
524 DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
525 GuiData
->hIcon
, ghDefaultIcon
, GuiData
->hIconSm
, ghDefaultIconSm
);
526 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
528 DPRINT("Destroy hIcon\n");
529 DestroyIcon(GuiData
->hIcon
);
531 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
533 DPRINT("Destroy hIconSm\n");
534 DestroyIcon(GuiData
->hIconSm
);
537 This
->Context
= NULL
;
538 DeleteCriticalSection(&GuiData
->Lock
);
539 ConsoleFreeHeap(GuiData
);
541 DPRINT("Quit GuiDeinitFrontEnd\n");
545 GuiDrawRegion(IN OUT PFRONTEND This
,
548 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
550 /* Do nothing if the window is hidden */
551 if (!GuiData
->IsWindowVisible
) return;
553 DrawRegion(GuiData
, Region
);
557 GuiWriteStream(IN OUT PFRONTEND This
,
565 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
566 PCONSOLE_SCREEN_BUFFER Buff
;
567 SHORT CursorEndX
, CursorEndY
;
570 if (NULL
== GuiData
|| NULL
== GuiData
->hWindow
) return;
572 /* Do nothing if the window is hidden */
573 if (!GuiData
->IsWindowVisible
) return;
575 Buff
= GuiData
->ActiveBuffer
;
576 if (GetType(Buff
) != TEXTMODE_BUFFER
) return;
578 if (0 != ScrolledLines
)
582 ScrollRect
.right
= Buff
->ViewSize
.X
* GuiData
->CharWidth
;
583 ScrollRect
.bottom
= Region
->Top
* GuiData
->CharHeight
;
585 ScrollWindowEx(GuiData
->hWindow
,
587 -(int)(ScrolledLines
* GuiData
->CharHeight
),
595 DrawRegion(GuiData
, Region
);
597 if (CursorStartX
< Region
->Left
|| Region
->Right
< CursorStartX
598 || CursorStartY
< Region
->Top
|| Region
->Bottom
< CursorStartY
)
600 InvalidateCell(GuiData
, CursorStartX
, CursorStartY
);
603 CursorEndX
= Buff
->CursorPosition
.X
;
604 CursorEndY
= Buff
->CursorPosition
.Y
;
605 if ((CursorEndX
< Region
->Left
|| Region
->Right
< CursorEndX
606 || CursorEndY
< Region
->Top
|| Region
->Bottom
< CursorEndY
)
607 && (CursorEndX
!= CursorStartX
|| CursorEndY
!= CursorStartY
))
609 InvalidateCell(GuiData
, CursorEndX
, CursorEndY
);
613 // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
614 // repaint the window without having it just freeze up and stay on the screen permanently.
615 Buff
->CursorBlinkOn
= TRUE
;
616 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
619 /* static */ VOID NTAPI
620 GuiRingBell(IN OUT PFRONTEND This
)
622 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
624 /* Emit an error beep sound */
625 SendNotifyMessage(GuiData
->hWindow
, PM_CONSOLE_BEEP
, 0, 0);
629 GuiSetCursorInfo(IN OUT PFRONTEND This
,
630 PCONSOLE_SCREEN_BUFFER Buff
)
632 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
634 /* Do nothing if the window is hidden */
635 if (!GuiData
->IsWindowVisible
) return TRUE
;
637 if (GuiData
->ActiveBuffer
== Buff
)
639 InvalidateCell(GuiData
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
646 GuiSetScreenInfo(IN OUT PFRONTEND This
,
647 PCONSOLE_SCREEN_BUFFER Buff
,
651 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
653 /* Do nothing if the window is hidden */
654 if (!GuiData
->IsWindowVisible
) return TRUE
;
656 if (GuiData
->ActiveBuffer
== Buff
)
658 /* Redraw char at old position (remove cursor) */
659 InvalidateCell(GuiData
, OldCursorX
, OldCursorY
);
660 /* Redraw char at new position (show cursor) */
661 InvalidateCell(GuiData
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
668 GuiResizeTerminal(IN OUT PFRONTEND This
)
670 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
672 /* Resize the window to the user's values */
673 PostMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
677 GuiSetActiveScreenBuffer(IN OUT PFRONTEND This
)
679 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
680 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
683 EnterCriticalSection(&GuiData
->Lock
);
684 GuiData
->WindowSizeLock
= TRUE
;
686 InterlockedExchangePointer(&GuiData
->ActiveBuffer
,
687 ConDrvGetActiveScreenBuffer(GuiData
->Console
));
689 GuiData
->WindowSizeLock
= FALSE
;
690 LeaveCriticalSection(&GuiData
->Lock
);
692 ActiveBuffer
= GuiData
->ActiveBuffer
;
694 /* Change the current palette */
695 if (ActiveBuffer
->PaletteHandle
== NULL
)
697 hPalette
= GuiData
->hSysPalette
;
701 hPalette
= ActiveBuffer
->PaletteHandle
;
704 DPRINT("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette
);
706 /* Set the new palette for the framebuffer */
707 SelectPalette(GuiData
->hMemDC
, hPalette
, FALSE
);
709 /* Specify the use of the system palette for the framebuffer */
710 SetSystemPaletteUse(GuiData
->hMemDC
, ActiveBuffer
->PaletteUsage
);
712 /* Realize the (logical) palette */
713 RealizePalette(GuiData
->hMemDC
);
715 GuiResizeTerminal(This
);
716 // ConioDrawConsole(Console);
720 GuiReleaseScreenBuffer(IN OUT PFRONTEND This
,
721 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer
)
723 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
726 * If we were notified to release a screen buffer that is not actually
727 * ours, then just ignore the notification...
729 if (ScreenBuffer
!= GuiData
->ActiveBuffer
) return;
732 * ... else, we must release our active buffer. Two cases are present:
733 * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console
734 * active screen buffer, then we can safely switch to it.
735 * - If ScreenBuffer IS the console active screen buffer, we must release
739 /* Release the old active palette and set the default one */
740 if (GetCurrentObject(GuiData
->hMemDC
, OBJ_PAL
) == ScreenBuffer
->PaletteHandle
)
742 /* Set the new palette */
743 SelectPalette(GuiData
->hMemDC
, GuiData
->hSysPalette
, FALSE
);
746 /* Set the adequate active screen buffer */
747 if (ScreenBuffer
!= GuiData
->Console
->ActiveBuffer
)
749 GuiSetActiveScreenBuffer(This
);
753 EnterCriticalSection(&GuiData
->Lock
);
754 GuiData
->WindowSizeLock
= TRUE
;
756 InterlockedExchangePointer(&GuiData
->ActiveBuffer
, NULL
);
758 GuiData
->WindowSizeLock
= FALSE
;
759 LeaveCriticalSection(&GuiData
->Lock
);
764 GuiSetMouseCursor(IN OUT PFRONTEND This
,
765 HCURSOR CursorHandle
);
768 GuiRefreshInternalInfo(IN OUT PFRONTEND This
)
770 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
772 /* Update the console leader information held by the window */
773 SetConWndConsoleLeaderCID(GuiData
);
777 * We reset the cursor here so that, when a console app quits, we reset
778 * the cursor to the default one. It's quite a hack since it doesn't proceed
779 * per - console process... This must be fixed.
781 * See GuiInitConsole(...) for more information.
784 /* Mouse is shown by default with its default cursor shape */
785 GuiData
->MouseCursorRefCount
= 0; // Reinitialize the reference counter
786 GuiSetMouseCursor(This
, NULL
);
790 GuiChangeTitle(IN OUT PFRONTEND This
)
792 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
793 // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
794 SetWindowText(GuiData
->hWindow
, GuiData
->Console
->Title
.Buffer
);
798 GuiChangeIcon(IN OUT PFRONTEND This
,
801 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
802 HICON hIcon
, hIconSm
;
804 if (IconHandle
== NULL
)
806 hIcon
= ghDefaultIcon
;
807 hIconSm
= ghDefaultIconSm
;
811 hIcon
= CopyIcon(IconHandle
);
812 hIconSm
= CopyIcon(IconHandle
);
820 if (hIcon
!= GuiData
->hIcon
)
822 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
824 DestroyIcon(GuiData
->hIcon
);
826 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
828 DestroyIcon(GuiData
->hIconSm
);
831 GuiData
->hIcon
= hIcon
;
832 GuiData
->hIconSm
= hIconSm
;
834 DPRINT("Set icons in GuiChangeIcon\n");
835 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
836 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
843 GuiGetConsoleWindowHandle(IN OUT PFRONTEND This
)
845 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
846 return GuiData
->hWindow
;
850 GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This
,
853 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
854 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
857 UINT WidthUnit
, HeightUnit
;
861 if (!SystemParametersInfoW(SPI_GETWORKAREA
, 0, &WorkArea
, 0))
863 DPRINT1("SystemParametersInfoW failed - What to do ??\n");
867 ActiveBuffer
= GuiData
->ActiveBuffer
;
870 GetScreenBufferSizeUnits(ActiveBuffer
, GuiData
, &WidthUnit
, &HeightUnit
);
874 /* Default: text mode */
875 WidthUnit
= GuiData
->CharWidth
;
876 HeightUnit
= GuiData
->CharHeight
;
879 width
= WorkArea
.right
;
880 height
= WorkArea
.bottom
;
882 width
-= (2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
)));
883 height
-= (2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
));
885 if (width
< 0) width
= 0;
886 if (height
< 0) height
= 0;
888 pSize
->X
= (SHORT
)(width
/ (int)WidthUnit
) /* HACK */ + 2;
889 pSize
->Y
= (SHORT
)(height
/ (int)HeightUnit
) /* HACK */ + 1;
893 GuiGetSelectionInfo(IN OUT PFRONTEND This
,
894 PCONSOLE_SELECTION_INFO pSelectionInfo
)
896 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
898 if (pSelectionInfo
== NULL
) return FALSE
;
900 ZeroMemory(pSelectionInfo
, sizeof(CONSOLE_SELECTION_INFO
));
901 if (GuiData
->Selection
.dwFlags
!= CONSOLE_NO_SELECTION
)
902 RtlCopyMemory(pSelectionInfo
, &GuiData
->Selection
, sizeof(CONSOLE_SELECTION_INFO
));
908 GuiSetPalette(IN OUT PFRONTEND This
,
909 HPALETTE PaletteHandle
,
912 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
915 // if (GetType(GuiData->ActiveBuffer) != GRAPHICS_BUFFER) return FALSE;
916 if (PaletteHandle
== NULL
) return FALSE
;
918 /* Set the new palette for the framebuffer */
919 OldPalette
= SelectPalette(GuiData
->hMemDC
, PaletteHandle
, FALSE
);
920 if (OldPalette
== NULL
) return FALSE
;
922 /* Specify the use of the system palette for the framebuffer */
923 SetSystemPaletteUse(GuiData
->hMemDC
, PaletteUsage
);
925 /* Realize the (logical) palette */
926 RealizePalette(GuiData
->hMemDC
);
928 /* Save the original system palette handle */
929 if (GuiData
->hSysPalette
== NULL
) GuiData
->hSysPalette
= OldPalette
;
935 GuiGetDisplayMode(IN OUT PFRONTEND This
)
937 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
938 ULONG DisplayMode
= 0;
940 if (GuiData
->GuiInfo
.FullScreen
)
941 DisplayMode
|= CONSOLE_FULLSCREEN_HARDWARE
; // CONSOLE_FULLSCREEN
943 DisplayMode
|= CONSOLE_WINDOWED
;
949 GuiSetDisplayMode(IN OUT PFRONTEND This
,
952 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
955 if (NewMode
& ~(CONSOLE_FULLSCREEN_MODE
| CONSOLE_WINDOWED_MODE
))
958 /* Do nothing if the window is hidden */
959 if (!GuiData
->IsWindowVisible
) return TRUE
;
961 FullScreen
= ((NewMode
& CONSOLE_FULLSCREEN_MODE
) != 0);
963 if (FullScreen
!= GuiData
->GuiInfo
.FullScreen
)
965 SwitchFullScreen(GuiData
, FullScreen
);
972 GuiShowMouseCursor(IN OUT PFRONTEND This
,
975 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
977 if (GuiData
->IsWindowVisible
)
979 /* Set the reference count */
980 if (Show
) ++GuiData
->MouseCursorRefCount
;
981 else --GuiData
->MouseCursorRefCount
;
983 /* Effectively show (or hide) the cursor (use special values for (w|l)Param) */
984 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
987 return GuiData
->MouseCursorRefCount
;
991 GuiSetMouseCursor(IN OUT PFRONTEND This
,
992 HCURSOR CursorHandle
)
994 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
996 /* Do nothing if the window is hidden */
997 if (!GuiData
->IsWindowVisible
) return TRUE
;
1000 * Set the cursor's handle. If the given handle is NULL,
1001 * then restore the default cursor.
1003 GuiData
->hCursor
= (CursorHandle
? CursorHandle
: ghDefaultCursor
);
1005 /* Effectively modify the shape of the cursor (use special values for (w|l)Param) */
1006 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
1012 GuiMenuControl(IN OUT PFRONTEND This
,
1016 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
1018 GuiData
->CmdIdLow
= CmdIdLow
;
1019 GuiData
->CmdIdHigh
= CmdIdHigh
;
1021 return GetSystemMenu(GuiData
->hWindow
, FALSE
);
1025 GuiSetMenuClose(IN OUT PFRONTEND This
,
1029 * NOTE: See http://www.mail-archive.com/harbour@harbour-project.org/msg27509.html
1030 * or http://harbour-devel.1590103.n2.nabble.com/Question-about-hb-gt-win-CtrlHandler-usage-td4670862i20.html
1031 * for more information.
1034 PGUI_CONSOLE_DATA GuiData
= This
->Context
;
1035 HMENU hSysMenu
= GetSystemMenu(GuiData
->hWindow
, FALSE
);
1037 if (hSysMenu
== NULL
) return FALSE
;
1039 GuiData
->IsCloseButtonEnabled
= Enable
;
1040 EnableMenuItem(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
| (Enable
? MF_ENABLED
: MF_GRAYED
));
1045 static FRONTEND_VTBL GuiVtbl
=
1055 GuiSetActiveScreenBuffer
,
1056 GuiReleaseScreenBuffer
,
1057 GuiRefreshInternalInfo
,
1060 GuiGetConsoleWindowHandle
,
1061 GuiGetLargestConsoleWindowSize
,
1062 GuiGetSelectionInfo
,
1074 GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd
,
1075 IN OUT PCONSOLE_INFO ConsoleInfo
,
1076 IN OUT PVOID ExtraConsoleInfo
,
1079 PCONSOLE_INIT_INFO ConsoleInitInfo
= ExtraConsoleInfo
;
1080 PGUI_INIT_INFO GuiInitInfo
;
1082 if (FrontEnd
== NULL
|| ConsoleInfo
== NULL
|| ConsoleInitInfo
== NULL
)
1083 return STATUS_INVALID_PARAMETER
;
1085 /* Initialize GUI terminal emulator common functionalities */
1086 if (!GuiInit()) return STATUS_UNSUCCESSFUL
;
1089 * Initialize a private initialization info structure for later use.
1090 * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd.
1092 GuiInitInfo
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_INIT_INFO
));
1093 if (GuiInitInfo
== NULL
) return STATUS_NO_MEMORY
;
1095 // HACK: We suppose that the pointers will be valid in GuiInitFrontEnd...
1096 // If not, then copy exactly what we need in GuiInitInfo.
1097 GuiInitInfo
->ConsoleInfo
= ConsoleInfo
;
1098 GuiInitInfo
->ConsoleStartInfo
= ConsoleInitInfo
->ConsoleStartInfo
;
1099 GuiInitInfo
->ProcessId
= ProcessId
;
1100 GuiInitInfo
->IsWindowVisible
= ConsoleInitInfo
->IsWindowVisible
;
1102 /* Finally, initialize the frontend structure */
1103 FrontEnd
->Vtbl
= &GuiVtbl
;
1104 FrontEnd
->Context
= NULL
;
1105 FrontEnd
->Context2
= GuiInitInfo
;
1107 return STATUS_SUCCESS
;
1111 GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd
)
1113 if (FrontEnd
== NULL
) return STATUS_INVALID_PARAMETER
;
1115 if (FrontEnd
->Context
) GuiDeinitFrontEnd(FrontEnd
);
1116 if (FrontEnd
->Context2
) ConsoleFreeHeap(FrontEnd
->Context2
);
1118 return STATUS_SUCCESS
;