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 // FIXME: HACK: Potential HACK for CORE-8129; see revision 63595.
204 CreateSysMenu(GuiData
->hWindow
);
206 /* Switch to full-screen mode if necessary */
207 // FIXME: Move elsewhere, it cause misdrawings of the window.
208 if (GuiData
->GuiInfo
.FullScreen
) SwitchFullScreen(GuiData
, TRUE
);
210 DPRINT("PM_CREATE_CONSOLE -- showing window\n");
211 // ShowWindow(NewWindow, (int)wParam);
212 ShowWindowAsync(NewWindow
, (int)wParam
);
213 DPRINT("Window showed\n");
216 return (LRESULT
)NewWindow
;
219 case PM_DESTROY_CONSOLE
:
221 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)lParam
;
223 /* Exit the full screen mode if it was already set */
224 // LeaveFullScreen(GuiData);
227 * Window creation is done using a PostMessage(), so it's possible
228 * that the window that we want to destroy doesn't exist yet.
229 * So first empty the message queue.
232 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
234 TranslateMessage(&Msg);
235 DispatchMessageW(&Msg);
237 while (PeekMessageW(&Msg
, NULL
, 0, 0, PM_REMOVE
)) ;
239 if (GuiData
->hWindow
!= NULL
) /* && DestroyWindow(GuiData->hWindow) */
241 DestroyWindow(GuiData
->hWindow
);
243 WindowCount
= GetWindowLongW(hWnd
, GWL_USERDATA
);
245 SetWindowLongW(hWnd
, GWL_USERDATA
, WindowCount
);
246 if (0 == WindowCount
)
250 DPRINT("CONSRV: Going to quit the Gui Thread!!\n");
259 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
264 GuiConsoleGuiThread(PVOID Data
)
267 PHANDLE GraphicsStartupEvent
= (PHANDLE
)Data
;
270 * This thread dispatches all the console notifications to the notify window.
271 * It is common for all the console windows.
274 PrivateCsrssManualGuiCheck(+1);
276 NotifyWnd
= CreateWindowW(L
"ConSrvCreateNotify",
287 if (NULL
== NotifyWnd
)
289 PrivateCsrssManualGuiCheck(-1);
290 SetEvent(*GraphicsStartupEvent
);
294 SetEvent(*GraphicsStartupEvent
);
296 while (GetMessageW(&msg
, NULL
, 0, 0))
298 TranslateMessage(&msg
);
299 DispatchMessageW(&msg
);
302 DPRINT("CONSRV: Quit the Gui Thread!!\n");
303 PrivateCsrssManualGuiCheck(-1);
313 /* Exit if we were already initialized */
314 // if (ConsInitialized) return TRUE;
317 * Initialize and register the different window classes, if needed.
319 if (!ConsInitialized
)
321 /* Initialize the notification window class */
322 wc
.cbSize
= sizeof(WNDCLASSEXW
);
323 wc
.lpszClassName
= L
"ConSrvCreateNotify";
324 wc
.lpfnWndProc
= GuiConsoleNotifyWndProc
;
326 wc
.hInstance
= ConSrvDllInstance
;
330 wc
.hbrBackground
= NULL
;
331 wc
.lpszMenuName
= NULL
;
334 if (RegisterClassExW(&wc
) == 0)
336 DPRINT1("Failed to register GUI notify wndproc\n");
340 /* Initialize the console window class */
341 if (!RegisterConWndClass(ConSrvDllInstance
))
344 ConsInitialized
= TRUE
;
348 * Set-up the notification window
350 if (NULL
== NotifyWnd
)
353 HANDLE GraphicsStartupEvent
;
355 GraphicsStartupEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
356 if (NULL
== GraphicsStartupEvent
) return FALSE
;
358 ThreadHandle
= CreateThread(NULL
,
361 (PVOID
)&GraphicsStartupEvent
,
364 if (NULL
== ThreadHandle
)
366 CloseHandle(GraphicsStartupEvent
);
367 DPRINT1("CONSRV: Failed to create graphics console thread. Expect problems\n");
370 SetThreadPriority(ThreadHandle
, THREAD_PRIORITY_HIGHEST
);
371 CloseHandle(ThreadHandle
);
373 WaitForSingleObject(GraphicsStartupEvent
, INFINITE
);
374 CloseHandle(GraphicsStartupEvent
);
376 if (NULL
== NotifyWnd
)
378 DPRINT1("CONSRV: Failed to create notification window.\n");
383 // ConsInitialized = TRUE;
390 /******************************************************************************
391 * GUI Console Driver *
392 ******************************************************************************/
395 GuiDeinitFrontEnd(IN OUT PFRONTEND This
);
398 GuiInitFrontEnd(IN OUT PFRONTEND This
,
401 PGUI_INIT_INFO GuiInitInfo
;
402 PCONSOLE_INFO ConsoleInfo
;
403 PCONSOLE_START_INFO ConsoleStartInfo
;
405 PGUI_CONSOLE_DATA GuiData
;
406 GUI_CONSOLE_INFO TermInfo
;
409 LPWSTR IconPath
= NULL
;
412 if (This
== NULL
|| Console
== NULL
|| This
->OldData
== NULL
)
413 return STATUS_INVALID_PARAMETER
;
415 ASSERT(This
->Console
== Console
);
417 GuiInitInfo
= This
->OldData
;
419 if (GuiInitInfo
->ConsoleInfo
== NULL
|| GuiInitInfo
->ConsoleStartInfo
== NULL
)
420 return STATUS_INVALID_PARAMETER
;
422 ConsoleInfo
= GuiInitInfo
->ConsoleInfo
;
423 ConsoleStartInfo
= GuiInitInfo
->ConsoleStartInfo
;
425 IconPath
= ConsoleStartInfo
->IconPath
;
426 IconIndex
= ConsoleStartInfo
->IconIndex
;
429 /* Terminal data allocation */
430 GuiData
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_CONSOLE_DATA
));
433 DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
434 return STATUS_UNSUCCESSFUL
;
436 ///// /* HACK */ Console->FrontEndIFace.Data = (PVOID)GuiData; /* HACK */
437 GuiData
->Console
= Console
;
438 GuiData
->ActiveBuffer
= Console
->ActiveBuffer
;
439 GuiData
->hWindow
= NULL
;
441 /* The console can be resized */
442 Console
->FixedSize
= FALSE
;
444 InitializeCriticalSection(&GuiData
->Lock
);
448 * Load terminal settings
451 /* 1. Load the default settings */
452 GuiConsoleGetDefaultSettings(&TermInfo
, GuiInitInfo
->ProcessId
);
454 /* 3. Load the remaining console settings via the registry. */
455 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
457 /* Load the terminal infos from the registry. */
458 GuiConsoleReadUserSettings(&TermInfo
,
459 ConsoleInfo
->ConsoleTitle
,
460 GuiInitInfo
->ProcessId
);
463 * Now, update them with the properties the user might gave to us
464 * via the STARTUPINFO structure before calling CreateProcess
465 * (and which was transmitted via the ConsoleStartInfo structure).
466 * We therefore overwrite the values read in the registry.
468 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USESHOWWINDOW
)
470 TermInfo
.ShowWindow
= ConsoleStartInfo
->wShowWindow
;
472 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USEPOSITION
)
474 TermInfo
.AutoPosition
= FALSE
;
475 TermInfo
.WindowOrigin
.x
= ConsoleStartInfo
->dwWindowOrigin
.X
;
476 TermInfo
.WindowOrigin
.y
= ConsoleStartInfo
->dwWindowOrigin
.Y
;
478 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_RUNFULLSCREEN
)
480 TermInfo
.FullScreen
= TRUE
;
490 Length
= min(wcslen(TermInfo
.FaceName
) + 1, LF_FACESIZE
); // wcsnlen
491 wcsncpy(GuiData
->GuiInfo
.FaceName
, TermInfo
.FaceName
, LF_FACESIZE
);
492 GuiData
->GuiInfo
.FaceName
[Length
] = L
'\0';
493 GuiData
->GuiInfo
.FontFamily
= TermInfo
.FontFamily
;
494 GuiData
->GuiInfo
.FontSize
= TermInfo
.FontSize
;
495 GuiData
->GuiInfo
.FontWeight
= TermInfo
.FontWeight
;
498 GuiData
->GuiInfo
.FullScreen
= TermInfo
.FullScreen
;
499 GuiData
->GuiInfo
.ShowWindow
= TermInfo
.ShowWindow
;
500 GuiData
->GuiInfo
.AutoPosition
= TermInfo
.AutoPosition
;
501 GuiData
->GuiInfo
.WindowOrigin
= TermInfo
.WindowOrigin
;
503 /* Initialize the icon handles to their default values */
504 GuiData
->hIcon
= ghDefaultIcon
;
505 GuiData
->hIconSm
= ghDefaultIconSm
;
507 /* Get the associated icon, if any */
508 if (IconPath
== NULL
|| IconPath
[0] == L
'\0')
510 IconPath
= ConsoleStartInfo
->AppPath
;
513 DPRINT("IconPath = %S ; IconIndex = %lu\n", (IconPath
? IconPath
: L
"n/a"), IconIndex
);
514 if (IconPath
&& IconPath
[0] != L
'\0')
516 HICON hIcon
= NULL
, hIconSm
= NULL
;
517 PrivateExtractIconExW(IconPath
,
522 DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon
, hIconSm
);
523 if (hIcon
!= NULL
) GuiData
->hIcon
= hIcon
;
524 if (hIconSm
!= NULL
) GuiData
->hIconSm
= hIconSm
;
526 ASSERT(GuiData
->hIcon
&& GuiData
->hIconSm
);
528 /* Mouse is shown by default with its default cursor shape */
529 GuiData
->hCursor
= ghDefaultCursor
;
530 GuiData
->MouseCursorRefCount
= 0;
532 /* A priori don't ignore mouse signals */
533 GuiData
->IgnoreNextMouseSignal
= FALSE
;
535 /* Close button and the corresponding system menu item are enabled by default */
536 GuiData
->IsCloseButtonEnabled
= TRUE
;
538 /* There is no user-reserved menu id range by default */
539 GuiData
->CmdIdLow
= GuiData
->CmdIdHigh
= 0;
541 /* Initialize the selection */
542 RtlZeroMemory(&GuiData
->Selection
, sizeof(GuiData
->Selection
));
543 GuiData
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
544 RtlZeroMemory(&GuiData
->dwSelectionCursor
, sizeof(GuiData
->dwSelectionCursor
));
545 GuiData
->LineSelection
= FALSE
; // Default to block selection
546 // TODO: Retrieve the selection mode via the registry.
549 * We need to wait until the GUI has been fully initialized
550 * to retrieve custom settings i.e. WindowSize etc...
551 * Ideally we could use SendNotifyMessage for this but its not
554 GuiData
->hGuiInitEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
556 DPRINT("GUI - Checkpoint\n");
558 /* Create the terminal window */
559 PostMessageW(NotifyWnd
, PM_CREATE_CONSOLE
, GuiData
->GuiInfo
.ShowWindow
, (LPARAM
)GuiData
);
561 /* Wait until initialization has finished */
562 WaitForSingleObject(GuiData
->hGuiInitEvent
, INFINITE
);
563 DPRINT("OK we created the console window\n");
564 CloseHandle(GuiData
->hGuiInitEvent
);
565 GuiData
->hGuiInitEvent
= NULL
;
567 /* Check whether we really succeeded in initializing the terminal window */
568 if (GuiData
->hWindow
== NULL
)
570 DPRINT("GuiInitConsole - We failed at creating a new terminal window\n");
571 GuiDeinitFrontEnd(This
);
572 return STATUS_UNSUCCESSFUL
;
575 /* Finally, finish to initialize the frontend structure */
576 This
->Data
= GuiData
;
577 if (This
->OldData
) ConsoleFreeHeap(This
->OldData
);
578 This
->OldData
= NULL
;
580 return STATUS_SUCCESS
;
584 GuiDeinitFrontEnd(IN OUT PFRONTEND This
)
586 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
588 SendMessageW(NotifyWnd
, PM_DESTROY_CONSOLE
, 0, (LPARAM
)GuiData
);
590 DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
591 GuiData
->hIcon
, ghDefaultIcon
, GuiData
->hIconSm
, ghDefaultIconSm
);
592 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
594 DPRINT("Destroy hIcon\n");
595 DestroyIcon(GuiData
->hIcon
);
597 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
599 DPRINT("Destroy hIconSm\n");
600 DestroyIcon(GuiData
->hIconSm
);
604 DeleteCriticalSection(&GuiData
->Lock
);
605 ConsoleFreeHeap(GuiData
);
607 DPRINT("Quit GuiDeinitFrontEnd\n");
611 GuiDrawRegion(IN OUT PFRONTEND This
,
614 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
615 DrawRegion(GuiData
, Region
);
619 GuiWriteStream(IN OUT PFRONTEND This
,
627 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
628 PCONSOLE_SCREEN_BUFFER Buff
;
629 SHORT CursorEndX
, CursorEndY
;
632 if (NULL
== GuiData
|| NULL
== GuiData
->hWindow
) return;
634 Buff
= GuiData
->ActiveBuffer
;
635 if (GetType(Buff
) != TEXTMODE_BUFFER
) return;
637 if (0 != ScrolledLines
)
641 ScrollRect
.right
= Buff
->ViewSize
.X
* GuiData
->CharWidth
;
642 ScrollRect
.bottom
= Region
->Top
* GuiData
->CharHeight
;
644 ScrollWindowEx(GuiData
->hWindow
,
646 -(int)(ScrolledLines
* GuiData
->CharHeight
),
654 DrawRegion(GuiData
, Region
);
656 if (CursorStartX
< Region
->Left
|| Region
->Right
< CursorStartX
657 || CursorStartY
< Region
->Top
|| Region
->Bottom
< CursorStartY
)
659 InvalidateCell(GuiData
, CursorStartX
, CursorStartY
);
662 CursorEndX
= Buff
->CursorPosition
.X
;
663 CursorEndY
= Buff
->CursorPosition
.Y
;
664 if ((CursorEndX
< Region
->Left
|| Region
->Right
< CursorEndX
665 || CursorEndY
< Region
->Top
|| Region
->Bottom
< CursorEndY
)
666 && (CursorEndX
!= CursorStartX
|| CursorEndY
!= CursorStartY
))
668 InvalidateCell(GuiData
, CursorEndX
, CursorEndY
);
672 // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
673 // repaint the window without having it just freeze up and stay on the screen permanently.
674 Buff
->CursorBlinkOn
= TRUE
;
675 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
679 GuiSetCursorInfo(IN OUT PFRONTEND This
,
680 PCONSOLE_SCREEN_BUFFER Buff
)
682 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
684 if (GuiData
->ActiveBuffer
== Buff
)
686 InvalidateCell(GuiData
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
693 GuiSetScreenInfo(IN OUT PFRONTEND This
,
694 PCONSOLE_SCREEN_BUFFER Buff
,
698 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
700 if (GuiData
->ActiveBuffer
== Buff
)
702 /* Redraw char at old position (remove cursor) */
703 InvalidateCell(GuiData
, OldCursorX
, OldCursorY
);
704 /* Redraw char at new position (show cursor) */
705 InvalidateCell(GuiData
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
712 GuiResizeTerminal(IN OUT PFRONTEND This
)
714 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
716 /* Resize the window to the user's values */
717 PostMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
721 GuiSetActiveScreenBuffer(IN OUT PFRONTEND This
)
723 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
724 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
727 EnterCriticalSection(&GuiData
->Lock
);
728 GuiData
->WindowSizeLock
= TRUE
;
730 InterlockedExchangePointer(&GuiData
->ActiveBuffer
,
731 ConDrvGetActiveScreenBuffer(GuiData
->Console
));
733 GuiData
->WindowSizeLock
= FALSE
;
734 LeaveCriticalSection(&GuiData
->Lock
);
736 ActiveBuffer
= GuiData
->ActiveBuffer
;
738 /* Change the current palette */
739 if (ActiveBuffer
->PaletteHandle
== NULL
)
741 hPalette
= GuiData
->hSysPalette
;
745 hPalette
= ActiveBuffer
->PaletteHandle
;
748 DPRINT1("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette
);
750 /* Set the new palette for the framebuffer */
751 SelectPalette(GuiData
->hMemDC
, hPalette
, FALSE
);
753 /* Specify the use of the system palette for the framebuffer */
754 SetSystemPaletteUse(GuiData
->hMemDC
, ActiveBuffer
->PaletteUsage
);
756 /* Realize the (logical) palette */
757 RealizePalette(GuiData
->hMemDC
);
759 GuiResizeTerminal(This
);
760 // ConioDrawConsole(Console);
764 GuiReleaseScreenBuffer(IN OUT PFRONTEND This
,
765 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer
)
767 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
770 * If we were notified to release a screen buffer that is not actually
771 * ours, then just ignore the notification...
773 if (ScreenBuffer
!= GuiData
->ActiveBuffer
) return;
776 * ... else, we must release our active buffer. Two cases are present:
777 * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console
778 * active screen buffer, then we can safely switch to it.
779 * - If ScreenBuffer IS the console active screen buffer, we must release
783 /* Release the old active palette and set the default one */
784 if (GetCurrentObject(GuiData
->hMemDC
, OBJ_PAL
) == ScreenBuffer
->PaletteHandle
)
786 /* Set the new palette */
787 SelectPalette(GuiData
->hMemDC
, GuiData
->hSysPalette
, FALSE
);
790 /* Set the adequate active screen buffer */
791 if (ScreenBuffer
!= GuiData
->Console
->ActiveBuffer
)
793 GuiSetActiveScreenBuffer(This
);
797 EnterCriticalSection(&GuiData
->Lock
);
798 GuiData
->WindowSizeLock
= TRUE
;
800 InterlockedExchangePointer(&GuiData
->ActiveBuffer
, NULL
);
802 GuiData
->WindowSizeLock
= FALSE
;
803 LeaveCriticalSection(&GuiData
->Lock
);
808 GuiSetMouseCursor(IN OUT PFRONTEND This
,
809 HCURSOR CursorHandle
);
812 GuiRefreshInternalInfo(IN OUT PFRONTEND This
)
814 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
816 /* Update the console leader information held by the window */
817 SetConWndConsoleLeaderCID(GuiData
);
821 * We reset the cursor here so that, when a console app quits, we reset
822 * the cursor to the default one. It's quite a hack since it doesn't proceed
823 * per - console process... This must be fixed.
825 * See GuiInitConsole(...) for more information.
828 /* Mouse is shown by default with its default cursor shape */
829 GuiData
->MouseCursorRefCount
= 0; // Reinitialize the reference counter
830 GuiSetMouseCursor(This
, NULL
);
834 GuiChangeTitle(IN OUT PFRONTEND This
)
836 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
837 // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
838 SetWindowText(GuiData
->hWindow
, GuiData
->Console
->Title
.Buffer
);
842 GuiChangeIcon(IN OUT PFRONTEND This
,
845 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
846 HICON hIcon
, hIconSm
;
848 if (IconHandle
== NULL
)
850 hIcon
= ghDefaultIcon
;
851 hIconSm
= ghDefaultIconSm
;
855 hIcon
= CopyIcon(IconHandle
);
856 hIconSm
= CopyIcon(IconHandle
);
864 if (hIcon
!= GuiData
->hIcon
)
866 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
868 DestroyIcon(GuiData
->hIcon
);
870 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
872 DestroyIcon(GuiData
->hIconSm
);
875 GuiData
->hIcon
= hIcon
;
876 GuiData
->hIconSm
= hIconSm
;
878 DPRINT("Set icons in GuiChangeIcon\n");
879 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
880 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
887 GuiGetConsoleWindowHandle(IN OUT PFRONTEND This
)
889 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
890 return GuiData
->hWindow
;
894 GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This
,
897 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
898 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
901 UINT WidthUnit
, HeightUnit
;
905 if (!SystemParametersInfoW(SPI_GETWORKAREA
, 0, &WorkArea
, 0))
907 DPRINT1("SystemParametersInfoW failed - What to do ??\n");
911 ActiveBuffer
= GuiData
->ActiveBuffer
;
914 GetScreenBufferSizeUnits(ActiveBuffer
, GuiData
, &WidthUnit
, &HeightUnit
);
918 /* Default: text mode */
919 WidthUnit
= GuiData
->CharWidth
;
920 HeightUnit
= GuiData
->CharHeight
;
923 width
= WorkArea
.right
;
924 height
= WorkArea
.bottom
;
926 width
-= (2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
)));
927 height
-= (2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
));
929 if (width
< 0) width
= 0;
930 if (height
< 0) height
= 0;
932 pSize
->X
= (SHORT
)(width
/ (int)WidthUnit
) /* HACK */ + 2;
933 pSize
->Y
= (SHORT
)(height
/ (int)HeightUnit
) /* HACK */ + 1;
937 GuiGetSelectionInfo(IN OUT PFRONTEND This
,
938 PCONSOLE_SELECTION_INFO pSelectionInfo
)
940 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
942 if (pSelectionInfo
== NULL
) return FALSE
;
944 ZeroMemory(pSelectionInfo
, sizeof(CONSOLE_SELECTION_INFO
));
945 if (GuiData
->Selection
.dwFlags
!= CONSOLE_NO_SELECTION
)
946 RtlCopyMemory(pSelectionInfo
, &GuiData
->Selection
, sizeof(CONSOLE_SELECTION_INFO
));
952 GuiSetPalette(IN OUT PFRONTEND This
,
953 HPALETTE PaletteHandle
,
956 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
959 // if (GetType(GuiData->ActiveBuffer) != GRAPHICS_BUFFER) return FALSE;
960 if (PaletteHandle
== NULL
) return FALSE
;
962 /* Set the new palette for the framebuffer */
963 OldPalette
= SelectPalette(GuiData
->hMemDC
, PaletteHandle
, FALSE
);
964 if (OldPalette
== NULL
) return FALSE
;
966 /* Specify the use of the system palette for the framebuffer */
967 SetSystemPaletteUse(GuiData
->hMemDC
, PaletteUsage
);
969 /* Realize the (logical) palette */
970 RealizePalette(GuiData
->hMemDC
);
972 /* Save the original system palette handle */
973 if (GuiData
->hSysPalette
== NULL
) GuiData
->hSysPalette
= OldPalette
;
979 GuiGetDisplayMode(IN OUT PFRONTEND This
)
981 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
982 ULONG DisplayMode
= 0;
984 if (GuiData
->GuiInfo
.FullScreen
)
985 DisplayMode
|= CONSOLE_FULLSCREEN_HARDWARE
; // CONSOLE_FULLSCREEN
987 DisplayMode
|= CONSOLE_WINDOWED
;
993 GuiSetDisplayMode(IN OUT PFRONTEND This
,
996 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
999 if (NewMode
& ~(CONSOLE_FULLSCREEN_MODE
| CONSOLE_WINDOWED_MODE
))
1002 FullScreen
= ((NewMode
& CONSOLE_FULLSCREEN_MODE
) != 0);
1004 if (FullScreen
!= GuiData
->GuiInfo
.FullScreen
)
1006 SwitchFullScreen(GuiData
, FullScreen
);
1013 GuiShowMouseCursor(IN OUT PFRONTEND This
,
1016 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1018 /* Set the reference count */
1019 if (Show
) ++GuiData
->MouseCursorRefCount
;
1020 else --GuiData
->MouseCursorRefCount
;
1022 /* Effectively show (or hide) the cursor (use special values for (w|l)Param) */
1023 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
1025 return GuiData
->MouseCursorRefCount
;
1029 GuiSetMouseCursor(IN OUT PFRONTEND This
,
1030 HCURSOR CursorHandle
)
1032 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1035 * Set the cursor's handle. If the given handle is NULL,
1036 * then restore the default cursor.
1038 GuiData
->hCursor
= (CursorHandle
? CursorHandle
: ghDefaultCursor
);
1040 /* Effectively modify the shape of the cursor (use special values for (w|l)Param) */
1041 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
1047 GuiMenuControl(IN OUT PFRONTEND This
,
1051 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1053 GuiData
->CmdIdLow
= CmdIdLow
;
1054 GuiData
->CmdIdHigh
= CmdIdHigh
;
1056 return GetSystemMenu(GuiData
->hWindow
, FALSE
);
1060 GuiSetMenuClose(IN OUT PFRONTEND This
,
1064 * NOTE: See http://www.mail-archive.com/harbour@harbour-project.org/msg27509.html
1065 * or http://harbour-devel.1590103.n2.nabble.com/Question-about-hb-gt-win-CtrlHandler-usage-td4670862i20.html
1066 * for more information.
1069 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
1070 HMENU hSysMenu
= GetSystemMenu(GuiData
->hWindow
, FALSE
);
1072 if (hSysMenu
== NULL
) return FALSE
;
1074 GuiData
->IsCloseButtonEnabled
= Enable
;
1075 EnableMenuItem(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
| (Enable
? MF_ENABLED
: MF_GRAYED
));
1080 static FRONTEND_VTBL GuiVtbl
=
1089 GuiSetActiveScreenBuffer
,
1090 GuiReleaseScreenBuffer
,
1091 GuiRefreshInternalInfo
,
1094 GuiGetConsoleWindowHandle
,
1095 GuiGetLargestConsoleWindowSize
,
1096 GuiGetSelectionInfo
,
1108 LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo
,
1109 IN OUT PCONSOLE_INFO ConsoleInfo
)
1111 #define PATH_SEPARATOR L'\\'
1113 BOOL RetVal
= FALSE
;
1114 HRESULT hRes
= S_OK
;
1115 LPWSTR LinkName
= NULL
;
1118 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
1121 ConsoleStartInfo
->IconPath
[0] = L
'\0';
1122 ConsoleStartInfo
->IconIndex
= 0;
1124 /* 1- Find the last path separator if any */
1125 LinkName
= wcsrchr(ConsoleStartInfo
->ConsoleTitle
, PATH_SEPARATOR
);
1126 if (LinkName
== NULL
)
1128 LinkName
= ConsoleStartInfo
->ConsoleTitle
;
1132 /* Skip the path separator */
1136 /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
1137 Length
= wcslen(LinkName
);
1138 if ( (Length
<= 4) || (wcsicmp(LinkName
+ (Length
- 4), L
".lnk") != 0) )
1141 /* 3- It may be a link. Try to retrieve some properties */
1142 hRes
= CoInitialize(NULL
);
1143 if (SUCCEEDED(hRes
))
1145 /* Get a pointer to the IShellLink interface */
1146 IShellLinkW
* pshl
= NULL
;
1147 hRes
= CoCreateInstance(&CLSID_ShellLink
,
1149 CLSCTX_INPROC_SERVER
,
1152 if (SUCCEEDED(hRes
))
1154 /* Get a pointer to the IPersistFile interface */
1155 IPersistFile
* ppf
= NULL
;
1156 hRes
= IPersistFile_QueryInterface(pshl
, &IID_IPersistFile
, (LPVOID
*)&ppf
);
1157 if (SUCCEEDED(hRes
))
1159 /* Load the shortcut */
1160 hRes
= IPersistFile_Load(ppf
, ConsoleStartInfo
->ConsoleTitle
, STGM_READ
);
1161 if (SUCCEEDED(hRes
))
1164 * Finally we can get the properties !
1165 * Update the old ones if needed.
1170 /* Reset the name of the console with the name of the shortcut */
1171 Length
= min(/*Length*/ Length
- 4, // 4 == len(".lnk")
1172 sizeof(ConsoleInfo
->ConsoleTitle
) / sizeof(ConsoleInfo
->ConsoleTitle
[0]) - 1);
1173 wcsncpy(ConsoleInfo
->ConsoleTitle
, LinkName
, Length
);
1174 ConsoleInfo
->ConsoleTitle
[Length
] = L
'\0';
1176 /* Get the window showing command */
1177 hRes
= IShellLinkW_GetShowCmd(pshl
, &ShowCmd
);
1178 if (SUCCEEDED(hRes
)) ConsoleStartInfo
->wShowWindow
= (WORD
)ShowCmd
;
1180 /* Get the hotkey */
1181 // hRes = pshl->GetHotkey(&ShowCmd);
1182 // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey;
1184 /* Get the icon location, if any */
1186 hRes
= IShellLinkW_GetIconLocation(pshl
,
1187 ConsoleStartInfo
->IconPath
,
1188 sizeof(ConsoleStartInfo
->IconPath
)/sizeof(ConsoleStartInfo
->IconPath
[0]) - 1, // == MAX_PATH
1189 &ConsoleStartInfo
->IconIndex
);
1190 if (!SUCCEEDED(hRes
))
1192 ConsoleStartInfo
->IconPath
[0] = L
'\0';
1193 ConsoleStartInfo
->IconIndex
= 0;
1196 // FIXME: Since we still don't load console properties from the shortcut,
1197 // return false. When this will be done, we will return true instead.
1200 IPersistFile_Release(ppf
);
1202 IShellLinkW_Release(pshl
);
1211 GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd
,
1212 IN OUT PCONSOLE_INFO ConsoleInfo
,
1213 IN OUT PVOID ExtraConsoleInfo
,
1216 PCONSOLE_START_INFO ConsoleStartInfo
= ExtraConsoleInfo
;
1217 PGUI_INIT_INFO GuiInitInfo
;
1219 if (FrontEnd
== NULL
|| ConsoleInfo
== NULL
|| ConsoleStartInfo
== NULL
)
1220 return STATUS_INVALID_PARAMETER
;
1222 /* Initialize GUI terminal emulator common functionalities */
1223 if (!GuiInit()) return STATUS_UNSUCCESSFUL
;
1226 * Load per-application terminal settings.
1228 * Check whether the process creating the console was launched via
1229 * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the
1230 * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too.
1232 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
)
1234 if (!LoadShellLinkConsoleInfo(ConsoleStartInfo
, ConsoleInfo
))
1236 ConsoleStartInfo
->dwStartupFlags
&= ~STARTF_TITLEISLINKNAME
;
1241 * Initialize a private initialization info structure for later use.
1242 * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd.
1244 GuiInitInfo
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_INIT_INFO
));
1245 if (GuiInitInfo
== NULL
) return STATUS_NO_MEMORY
;
1247 // HACK: We suppose that the pointers will be valid in GuiInitFrontEnd...
1248 GuiInitInfo
->ConsoleInfo
= ConsoleInfo
;
1249 GuiInitInfo
->ConsoleStartInfo
= ConsoleStartInfo
;
1250 GuiInitInfo
->ProcessId
= ProcessId
;
1252 /* Finally, initialize the frontend structure */
1253 FrontEnd
->Vtbl
= &GuiVtbl
;
1254 FrontEnd
->Data
= NULL
;
1255 FrontEnd
->OldData
= GuiInitInfo
;
1257 return STATUS_SUCCESS
;
1261 GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd
)
1263 if (FrontEnd
== NULL
) return STATUS_INVALID_PARAMETER
;
1265 if (FrontEnd
->Data
) GuiDeinitFrontEnd(FrontEnd
);
1266 if (FrontEnd
->OldData
) ConsoleFreeHeap(FrontEnd
->OldData
);
1268 return STATUS_SUCCESS
;