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 BOOLEAN IsWindowVisible
;
43 } GUI_INIT_INFO
, *PGUI_INIT_INFO
;
45 static BOOL ConsInitialized
= FALSE
;
46 static HANDLE hInputThread
= NULL
;
47 static DWORD dwInputThreadId
= 0;
49 extern HICON ghDefaultIcon
;
50 extern HICON ghDefaultIconSm
;
51 extern HCURSOR ghDefaultCursor
;
54 SetConWndConsoleLeaderCID(IN PGUI_CONSOLE_DATA GuiData
);
56 RegisterConWndClass(IN HINSTANCE hInstance
);
58 UnRegisterConWndClass(HINSTANCE hInstance
);
60 /* FUNCTIONS ******************************************************************/
63 GetScreenBufferSizeUnits(IN PCONSOLE_SCREEN_BUFFER Buffer
,
64 IN PGUI_CONSOLE_DATA GuiData
,
68 if (Buffer
== NULL
|| GuiData
== NULL
||
69 WidthUnit
== NULL
|| HeightUnit
== NULL
)
74 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
76 *WidthUnit
= GuiData
->CharWidth
;
77 *HeightUnit
= GuiData
->CharHeight
;
79 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
87 GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData
)
89 /* Move the window if needed (not positioned by the system) */
90 if (!GuiData
->GuiInfo
.AutoPosition
)
92 SetWindowPos(GuiData
->hWindow
,
94 GuiData
->GuiInfo
.WindowOrigin
.x
,
95 GuiData
->GuiInfo
.WindowOrigin
.y
,
97 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
102 SmallRectToRect(PGUI_CONSOLE_DATA GuiData
, PRECT Rect
, PSMALL_RECT SmallRect
)
104 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
105 UINT WidthUnit
, HeightUnit
;
107 GetScreenBufferSizeUnits(Buffer
, GuiData
, &WidthUnit
, &HeightUnit
);
109 Rect
->left
= (SmallRect
->Left
- Buffer
->ViewOrigin
.X
) * WidthUnit
;
110 Rect
->top
= (SmallRect
->Top
- Buffer
->ViewOrigin
.Y
) * HeightUnit
;
111 Rect
->right
= (SmallRect
->Right
+ 1 - Buffer
->ViewOrigin
.X
) * WidthUnit
;
112 Rect
->bottom
= (SmallRect
->Bottom
+ 1 - Buffer
->ViewOrigin
.Y
) * HeightUnit
;
116 DrawRegion(PGUI_CONSOLE_DATA GuiData
,
121 SmallRectToRect(GuiData
, &RegionRect
, Region
);
122 /* Do not erase the background: it speeds up redrawing and reduce flickering */
123 InvalidateRect(GuiData
->hWindow
, &RegionRect
, FALSE
);
124 /**UpdateWindow(GuiData->hWindow);**/
128 InvalidateCell(PGUI_CONSOLE_DATA GuiData
,
131 SMALL_RECT CellRect
= { x
, y
, x
, y
};
132 DrawRegion(GuiData
, &CellRect
);
136 /******************************************************************************
137 * GUI Terminal Initialization *
138 ******************************************************************************/
141 SwitchFullScreen(PGUI_CONSOLE_DATA GuiData
, BOOL FullScreen
);
143 CreateSysMenu(HWND hWnd
);
146 GuiConsoleInputThread(PVOID Data
)
148 PHANDLE GraphicsStartupEvent
= (PHANDLE
)Data
;
149 LONG WindowCount
= 0;
153 * This thread dispatches all the console notifications to the
154 * notification window. It is common for all the console windows.
157 /* The thread has been initialized, set the event */
158 NtSetEvent(*GraphicsStartupEvent
, NULL
);
160 while (GetMessageW(&msg
, NULL
, 0, 0))
164 case PM_CREATE_CONSOLE
:
166 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)msg
.lParam
;
167 PCONSRV_CONSOLE Console
= GuiData
->Console
;
171 DPRINT("PM_CREATE_CONSOLE -- creating window\n");
173 PrivateCsrssManualGuiCheck(-1); // co_AddGuiApp
175 NewWindow
= CreateWindowExW(WS_EX_CLIENTEDGE
,
177 Console
->Title
.Buffer
,
178 WS_OVERLAPPEDWINDOW
| WS_HSCROLL
| WS_VSCROLL
,
183 GuiData
->IsWindowVisible
? HWND_DESKTOP
: HWND_MESSAGE
,
187 if (NewWindow
== NULL
)
189 DPRINT1("Failed to create a new console window\n");
190 PrivateCsrssManualGuiCheck(+1); // RemoveGuiApp
194 ASSERT(NewWindow
== GuiData
->hWindow
);
196 InterlockedIncrement(&WindowCount
);
199 // FIXME: TODO: Move everything there into conwnd.c!OnNcCreate()
202 /* Retrieve our real position */
203 // See conwnd.c!OnMove()
204 GetWindowRect(GuiData
->hWindow
, &rcWnd
);
205 GuiData
->GuiInfo
.WindowOrigin
.x
= rcWnd
.left
;
206 GuiData
->GuiInfo
.WindowOrigin
.y
= rcWnd
.top
;
208 if (GuiData
->IsWindowVisible
)
210 /* Move and resize the window to the user's values */
211 /* CAN WE DEADLOCK ?? */
212 GuiConsoleMoveWindow(GuiData
); // FIXME: This MUST be done via the CreateWindowExW call.
213 SendMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
216 // FIXME: HACK: Potential HACK for CORE-8129; see revision 63595.
217 CreateSysMenu(GuiData
->hWindow
);
219 if (GuiData
->IsWindowVisible
)
221 /* Switch to full-screen mode if necessary */
222 // FIXME: Move elsewhere, it cause misdrawings of the window.
223 if (GuiData
->GuiInfo
.FullScreen
) SwitchFullScreen(GuiData
, TRUE
);
225 DPRINT("PM_CREATE_CONSOLE -- showing window\n");
226 // ShowWindow(NewWindow, (int)GuiData->GuiInfo.ShowWindow);
227 ShowWindowAsync(NewWindow
, (int)GuiData
->GuiInfo
.ShowWindow
);
228 DPRINT("Window showed\n");
232 DPRINT("PM_CREATE_CONSOLE -- hidden window\n");
233 ShowWindowAsync(NewWindow
, SW_HIDE
);
239 case PM_DESTROY_CONSOLE
:
241 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)msg
.lParam
;
244 /* Exit the full screen mode if it was already set */
245 // LeaveFullScreen(GuiData);
248 * Window creation is done using a PostMessage(), so it's possible
249 * that the window that we want to destroy doesn't exist yet.
250 * So first empty the message queue.
253 while (PeekMessageW(&TempMsg, NULL, 0, 0, PM_REMOVE))
255 TranslateMessage(&TempMsg);
256 DispatchMessageW(&TempMsg);
258 while (PeekMessageW(&TempMsg
, NULL
, 0, 0, PM_REMOVE
)) ;
260 if (GuiData
->hWindow
== NULL
) continue;
262 DestroyWindow(GuiData
->hWindow
);
263 PrivateCsrssManualGuiCheck(+1); // RemoveGuiApp
265 NtSetEvent(GuiData
->hGuiTermEvent
, NULL
);
267 if (InterlockedDecrement(&WindowCount
) == 0)
269 DPRINT("CONSRV: Going to quit the Input Thread!!\n");
277 TranslateMessage(&msg
);
278 DispatchMessageW(&msg
);
282 DPRINT("CONSRV: Quit the Input Thread!!\n");
293 /* Exit if we were already initialized */
294 // if (ConsInitialized) return TRUE;
297 * Initialize and register the console window class, if needed.
299 if (!ConsInitialized
)
301 if (!RegisterConWndClass(ConSrvDllInstance
)) return FALSE
;
302 ConsInitialized
= TRUE
;
306 * Set-up the console input thread
308 if (hInputThread
== NULL
)
310 HANDLE GraphicsStartupEvent
;
313 Status
= NtCreateEvent(&GraphicsStartupEvent
, EVENT_ALL_ACCESS
,
314 NULL
, SynchronizationEvent
, FALSE
);
315 if (!NT_SUCCESS(Status
)) return FALSE
;
317 hInputThread
= CreateThread(NULL
,
319 GuiConsoleInputThread
,
320 (PVOID
)&GraphicsStartupEvent
,
323 if (hInputThread
== NULL
)
325 NtClose(GraphicsStartupEvent
);
326 DPRINT1("CONSRV: Failed to create graphics console thread.\n");
329 SetThreadPriority(hInputThread
, THREAD_PRIORITY_HIGHEST
);
330 CloseHandle(hInputThread
);
332 WaitForSingleObject(GraphicsStartupEvent
, INFINITE
);
333 NtClose(GraphicsStartupEvent
);
336 // ConsInitialized = TRUE;
342 /******************************************************************************
343 * GUI Console Driver *
344 ******************************************************************************/
347 GuiDeinitFrontEnd(IN OUT PFRONTEND This
);
349 static NTSTATUS NTAPI
350 GuiInitFrontEnd(IN OUT PFRONTEND This
,
351 IN PCONSRV_CONSOLE Console
)
353 PGUI_INIT_INFO GuiInitInfo
;
354 PCONSOLE_INFO ConsoleInfo
;
355 PCONSOLE_START_INFO ConsoleStartInfo
;
357 PGUI_CONSOLE_DATA GuiData
;
358 GUI_CONSOLE_INFO TermInfo
;
360 if (This
== NULL
|| Console
== NULL
|| This
->OldData
== NULL
)
361 return STATUS_INVALID_PARAMETER
;
363 ASSERT(This
->Console
== Console
);
365 GuiInitInfo
= This
->OldData
;
367 if (GuiInitInfo
->ConsoleInfo
== NULL
|| GuiInitInfo
->ConsoleStartInfo
== NULL
)
368 return STATUS_INVALID_PARAMETER
;
370 ConsoleInfo
= GuiInitInfo
->ConsoleInfo
;
371 ConsoleStartInfo
= GuiInitInfo
->ConsoleStartInfo
;
373 /* Terminal data allocation */
374 GuiData
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_CONSOLE_DATA
));
377 DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
378 return STATUS_UNSUCCESSFUL
;
380 ///// /* HACK */ Console->FrontEndIFace.Data = (PVOID)GuiData; /* HACK */
381 GuiData
->Console
= Console
;
382 GuiData
->ActiveBuffer
= Console
->ActiveBuffer
;
383 GuiData
->hWindow
= NULL
;
384 GuiData
->IsWindowVisible
= GuiInitInfo
->IsWindowVisible
;
386 /* The console can be resized */
387 Console
->FixedSize
= FALSE
;
389 InitializeCriticalSection(&GuiData
->Lock
);
393 * Load terminal settings
396 /* 1. Load the default settings */
397 GuiConsoleGetDefaultSettings(&TermInfo
, GuiInitInfo
->ProcessId
);
399 if (GuiData
->IsWindowVisible
)
401 /* 2. Load the remaining console settings via the registry */
402 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
404 /* Load the terminal infos from the registry */
405 GuiConsoleReadUserSettings(&TermInfo
,
406 ConsoleInfo
->ConsoleTitle
,
407 GuiInitInfo
->ProcessId
);
410 * Now, update them with the properties the user might gave to us
411 * via the STARTUPINFO structure before calling CreateProcess
412 * (and which was transmitted via the ConsoleStartInfo structure).
413 * We therefore overwrite the values read in the registry.
415 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USESHOWWINDOW
)
417 TermInfo
.ShowWindow
= ConsoleStartInfo
->wShowWindow
;
419 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USEPOSITION
)
421 TermInfo
.AutoPosition
= FALSE
;
422 TermInfo
.WindowOrigin
.x
= ConsoleStartInfo
->dwWindowOrigin
.X
;
423 TermInfo
.WindowOrigin
.y
= ConsoleStartInfo
->dwWindowOrigin
.Y
;
425 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_RUNFULLSCREEN
)
427 TermInfo
.FullScreen
= TRUE
;
438 wcsncpy(GuiData
->GuiInfo
.FaceName
, TermInfo
.FaceName
, LF_FACESIZE
);
439 GuiData
->GuiInfo
.FaceName
[LF_FACESIZE
- 1] = UNICODE_NULL
;
440 GuiData
->GuiInfo
.FontFamily
= TermInfo
.FontFamily
;
441 GuiData
->GuiInfo
.FontSize
= TermInfo
.FontSize
;
442 GuiData
->GuiInfo
.FontWeight
= TermInfo
.FontWeight
;
445 GuiData
->GuiInfo
.FullScreen
= TermInfo
.FullScreen
;
446 GuiData
->GuiInfo
.ShowWindow
= TermInfo
.ShowWindow
;
447 GuiData
->GuiInfo
.AutoPosition
= TermInfo
.AutoPosition
;
448 GuiData
->GuiInfo
.WindowOrigin
= TermInfo
.WindowOrigin
;
450 /* Initialize the icon handles */
451 if (ConsoleStartInfo
->hIcon
!= NULL
)
452 GuiData
->hIcon
= ConsoleStartInfo
->hIcon
;
454 GuiData
->hIcon
= ghDefaultIcon
;
456 if (ConsoleStartInfo
->hIconSm
!= NULL
)
457 GuiData
->hIconSm
= ConsoleStartInfo
->hIconSm
;
459 GuiData
->hIconSm
= ghDefaultIconSm
;
461 ASSERT(GuiData
->hIcon
&& GuiData
->hIconSm
);
463 /* Mouse is shown by default with its default cursor shape */
464 GuiData
->hCursor
= ghDefaultCursor
;
465 GuiData
->MouseCursorRefCount
= 0;
467 /* A priori don't ignore mouse signals */
468 GuiData
->IgnoreNextMouseSignal
= FALSE
;
470 /* Close button and the corresponding system menu item are enabled by default */
471 GuiData
->IsCloseButtonEnabled
= TRUE
;
473 /* There is no user-reserved menu id range by default */
474 GuiData
->CmdIdLow
= GuiData
->CmdIdHigh
= 0;
476 /* Initialize the selection */
477 RtlZeroMemory(&GuiData
->Selection
, sizeof(GuiData
->Selection
));
478 GuiData
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
479 RtlZeroMemory(&GuiData
->dwSelectionCursor
, sizeof(GuiData
->dwSelectionCursor
));
480 GuiData
->LineSelection
= FALSE
; // Default to block selection
481 // TODO: Retrieve the selection mode via the registry.
483 /* Finally, finish to initialize the frontend structure */
484 This
->Data
= GuiData
;
485 if (This
->OldData
) ConsoleFreeHeap(This
->OldData
);
486 This
->OldData
= NULL
;
489 * We need to wait until the GUI has been fully initialized
490 * to retrieve custom settings i.e. WindowSize etc...
491 * Ideally we could use SendNotifyMessage for this but its not
494 NtCreateEvent(&GuiData
->hGuiInitEvent
, EVENT_ALL_ACCESS
,
495 NULL
, SynchronizationEvent
, FALSE
);
496 NtCreateEvent(&GuiData
->hGuiTermEvent
, EVENT_ALL_ACCESS
,
497 NULL
, SynchronizationEvent
, FALSE
);
499 DPRINT("GUI - Checkpoint\n");
501 /* Create the terminal window */
502 PostThreadMessageW(dwInputThreadId
, PM_CREATE_CONSOLE
, 0, (LPARAM
)GuiData
);
504 /* Wait until initialization has finished */
505 WaitForSingleObject(GuiData
->hGuiInitEvent
, INFINITE
);
506 DPRINT("OK we created the console window\n");
507 NtClose(GuiData
->hGuiInitEvent
);
508 GuiData
->hGuiInitEvent
= NULL
;
510 /* Check whether we really succeeded in initializing the terminal window */
511 if (GuiData
->hWindow
== NULL
)
513 DPRINT("GuiInitConsole - We failed at creating a new terminal window\n");
514 GuiDeinitFrontEnd(This
);
515 return STATUS_UNSUCCESSFUL
;
518 return STATUS_SUCCESS
;
522 GuiDeinitFrontEnd(IN OUT PFRONTEND This
)
524 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
526 DPRINT("Send PM_DESTROY_CONSOLE message and wait on hGuiTermEvent...\n");
527 PostThreadMessageW(dwInputThreadId
, PM_DESTROY_CONSOLE
, 0, (LPARAM
)GuiData
);
528 WaitForSingleObject(GuiData
->hGuiTermEvent
, INFINITE
);
529 DPRINT("hGuiTermEvent set\n");
530 NtClose(GuiData
->hGuiTermEvent
);
531 GuiData
->hGuiTermEvent
= NULL
;
533 DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
534 GuiData
->hIcon
, ghDefaultIcon
, GuiData
->hIconSm
, ghDefaultIconSm
);
535 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
537 DPRINT("Destroy hIcon\n");
538 DestroyIcon(GuiData
->hIcon
);
540 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
542 DPRINT("Destroy hIconSm\n");
543 DestroyIcon(GuiData
->hIconSm
);
547 DeleteCriticalSection(&GuiData
->Lock
);
548 ConsoleFreeHeap(GuiData
);
550 DPRINT("Quit GuiDeinitFrontEnd\n");
554 GuiDrawRegion(IN OUT PFRONTEND This
,
557 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
559 /* Do nothing if the window is hidden */
560 if (!GuiData
->IsWindowVisible
) return;
562 DrawRegion(GuiData
, Region
);
566 GuiWriteStream(IN OUT PFRONTEND This
,
574 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
575 PCONSOLE_SCREEN_BUFFER Buff
;
576 SHORT CursorEndX
, CursorEndY
;
579 if (NULL
== GuiData
|| NULL
== GuiData
->hWindow
) return;
581 /* Do nothing if the window is hidden */
582 if (!GuiData
->IsWindowVisible
) return;
584 Buff
= GuiData
->ActiveBuffer
;
585 if (GetType(Buff
) != TEXTMODE_BUFFER
) return;
587 if (0 != ScrolledLines
)
591 ScrollRect
.right
= Buff
->ViewSize
.X
* GuiData
->CharWidth
;
592 ScrollRect
.bottom
= Region
->Top
* GuiData
->CharHeight
;
594 ScrollWindowEx(GuiData
->hWindow
,
596 -(int)(ScrolledLines
* GuiData
->CharHeight
),
604 DrawRegion(GuiData
, Region
);
606 if (CursorStartX
< Region
->Left
|| Region
->Right
< CursorStartX
607 || CursorStartY
< Region
->Top
|| Region
->Bottom
< CursorStartY
)
609 InvalidateCell(GuiData
, CursorStartX
, CursorStartY
);
612 CursorEndX
= Buff
->CursorPosition
.X
;
613 CursorEndY
= Buff
->CursorPosition
.Y
;
614 if ((CursorEndX
< Region
->Left
|| Region
->Right
< CursorEndX
615 || CursorEndY
< Region
->Top
|| Region
->Bottom
< CursorEndY
)
616 && (CursorEndX
!= CursorStartX
|| CursorEndY
!= CursorStartY
))
618 InvalidateCell(GuiData
, CursorEndX
, CursorEndY
);
622 // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
623 // repaint the window without having it just freeze up and stay on the screen permanently.
624 Buff
->CursorBlinkOn
= TRUE
;
625 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
628 /* static */ VOID NTAPI
629 GuiRingBell(IN OUT PFRONTEND This
)
631 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
633 /* Emit an error beep sound */
634 SendNotifyMessage(GuiData
->hWindow
, PM_CONSOLE_BEEP
, 0, 0);
638 GuiSetCursorInfo(IN OUT PFRONTEND This
,
639 PCONSOLE_SCREEN_BUFFER Buff
)
641 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
643 /* Do nothing if the window is hidden */
644 if (!GuiData
->IsWindowVisible
) return TRUE
;
646 if (GuiData
->ActiveBuffer
== Buff
)
648 InvalidateCell(GuiData
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
655 GuiSetScreenInfo(IN OUT PFRONTEND This
,
656 PCONSOLE_SCREEN_BUFFER Buff
,
660 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
662 /* Do nothing if the window is hidden */
663 if (!GuiData
->IsWindowVisible
) return TRUE
;
665 if (GuiData
->ActiveBuffer
== Buff
)
667 /* Redraw char at old position (remove cursor) */
668 InvalidateCell(GuiData
, OldCursorX
, OldCursorY
);
669 /* Redraw char at new position (show cursor) */
670 InvalidateCell(GuiData
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
677 GuiResizeTerminal(IN OUT PFRONTEND This
)
679 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
681 /* Resize the window to the user's values */
682 PostMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
686 GuiSetActiveScreenBuffer(IN OUT PFRONTEND This
)
688 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
689 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
692 EnterCriticalSection(&GuiData
->Lock
);
693 GuiData
->WindowSizeLock
= TRUE
;
695 InterlockedExchangePointer(&GuiData
->ActiveBuffer
,
696 ConDrvGetActiveScreenBuffer(GuiData
->Console
));
698 GuiData
->WindowSizeLock
= FALSE
;
699 LeaveCriticalSection(&GuiData
->Lock
);
701 ActiveBuffer
= GuiData
->ActiveBuffer
;
703 /* Change the current palette */
704 if (ActiveBuffer
->PaletteHandle
== NULL
)
706 hPalette
= GuiData
->hSysPalette
;
710 hPalette
= ActiveBuffer
->PaletteHandle
;
713 DPRINT("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette
);
715 /* Set the new palette for the framebuffer */
716 SelectPalette(GuiData
->hMemDC
, hPalette
, FALSE
);
718 /* Specify the use of the system palette for the framebuffer */
719 SetSystemPaletteUse(GuiData
->hMemDC
, ActiveBuffer
->PaletteUsage
);
721 /* Realize the (logical) palette */
722 RealizePalette(GuiData
->hMemDC
);
724 GuiResizeTerminal(This
);
725 // ConioDrawConsole(Console);
729 GuiReleaseScreenBuffer(IN OUT PFRONTEND This
,
730 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer
)
732 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
735 * If we were notified to release a screen buffer that is not actually
736 * ours, then just ignore the notification...
738 if (ScreenBuffer
!= GuiData
->ActiveBuffer
) return;
741 * ... else, we must release our active buffer. Two cases are present:
742 * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console
743 * active screen buffer, then we can safely switch to it.
744 * - If ScreenBuffer IS the console active screen buffer, we must release
748 /* Release the old active palette and set the default one */
749 if (GetCurrentObject(GuiData
->hMemDC
, OBJ_PAL
) == ScreenBuffer
->PaletteHandle
)
751 /* Set the new palette */
752 SelectPalette(GuiData
->hMemDC
, GuiData
->hSysPalette
, FALSE
);
755 /* Set the adequate active screen buffer */
756 if (ScreenBuffer
!= GuiData
->Console
->ActiveBuffer
)
758 GuiSetActiveScreenBuffer(This
);
762 EnterCriticalSection(&GuiData
->Lock
);
763 GuiData
->WindowSizeLock
= TRUE
;
765 InterlockedExchangePointer(&GuiData
->ActiveBuffer
, NULL
);
767 GuiData
->WindowSizeLock
= FALSE
;
768 LeaveCriticalSection(&GuiData
->Lock
);
773 GuiSetMouseCursor(IN OUT PFRONTEND This
,
774 HCURSOR CursorHandle
);
777 GuiRefreshInternalInfo(IN OUT PFRONTEND This
)
779 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
781 /* Update the console leader information held by the window */
782 SetConWndConsoleLeaderCID(GuiData
);
786 * We reset the cursor here so that, when a console app quits, we reset
787 * the cursor to the default one. It's quite a hack since it doesn't proceed
788 * per - console process... This must be fixed.
790 * See GuiInitConsole(...) for more information.
793 /* Mouse is shown by default with its default cursor shape */
794 GuiData
->MouseCursorRefCount
= 0; // Reinitialize the reference counter
795 GuiSetMouseCursor(This
, NULL
);
799 GuiChangeTitle(IN OUT PFRONTEND This
)
801 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
802 // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
803 SetWindowText(GuiData
->hWindow
, GuiData
->Console
->Title
.Buffer
);
807 GuiChangeIcon(IN OUT PFRONTEND This
,
810 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
811 HICON hIcon
, hIconSm
;
813 if (IconHandle
== NULL
)
815 hIcon
= ghDefaultIcon
;
816 hIconSm
= ghDefaultIconSm
;
820 hIcon
= CopyIcon(IconHandle
);
821 hIconSm
= CopyIcon(IconHandle
);
829 if (hIcon
!= GuiData
->hIcon
)
831 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
833 DestroyIcon(GuiData
->hIcon
);
835 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
837 DestroyIcon(GuiData
->hIconSm
);
840 GuiData
->hIcon
= hIcon
;
841 GuiData
->hIconSm
= hIconSm
;
843 DPRINT("Set icons in GuiChangeIcon\n");
844 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
845 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
852 GuiGetConsoleWindowHandle(IN OUT PFRONTEND This
)
854 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
855 return GuiData
->hWindow
;
859 GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This
,
862 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
863 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
866 UINT WidthUnit
, HeightUnit
;
870 if (!SystemParametersInfoW(SPI_GETWORKAREA
, 0, &WorkArea
, 0))
872 DPRINT1("SystemParametersInfoW failed - What to do ??\n");
876 ActiveBuffer
= GuiData
->ActiveBuffer
;
879 GetScreenBufferSizeUnits(ActiveBuffer
, GuiData
, &WidthUnit
, &HeightUnit
);
883 /* Default: text mode */
884 WidthUnit
= GuiData
->CharWidth
;
885 HeightUnit
= GuiData
->CharHeight
;
888 width
= WorkArea
.right
;
889 height
= WorkArea
.bottom
;
891 width
-= (2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
)));
892 height
-= (2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
));
894 if (width
< 0) width
= 0;
895 if (height
< 0) height
= 0;
897 pSize
->X
= (SHORT
)(width
/ (int)WidthUnit
) /* HACK */ + 2;
898 pSize
->Y
= (SHORT
)(height
/ (int)HeightUnit
) /* HACK */ + 1;
902 GuiGetSelectionInfo(IN OUT PFRONTEND This
,
903 PCONSOLE_SELECTION_INFO pSelectionInfo
)
905 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
907 if (pSelectionInfo
== NULL
) return FALSE
;
909 ZeroMemory(pSelectionInfo
, sizeof(CONSOLE_SELECTION_INFO
));
910 if (GuiData
->Selection
.dwFlags
!= CONSOLE_NO_SELECTION
)
911 RtlCopyMemory(pSelectionInfo
, &GuiData
->Selection
, sizeof(CONSOLE_SELECTION_INFO
));
917 GuiSetPalette(IN OUT PFRONTEND This
,
918 HPALETTE PaletteHandle
,
921 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
924 // if (GetType(GuiData->ActiveBuffer) != GRAPHICS_BUFFER) return FALSE;
925 if (PaletteHandle
== NULL
) return FALSE
;
927 /* Set the new palette for the framebuffer */
928 OldPalette
= SelectPalette(GuiData
->hMemDC
, PaletteHandle
, FALSE
);
929 if (OldPalette
== NULL
) return FALSE
;
931 /* Specify the use of the system palette for the framebuffer */
932 SetSystemPaletteUse(GuiData
->hMemDC
, PaletteUsage
);
934 /* Realize the (logical) palette */
935 RealizePalette(GuiData
->hMemDC
);
937 /* Save the original system palette handle */
938 if (GuiData
->hSysPalette
== NULL
) GuiData
->hSysPalette
= OldPalette
;
944 GuiGetDisplayMode(IN OUT PFRONTEND This
)
946 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
947 ULONG DisplayMode
= 0;
949 if (GuiData
->GuiInfo
.FullScreen
)
950 DisplayMode
|= CONSOLE_FULLSCREEN_HARDWARE
; // CONSOLE_FULLSCREEN
952 DisplayMode
|= CONSOLE_WINDOWED
;
958 GuiSetDisplayMode(IN OUT PFRONTEND This
,
961 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
964 if (NewMode
& ~(CONSOLE_FULLSCREEN_MODE
| CONSOLE_WINDOWED_MODE
))
967 /* Do nothing if the window is hidden */
968 if (!GuiData
->IsWindowVisible
) return TRUE
;
970 FullScreen
= ((NewMode
& CONSOLE_FULLSCREEN_MODE
) != 0);
972 if (FullScreen
!= GuiData
->GuiInfo
.FullScreen
)
974 SwitchFullScreen(GuiData
, FullScreen
);
981 GuiShowMouseCursor(IN OUT PFRONTEND This
,
984 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
986 if (GuiData
->IsWindowVisible
)
988 /* Set the reference count */
989 if (Show
) ++GuiData
->MouseCursorRefCount
;
990 else --GuiData
->MouseCursorRefCount
;
992 /* Effectively show (or hide) the cursor (use special values for (w|l)Param) */
993 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
996 return GuiData
->MouseCursorRefCount
;
1000 GuiSetMouseCursor(IN OUT PFRONTEND This
,
1001 HCURSOR CursorHandle
)
1003 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1005 /* Do nothing if the window is hidden */
1006 if (!GuiData
->IsWindowVisible
) return TRUE
;
1009 * Set the cursor's handle. If the given handle is NULL,
1010 * then restore the default cursor.
1012 GuiData
->hCursor
= (CursorHandle
? CursorHandle
: ghDefaultCursor
);
1014 /* Effectively modify the shape of the cursor (use special values for (w|l)Param) */
1015 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
1021 GuiMenuControl(IN OUT PFRONTEND This
,
1025 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1027 GuiData
->CmdIdLow
= CmdIdLow
;
1028 GuiData
->CmdIdHigh
= CmdIdHigh
;
1030 return GetSystemMenu(GuiData
->hWindow
, FALSE
);
1034 GuiSetMenuClose(IN OUT PFRONTEND This
,
1038 * NOTE: See http://www.mail-archive.com/harbour@harbour-project.org/msg27509.html
1039 * or http://harbour-devel.1590103.n2.nabble.com/Question-about-hb-gt-win-CtrlHandler-usage-td4670862i20.html
1040 * for more information.
1043 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1044 HMENU hSysMenu
= GetSystemMenu(GuiData
->hWindow
, FALSE
);
1046 if (hSysMenu
== NULL
) return FALSE
;
1048 GuiData
->IsCloseButtonEnabled
= Enable
;
1049 EnableMenuItem(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
| (Enable
? MF_ENABLED
: MF_GRAYED
));
1054 static FRONTEND_VTBL GuiVtbl
=
1064 GuiSetActiveScreenBuffer
,
1065 GuiReleaseScreenBuffer
,
1066 GuiRefreshInternalInfo
,
1069 GuiGetConsoleWindowHandle
,
1070 GuiGetLargestConsoleWindowSize
,
1071 GuiGetSelectionInfo
,
1083 GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd
,
1084 IN OUT PCONSOLE_INFO ConsoleInfo
,
1085 IN OUT PVOID ExtraConsoleInfo
,
1088 PCONSOLE_INIT_INFO ConsoleInitInfo
= ExtraConsoleInfo
;
1089 PGUI_INIT_INFO GuiInitInfo
;
1091 if (FrontEnd
== NULL
|| ConsoleInfo
== NULL
|| ConsoleInitInfo
== NULL
)
1092 return STATUS_INVALID_PARAMETER
;
1094 /* Initialize GUI terminal emulator common functionalities */
1095 if (!GuiInit()) return STATUS_UNSUCCESSFUL
;
1098 * Initialize a private initialization info structure for later use.
1099 * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd.
1101 GuiInitInfo
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_INIT_INFO
));
1102 if (GuiInitInfo
== NULL
) return STATUS_NO_MEMORY
;
1104 // HACK: We suppose that the pointers will be valid in GuiInitFrontEnd...
1105 // If not, then copy exactly what we need in GuiInitInfo.
1106 GuiInitInfo
->ConsoleInfo
= ConsoleInfo
;
1107 GuiInitInfo
->ConsoleStartInfo
= ConsoleInitInfo
->ConsoleStartInfo
;
1108 GuiInitInfo
->ProcessId
= ProcessId
;
1109 GuiInitInfo
->IsWindowVisible
= ConsoleInitInfo
->IsWindowVisible
;
1111 /* Finally, initialize the frontend structure */
1112 FrontEnd
->Vtbl
= &GuiVtbl
;
1113 FrontEnd
->Data
= NULL
;
1114 FrontEnd
->OldData
= GuiInitInfo
;
1116 return STATUS_SUCCESS
;
1120 GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd
)
1122 if (FrontEnd
== NULL
) return STATUS_INVALID_PARAMETER
;
1124 if (FrontEnd
->Data
) GuiDeinitFrontEnd(FrontEnd
);
1125 if (FrontEnd
->OldData
) ConsoleFreeHeap(FrontEnd
->OldData
);
1127 return STATUS_SUCCESS
;