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 *******************************************************************/
26 /* GUI Console Window Class name */
27 #define GUI_CONSOLE_WINDOW_CLASS L"ConsoleWindowClass"
32 #define PM_CREATE_CONSOLE (WM_APP + 1)
33 #define PM_DESTROY_CONSOLE (WM_APP + 2)
34 #define PM_RESIZE_TERMINAL (WM_APP + 3)
35 #define PM_CONSOLE_BEEP (WM_APP + 4)
36 #define PM_CONSOLE_SET_TITLE (WM_APP + 5)
39 /* Not defined in any header file */
40 extern VOID NTAPI
PrivateCsrssManualGuiCheck(LONG Check
);
41 // See winsrv/usersrv/init.c line 234
44 /* GLOBALS ********************************************************************/
46 typedef struct _GUI_INIT_INFO
48 PCONSOLE_INFO ConsoleInfo
;
49 PCONSOLE_START_INFO ConsoleStartInfo
;
51 } GUI_INIT_INFO
, *PGUI_INIT_INFO
;
53 /**************************************************************\
54 \** Define the Console Leader Process for the console window **/
55 #define GWLP_CONSOLEWND_ALLOC (2 * sizeof(LONG_PTR))
56 #define GWLP_CONSOLE_LEADER_PID 0
57 #define GWLP_CONSOLE_LEADER_TID 4
59 #define SetConsoleWndConsoleLeaderCID(GuiData) \
61 PCONSOLE_PROCESS_DATA ProcessData; \
62 CLIENT_ID ConsoleLeaderCID; \
63 ProcessData = CONTAINING_RECORD((GuiData)->Console->ProcessList.Blink, \
64 CONSOLE_PROCESS_DATA, \
66 ConsoleLeaderCID = ProcessData->Process->ClientId; \
67 SetWindowLongPtrW((GuiData)->hWindow, GWLP_CONSOLE_LEADER_PID, \
68 (LONG_PTR)(ConsoleLeaderCID.UniqueProcess)); \
69 SetWindowLongPtrW((GuiData)->hWindow, GWLP_CONSOLE_LEADER_TID, \
70 (LONG_PTR)(ConsoleLeaderCID.UniqueThread )); \
72 /**************************************************************/
74 static BOOL ConsInitialized
= FALSE
;
75 static HICON ghDefaultIcon
= NULL
;
76 static HICON ghDefaultIconSm
= NULL
;
77 static HCURSOR ghDefaultCursor
= NULL
;
78 static HWND NotifyWnd
= NULL
;
80 typedef struct _GUICONSOLE_MENUITEM
83 const struct _GUICONSOLE_MENUITEM
*SubMenu
;
85 } GUICONSOLE_MENUITEM
, *PGUICONSOLE_MENUITEM
;
87 static const GUICONSOLE_MENUITEM GuiConsoleEditMenuItems
[] =
89 { IDS_MARK
, NULL
, ID_SYSTEM_EDIT_MARK
},
90 { IDS_COPY
, NULL
, ID_SYSTEM_EDIT_COPY
},
91 { IDS_PASTE
, NULL
, ID_SYSTEM_EDIT_PASTE
},
92 { IDS_SELECTALL
, NULL
, ID_SYSTEM_EDIT_SELECTALL
},
93 { IDS_SCROLL
, NULL
, ID_SYSTEM_EDIT_SCROLL
},
94 { IDS_FIND
, NULL
, ID_SYSTEM_EDIT_FIND
},
96 { 0, NULL
, 0 } /* End of list */
99 static const GUICONSOLE_MENUITEM GuiConsoleMainMenuItems
[] =
101 { IDS_EDIT
, GuiConsoleEditMenuItems
, 0 },
102 { IDS_DEFAULTS
, NULL
, ID_SYSTEM_DEFAULTS
},
103 { IDS_PROPERTIES
, NULL
, ID_SYSTEM_PROPERTIES
},
105 { 0, NULL
, 0 } /* End of list */
109 * Default 16-color palette for foreground and background
110 * (corresponding flags in comments).
112 const COLORREF s_Colors
[16] =
114 RGB(0, 0, 0), // (Black)
115 RGB(0, 0, 128), // BLUE
116 RGB(0, 128, 0), // GREEN
117 RGB(0, 128, 128), // BLUE | GREEN
118 RGB(128, 0, 0), // RED
119 RGB(128, 0, 128), // BLUE | RED
120 RGB(128, 128, 0), // GREEN | RED
121 RGB(192, 192, 192), // BLUE | GREEN | RED
123 RGB(128, 128, 128), // (Grey) INTENSITY
124 RGB(0, 0, 255), // BLUE | INTENSITY
125 RGB(0, 255, 0), // GREEN | INTENSITY
126 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
127 RGB(255, 0, 0), // RED | INTENSITY
128 RGB(255, 0, 255), // BLUE | RED | INTENSITY
129 RGB(255, 255, 0), // GREEN | RED | INTENSITY
130 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
133 /* FUNCTIONS ******************************************************************/
136 GetScreenBufferSizeUnits(IN PCONSOLE_SCREEN_BUFFER Buffer
,
137 IN PGUI_CONSOLE_DATA GuiData
,
139 OUT PUINT HeightUnit
)
141 if (Buffer
== NULL
|| GuiData
== NULL
||
142 WidthUnit
== NULL
|| HeightUnit
== NULL
)
147 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
149 *WidthUnit
= GuiData
->CharWidth
;
150 *HeightUnit
= GuiData
->CharHeight
;
152 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
162 GuiConsoleAppendMenuItems(HMENU hMenu
,
163 const GUICONSOLE_MENUITEM
*Items
)
166 WCHAR szMenuString
[255];
171 if (Items
[i
].uID
!= (UINT
)-1)
173 if (LoadStringW(ConSrvDllInstance
,
176 sizeof(szMenuString
) / sizeof(szMenuString
[0])) > 0)
178 if (Items
[i
].SubMenu
!= NULL
)
180 hSubMenu
= CreatePopupMenu();
181 if (hSubMenu
!= NULL
)
183 GuiConsoleAppendMenuItems(hSubMenu
,
186 if (!AppendMenuW(hMenu
,
187 MF_STRING
| MF_POPUP
,
191 DestroyMenu(hSubMenu
);
212 } while (!(Items
[i
].uID
== 0 && Items
[i
].SubMenu
== NULL
&& Items
[i
].wCmdID
== 0));
216 GuiConsoleCreateSysMenu(HWND hWnd
)
218 HMENU hMenu
= GetSystemMenu(hWnd
, FALSE
);
221 GuiConsoleAppendMenuItems(hMenu
, GuiConsoleMainMenuItems
);
227 GuiSendMenuEvent(PCONSOLE Console
, UINT CmdId
)
231 er
.EventType
= MENU_EVENT
;
232 er
.Event
.MenuEvent
.dwCommandId
= CmdId
;
234 ConioProcessInputEvent(Console
, &er
);
238 GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData
);
240 GuiConsolePaste(PGUI_CONSOLE_DATA GuiData
);
242 GuiConsoleUpdateSelection(PCONSOLE Console
, PCOORD coord
);
244 GuiDrawRegion(IN OUT PFRONTEND This
, SMALL_RECT
* Region
);
246 GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData
, DWORD WidthUnit
, DWORD HeightUnit
);
250 GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData
, WPARAM wParam
, LPARAM lParam
)
253 PCONSOLE Console
= GuiData
->Console
;
254 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
256 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
261 ActiveBuffer
= GuiData
->ActiveBuffer
;
264 * In case the selected menu item belongs to the user-reserved menu id range,
265 * send to him a menu event and return directly. The user must handle those
266 * reserved menu commands...
268 if (GuiData
->cmdIdLow
<= (UINT
)wParam
&& (UINT
)wParam
<= GuiData
->cmdIdHigh
)
270 GuiSendMenuEvent(Console
, (UINT
)wParam
);
274 /* ... otherwise, perform actions. */
277 case ID_SYSTEM_EDIT_MARK
:
279 LPWSTR WindowTitle
= NULL
;
282 Console
->dwSelectionCursor
.X
= ActiveBuffer
->ViewOrigin
.X
;
283 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->ViewOrigin
.Y
;
284 Console
->Selection
.dwSelectionAnchor
= Console
->dwSelectionCursor
;
285 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_IN_PROGRESS
;
286 GuiConsoleUpdateSelection(Console
, &Console
->Selection
.dwSelectionAnchor
);
288 Length
= Console
->Title
.Length
+ sizeof(L
"Mark - ")/sizeof(WCHAR
) + 1;
289 WindowTitle
= ConsoleAllocHeap(0, Length
* sizeof(WCHAR
));
290 wcscpy(WindowTitle
, L
"Mark - ");
291 wcscat(WindowTitle
, Console
->Title
.Buffer
);
292 SetWindowText(GuiData
->hWindow
, WindowTitle
);
293 ConsoleFreeHeap(WindowTitle
);
298 case ID_SYSTEM_EDIT_COPY
:
299 GuiConsoleCopy(GuiData
);
302 case ID_SYSTEM_EDIT_PASTE
:
303 GuiConsolePaste(GuiData
);
306 case ID_SYSTEM_EDIT_SELECTALL
:
308 LPWSTR WindowTitle
= NULL
;
312 * The selection area extends to the whole screen buffer's width.
314 Console
->Selection
.dwSelectionAnchor
.X
= 0;
315 Console
->Selection
.dwSelectionAnchor
.Y
= 0;
316 Console
->dwSelectionCursor
.X
= ActiveBuffer
->ScreenBufferSize
.X
- 1;
319 * Determine whether the selection must extend to just some part
320 * (for text-mode screen buffers) or to all of the screen buffer's
321 * height (for graphics ones).
323 if (GetType(ActiveBuffer
) == TEXTMODE_BUFFER
)
326 * We select all the characters from the first line
327 * to the line where the cursor is positioned.
329 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->CursorPosition
.Y
;
331 else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
334 * We select all the screen buffer area.
336 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->ScreenBufferSize
.Y
- 1;
339 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_IN_PROGRESS
| CONSOLE_MOUSE_SELECTION
;
340 GuiConsoleUpdateSelection(Console
, &Console
->dwSelectionCursor
);
342 Length
= Console
->Title
.Length
+ sizeof(L
"Selection - ")/sizeof(WCHAR
) + 1;
343 WindowTitle
= ConsoleAllocHeap(0, Length
* sizeof(WCHAR
));
344 wcscpy(WindowTitle
, L
"Selection - ");
345 wcscat(WindowTitle
, Console
->Title
.Buffer
);
346 SetWindowText(GuiData
->hWindow
, WindowTitle
);
347 ConsoleFreeHeap(WindowTitle
);
352 case ID_SYSTEM_EDIT_SCROLL
:
353 DPRINT1("Scrolling is not handled yet\n");
356 case ID_SYSTEM_EDIT_FIND
:
357 DPRINT1("Finding is not handled yet\n");
360 case ID_SYSTEM_DEFAULTS
:
361 GuiConsoleShowConsoleProperties(GuiData
, TRUE
);
364 case ID_SYSTEM_PROPERTIES
:
365 GuiConsoleShowConsoleProperties(GuiData
, FALSE
);
374 LeaveCriticalSection(&Console
->Lock
);
377 Ret
= DefWindowProcW(GuiData
->hWindow
, WM_SYSCOMMAND
, wParam
, lParam
);
382 static PGUI_CONSOLE_DATA
383 GuiGetGuiData(HWND hWnd
)
385 /* This function ensures that the console pointer is not NULL */
386 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
387 return ( ((GuiData
== NULL
) || (GuiData
->hWindow
== hWnd
&& GuiData
->Console
!= NULL
)) ? GuiData
: NULL
);
391 GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData
)
393 /* Move the window if needed (not positioned by the system) */
394 if (!GuiData
->GuiInfo
.AutoPosition
)
396 SetWindowPos(GuiData
->hWindow
,
398 GuiData
->GuiInfo
.WindowOrigin
.x
,
399 GuiData
->GuiInfo
.WindowOrigin
.y
,
402 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
407 GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData
, DWORD WidthUnit
, DWORD HeightUnit
)
409 PCONSOLE_SCREEN_BUFFER Buff
= GuiData
->ActiveBuffer
;
414 Width
= Buff
->ViewSize
.X
* WidthUnit
+
415 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
416 Height
= Buff
->ViewSize
.Y
* HeightUnit
+
417 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
419 /* Set scrollbar sizes */
420 sInfo
.cbSize
= sizeof(SCROLLINFO
);
421 sInfo
.fMask
= SIF_RANGE
| SIF_PAGE
| SIF_POS
;
423 if (Buff
->ScreenBufferSize
.Y
> Buff
->ViewSize
.Y
)
425 sInfo
.nMax
= Buff
->ScreenBufferSize
.Y
- 1;
426 sInfo
.nPage
= Buff
->ViewSize
.Y
;
427 sInfo
.nPos
= Buff
->ViewOrigin
.Y
;
428 SetScrollInfo(GuiData
->hWindow
, SB_VERT
, &sInfo
, TRUE
);
429 Width
+= GetSystemMetrics(SM_CXVSCROLL
);
430 ShowScrollBar(GuiData
->hWindow
, SB_VERT
, TRUE
);
434 ShowScrollBar(GuiData
->hWindow
, SB_VERT
, FALSE
);
437 if (Buff
->ScreenBufferSize
.X
> Buff
->ViewSize
.X
)
439 sInfo
.nMax
= Buff
->ScreenBufferSize
.X
- 1;
440 sInfo
.nPage
= Buff
->ViewSize
.X
;
441 sInfo
.nPos
= Buff
->ViewOrigin
.X
;
442 SetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &sInfo
, TRUE
);
443 Height
+= GetSystemMetrics(SM_CYHSCROLL
);
444 ShowScrollBar(GuiData
->hWindow
, SB_HORZ
, TRUE
);
448 ShowScrollBar(GuiData
->hWindow
, SB_HORZ
, FALSE
);
451 /* Resize the window */
452 SetWindowPos(GuiData
->hWindow
, NULL
, 0, 0, Width
, Height
,
453 SWP_NOZORDER
| SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOCOPYBITS
);
454 // NOTE: The SWP_NOCOPYBITS flag can be replaced by a subsequent call
455 // to: InvalidateRect(GuiData->hWindow, NULL, TRUE);
459 GuiConsoleHandleNcCreate(HWND hWnd
, LPCREATESTRUCTW Create
)
461 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)Create
->lpCreateParams
;
468 DPRINT("GuiConsoleHandleNcCreate\n");
472 DPRINT1("GuiConsoleNcCreate: No GUI data\n");
476 Console
= GuiData
->Console
;
478 GuiData
->hWindow
= hWnd
;
480 GuiData
->Font
= CreateFontW(LOWORD(GuiData
->GuiInfo
.FontSize
),
481 0, // HIWORD(GuiData->GuiInfo.FontSize),
484 GuiData
->GuiInfo
.FontWeight
,
491 NONANTIALIASED_QUALITY
,
492 FIXED_PITCH
| GuiData
->GuiInfo
.FontFamily
/* FF_DONTCARE */,
493 GuiData
->GuiInfo
.FaceName
);
495 if (NULL
== GuiData
->Font
)
497 DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
498 GuiData
->hWindow
= NULL
;
499 SetEvent(GuiData
->hGuiInitEvent
);
502 hDC
= GetDC(GuiData
->hWindow
);
505 DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
506 DeleteObject(GuiData
->Font
);
507 GuiData
->hWindow
= NULL
;
508 SetEvent(GuiData
->hGuiInitEvent
);
511 OldFont
= SelectObject(hDC
, GuiData
->Font
);
514 DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
515 ReleaseDC(GuiData
->hWindow
, hDC
);
516 DeleteObject(GuiData
->Font
);
517 GuiData
->hWindow
= NULL
;
518 SetEvent(GuiData
->hGuiInitEvent
);
521 if (!GetTextMetricsW(hDC
, &Metrics
))
523 DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
524 SelectObject(hDC
, OldFont
);
525 ReleaseDC(GuiData
->hWindow
, hDC
);
526 DeleteObject(GuiData
->Font
);
527 GuiData
->hWindow
= NULL
;
528 SetEvent(GuiData
->hGuiInitEvent
);
531 GuiData
->CharWidth
= Metrics
.tmMaxCharWidth
;
532 GuiData
->CharHeight
= Metrics
.tmHeight
+ Metrics
.tmExternalLeading
;
534 /* Measure real char width more precisely if possible. */
535 if (GetTextExtentPoint32W(hDC
, L
"R", 1, &CharSize
))
536 GuiData
->CharWidth
= CharSize
.cx
;
538 SelectObject(hDC
, OldFont
);
540 ReleaseDC(GuiData
->hWindow
, hDC
);
542 /* Initialize the terminal framebuffer */
543 GuiData
->hMemDC
= CreateCompatibleDC(NULL
);
544 GuiData
->hBitmap
= NULL
;
545 GuiData
->hSysPalette
= NULL
; /* Original system palette */
547 // FIXME: Keep these instructions here ? ///////////////////////////////////
548 Console
->ActiveBuffer
->CursorBlinkOn
= TRUE
;
549 Console
->ActiveBuffer
->ForceCursorOff
= FALSE
;
550 ////////////////////////////////////////////////////////////////////////////
552 SetWindowLongPtrW(GuiData
->hWindow
, GWLP_USERDATA
, (DWORD_PTR
)GuiData
);
554 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
555 GuiConsoleCreateSysMenu(GuiData
->hWindow
);
557 DPRINT("GuiConsoleHandleNcCreate - setting start event\n");
558 SetEvent(GuiData
->hGuiInitEvent
);
560 return (BOOL
)DefWindowProcW(GuiData
->hWindow
, WM_NCCREATE
, 0, (LPARAM
)Create
);
564 SmallRectToRect(PGUI_CONSOLE_DATA GuiData
, PRECT Rect
, PSMALL_RECT SmallRect
)
566 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
567 UINT WidthUnit
, HeightUnit
;
569 GetScreenBufferSizeUnits(Buffer
, GuiData
, &WidthUnit
, &HeightUnit
);
571 Rect
->left
= (SmallRect
->Left
- Buffer
->ViewOrigin
.X
) * WidthUnit
;
572 Rect
->top
= (SmallRect
->Top
- Buffer
->ViewOrigin
.Y
) * HeightUnit
;
573 Rect
->right
= (SmallRect
->Right
+ 1 - Buffer
->ViewOrigin
.X
) * WidthUnit
;
574 Rect
->bottom
= (SmallRect
->Bottom
+ 1 - Buffer
->ViewOrigin
.Y
) * HeightUnit
;
578 GuiConsoleUpdateSelection(PCONSOLE Console
, PCOORD coord
)
580 PGUI_CONSOLE_DATA GuiData
= Console
->TermIFace
.Data
;
581 RECT oldRect
, newRect
;
583 SmallRectToRect(GuiData
, &oldRect
, &Console
->Selection
.srSelection
);
588 /* exchange left/top with right/bottom if required */
589 rc
.Left
= min(Console
->Selection
.dwSelectionAnchor
.X
, coord
->X
);
590 rc
.Top
= min(Console
->Selection
.dwSelectionAnchor
.Y
, coord
->Y
);
591 rc
.Right
= max(Console
->Selection
.dwSelectionAnchor
.X
, coord
->X
);
592 rc
.Bottom
= max(Console
->Selection
.dwSelectionAnchor
.Y
, coord
->Y
);
594 SmallRectToRect(GuiData
, &newRect
, &rc
);
596 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
598 if (memcmp(&rc
, &Console
->Selection
.srSelection
, sizeof(SMALL_RECT
)) != 0)
602 /* calculate the region that needs to be updated */
603 if ((rgn1
= CreateRectRgnIndirect(&oldRect
)))
605 if ((rgn2
= CreateRectRgnIndirect(&newRect
)))
607 if (CombineRgn(rgn1
, rgn2
, rgn1
, RGN_XOR
) != ERROR
)
609 InvalidateRgn(GuiData
->hWindow
, rgn1
, FALSE
);
619 InvalidateRect(GuiData
->hWindow
, &newRect
, FALSE
);
621 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_NOT_EMPTY
;
622 Console
->Selection
.srSelection
= rc
;
623 Console
->dwSelectionCursor
= *coord
;
624 ConioPause(Console
, PAUSED_FROM_SELECTION
);
628 /* clear the selection */
629 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
631 InvalidateRect(GuiData
->hWindow
, &oldRect
, FALSE
);
633 Console
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
634 ConioUnpause(Console
, PAUSED_FROM_SELECTION
);
640 GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
,
641 PGUI_CONSOLE_DATA GuiData
,
643 PRECT rcFramebuffer
);
645 GuiPaintGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
,
646 PGUI_CONSOLE_DATA GuiData
,
648 PRECT rcFramebuffer
);
651 GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData
)
654 PCONSOLE Console
= GuiData
->Console
;
655 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
659 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
664 ActiveBuffer
= GuiData
->ActiveBuffer
;
666 BeginPaint(GuiData
->hWindow
, &ps
);
667 if (ps
.hdc
!= NULL
&&
668 ps
.rcPaint
.left
< ps
.rcPaint
.right
&&
669 ps
.rcPaint
.top
< ps
.rcPaint
.bottom
)
671 EnterCriticalSection(&GuiData
->Lock
);
673 /* Compose the current screen-buffer on-memory */
674 if (GetType(ActiveBuffer
) == TEXTMODE_BUFFER
)
676 GuiPaintTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)ActiveBuffer
,
677 GuiData
, &ps
.rcPaint
, &rcPaint
);
679 else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
681 GuiPaintGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)ActiveBuffer
,
682 GuiData
, &ps
.rcPaint
, &rcPaint
);
685 /* Send it to screen */
689 rcPaint
.right
- rcPaint
.left
,
690 rcPaint
.bottom
- rcPaint
.top
,
696 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
698 SmallRectToRect(GuiData
, &rcPaint
, &Console
->Selection
.srSelection
);
700 /* Invert the selection */
701 if (IntersectRect(&rcPaint
, &ps
.rcPaint
, &rcPaint
))
703 InvertRect(ps
.hdc
, &rcPaint
);
707 LeaveCriticalSection(&GuiData
->Lock
);
709 EndPaint(GuiData
->hWindow
, &ps
);
713 LeaveCriticalSection(&Console
->Lock
);
715 DefWindowProcW(GuiData
->hWindow
, WM_PAINT
, 0, 0);
721 IsSystemKey(WORD VirtualKeyCode
)
723 switch (VirtualKeyCode
)
725 /* From MSDN, "Virtual-Key Codes" */
744 GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
746 PCONSOLE Console
= GuiData
->Console
;
747 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
749 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
751 ActiveBuffer
= GuiData
->ActiveBuffer
;
753 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
)
755 WORD VirtualKeyCode
= LOWORD(wParam
);
757 if (msg
!= WM_KEYDOWN
) goto Quit
;
759 if (VirtualKeyCode
== VK_RETURN
)
761 /* Copy (and clear) selection if ENTER is pressed */
762 GuiConsoleCopy(GuiData
);
765 else if ( VirtualKeyCode
== VK_ESCAPE
||
766 (VirtualKeyCode
== 'C' && GetKeyState(VK_CONTROL
) & 0x8000) )
768 /* Cancel selection if ESC or Ctrl-C are pressed */
769 GuiConsoleUpdateSelection(Console
, NULL
);
770 SetWindowText(GuiData
->hWindow
, Console
->Title
.Buffer
);
775 if ((Console
->Selection
.dwFlags
& CONSOLE_MOUSE_SELECTION
) == 0)
777 /* Keyboard selection mode */
778 BOOL Interpreted
= FALSE
;
779 BOOL MajPressed
= (GetKeyState(VK_SHIFT
) & 0x8000);
781 switch (VirtualKeyCode
)
786 if (Console
->dwSelectionCursor
.X
> 0)
787 Console
->dwSelectionCursor
.X
--;
795 if (Console
->dwSelectionCursor
.X
< ActiveBuffer
->ScreenBufferSize
.X
- 1)
796 Console
->dwSelectionCursor
.X
++;
804 if (Console
->dwSelectionCursor
.Y
> 0)
805 Console
->dwSelectionCursor
.Y
--;
813 if (Console
->dwSelectionCursor
.Y
< ActiveBuffer
->ScreenBufferSize
.Y
- 1)
814 Console
->dwSelectionCursor
.Y
++;
822 Console
->dwSelectionCursor
.X
= 0;
823 Console
->dwSelectionCursor
.Y
= 0;
830 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->ScreenBufferSize
.Y
- 1;
837 Console
->dwSelectionCursor
.Y
-= ActiveBuffer
->ViewSize
.Y
;
838 if (Console
->dwSelectionCursor
.Y
< 0)
839 Console
->dwSelectionCursor
.Y
= 0;
847 Console
->dwSelectionCursor
.Y
+= ActiveBuffer
->ViewSize
.Y
;
848 if (Console
->dwSelectionCursor
.Y
>= ActiveBuffer
->ScreenBufferSize
.Y
)
849 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->ScreenBufferSize
.Y
- 1;
861 Console
->Selection
.dwSelectionAnchor
= Console
->dwSelectionCursor
;
863 GuiConsoleUpdateSelection(Console
, &Console
->dwSelectionCursor
);
865 else if (!IsSystemKey(VirtualKeyCode
))
867 /* Emit an error beep sound */
868 SendNotifyMessage(GuiData
->hWindow
, PM_CONSOLE_BEEP
, 0, 0);
875 /* Mouse selection mode */
877 if (!IsSystemKey(VirtualKeyCode
))
879 /* Clear the selection and send the key into the input buffer */
880 GuiConsoleUpdateSelection(Console
, NULL
);
881 SetWindowText(GuiData
->hWindow
, Console
->Title
.Buffer
);
890 if ((Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) == 0)
894 Message
.hwnd
= GuiData
->hWindow
;
895 Message
.message
= msg
;
896 Message
.wParam
= wParam
;
897 Message
.lParam
= lParam
;
899 ConioProcessKey(Console
, &Message
);
903 LeaveCriticalSection(&Console
->Lock
);
907 GuiInvalidateCell(IN OUT PFRONTEND This
, SHORT x
, SHORT y
)
909 SMALL_RECT CellRect
= { x
, y
, x
, y
};
910 GuiDrawRegion(This
, &CellRect
);
914 GuiConsoleHandleTimer(PGUI_CONSOLE_DATA GuiData
)
916 PCONSOLE Console
= GuiData
->Console
;
917 PCONSOLE_SCREEN_BUFFER Buff
;
919 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CURSOR_BLINK_TIME
, NULL
);
921 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
923 Buff
= GuiData
->ActiveBuffer
;
925 if (GetType(Buff
) == TEXTMODE_BUFFER
)
927 GuiInvalidateCell(&Console
->TermIFace
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
928 Buff
->CursorBlinkOn
= !Buff
->CursorBlinkOn
;
930 if ((GuiData
->OldCursor
.x
!= Buff
->CursorPosition
.X
) ||
931 (GuiData
->OldCursor
.y
!= Buff
->CursorPosition
.Y
))
934 int OldScrollX
= -1, OldScrollY
= -1;
935 int NewScrollX
= -1, NewScrollY
= -1;
937 xScroll
.cbSize
= sizeof(SCROLLINFO
);
938 xScroll
.fMask
= SIF_POS
;
939 // Capture the original position of the scroll bars and save them.
940 if (GetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &xScroll
)) OldScrollX
= xScroll
.nPos
;
941 if (GetScrollInfo(GuiData
->hWindow
, SB_VERT
, &xScroll
)) OldScrollY
= xScroll
.nPos
;
943 // If we successfully got the info for the horizontal scrollbar
946 if ((Buff
->CursorPosition
.X
< Buff
->ViewOrigin
.X
) ||
947 (Buff
->CursorPosition
.X
>= (Buff
->ViewOrigin
.X
+ Buff
->ViewSize
.X
)))
949 // Handle the horizontal scroll bar
950 if (Buff
->CursorPosition
.X
>= Buff
->ViewSize
.X
)
951 NewScrollX
= Buff
->CursorPosition
.X
- Buff
->ViewSize
.X
+ 1;
957 NewScrollX
= OldScrollX
;
960 // If we successfully got the info for the vertical scrollbar
963 if ((Buff
->CursorPosition
.Y
< Buff
->ViewOrigin
.Y
) ||
964 (Buff
->CursorPosition
.Y
>= (Buff
->ViewOrigin
.Y
+ Buff
->ViewSize
.Y
)))
966 // Handle the vertical scroll bar
967 if (Buff
->CursorPosition
.Y
>= Buff
->ViewSize
.Y
)
968 NewScrollY
= Buff
->CursorPosition
.Y
- Buff
->ViewSize
.Y
+ 1;
974 NewScrollY
= OldScrollY
;
978 // Adjust scroll bars and refresh the window if the cursor has moved outside the visible area
979 // NOTE: OldScroll# and NewScroll# will both be -1 (initial value) if the info for the respective scrollbar
980 // was not obtained successfully in the previous steps. This means their difference is 0 (no scrolling)
981 // and their associated scrollbar is left alone.
982 if ((OldScrollX
!= NewScrollX
) || (OldScrollY
!= NewScrollY
))
984 Buff
->ViewOrigin
.X
= NewScrollX
;
985 Buff
->ViewOrigin
.Y
= NewScrollY
;
986 ScrollWindowEx(GuiData
->hWindow
,
987 (OldScrollX
- NewScrollX
) * GuiData
->CharWidth
,
988 (OldScrollY
- NewScrollY
) * GuiData
->CharHeight
,
996 xScroll
.nPos
= NewScrollX
;
997 SetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &xScroll
, TRUE
);
1001 xScroll
.nPos
= NewScrollY
;
1002 SetScrollInfo(GuiData
->hWindow
, SB_VERT
, &xScroll
, TRUE
);
1004 UpdateWindow(GuiData
->hWindow
);
1005 // InvalidateRect(GuiData->hWindow, NULL, FALSE);
1006 GuiData
->OldCursor
.x
= Buff
->CursorPosition
.X
;
1007 GuiData
->OldCursor
.y
= Buff
->CursorPosition
.Y
;
1011 else /* if (GetType(Buff) == GRAPHICS_BUFFER) */
1015 LeaveCriticalSection(&Console
->Lock
);
1019 GuiConsoleHandleClose(PGUI_CONSOLE_DATA GuiData
)
1021 PCONSOLE Console
= GuiData
->Console
;
1023 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1026 // TODO: Prompt for termination ? (Warn the user about possible apps running in this console)
1029 * FIXME: Windows will wait up to 5 seconds for the thread to exit.
1030 * We shouldn't wait here, though, since the console lock is entered.
1031 * A copy of the thread list probably needs to be made.
1033 ConDrvConsoleProcessCtrlEvent(Console
, 0, CTRL_CLOSE_EVENT
);
1035 LeaveCriticalSection(&Console
->Lock
);
1040 GuiConsoleHandleNcDestroy(HWND hWnd
)
1042 PGUI_CONSOLE_DATA GuiData
= GuiGetGuiData(hWnd
);
1044 KillTimer(hWnd
, CONGUI_UPDATE_TIMER
);
1045 GetSystemMenu(hWnd
, TRUE
);
1049 /* Free the terminal framebuffer */
1050 if (GuiData
->hMemDC
) DeleteDC(GuiData
->hMemDC
);
1051 if (GuiData
->hBitmap
) DeleteObject(GuiData
->hBitmap
);
1052 // if (GuiData->hSysPalette) DeleteObject(GuiData->hSysPalette);
1053 if (GuiData
->Font
) DeleteObject(GuiData
->Font
);
1056 /* Free the GuiData registration */
1057 SetWindowLongPtrW(hWnd
, GWLP_USERDATA
, (DWORD_PTR
)NULL
);
1059 return DefWindowProcW(hWnd
, WM_NCDESTROY
, 0, 0);
1063 PointToCoord(PGUI_CONSOLE_DATA GuiData
, LPARAM lParam
)
1065 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
1067 UINT WidthUnit
, HeightUnit
;
1069 GetScreenBufferSizeUnits(Buffer
, GuiData
, &WidthUnit
, &HeightUnit
);
1071 Coord
.X
= Buffer
->ViewOrigin
.X
+ ((SHORT
)LOWORD(lParam
) / (int)WidthUnit
);
1072 Coord
.Y
= Buffer
->ViewOrigin
.Y
+ ((SHORT
)HIWORD(lParam
) / (int)HeightUnit
);
1074 /* Clip coordinate to ensure it's inside buffer */
1077 else if (Coord
.X
>= Buffer
->ScreenBufferSize
.X
)
1078 Coord
.X
= Buffer
->ScreenBufferSize
.X
- 1;
1082 else if (Coord
.Y
>= Buffer
->ScreenBufferSize
.Y
)
1083 Coord
.Y
= Buffer
->ScreenBufferSize
.Y
- 1;
1089 GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1092 PCONSOLE Console
= GuiData
->Console
;
1094 if (GuiData
->IgnoreNextMouseSignal
)
1096 if (msg
!= WM_LBUTTONDOWN
&&
1097 msg
!= WM_MBUTTONDOWN
&&
1098 msg
!= WM_RBUTTONDOWN
)
1101 * If this mouse signal is not a button-down action,
1102 * then it is the last signal being ignored.
1104 GuiData
->IgnoreNextMouseSignal
= FALSE
;
1109 * This mouse signal is a button-down action.
1110 * Ignore it and perform default action.
1117 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1123 if ( (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) ||
1124 (Console
->QuickEdit
) )
1128 case WM_LBUTTONDOWN
:
1130 LPWSTR WindowTitle
= NULL
;
1133 Console
->Selection
.dwSelectionAnchor
= PointToCoord(GuiData
, lParam
);
1134 SetCapture(GuiData
->hWindow
);
1135 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_IN_PROGRESS
| CONSOLE_MOUSE_SELECTION
| CONSOLE_MOUSE_DOWN
;
1136 GuiConsoleUpdateSelection(Console
, &Console
->Selection
.dwSelectionAnchor
);
1138 Length
= Console
->Title
.Length
+ sizeof(L
"Selection - ")/sizeof(WCHAR
) + 1;
1139 WindowTitle
= ConsoleAllocHeap(0, Length
* sizeof(WCHAR
));
1140 wcscpy(WindowTitle
, L
"Selection - ");
1141 wcscat(WindowTitle
, Console
->Title
.Buffer
);
1142 SetWindowText(GuiData
->hWindow
, WindowTitle
);
1143 ConsoleFreeHeap(WindowTitle
);
1152 if (!(Console
->Selection
.dwFlags
& CONSOLE_MOUSE_DOWN
)) break;
1154 c
= PointToCoord(GuiData
, lParam
);
1155 Console
->Selection
.dwFlags
&= ~CONSOLE_MOUSE_DOWN
;
1156 GuiConsoleUpdateSelection(Console
, &c
);
1162 case WM_LBUTTONDBLCLK
:
1164 DPRINT1("Handle left-double-click for selecting a word\n");
1168 case WM_RBUTTONDOWN
:
1169 case WM_RBUTTONDBLCLK
:
1171 if (!(Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
))
1173 GuiConsolePaste(GuiData
);
1177 GuiConsoleCopy(GuiData
);
1180 GuiData
->IgnoreNextMouseSignal
= TRUE
;
1188 if (!(wParam
& MK_LBUTTON
)) break;
1189 if (!(Console
->Selection
.dwFlags
& CONSOLE_MOUSE_DOWN
)) break;
1191 c
= PointToCoord(GuiData
, lParam
); /* TODO: Scroll buffer to bring c into view */
1192 GuiConsoleUpdateSelection(Console
, &c
);
1198 Err
= FALSE
; // TRUE;
1202 else if (Console
->InputBuffer
.Mode
& ENABLE_MOUSE_INPUT
)
1205 WORD wKeyState
= GET_KEYSTATE_WPARAM(wParam
);
1206 DWORD dwButtonState
= 0;
1207 DWORD dwControlKeyState
= 0;
1208 DWORD dwEventFlags
= 0;
1212 case WM_LBUTTONDOWN
:
1213 SetCapture(GuiData
->hWindow
);
1214 dwButtonState
= FROM_LEFT_1ST_BUTTON_PRESSED
;
1218 case WM_MBUTTONDOWN
:
1219 SetCapture(GuiData
->hWindow
);
1220 dwButtonState
= FROM_LEFT_2ND_BUTTON_PRESSED
;
1224 case WM_RBUTTONDOWN
:
1225 SetCapture(GuiData
->hWindow
);
1226 dwButtonState
= RIGHTMOST_BUTTON_PRESSED
;
1248 case WM_LBUTTONDBLCLK
:
1249 dwButtonState
= FROM_LEFT_1ST_BUTTON_PRESSED
;
1250 dwEventFlags
= DOUBLE_CLICK
;
1253 case WM_MBUTTONDBLCLK
:
1254 dwButtonState
= FROM_LEFT_2ND_BUTTON_PRESSED
;
1255 dwEventFlags
= DOUBLE_CLICK
;
1258 case WM_RBUTTONDBLCLK
:
1259 dwButtonState
= RIGHTMOST_BUTTON_PRESSED
;
1260 dwEventFlags
= DOUBLE_CLICK
;
1265 dwEventFlags
= MOUSE_MOVED
;
1269 dwButtonState
= GET_WHEEL_DELTA_WPARAM(wParam
) << 16;
1270 dwEventFlags
= MOUSE_WHEELED
;
1273 case WM_MOUSEHWHEEL
:
1274 dwButtonState
= GET_WHEEL_DELTA_WPARAM(wParam
) << 16;
1275 dwEventFlags
= MOUSE_HWHEELED
;
1285 if (wKeyState
& MK_LBUTTON
)
1286 dwButtonState
|= FROM_LEFT_1ST_BUTTON_PRESSED
;
1287 if (wKeyState
& MK_MBUTTON
)
1288 dwButtonState
|= FROM_LEFT_2ND_BUTTON_PRESSED
;
1289 if (wKeyState
& MK_RBUTTON
)
1290 dwButtonState
|= RIGHTMOST_BUTTON_PRESSED
;
1292 if (GetKeyState(VK_RMENU
) & 0x8000)
1293 dwControlKeyState
|= RIGHT_ALT_PRESSED
;
1294 if (GetKeyState(VK_LMENU
) & 0x8000)
1295 dwControlKeyState
|= LEFT_ALT_PRESSED
;
1296 if (GetKeyState(VK_RCONTROL
) & 0x8000)
1297 dwControlKeyState
|= RIGHT_CTRL_PRESSED
;
1298 if (GetKeyState(VK_LCONTROL
) & 0x8000)
1299 dwControlKeyState
|= LEFT_CTRL_PRESSED
;
1300 if (GetKeyState(VK_SHIFT
) & 0x8000)
1301 dwControlKeyState
|= SHIFT_PRESSED
;
1302 if (GetKeyState(VK_NUMLOCK
) & 0x0001)
1303 dwControlKeyState
|= NUMLOCK_ON
;
1304 if (GetKeyState(VK_SCROLL
) & 0x0001)
1305 dwControlKeyState
|= SCROLLLOCK_ON
;
1306 if (GetKeyState(VK_CAPITAL
) & 0x0001)
1307 dwControlKeyState
|= CAPSLOCK_ON
;
1308 /* See WM_CHAR MSDN documentation for instance */
1309 if (lParam
& 0x01000000)
1310 dwControlKeyState
|= ENHANCED_KEY
;
1312 er
.EventType
= MOUSE_EVENT
;
1313 er
.Event
.MouseEvent
.dwMousePosition
= PointToCoord(GuiData
, lParam
);
1314 er
.Event
.MouseEvent
.dwButtonState
= dwButtonState
;
1315 er
.Event
.MouseEvent
.dwControlKeyState
= dwControlKeyState
;
1316 er
.Event
.MouseEvent
.dwEventFlags
= dwEventFlags
;
1318 ConioProcessInputEvent(Console
, &er
);
1326 LeaveCriticalSection(&Console
->Lock
);
1330 return DefWindowProcW(GuiData
->hWindow
, msg
, wParam
, lParam
);
1335 VOID
GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
);
1336 VOID
GuiCopyFromGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
);
1339 GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData
)
1341 if (OpenClipboard(GuiData
->hWindow
) == TRUE
)
1343 PCONSOLE Console
= GuiData
->Console
;
1344 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
1346 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
1348 GuiCopyFromTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)Buffer
);
1350 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
1352 GuiCopyFromGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)Buffer
);
1357 /* Clear the selection */
1358 GuiConsoleUpdateSelection(Console
, NULL
);
1359 SetWindowText(GuiData
->hWindow
, Console
->Title
.Buffer
);
1363 VOID
GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
);
1364 VOID
GuiPasteToGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
);
1367 GuiConsolePaste(PGUI_CONSOLE_DATA GuiData
)
1369 if (OpenClipboard(GuiData
->hWindow
) == TRUE
)
1371 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
1373 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
1375 GuiPasteToTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)Buffer
);
1377 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
1379 GuiPasteToGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)Buffer
);
1387 GuiConsoleGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData
, PMINMAXINFO minMaxInfo
)
1389 PCONSOLE Console
= GuiData
->Console
;
1390 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
1392 UINT WidthUnit
, HeightUnit
;
1394 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
1396 ActiveBuffer
= GuiData
->ActiveBuffer
;
1398 GetScreenBufferSizeUnits(ActiveBuffer
, GuiData
, &WidthUnit
, &HeightUnit
);
1400 windx
= CONGUI_MIN_WIDTH
* WidthUnit
+ 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
1401 windy
= CONGUI_MIN_HEIGHT
* HeightUnit
+ 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
1403 minMaxInfo
->ptMinTrackSize
.x
= windx
;
1404 minMaxInfo
->ptMinTrackSize
.y
= windy
;
1406 windx
= (ActiveBuffer
->ScreenBufferSize
.X
) * WidthUnit
+ 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
1407 windy
= (ActiveBuffer
->ScreenBufferSize
.Y
) * HeightUnit
+ 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
1409 if (ActiveBuffer
->ViewSize
.X
< ActiveBuffer
->ScreenBufferSize
.X
) windy
+= GetSystemMetrics(SM_CYHSCROLL
); // window currently has a horizontal scrollbar
1410 if (ActiveBuffer
->ViewSize
.Y
< ActiveBuffer
->ScreenBufferSize
.Y
) windx
+= GetSystemMetrics(SM_CXVSCROLL
); // window currently has a vertical scrollbar
1412 minMaxInfo
->ptMaxTrackSize
.x
= windx
;
1413 minMaxInfo
->ptMaxTrackSize
.y
= windy
;
1415 LeaveCriticalSection(&Console
->Lock
);
1419 GuiConsoleResize(PGUI_CONSOLE_DATA GuiData
, WPARAM wParam
, LPARAM lParam
)
1421 PCONSOLE Console
= GuiData
->Console
;
1423 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
1425 if ((GuiData
->WindowSizeLock
== FALSE
) &&
1426 (wParam
== SIZE_RESTORED
|| wParam
== SIZE_MAXIMIZED
|| wParam
== SIZE_MINIMIZED
))
1428 PCONSOLE_SCREEN_BUFFER Buff
= GuiData
->ActiveBuffer
;
1429 DWORD windx
, windy
, charx
, chary
;
1430 UINT WidthUnit
, HeightUnit
;
1432 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
1434 GuiData
->WindowSizeLock
= TRUE
;
1436 windx
= LOWORD(lParam
);
1437 windy
= HIWORD(lParam
);
1439 // Compensate for existing scroll bars (because lParam values do not accommodate scroll bar)
1440 if (Buff
->ViewSize
.X
< Buff
->ScreenBufferSize
.X
) windy
+= GetSystemMetrics(SM_CYHSCROLL
); // window currently has a horizontal scrollbar
1441 if (Buff
->ViewSize
.Y
< Buff
->ScreenBufferSize
.Y
) windx
+= GetSystemMetrics(SM_CXVSCROLL
); // window currently has a vertical scrollbar
1443 charx
= windx
/ (int)WidthUnit
;
1444 chary
= windy
/ (int)HeightUnit
;
1446 // Character alignment (round size up or down)
1447 if ((windx
% WidthUnit
) >= (WidthUnit
/ 2)) ++charx
;
1448 if ((windy
% HeightUnit
) >= (HeightUnit
/ 2)) ++chary
;
1450 // Compensate for added scroll bars in new window
1451 if (charx
< Buff
->ScreenBufferSize
.X
) windy
-= GetSystemMetrics(SM_CYHSCROLL
); // new window will have a horizontal scroll bar
1452 if (chary
< Buff
->ScreenBufferSize
.Y
) windx
-= GetSystemMetrics(SM_CXVSCROLL
); // new window will have a vertical scroll bar
1454 charx
= windx
/ (int)WidthUnit
;
1455 chary
= windy
/ (int)HeightUnit
;
1457 // Character alignment (round size up or down)
1458 if ((windx
% WidthUnit
) >= (WidthUnit
/ 2)) ++charx
;
1459 if ((windy
% HeightUnit
) >= (HeightUnit
/ 2)) ++chary
;
1462 if ((charx
!= Buff
->ViewSize
.X
) || (chary
!= Buff
->ViewSize
.Y
))
1464 Buff
->ViewSize
.X
= (charx
<= Buff
->ScreenBufferSize
.X
) ? charx
: Buff
->ScreenBufferSize
.X
;
1465 Buff
->ViewSize
.Y
= (chary
<= Buff
->ScreenBufferSize
.Y
) ? chary
: Buff
->ScreenBufferSize
.Y
;
1468 GuiConsoleResizeWindow(GuiData
, WidthUnit
, HeightUnit
);
1470 // Adjust the start of the visible area if we are attempting to show nonexistent areas
1471 if ((Buff
->ScreenBufferSize
.X
- Buff
->ViewOrigin
.X
) < Buff
->ViewSize
.X
) Buff
->ViewOrigin
.X
= Buff
->ScreenBufferSize
.X
- Buff
->ViewSize
.X
;
1472 if ((Buff
->ScreenBufferSize
.Y
- Buff
->ViewOrigin
.Y
) < Buff
->ViewSize
.Y
) Buff
->ViewOrigin
.Y
= Buff
->ScreenBufferSize
.Y
- Buff
->ViewSize
.Y
;
1473 InvalidateRect(GuiData
->hWindow
, NULL
, TRUE
);
1475 GuiData
->WindowSizeLock
= FALSE
;
1478 LeaveCriticalSection(&Console
->Lock
);
1482 // HACK: This functionality is standard for general scrollbars. Don't add it by hand.
1486 GuiConsoleHandleScrollbarMenu(VOID)
1490 hMenu = CreatePopupMenu();
1493 DPRINT("CreatePopupMenu failed\n");
1497 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLHERE);
1498 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1499 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLTOP);
1500 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLBOTTOM);
1501 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1502 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_UP);
1503 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_DOWN);
1504 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1505 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLUP);
1506 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLDOWN);
1511 GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData
, UINT uMsg
, WPARAM wParam
)
1513 PCONSOLE Console
= GuiData
->Console
;
1514 PCONSOLE_SCREEN_BUFFER Buff
;
1517 int old_pos
, Maximum
;
1520 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return 0;
1522 Buff
= GuiData
->ActiveBuffer
;
1524 if (uMsg
== WM_HSCROLL
)
1527 Maximum
= Buff
->ScreenBufferSize
.X
- Buff
->ViewSize
.X
;
1528 pShowXY
= &Buff
->ViewOrigin
.X
;
1533 Maximum
= Buff
->ScreenBufferSize
.Y
- Buff
->ViewSize
.Y
;
1534 pShowXY
= &Buff
->ViewOrigin
.Y
;
1537 /* set scrollbar sizes */
1538 sInfo
.cbSize
= sizeof(SCROLLINFO
);
1539 sInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
| SIF_TRACKPOS
;
1541 if (!GetScrollInfo(GuiData
->hWindow
, fnBar
, &sInfo
)) goto Quit
;
1543 old_pos
= sInfo
.nPos
;
1545 switch (LOWORD(wParam
))
1556 sInfo
.nPos
-= sInfo
.nPage
;
1560 sInfo
.nPos
+= sInfo
.nPage
;
1564 sInfo
.nPos
= sInfo
.nTrackPos
;
1565 ConioPause(Console
, PAUSED_FROM_SCROLLBAR
);
1568 case SB_THUMBPOSITION
:
1569 ConioUnpause(Console
, PAUSED_FROM_SCROLLBAR
);
1573 sInfo
.nPos
= sInfo
.nMin
;
1577 sInfo
.nPos
= sInfo
.nMax
;
1584 sInfo
.nPos
= max(sInfo
.nPos
, 0);
1585 sInfo
.nPos
= min(sInfo
.nPos
, Maximum
);
1587 if (old_pos
!= sInfo
.nPos
)
1589 USHORT OldX
= Buff
->ViewOrigin
.X
;
1590 USHORT OldY
= Buff
->ViewOrigin
.Y
;
1591 UINT WidthUnit
, HeightUnit
;
1593 *pShowXY
= sInfo
.nPos
;
1595 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
1597 ScrollWindowEx(GuiData
->hWindow
,
1598 (OldX
- Buff
->ViewOrigin
.X
) * WidthUnit
,
1599 (OldY
- Buff
->ViewOrigin
.Y
) * HeightUnit
,
1606 sInfo
.fMask
= SIF_POS
;
1607 SetScrollInfo(GuiData
->hWindow
, fnBar
, &sInfo
, TRUE
);
1609 UpdateWindow(GuiData
->hWindow
);
1610 // InvalidateRect(GuiData->hWindow, NULL, FALSE);
1614 LeaveCriticalSection(&Console
->Lock
);
1620 EnterFullScreen(PGUI_CONSOLE_DATA GuiData
);
1622 LeaveFullScreen(PGUI_CONSOLE_DATA GuiData
);
1624 SwitchFullScreen(PGUI_CONSOLE_DATA GuiData
, BOOL FullScreen
);
1626 GuiConsoleSwitchFullScreen(PGUI_CONSOLE_DATA GuiData
);
1628 static LRESULT CALLBACK
1629 GuiConsoleWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1632 PGUI_CONSOLE_DATA GuiData
= NULL
;
1633 PCONSOLE Console
= NULL
;
1636 * - If it's the first time we create a window for the terminal,
1637 * just initialize it and return.
1639 * - If we are destroying the window, just do it and return.
1641 if (msg
== WM_NCCREATE
)
1643 return (LRESULT
)GuiConsoleHandleNcCreate(hWnd
, (LPCREATESTRUCTW
)lParam
);
1645 else if (msg
== WM_NCDESTROY
)
1647 return GuiConsoleHandleNcDestroy(hWnd
);
1651 * Now the terminal window is initialized.
1652 * Get the terminal data via the window's data.
1653 * If there is no data, just go away.
1655 GuiData
= GuiGetGuiData(hWnd
);
1656 if (GuiData
== NULL
) return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1658 // TEMPORARY HACK until all of the functions can deal with a NULL GuiData->ActiveBuffer ...
1659 if (GuiData
->ActiveBuffer
== NULL
) return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1662 * Just retrieve a pointer to the console in case somebody needs it.
1663 * It is not NULL because it was checked in GuiGetGuiData.
1664 * Each helper function which needs the console has to validate and lock it.
1666 Console
= GuiData
->Console
;
1668 /* We have a console, start message dispatching */
1673 WORD ActivationState
= LOWORD(wParam
);
1675 DPRINT1("WM_ACTIVATE - ActivationState = %d\n");
1677 if ( ActivationState
== WA_ACTIVE
||
1678 ActivationState
== WA_CLICKACTIVE
)
1680 if (GuiData
->GuiInfo
.FullScreen
)
1682 EnterFullScreen(GuiData
);
1683 // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
1684 // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
1687 else // if (ActivationState == WA_INACTIVE)
1689 if (GuiData
->GuiInfo
.FullScreen
)
1691 SendMessageW(GuiData
->hWindow
, WM_SYSCOMMAND
, SC_MINIMIZE
, 0);
1692 LeaveFullScreen(GuiData
);
1693 // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
1694 // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
1698 if (ActivationState
== WA_CLICKACTIVE
) GuiData
->IgnoreNextMouseSignal
= TRUE
;
1704 if (GuiConsoleHandleClose(GuiData
)) goto Default
;
1708 GuiConsoleHandlePaint(GuiData
);
1711 case WM_PALETTECHANGED
:
1713 PCONSOLE_SCREEN_BUFFER ActiveBuffer
= GuiData
->ActiveBuffer
;
1715 DPRINT1("WM_PALETTECHANGED called\n");
1718 * Protects against infinite loops:
1719 * "... A window that receives this message must not realize
1720 * its palette, unless it determines that wParam does not contain
1721 * its own window handle." (WM_PALETTECHANGED description - MSDN)
1723 * This message is sent to all windows, including the one that
1724 * changed the system palette and caused this message to be sent.
1725 * The wParam of this message contains the handle of the window
1726 * that caused the system palette to change. To avoid an infinite
1727 * loop, care must be taken to check that the wParam of this message
1728 * does not match the window's handle.
1730 if ((HWND
)wParam
== hWnd
) break;
1732 DPRINT1("WM_PALETTECHANGED ok\n");
1734 // if (GetType(ActiveBuffer) == GRAPHICS_BUFFER)
1735 if (ActiveBuffer
->PaletteHandle
)
1737 DPRINT1("WM_PALETTECHANGED changing palette\n");
1739 /* Specify the use of the system palette for the framebuffer */
1740 SetSystemPaletteUse(GuiData
->hMemDC
, ActiveBuffer
->PaletteUsage
);
1742 /* Realize the (logical) palette */
1743 RealizePalette(GuiData
->hMemDC
);
1746 DPRINT1("WM_PALETTECHANGED quit\n");
1758 case WM_SYSDEADCHAR
:
1760 /* Detect Alt-Enter presses and switch back and forth to fullscreen mode */
1761 if (msg
== WM_SYSKEYDOWN
&& (HIWORD(lParam
) & KF_ALTDOWN
) && wParam
== VK_RETURN
)
1763 /* Switch only at first Alt-Enter press, and ignore subsequent key repetitions */
1764 if ((HIWORD(lParam
) & (KF_UP
| KF_REPEAT
)) != KF_REPEAT
)
1765 GuiConsoleSwitchFullScreen(GuiData
);
1770 GuiConsoleHandleKey(GuiData
, msg
, wParam
, lParam
);
1775 GuiConsoleHandleTimer(GuiData
);
1781 * The message was sent because we are manually triggering a change.
1782 * Check whether the mouse is indeed present on this console window
1783 * and take appropriate decisions.
1785 if (wParam
== -1 && lParam
== -1)
1790 /* Get the placement of the mouse */
1791 GetCursorPos(&mouseCoords
);
1793 /* On which window is placed the mouse ? */
1794 hWndHit
= WindowFromPoint(mouseCoords
);
1796 /* It's our window. Perform the hit-test to be used later on. */
1797 if (hWndHit
== hWnd
)
1799 wParam
= (WPARAM
)hWnd
;
1800 lParam
= DefWindowProcW(hWndHit
, WM_NCHITTEST
, 0,
1801 MAKELPARAM(mouseCoords
.x
, mouseCoords
.y
));
1805 /* Set the mouse cursor only when we are in the client area */
1806 if ((HWND
)wParam
== hWnd
&& LOWORD(lParam
) == HTCLIENT
)
1808 if (GuiData
->MouseCursorRefCount
>= 0)
1810 /* Show the cursor */
1811 SetCursor(GuiData
->hCursor
);
1815 /* Hide the cursor if the reference count is negative */
1826 case WM_LBUTTONDOWN
:
1827 case WM_MBUTTONDOWN
:
1828 case WM_RBUTTONDOWN
:
1832 case WM_LBUTTONDBLCLK
:
1833 case WM_MBUTTONDBLCLK
:
1834 case WM_RBUTTONDBLCLK
:
1837 case WM_MOUSEHWHEEL
:
1839 Result
= GuiConsoleHandleMouse(GuiData
, msg
, wParam
, lParam
);
1846 Result
= GuiConsoleHandleScroll(GuiData
, msg
, wParam
);
1850 case WM_NCRBUTTONDOWN
:
1852 DPRINT1("WM_NCRBUTTONDOWN\n");
1854 * HACK: !! Because, when we deal with WM_RBUTTON* and we do not
1855 * call after that DefWindowProc, on ReactOS, right-clicks on the
1856 * (non-client) application title-bar does not display the system
1857 * menu and does not trigger a WM_NCRBUTTONUP message too.
1858 * See: http://git.reactos.org/?p=reactos.git;a=blob;f=reactos/win32ss/user/user32/windows/defwnd.c;hb=332bc8f482f40fd05ab510f78276576719fbfba8#l1103
1859 * and line 1135 too.
1862 if (DefWindowProcW(hWnd
, WM_NCHITTEST
, 0, lParam
) == HTCAPTION
)
1864 /* Call DefWindowProcW with the WM_CONTEXTMENU message */
1865 msg
= WM_CONTEXTMENU
;
1870 // case WM_NCRBUTTONUP:
1871 // DPRINT1("WM_NCRBUTTONUP\n");
1874 case WM_CONTEXTMENU
:
1876 if (DefWindowProcW(hWnd
/*GuiData->hWindow*/, WM_NCHITTEST
, 0, lParam
) == HTCLIENT
)
1878 HMENU hMenu
= CreatePopupMenu();
1881 GuiConsoleAppendMenuItems(hMenu
, GuiConsoleEditMenuItems
);
1882 TrackPopupMenuEx(hMenu
,
1884 GET_X_LPARAM(lParam
),
1885 GET_Y_LPARAM(lParam
),
1900 HMENU hMenu
= (HMENU
)wParam
;
1903 /* Enable or disable the Close menu item */
1904 EnableMenuItem(hMenu
, SC_CLOSE
, MF_BYCOMMAND
|
1905 (GuiData
->IsCloseButtonEnabled
? MF_ENABLED
: MF_GRAYED
));
1907 /* Enable or disable the Copy and Paste items */
1908 EnableMenuItem(hMenu
, ID_SYSTEM_EDIT_COPY
, MF_BYCOMMAND
|
1909 ((Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) &&
1910 (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
) ? MF_ENABLED
: MF_GRAYED
));
1911 EnableMenuItem(hMenu
, ID_SYSTEM_EDIT_PASTE
, MF_BYCOMMAND
|
1912 (!(Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) &&
1913 IsClipboardFormatAvailable(CF_UNICODETEXT
) ? MF_ENABLED
: MF_GRAYED
));
1916 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1918 GuiSendMenuEvent(Console
, WM_INITMENU
);
1919 LeaveCriticalSection(&Console
->Lock
);
1926 if (HIWORD(wParam
) == 0xFFFF) // Allow all the menu flags
1928 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1930 GuiSendMenuEvent(Console
, WM_MENUSELECT
);
1931 LeaveCriticalSection(&Console
->Lock
);
1940 Result
= GuiConsoleHandleSysMenuCommand(GuiData
, wParam
, lParam
);
1947 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1949 BOOL SetFocus
= (msg
== WM_SETFOCUS
);
1952 er
.EventType
= FOCUS_EVENT
;
1953 er
.Event
.FocusEvent
.bSetFocus
= SetFocus
;
1954 ConioProcessInputEvent(Console
, &er
);
1957 DPRINT1("TODO: Create console caret\n");
1959 DPRINT1("TODO: Destroy console caret\n");
1961 LeaveCriticalSection(&Console
->Lock
);
1966 case WM_GETMINMAXINFO
:
1967 GuiConsoleGetMinMaxInfo(GuiData
, (PMINMAXINFO
)lParam
);
1971 GuiConsoleResize(GuiData
, wParam
, lParam
);
1974 case PM_RESIZE_TERMINAL
:
1976 PCONSOLE_SCREEN_BUFFER Buff
= GuiData
->ActiveBuffer
;
1980 DWORD Width
, Height
;
1981 UINT WidthUnit
, HeightUnit
;
1983 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
1985 Width
= Buff
->ScreenBufferSize
.X
* WidthUnit
;
1986 Height
= Buff
->ScreenBufferSize
.Y
* HeightUnit
;
1988 /* Recreate the framebuffer */
1989 hDC
= GetDC(GuiData
->hWindow
);
1990 hnew
= CreateCompatibleBitmap(hDC
, Width
, Height
);
1991 ReleaseDC(GuiData
->hWindow
, hDC
);
1992 hold
= SelectObject(GuiData
->hMemDC
, hnew
);
1993 if (GuiData
->hBitmap
)
1995 if (hold
== GuiData
->hBitmap
) DeleteObject(GuiData
->hBitmap
);
1997 GuiData
->hBitmap
= hnew
;
1999 /* Resize the window to the user's values */
2000 GuiData
->WindowSizeLock
= TRUE
;
2001 GuiConsoleResizeWindow(GuiData
, WidthUnit
, HeightUnit
);
2002 GuiData
->WindowSizeLock
= FALSE
;
2006 case PM_APPLY_CONSOLE_INFO
:
2008 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
2010 GuiApplyUserSettings(GuiData
, (HANDLE
)wParam
, (BOOL
)lParam
);
2011 LeaveCriticalSection(&Console
->Lock
);
2016 case PM_CONSOLE_BEEP
:
2017 DPRINT1("Beep !!\n");
2021 // case PM_CONSOLE_SET_TITLE:
2022 // SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
2026 Result
= DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
2035 /******************************************************************************
2036 * GUI Terminal Initialization *
2037 ******************************************************************************/
2039 static LRESULT CALLBACK
2040 GuiConsoleNotifyWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
2050 SetWindowLongW(hWnd
, GWL_USERDATA
, 0);
2054 case PM_CREATE_CONSOLE
:
2056 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)lParam
;
2057 PCONSOLE Console
= GuiData
->Console
;
2059 NewWindow
= CreateWindowExW(WS_EX_CLIENTEDGE
,
2060 GUI_CONSOLE_WINDOW_CLASS
,
2061 Console
->Title
.Buffer
,
2062 WS_OVERLAPPEDWINDOW
| WS_HSCROLL
| WS_VSCROLL
,
2071 if (NULL
!= NewWindow
)
2073 ASSERT(NewWindow
== GuiData
->hWindow
);
2075 WindowCount
= GetWindowLongW(hWnd
, GWL_USERDATA
);
2077 SetWindowLongW(hWnd
, GWL_USERDATA
, WindowCount
);
2079 DPRINT("Set icons via PM_CREATE_CONSOLE\n");
2080 if (GuiData
->hIcon
== NULL
)
2082 DPRINT("Not really /o\\...\n");
2083 GuiData
->hIcon
= ghDefaultIcon
;
2084 GuiData
->hIconSm
= ghDefaultIconSm
;
2086 else if (GuiData
->hIcon
!= ghDefaultIcon
)
2088 DPRINT("Yes \\o/\n");
2089 SendMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
2090 SendMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
2093 /* Move and resize the window to the user's values */
2094 /* CAN WE DEADLOCK ?? */
2095 GuiConsoleMoveWindow(GuiData
);
2096 SendMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
2098 /* Switch to full-screen mode if necessary */
2099 if (GuiData
->GuiInfo
.FullScreen
) SwitchFullScreen(GuiData
, TRUE
);
2101 // ShowWindow(NewWindow, (int)wParam);
2102 ShowWindowAsync(NewWindow
, (int)wParam
);
2103 DPRINT("Window showed\n");
2106 return (LRESULT
)NewWindow
;
2109 case PM_DESTROY_CONSOLE
:
2111 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)lParam
;
2113 /* Exit the full screen mode if it was already set */
2114 // LeaveFullScreen(GuiData);
2117 * Window creation is done using a PostMessage(), so it's possible
2118 * that the window that we want to destroy doesn't exist yet.
2119 * So first empty the message queue.
2122 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
2124 TranslateMessage(&Msg);
2125 DispatchMessageW(&Msg);
2127 while (PeekMessageW(&Msg
, NULL
, 0, 0, PM_REMOVE
)) ;
2129 if (GuiData
->hWindow
!= NULL
) /* && DestroyWindow(GuiData->hWindow) */
2131 DestroyWindow(GuiData
->hWindow
);
2133 WindowCount
= GetWindowLongW(hWnd
, GWL_USERDATA
);
2135 SetWindowLongW(hWnd
, GWL_USERDATA
, WindowCount
);
2136 if (0 == WindowCount
)
2139 DestroyWindow(hWnd
);
2140 DPRINT("CONSRV: Going to quit the Gui Thread!!\n");
2149 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
2154 GuiConsoleGuiThread(PVOID Data
)
2157 PHANDLE GraphicsStartupEvent
= (PHANDLE
)Data
;
2160 * This thread dispatches all the console notifications to the notify window.
2161 * It is common for all the console windows.
2164 PrivateCsrssManualGuiCheck(+1);
2166 NotifyWnd
= CreateWindowW(L
"ConSrvCreateNotify",
2168 WS_OVERLAPPEDWINDOW
,
2177 if (NULL
== NotifyWnd
)
2179 PrivateCsrssManualGuiCheck(-1);
2180 SetEvent(*GraphicsStartupEvent
);
2184 SetEvent(*GraphicsStartupEvent
);
2186 while (GetMessageW(&msg
, NULL
, 0, 0))
2188 TranslateMessage(&msg
);
2189 DispatchMessageW(&msg
);
2192 DPRINT("CONSRV: Quit the Gui Thread!!\n");
2193 PrivateCsrssManualGuiCheck(-1);
2202 ATOM ConsoleClassAtom
;
2204 /* Exit if we were already initialized */
2205 // if (ConsInitialized) return TRUE;
2208 * Initialize and register the different window classes, if needed.
2210 if (!ConsInitialized
)
2212 /* Initialize the notification window class */
2213 wc
.cbSize
= sizeof(WNDCLASSEXW
);
2214 wc
.lpszClassName
= L
"ConSrvCreateNotify";
2215 wc
.lpfnWndProc
= GuiConsoleNotifyWndProc
;
2217 wc
.hInstance
= ConSrvDllInstance
;
2221 wc
.hbrBackground
= NULL
;
2222 wc
.lpszMenuName
= NULL
;
2225 if (RegisterClassExW(&wc
) == 0)
2227 DPRINT1("Failed to register GUI notify wndproc\n");
2231 /* Initialize the console window class */
2232 ghDefaultIcon
= LoadImageW(ConSrvDllInstance
,
2233 MAKEINTRESOURCEW(IDI_TERMINAL
),
2235 GetSystemMetrics(SM_CXICON
),
2236 GetSystemMetrics(SM_CYICON
),
2238 ghDefaultIconSm
= LoadImageW(ConSrvDllInstance
,
2239 MAKEINTRESOURCEW(IDI_TERMINAL
),
2241 GetSystemMetrics(SM_CXSMICON
),
2242 GetSystemMetrics(SM_CYSMICON
),
2244 ghDefaultCursor
= LoadCursorW(NULL
, IDC_ARROW
);
2245 wc
.cbSize
= sizeof(WNDCLASSEXW
);
2246 wc
.lpszClassName
= GUI_CONSOLE_WINDOW_CLASS
;
2247 wc
.lpfnWndProc
= GuiConsoleWndProc
;
2248 wc
.style
= CS_DBLCLKS
/* | CS_HREDRAW | CS_VREDRAW */;
2249 wc
.hInstance
= ConSrvDllInstance
;
2250 wc
.hIcon
= ghDefaultIcon
;
2251 wc
.hIconSm
= ghDefaultIconSm
;
2252 wc
.hCursor
= ghDefaultCursor
;
2253 wc
.hbrBackground
= (HBRUSH
)GetStockObject(BLACK_BRUSH
); // The color of a terminal when it is switch off.
2254 wc
.lpszMenuName
= NULL
;
2256 wc
.cbWndExtra
= GWLP_CONSOLEWND_ALLOC
;
2258 ConsoleClassAtom
= RegisterClassExW(&wc
);
2259 if (ConsoleClassAtom
== 0)
2261 DPRINT1("Failed to register GUI console wndproc\n");
2266 NtUserConsoleControl(GuiConsoleWndClassAtom
, &ConsoleClassAtom
, sizeof(ATOM
));
2269 ConsInitialized
= TRUE
;
2273 * Set-up the notification window
2275 if (NULL
== NotifyWnd
)
2277 HANDLE ThreadHandle
;
2278 HANDLE GraphicsStartupEvent
;
2280 GraphicsStartupEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
2281 if (NULL
== GraphicsStartupEvent
) return FALSE
;
2283 ThreadHandle
= CreateThread(NULL
,
2285 GuiConsoleGuiThread
,
2286 (PVOID
)&GraphicsStartupEvent
,
2289 if (NULL
== ThreadHandle
)
2291 CloseHandle(GraphicsStartupEvent
);
2292 DPRINT1("CONSRV: Failed to create graphics console thread. Expect problems\n");
2295 SetThreadPriority(ThreadHandle
, THREAD_PRIORITY_HIGHEST
);
2296 CloseHandle(ThreadHandle
);
2298 WaitForSingleObject(GraphicsStartupEvent
, INFINITE
);
2299 CloseHandle(GraphicsStartupEvent
);
2301 if (NULL
== NotifyWnd
)
2303 DPRINT1("CONSRV: Failed to create notification window.\n");
2308 // ConsInitialized = TRUE;
2315 /******************************************************************************
2316 * GUI Console Driver *
2317 ******************************************************************************/
2320 GuiDeinitFrontEnd(IN OUT PFRONTEND This
);
2323 GuiInitFrontEnd(IN OUT PFRONTEND This
,
2324 IN PCONSOLE Console
)
2326 PGUI_INIT_INFO GuiInitInfo
;
2327 PCONSOLE_INFO ConsoleInfo
;
2328 PCONSOLE_START_INFO ConsoleStartInfo
;
2330 PGUI_CONSOLE_DATA GuiData
;
2331 GUI_CONSOLE_INFO TermInfo
;
2334 LPWSTR IconPath
= NULL
;
2337 if (This
== NULL
|| Console
== NULL
|| This
->OldData
== NULL
)
2338 return STATUS_INVALID_PARAMETER
;
2340 ASSERT(This
->Console
== Console
);
2342 GuiInitInfo
= This
->OldData
;
2344 if (GuiInitInfo
->ConsoleInfo
== NULL
|| GuiInitInfo
->ConsoleStartInfo
== NULL
)
2345 return STATUS_INVALID_PARAMETER
;
2347 ConsoleInfo
= GuiInitInfo
->ConsoleInfo
;
2348 ConsoleStartInfo
= GuiInitInfo
->ConsoleStartInfo
;
2350 IconPath
= ConsoleStartInfo
->IconPath
;
2351 IconIndex
= ConsoleStartInfo
->IconIndex
;
2354 /* Terminal data allocation */
2355 GuiData
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_CONSOLE_DATA
));
2358 DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
2359 return STATUS_UNSUCCESSFUL
;
2361 /* HACK */ Console
->TermIFace
.Data
= (PVOID
)GuiData
; /* HACK */
2362 GuiData
->Console
= Console
;
2363 GuiData
->ActiveBuffer
= Console
->ActiveBuffer
;
2364 GuiData
->hWindow
= NULL
;
2366 /* The console can be resized */
2367 Console
->FixedSize
= FALSE
;
2369 InitializeCriticalSection(&GuiData
->Lock
);
2373 * Load terminal settings
2376 /* 1. Load the default settings */
2377 GuiConsoleGetDefaultSettings(&TermInfo
, GuiInitInfo
->ProcessId
);
2379 /* 3. Load the remaining console settings via the registry. */
2380 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
2382 /* Load the terminal infos from the registry. */
2383 GuiConsoleReadUserSettings(&TermInfo
,
2384 ConsoleInfo
->ConsoleTitle
,
2385 GuiInitInfo
->ProcessId
);
2388 * Now, update them with the properties the user might gave to us
2389 * via the STARTUPINFO structure before calling CreateProcess
2390 * (and which was transmitted via the ConsoleStartInfo structure).
2391 * We therefore overwrite the values read in the registry.
2393 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USESHOWWINDOW
)
2395 TermInfo
.ShowWindow
= ConsoleStartInfo
->wShowWindow
;
2397 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USEPOSITION
)
2399 TermInfo
.AutoPosition
= FALSE
;
2400 TermInfo
.WindowOrigin
.x
= ConsoleStartInfo
->dwWindowOrigin
.X
;
2401 TermInfo
.WindowOrigin
.y
= ConsoleStartInfo
->dwWindowOrigin
.Y
;
2403 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_RUNFULLSCREEN
)
2405 TermInfo
.FullScreen
= TRUE
;
2414 Length
= min(wcslen(TermInfo
.FaceName
) + 1, LF_FACESIZE
); // wcsnlen
2415 wcsncpy(GuiData
->GuiInfo
.FaceName
, TermInfo
.FaceName
, LF_FACESIZE
);
2416 GuiData
->GuiInfo
.FaceName
[Length
] = L
'\0';
2417 GuiData
->GuiInfo
.FontFamily
= TermInfo
.FontFamily
;
2418 GuiData
->GuiInfo
.FontSize
= TermInfo
.FontSize
;
2419 GuiData
->GuiInfo
.FontWeight
= TermInfo
.FontWeight
;
2420 GuiData
->GuiInfo
.UseRasterFonts
= TermInfo
.UseRasterFonts
;
2421 GuiData
->GuiInfo
.FullScreen
= TermInfo
.FullScreen
;
2422 GuiData
->GuiInfo
.ShowWindow
= TermInfo
.ShowWindow
;
2423 GuiData
->GuiInfo
.AutoPosition
= TermInfo
.AutoPosition
;
2424 GuiData
->GuiInfo
.WindowOrigin
= TermInfo
.WindowOrigin
;
2426 /* Initialize the icon handles to their default values */
2427 GuiData
->hIcon
= ghDefaultIcon
;
2428 GuiData
->hIconSm
= ghDefaultIconSm
;
2430 /* Get the associated icon, if any */
2431 if (IconPath
== NULL
|| IconPath
[0] == L
'\0')
2433 IconPath
= ConsoleStartInfo
->AppPath
;
2436 DPRINT("IconPath = %S ; IconIndex = %lu\n", (IconPath
? IconPath
: L
"n/a"), IconIndex
);
2437 if (IconPath
&& IconPath
[0] != L
'\0')
2439 HICON hIcon
= NULL
, hIconSm
= NULL
;
2440 PrivateExtractIconExW(IconPath
,
2445 DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon
, hIconSm
);
2448 DPRINT("Effectively set the icons\n");
2449 GuiData
->hIcon
= hIcon
;
2450 GuiData
->hIconSm
= hIconSm
;
2454 /* Mouse is shown by default with its default cursor shape */
2455 GuiData
->hCursor
= ghDefaultCursor
;
2456 GuiData
->MouseCursorRefCount
= 0;
2458 /* A priori don't ignore mouse signals */
2459 GuiData
->IgnoreNextMouseSignal
= FALSE
;
2461 /* Close button and the corresponding system menu item are enabled by default */
2462 GuiData
->IsCloseButtonEnabled
= TRUE
;
2464 /* There is no user-reserved menu id range by default */
2465 GuiData
->cmdIdLow
= GuiData
->cmdIdHigh
= 0;
2468 * We need to wait until the GUI has been fully initialized
2469 * to retrieve custom settings i.e. WindowSize etc...
2470 * Ideally we could use SendNotifyMessage for this but its not
2473 GuiData
->hGuiInitEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
2475 DPRINT("GUI - Checkpoint\n");
2477 /* Create the terminal window */
2478 PostMessageW(NotifyWnd
, PM_CREATE_CONSOLE
, GuiData
->GuiInfo
.ShowWindow
, (LPARAM
)GuiData
);
2480 /* Wait until initialization has finished */
2481 WaitForSingleObject(GuiData
->hGuiInitEvent
, INFINITE
);
2482 DPRINT("OK we created the console window\n");
2483 CloseHandle(GuiData
->hGuiInitEvent
);
2484 GuiData
->hGuiInitEvent
= NULL
;
2486 /* Check whether we really succeeded in initializing the terminal window */
2487 if (GuiData
->hWindow
== NULL
)
2489 DPRINT("GuiInitConsole - We failed at creating a new terminal window\n");
2490 GuiDeinitFrontEnd(This
);
2491 return STATUS_UNSUCCESSFUL
;
2494 /* Finally, finish to initialize the frontend structure */
2495 This
->Data
= GuiData
;
2496 if (This
->OldData
) ConsoleFreeHeap(This
->OldData
);
2497 This
->OldData
= NULL
;
2499 return STATUS_SUCCESS
;
2503 GuiDeinitFrontEnd(IN OUT PFRONTEND This
)
2505 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2507 SendMessageW(NotifyWnd
, PM_DESTROY_CONSOLE
, 0, (LPARAM
)GuiData
);
2509 DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
2510 GuiData
->hIcon
, ghDefaultIcon
, GuiData
->hIconSm
, ghDefaultIconSm
);
2511 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
2513 DPRINT("Destroy hIcon\n");
2514 DestroyIcon(GuiData
->hIcon
);
2516 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
2518 DPRINT("Destroy hIconSm\n");
2519 DestroyIcon(GuiData
->hIconSm
);
2523 DeleteCriticalSection(&GuiData
->Lock
);
2524 ConsoleFreeHeap(GuiData
);
2526 DPRINT("Quit GuiDeinitFrontEnd\n");
2530 GuiDrawRegion(IN OUT PFRONTEND This
,
2533 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2536 SmallRectToRect(GuiData
, &RegionRect
, Region
);
2537 /* Do not erase the background: it speeds up redrawing and reduce flickering */
2538 InvalidateRect(GuiData
->hWindow
, &RegionRect
, FALSE
);
2539 /**UpdateWindow(GuiData->hWindow);**/
2543 GuiWriteStream(IN OUT PFRONTEND This
,
2551 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2552 PCONSOLE_SCREEN_BUFFER Buff
;
2553 SHORT CursorEndX
, CursorEndY
;
2556 if (NULL
== GuiData
|| NULL
== GuiData
->hWindow
) return;
2558 Buff
= GuiData
->ActiveBuffer
;
2559 if (GetType(Buff
) != TEXTMODE_BUFFER
) return;
2561 if (0 != ScrolledLines
)
2563 ScrollRect
.left
= 0;
2565 ScrollRect
.right
= Buff
->ViewSize
.X
* GuiData
->CharWidth
;
2566 ScrollRect
.bottom
= Region
->Top
* GuiData
->CharHeight
;
2568 ScrollWindowEx(GuiData
->hWindow
,
2570 -(int)(ScrolledLines
* GuiData
->CharHeight
),
2578 GuiDrawRegion(This
, Region
);
2580 if (CursorStartX
< Region
->Left
|| Region
->Right
< CursorStartX
2581 || CursorStartY
< Region
->Top
|| Region
->Bottom
< CursorStartY
)
2583 GuiInvalidateCell(This
, CursorStartX
, CursorStartY
);
2586 CursorEndX
= Buff
->CursorPosition
.X
;
2587 CursorEndY
= Buff
->CursorPosition
.Y
;
2588 if ((CursorEndX
< Region
->Left
|| Region
->Right
< CursorEndX
2589 || CursorEndY
< Region
->Top
|| Region
->Bottom
< CursorEndY
)
2590 && (CursorEndX
!= CursorStartX
|| CursorEndY
!= CursorStartY
))
2592 GuiInvalidateCell(This
, CursorEndX
, CursorEndY
);
2595 // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
2596 // repaint the window without having it just freeze up and stay on the screen permanently.
2597 Buff
->CursorBlinkOn
= TRUE
;
2598 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
2602 GuiSetCursorInfo(IN OUT PFRONTEND This
,
2603 PCONSOLE_SCREEN_BUFFER Buff
)
2605 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2607 if (GuiData
->ActiveBuffer
== Buff
)
2609 GuiInvalidateCell(This
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
2616 GuiSetScreenInfo(IN OUT PFRONTEND This
,
2617 PCONSOLE_SCREEN_BUFFER Buff
,
2621 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2623 if (GuiData
->ActiveBuffer
== Buff
)
2625 /* Redraw char at old position (remove cursor) */
2626 GuiInvalidateCell(This
, OldCursorX
, OldCursorY
);
2627 /* Redraw char at new position (show cursor) */
2628 GuiInvalidateCell(This
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
2635 GuiResizeTerminal(IN OUT PFRONTEND This
)
2637 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2639 /* Resize the window to the user's values */
2640 PostMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
2644 GuiSetActiveScreenBuffer(IN OUT PFRONTEND This
)
2646 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2647 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
2650 EnterCriticalSection(&GuiData
->Lock
);
2651 GuiData
->WindowSizeLock
= TRUE
;
2653 InterlockedExchangePointer(&GuiData
->ActiveBuffer
,
2654 ConDrvGetActiveScreenBuffer(GuiData
->Console
));
2656 GuiData
->WindowSizeLock
= FALSE
;
2657 LeaveCriticalSection(&GuiData
->Lock
);
2659 ActiveBuffer
= GuiData
->ActiveBuffer
;
2661 /* Change the current palette */
2662 if (ActiveBuffer
->PaletteHandle
== NULL
)
2664 hPalette
= GuiData
->hSysPalette
;
2668 hPalette
= ActiveBuffer
->PaletteHandle
;
2671 DPRINT1("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette
);
2673 /* Set the new palette for the framebuffer */
2674 SelectPalette(GuiData
->hMemDC
, hPalette
, FALSE
);
2676 /* Specify the use of the system palette for the framebuffer */
2677 SetSystemPaletteUse(GuiData
->hMemDC
, ActiveBuffer
->PaletteUsage
);
2679 /* Realize the (logical) palette */
2680 RealizePalette(GuiData
->hMemDC
);
2682 GuiResizeTerminal(This
);
2683 // ConioDrawConsole(Console);
2687 GuiReleaseScreenBuffer(IN OUT PFRONTEND This
,
2688 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer
)
2690 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2693 * If we were notified to release a screen buffer that is not actually
2694 * ours, then just ignore the notification...
2696 if (ScreenBuffer
!= GuiData
->ActiveBuffer
) return;
2699 * ... else, we must release our active buffer. Two cases are present:
2700 * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console
2701 * active screen buffer, then we can safely switch to it.
2702 * - If ScreenBuffer IS the console active screen buffer, we must release
2706 /* Release the old active palette and set the default one */
2707 if (GetCurrentObject(GuiData
->hMemDC
, OBJ_PAL
) == ScreenBuffer
->PaletteHandle
)
2709 /* Set the new palette */
2710 SelectPalette(GuiData
->hMemDC
, GuiData
->hSysPalette
, FALSE
);
2713 /* Set the adequate active screen buffer */
2714 if (ScreenBuffer
!= GuiData
->Console
->ActiveBuffer
)
2716 GuiSetActiveScreenBuffer(This
);
2720 EnterCriticalSection(&GuiData
->Lock
);
2721 GuiData
->WindowSizeLock
= TRUE
;
2723 InterlockedExchangePointer(&GuiData
->ActiveBuffer
, NULL
);
2725 GuiData
->WindowSizeLock
= FALSE
;
2726 LeaveCriticalSection(&GuiData
->Lock
);
2731 GuiProcessKeyCallback(IN OUT PFRONTEND This
,
2735 UINT VirtualKeyCode
,
2738 if ((ShiftState
& (RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
) || KeyStateMenu
& 0x80) &&
2739 (VirtualKeyCode
== VK_ESCAPE
|| VirtualKeyCode
== VK_TAB
|| VirtualKeyCode
== VK_SPACE
))
2741 DefWindowProcW(msg
->hwnd
, msg
->message
, msg
->wParam
, msg
->lParam
);
2749 GuiSetMouseCursor(IN OUT PFRONTEND This
,
2753 GuiRefreshInternalInfo(IN OUT PFRONTEND This
)
2755 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2757 /* Update the console leader information held by the window */
2758 SetConsoleWndConsoleLeaderCID(GuiData
);
2762 * We reset the cursor here so that, when a console app quits, we reset
2763 * the cursor to the default one. It's quite a hack since it doesn't proceed
2764 * per - console process... This must be fixed.
2766 * See GuiInitConsole(...) for more information.
2769 /* Mouse is shown by default with its default cursor shape */
2770 GuiData
->MouseCursorRefCount
= 0; // Reinitialize the reference counter
2771 GuiSetMouseCursor(This
, NULL
);
2775 GuiChangeTitle(IN OUT PFRONTEND This
)
2777 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2778 // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
2779 SetWindowText(GuiData
->hWindow
, GuiData
->Console
->Title
.Buffer
);
2783 GuiChangeIcon(IN OUT PFRONTEND This
,
2786 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2787 HICON hIcon
, hIconSm
;
2789 if (hWindowIcon
== NULL
)
2791 hIcon
= ghDefaultIcon
;
2792 hIconSm
= ghDefaultIconSm
;
2796 hIcon
= CopyIcon(hWindowIcon
);
2797 hIconSm
= CopyIcon(hWindowIcon
);
2805 if (hIcon
!= GuiData
->hIcon
)
2807 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
2809 DestroyIcon(GuiData
->hIcon
);
2811 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
2813 DestroyIcon(GuiData
->hIconSm
);
2816 GuiData
->hIcon
= hIcon
;
2817 GuiData
->hIconSm
= hIconSm
;
2819 DPRINT("Set icons in GuiChangeIcon\n");
2820 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
2821 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
2828 GuiGetConsoleWindowHandle(IN OUT PFRONTEND This
)
2830 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2831 return GuiData
->hWindow
;
2835 GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This
,
2838 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2839 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
2842 UINT WidthUnit
, HeightUnit
;
2846 if (!SystemParametersInfoW(SPI_GETWORKAREA
, 0, &WorkArea
, 0))
2848 DPRINT1("SystemParametersInfoW failed - What to do ??\n");
2852 ActiveBuffer
= GuiData
->ActiveBuffer
;
2855 GetScreenBufferSizeUnits(ActiveBuffer
, GuiData
, &WidthUnit
, &HeightUnit
);
2859 /* Default: text mode */
2860 WidthUnit
= GuiData
->CharWidth
;
2861 HeightUnit
= GuiData
->CharHeight
;
2864 width
= WorkArea
.right
;
2865 height
= WorkArea
.bottom
;
2867 width
-= (2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
)));
2868 height
-= (2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
));
2870 if (width
< 0) width
= 0;
2871 if (height
< 0) height
= 0;
2873 pSize
->X
= (SHORT
)(width
/ (int)WidthUnit
) /* HACK */ + 2;
2874 pSize
->Y
= (SHORT
)(height
/ (int)HeightUnit
) /* HACK */ + 1;
2878 GuiSetPalette(IN OUT PFRONTEND This
,
2879 HPALETTE PaletteHandle
,
2882 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2883 HPALETTE OldPalette
;
2885 // if (GetType(GuiData->ActiveBuffer) != GRAPHICS_BUFFER) return FALSE;
2886 if (PaletteHandle
== NULL
) return FALSE
;
2888 /* Set the new palette for the framebuffer */
2889 OldPalette
= SelectPalette(GuiData
->hMemDC
, PaletteHandle
, FALSE
);
2890 if (OldPalette
== NULL
) return FALSE
;
2892 /* Specify the use of the system palette for the framebuffer */
2893 SetSystemPaletteUse(GuiData
->hMemDC
, PaletteUsage
);
2895 /* Realize the (logical) palette */
2896 RealizePalette(GuiData
->hMemDC
);
2898 /* Save the original system palette handle */
2899 if (GuiData
->hSysPalette
== NULL
) GuiData
->hSysPalette
= OldPalette
;
2905 GuiGetDisplayMode(IN OUT PFRONTEND This
)
2907 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2908 ULONG DisplayMode
= 0;
2910 if (GuiData
->GuiInfo
.FullScreen
)
2911 DisplayMode
|= CONSOLE_FULLSCREEN_HARDWARE
; // CONSOLE_FULLSCREEN
2913 DisplayMode
|= CONSOLE_WINDOWED
;
2919 GuiSetDisplayMode(IN OUT PFRONTEND This
,
2922 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2925 if (NewMode
& ~(CONSOLE_FULLSCREEN_MODE
| CONSOLE_WINDOWED_MODE
))
2928 FullScreen
= ((NewMode
& CONSOLE_FULLSCREEN_MODE
) != 0);
2930 if (FullScreen
!= GuiData
->GuiInfo
.FullScreen
)
2932 SwitchFullScreen(GuiData
, FullScreen
);
2939 GuiShowMouseCursor(IN OUT PFRONTEND This
,
2942 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2944 /* Set the reference count */
2945 if (Show
) ++GuiData
->MouseCursorRefCount
;
2946 else --GuiData
->MouseCursorRefCount
;
2948 /* Effectively show (or hide) the cursor (use special values for (w|l)Param) */
2949 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
2951 return GuiData
->MouseCursorRefCount
;
2955 GuiSetMouseCursor(IN OUT PFRONTEND This
,
2958 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2961 * Set the cursor's handle. If the given handle is NULL,
2962 * then restore the default cursor.
2964 GuiData
->hCursor
= (hCursor
? hCursor
: ghDefaultCursor
);
2966 /* Effectively modify the shape of the cursor (use special values for (w|l)Param) */
2967 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
2973 GuiMenuControl(IN OUT PFRONTEND This
,
2977 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2979 GuiData
->cmdIdLow
= cmdIdLow
;
2980 GuiData
->cmdIdHigh
= cmdIdHigh
;
2982 return GetSystemMenu(GuiData
->hWindow
, FALSE
);
2986 GuiSetMenuClose(IN OUT PFRONTEND This
,
2990 * NOTE: See http://www.mail-archive.com/harbour@harbour-project.org/msg27509.html
2991 * or http://harbour-devel.1590103.n2.nabble.com/Question-about-hb-gt-win-CtrlHandler-usage-td4670862i20.html
2992 * for more information.
2995 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2996 HMENU hSysMenu
= GetSystemMenu(GuiData
->hWindow
, FALSE
);
2998 if (hSysMenu
== NULL
) return FALSE
;
3000 GuiData
->IsCloseButtonEnabled
= Enable
;
3001 EnableMenuItem(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
| (Enable
? MF_ENABLED
: MF_GRAYED
));
3006 static FRONTEND_VTBL GuiVtbl
=
3015 GuiSetActiveScreenBuffer
,
3016 GuiReleaseScreenBuffer
,
3017 GuiProcessKeyCallback
,
3018 GuiRefreshInternalInfo
,
3021 GuiGetConsoleWindowHandle
,
3022 GuiGetLargestConsoleWindowSize
,
3034 LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo
,
3035 IN OUT PCONSOLE_INFO ConsoleInfo
)
3037 #define PATH_SEPARATOR L'\\'
3039 BOOL RetVal
= FALSE
;
3040 HRESULT hRes
= S_OK
;
3041 LPWSTR LinkName
= NULL
;
3044 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
3047 ConsoleStartInfo
->IconPath
[0] = L
'\0';
3048 ConsoleStartInfo
->IconIndex
= 0;
3050 /* 1- Find the last path separator if any */
3051 LinkName
= wcsrchr(ConsoleStartInfo
->ConsoleTitle
, PATH_SEPARATOR
);
3052 if (LinkName
== NULL
)
3054 LinkName
= ConsoleStartInfo
->ConsoleTitle
;
3058 /* Skip the path separator */
3062 /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
3063 Length
= wcslen(LinkName
);
3064 if ( (Length
<= 4) || (wcsicmp(LinkName
+ (Length
- 4), L
".lnk") != 0) )
3067 /* 3- It may be a link. Try to retrieve some properties */
3068 hRes
= CoInitialize(NULL
);
3069 if (SUCCEEDED(hRes
))
3071 /* Get a pointer to the IShellLink interface */
3072 IShellLinkW
* pshl
= NULL
;
3073 hRes
= CoCreateInstance(&CLSID_ShellLink
,
3075 CLSCTX_INPROC_SERVER
,
3078 if (SUCCEEDED(hRes
))
3080 /* Get a pointer to the IPersistFile interface */
3081 IPersistFile
* ppf
= NULL
;
3082 hRes
= IPersistFile_QueryInterface(pshl
, &IID_IPersistFile
, (LPVOID
*)&ppf
);
3083 if (SUCCEEDED(hRes
))
3085 /* Load the shortcut */
3086 hRes
= IPersistFile_Load(ppf
, ConsoleStartInfo
->ConsoleTitle
, STGM_READ
);
3087 if (SUCCEEDED(hRes
))
3090 * Finally we can get the properties !
3091 * Update the old ones if needed.
3096 /* Reset the name of the console with the name of the shortcut */
3097 Length
= min(/*Length*/ Length
- 4, // 4 == len(".lnk")
3098 sizeof(ConsoleInfo
->ConsoleTitle
) / sizeof(ConsoleInfo
->ConsoleTitle
[0]) - 1);
3099 wcsncpy(ConsoleInfo
->ConsoleTitle
, LinkName
, Length
);
3100 ConsoleInfo
->ConsoleTitle
[Length
] = L
'\0';
3102 /* Get the window showing command */
3103 hRes
= IShellLinkW_GetShowCmd(pshl
, &ShowCmd
);
3104 if (SUCCEEDED(hRes
)) ConsoleStartInfo
->wShowWindow
= (WORD
)ShowCmd
;
3106 /* Get the hotkey */
3107 // hRes = pshl->GetHotkey(&ShowCmd);
3108 // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey;
3110 /* Get the icon location, if any */
3112 hRes
= IShellLinkW_GetIconLocation(pshl
,
3113 ConsoleStartInfo
->IconPath
,
3114 sizeof(ConsoleStartInfo
->IconPath
)/sizeof(ConsoleStartInfo
->IconPath
[0]) - 1, // == MAX_PATH
3115 &ConsoleStartInfo
->IconIndex
);
3116 if (!SUCCEEDED(hRes
))
3118 ConsoleStartInfo
->IconPath
[0] = L
'\0';
3119 ConsoleStartInfo
->IconIndex
= 0;
3122 // FIXME: Since we still don't load console properties from the shortcut,
3123 // return false. When this will be done, we will return true instead.
3126 IPersistFile_Release(ppf
);
3128 IShellLinkW_Release(pshl
);
3137 GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd
,
3138 IN OUT PCONSOLE_INFO ConsoleInfo
,
3139 IN OUT PVOID ExtraConsoleInfo
,
3142 PCONSOLE_START_INFO ConsoleStartInfo
= ExtraConsoleInfo
;
3143 PGUI_INIT_INFO GuiInitInfo
;
3145 if (FrontEnd
== NULL
|| ConsoleInfo
== NULL
|| ConsoleStartInfo
== NULL
)
3146 return STATUS_INVALID_PARAMETER
;
3148 /* Initialize GUI terminal emulator common functionalities */
3149 if (!GuiInit()) return STATUS_UNSUCCESSFUL
;
3152 * Load per-application terminal settings.
3154 * Check whether the process creating the console was launched via
3155 * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the
3156 * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too.
3158 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
)
3160 if (!LoadShellLinkConsoleInfo(ConsoleStartInfo
, ConsoleInfo
))
3162 ConsoleStartInfo
->dwStartupFlags
&= ~STARTF_TITLEISLINKNAME
;
3167 * Initialize a private initialization info structure for later use.
3168 * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd.
3170 GuiInitInfo
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_INIT_INFO
));
3171 if (GuiInitInfo
== NULL
) return STATUS_NO_MEMORY
;
3173 // HACK: We suppose that the pointers will be valid in GuiInitFrontEnd...
3174 GuiInitInfo
->ConsoleInfo
= ConsoleInfo
;
3175 GuiInitInfo
->ConsoleStartInfo
= ConsoleStartInfo
;
3176 GuiInitInfo
->ProcessId
= ProcessId
;
3178 /* Finally, initialize the frontend structure */
3179 FrontEnd
->Vtbl
= &GuiVtbl
;
3180 FrontEnd
->Data
= NULL
;
3181 FrontEnd
->OldData
= GuiInitInfo
;
3183 return STATUS_SUCCESS
;
3187 GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd
)
3189 if (FrontEnd
== NULL
) return STATUS_INVALID_PARAMETER
;
3191 if (FrontEnd
->Data
) GuiDeinitFrontEnd(FrontEnd
);
3192 if (FrontEnd
->OldData
) ConsoleFreeHeap(FrontEnd
->OldData
);
3194 return STATUS_SUCCESS
;