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 /* Not defined in any header file */
31 extern VOID NTAPI
PrivateCsrssManualGuiCheck(LONG Check
);
32 // See winsrv/usersrv/init.c line 234
35 /* GLOBALS ********************************************************************/
37 typedef struct _GUI_INIT_INFO
39 PCONSOLE_INFO ConsoleInfo
;
40 PCONSOLE_START_INFO ConsoleStartInfo
;
42 } GUI_INIT_INFO
, *PGUI_INIT_INFO
;
44 static BOOL ConsInitialized
= FALSE
;
45 static HANDLE hInputThread
= NULL
;
46 static DWORD dwInputThreadId
= 0;
48 extern HICON ghDefaultIcon
;
49 extern HICON ghDefaultIconSm
;
50 extern HCURSOR ghDefaultCursor
;
53 SetConWndConsoleLeaderCID(IN PGUI_CONSOLE_DATA GuiData
);
55 RegisterConWndClass(IN HINSTANCE hInstance
);
57 UnRegisterConWndClass(HINSTANCE hInstance
);
59 /* FUNCTIONS ******************************************************************/
62 GetScreenBufferSizeUnits(IN PCONSOLE_SCREEN_BUFFER Buffer
,
63 IN PGUI_CONSOLE_DATA GuiData
,
67 if (Buffer
== NULL
|| GuiData
== NULL
||
68 WidthUnit
== NULL
|| HeightUnit
== NULL
)
73 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
75 *WidthUnit
= GuiData
->CharWidth
;
76 *HeightUnit
= GuiData
->CharHeight
;
78 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
86 GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData
)
88 /* Move the window if needed (not positioned by the system) */
89 if (!GuiData
->GuiInfo
.AutoPosition
)
91 SetWindowPos(GuiData
->hWindow
,
93 GuiData
->GuiInfo
.WindowOrigin
.x
,
94 GuiData
->GuiInfo
.WindowOrigin
.y
,
96 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
101 SmallRectToRect(PGUI_CONSOLE_DATA GuiData
, PRECT Rect
, PSMALL_RECT SmallRect
)
103 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
104 UINT WidthUnit
, HeightUnit
;
106 GetScreenBufferSizeUnits(Buffer
, GuiData
, &WidthUnit
, &HeightUnit
);
108 Rect
->left
= (SmallRect
->Left
- Buffer
->ViewOrigin
.X
) * WidthUnit
;
109 Rect
->top
= (SmallRect
->Top
- Buffer
->ViewOrigin
.Y
) * HeightUnit
;
110 Rect
->right
= (SmallRect
->Right
+ 1 - Buffer
->ViewOrigin
.X
) * WidthUnit
;
111 Rect
->bottom
= (SmallRect
->Bottom
+ 1 - Buffer
->ViewOrigin
.Y
) * HeightUnit
;
115 DrawRegion(PGUI_CONSOLE_DATA GuiData
,
120 SmallRectToRect(GuiData
, &RegionRect
, Region
);
121 /* Do not erase the background: it speeds up redrawing and reduce flickering */
122 InvalidateRect(GuiData
->hWindow
, &RegionRect
, FALSE
);
123 /**UpdateWindow(GuiData->hWindow);**/
127 InvalidateCell(PGUI_CONSOLE_DATA GuiData
,
130 SMALL_RECT CellRect
= { x
, y
, x
, y
};
131 DrawRegion(GuiData
, &CellRect
);
135 /******************************************************************************
136 * GUI Terminal Initialization *
137 ******************************************************************************/
140 SwitchFullScreen(PGUI_CONSOLE_DATA GuiData
, BOOL FullScreen
);
142 CreateSysMenu(HWND hWnd
);
145 GuiConsoleInputThread(PVOID Data
)
147 PHANDLE GraphicsStartupEvent
= (PHANDLE
)Data
;
148 LONG WindowCount
= 0;
152 * This thread dispatches all the console notifications to the notify window.
153 * It is common for all the console windows.
156 /* The thread has been initialized, set the event */
157 SetEvent(*GraphicsStartupEvent
);
159 while (GetMessageW(&msg
, NULL
, 0, 0))
163 case PM_CREATE_CONSOLE
:
165 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)msg
.lParam
;
166 PCONSRV_CONSOLE Console
= GuiData
->Console
;
170 DPRINT("PM_CREATE_CONSOLE -- creating window\n");
172 PrivateCsrssManualGuiCheck(-1); // co_AddGuiApp
174 NewWindow
= CreateWindowExW(WS_EX_CLIENTEDGE
,
176 Console
->Title
.Buffer
,
177 WS_OVERLAPPEDWINDOW
| WS_HSCROLL
| WS_VSCROLL
,
186 if (NewWindow
== NULL
)
188 DPRINT1("Failed to create a new console window\n");
189 PrivateCsrssManualGuiCheck(+1); // RemoveGuiApp
193 ASSERT(NewWindow
== GuiData
->hWindow
);
195 InterlockedIncrement(&WindowCount
);
198 // FIXME: TODO: Move everything there into conwnd.c!OnNcCreate()
201 /* Retrieve our real position */
202 // See conwnd.c!OnMove()
203 GetWindowRect(GuiData
->hWindow
, &rcWnd
);
204 GuiData
->GuiInfo
.WindowOrigin
.x
= rcWnd
.left
;
205 GuiData
->GuiInfo
.WindowOrigin
.y
= rcWnd
.top
;
207 /* Move and resize the window to the user's values */
208 /* CAN WE DEADLOCK ?? */
209 GuiConsoleMoveWindow(GuiData
); // FIXME: This MUST be done via the CreateWindowExW call.
210 SendMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
212 // FIXME: HACK: Potential HACK for CORE-8129; see revision 63595.
213 CreateSysMenu(GuiData
->hWindow
);
215 /* Switch to full-screen mode if necessary */
216 // FIXME: Move elsewhere, it cause misdrawings of the window.
217 if (GuiData
->GuiInfo
.FullScreen
) SwitchFullScreen(GuiData
, TRUE
);
219 DPRINT("PM_CREATE_CONSOLE -- showing window\n");
220 // ShowWindow(NewWindow, (int)GuiData->GuiInfo.ShowWindow);
221 ShowWindowAsync(NewWindow
, (int)GuiData
->GuiInfo
.ShowWindow
);
222 DPRINT("Window showed\n");
227 case PM_DESTROY_CONSOLE
:
229 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)msg
.lParam
;
232 /* Exit the full screen mode if it was already set */
233 // LeaveFullScreen(GuiData);
236 * Window creation is done using a PostMessage(), so it's possible
237 * that the window that we want to destroy doesn't exist yet.
238 * So first empty the message queue.
241 while (PeekMessageW(&TempMsg, NULL, 0, 0, PM_REMOVE))
243 TranslateMessage(&TempMsg);
244 DispatchMessageW(&TempMsg);
246 while (PeekMessageW(&TempMsg
, NULL
, 0, 0, PM_REMOVE
)) ;
248 if (GuiData
->hWindow
== NULL
) continue;
250 DestroyWindow(GuiData
->hWindow
);
251 PrivateCsrssManualGuiCheck(+1); // RemoveGuiApp
253 SetEvent(GuiData
->hGuiTermEvent
);
255 if (InterlockedDecrement(&WindowCount
) == 0)
257 DPRINT("CONSRV: Going to quit the Input Thread!!\n");
265 TranslateMessage(&msg
);
266 DispatchMessageW(&msg
);
270 DPRINT("CONSRV: Quit the Input Thread!!\n");
281 /* Exit if we were already initialized */
282 // if (ConsInitialized) return TRUE;
285 * Initialize and register the console window class, if needed.
287 if (!ConsInitialized
)
289 if (!RegisterConWndClass(ConSrvDllInstance
)) return FALSE
;
290 ConsInitialized
= TRUE
;
294 * Set-up the console input thread
296 if (hInputThread
== NULL
)
298 HANDLE GraphicsStartupEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
299 if (GraphicsStartupEvent
== NULL
) return FALSE
;
301 hInputThread
= CreateThread(NULL
,
303 GuiConsoleInputThread
,
304 (PVOID
)&GraphicsStartupEvent
,
307 if (hInputThread
== NULL
)
309 CloseHandle(GraphicsStartupEvent
);
310 DPRINT1("CONSRV: Failed to create graphics console thread.\n");
313 SetThreadPriority(hInputThread
, THREAD_PRIORITY_HIGHEST
);
314 CloseHandle(hInputThread
);
316 WaitForSingleObject(GraphicsStartupEvent
, INFINITE
);
317 CloseHandle(GraphicsStartupEvent
);
320 // ConsInitialized = TRUE;
326 /******************************************************************************
327 * GUI Console Driver *
328 ******************************************************************************/
331 GuiDeinitFrontEnd(IN OUT PFRONTEND This
);
333 static NTSTATUS NTAPI
334 GuiInitFrontEnd(IN OUT PFRONTEND This
,
335 IN PCONSRV_CONSOLE Console
)
337 PGUI_INIT_INFO GuiInitInfo
;
338 PCONSOLE_INFO ConsoleInfo
;
339 PCONSOLE_START_INFO ConsoleStartInfo
;
341 PGUI_CONSOLE_DATA GuiData
;
342 GUI_CONSOLE_INFO TermInfo
;
344 if (This
== NULL
|| Console
== NULL
|| This
->OldData
== NULL
)
345 return STATUS_INVALID_PARAMETER
;
347 ASSERT(This
->Console
== Console
);
349 GuiInitInfo
= This
->OldData
;
351 if (GuiInitInfo
->ConsoleInfo
== NULL
|| GuiInitInfo
->ConsoleStartInfo
== NULL
)
352 return STATUS_INVALID_PARAMETER
;
354 ConsoleInfo
= GuiInitInfo
->ConsoleInfo
;
355 ConsoleStartInfo
= GuiInitInfo
->ConsoleStartInfo
;
357 /* Terminal data allocation */
358 GuiData
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_CONSOLE_DATA
));
361 DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
362 return STATUS_UNSUCCESSFUL
;
364 ///// /* HACK */ Console->FrontEndIFace.Data = (PVOID)GuiData; /* HACK */
365 GuiData
->Console
= Console
;
366 GuiData
->ActiveBuffer
= Console
->ActiveBuffer
;
367 GuiData
->hWindow
= NULL
;
369 /* The console can be resized */
370 Console
->FixedSize
= FALSE
;
372 InitializeCriticalSection(&GuiData
->Lock
);
376 * Load terminal settings
379 /* 1. Load the default settings */
380 GuiConsoleGetDefaultSettings(&TermInfo
, GuiInitInfo
->ProcessId
);
382 /* 3. Load the remaining console settings via the registry */
383 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
385 /* Load the terminal infos from the registry */
386 GuiConsoleReadUserSettings(&TermInfo
,
387 ConsoleInfo
->ConsoleTitle
,
388 GuiInitInfo
->ProcessId
);
391 * Now, update them with the properties the user might gave to us
392 * via the STARTUPINFO structure before calling CreateProcess
393 * (and which was transmitted via the ConsoleStartInfo structure).
394 * We therefore overwrite the values read in the registry.
396 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USESHOWWINDOW
)
398 TermInfo
.ShowWindow
= ConsoleStartInfo
->wShowWindow
;
400 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USEPOSITION
)
402 TermInfo
.AutoPosition
= FALSE
;
403 TermInfo
.WindowOrigin
.x
= ConsoleStartInfo
->dwWindowOrigin
.X
;
404 TermInfo
.WindowOrigin
.y
= ConsoleStartInfo
->dwWindowOrigin
.Y
;
406 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_RUNFULLSCREEN
)
408 TermInfo
.FullScreen
= TRUE
;
418 wcsncpy(GuiData
->GuiInfo
.FaceName
, TermInfo
.FaceName
, LF_FACESIZE
);
419 GuiData
->GuiInfo
.FaceName
[LF_FACESIZE
- 1] = UNICODE_NULL
;
420 GuiData
->GuiInfo
.FontFamily
= TermInfo
.FontFamily
;
421 GuiData
->GuiInfo
.FontSize
= TermInfo
.FontSize
;
422 GuiData
->GuiInfo
.FontWeight
= TermInfo
.FontWeight
;
425 GuiData
->GuiInfo
.FullScreen
= TermInfo
.FullScreen
;
426 GuiData
->GuiInfo
.ShowWindow
= TermInfo
.ShowWindow
;
427 GuiData
->GuiInfo
.AutoPosition
= TermInfo
.AutoPosition
;
428 GuiData
->GuiInfo
.WindowOrigin
= TermInfo
.WindowOrigin
;
430 /* Initialize the icon handles */
431 if (ConsoleStartInfo
->hIcon
!= NULL
)
432 GuiData
->hIcon
= ConsoleStartInfo
->hIcon
;
434 GuiData
->hIcon
= ghDefaultIcon
;
436 if (ConsoleStartInfo
->hIconSm
!= NULL
)
437 GuiData
->hIconSm
= ConsoleStartInfo
->hIconSm
;
439 GuiData
->hIconSm
= ghDefaultIconSm
;
441 ASSERT(GuiData
->hIcon
&& GuiData
->hIconSm
);
443 /* Mouse is shown by default with its default cursor shape */
444 GuiData
->hCursor
= ghDefaultCursor
;
445 GuiData
->MouseCursorRefCount
= 0;
447 /* A priori don't ignore mouse signals */
448 GuiData
->IgnoreNextMouseSignal
= FALSE
;
450 /* Close button and the corresponding system menu item are enabled by default */
451 GuiData
->IsCloseButtonEnabled
= TRUE
;
453 /* There is no user-reserved menu id range by default */
454 GuiData
->CmdIdLow
= GuiData
->CmdIdHigh
= 0;
456 /* Initialize the selection */
457 RtlZeroMemory(&GuiData
->Selection
, sizeof(GuiData
->Selection
));
458 GuiData
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
459 RtlZeroMemory(&GuiData
->dwSelectionCursor
, sizeof(GuiData
->dwSelectionCursor
));
460 GuiData
->LineSelection
= FALSE
; // Default to block selection
461 // TODO: Retrieve the selection mode via the registry.
463 /* Finally, finish to initialize the frontend structure */
464 This
->Data
= GuiData
;
465 if (This
->OldData
) ConsoleFreeHeap(This
->OldData
);
466 This
->OldData
= NULL
;
469 * We need to wait until the GUI has been fully initialized
470 * to retrieve custom settings i.e. WindowSize etc...
471 * Ideally we could use SendNotifyMessage for this but its not
474 GuiData
->hGuiInitEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
475 GuiData
->hGuiTermEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
477 DPRINT("GUI - Checkpoint\n");
479 /* Create the terminal window */
480 PostThreadMessageW(dwInputThreadId
, PM_CREATE_CONSOLE
, 0, (LPARAM
)GuiData
);
482 /* Wait until initialization has finished */
483 WaitForSingleObject(GuiData
->hGuiInitEvent
, INFINITE
);
484 DPRINT("OK we created the console window\n");
485 CloseHandle(GuiData
->hGuiInitEvent
);
486 GuiData
->hGuiInitEvent
= NULL
;
488 /* Check whether we really succeeded in initializing the terminal window */
489 if (GuiData
->hWindow
== NULL
)
491 DPRINT("GuiInitConsole - We failed at creating a new terminal window\n");
492 GuiDeinitFrontEnd(This
);
493 return STATUS_UNSUCCESSFUL
;
496 return STATUS_SUCCESS
;
500 GuiDeinitFrontEnd(IN OUT PFRONTEND This
)
502 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
504 DPRINT("Send PM_DESTROY_CONSOLE message and wait on hGuiTermEvent...\n");
505 PostThreadMessageW(dwInputThreadId
, PM_DESTROY_CONSOLE
, 0, (LPARAM
)GuiData
);
506 WaitForSingleObject(GuiData
->hGuiTermEvent
, INFINITE
);
507 DPRINT("hGuiTermEvent set\n");
508 CloseHandle(GuiData
->hGuiTermEvent
);
509 GuiData
->hGuiTermEvent
= NULL
;
511 DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
512 GuiData
->hIcon
, ghDefaultIcon
, GuiData
->hIconSm
, ghDefaultIconSm
);
513 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
515 DPRINT("Destroy hIcon\n");
516 DestroyIcon(GuiData
->hIcon
);
518 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
520 DPRINT("Destroy hIconSm\n");
521 DestroyIcon(GuiData
->hIconSm
);
525 DeleteCriticalSection(&GuiData
->Lock
);
526 ConsoleFreeHeap(GuiData
);
528 DPRINT("Quit GuiDeinitFrontEnd\n");
532 GuiDrawRegion(IN OUT PFRONTEND This
,
535 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
536 DrawRegion(GuiData
, Region
);
540 GuiWriteStream(IN OUT PFRONTEND This
,
548 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
549 PCONSOLE_SCREEN_BUFFER Buff
;
550 SHORT CursorEndX
, CursorEndY
;
553 if (NULL
== GuiData
|| NULL
== GuiData
->hWindow
) return;
555 Buff
= GuiData
->ActiveBuffer
;
556 if (GetType(Buff
) != TEXTMODE_BUFFER
) return;
558 if (0 != ScrolledLines
)
562 ScrollRect
.right
= Buff
->ViewSize
.X
* GuiData
->CharWidth
;
563 ScrollRect
.bottom
= Region
->Top
* GuiData
->CharHeight
;
565 ScrollWindowEx(GuiData
->hWindow
,
567 -(int)(ScrolledLines
* GuiData
->CharHeight
),
575 DrawRegion(GuiData
, Region
);
577 if (CursorStartX
< Region
->Left
|| Region
->Right
< CursorStartX
578 || CursorStartY
< Region
->Top
|| Region
->Bottom
< CursorStartY
)
580 InvalidateCell(GuiData
, CursorStartX
, CursorStartY
);
583 CursorEndX
= Buff
->CursorPosition
.X
;
584 CursorEndY
= Buff
->CursorPosition
.Y
;
585 if ((CursorEndX
< Region
->Left
|| Region
->Right
< CursorEndX
586 || CursorEndY
< Region
->Top
|| Region
->Bottom
< CursorEndY
)
587 && (CursorEndX
!= CursorStartX
|| CursorEndY
!= CursorStartY
))
589 InvalidateCell(GuiData
, CursorEndX
, CursorEndY
);
593 // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
594 // repaint the window without having it just freeze up and stay on the screen permanently.
595 Buff
->CursorBlinkOn
= TRUE
;
596 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
599 /* static */ VOID NTAPI
600 GuiRingBell(IN OUT PFRONTEND This
)
602 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
604 /* Emit an error beep sound */
605 SendNotifyMessage(GuiData
->hWindow
, PM_CONSOLE_BEEP
, 0, 0);
609 GuiSetCursorInfo(IN OUT PFRONTEND This
,
610 PCONSOLE_SCREEN_BUFFER Buff
)
612 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
614 if (GuiData
->ActiveBuffer
== Buff
)
616 InvalidateCell(GuiData
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
623 GuiSetScreenInfo(IN OUT PFRONTEND This
,
624 PCONSOLE_SCREEN_BUFFER Buff
,
628 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
630 if (GuiData
->ActiveBuffer
== Buff
)
632 /* Redraw char at old position (remove cursor) */
633 InvalidateCell(GuiData
, OldCursorX
, OldCursorY
);
634 /* Redraw char at new position (show cursor) */
635 InvalidateCell(GuiData
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
642 GuiResizeTerminal(IN OUT PFRONTEND This
)
644 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
646 /* Resize the window to the user's values */
647 PostMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
651 GuiSetActiveScreenBuffer(IN OUT PFRONTEND This
)
653 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
654 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
657 EnterCriticalSection(&GuiData
->Lock
);
658 GuiData
->WindowSizeLock
= TRUE
;
660 InterlockedExchangePointer(&GuiData
->ActiveBuffer
,
661 ConDrvGetActiveScreenBuffer(GuiData
->Console
));
663 GuiData
->WindowSizeLock
= FALSE
;
664 LeaveCriticalSection(&GuiData
->Lock
);
666 ActiveBuffer
= GuiData
->ActiveBuffer
;
668 /* Change the current palette */
669 if (ActiveBuffer
->PaletteHandle
== NULL
)
671 hPalette
= GuiData
->hSysPalette
;
675 hPalette
= ActiveBuffer
->PaletteHandle
;
678 DPRINT1("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette
);
680 /* Set the new palette for the framebuffer */
681 SelectPalette(GuiData
->hMemDC
, hPalette
, FALSE
);
683 /* Specify the use of the system palette for the framebuffer */
684 SetSystemPaletteUse(GuiData
->hMemDC
, ActiveBuffer
->PaletteUsage
);
686 /* Realize the (logical) palette */
687 RealizePalette(GuiData
->hMemDC
);
689 GuiResizeTerminal(This
);
690 // ConioDrawConsole(Console);
694 GuiReleaseScreenBuffer(IN OUT PFRONTEND This
,
695 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer
)
697 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
700 * If we were notified to release a screen buffer that is not actually
701 * ours, then just ignore the notification...
703 if (ScreenBuffer
!= GuiData
->ActiveBuffer
) return;
706 * ... else, we must release our active buffer. Two cases are present:
707 * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console
708 * active screen buffer, then we can safely switch to it.
709 * - If ScreenBuffer IS the console active screen buffer, we must release
713 /* Release the old active palette and set the default one */
714 if (GetCurrentObject(GuiData
->hMemDC
, OBJ_PAL
) == ScreenBuffer
->PaletteHandle
)
716 /* Set the new palette */
717 SelectPalette(GuiData
->hMemDC
, GuiData
->hSysPalette
, FALSE
);
720 /* Set the adequate active screen buffer */
721 if (ScreenBuffer
!= GuiData
->Console
->ActiveBuffer
)
723 GuiSetActiveScreenBuffer(This
);
727 EnterCriticalSection(&GuiData
->Lock
);
728 GuiData
->WindowSizeLock
= TRUE
;
730 InterlockedExchangePointer(&GuiData
->ActiveBuffer
, NULL
);
732 GuiData
->WindowSizeLock
= FALSE
;
733 LeaveCriticalSection(&GuiData
->Lock
);
738 GuiSetMouseCursor(IN OUT PFRONTEND This
,
739 HCURSOR CursorHandle
);
742 GuiRefreshInternalInfo(IN OUT PFRONTEND This
)
744 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
746 /* Update the console leader information held by the window */
747 SetConWndConsoleLeaderCID(GuiData
);
751 * We reset the cursor here so that, when a console app quits, we reset
752 * the cursor to the default one. It's quite a hack since it doesn't proceed
753 * per - console process... This must be fixed.
755 * See GuiInitConsole(...) for more information.
758 /* Mouse is shown by default with its default cursor shape */
759 GuiData
->MouseCursorRefCount
= 0; // Reinitialize the reference counter
760 GuiSetMouseCursor(This
, NULL
);
764 GuiChangeTitle(IN OUT PFRONTEND This
)
766 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
767 // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
768 SetWindowText(GuiData
->hWindow
, GuiData
->Console
->Title
.Buffer
);
772 GuiChangeIcon(IN OUT PFRONTEND This
,
775 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
776 HICON hIcon
, hIconSm
;
778 if (IconHandle
== NULL
)
780 hIcon
= ghDefaultIcon
;
781 hIconSm
= ghDefaultIconSm
;
785 hIcon
= CopyIcon(IconHandle
);
786 hIconSm
= CopyIcon(IconHandle
);
794 if (hIcon
!= GuiData
->hIcon
)
796 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
798 DestroyIcon(GuiData
->hIcon
);
800 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
802 DestroyIcon(GuiData
->hIconSm
);
805 GuiData
->hIcon
= hIcon
;
806 GuiData
->hIconSm
= hIconSm
;
808 DPRINT("Set icons in GuiChangeIcon\n");
809 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
810 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
817 GuiGetConsoleWindowHandle(IN OUT PFRONTEND This
)
819 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
820 return GuiData
->hWindow
;
824 GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This
,
827 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
828 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
831 UINT WidthUnit
, HeightUnit
;
835 if (!SystemParametersInfoW(SPI_GETWORKAREA
, 0, &WorkArea
, 0))
837 DPRINT1("SystemParametersInfoW failed - What to do ??\n");
841 ActiveBuffer
= GuiData
->ActiveBuffer
;
844 GetScreenBufferSizeUnits(ActiveBuffer
, GuiData
, &WidthUnit
, &HeightUnit
);
848 /* Default: text mode */
849 WidthUnit
= GuiData
->CharWidth
;
850 HeightUnit
= GuiData
->CharHeight
;
853 width
= WorkArea
.right
;
854 height
= WorkArea
.bottom
;
856 width
-= (2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
)));
857 height
-= (2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
));
859 if (width
< 0) width
= 0;
860 if (height
< 0) height
= 0;
862 pSize
->X
= (SHORT
)(width
/ (int)WidthUnit
) /* HACK */ + 2;
863 pSize
->Y
= (SHORT
)(height
/ (int)HeightUnit
) /* HACK */ + 1;
867 GuiGetSelectionInfo(IN OUT PFRONTEND This
,
868 PCONSOLE_SELECTION_INFO pSelectionInfo
)
870 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
872 if (pSelectionInfo
== NULL
) return FALSE
;
874 ZeroMemory(pSelectionInfo
, sizeof(CONSOLE_SELECTION_INFO
));
875 if (GuiData
->Selection
.dwFlags
!= CONSOLE_NO_SELECTION
)
876 RtlCopyMemory(pSelectionInfo
, &GuiData
->Selection
, sizeof(CONSOLE_SELECTION_INFO
));
882 GuiSetPalette(IN OUT PFRONTEND This
,
883 HPALETTE PaletteHandle
,
886 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
889 // if (GetType(GuiData->ActiveBuffer) != GRAPHICS_BUFFER) return FALSE;
890 if (PaletteHandle
== NULL
) return FALSE
;
892 /* Set the new palette for the framebuffer */
893 OldPalette
= SelectPalette(GuiData
->hMemDC
, PaletteHandle
, FALSE
);
894 if (OldPalette
== NULL
) return FALSE
;
896 /* Specify the use of the system palette for the framebuffer */
897 SetSystemPaletteUse(GuiData
->hMemDC
, PaletteUsage
);
899 /* Realize the (logical) palette */
900 RealizePalette(GuiData
->hMemDC
);
902 /* Save the original system palette handle */
903 if (GuiData
->hSysPalette
== NULL
) GuiData
->hSysPalette
= OldPalette
;
909 GuiGetDisplayMode(IN OUT PFRONTEND This
)
911 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
912 ULONG DisplayMode
= 0;
914 if (GuiData
->GuiInfo
.FullScreen
)
915 DisplayMode
|= CONSOLE_FULLSCREEN_HARDWARE
; // CONSOLE_FULLSCREEN
917 DisplayMode
|= CONSOLE_WINDOWED
;
923 GuiSetDisplayMode(IN OUT PFRONTEND This
,
926 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
929 if (NewMode
& ~(CONSOLE_FULLSCREEN_MODE
| CONSOLE_WINDOWED_MODE
))
932 FullScreen
= ((NewMode
& CONSOLE_FULLSCREEN_MODE
) != 0);
934 if (FullScreen
!= GuiData
->GuiInfo
.FullScreen
)
936 SwitchFullScreen(GuiData
, FullScreen
);
943 GuiShowMouseCursor(IN OUT PFRONTEND This
,
946 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
948 /* Set the reference count */
949 if (Show
) ++GuiData
->MouseCursorRefCount
;
950 else --GuiData
->MouseCursorRefCount
;
952 /* Effectively show (or hide) the cursor (use special values for (w|l)Param) */
953 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
955 return GuiData
->MouseCursorRefCount
;
959 GuiSetMouseCursor(IN OUT PFRONTEND This
,
960 HCURSOR CursorHandle
)
962 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
965 * Set the cursor's handle. If the given handle is NULL,
966 * then restore the default cursor.
968 GuiData
->hCursor
= (CursorHandle
? CursorHandle
: ghDefaultCursor
);
970 /* Effectively modify the shape of the cursor (use special values for (w|l)Param) */
971 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
977 GuiMenuControl(IN OUT PFRONTEND This
,
981 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
983 GuiData
->CmdIdLow
= CmdIdLow
;
984 GuiData
->CmdIdHigh
= CmdIdHigh
;
986 return GetSystemMenu(GuiData
->hWindow
, FALSE
);
990 GuiSetMenuClose(IN OUT PFRONTEND This
,
994 * NOTE: See http://www.mail-archive.com/harbour@harbour-project.org/msg27509.html
995 * or http://harbour-devel.1590103.n2.nabble.com/Question-about-hb-gt-win-CtrlHandler-usage-td4670862i20.html
996 * for more information.
999 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1000 HMENU hSysMenu
= GetSystemMenu(GuiData
->hWindow
, FALSE
);
1002 if (hSysMenu
== NULL
) return FALSE
;
1004 GuiData
->IsCloseButtonEnabled
= Enable
;
1005 EnableMenuItem(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
| (Enable
? MF_ENABLED
: MF_GRAYED
));
1010 static FRONTEND_VTBL GuiVtbl
=
1020 GuiSetActiveScreenBuffer
,
1021 GuiReleaseScreenBuffer
,
1022 GuiRefreshInternalInfo
,
1025 GuiGetConsoleWindowHandle
,
1026 GuiGetLargestConsoleWindowSize
,
1027 GuiGetSelectionInfo
,
1039 GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd
,
1040 IN OUT PCONSOLE_INFO ConsoleInfo
,
1041 IN OUT PVOID ExtraConsoleInfo
,
1044 PCONSOLE_INIT_INFO ConsoleInitInfo
= ExtraConsoleInfo
;
1045 PGUI_INIT_INFO GuiInitInfo
;
1047 if (FrontEnd
== NULL
|| ConsoleInfo
== NULL
|| ConsoleInitInfo
== NULL
)
1048 return STATUS_INVALID_PARAMETER
;
1050 /* Initialize GUI terminal emulator common functionalities */
1051 if (!GuiInit()) return STATUS_UNSUCCESSFUL
;
1054 * Initialize a private initialization info structure for later use.
1055 * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd.
1057 GuiInitInfo
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_INIT_INFO
));
1058 if (GuiInitInfo
== NULL
) return STATUS_NO_MEMORY
;
1060 // HACK: We suppose that the pointers will be valid in GuiInitFrontEnd...
1061 // If not, then copy exactly what we need in GuiInitInfo.
1062 GuiInitInfo
->ConsoleInfo
= ConsoleInfo
;
1063 GuiInitInfo
->ConsoleStartInfo
= ConsoleInitInfo
->ConsoleStartInfo
;
1064 GuiInitInfo
->ProcessId
= ProcessId
;
1066 /* Finally, initialize the frontend structure */
1067 FrontEnd
->Vtbl
= &GuiVtbl
;
1068 FrontEnd
->Data
= NULL
;
1069 FrontEnd
->OldData
= GuiInitInfo
;
1071 return STATUS_SUCCESS
;
1075 GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd
)
1077 if (FrontEnd
== NULL
) return STATUS_INVALID_PARAMETER
;
1079 if (FrontEnd
->Data
) GuiDeinitFrontEnd(FrontEnd
);
1080 if (FrontEnd
->OldData
) ConsoleFreeHeap(FrontEnd
->OldData
);
1082 return STATUS_SUCCESS
;