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 DPRINT("Menu item ID: %d\n", CmdId
);
235 ConioProcessInputEvent(Console
, &er
);
239 GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData
);
241 GuiConsolePaste(PGUI_CONSOLE_DATA GuiData
);
243 GuiConsoleUpdateSelection(PCONSOLE Console
, PCOORD coord
);
245 GuiDrawRegion(IN OUT PFRONTEND This
, SMALL_RECT
* Region
);
247 GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData
, DWORD WidthUnit
, DWORD HeightUnit
);
251 GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData
, WPARAM wParam
, LPARAM lParam
)
254 PCONSOLE Console
= GuiData
->Console
;
255 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
257 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
262 ActiveBuffer
= GuiData
->ActiveBuffer
;
265 * In case the selected menu item belongs to the user-reserved menu id range,
266 * send to him a menu event and return directly. The user must handle those
267 * reserved menu commands...
269 if (GuiData
->CmdIdLow
<= (UINT
)wParam
&& (UINT
)wParam
<= GuiData
->CmdIdHigh
)
271 GuiSendMenuEvent(Console
, (UINT
)wParam
);
275 /* ... otherwise, perform actions. */
278 case ID_SYSTEM_EDIT_MARK
:
280 LPWSTR WindowTitle
= NULL
;
283 Console
->dwSelectionCursor
.X
= ActiveBuffer
->ViewOrigin
.X
;
284 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->ViewOrigin
.Y
;
285 Console
->Selection
.dwSelectionAnchor
= Console
->dwSelectionCursor
;
286 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_IN_PROGRESS
;
287 GuiConsoleUpdateSelection(Console
, &Console
->Selection
.dwSelectionAnchor
);
289 Length
= Console
->Title
.Length
+ sizeof(L
"Mark - ")/sizeof(WCHAR
) + 1;
290 WindowTitle
= ConsoleAllocHeap(0, Length
* sizeof(WCHAR
));
291 wcscpy(WindowTitle
, L
"Mark - ");
292 wcscat(WindowTitle
, Console
->Title
.Buffer
);
293 SetWindowText(GuiData
->hWindow
, WindowTitle
);
294 ConsoleFreeHeap(WindowTitle
);
299 case ID_SYSTEM_EDIT_COPY
:
300 GuiConsoleCopy(GuiData
);
303 case ID_SYSTEM_EDIT_PASTE
:
304 GuiConsolePaste(GuiData
);
307 case ID_SYSTEM_EDIT_SELECTALL
:
309 LPWSTR WindowTitle
= NULL
;
313 * The selection area extends to the whole screen buffer's width.
315 Console
->Selection
.dwSelectionAnchor
.X
= 0;
316 Console
->Selection
.dwSelectionAnchor
.Y
= 0;
317 Console
->dwSelectionCursor
.X
= ActiveBuffer
->ScreenBufferSize
.X
- 1;
320 * Determine whether the selection must extend to just some part
321 * (for text-mode screen buffers) or to all of the screen buffer's
322 * height (for graphics ones).
324 if (GetType(ActiveBuffer
) == TEXTMODE_BUFFER
)
327 * We select all the characters from the first line
328 * to the line where the cursor is positioned.
330 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->CursorPosition
.Y
;
332 else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
335 * We select all the screen buffer area.
337 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->ScreenBufferSize
.Y
- 1;
340 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_IN_PROGRESS
| CONSOLE_MOUSE_SELECTION
;
341 GuiConsoleUpdateSelection(Console
, &Console
->dwSelectionCursor
);
343 Length
= Console
->Title
.Length
+ sizeof(L
"Selection - ")/sizeof(WCHAR
) + 1;
344 WindowTitle
= ConsoleAllocHeap(0, Length
* sizeof(WCHAR
));
345 wcscpy(WindowTitle
, L
"Selection - ");
346 wcscat(WindowTitle
, Console
->Title
.Buffer
);
347 SetWindowText(GuiData
->hWindow
, WindowTitle
);
348 ConsoleFreeHeap(WindowTitle
);
353 case ID_SYSTEM_EDIT_SCROLL
:
354 DPRINT1("Scrolling is not handled yet\n");
357 case ID_SYSTEM_EDIT_FIND
:
358 DPRINT1("Finding is not handled yet\n");
361 case ID_SYSTEM_DEFAULTS
:
362 GuiConsoleShowConsoleProperties(GuiData
, TRUE
);
365 case ID_SYSTEM_PROPERTIES
:
366 GuiConsoleShowConsoleProperties(GuiData
, FALSE
);
375 LeaveCriticalSection(&Console
->Lock
);
378 Ret
= DefWindowProcW(GuiData
->hWindow
, WM_SYSCOMMAND
, wParam
, lParam
);
383 static PGUI_CONSOLE_DATA
384 GuiGetGuiData(HWND hWnd
)
386 /* This function ensures that the console pointer is not NULL */
387 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
388 return ( ((GuiData
== NULL
) || (GuiData
->hWindow
== hWnd
&& GuiData
->Console
!= NULL
)) ? GuiData
: NULL
);
392 GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData
)
394 /* Move the window if needed (not positioned by the system) */
395 if (!GuiData
->GuiInfo
.AutoPosition
)
397 SetWindowPos(GuiData
->hWindow
,
399 GuiData
->GuiInfo
.WindowOrigin
.x
,
400 GuiData
->GuiInfo
.WindowOrigin
.y
,
403 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
408 GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData
, DWORD WidthUnit
, DWORD HeightUnit
)
410 PCONSOLE_SCREEN_BUFFER Buff
= GuiData
->ActiveBuffer
;
415 Width
= Buff
->ViewSize
.X
* WidthUnit
+
416 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
417 Height
= Buff
->ViewSize
.Y
* HeightUnit
+
418 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
420 /* Set scrollbar sizes */
421 sInfo
.cbSize
= sizeof(SCROLLINFO
);
422 sInfo
.fMask
= SIF_RANGE
| SIF_PAGE
| SIF_POS
;
424 if (Buff
->ScreenBufferSize
.Y
> Buff
->ViewSize
.Y
)
426 sInfo
.nMax
= Buff
->ScreenBufferSize
.Y
- 1;
427 sInfo
.nPage
= Buff
->ViewSize
.Y
;
428 sInfo
.nPos
= Buff
->ViewOrigin
.Y
;
429 SetScrollInfo(GuiData
->hWindow
, SB_VERT
, &sInfo
, TRUE
);
430 Width
+= GetSystemMetrics(SM_CXVSCROLL
);
431 ShowScrollBar(GuiData
->hWindow
, SB_VERT
, TRUE
);
435 ShowScrollBar(GuiData
->hWindow
, SB_VERT
, FALSE
);
438 if (Buff
->ScreenBufferSize
.X
> Buff
->ViewSize
.X
)
440 sInfo
.nMax
= Buff
->ScreenBufferSize
.X
- 1;
441 sInfo
.nPage
= Buff
->ViewSize
.X
;
442 sInfo
.nPos
= Buff
->ViewOrigin
.X
;
443 SetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &sInfo
, TRUE
);
444 Height
+= GetSystemMetrics(SM_CYHSCROLL
);
445 ShowScrollBar(GuiData
->hWindow
, SB_HORZ
, TRUE
);
449 ShowScrollBar(GuiData
->hWindow
, SB_HORZ
, FALSE
);
452 /* Resize the window */
453 SetWindowPos(GuiData
->hWindow
, NULL
, 0, 0, Width
, Height
,
454 SWP_NOZORDER
| SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOCOPYBITS
);
455 // NOTE: The SWP_NOCOPYBITS flag can be replaced by a subsequent call
456 // to: InvalidateRect(GuiData->hWindow, NULL, TRUE);
460 GuiConsoleHandleNcCreate(HWND hWnd
, LPCREATESTRUCTW Create
)
462 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)Create
->lpCreateParams
;
469 DPRINT("GuiConsoleHandleNcCreate\n");
473 DPRINT1("GuiConsoleNcCreate: No GUI data\n");
477 Console
= GuiData
->Console
;
479 GuiData
->hWindow
= hWnd
;
481 GuiData
->Font
= CreateFontW(LOWORD(GuiData
->GuiInfo
.FontSize
),
482 0, // HIWORD(GuiData->GuiInfo.FontSize),
485 GuiData
->GuiInfo
.FontWeight
,
492 NONANTIALIASED_QUALITY
,
493 FIXED_PITCH
| GuiData
->GuiInfo
.FontFamily
/* FF_DONTCARE */,
494 GuiData
->GuiInfo
.FaceName
);
496 if (NULL
== GuiData
->Font
)
498 DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
499 GuiData
->hWindow
= NULL
;
500 SetEvent(GuiData
->hGuiInitEvent
);
503 hDC
= GetDC(GuiData
->hWindow
);
506 DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
507 DeleteObject(GuiData
->Font
);
508 GuiData
->hWindow
= NULL
;
509 SetEvent(GuiData
->hGuiInitEvent
);
512 OldFont
= SelectObject(hDC
, GuiData
->Font
);
515 DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
516 ReleaseDC(GuiData
->hWindow
, hDC
);
517 DeleteObject(GuiData
->Font
);
518 GuiData
->hWindow
= NULL
;
519 SetEvent(GuiData
->hGuiInitEvent
);
522 if (!GetTextMetricsW(hDC
, &Metrics
))
524 DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
525 SelectObject(hDC
, OldFont
);
526 ReleaseDC(GuiData
->hWindow
, hDC
);
527 DeleteObject(GuiData
->Font
);
528 GuiData
->hWindow
= NULL
;
529 SetEvent(GuiData
->hGuiInitEvent
);
532 GuiData
->CharWidth
= Metrics
.tmMaxCharWidth
;
533 GuiData
->CharHeight
= Metrics
.tmHeight
+ Metrics
.tmExternalLeading
;
535 /* Measure real char width more precisely if possible. */
536 if (GetTextExtentPoint32W(hDC
, L
"R", 1, &CharSize
))
537 GuiData
->CharWidth
= CharSize
.cx
;
539 SelectObject(hDC
, OldFont
);
541 ReleaseDC(GuiData
->hWindow
, hDC
);
543 /* Initialize the terminal framebuffer */
544 GuiData
->hMemDC
= CreateCompatibleDC(NULL
);
545 GuiData
->hBitmap
= NULL
;
546 GuiData
->hSysPalette
= NULL
; /* Original system palette */
548 // FIXME: Keep these instructions here ? ///////////////////////////////////
549 Console
->ActiveBuffer
->CursorBlinkOn
= TRUE
;
550 Console
->ActiveBuffer
->ForceCursorOff
= FALSE
;
551 ////////////////////////////////////////////////////////////////////////////
553 SetWindowLongPtrW(GuiData
->hWindow
, GWLP_USERDATA
, (DWORD_PTR
)GuiData
);
555 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
556 GuiConsoleCreateSysMenu(GuiData
->hWindow
);
558 DPRINT("GuiConsoleHandleNcCreate - setting start event\n");
559 SetEvent(GuiData
->hGuiInitEvent
);
561 return (BOOL
)DefWindowProcW(GuiData
->hWindow
, WM_NCCREATE
, 0, (LPARAM
)Create
);
565 SmallRectToRect(PGUI_CONSOLE_DATA GuiData
, PRECT Rect
, PSMALL_RECT SmallRect
)
567 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
568 UINT WidthUnit
, HeightUnit
;
570 GetScreenBufferSizeUnits(Buffer
, GuiData
, &WidthUnit
, &HeightUnit
);
572 Rect
->left
= (SmallRect
->Left
- Buffer
->ViewOrigin
.X
) * WidthUnit
;
573 Rect
->top
= (SmallRect
->Top
- Buffer
->ViewOrigin
.Y
) * HeightUnit
;
574 Rect
->right
= (SmallRect
->Right
+ 1 - Buffer
->ViewOrigin
.X
) * WidthUnit
;
575 Rect
->bottom
= (SmallRect
->Bottom
+ 1 - Buffer
->ViewOrigin
.Y
) * HeightUnit
;
579 GuiConsoleUpdateSelection(PCONSOLE Console
, PCOORD coord
)
581 PGUI_CONSOLE_DATA GuiData
= Console
->TermIFace
.Data
;
582 RECT oldRect
, newRect
;
584 SmallRectToRect(GuiData
, &oldRect
, &Console
->Selection
.srSelection
);
589 /* exchange left/top with right/bottom if required */
590 rc
.Left
= min(Console
->Selection
.dwSelectionAnchor
.X
, coord
->X
);
591 rc
.Top
= min(Console
->Selection
.dwSelectionAnchor
.Y
, coord
->Y
);
592 rc
.Right
= max(Console
->Selection
.dwSelectionAnchor
.X
, coord
->X
);
593 rc
.Bottom
= max(Console
->Selection
.dwSelectionAnchor
.Y
, coord
->Y
);
595 SmallRectToRect(GuiData
, &newRect
, &rc
);
597 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
599 if (memcmp(&rc
, &Console
->Selection
.srSelection
, sizeof(SMALL_RECT
)) != 0)
603 /* calculate the region that needs to be updated */
604 if ((rgn1
= CreateRectRgnIndirect(&oldRect
)))
606 if ((rgn2
= CreateRectRgnIndirect(&newRect
)))
608 if (CombineRgn(rgn1
, rgn2
, rgn1
, RGN_XOR
) != ERROR
)
610 InvalidateRgn(GuiData
->hWindow
, rgn1
, FALSE
);
620 InvalidateRect(GuiData
->hWindow
, &newRect
, FALSE
);
622 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_NOT_EMPTY
;
623 Console
->Selection
.srSelection
= rc
;
624 Console
->dwSelectionCursor
= *coord
;
625 ConioPause(Console
, PAUSED_FROM_SELECTION
);
629 /* clear the selection */
630 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
632 InvalidateRect(GuiData
->hWindow
, &oldRect
, FALSE
);
634 Console
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
635 ConioUnpause(Console
, PAUSED_FROM_SELECTION
);
641 GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
,
642 PGUI_CONSOLE_DATA GuiData
,
644 PRECT rcFramebuffer
);
646 GuiPaintGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
,
647 PGUI_CONSOLE_DATA GuiData
,
649 PRECT rcFramebuffer
);
652 GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData
)
655 PCONSOLE Console
= GuiData
->Console
;
656 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
660 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
665 ActiveBuffer
= GuiData
->ActiveBuffer
;
667 BeginPaint(GuiData
->hWindow
, &ps
);
668 if (ps
.hdc
!= NULL
&&
669 ps
.rcPaint
.left
< ps
.rcPaint
.right
&&
670 ps
.rcPaint
.top
< ps
.rcPaint
.bottom
)
672 EnterCriticalSection(&GuiData
->Lock
);
674 /* Compose the current screen-buffer on-memory */
675 if (GetType(ActiveBuffer
) == TEXTMODE_BUFFER
)
677 GuiPaintTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)ActiveBuffer
,
678 GuiData
, &ps
.rcPaint
, &rcPaint
);
680 else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
682 GuiPaintGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)ActiveBuffer
,
683 GuiData
, &ps
.rcPaint
, &rcPaint
);
686 /* Send it to screen */
690 rcPaint
.right
- rcPaint
.left
,
691 rcPaint
.bottom
- rcPaint
.top
,
697 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
699 SmallRectToRect(GuiData
, &rcPaint
, &Console
->Selection
.srSelection
);
701 /* Invert the selection */
702 if (IntersectRect(&rcPaint
, &ps
.rcPaint
, &rcPaint
))
704 InvertRect(ps
.hdc
, &rcPaint
);
708 LeaveCriticalSection(&GuiData
->Lock
);
710 EndPaint(GuiData
->hWindow
, &ps
);
714 LeaveCriticalSection(&Console
->Lock
);
716 DefWindowProcW(GuiData
->hWindow
, WM_PAINT
, 0, 0);
722 IsSystemKey(WORD VirtualKeyCode
)
724 switch (VirtualKeyCode
)
726 /* From MSDN, "Virtual-Key Codes" */
745 GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
747 PCONSOLE Console
= GuiData
->Console
;
748 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
750 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
752 ActiveBuffer
= GuiData
->ActiveBuffer
;
754 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
)
756 WORD VirtualKeyCode
= LOWORD(wParam
);
758 if (msg
!= WM_KEYDOWN
) goto Quit
;
760 if (VirtualKeyCode
== VK_RETURN
)
762 /* Copy (and clear) selection if ENTER is pressed */
763 GuiConsoleCopy(GuiData
);
766 else if ( VirtualKeyCode
== VK_ESCAPE
||
767 (VirtualKeyCode
== 'C' && GetKeyState(VK_CONTROL
) & 0x8000) )
769 /* Cancel selection if ESC or Ctrl-C are pressed */
770 GuiConsoleUpdateSelection(Console
, NULL
);
771 SetWindowText(GuiData
->hWindow
, Console
->Title
.Buffer
);
776 if ((Console
->Selection
.dwFlags
& CONSOLE_MOUSE_SELECTION
) == 0)
778 /* Keyboard selection mode */
779 BOOL Interpreted
= FALSE
;
780 BOOL MajPressed
= (GetKeyState(VK_SHIFT
) & 0x8000);
782 switch (VirtualKeyCode
)
787 if (Console
->dwSelectionCursor
.X
> 0)
788 Console
->dwSelectionCursor
.X
--;
796 if (Console
->dwSelectionCursor
.X
< ActiveBuffer
->ScreenBufferSize
.X
- 1)
797 Console
->dwSelectionCursor
.X
++;
805 if (Console
->dwSelectionCursor
.Y
> 0)
806 Console
->dwSelectionCursor
.Y
--;
814 if (Console
->dwSelectionCursor
.Y
< ActiveBuffer
->ScreenBufferSize
.Y
- 1)
815 Console
->dwSelectionCursor
.Y
++;
823 Console
->dwSelectionCursor
.X
= 0;
824 Console
->dwSelectionCursor
.Y
= 0;
831 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->ScreenBufferSize
.Y
- 1;
838 Console
->dwSelectionCursor
.Y
-= ActiveBuffer
->ViewSize
.Y
;
839 if (Console
->dwSelectionCursor
.Y
< 0)
840 Console
->dwSelectionCursor
.Y
= 0;
848 Console
->dwSelectionCursor
.Y
+= ActiveBuffer
->ViewSize
.Y
;
849 if (Console
->dwSelectionCursor
.Y
>= ActiveBuffer
->ScreenBufferSize
.Y
)
850 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->ScreenBufferSize
.Y
- 1;
862 Console
->Selection
.dwSelectionAnchor
= Console
->dwSelectionCursor
;
864 GuiConsoleUpdateSelection(Console
, &Console
->dwSelectionCursor
);
866 else if (!IsSystemKey(VirtualKeyCode
))
868 /* Emit an error beep sound */
869 SendNotifyMessage(GuiData
->hWindow
, PM_CONSOLE_BEEP
, 0, 0);
876 /* Mouse selection mode */
878 if (!IsSystemKey(VirtualKeyCode
))
880 /* Clear the selection and send the key into the input buffer */
881 GuiConsoleUpdateSelection(Console
, NULL
);
882 SetWindowText(GuiData
->hWindow
, Console
->Title
.Buffer
);
891 if ((Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) == 0)
895 Message
.hwnd
= GuiData
->hWindow
;
896 Message
.message
= msg
;
897 Message
.wParam
= wParam
;
898 Message
.lParam
= lParam
;
900 ConioProcessKey(Console
, &Message
);
904 LeaveCriticalSection(&Console
->Lock
);
908 GuiInvalidateCell(IN OUT PFRONTEND This
, SHORT x
, SHORT y
)
910 SMALL_RECT CellRect
= { x
, y
, x
, y
};
911 GuiDrawRegion(This
, &CellRect
);
915 GuiConsoleHandleTimer(PGUI_CONSOLE_DATA GuiData
)
917 PCONSOLE Console
= GuiData
->Console
;
918 PCONSOLE_SCREEN_BUFFER Buff
;
920 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CURSOR_BLINK_TIME
, NULL
);
922 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
924 Buff
= GuiData
->ActiveBuffer
;
926 if (GetType(Buff
) == TEXTMODE_BUFFER
)
928 GuiInvalidateCell(&Console
->TermIFace
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
929 Buff
->CursorBlinkOn
= !Buff
->CursorBlinkOn
;
931 if ((GuiData
->OldCursor
.x
!= Buff
->CursorPosition
.X
) ||
932 (GuiData
->OldCursor
.y
!= Buff
->CursorPosition
.Y
))
935 int OldScrollX
= -1, OldScrollY
= -1;
936 int NewScrollX
= -1, NewScrollY
= -1;
938 xScroll
.cbSize
= sizeof(SCROLLINFO
);
939 xScroll
.fMask
= SIF_POS
;
940 // Capture the original position of the scroll bars and save them.
941 if (GetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &xScroll
)) OldScrollX
= xScroll
.nPos
;
942 if (GetScrollInfo(GuiData
->hWindow
, SB_VERT
, &xScroll
)) OldScrollY
= xScroll
.nPos
;
944 // If we successfully got the info for the horizontal scrollbar
947 if ((Buff
->CursorPosition
.X
< Buff
->ViewOrigin
.X
) ||
948 (Buff
->CursorPosition
.X
>= (Buff
->ViewOrigin
.X
+ Buff
->ViewSize
.X
)))
950 // Handle the horizontal scroll bar
951 if (Buff
->CursorPosition
.X
>= Buff
->ViewSize
.X
)
952 NewScrollX
= Buff
->CursorPosition
.X
- Buff
->ViewSize
.X
+ 1;
958 NewScrollX
= OldScrollX
;
961 // If we successfully got the info for the vertical scrollbar
964 if ((Buff
->CursorPosition
.Y
< Buff
->ViewOrigin
.Y
) ||
965 (Buff
->CursorPosition
.Y
>= (Buff
->ViewOrigin
.Y
+ Buff
->ViewSize
.Y
)))
967 // Handle the vertical scroll bar
968 if (Buff
->CursorPosition
.Y
>= Buff
->ViewSize
.Y
)
969 NewScrollY
= Buff
->CursorPosition
.Y
- Buff
->ViewSize
.Y
+ 1;
975 NewScrollY
= OldScrollY
;
979 // Adjust scroll bars and refresh the window if the cursor has moved outside the visible area
980 // NOTE: OldScroll# and NewScroll# will both be -1 (initial value) if the info for the respective scrollbar
981 // was not obtained successfully in the previous steps. This means their difference is 0 (no scrolling)
982 // and their associated scrollbar is left alone.
983 if ((OldScrollX
!= NewScrollX
) || (OldScrollY
!= NewScrollY
))
985 Buff
->ViewOrigin
.X
= NewScrollX
;
986 Buff
->ViewOrigin
.Y
= NewScrollY
;
987 ScrollWindowEx(GuiData
->hWindow
,
988 (OldScrollX
- NewScrollX
) * GuiData
->CharWidth
,
989 (OldScrollY
- NewScrollY
) * GuiData
->CharHeight
,
997 xScroll
.nPos
= NewScrollX
;
998 SetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &xScroll
, TRUE
);
1000 if (NewScrollY
>= 0)
1002 xScroll
.nPos
= NewScrollY
;
1003 SetScrollInfo(GuiData
->hWindow
, SB_VERT
, &xScroll
, TRUE
);
1005 UpdateWindow(GuiData
->hWindow
);
1006 // InvalidateRect(GuiData->hWindow, NULL, FALSE);
1007 GuiData
->OldCursor
.x
= Buff
->CursorPosition
.X
;
1008 GuiData
->OldCursor
.y
= Buff
->CursorPosition
.Y
;
1012 else /* if (GetType(Buff) == GRAPHICS_BUFFER) */
1016 LeaveCriticalSection(&Console
->Lock
);
1020 GuiConsoleHandleClose(PGUI_CONSOLE_DATA GuiData
)
1022 PCONSOLE Console
= GuiData
->Console
;
1024 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1027 // TODO: Prompt for termination ? (Warn the user about possible apps running in this console)
1030 * FIXME: Windows will wait up to 5 seconds for the thread to exit.
1031 * We shouldn't wait here, though, since the console lock is entered.
1032 * A copy of the thread list probably needs to be made.
1034 ConDrvConsoleProcessCtrlEvent(Console
, 0, CTRL_CLOSE_EVENT
);
1036 LeaveCriticalSection(&Console
->Lock
);
1041 GuiConsoleHandleNcDestroy(HWND hWnd
)
1043 PGUI_CONSOLE_DATA GuiData
= GuiGetGuiData(hWnd
);
1045 KillTimer(hWnd
, CONGUI_UPDATE_TIMER
);
1046 GetSystemMenu(hWnd
, TRUE
);
1050 /* Free the terminal framebuffer */
1051 if (GuiData
->hMemDC
) DeleteDC(GuiData
->hMemDC
);
1052 if (GuiData
->hBitmap
) DeleteObject(GuiData
->hBitmap
);
1053 // if (GuiData->hSysPalette) DeleteObject(GuiData->hSysPalette);
1054 if (GuiData
->Font
) DeleteObject(GuiData
->Font
);
1057 /* Free the GuiData registration */
1058 SetWindowLongPtrW(hWnd
, GWLP_USERDATA
, (DWORD_PTR
)NULL
);
1060 return DefWindowProcW(hWnd
, WM_NCDESTROY
, 0, 0);
1064 PointToCoord(PGUI_CONSOLE_DATA GuiData
, LPARAM lParam
)
1066 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
1068 UINT WidthUnit
, HeightUnit
;
1070 GetScreenBufferSizeUnits(Buffer
, GuiData
, &WidthUnit
, &HeightUnit
);
1072 Coord
.X
= Buffer
->ViewOrigin
.X
+ ((SHORT
)LOWORD(lParam
) / (int)WidthUnit
);
1073 Coord
.Y
= Buffer
->ViewOrigin
.Y
+ ((SHORT
)HIWORD(lParam
) / (int)HeightUnit
);
1075 /* Clip coordinate to ensure it's inside buffer */
1078 else if (Coord
.X
>= Buffer
->ScreenBufferSize
.X
)
1079 Coord
.X
= Buffer
->ScreenBufferSize
.X
- 1;
1083 else if (Coord
.Y
>= Buffer
->ScreenBufferSize
.Y
)
1084 Coord
.Y
= Buffer
->ScreenBufferSize
.Y
- 1;
1090 GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1093 PCONSOLE Console
= GuiData
->Console
;
1095 if (GuiData
->IgnoreNextMouseSignal
)
1097 if (msg
!= WM_LBUTTONDOWN
&&
1098 msg
!= WM_MBUTTONDOWN
&&
1099 msg
!= WM_RBUTTONDOWN
)
1102 * If this mouse signal is not a button-down action,
1103 * then it is the last signal being ignored.
1105 GuiData
->IgnoreNextMouseSignal
= FALSE
;
1110 * This mouse signal is a button-down action.
1111 * Ignore it and perform default action.
1118 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1124 if ( (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) ||
1125 (Console
->QuickEdit
) )
1129 case WM_LBUTTONDOWN
:
1131 LPWSTR WindowTitle
= NULL
;
1134 Console
->Selection
.dwSelectionAnchor
= PointToCoord(GuiData
, lParam
);
1135 SetCapture(GuiData
->hWindow
);
1136 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_IN_PROGRESS
| CONSOLE_MOUSE_SELECTION
| CONSOLE_MOUSE_DOWN
;
1137 GuiConsoleUpdateSelection(Console
, &Console
->Selection
.dwSelectionAnchor
);
1139 Length
= Console
->Title
.Length
+ sizeof(L
"Selection - ")/sizeof(WCHAR
) + 1;
1140 WindowTitle
= ConsoleAllocHeap(0, Length
* sizeof(WCHAR
));
1141 wcscpy(WindowTitle
, L
"Selection - ");
1142 wcscat(WindowTitle
, Console
->Title
.Buffer
);
1143 SetWindowText(GuiData
->hWindow
, WindowTitle
);
1144 ConsoleFreeHeap(WindowTitle
);
1153 if (!(Console
->Selection
.dwFlags
& CONSOLE_MOUSE_DOWN
)) break;
1155 c
= PointToCoord(GuiData
, lParam
);
1156 Console
->Selection
.dwFlags
&= ~CONSOLE_MOUSE_DOWN
;
1157 GuiConsoleUpdateSelection(Console
, &c
);
1163 case WM_LBUTTONDBLCLK
:
1165 DPRINT1("Handle left-double-click for selecting a word\n");
1169 case WM_RBUTTONDOWN
:
1170 case WM_RBUTTONDBLCLK
:
1172 if (!(Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
))
1174 GuiConsolePaste(GuiData
);
1178 GuiConsoleCopy(GuiData
);
1181 GuiData
->IgnoreNextMouseSignal
= TRUE
;
1189 if (!(wParam
& MK_LBUTTON
)) break;
1190 if (!(Console
->Selection
.dwFlags
& CONSOLE_MOUSE_DOWN
)) break;
1192 c
= PointToCoord(GuiData
, lParam
); /* TODO: Scroll buffer to bring c into view */
1193 GuiConsoleUpdateSelection(Console
, &c
);
1199 Err
= FALSE
; // TRUE;
1203 else if (Console
->InputBuffer
.Mode
& ENABLE_MOUSE_INPUT
)
1206 WORD wKeyState
= GET_KEYSTATE_WPARAM(wParam
);
1207 DWORD dwButtonState
= 0;
1208 DWORD dwControlKeyState
= 0;
1209 DWORD dwEventFlags
= 0;
1213 case WM_LBUTTONDOWN
:
1214 SetCapture(GuiData
->hWindow
);
1215 dwButtonState
= FROM_LEFT_1ST_BUTTON_PRESSED
;
1219 case WM_MBUTTONDOWN
:
1220 SetCapture(GuiData
->hWindow
);
1221 dwButtonState
= FROM_LEFT_2ND_BUTTON_PRESSED
;
1225 case WM_RBUTTONDOWN
:
1226 SetCapture(GuiData
->hWindow
);
1227 dwButtonState
= RIGHTMOST_BUTTON_PRESSED
;
1249 case WM_LBUTTONDBLCLK
:
1250 dwButtonState
= FROM_LEFT_1ST_BUTTON_PRESSED
;
1251 dwEventFlags
= DOUBLE_CLICK
;
1254 case WM_MBUTTONDBLCLK
:
1255 dwButtonState
= FROM_LEFT_2ND_BUTTON_PRESSED
;
1256 dwEventFlags
= DOUBLE_CLICK
;
1259 case WM_RBUTTONDBLCLK
:
1260 dwButtonState
= RIGHTMOST_BUTTON_PRESSED
;
1261 dwEventFlags
= DOUBLE_CLICK
;
1266 dwEventFlags
= MOUSE_MOVED
;
1270 dwButtonState
= GET_WHEEL_DELTA_WPARAM(wParam
) << 16;
1271 dwEventFlags
= MOUSE_WHEELED
;
1274 case WM_MOUSEHWHEEL
:
1275 dwButtonState
= GET_WHEEL_DELTA_WPARAM(wParam
) << 16;
1276 dwEventFlags
= MOUSE_HWHEELED
;
1286 if (wKeyState
& MK_LBUTTON
)
1287 dwButtonState
|= FROM_LEFT_1ST_BUTTON_PRESSED
;
1288 if (wKeyState
& MK_MBUTTON
)
1289 dwButtonState
|= FROM_LEFT_2ND_BUTTON_PRESSED
;
1290 if (wKeyState
& MK_RBUTTON
)
1291 dwButtonState
|= RIGHTMOST_BUTTON_PRESSED
;
1293 if (GetKeyState(VK_RMENU
) & 0x8000)
1294 dwControlKeyState
|= RIGHT_ALT_PRESSED
;
1295 if (GetKeyState(VK_LMENU
) & 0x8000)
1296 dwControlKeyState
|= LEFT_ALT_PRESSED
;
1297 if (GetKeyState(VK_RCONTROL
) & 0x8000)
1298 dwControlKeyState
|= RIGHT_CTRL_PRESSED
;
1299 if (GetKeyState(VK_LCONTROL
) & 0x8000)
1300 dwControlKeyState
|= LEFT_CTRL_PRESSED
;
1301 if (GetKeyState(VK_SHIFT
) & 0x8000)
1302 dwControlKeyState
|= SHIFT_PRESSED
;
1303 if (GetKeyState(VK_NUMLOCK
) & 0x0001)
1304 dwControlKeyState
|= NUMLOCK_ON
;
1305 if (GetKeyState(VK_SCROLL
) & 0x0001)
1306 dwControlKeyState
|= SCROLLLOCK_ON
;
1307 if (GetKeyState(VK_CAPITAL
) & 0x0001)
1308 dwControlKeyState
|= CAPSLOCK_ON
;
1309 /* See WM_CHAR MSDN documentation for instance */
1310 if (lParam
& 0x01000000)
1311 dwControlKeyState
|= ENHANCED_KEY
;
1313 er
.EventType
= MOUSE_EVENT
;
1314 er
.Event
.MouseEvent
.dwMousePosition
= PointToCoord(GuiData
, lParam
);
1315 er
.Event
.MouseEvent
.dwButtonState
= dwButtonState
;
1316 er
.Event
.MouseEvent
.dwControlKeyState
= dwControlKeyState
;
1317 er
.Event
.MouseEvent
.dwEventFlags
= dwEventFlags
;
1319 ConioProcessInputEvent(Console
, &er
);
1327 LeaveCriticalSection(&Console
->Lock
);
1331 return DefWindowProcW(GuiData
->hWindow
, msg
, wParam
, lParam
);
1336 VOID
GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
);
1337 VOID
GuiCopyFromGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
);
1340 GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData
)
1342 if (OpenClipboard(GuiData
->hWindow
) == TRUE
)
1344 PCONSOLE Console
= GuiData
->Console
;
1345 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
1347 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
1349 GuiCopyFromTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)Buffer
);
1351 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
1353 GuiCopyFromGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)Buffer
);
1358 /* Clear the selection */
1359 GuiConsoleUpdateSelection(Console
, NULL
);
1360 SetWindowText(GuiData
->hWindow
, Console
->Title
.Buffer
);
1364 VOID
GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
);
1365 VOID
GuiPasteToGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
);
1368 GuiConsolePaste(PGUI_CONSOLE_DATA GuiData
)
1370 if (OpenClipboard(GuiData
->hWindow
) == TRUE
)
1372 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
1374 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
1376 GuiPasteToTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)Buffer
);
1378 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
1380 GuiPasteToGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)Buffer
);
1388 GuiConsoleGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData
, PMINMAXINFO minMaxInfo
)
1390 PCONSOLE Console
= GuiData
->Console
;
1391 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
1393 UINT WidthUnit
, HeightUnit
;
1395 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
1397 ActiveBuffer
= GuiData
->ActiveBuffer
;
1399 GetScreenBufferSizeUnits(ActiveBuffer
, GuiData
, &WidthUnit
, &HeightUnit
);
1401 windx
= CONGUI_MIN_WIDTH
* WidthUnit
+ 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
1402 windy
= CONGUI_MIN_HEIGHT
* HeightUnit
+ 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
1404 minMaxInfo
->ptMinTrackSize
.x
= windx
;
1405 minMaxInfo
->ptMinTrackSize
.y
= windy
;
1407 windx
= (ActiveBuffer
->ScreenBufferSize
.X
) * WidthUnit
+ 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
1408 windy
= (ActiveBuffer
->ScreenBufferSize
.Y
) * HeightUnit
+ 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
1410 if (ActiveBuffer
->ViewSize
.X
< ActiveBuffer
->ScreenBufferSize
.X
) windy
+= GetSystemMetrics(SM_CYHSCROLL
); // window currently has a horizontal scrollbar
1411 if (ActiveBuffer
->ViewSize
.Y
< ActiveBuffer
->ScreenBufferSize
.Y
) windx
+= GetSystemMetrics(SM_CXVSCROLL
); // window currently has a vertical scrollbar
1413 minMaxInfo
->ptMaxTrackSize
.x
= windx
;
1414 minMaxInfo
->ptMaxTrackSize
.y
= windy
;
1416 LeaveCriticalSection(&Console
->Lock
);
1420 GuiConsoleResize(PGUI_CONSOLE_DATA GuiData
, WPARAM wParam
, LPARAM lParam
)
1422 PCONSOLE Console
= GuiData
->Console
;
1424 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
1426 if ((GuiData
->WindowSizeLock
== FALSE
) &&
1427 (wParam
== SIZE_RESTORED
|| wParam
== SIZE_MAXIMIZED
|| wParam
== SIZE_MINIMIZED
))
1429 PCONSOLE_SCREEN_BUFFER Buff
= GuiData
->ActiveBuffer
;
1430 DWORD windx
, windy
, charx
, chary
;
1431 UINT WidthUnit
, HeightUnit
;
1433 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
1435 GuiData
->WindowSizeLock
= TRUE
;
1437 windx
= LOWORD(lParam
);
1438 windy
= HIWORD(lParam
);
1440 // Compensate for existing scroll bars (because lParam values do not accommodate scroll bar)
1441 if (Buff
->ViewSize
.X
< Buff
->ScreenBufferSize
.X
) windy
+= GetSystemMetrics(SM_CYHSCROLL
); // window currently has a horizontal scrollbar
1442 if (Buff
->ViewSize
.Y
< Buff
->ScreenBufferSize
.Y
) windx
+= GetSystemMetrics(SM_CXVSCROLL
); // window currently has a vertical scrollbar
1444 charx
= windx
/ (int)WidthUnit
;
1445 chary
= windy
/ (int)HeightUnit
;
1447 // Character alignment (round size up or down)
1448 if ((windx
% WidthUnit
) >= (WidthUnit
/ 2)) ++charx
;
1449 if ((windy
% HeightUnit
) >= (HeightUnit
/ 2)) ++chary
;
1451 // Compensate for added scroll bars in new window
1452 if (charx
< Buff
->ScreenBufferSize
.X
) windy
-= GetSystemMetrics(SM_CYHSCROLL
); // new window will have a horizontal scroll bar
1453 if (chary
< Buff
->ScreenBufferSize
.Y
) windx
-= GetSystemMetrics(SM_CXVSCROLL
); // new window will have a vertical scroll bar
1455 charx
= windx
/ (int)WidthUnit
;
1456 chary
= windy
/ (int)HeightUnit
;
1458 // Character alignment (round size up or down)
1459 if ((windx
% WidthUnit
) >= (WidthUnit
/ 2)) ++charx
;
1460 if ((windy
% HeightUnit
) >= (HeightUnit
/ 2)) ++chary
;
1463 if ((charx
!= Buff
->ViewSize
.X
) || (chary
!= Buff
->ViewSize
.Y
))
1465 Buff
->ViewSize
.X
= (charx
<= Buff
->ScreenBufferSize
.X
) ? charx
: Buff
->ScreenBufferSize
.X
;
1466 Buff
->ViewSize
.Y
= (chary
<= Buff
->ScreenBufferSize
.Y
) ? chary
: Buff
->ScreenBufferSize
.Y
;
1469 GuiConsoleResizeWindow(GuiData
, WidthUnit
, HeightUnit
);
1471 // Adjust the start of the visible area if we are attempting to show nonexistent areas
1472 if ((Buff
->ScreenBufferSize
.X
- Buff
->ViewOrigin
.X
) < Buff
->ViewSize
.X
) Buff
->ViewOrigin
.X
= Buff
->ScreenBufferSize
.X
- Buff
->ViewSize
.X
;
1473 if ((Buff
->ScreenBufferSize
.Y
- Buff
->ViewOrigin
.Y
) < Buff
->ViewSize
.Y
) Buff
->ViewOrigin
.Y
= Buff
->ScreenBufferSize
.Y
- Buff
->ViewSize
.Y
;
1474 InvalidateRect(GuiData
->hWindow
, NULL
, TRUE
);
1476 GuiData
->WindowSizeLock
= FALSE
;
1479 LeaveCriticalSection(&Console
->Lock
);
1483 // HACK: This functionality is standard for general scrollbars. Don't add it by hand.
1487 GuiConsoleHandleScrollbarMenu(VOID)
1491 hMenu = CreatePopupMenu();
1494 DPRINT("CreatePopupMenu failed\n");
1498 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLHERE);
1499 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1500 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLTOP);
1501 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLBOTTOM);
1502 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1503 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_UP);
1504 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_DOWN);
1505 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1506 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLUP);
1507 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLDOWN);
1512 GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData
, UINT uMsg
, WPARAM wParam
)
1514 PCONSOLE Console
= GuiData
->Console
;
1515 PCONSOLE_SCREEN_BUFFER Buff
;
1518 int old_pos
, Maximum
;
1521 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return 0;
1523 Buff
= GuiData
->ActiveBuffer
;
1525 if (uMsg
== WM_HSCROLL
)
1528 Maximum
= Buff
->ScreenBufferSize
.X
- Buff
->ViewSize
.X
;
1529 pShowXY
= &Buff
->ViewOrigin
.X
;
1534 Maximum
= Buff
->ScreenBufferSize
.Y
- Buff
->ViewSize
.Y
;
1535 pShowXY
= &Buff
->ViewOrigin
.Y
;
1538 /* set scrollbar sizes */
1539 sInfo
.cbSize
= sizeof(SCROLLINFO
);
1540 sInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
| SIF_TRACKPOS
;
1542 if (!GetScrollInfo(GuiData
->hWindow
, fnBar
, &sInfo
)) goto Quit
;
1544 old_pos
= sInfo
.nPos
;
1546 switch (LOWORD(wParam
))
1557 sInfo
.nPos
-= sInfo
.nPage
;
1561 sInfo
.nPos
+= sInfo
.nPage
;
1565 sInfo
.nPos
= sInfo
.nTrackPos
;
1566 ConioPause(Console
, PAUSED_FROM_SCROLLBAR
);
1569 case SB_THUMBPOSITION
:
1570 ConioUnpause(Console
, PAUSED_FROM_SCROLLBAR
);
1574 sInfo
.nPos
= sInfo
.nMin
;
1578 sInfo
.nPos
= sInfo
.nMax
;
1585 sInfo
.nPos
= max(sInfo
.nPos
, 0);
1586 sInfo
.nPos
= min(sInfo
.nPos
, Maximum
);
1588 if (old_pos
!= sInfo
.nPos
)
1590 USHORT OldX
= Buff
->ViewOrigin
.X
;
1591 USHORT OldY
= Buff
->ViewOrigin
.Y
;
1592 UINT WidthUnit
, HeightUnit
;
1594 *pShowXY
= sInfo
.nPos
;
1596 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
1598 ScrollWindowEx(GuiData
->hWindow
,
1599 (OldX
- Buff
->ViewOrigin
.X
) * WidthUnit
,
1600 (OldY
- Buff
->ViewOrigin
.Y
) * HeightUnit
,
1607 sInfo
.fMask
= SIF_POS
;
1608 SetScrollInfo(GuiData
->hWindow
, fnBar
, &sInfo
, TRUE
);
1610 UpdateWindow(GuiData
->hWindow
);
1611 // InvalidateRect(GuiData->hWindow, NULL, FALSE);
1615 LeaveCriticalSection(&Console
->Lock
);
1621 EnterFullScreen(PGUI_CONSOLE_DATA GuiData
);
1623 LeaveFullScreen(PGUI_CONSOLE_DATA GuiData
);
1625 SwitchFullScreen(PGUI_CONSOLE_DATA GuiData
, BOOL FullScreen
);
1627 GuiConsoleSwitchFullScreen(PGUI_CONSOLE_DATA GuiData
);
1629 static LRESULT CALLBACK
1630 GuiConsoleWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1633 PGUI_CONSOLE_DATA GuiData
= NULL
;
1634 PCONSOLE Console
= NULL
;
1637 * - If it's the first time we create a window for the terminal,
1638 * just initialize it and return.
1640 * - If we are destroying the window, just do it and return.
1642 if (msg
== WM_NCCREATE
)
1644 return (LRESULT
)GuiConsoleHandleNcCreate(hWnd
, (LPCREATESTRUCTW
)lParam
);
1646 else if (msg
== WM_NCDESTROY
)
1648 return GuiConsoleHandleNcDestroy(hWnd
);
1652 * Now the terminal window is initialized.
1653 * Get the terminal data via the window's data.
1654 * If there is no data, just go away.
1656 GuiData
= GuiGetGuiData(hWnd
);
1657 if (GuiData
== NULL
) return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1659 // TEMPORARY HACK until all of the functions can deal with a NULL GuiData->ActiveBuffer ...
1660 if (GuiData
->ActiveBuffer
== NULL
) return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1663 * Just retrieve a pointer to the console in case somebody needs it.
1664 * It is not NULL because it was checked in GuiGetGuiData.
1665 * Each helper function which needs the console has to validate and lock it.
1667 Console
= GuiData
->Console
;
1669 /* We have a console, start message dispatching */
1674 WORD ActivationState
= LOWORD(wParam
);
1676 DPRINT1("WM_ACTIVATE - ActivationState = %d\n");
1678 if ( ActivationState
== WA_ACTIVE
||
1679 ActivationState
== WA_CLICKACTIVE
)
1681 if (GuiData
->GuiInfo
.FullScreen
)
1683 EnterFullScreen(GuiData
);
1684 // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
1685 // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
1688 else // if (ActivationState == WA_INACTIVE)
1690 if (GuiData
->GuiInfo
.FullScreen
)
1692 SendMessageW(GuiData
->hWindow
, WM_SYSCOMMAND
, SC_MINIMIZE
, 0);
1693 LeaveFullScreen(GuiData
);
1694 // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
1695 // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
1699 if (ActivationState
== WA_CLICKACTIVE
) GuiData
->IgnoreNextMouseSignal
= TRUE
;
1705 if (GuiConsoleHandleClose(GuiData
)) goto Default
;
1709 GuiConsoleHandlePaint(GuiData
);
1712 case WM_PALETTECHANGED
:
1714 PCONSOLE_SCREEN_BUFFER ActiveBuffer
= GuiData
->ActiveBuffer
;
1716 DPRINT("WM_PALETTECHANGED called\n");
1719 * Protects against infinite loops:
1720 * "... A window that receives this message must not realize
1721 * its palette, unless it determines that wParam does not contain
1722 * its own window handle." (WM_PALETTECHANGED description - MSDN)
1724 * This message is sent to all windows, including the one that
1725 * changed the system palette and caused this message to be sent.
1726 * The wParam of this message contains the handle of the window
1727 * that caused the system palette to change. To avoid an infinite
1728 * loop, care must be taken to check that the wParam of this message
1729 * does not match the window's handle.
1731 if ((HWND
)wParam
== hWnd
) break;
1733 DPRINT("WM_PALETTECHANGED ok\n");
1735 // if (GetType(ActiveBuffer) == GRAPHICS_BUFFER)
1736 if (ActiveBuffer
->PaletteHandle
)
1738 DPRINT("WM_PALETTECHANGED changing palette\n");
1740 /* Specify the use of the system palette for the framebuffer */
1741 SetSystemPaletteUse(GuiData
->hMemDC
, ActiveBuffer
->PaletteUsage
);
1743 /* Realize the (logical) palette */
1744 RealizePalette(GuiData
->hMemDC
);
1747 DPRINT("WM_PALETTECHANGED quit\n");
1759 case WM_SYSDEADCHAR
:
1761 /* Detect Alt-Enter presses and switch back and forth to fullscreen mode */
1762 if (msg
== WM_SYSKEYDOWN
&& (HIWORD(lParam
) & KF_ALTDOWN
) && wParam
== VK_RETURN
)
1764 /* Switch only at first Alt-Enter press, and ignore subsequent key repetitions */
1765 if ((HIWORD(lParam
) & (KF_UP
| KF_REPEAT
)) != KF_REPEAT
)
1766 GuiConsoleSwitchFullScreen(GuiData
);
1771 GuiConsoleHandleKey(GuiData
, msg
, wParam
, lParam
);
1776 GuiConsoleHandleTimer(GuiData
);
1782 * The message was sent because we are manually triggering a change.
1783 * Check whether the mouse is indeed present on this console window
1784 * and take appropriate decisions.
1786 if (wParam
== -1 && lParam
== -1)
1791 /* Get the placement of the mouse */
1792 GetCursorPos(&mouseCoords
);
1794 /* On which window is placed the mouse ? */
1795 hWndHit
= WindowFromPoint(mouseCoords
);
1797 /* It's our window. Perform the hit-test to be used later on. */
1798 if (hWndHit
== hWnd
)
1800 wParam
= (WPARAM
)hWnd
;
1801 lParam
= DefWindowProcW(hWndHit
, WM_NCHITTEST
, 0,
1802 MAKELPARAM(mouseCoords
.x
, mouseCoords
.y
));
1806 /* Set the mouse cursor only when we are in the client area */
1807 if ((HWND
)wParam
== hWnd
&& LOWORD(lParam
) == HTCLIENT
)
1809 if (GuiData
->MouseCursorRefCount
>= 0)
1811 /* Show the cursor */
1812 SetCursor(GuiData
->hCursor
);
1816 /* Hide the cursor if the reference count is negative */
1827 case WM_LBUTTONDOWN
:
1828 case WM_MBUTTONDOWN
:
1829 case WM_RBUTTONDOWN
:
1833 case WM_LBUTTONDBLCLK
:
1834 case WM_MBUTTONDBLCLK
:
1835 case WM_RBUTTONDBLCLK
:
1838 case WM_MOUSEHWHEEL
:
1840 Result
= GuiConsoleHandleMouse(GuiData
, msg
, wParam
, lParam
);
1847 Result
= GuiConsoleHandleScroll(GuiData
, msg
, wParam
);
1851 case WM_NCRBUTTONDOWN
:
1853 DPRINT1("WM_NCRBUTTONDOWN\n");
1855 * HACK: !! Because, when we deal with WM_RBUTTON* and we do not
1856 * call after that DefWindowProc, on ReactOS, right-clicks on the
1857 * (non-client) application title-bar does not display the system
1858 * menu and does not trigger a WM_NCRBUTTONUP message too.
1859 * See: http://git.reactos.org/?p=reactos.git;a=blob;f=reactos/win32ss/user/user32/windows/defwnd.c;hb=332bc8f482f40fd05ab510f78276576719fbfba8#l1103
1860 * and line 1135 too.
1863 if (DefWindowProcW(hWnd
, WM_NCHITTEST
, 0, lParam
) == HTCAPTION
)
1865 /* Call DefWindowProcW with the WM_CONTEXTMENU message */
1866 msg
= WM_CONTEXTMENU
;
1871 // case WM_NCRBUTTONUP:
1872 // DPRINT1("WM_NCRBUTTONUP\n");
1875 case WM_CONTEXTMENU
:
1877 if (DefWindowProcW(hWnd
/*GuiData->hWindow*/, WM_NCHITTEST
, 0, lParam
) == HTCLIENT
)
1879 HMENU hMenu
= CreatePopupMenu();
1882 GuiConsoleAppendMenuItems(hMenu
, GuiConsoleEditMenuItems
);
1883 TrackPopupMenuEx(hMenu
,
1885 GET_X_LPARAM(lParam
),
1886 GET_Y_LPARAM(lParam
),
1901 HMENU hMenu
= (HMENU
)wParam
;
1904 /* Enable or disable the Close menu item */
1905 EnableMenuItem(hMenu
, SC_CLOSE
, MF_BYCOMMAND
|
1906 (GuiData
->IsCloseButtonEnabled
? MF_ENABLED
: MF_GRAYED
));
1908 /* Enable or disable the Copy and Paste items */
1909 EnableMenuItem(hMenu
, ID_SYSTEM_EDIT_COPY
, MF_BYCOMMAND
|
1910 ((Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) &&
1911 (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
) ? MF_ENABLED
: MF_GRAYED
));
1912 EnableMenuItem(hMenu
, ID_SYSTEM_EDIT_PASTE
, MF_BYCOMMAND
|
1913 (!(Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) &&
1914 IsClipboardFormatAvailable(CF_UNICODETEXT
) ? MF_ENABLED
: MF_GRAYED
));
1917 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1919 GuiSendMenuEvent(Console
, WM_INITMENU
);
1920 LeaveCriticalSection(&Console
->Lock
);
1927 if (HIWORD(wParam
) == 0xFFFF) // Allow all the menu flags
1929 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1931 GuiSendMenuEvent(Console
, WM_MENUSELECT
);
1932 LeaveCriticalSection(&Console
->Lock
);
1941 Result
= GuiConsoleHandleSysMenuCommand(GuiData
, wParam
, lParam
);
1948 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1950 BOOL SetFocus
= (msg
== WM_SETFOCUS
);
1953 er
.EventType
= FOCUS_EVENT
;
1954 er
.Event
.FocusEvent
.bSetFocus
= SetFocus
;
1955 ConioProcessInputEvent(Console
, &er
);
1958 DPRINT1("TODO: Create console caret\n");
1960 DPRINT1("TODO: Destroy console caret\n");
1962 LeaveCriticalSection(&Console
->Lock
);
1967 case WM_GETMINMAXINFO
:
1968 GuiConsoleGetMinMaxInfo(GuiData
, (PMINMAXINFO
)lParam
);
1972 GuiConsoleResize(GuiData
, wParam
, lParam
);
1975 case PM_RESIZE_TERMINAL
:
1977 PCONSOLE_SCREEN_BUFFER Buff
= GuiData
->ActiveBuffer
;
1981 DWORD Width
, Height
;
1982 UINT WidthUnit
, HeightUnit
;
1984 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
1986 Width
= Buff
->ScreenBufferSize
.X
* WidthUnit
;
1987 Height
= Buff
->ScreenBufferSize
.Y
* HeightUnit
;
1989 /* Recreate the framebuffer */
1990 hDC
= GetDC(GuiData
->hWindow
);
1991 hnew
= CreateCompatibleBitmap(hDC
, Width
, Height
);
1992 ReleaseDC(GuiData
->hWindow
, hDC
);
1993 hold
= SelectObject(GuiData
->hMemDC
, hnew
);
1994 if (GuiData
->hBitmap
)
1996 if (hold
== GuiData
->hBitmap
) DeleteObject(GuiData
->hBitmap
);
1998 GuiData
->hBitmap
= hnew
;
2000 /* Resize the window to the user's values */
2001 GuiData
->WindowSizeLock
= TRUE
;
2002 GuiConsoleResizeWindow(GuiData
, WidthUnit
, HeightUnit
);
2003 GuiData
->WindowSizeLock
= FALSE
;
2007 case PM_APPLY_CONSOLE_INFO
:
2009 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
2011 GuiApplyUserSettings(GuiData
, (HANDLE
)wParam
, (BOOL
)lParam
);
2012 LeaveCriticalSection(&Console
->Lock
);
2017 case PM_CONSOLE_BEEP
:
2018 DPRINT1("Beep !!\n");
2022 // case PM_CONSOLE_SET_TITLE:
2023 // SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
2027 Result
= DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
2036 /******************************************************************************
2037 * GUI Terminal Initialization *
2038 ******************************************************************************/
2040 static LRESULT CALLBACK
2041 GuiConsoleNotifyWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
2051 SetWindowLongW(hWnd
, GWL_USERDATA
, 0);
2055 case PM_CREATE_CONSOLE
:
2057 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)lParam
;
2058 PCONSOLE Console
= GuiData
->Console
;
2060 NewWindow
= CreateWindowExW(WS_EX_CLIENTEDGE
,
2061 GUI_CONSOLE_WINDOW_CLASS
,
2062 Console
->Title
.Buffer
,
2063 WS_OVERLAPPEDWINDOW
| WS_HSCROLL
| WS_VSCROLL
,
2072 if (NULL
!= NewWindow
)
2074 ASSERT(NewWindow
== GuiData
->hWindow
);
2076 WindowCount
= GetWindowLongW(hWnd
, GWL_USERDATA
);
2078 SetWindowLongW(hWnd
, GWL_USERDATA
, WindowCount
);
2080 DPRINT("Set icons via PM_CREATE_CONSOLE\n");
2081 if (GuiData
->hIcon
== NULL
)
2083 DPRINT("Not really /o\\...\n");
2084 GuiData
->hIcon
= ghDefaultIcon
;
2085 GuiData
->hIconSm
= ghDefaultIconSm
;
2087 else if (GuiData
->hIcon
!= ghDefaultIcon
)
2089 DPRINT("Yes \\o/\n");
2090 SendMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
2091 SendMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
2094 /* Move and resize the window to the user's values */
2095 /* CAN WE DEADLOCK ?? */
2096 GuiConsoleMoveWindow(GuiData
);
2097 SendMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
2099 /* Switch to full-screen mode if necessary */
2100 if (GuiData
->GuiInfo
.FullScreen
) SwitchFullScreen(GuiData
, TRUE
);
2102 // ShowWindow(NewWindow, (int)wParam);
2103 ShowWindowAsync(NewWindow
, (int)wParam
);
2104 DPRINT("Window showed\n");
2107 return (LRESULT
)NewWindow
;
2110 case PM_DESTROY_CONSOLE
:
2112 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)lParam
;
2114 /* Exit the full screen mode if it was already set */
2115 // LeaveFullScreen(GuiData);
2118 * Window creation is done using a PostMessage(), so it's possible
2119 * that the window that we want to destroy doesn't exist yet.
2120 * So first empty the message queue.
2123 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
2125 TranslateMessage(&Msg);
2126 DispatchMessageW(&Msg);
2128 while (PeekMessageW(&Msg
, NULL
, 0, 0, PM_REMOVE
)) ;
2130 if (GuiData
->hWindow
!= NULL
) /* && DestroyWindow(GuiData->hWindow) */
2132 DestroyWindow(GuiData
->hWindow
);
2134 WindowCount
= GetWindowLongW(hWnd
, GWL_USERDATA
);
2136 SetWindowLongW(hWnd
, GWL_USERDATA
, WindowCount
);
2137 if (0 == WindowCount
)
2140 DestroyWindow(hWnd
);
2141 DPRINT("CONSRV: Going to quit the Gui Thread!!\n");
2150 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
2155 GuiConsoleGuiThread(PVOID Data
)
2158 PHANDLE GraphicsStartupEvent
= (PHANDLE
)Data
;
2161 * This thread dispatches all the console notifications to the notify window.
2162 * It is common for all the console windows.
2165 PrivateCsrssManualGuiCheck(+1);
2167 NotifyWnd
= CreateWindowW(L
"ConSrvCreateNotify",
2169 WS_OVERLAPPEDWINDOW
,
2178 if (NULL
== NotifyWnd
)
2180 PrivateCsrssManualGuiCheck(-1);
2181 SetEvent(*GraphicsStartupEvent
);
2185 SetEvent(*GraphicsStartupEvent
);
2187 while (GetMessageW(&msg
, NULL
, 0, 0))
2189 TranslateMessage(&msg
);
2190 DispatchMessageW(&msg
);
2193 DPRINT("CONSRV: Quit the Gui Thread!!\n");
2194 PrivateCsrssManualGuiCheck(-1);
2203 ATOM ConsoleClassAtom
;
2205 /* Exit if we were already initialized */
2206 // if (ConsInitialized) return TRUE;
2209 * Initialize and register the different window classes, if needed.
2211 if (!ConsInitialized
)
2213 /* Initialize the notification window class */
2214 wc
.cbSize
= sizeof(WNDCLASSEXW
);
2215 wc
.lpszClassName
= L
"ConSrvCreateNotify";
2216 wc
.lpfnWndProc
= GuiConsoleNotifyWndProc
;
2218 wc
.hInstance
= ConSrvDllInstance
;
2222 wc
.hbrBackground
= NULL
;
2223 wc
.lpszMenuName
= NULL
;
2226 if (RegisterClassExW(&wc
) == 0)
2228 DPRINT1("Failed to register GUI notify wndproc\n");
2232 /* Initialize the console window class */
2233 ghDefaultIcon
= LoadImageW(ConSrvDllInstance
,
2234 MAKEINTRESOURCEW(IDI_TERMINAL
),
2236 GetSystemMetrics(SM_CXICON
),
2237 GetSystemMetrics(SM_CYICON
),
2239 ghDefaultIconSm
= LoadImageW(ConSrvDllInstance
,
2240 MAKEINTRESOURCEW(IDI_TERMINAL
),
2242 GetSystemMetrics(SM_CXSMICON
),
2243 GetSystemMetrics(SM_CYSMICON
),
2245 ghDefaultCursor
= LoadCursorW(NULL
, IDC_ARROW
);
2246 wc
.cbSize
= sizeof(WNDCLASSEXW
);
2247 wc
.lpszClassName
= GUI_CONSOLE_WINDOW_CLASS
;
2248 wc
.lpfnWndProc
= GuiConsoleWndProc
;
2249 wc
.style
= CS_DBLCLKS
/* | CS_HREDRAW | CS_VREDRAW */;
2250 wc
.hInstance
= ConSrvDllInstance
;
2251 wc
.hIcon
= ghDefaultIcon
;
2252 wc
.hIconSm
= ghDefaultIconSm
;
2253 wc
.hCursor
= ghDefaultCursor
;
2254 wc
.hbrBackground
= (HBRUSH
)GetStockObject(BLACK_BRUSH
); // The color of a terminal when it is switch off.
2255 wc
.lpszMenuName
= NULL
;
2257 wc
.cbWndExtra
= GWLP_CONSOLEWND_ALLOC
;
2259 ConsoleClassAtom
= RegisterClassExW(&wc
);
2260 if (ConsoleClassAtom
== 0)
2262 DPRINT1("Failed to register GUI console wndproc\n");
2267 NtUserConsoleControl(GuiConsoleWndClassAtom
, &ConsoleClassAtom
, sizeof(ATOM
));
2270 ConsInitialized
= TRUE
;
2274 * Set-up the notification window
2276 if (NULL
== NotifyWnd
)
2278 HANDLE ThreadHandle
;
2279 HANDLE GraphicsStartupEvent
;
2281 GraphicsStartupEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
2282 if (NULL
== GraphicsStartupEvent
) return FALSE
;
2284 ThreadHandle
= CreateThread(NULL
,
2286 GuiConsoleGuiThread
,
2287 (PVOID
)&GraphicsStartupEvent
,
2290 if (NULL
== ThreadHandle
)
2292 CloseHandle(GraphicsStartupEvent
);
2293 DPRINT1("CONSRV: Failed to create graphics console thread. Expect problems\n");
2296 SetThreadPriority(ThreadHandle
, THREAD_PRIORITY_HIGHEST
);
2297 CloseHandle(ThreadHandle
);
2299 WaitForSingleObject(GraphicsStartupEvent
, INFINITE
);
2300 CloseHandle(GraphicsStartupEvent
);
2302 if (NULL
== NotifyWnd
)
2304 DPRINT1("CONSRV: Failed to create notification window.\n");
2309 // ConsInitialized = TRUE;
2316 /******************************************************************************
2317 * GUI Console Driver *
2318 ******************************************************************************/
2321 GuiDeinitFrontEnd(IN OUT PFRONTEND This
);
2324 GuiInitFrontEnd(IN OUT PFRONTEND This
,
2325 IN PCONSOLE Console
)
2327 PGUI_INIT_INFO GuiInitInfo
;
2328 PCONSOLE_INFO ConsoleInfo
;
2329 PCONSOLE_START_INFO ConsoleStartInfo
;
2331 PGUI_CONSOLE_DATA GuiData
;
2332 GUI_CONSOLE_INFO TermInfo
;
2335 LPWSTR IconPath
= NULL
;
2338 if (This
== NULL
|| Console
== NULL
|| This
->OldData
== NULL
)
2339 return STATUS_INVALID_PARAMETER
;
2341 ASSERT(This
->Console
== Console
);
2343 GuiInitInfo
= This
->OldData
;
2345 if (GuiInitInfo
->ConsoleInfo
== NULL
|| GuiInitInfo
->ConsoleStartInfo
== NULL
)
2346 return STATUS_INVALID_PARAMETER
;
2348 ConsoleInfo
= GuiInitInfo
->ConsoleInfo
;
2349 ConsoleStartInfo
= GuiInitInfo
->ConsoleStartInfo
;
2351 IconPath
= ConsoleStartInfo
->IconPath
;
2352 IconIndex
= ConsoleStartInfo
->IconIndex
;
2355 /* Terminal data allocation */
2356 GuiData
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_CONSOLE_DATA
));
2359 DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
2360 return STATUS_UNSUCCESSFUL
;
2362 /* HACK */ Console
->TermIFace
.Data
= (PVOID
)GuiData
; /* HACK */
2363 GuiData
->Console
= Console
;
2364 GuiData
->ActiveBuffer
= Console
->ActiveBuffer
;
2365 GuiData
->hWindow
= NULL
;
2367 /* The console can be resized */
2368 Console
->FixedSize
= FALSE
;
2370 InitializeCriticalSection(&GuiData
->Lock
);
2374 * Load terminal settings
2377 /* 1. Load the default settings */
2378 GuiConsoleGetDefaultSettings(&TermInfo
, GuiInitInfo
->ProcessId
);
2380 /* 3. Load the remaining console settings via the registry. */
2381 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
2383 /* Load the terminal infos from the registry. */
2384 GuiConsoleReadUserSettings(&TermInfo
,
2385 ConsoleInfo
->ConsoleTitle
,
2386 GuiInitInfo
->ProcessId
);
2389 * Now, update them with the properties the user might gave to us
2390 * via the STARTUPINFO structure before calling CreateProcess
2391 * (and which was transmitted via the ConsoleStartInfo structure).
2392 * We therefore overwrite the values read in the registry.
2394 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USESHOWWINDOW
)
2396 TermInfo
.ShowWindow
= ConsoleStartInfo
->wShowWindow
;
2398 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USEPOSITION
)
2400 TermInfo
.AutoPosition
= FALSE
;
2401 TermInfo
.WindowOrigin
.x
= ConsoleStartInfo
->dwWindowOrigin
.X
;
2402 TermInfo
.WindowOrigin
.y
= ConsoleStartInfo
->dwWindowOrigin
.Y
;
2404 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_RUNFULLSCREEN
)
2406 TermInfo
.FullScreen
= TRUE
;
2415 Length
= min(wcslen(TermInfo
.FaceName
) + 1, LF_FACESIZE
); // wcsnlen
2416 wcsncpy(GuiData
->GuiInfo
.FaceName
, TermInfo
.FaceName
, LF_FACESIZE
);
2417 GuiData
->GuiInfo
.FaceName
[Length
] = L
'\0';
2418 GuiData
->GuiInfo
.FontFamily
= TermInfo
.FontFamily
;
2419 GuiData
->GuiInfo
.FontSize
= TermInfo
.FontSize
;
2420 GuiData
->GuiInfo
.FontWeight
= TermInfo
.FontWeight
;
2421 GuiData
->GuiInfo
.UseRasterFonts
= TermInfo
.UseRasterFonts
;
2422 GuiData
->GuiInfo
.FullScreen
= TermInfo
.FullScreen
;
2423 GuiData
->GuiInfo
.ShowWindow
= TermInfo
.ShowWindow
;
2424 GuiData
->GuiInfo
.AutoPosition
= TermInfo
.AutoPosition
;
2425 GuiData
->GuiInfo
.WindowOrigin
= TermInfo
.WindowOrigin
;
2427 /* Initialize the icon handles to their default values */
2428 GuiData
->hIcon
= ghDefaultIcon
;
2429 GuiData
->hIconSm
= ghDefaultIconSm
;
2431 /* Get the associated icon, if any */
2432 if (IconPath
== NULL
|| IconPath
[0] == L
'\0')
2434 IconPath
= ConsoleStartInfo
->AppPath
;
2437 DPRINT("IconPath = %S ; IconIndex = %lu\n", (IconPath
? IconPath
: L
"n/a"), IconIndex
);
2438 if (IconPath
&& IconPath
[0] != L
'\0')
2440 HICON hIcon
= NULL
, hIconSm
= NULL
;
2441 PrivateExtractIconExW(IconPath
,
2446 DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon
, hIconSm
);
2449 DPRINT("Effectively set the icons\n");
2450 GuiData
->hIcon
= hIcon
;
2451 GuiData
->hIconSm
= hIconSm
;
2455 /* Mouse is shown by default with its default cursor shape */
2456 GuiData
->hCursor
= ghDefaultCursor
;
2457 GuiData
->MouseCursorRefCount
= 0;
2459 /* A priori don't ignore mouse signals */
2460 GuiData
->IgnoreNextMouseSignal
= FALSE
;
2462 /* Close button and the corresponding system menu item are enabled by default */
2463 GuiData
->IsCloseButtonEnabled
= TRUE
;
2465 /* There is no user-reserved menu id range by default */
2466 GuiData
->CmdIdLow
= GuiData
->CmdIdHigh
= 0;
2469 * We need to wait until the GUI has been fully initialized
2470 * to retrieve custom settings i.e. WindowSize etc...
2471 * Ideally we could use SendNotifyMessage for this but its not
2474 GuiData
->hGuiInitEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
2476 DPRINT("GUI - Checkpoint\n");
2478 /* Create the terminal window */
2479 PostMessageW(NotifyWnd
, PM_CREATE_CONSOLE
, GuiData
->GuiInfo
.ShowWindow
, (LPARAM
)GuiData
);
2481 /* Wait until initialization has finished */
2482 WaitForSingleObject(GuiData
->hGuiInitEvent
, INFINITE
);
2483 DPRINT("OK we created the console window\n");
2484 CloseHandle(GuiData
->hGuiInitEvent
);
2485 GuiData
->hGuiInitEvent
= NULL
;
2487 /* Check whether we really succeeded in initializing the terminal window */
2488 if (GuiData
->hWindow
== NULL
)
2490 DPRINT("GuiInitConsole - We failed at creating a new terminal window\n");
2491 GuiDeinitFrontEnd(This
);
2492 return STATUS_UNSUCCESSFUL
;
2495 /* Finally, finish to initialize the frontend structure */
2496 This
->Data
= GuiData
;
2497 if (This
->OldData
) ConsoleFreeHeap(This
->OldData
);
2498 This
->OldData
= NULL
;
2500 return STATUS_SUCCESS
;
2504 GuiDeinitFrontEnd(IN OUT PFRONTEND This
)
2506 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2508 SendMessageW(NotifyWnd
, PM_DESTROY_CONSOLE
, 0, (LPARAM
)GuiData
);
2510 DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
2511 GuiData
->hIcon
, ghDefaultIcon
, GuiData
->hIconSm
, ghDefaultIconSm
);
2512 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
2514 DPRINT("Destroy hIcon\n");
2515 DestroyIcon(GuiData
->hIcon
);
2517 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
2519 DPRINT("Destroy hIconSm\n");
2520 DestroyIcon(GuiData
->hIconSm
);
2524 DeleteCriticalSection(&GuiData
->Lock
);
2525 ConsoleFreeHeap(GuiData
);
2527 DPRINT("Quit GuiDeinitFrontEnd\n");
2531 GuiDrawRegion(IN OUT PFRONTEND This
,
2534 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2537 SmallRectToRect(GuiData
, &RegionRect
, Region
);
2538 /* Do not erase the background: it speeds up redrawing and reduce flickering */
2539 InvalidateRect(GuiData
->hWindow
, &RegionRect
, FALSE
);
2540 /**UpdateWindow(GuiData->hWindow);**/
2544 GuiWriteStream(IN OUT PFRONTEND This
,
2552 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2553 PCONSOLE_SCREEN_BUFFER Buff
;
2554 SHORT CursorEndX
, CursorEndY
;
2557 if (NULL
== GuiData
|| NULL
== GuiData
->hWindow
) return;
2559 Buff
= GuiData
->ActiveBuffer
;
2560 if (GetType(Buff
) != TEXTMODE_BUFFER
) return;
2562 if (0 != ScrolledLines
)
2564 ScrollRect
.left
= 0;
2566 ScrollRect
.right
= Buff
->ViewSize
.X
* GuiData
->CharWidth
;
2567 ScrollRect
.bottom
= Region
->Top
* GuiData
->CharHeight
;
2569 ScrollWindowEx(GuiData
->hWindow
,
2571 -(int)(ScrolledLines
* GuiData
->CharHeight
),
2579 GuiDrawRegion(This
, Region
);
2581 if (CursorStartX
< Region
->Left
|| Region
->Right
< CursorStartX
2582 || CursorStartY
< Region
->Top
|| Region
->Bottom
< CursorStartY
)
2584 GuiInvalidateCell(This
, CursorStartX
, CursorStartY
);
2587 CursorEndX
= Buff
->CursorPosition
.X
;
2588 CursorEndY
= Buff
->CursorPosition
.Y
;
2589 if ((CursorEndX
< Region
->Left
|| Region
->Right
< CursorEndX
2590 || CursorEndY
< Region
->Top
|| Region
->Bottom
< CursorEndY
)
2591 && (CursorEndX
!= CursorStartX
|| CursorEndY
!= CursorStartY
))
2593 GuiInvalidateCell(This
, CursorEndX
, CursorEndY
);
2596 // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
2597 // repaint the window without having it just freeze up and stay on the screen permanently.
2598 Buff
->CursorBlinkOn
= TRUE
;
2599 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
2603 GuiSetCursorInfo(IN OUT PFRONTEND This
,
2604 PCONSOLE_SCREEN_BUFFER Buff
)
2606 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2608 if (GuiData
->ActiveBuffer
== Buff
)
2610 GuiInvalidateCell(This
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
2617 GuiSetScreenInfo(IN OUT PFRONTEND This
,
2618 PCONSOLE_SCREEN_BUFFER Buff
,
2622 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2624 if (GuiData
->ActiveBuffer
== Buff
)
2626 /* Redraw char at old position (remove cursor) */
2627 GuiInvalidateCell(This
, OldCursorX
, OldCursorY
);
2628 /* Redraw char at new position (show cursor) */
2629 GuiInvalidateCell(This
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
2636 GuiResizeTerminal(IN OUT PFRONTEND This
)
2638 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2640 /* Resize the window to the user's values */
2641 PostMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
2645 GuiSetActiveScreenBuffer(IN OUT PFRONTEND This
)
2647 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2648 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
2651 EnterCriticalSection(&GuiData
->Lock
);
2652 GuiData
->WindowSizeLock
= TRUE
;
2654 InterlockedExchangePointer(&GuiData
->ActiveBuffer
,
2655 ConDrvGetActiveScreenBuffer(GuiData
->Console
));
2657 GuiData
->WindowSizeLock
= FALSE
;
2658 LeaveCriticalSection(&GuiData
->Lock
);
2660 ActiveBuffer
= GuiData
->ActiveBuffer
;
2662 /* Change the current palette */
2663 if (ActiveBuffer
->PaletteHandle
== NULL
)
2665 hPalette
= GuiData
->hSysPalette
;
2669 hPalette
= ActiveBuffer
->PaletteHandle
;
2672 DPRINT1("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette
);
2674 /* Set the new palette for the framebuffer */
2675 SelectPalette(GuiData
->hMemDC
, hPalette
, FALSE
);
2677 /* Specify the use of the system palette for the framebuffer */
2678 SetSystemPaletteUse(GuiData
->hMemDC
, ActiveBuffer
->PaletteUsage
);
2680 /* Realize the (logical) palette */
2681 RealizePalette(GuiData
->hMemDC
);
2683 GuiResizeTerminal(This
);
2684 // ConioDrawConsole(Console);
2688 GuiReleaseScreenBuffer(IN OUT PFRONTEND This
,
2689 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer
)
2691 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2694 * If we were notified to release a screen buffer that is not actually
2695 * ours, then just ignore the notification...
2697 if (ScreenBuffer
!= GuiData
->ActiveBuffer
) return;
2700 * ... else, we must release our active buffer. Two cases are present:
2701 * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console
2702 * active screen buffer, then we can safely switch to it.
2703 * - If ScreenBuffer IS the console active screen buffer, we must release
2707 /* Release the old active palette and set the default one */
2708 if (GetCurrentObject(GuiData
->hMemDC
, OBJ_PAL
) == ScreenBuffer
->PaletteHandle
)
2710 /* Set the new palette */
2711 SelectPalette(GuiData
->hMemDC
, GuiData
->hSysPalette
, FALSE
);
2714 /* Set the adequate active screen buffer */
2715 if (ScreenBuffer
!= GuiData
->Console
->ActiveBuffer
)
2717 GuiSetActiveScreenBuffer(This
);
2721 EnterCriticalSection(&GuiData
->Lock
);
2722 GuiData
->WindowSizeLock
= TRUE
;
2724 InterlockedExchangePointer(&GuiData
->ActiveBuffer
, NULL
);
2726 GuiData
->WindowSizeLock
= FALSE
;
2727 LeaveCriticalSection(&GuiData
->Lock
);
2732 GuiProcessKeyCallback(IN OUT PFRONTEND This
,
2736 UINT VirtualKeyCode
,
2739 if ((ShiftState
& (RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
) || KeyStateMenu
& 0x80) &&
2740 (VirtualKeyCode
== VK_ESCAPE
|| VirtualKeyCode
== VK_TAB
|| VirtualKeyCode
== VK_SPACE
))
2742 DefWindowProcW(msg
->hwnd
, msg
->message
, msg
->wParam
, msg
->lParam
);
2750 GuiSetMouseCursor(IN OUT PFRONTEND This
,
2751 HCURSOR CursorHandle
);
2754 GuiRefreshInternalInfo(IN OUT PFRONTEND This
)
2756 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2758 /* Update the console leader information held by the window */
2759 SetConsoleWndConsoleLeaderCID(GuiData
);
2763 * We reset the cursor here so that, when a console app quits, we reset
2764 * the cursor to the default one. It's quite a hack since it doesn't proceed
2765 * per - console process... This must be fixed.
2767 * See GuiInitConsole(...) for more information.
2770 /* Mouse is shown by default with its default cursor shape */
2771 GuiData
->MouseCursorRefCount
= 0; // Reinitialize the reference counter
2772 GuiSetMouseCursor(This
, NULL
);
2776 GuiChangeTitle(IN OUT PFRONTEND This
)
2778 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2779 // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
2780 SetWindowText(GuiData
->hWindow
, GuiData
->Console
->Title
.Buffer
);
2784 GuiChangeIcon(IN OUT PFRONTEND This
,
2787 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2788 HICON hIcon
, hIconSm
;
2790 if (IconHandle
== NULL
)
2792 hIcon
= ghDefaultIcon
;
2793 hIconSm
= ghDefaultIconSm
;
2797 hIcon
= CopyIcon(IconHandle
);
2798 hIconSm
= CopyIcon(IconHandle
);
2806 if (hIcon
!= GuiData
->hIcon
)
2808 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
2810 DestroyIcon(GuiData
->hIcon
);
2812 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
2814 DestroyIcon(GuiData
->hIconSm
);
2817 GuiData
->hIcon
= hIcon
;
2818 GuiData
->hIconSm
= hIconSm
;
2820 DPRINT("Set icons in GuiChangeIcon\n");
2821 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
2822 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
2829 GuiGetConsoleWindowHandle(IN OUT PFRONTEND This
)
2831 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2832 return GuiData
->hWindow
;
2836 GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This
,
2839 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2840 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
2843 UINT WidthUnit
, HeightUnit
;
2847 if (!SystemParametersInfoW(SPI_GETWORKAREA
, 0, &WorkArea
, 0))
2849 DPRINT1("SystemParametersInfoW failed - What to do ??\n");
2853 ActiveBuffer
= GuiData
->ActiveBuffer
;
2856 GetScreenBufferSizeUnits(ActiveBuffer
, GuiData
, &WidthUnit
, &HeightUnit
);
2860 /* Default: text mode */
2861 WidthUnit
= GuiData
->CharWidth
;
2862 HeightUnit
= GuiData
->CharHeight
;
2865 width
= WorkArea
.right
;
2866 height
= WorkArea
.bottom
;
2868 width
-= (2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
)));
2869 height
-= (2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
));
2871 if (width
< 0) width
= 0;
2872 if (height
< 0) height
= 0;
2874 pSize
->X
= (SHORT
)(width
/ (int)WidthUnit
) /* HACK */ + 2;
2875 pSize
->Y
= (SHORT
)(height
/ (int)HeightUnit
) /* HACK */ + 1;
2879 GuiSetPalette(IN OUT PFRONTEND This
,
2880 HPALETTE PaletteHandle
,
2883 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2884 HPALETTE OldPalette
;
2886 // if (GetType(GuiData->ActiveBuffer) != GRAPHICS_BUFFER) return FALSE;
2887 if (PaletteHandle
== NULL
) return FALSE
;
2889 /* Set the new palette for the framebuffer */
2890 OldPalette
= SelectPalette(GuiData
->hMemDC
, PaletteHandle
, FALSE
);
2891 if (OldPalette
== NULL
) return FALSE
;
2893 /* Specify the use of the system palette for the framebuffer */
2894 SetSystemPaletteUse(GuiData
->hMemDC
, PaletteUsage
);
2896 /* Realize the (logical) palette */
2897 RealizePalette(GuiData
->hMemDC
);
2899 /* Save the original system palette handle */
2900 if (GuiData
->hSysPalette
== NULL
) GuiData
->hSysPalette
= OldPalette
;
2906 GuiGetDisplayMode(IN OUT PFRONTEND This
)
2908 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2909 ULONG DisplayMode
= 0;
2911 if (GuiData
->GuiInfo
.FullScreen
)
2912 DisplayMode
|= CONSOLE_FULLSCREEN_HARDWARE
; // CONSOLE_FULLSCREEN
2914 DisplayMode
|= CONSOLE_WINDOWED
;
2920 GuiSetDisplayMode(IN OUT PFRONTEND This
,
2923 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2926 if (NewMode
& ~(CONSOLE_FULLSCREEN_MODE
| CONSOLE_WINDOWED_MODE
))
2929 FullScreen
= ((NewMode
& CONSOLE_FULLSCREEN_MODE
) != 0);
2931 if (FullScreen
!= GuiData
->GuiInfo
.FullScreen
)
2933 SwitchFullScreen(GuiData
, FullScreen
);
2940 GuiShowMouseCursor(IN OUT PFRONTEND This
,
2943 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2945 /* Set the reference count */
2946 if (Show
) ++GuiData
->MouseCursorRefCount
;
2947 else --GuiData
->MouseCursorRefCount
;
2949 /* Effectively show (or hide) the cursor (use special values for (w|l)Param) */
2950 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
2952 return GuiData
->MouseCursorRefCount
;
2956 GuiSetMouseCursor(IN OUT PFRONTEND This
,
2957 HCURSOR CursorHandle
)
2959 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2962 * Set the cursor's handle. If the given handle is NULL,
2963 * then restore the default cursor.
2965 GuiData
->hCursor
= (CursorHandle
? CursorHandle
: ghDefaultCursor
);
2967 /* Effectively modify the shape of the cursor (use special values for (w|l)Param) */
2968 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
2974 GuiMenuControl(IN OUT PFRONTEND This
,
2978 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2980 GuiData
->CmdIdLow
= CmdIdLow
;
2981 GuiData
->CmdIdHigh
= CmdIdHigh
;
2983 return GetSystemMenu(GuiData
->hWindow
, FALSE
);
2987 GuiSetMenuClose(IN OUT PFRONTEND This
,
2991 * NOTE: See http://www.mail-archive.com/harbour@harbour-project.org/msg27509.html
2992 * or http://harbour-devel.1590103.n2.nabble.com/Question-about-hb-gt-win-CtrlHandler-usage-td4670862i20.html
2993 * for more information.
2996 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2997 HMENU hSysMenu
= GetSystemMenu(GuiData
->hWindow
, FALSE
);
2999 if (hSysMenu
== NULL
) return FALSE
;
3001 GuiData
->IsCloseButtonEnabled
= Enable
;
3002 EnableMenuItem(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
| (Enable
? MF_ENABLED
: MF_GRAYED
));
3007 static FRONTEND_VTBL GuiVtbl
=
3016 GuiSetActiveScreenBuffer
,
3017 GuiReleaseScreenBuffer
,
3018 GuiProcessKeyCallback
,
3019 GuiRefreshInternalInfo
,
3022 GuiGetConsoleWindowHandle
,
3023 GuiGetLargestConsoleWindowSize
,
3035 LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo
,
3036 IN OUT PCONSOLE_INFO ConsoleInfo
)
3038 #define PATH_SEPARATOR L'\\'
3040 BOOL RetVal
= FALSE
;
3041 HRESULT hRes
= S_OK
;
3042 LPWSTR LinkName
= NULL
;
3045 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
3048 ConsoleStartInfo
->IconPath
[0] = L
'\0';
3049 ConsoleStartInfo
->IconIndex
= 0;
3051 /* 1- Find the last path separator if any */
3052 LinkName
= wcsrchr(ConsoleStartInfo
->ConsoleTitle
, PATH_SEPARATOR
);
3053 if (LinkName
== NULL
)
3055 LinkName
= ConsoleStartInfo
->ConsoleTitle
;
3059 /* Skip the path separator */
3063 /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
3064 Length
= wcslen(LinkName
);
3065 if ( (Length
<= 4) || (wcsicmp(LinkName
+ (Length
- 4), L
".lnk") != 0) )
3068 /* 3- It may be a link. Try to retrieve some properties */
3069 hRes
= CoInitialize(NULL
);
3070 if (SUCCEEDED(hRes
))
3072 /* Get a pointer to the IShellLink interface */
3073 IShellLinkW
* pshl
= NULL
;
3074 hRes
= CoCreateInstance(&CLSID_ShellLink
,
3076 CLSCTX_INPROC_SERVER
,
3079 if (SUCCEEDED(hRes
))
3081 /* Get a pointer to the IPersistFile interface */
3082 IPersistFile
* ppf
= NULL
;
3083 hRes
= IPersistFile_QueryInterface(pshl
, &IID_IPersistFile
, (LPVOID
*)&ppf
);
3084 if (SUCCEEDED(hRes
))
3086 /* Load the shortcut */
3087 hRes
= IPersistFile_Load(ppf
, ConsoleStartInfo
->ConsoleTitle
, STGM_READ
);
3088 if (SUCCEEDED(hRes
))
3091 * Finally we can get the properties !
3092 * Update the old ones if needed.
3097 /* Reset the name of the console with the name of the shortcut */
3098 Length
= min(/*Length*/ Length
- 4, // 4 == len(".lnk")
3099 sizeof(ConsoleInfo
->ConsoleTitle
) / sizeof(ConsoleInfo
->ConsoleTitle
[0]) - 1);
3100 wcsncpy(ConsoleInfo
->ConsoleTitle
, LinkName
, Length
);
3101 ConsoleInfo
->ConsoleTitle
[Length
] = L
'\0';
3103 /* Get the window showing command */
3104 hRes
= IShellLinkW_GetShowCmd(pshl
, &ShowCmd
);
3105 if (SUCCEEDED(hRes
)) ConsoleStartInfo
->wShowWindow
= (WORD
)ShowCmd
;
3107 /* Get the hotkey */
3108 // hRes = pshl->GetHotkey(&ShowCmd);
3109 // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey;
3111 /* Get the icon location, if any */
3113 hRes
= IShellLinkW_GetIconLocation(pshl
,
3114 ConsoleStartInfo
->IconPath
,
3115 sizeof(ConsoleStartInfo
->IconPath
)/sizeof(ConsoleStartInfo
->IconPath
[0]) - 1, // == MAX_PATH
3116 &ConsoleStartInfo
->IconIndex
);
3117 if (!SUCCEEDED(hRes
))
3119 ConsoleStartInfo
->IconPath
[0] = L
'\0';
3120 ConsoleStartInfo
->IconIndex
= 0;
3123 // FIXME: Since we still don't load console properties from the shortcut,
3124 // return false. When this will be done, we will return true instead.
3127 IPersistFile_Release(ppf
);
3129 IShellLinkW_Release(pshl
);
3138 GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd
,
3139 IN OUT PCONSOLE_INFO ConsoleInfo
,
3140 IN OUT PVOID ExtraConsoleInfo
,
3143 PCONSOLE_START_INFO ConsoleStartInfo
= ExtraConsoleInfo
;
3144 PGUI_INIT_INFO GuiInitInfo
;
3146 if (FrontEnd
== NULL
|| ConsoleInfo
== NULL
|| ConsoleStartInfo
== NULL
)
3147 return STATUS_INVALID_PARAMETER
;
3149 /* Initialize GUI terminal emulator common functionalities */
3150 if (!GuiInit()) return STATUS_UNSUCCESSFUL
;
3153 * Load per-application terminal settings.
3155 * Check whether the process creating the console was launched via
3156 * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the
3157 * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too.
3159 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
)
3161 if (!LoadShellLinkConsoleInfo(ConsoleStartInfo
, ConsoleInfo
))
3163 ConsoleStartInfo
->dwStartupFlags
&= ~STARTF_TITLEISLINKNAME
;
3168 * Initialize a private initialization info structure for later use.
3169 * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd.
3171 GuiInitInfo
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_INIT_INFO
));
3172 if (GuiInitInfo
== NULL
) return STATUS_NO_MEMORY
;
3174 // HACK: We suppose that the pointers will be valid in GuiInitFrontEnd...
3175 GuiInitInfo
->ConsoleInfo
= ConsoleInfo
;
3176 GuiInitInfo
->ConsoleStartInfo
= ConsoleStartInfo
;
3177 GuiInitInfo
->ProcessId
= ProcessId
;
3179 /* Finally, initialize the frontend structure */
3180 FrontEnd
->Vtbl
= &GuiVtbl
;
3181 FrontEnd
->Data
= NULL
;
3182 FrontEnd
->OldData
= GuiInitInfo
;
3184 return STATUS_SUCCESS
;
3188 GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd
)
3190 if (FrontEnd
== NULL
) return STATUS_INVALID_PARAMETER
;
3192 if (FrontEnd
->Data
) GuiDeinitFrontEnd(FrontEnd
);
3193 if (FrontEnd
->OldData
) ConsoleFreeHeap(FrontEnd
->OldData
);
3195 return STATUS_SUCCESS
;