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 *******************************************************************/
17 #include "include/conio.h"
18 #include "include/console.h"
19 #include "include/settings.h"
20 #include "conoutput.h"
22 #include "guisettings.h"
33 /* GUI Console Window Class name */
34 #define GUI_CONSOLE_WINDOW_CLASS L"ConsoleWindowClass"
39 #define PM_CREATE_CONSOLE (WM_APP + 1)
40 #define PM_DESTROY_CONSOLE (WM_APP + 2)
41 #define PM_RESIZE_TERMINAL (WM_APP + 3)
42 #define PM_CONSOLE_BEEP (WM_APP + 4)
43 #define PM_CONSOLE_SET_TITLE (WM_APP + 5)
46 /* Not defined in any header file */
47 extern VOID NTAPI
PrivateCsrssManualGuiCheck(LONG Check
);
48 // See winsrv/usersrv/init.c line 234
51 /* GLOBALS ********************************************************************/
53 typedef struct _GUI_INIT_INFO
55 PCONSOLE_INFO ConsoleInfo
;
56 PCONSOLE_START_INFO ConsoleStartInfo
;
58 } GUI_INIT_INFO
, *PGUI_INIT_INFO
;
60 /**************************************************************\
61 \** Define the Console Leader Process for the console window **/
62 #define GWLP_CONSOLEWND_ALLOC (2 * sizeof(LONG_PTR))
63 #define GWLP_CONSOLE_LEADER_PID 0
64 #define GWLP_CONSOLE_LEADER_TID 4
66 #define SetConsoleWndConsoleLeaderCID(GuiData) \
68 PCONSOLE_PROCESS_DATA ProcessData; \
69 CLIENT_ID ConsoleLeaderCID; \
70 ProcessData = CONTAINING_RECORD((GuiData)->Console->ProcessList.Blink, \
71 CONSOLE_PROCESS_DATA, \
73 ConsoleLeaderCID = ProcessData->Process->ClientId; \
74 SetWindowLongPtrW((GuiData)->hWindow, GWLP_CONSOLE_LEADER_PID, \
75 (LONG_PTR)(ConsoleLeaderCID.UniqueProcess)); \
76 SetWindowLongPtrW((GuiData)->hWindow, GWLP_CONSOLE_LEADER_TID, \
77 (LONG_PTR)(ConsoleLeaderCID.UniqueThread )); \
79 /**************************************************************/
81 static BOOL ConsInitialized
= FALSE
;
82 static HICON ghDefaultIcon
= NULL
;
83 static HICON ghDefaultIconSm
= NULL
;
84 static HCURSOR ghDefaultCursor
= NULL
;
85 static HWND NotifyWnd
= NULL
;
87 typedef struct _GUICONSOLE_MENUITEM
90 const struct _GUICONSOLE_MENUITEM
*SubMenu
;
92 } GUICONSOLE_MENUITEM
, *PGUICONSOLE_MENUITEM
;
94 static const GUICONSOLE_MENUITEM GuiConsoleEditMenuItems
[] =
96 { IDS_MARK
, NULL
, ID_SYSTEM_EDIT_MARK
},
97 { IDS_COPY
, NULL
, ID_SYSTEM_EDIT_COPY
},
98 { IDS_PASTE
, NULL
, ID_SYSTEM_EDIT_PASTE
},
99 { IDS_SELECTALL
, NULL
, ID_SYSTEM_EDIT_SELECTALL
},
100 { IDS_SCROLL
, NULL
, ID_SYSTEM_EDIT_SCROLL
},
101 { IDS_FIND
, NULL
, ID_SYSTEM_EDIT_FIND
},
103 { 0, NULL
, 0 } /* End of list */
106 static const GUICONSOLE_MENUITEM GuiConsoleMainMenuItems
[] =
108 { IDS_EDIT
, GuiConsoleEditMenuItems
, 0 },
109 { IDS_DEFAULTS
, NULL
, ID_SYSTEM_DEFAULTS
},
110 { IDS_PROPERTIES
, NULL
, ID_SYSTEM_PROPERTIES
},
112 { 0, NULL
, 0 } /* End of list */
116 * Default 16-color palette for foreground and background
117 * (corresponding flags in comments).
119 const COLORREF s_Colors
[16] =
121 RGB(0, 0, 0), // (Black)
122 RGB(0, 0, 128), // BLUE
123 RGB(0, 128, 0), // GREEN
124 RGB(0, 128, 128), // BLUE | GREEN
125 RGB(128, 0, 0), // RED
126 RGB(128, 0, 128), // BLUE | RED
127 RGB(128, 128, 0), // GREEN | RED
128 RGB(192, 192, 192), // BLUE | GREEN | RED
130 RGB(128, 128, 128), // (Grey) INTENSITY
131 RGB(0, 0, 255), // BLUE | INTENSITY
132 RGB(0, 255, 0), // GREEN | INTENSITY
133 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
134 RGB(255, 0, 0), // RED | INTENSITY
135 RGB(255, 0, 255), // BLUE | RED | INTENSITY
136 RGB(255, 255, 0), // GREEN | RED | INTENSITY
137 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
140 /* FUNCTIONS ******************************************************************/
143 GetScreenBufferSizeUnits(IN PCONSOLE_SCREEN_BUFFER Buffer
,
144 IN PGUI_CONSOLE_DATA GuiData
,
146 OUT PUINT HeightUnit
)
148 if (Buffer
== NULL
|| GuiData
== NULL
||
149 WidthUnit
== NULL
|| HeightUnit
== NULL
)
154 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
156 *WidthUnit
= GuiData
->CharWidth
;
157 *HeightUnit
= GuiData
->CharHeight
;
159 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
169 GuiConsoleAppendMenuItems(HMENU hMenu
,
170 const GUICONSOLE_MENUITEM
*Items
)
173 WCHAR szMenuString
[255];
178 if (Items
[i
].uID
!= (UINT
)-1)
180 if (LoadStringW(ConSrvDllInstance
,
183 sizeof(szMenuString
) / sizeof(szMenuString
[0])) > 0)
185 if (Items
[i
].SubMenu
!= NULL
)
187 hSubMenu
= CreatePopupMenu();
188 if (hSubMenu
!= NULL
)
190 GuiConsoleAppendMenuItems(hSubMenu
,
193 if (!AppendMenuW(hMenu
,
194 MF_STRING
| MF_POPUP
,
198 DestroyMenu(hSubMenu
);
219 } while (!(Items
[i
].uID
== 0 && Items
[i
].SubMenu
== NULL
&& Items
[i
].wCmdID
== 0));
223 GuiConsoleCreateSysMenu(HWND hWnd
)
225 HMENU hMenu
= GetSystemMenu(hWnd
, FALSE
);
228 GuiConsoleAppendMenuItems(hMenu
, GuiConsoleMainMenuItems
);
234 GuiSendMenuEvent(PCONSOLE Console
, UINT CmdId
)
238 er
.EventType
= MENU_EVENT
;
239 er
.Event
.MenuEvent
.dwCommandId
= CmdId
;
241 ConioProcessInputEvent(Console
, &er
);
245 GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData
);
247 GuiConsolePaste(PGUI_CONSOLE_DATA GuiData
);
249 GuiConsoleUpdateSelection(PCONSOLE Console
, PCOORD coord
);
251 GuiDrawRegion(IN OUT PFRONTEND This
, SMALL_RECT
* Region
);
253 GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData
);
257 GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData
, WPARAM wParam
, LPARAM lParam
)
260 PCONSOLE Console
= GuiData
->Console
;
261 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
263 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
268 // ActiveBuffer = ConDrvGetActiveScreenBuffer(Console);
269 ActiveBuffer
= GuiData
->ActiveBuffer
;
272 * In case the selected menu item belongs to the user-reserved menu id range,
273 * send to him a menu event and return directly. The user must handle those
274 * reserved menu commands...
276 if (GuiData
->cmdIdLow
<= (UINT
)wParam
&& (UINT
)wParam
<= GuiData
->cmdIdHigh
)
278 GuiSendMenuEvent(Console
, (UINT
)wParam
);
282 /* ... otherwise, perform actions. */
285 case ID_SYSTEM_EDIT_MARK
:
287 LPWSTR WindowTitle
= NULL
;
290 Console
->dwSelectionCursor
.X
= ActiveBuffer
->ViewOrigin
.X
;
291 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->ViewOrigin
.Y
;
292 Console
->Selection
.dwSelectionAnchor
= Console
->dwSelectionCursor
;
293 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_IN_PROGRESS
;
294 GuiConsoleUpdateSelection(Console
, &Console
->Selection
.dwSelectionAnchor
);
296 Length
= Console
->Title
.Length
+ sizeof(L
"Mark - ")/sizeof(WCHAR
) + 1;
297 WindowTitle
= ConsoleAllocHeap(0, Length
* sizeof(WCHAR
));
298 wcscpy(WindowTitle
, L
"Mark - ");
299 wcscat(WindowTitle
, Console
->Title
.Buffer
);
300 SetWindowText(GuiData
->hWindow
, WindowTitle
);
301 ConsoleFreeHeap(WindowTitle
);
306 case ID_SYSTEM_EDIT_COPY
:
307 GuiConsoleCopy(GuiData
);
310 case ID_SYSTEM_EDIT_PASTE
:
311 GuiConsolePaste(GuiData
);
314 case ID_SYSTEM_EDIT_SELECTALL
:
316 LPWSTR WindowTitle
= NULL
;
320 * The selection area extends to the whole screen buffer's width.
322 Console
->Selection
.dwSelectionAnchor
.X
= 0;
323 Console
->Selection
.dwSelectionAnchor
.Y
= 0;
324 Console
->dwSelectionCursor
.X
= ActiveBuffer
->ScreenBufferSize
.X
- 1;
327 * Determine whether the selection must extend to just some part
328 * (for text-mode screen buffers) or to all of the screen buffer's
329 * height (for graphics ones).
331 if (GetType(ActiveBuffer
) == TEXTMODE_BUFFER
)
334 * We select all the characters from the first line
335 * to the line where the cursor is positioned.
337 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->CursorPosition
.Y
;
339 else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
342 * We select all the screen buffer area.
344 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->ScreenBufferSize
.Y
- 1;
347 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_IN_PROGRESS
| CONSOLE_MOUSE_SELECTION
;
348 GuiConsoleUpdateSelection(Console
, &Console
->dwSelectionCursor
);
350 Length
= Console
->Title
.Length
+ sizeof(L
"Selection - ")/sizeof(WCHAR
) + 1;
351 WindowTitle
= ConsoleAllocHeap(0, Length
* sizeof(WCHAR
));
352 wcscpy(WindowTitle
, L
"Selection - ");
353 wcscat(WindowTitle
, Console
->Title
.Buffer
);
354 SetWindowText(GuiData
->hWindow
, WindowTitle
);
355 ConsoleFreeHeap(WindowTitle
);
360 case ID_SYSTEM_EDIT_SCROLL
:
361 DPRINT1("Scrolling is not handled yet\n");
364 case ID_SYSTEM_EDIT_FIND
:
365 DPRINT1("Finding is not handled yet\n");
368 case ID_SYSTEM_DEFAULTS
:
369 GuiConsoleShowConsoleProperties(GuiData
, TRUE
);
372 case ID_SYSTEM_PROPERTIES
:
373 GuiConsoleShowConsoleProperties(GuiData
, FALSE
);
382 LeaveCriticalSection(&Console
->Lock
);
385 Ret
= DefWindowProcW(GuiData
->hWindow
, WM_SYSCOMMAND
, wParam
, lParam
);
390 static PGUI_CONSOLE_DATA
391 GuiGetGuiData(HWND hWnd
)
393 /* This function ensures that the console pointer is not NULL */
394 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
395 return ( ((GuiData
== NULL
) || (GuiData
->hWindow
== hWnd
&& GuiData
->Console
!= NULL
)) ? GuiData
: NULL
);
399 GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData
)
401 /* Move the window if needed (not positioned by the system) */
402 if (!GuiData
->GuiInfo
.AutoPosition
)
404 SetWindowPos(GuiData
->hWindow
,
406 GuiData
->GuiInfo
.WindowOrigin
.x
,
407 GuiData
->GuiInfo
.WindowOrigin
.y
,
410 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
415 GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData
)
417 // PCONSOLE Console = GuiData->Console;
418 PCONSOLE_SCREEN_BUFFER Buff
= GuiData
->ActiveBuffer
; // ConDrvGetActiveScreenBuffer(Console);
422 UINT WidthUnit
, HeightUnit
;
424 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
426 Width
= Buff
->ViewSize
.X
* WidthUnit
+
427 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
428 Height
= Buff
->ViewSize
.Y
* HeightUnit
+
429 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
431 /* Set scrollbar sizes */
432 sInfo
.cbSize
= sizeof(SCROLLINFO
);
433 sInfo
.fMask
= SIF_RANGE
| SIF_PAGE
| SIF_POS
;
435 if (Buff
->ScreenBufferSize
.Y
> Buff
->ViewSize
.Y
)
437 sInfo
.nMax
= Buff
->ScreenBufferSize
.Y
- 1;
438 sInfo
.nPage
= Buff
->ViewSize
.Y
;
439 sInfo
.nPos
= Buff
->ViewOrigin
.Y
;
440 SetScrollInfo(GuiData
->hWindow
, SB_VERT
, &sInfo
, TRUE
);
441 Width
+= GetSystemMetrics(SM_CXVSCROLL
);
442 ShowScrollBar(GuiData
->hWindow
, SB_VERT
, TRUE
);
446 ShowScrollBar(GuiData
->hWindow
, SB_VERT
, FALSE
);
449 if (Buff
->ScreenBufferSize
.X
> Buff
->ViewSize
.X
)
451 sInfo
.nMax
= Buff
->ScreenBufferSize
.X
- 1;
452 sInfo
.nPage
= Buff
->ViewSize
.X
;
453 sInfo
.nPos
= Buff
->ViewOrigin
.X
;
454 SetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &sInfo
, TRUE
);
455 Height
+= GetSystemMetrics(SM_CYHSCROLL
);
456 ShowScrollBar(GuiData
->hWindow
, SB_HORZ
, TRUE
);
460 ShowScrollBar(GuiData
->hWindow
, SB_HORZ
, FALSE
);
463 /* Resize the window */
464 SetWindowPos(GuiData
->hWindow
, NULL
, 0, 0, Width
, Height
,
465 SWP_NOZORDER
| SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOCOPYBITS
);
466 // NOTE: The SWP_NOCOPYBITS flag can be replaced by a subsequent call
467 // to: InvalidateRect(GuiData->hWindow, NULL, TRUE);
471 GuiConsoleHandleNcCreate(HWND hWnd
, LPCREATESTRUCTW Create
)
473 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)Create
->lpCreateParams
;
480 DPRINT("GuiConsoleHandleNcCreate\n");
484 DPRINT1("GuiConsoleNcCreate: No GUI data\n");
488 Console
= GuiData
->Console
;
490 GuiData
->hWindow
= hWnd
;
492 GuiData
->Font
= CreateFontW(LOWORD(GuiData
->GuiInfo
.FontSize
),
493 0, // HIWORD(GuiData->GuiInfo.FontSize),
496 GuiData
->GuiInfo
.FontWeight
,
503 NONANTIALIASED_QUALITY
,
504 FIXED_PITCH
| GuiData
->GuiInfo
.FontFamily
/* FF_DONTCARE */,
505 GuiData
->GuiInfo
.FaceName
);
507 if (NULL
== GuiData
->Font
)
509 DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
510 GuiData
->hWindow
= NULL
;
511 SetEvent(GuiData
->hGuiInitEvent
);
514 hDC
= GetDC(GuiData
->hWindow
);
517 DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
518 DeleteObject(GuiData
->Font
);
519 GuiData
->hWindow
= NULL
;
520 SetEvent(GuiData
->hGuiInitEvent
);
523 OldFont
= SelectObject(hDC
, GuiData
->Font
);
526 DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
527 ReleaseDC(GuiData
->hWindow
, hDC
);
528 DeleteObject(GuiData
->Font
);
529 GuiData
->hWindow
= NULL
;
530 SetEvent(GuiData
->hGuiInitEvent
);
533 if (!GetTextMetricsW(hDC
, &Metrics
))
535 DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
536 SelectObject(hDC
, OldFont
);
537 ReleaseDC(GuiData
->hWindow
, hDC
);
538 DeleteObject(GuiData
->Font
);
539 GuiData
->hWindow
= NULL
;
540 SetEvent(GuiData
->hGuiInitEvent
);
543 GuiData
->CharWidth
= Metrics
.tmMaxCharWidth
;
544 GuiData
->CharHeight
= Metrics
.tmHeight
+ Metrics
.tmExternalLeading
;
546 /* Measure real char width more precisely if possible. */
547 if (GetTextExtentPoint32W(hDC
, L
"R", 1, &CharSize
))
548 GuiData
->CharWidth
= CharSize
.cx
;
550 SelectObject(hDC
, OldFont
);
552 ReleaseDC(GuiData
->hWindow
, hDC
);
554 // FIXME: Keep these instructions here ? ///////////////////////////////////
555 Console
->ActiveBuffer
->CursorBlinkOn
= TRUE
;
556 Console
->ActiveBuffer
->ForceCursorOff
= FALSE
;
557 ////////////////////////////////////////////////////////////////////////////
559 SetWindowLongPtrW(GuiData
->hWindow
, GWLP_USERDATA
, (DWORD_PTR
)GuiData
);
561 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
562 GuiConsoleCreateSysMenu(GuiData
->hWindow
);
564 DPRINT("GuiConsoleHandleNcCreate - setting start event\n");
565 SetEvent(GuiData
->hGuiInitEvent
);
567 return (BOOL
)DefWindowProcW(GuiData
->hWindow
, WM_NCCREATE
, 0, (LPARAM
)Create
);
571 SmallRectToRect(PGUI_CONSOLE_DATA GuiData
, PRECT Rect
, PSMALL_RECT SmallRect
)
573 // PCONSOLE Console = GuiData->Console;
574 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
; // ConDrvGetActiveScreenBuffer(Console);
575 UINT WidthUnit
, HeightUnit
;
577 GetScreenBufferSizeUnits(Buffer
, GuiData
, &WidthUnit
, &HeightUnit
);
579 Rect
->left
= (SmallRect
->Left
- Buffer
->ViewOrigin
.X
) * WidthUnit
;
580 Rect
->top
= (SmallRect
->Top
- Buffer
->ViewOrigin
.Y
) * HeightUnit
;
581 Rect
->right
= (SmallRect
->Right
+ 1 - Buffer
->ViewOrigin
.X
) * WidthUnit
;
582 Rect
->bottom
= (SmallRect
->Bottom
+ 1 - Buffer
->ViewOrigin
.Y
) * HeightUnit
;
586 GuiConsoleUpdateSelection(PCONSOLE Console
, PCOORD coord
)
588 PGUI_CONSOLE_DATA GuiData
= Console
->TermIFace
.Data
;
589 RECT oldRect
, newRect
;
591 SmallRectToRect(GuiData
, &oldRect
, &Console
->Selection
.srSelection
);
596 /* exchange left/top with right/bottom if required */
597 rc
.Left
= min(Console
->Selection
.dwSelectionAnchor
.X
, coord
->X
);
598 rc
.Top
= min(Console
->Selection
.dwSelectionAnchor
.Y
, coord
->Y
);
599 rc
.Right
= max(Console
->Selection
.dwSelectionAnchor
.X
, coord
->X
);
600 rc
.Bottom
= max(Console
->Selection
.dwSelectionAnchor
.Y
, coord
->Y
);
602 SmallRectToRect(GuiData
, &newRect
, &rc
);
604 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
606 if (memcmp(&rc
, &Console
->Selection
.srSelection
, sizeof(SMALL_RECT
)) != 0)
610 /* calculate the region that needs to be updated */
611 if ((rgn1
= CreateRectRgnIndirect(&oldRect
)))
613 if ((rgn2
= CreateRectRgnIndirect(&newRect
)))
615 if (CombineRgn(rgn1
, rgn2
, rgn1
, RGN_XOR
) != ERROR
)
617 InvalidateRgn(GuiData
->hWindow
, rgn1
, FALSE
);
627 InvalidateRect(GuiData
->hWindow
, &newRect
, FALSE
);
629 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_NOT_EMPTY
;
630 Console
->Selection
.srSelection
= rc
;
631 Console
->dwSelectionCursor
= *coord
;
632 ConioPause(Console
, PAUSED_FROM_SELECTION
);
636 /* clear the selection */
637 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
639 InvalidateRect(GuiData
->hWindow
, &oldRect
, FALSE
);
641 Console
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
642 ConioUnpause(Console
, PAUSED_FROM_SELECTION
);
648 GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
,
649 PGUI_CONSOLE_DATA GuiData
,
653 GuiPaintGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
,
654 PGUI_CONSOLE_DATA GuiData
,
659 GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData
)
662 PCONSOLE Console
= GuiData
->Console
;
663 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
667 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
672 // ActiveBuffer = ConDrvGetActiveScreenBuffer(Console);
673 ActiveBuffer
= GuiData
->ActiveBuffer
;
675 hDC
= BeginPaint(GuiData
->hWindow
, &ps
);
677 ps
.rcPaint
.left
< ps
.rcPaint
.right
&&
678 ps
.rcPaint
.top
< ps
.rcPaint
.bottom
)
680 EnterCriticalSection(&GuiData
->Lock
);
682 if (GetType(ActiveBuffer
) == TEXTMODE_BUFFER
)
684 GuiPaintTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)ActiveBuffer
,
685 GuiData
, hDC
, &ps
.rcPaint
);
687 else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
689 GuiPaintGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)ActiveBuffer
,
690 GuiData
, hDC
, &ps
.rcPaint
);
693 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
696 SmallRectToRect(GuiData
, &rc
, &Console
->Selection
.srSelection
);
698 /* invert the selection */
699 if (IntersectRect(&rc
, &ps
.rcPaint
, &rc
))
710 LeaveCriticalSection(&GuiData
->Lock
);
712 EndPaint(GuiData
->hWindow
, &ps
);
716 LeaveCriticalSection(&Console
->Lock
);
718 DefWindowProcW(GuiData
->hWindow
, WM_PAINT
, 0, 0);
724 IsSystemKey(WORD VirtualKeyCode
)
726 switch (VirtualKeyCode
)
728 /* From MSDN, "Virtual-Key Codes" */
747 GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
749 PCONSOLE Console
= GuiData
->Console
;
750 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
752 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
754 // ActiveBuffer = ConDrvGetActiveScreenBuffer(Console);
755 ActiveBuffer
= GuiData
->ActiveBuffer
;
757 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
)
759 WORD VirtualKeyCode
= LOWORD(wParam
);
761 if (msg
!= WM_KEYDOWN
) goto Quit
;
763 if (VirtualKeyCode
== VK_RETURN
)
765 /* Copy (and clear) selection if ENTER is pressed */
766 GuiConsoleCopy(GuiData
);
769 else if ( VirtualKeyCode
== VK_ESCAPE
||
770 (VirtualKeyCode
== 'C' && GetKeyState(VK_CONTROL
) & 0x8000) )
772 /* Cancel selection if ESC or Ctrl-C are pressed */
773 GuiConsoleUpdateSelection(Console
, NULL
);
774 SetWindowText(GuiData
->hWindow
, Console
->Title
.Buffer
);
779 if ((Console
->Selection
.dwFlags
& CONSOLE_MOUSE_SELECTION
) == 0)
781 /* Keyboard selection mode */
782 BOOL Interpreted
= FALSE
;
783 BOOL MajPressed
= (GetKeyState(VK_SHIFT
) & 0x8000);
785 switch (VirtualKeyCode
)
790 if (Console
->dwSelectionCursor
.X
> 0)
791 Console
->dwSelectionCursor
.X
--;
799 if (Console
->dwSelectionCursor
.X
< ActiveBuffer
->ScreenBufferSize
.X
- 1)
800 Console
->dwSelectionCursor
.X
++;
808 if (Console
->dwSelectionCursor
.Y
> 0)
809 Console
->dwSelectionCursor
.Y
--;
817 if (Console
->dwSelectionCursor
.Y
< ActiveBuffer
->ScreenBufferSize
.Y
- 1)
818 Console
->dwSelectionCursor
.Y
++;
826 Console
->dwSelectionCursor
.X
= 0;
827 Console
->dwSelectionCursor
.Y
= 0;
834 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->ScreenBufferSize
.Y
- 1;
841 Console
->dwSelectionCursor
.Y
-= ActiveBuffer
->ViewSize
.Y
;
842 if (Console
->dwSelectionCursor
.Y
< 0)
843 Console
->dwSelectionCursor
.Y
= 0;
851 Console
->dwSelectionCursor
.Y
+= ActiveBuffer
->ViewSize
.Y
;
852 if (Console
->dwSelectionCursor
.Y
>= ActiveBuffer
->ScreenBufferSize
.Y
)
853 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->ScreenBufferSize
.Y
- 1;
865 Console
->Selection
.dwSelectionAnchor
= Console
->dwSelectionCursor
;
867 GuiConsoleUpdateSelection(Console
, &Console
->dwSelectionCursor
);
869 else if (!IsSystemKey(VirtualKeyCode
))
871 /* Emit an error beep sound */
872 SendNotifyMessage(GuiData
->hWindow
, PM_CONSOLE_BEEP
, 0, 0);
879 /* Mouse selection mode */
881 if (!IsSystemKey(VirtualKeyCode
))
883 /* Clear the selection and send the key into the input buffer */
884 GuiConsoleUpdateSelection(Console
, NULL
);
885 SetWindowText(GuiData
->hWindow
, Console
->Title
.Buffer
);
894 if ((Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) == 0)
898 Message
.hwnd
= GuiData
->hWindow
;
899 Message
.message
= msg
;
900 Message
.wParam
= wParam
;
901 Message
.lParam
= lParam
;
903 ConioProcessKey(Console
, &Message
);
907 LeaveCriticalSection(&Console
->Lock
);
911 GuiInvalidateCell(IN OUT PFRONTEND This
, SHORT x
, SHORT y
)
913 SMALL_RECT CellRect
= { x
, y
, x
, y
};
914 GuiDrawRegion(This
, &CellRect
);
918 GuiConsoleHandleTimer(PGUI_CONSOLE_DATA GuiData
)
920 PCONSOLE Console
= GuiData
->Console
;
921 PCONSOLE_SCREEN_BUFFER Buff
;
923 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CURSOR_BLINK_TIME
, NULL
);
925 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
927 Buff
= GuiData
->ActiveBuffer
; // ConDrvGetActiveScreenBuffer(Console);
929 if (GetType(Buff
) == TEXTMODE_BUFFER
)
931 GuiInvalidateCell(&Console
->TermIFace
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
932 Buff
->CursorBlinkOn
= !Buff
->CursorBlinkOn
;
934 if ((GuiData
->OldCursor
.x
!= Buff
->CursorPosition
.X
) || (GuiData
->OldCursor
.y
!= Buff
->CursorPosition
.Y
))
937 int OldScrollX
= -1, OldScrollY
= -1;
938 int NewScrollX
= -1, NewScrollY
= -1;
940 xScroll
.cbSize
= sizeof(SCROLLINFO
);
941 xScroll
.fMask
= SIF_POS
;
942 // Capture the original position of the scroll bars and save them.
943 if (GetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &xScroll
)) OldScrollX
= xScroll
.nPos
;
944 if (GetScrollInfo(GuiData
->hWindow
, SB_VERT
, &xScroll
)) OldScrollY
= xScroll
.nPos
;
946 // If we successfully got the info for the horizontal scrollbar
949 if ((Buff
->CursorPosition
.X
< Buff
->ViewOrigin
.X
) || (Buff
->CursorPosition
.X
>= (Buff
->ViewOrigin
.X
+ Buff
->ViewSize
.X
)))
951 // Handle the horizontal scroll bar
952 if (Buff
->CursorPosition
.X
>= Buff
->ViewSize
.X
) 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
) || (Buff
->CursorPosition
.Y
>= (Buff
->ViewOrigin
.Y
+ Buff
->ViewSize
.Y
)))
965 // Handle the vertical scroll bar
966 if (Buff
->CursorPosition
.Y
>= Buff
->ViewSize
.Y
) NewScrollY
= Buff
->CursorPosition
.Y
- Buff
->ViewSize
.Y
+ 1;
971 NewScrollY
= OldScrollY
;
975 // Adjust scroll bars and refresh the window if the cursor has moved outside the visible area
976 // NOTE: OldScroll# and NewScroll# will both be -1 (initial value) if the info for the respective scrollbar
977 // was not obtained successfully in the previous steps. This means their difference is 0 (no scrolling)
978 // and their associated scrollbar is left alone.
979 if ((OldScrollX
!= NewScrollX
) || (OldScrollY
!= NewScrollY
))
981 Buff
->ViewOrigin
.X
= NewScrollX
;
982 Buff
->ViewOrigin
.Y
= NewScrollY
;
983 ScrollWindowEx(GuiData
->hWindow
,
984 (OldScrollX
- NewScrollX
) * GuiData
->CharWidth
,
985 (OldScrollY
- NewScrollY
) * GuiData
->CharHeight
,
993 xScroll
.nPos
= NewScrollX
;
994 SetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &xScroll
, TRUE
);
998 xScroll
.nPos
= NewScrollY
;
999 SetScrollInfo(GuiData
->hWindow
, SB_VERT
, &xScroll
, TRUE
);
1001 UpdateWindow(GuiData
->hWindow
);
1002 GuiData
->OldCursor
.x
= Buff
->CursorPosition
.X
;
1003 GuiData
->OldCursor
.y
= Buff
->CursorPosition
.Y
;
1007 else /* if (GetType(Buff) == GRAPHICS_BUFFER) */
1011 LeaveCriticalSection(&Console
->Lock
);
1015 GuiConsoleHandleClose(PGUI_CONSOLE_DATA GuiData
)
1017 PCONSOLE Console
= GuiData
->Console
;
1019 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1022 // TODO: Prompt for termination ? (Warn the user about possible apps running in this console)
1025 * FIXME: Windows will wait up to 5 seconds for the thread to exit.
1026 * We shouldn't wait here, though, since the console lock is entered.
1027 * A copy of the thread list probably needs to be made.
1029 ConDrvConsoleProcessCtrlEvent(Console
, 0, CTRL_CLOSE_EVENT
);
1031 LeaveCriticalSection(&Console
->Lock
);
1036 GuiConsoleHandleNcDestroy(HWND hWnd
)
1038 KillTimer(hWnd
, CONGUI_UPDATE_TIMER
);
1039 GetSystemMenu(hWnd
, TRUE
);
1041 /* Free the GuiData registration */
1042 SetWindowLongPtrW(hWnd
, GWLP_USERDATA
, (DWORD_PTR
)NULL
);
1044 return DefWindowProcW(hWnd
, WM_NCDESTROY
, 0, 0);
1048 PointToCoord(PGUI_CONSOLE_DATA GuiData
, LPARAM lParam
)
1050 // PCONSOLE Console = GuiData->Console;
1051 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
; // ConDrvGetActiveScreenBuffer(Console);
1053 UINT WidthUnit
, HeightUnit
;
1055 GetScreenBufferSizeUnits(Buffer
, GuiData
, &WidthUnit
, &HeightUnit
);
1057 Coord
.X
= Buffer
->ViewOrigin
.X
+ ((SHORT
)LOWORD(lParam
) / (int)WidthUnit
);
1058 Coord
.Y
= Buffer
->ViewOrigin
.Y
+ ((SHORT
)HIWORD(lParam
) / (int)HeightUnit
);
1060 /* Clip coordinate to ensure it's inside buffer */
1063 else if (Coord
.X
>= Buffer
->ScreenBufferSize
.X
)
1064 Coord
.X
= Buffer
->ScreenBufferSize
.X
- 1;
1068 else if (Coord
.Y
>= Buffer
->ScreenBufferSize
.Y
)
1069 Coord
.Y
= Buffer
->ScreenBufferSize
.Y
- 1;
1075 GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1078 PCONSOLE Console
= GuiData
->Console
;
1080 if (GuiData
->IgnoreNextMouseSignal
)
1082 if (msg
!= WM_LBUTTONDOWN
&&
1083 msg
!= WM_MBUTTONDOWN
&&
1084 msg
!= WM_RBUTTONDOWN
)
1087 * If this mouse signal is not a button-down action,
1088 * then it is the last signal being ignored.
1090 GuiData
->IgnoreNextMouseSignal
= FALSE
;
1095 * This mouse signal is a button-down action.
1096 * Ignore it and perform default action.
1103 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1109 if ( (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) ||
1110 (Console
->QuickEdit
) )
1114 case WM_LBUTTONDOWN
:
1116 LPWSTR WindowTitle
= NULL
;
1119 Console
->Selection
.dwSelectionAnchor
= PointToCoord(GuiData
, lParam
);
1120 SetCapture(GuiData
->hWindow
);
1121 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_IN_PROGRESS
| CONSOLE_MOUSE_SELECTION
| CONSOLE_MOUSE_DOWN
;
1122 GuiConsoleUpdateSelection(Console
, &Console
->Selection
.dwSelectionAnchor
);
1124 Length
= Console
->Title
.Length
+ sizeof(L
"Selection - ")/sizeof(WCHAR
) + 1;
1125 WindowTitle
= ConsoleAllocHeap(0, Length
* sizeof(WCHAR
));
1126 wcscpy(WindowTitle
, L
"Selection - ");
1127 wcscat(WindowTitle
, Console
->Title
.Buffer
);
1128 SetWindowText(GuiData
->hWindow
, WindowTitle
);
1129 ConsoleFreeHeap(WindowTitle
);
1138 if (!(Console
->Selection
.dwFlags
& CONSOLE_MOUSE_DOWN
)) break;
1140 c
= PointToCoord(GuiData
, lParam
);
1141 Console
->Selection
.dwFlags
&= ~CONSOLE_MOUSE_DOWN
;
1142 GuiConsoleUpdateSelection(Console
, &c
);
1148 case WM_LBUTTONDBLCLK
:
1150 DPRINT1("Handle left-double-click for selecting a word\n");
1154 case WM_RBUTTONDOWN
:
1155 case WM_RBUTTONDBLCLK
:
1157 if (!(Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
))
1159 GuiConsolePaste(GuiData
);
1163 GuiConsoleCopy(GuiData
);
1166 GuiData
->IgnoreNextMouseSignal
= TRUE
;
1174 if (!(wParam
& MK_LBUTTON
)) break;
1175 if (!(Console
->Selection
.dwFlags
& CONSOLE_MOUSE_DOWN
)) break;
1177 c
= PointToCoord(GuiData
, lParam
); /* TODO: Scroll buffer to bring c into view */
1178 GuiConsoleUpdateSelection(Console
, &c
);
1184 Err
= FALSE
; // TRUE;
1188 else if (Console
->InputBuffer
.Mode
& ENABLE_MOUSE_INPUT
)
1191 WORD wKeyState
= GET_KEYSTATE_WPARAM(wParam
);
1192 DWORD dwButtonState
= 0;
1193 DWORD dwControlKeyState
= 0;
1194 DWORD dwEventFlags
= 0;
1198 case WM_LBUTTONDOWN
:
1199 SetCapture(GuiData
->hWindow
);
1200 dwButtonState
= FROM_LEFT_1ST_BUTTON_PRESSED
;
1204 case WM_MBUTTONDOWN
:
1205 SetCapture(GuiData
->hWindow
);
1206 dwButtonState
= FROM_LEFT_2ND_BUTTON_PRESSED
;
1210 case WM_RBUTTONDOWN
:
1211 SetCapture(GuiData
->hWindow
);
1212 dwButtonState
= RIGHTMOST_BUTTON_PRESSED
;
1234 case WM_LBUTTONDBLCLK
:
1235 dwButtonState
= FROM_LEFT_1ST_BUTTON_PRESSED
;
1236 dwEventFlags
= DOUBLE_CLICK
;
1239 case WM_MBUTTONDBLCLK
:
1240 dwButtonState
= FROM_LEFT_2ND_BUTTON_PRESSED
;
1241 dwEventFlags
= DOUBLE_CLICK
;
1244 case WM_RBUTTONDBLCLK
:
1245 dwButtonState
= RIGHTMOST_BUTTON_PRESSED
;
1246 dwEventFlags
= DOUBLE_CLICK
;
1251 dwEventFlags
= MOUSE_MOVED
;
1255 dwButtonState
= GET_WHEEL_DELTA_WPARAM(wParam
) << 16;
1256 dwEventFlags
= MOUSE_WHEELED
;
1259 case WM_MOUSEHWHEEL
:
1260 dwButtonState
= GET_WHEEL_DELTA_WPARAM(wParam
) << 16;
1261 dwEventFlags
= MOUSE_HWHEELED
;
1271 if (wKeyState
& MK_LBUTTON
)
1272 dwButtonState
|= FROM_LEFT_1ST_BUTTON_PRESSED
;
1273 if (wKeyState
& MK_MBUTTON
)
1274 dwButtonState
|= FROM_LEFT_2ND_BUTTON_PRESSED
;
1275 if (wKeyState
& MK_RBUTTON
)
1276 dwButtonState
|= RIGHTMOST_BUTTON_PRESSED
;
1278 if (GetKeyState(VK_RMENU
) & 0x8000)
1279 dwControlKeyState
|= RIGHT_ALT_PRESSED
;
1280 if (GetKeyState(VK_LMENU
) & 0x8000)
1281 dwControlKeyState
|= LEFT_ALT_PRESSED
;
1282 if (GetKeyState(VK_RCONTROL
) & 0x8000)
1283 dwControlKeyState
|= RIGHT_CTRL_PRESSED
;
1284 if (GetKeyState(VK_LCONTROL
) & 0x8000)
1285 dwControlKeyState
|= LEFT_CTRL_PRESSED
;
1286 if (GetKeyState(VK_SHIFT
) & 0x8000)
1287 dwControlKeyState
|= SHIFT_PRESSED
;
1288 if (GetKeyState(VK_NUMLOCK
) & 0x0001)
1289 dwControlKeyState
|= NUMLOCK_ON
;
1290 if (GetKeyState(VK_SCROLL
) & 0x0001)
1291 dwControlKeyState
|= SCROLLLOCK_ON
;
1292 if (GetKeyState(VK_CAPITAL
) & 0x0001)
1293 dwControlKeyState
|= CAPSLOCK_ON
;
1294 /* See WM_CHAR MSDN documentation for instance */
1295 if (lParam
& 0x01000000)
1296 dwControlKeyState
|= ENHANCED_KEY
;
1298 er
.EventType
= MOUSE_EVENT
;
1299 er
.Event
.MouseEvent
.dwMousePosition
= PointToCoord(GuiData
, lParam
);
1300 er
.Event
.MouseEvent
.dwButtonState
= dwButtonState
;
1301 er
.Event
.MouseEvent
.dwControlKeyState
= dwControlKeyState
;
1302 er
.Event
.MouseEvent
.dwEventFlags
= dwEventFlags
;
1304 ConioProcessInputEvent(Console
, &er
);
1312 LeaveCriticalSection(&Console
->Lock
);
1316 return DefWindowProcW(GuiData
->hWindow
, msg
, wParam
, lParam
);
1321 VOID
GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
);
1322 VOID
GuiCopyFromGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
);
1325 GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData
)
1327 if (OpenClipboard(GuiData
->hWindow
) == TRUE
)
1329 PCONSOLE Console
= GuiData
->Console
;
1330 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
; // ConDrvGetActiveScreenBuffer(Console);
1332 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
1334 GuiCopyFromTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)Buffer
);
1336 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
1338 GuiCopyFromGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)Buffer
);
1343 /* Clear the selection */
1344 GuiConsoleUpdateSelection(Console
, NULL
);
1345 SetWindowText(GuiData
->hWindow
, Console
->Title
.Buffer
);
1349 VOID
GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
);
1350 VOID
GuiPasteToGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
);
1353 GuiConsolePaste(PGUI_CONSOLE_DATA GuiData
)
1355 if (OpenClipboard(GuiData
->hWindow
) == TRUE
)
1357 // PCONSOLE Console = GuiData->Console;
1358 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
; // ConDrvGetActiveScreenBuffer(Console);
1360 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
1362 GuiPasteToTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)Buffer
);
1364 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
1366 GuiPasteToGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)Buffer
);
1374 GuiConsoleGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData
, PMINMAXINFO minMaxInfo
)
1376 PCONSOLE Console
= GuiData
->Console
;
1377 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
1379 UINT WidthUnit
, HeightUnit
;
1381 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
1383 // ActiveBuffer = ConDrvGetActiveScreenBuffer(Console);
1384 ActiveBuffer
= GuiData
->ActiveBuffer
;
1386 GetScreenBufferSizeUnits(ActiveBuffer
, GuiData
, &WidthUnit
, &HeightUnit
);
1388 windx
= CONGUI_MIN_WIDTH
* WidthUnit
+ 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
1389 windy
= CONGUI_MIN_HEIGHT
* HeightUnit
+ 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
1391 minMaxInfo
->ptMinTrackSize
.x
= windx
;
1392 minMaxInfo
->ptMinTrackSize
.y
= windy
;
1394 windx
= (ActiveBuffer
->ScreenBufferSize
.X
) * WidthUnit
+ 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
1395 windy
= (ActiveBuffer
->ScreenBufferSize
.Y
) * HeightUnit
+ 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
1397 if (ActiveBuffer
->ViewSize
.X
< ActiveBuffer
->ScreenBufferSize
.X
) windy
+= GetSystemMetrics(SM_CYHSCROLL
); // window currently has a horizontal scrollbar
1398 if (ActiveBuffer
->ViewSize
.Y
< ActiveBuffer
->ScreenBufferSize
.Y
) windx
+= GetSystemMetrics(SM_CXVSCROLL
); // window currently has a vertical scrollbar
1400 minMaxInfo
->ptMaxTrackSize
.x
= windx
;
1401 minMaxInfo
->ptMaxTrackSize
.y
= windy
;
1403 LeaveCriticalSection(&Console
->Lock
);
1407 GuiConsoleResize(PGUI_CONSOLE_DATA GuiData
, WPARAM wParam
, LPARAM lParam
)
1409 PCONSOLE Console
= GuiData
->Console
;
1411 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
1413 if ((GuiData
->WindowSizeLock
== FALSE
) &&
1414 (wParam
== SIZE_RESTORED
|| wParam
== SIZE_MAXIMIZED
|| wParam
== SIZE_MINIMIZED
))
1416 PCONSOLE_SCREEN_BUFFER Buff
= GuiData
->ActiveBuffer
; // ConDrvGetActiveScreenBuffer(Console);
1417 DWORD windx
, windy
, charx
, chary
;
1418 UINT WidthUnit
, HeightUnit
;
1420 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
1422 GuiData
->WindowSizeLock
= TRUE
;
1424 windx
= LOWORD(lParam
);
1425 windy
= HIWORD(lParam
);
1427 // Compensate for existing scroll bars (because lParam values do not accommodate scroll bar)
1428 if (Buff
->ViewSize
.X
< Buff
->ScreenBufferSize
.X
) windy
+= GetSystemMetrics(SM_CYHSCROLL
); // window currently has a horizontal scrollbar
1429 if (Buff
->ViewSize
.Y
< Buff
->ScreenBufferSize
.Y
) windx
+= GetSystemMetrics(SM_CXVSCROLL
); // window currently has a vertical scrollbar
1431 charx
= windx
/ (int)WidthUnit
;
1432 chary
= windy
/ (int)HeightUnit
;
1434 // Character alignment (round size up or down)
1435 if ((windx
% WidthUnit
) >= (WidthUnit
/ 2)) ++charx
;
1436 if ((windy
% HeightUnit
) >= (HeightUnit
/ 2)) ++chary
;
1438 // Compensate for added scroll bars in new window
1439 if (charx
< Buff
->ScreenBufferSize
.X
) windy
-= GetSystemMetrics(SM_CYHSCROLL
); // new window will have a horizontal scroll bar
1440 if (chary
< Buff
->ScreenBufferSize
.Y
) windx
-= GetSystemMetrics(SM_CXVSCROLL
); // new window will have a vertical scroll bar
1442 charx
= windx
/ (int)WidthUnit
;
1443 chary
= windy
/ (int)HeightUnit
;
1445 // Character alignment (round size up or down)
1446 if ((windx
% WidthUnit
) >= (WidthUnit
/ 2)) ++charx
;
1447 if ((windy
% HeightUnit
) >= (HeightUnit
/ 2)) ++chary
;
1450 if ((charx
!= Buff
->ViewSize
.X
) || (chary
!= Buff
->ViewSize
.Y
))
1452 Buff
->ViewSize
.X
= (charx
<= Buff
->ScreenBufferSize
.X
) ? charx
: Buff
->ScreenBufferSize
.X
;
1453 Buff
->ViewSize
.Y
= (chary
<= Buff
->ScreenBufferSize
.Y
) ? chary
: Buff
->ScreenBufferSize
.Y
;
1456 GuiConsoleResizeWindow(GuiData
);
1458 // Adjust the start of the visible area if we are attempting to show nonexistent areas
1459 if ((Buff
->ScreenBufferSize
.X
- Buff
->ViewOrigin
.X
) < Buff
->ViewSize
.X
) Buff
->ViewOrigin
.X
= Buff
->ScreenBufferSize
.X
- Buff
->ViewSize
.X
;
1460 if ((Buff
->ScreenBufferSize
.Y
- Buff
->ViewOrigin
.Y
) < Buff
->ViewSize
.Y
) Buff
->ViewOrigin
.Y
= Buff
->ScreenBufferSize
.Y
- Buff
->ViewSize
.Y
;
1461 InvalidateRect(GuiData
->hWindow
, NULL
, TRUE
);
1463 GuiData
->WindowSizeLock
= FALSE
;
1466 LeaveCriticalSection(&Console
->Lock
);
1470 // HACK: This functionality is standard for general scrollbars. Don't add it by hand.
1474 GuiConsoleHandleScrollbarMenu(VOID)
1478 hMenu = CreatePopupMenu();
1481 DPRINT("CreatePopupMenu failed\n");
1485 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLHERE);
1486 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1487 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLTOP);
1488 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLBOTTOM);
1489 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1490 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_UP);
1491 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_DOWN);
1492 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1493 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLUP);
1494 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLDOWN);
1499 GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData
, UINT uMsg
, WPARAM wParam
)
1501 PCONSOLE Console
= GuiData
->Console
;
1502 PCONSOLE_SCREEN_BUFFER Buff
;
1505 int old_pos
, Maximum
;
1508 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return 0;
1510 Buff
= GuiData
->ActiveBuffer
; // ConDrvGetActiveScreenBuffer(Console);
1512 if (uMsg
== WM_HSCROLL
)
1515 Maximum
= Buff
->ScreenBufferSize
.X
- Buff
->ViewSize
.X
;
1516 pShowXY
= &Buff
->ViewOrigin
.X
;
1521 Maximum
= Buff
->ScreenBufferSize
.Y
- Buff
->ViewSize
.Y
;
1522 pShowXY
= &Buff
->ViewOrigin
.Y
;
1525 /* set scrollbar sizes */
1526 sInfo
.cbSize
= sizeof(SCROLLINFO
);
1527 sInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
| SIF_TRACKPOS
;
1529 if (!GetScrollInfo(GuiData
->hWindow
, fnBar
, &sInfo
)) goto Quit
;
1531 old_pos
= sInfo
.nPos
;
1533 switch (LOWORD(wParam
))
1544 sInfo
.nPos
-= sInfo
.nPage
;
1548 sInfo
.nPos
+= sInfo
.nPage
;
1552 sInfo
.nPos
= sInfo
.nTrackPos
;
1553 ConioPause(Console
, PAUSED_FROM_SCROLLBAR
);
1556 case SB_THUMBPOSITION
:
1557 ConioUnpause(Console
, PAUSED_FROM_SCROLLBAR
);
1561 sInfo
.nPos
= sInfo
.nMin
;
1565 sInfo
.nPos
= sInfo
.nMax
;
1572 sInfo
.nPos
= max(sInfo
.nPos
, 0);
1573 sInfo
.nPos
= min(sInfo
.nPos
, Maximum
);
1575 if (old_pos
!= sInfo
.nPos
)
1577 USHORT OldX
= Buff
->ViewOrigin
.X
;
1578 USHORT OldY
= Buff
->ViewOrigin
.Y
;
1579 UINT WidthUnit
, HeightUnit
;
1581 *pShowXY
= sInfo
.nPos
;
1583 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
1585 ScrollWindowEx(GuiData
->hWindow
,
1586 (OldX
- Buff
->ViewOrigin
.X
) * WidthUnit
,
1587 (OldY
- Buff
->ViewOrigin
.Y
) * HeightUnit
,
1594 sInfo
.fMask
= SIF_POS
;
1595 SetScrollInfo(GuiData
->hWindow
, fnBar
, &sInfo
, TRUE
);
1597 UpdateWindow(GuiData
->hWindow
);
1601 LeaveCriticalSection(&Console
->Lock
);
1607 EnterFullScreen(PGUI_CONSOLE_DATA GuiData
);
1609 LeaveFullScreen(PGUI_CONSOLE_DATA GuiData
);
1611 SwitchFullScreen(PGUI_CONSOLE_DATA GuiData
, BOOL FullScreen
);
1613 GuiConsoleSwitchFullScreen(PGUI_CONSOLE_DATA GuiData
);
1615 static LRESULT CALLBACK
1616 GuiConsoleWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1619 PGUI_CONSOLE_DATA GuiData
= NULL
;
1620 PCONSOLE Console
= NULL
;
1623 * - If it's the first time we create a window for the terminal,
1624 * just initialize it and return.
1626 * - If we are destroying the window, just do it and return.
1628 if (msg
== WM_NCCREATE
)
1630 return (LRESULT
)GuiConsoleHandleNcCreate(hWnd
, (LPCREATESTRUCTW
)lParam
);
1632 else if (msg
== WM_NCDESTROY
)
1634 return GuiConsoleHandleNcDestroy(hWnd
);
1638 * Now the terminal window is initialized.
1639 * Get the terminal data via the window's data.
1640 * If there is no data, just go away.
1642 GuiData
= GuiGetGuiData(hWnd
);
1643 if (GuiData
== NULL
) return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1645 // TEMPORARY HACK until all of the functions can deal with a NULL GuiData->ActiveBuffer ...
1646 if (GuiData
->ActiveBuffer
== NULL
) return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1649 * Just retrieve a pointer to the console in case somebody needs it.
1650 * It is not NULL because it was checked in GuiGetGuiData.
1651 * Each helper function which needs the console has to validate and lock it.
1653 Console
= GuiData
->Console
;
1655 /* We have a console, start message dispatching */
1660 WORD ActivationState
= LOWORD(wParam
);
1662 DPRINT1("WM_ACTIVATE - ActivationState = %d\n");
1664 if ( ActivationState
== WA_ACTIVE
||
1665 ActivationState
== WA_CLICKACTIVE
)
1667 if (GuiData
->GuiInfo
.FullScreen
)
1669 EnterFullScreen(GuiData
);
1670 // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
1671 // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
1674 else // if (ActivationState == WA_INACTIVE)
1676 if (GuiData
->GuiInfo
.FullScreen
)
1678 SendMessageW(GuiData
->hWindow
, WM_SYSCOMMAND
, SC_MINIMIZE
, 0);
1679 LeaveFullScreen(GuiData
);
1680 // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
1681 // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
1685 if (ActivationState
== WA_CLICKACTIVE
) GuiData
->IgnoreNextMouseSignal
= TRUE
;
1691 if (GuiConsoleHandleClose(GuiData
)) goto Default
;
1695 GuiConsoleHandlePaint(GuiData
);
1698 case WM_PALETTECHANGED
:
1700 PCONSOLE_SCREEN_BUFFER ActiveBuffer
= GuiData
->ActiveBuffer
; // ConDrvGetActiveScreenBuffer(GuiData->Console);
1702 DPRINT1("WM_PALETTECHANGED called\n");
1705 * Protects against infinite loops:
1706 * "... A window that receives this message must not realize
1707 * its palette, unless it determines that wParam does not contain
1708 * its own window handle." (WM_PALETTECHANGED description - MSDN)
1710 * This message is sent to all windows, including the one that
1711 * changed the system palette and caused this message to be sent.
1712 * The wParam of this message contains the handle of the window
1713 * that caused the system palette to change. To avoid an infinite
1714 * loop, care must be taken to check that the wParam of this message
1715 * does not match the window's handle.
1717 if ((HWND
)wParam
== hWnd
) break;
1719 DPRINT1("WM_PALETTECHANGED ok\n");
1721 // if (GetType(ActiveBuffer) == GRAPHICS_BUFFER)
1722 if (ActiveBuffer
->PaletteHandle
)
1724 /* Get the Device Context of the console window */
1725 HDC hDC
= GetDC(GuiData
->hWindow
);
1727 DPRINT1("WM_PALETTECHANGED changing palette\n");
1729 /* Specify the use of the system palette */
1730 SetSystemPaletteUse(hDC
, ActiveBuffer
->PaletteUsage
);
1732 /* Realize the (logical) palette */
1733 RealizePalette(hDC
);
1735 /* Release the Device Context and return */
1736 ReleaseDC(GuiData
->hWindow
, hDC
);
1739 DPRINT1("WM_PALETTECHANGED quit\n");
1751 case WM_SYSDEADCHAR
:
1753 /* Detect Alt-Enter presses and switch back and forth to fullscreen mode */
1754 if (msg
== WM_SYSKEYDOWN
&& (HIWORD(lParam
) & KF_ALTDOWN
) && wParam
== VK_RETURN
)
1756 /* Switch only at first Alt-Enter press, and ignore subsequent key repetitions */
1757 if ((HIWORD(lParam
) & (KF_UP
| KF_REPEAT
)) != KF_REPEAT
)
1758 GuiConsoleSwitchFullScreen(GuiData
);
1763 GuiConsoleHandleKey(GuiData
, msg
, wParam
, lParam
);
1768 GuiConsoleHandleTimer(GuiData
);
1774 * The message was sent because we are manually triggering a change.
1775 * Check whether the mouse is indeed present on this console window
1776 * and take appropriate decisions.
1778 if (wParam
== -1 && lParam
== -1)
1783 /* Get the placement of the mouse */
1784 GetCursorPos(&mouseCoords
);
1786 /* On which window is placed the mouse ? */
1787 hWndHit
= WindowFromPoint(mouseCoords
);
1789 /* It's our window. Perform the hit-test to be used later on. */
1790 if (hWndHit
== hWnd
)
1792 wParam
= (WPARAM
)hWnd
;
1793 lParam
= DefWindowProcW(hWndHit
, WM_NCHITTEST
, 0,
1794 MAKELPARAM(mouseCoords
.x
, mouseCoords
.y
));
1798 /* Set the mouse cursor only when we are in the client area */
1799 if ((HWND
)wParam
== hWnd
&& LOWORD(lParam
) == HTCLIENT
)
1801 if (GuiData
->MouseCursorRefCount
>= 0)
1803 /* Show the cursor */
1804 SetCursor(GuiData
->hCursor
);
1808 /* Hide the cursor if the reference count is negative */
1819 case WM_LBUTTONDOWN
:
1820 case WM_MBUTTONDOWN
:
1821 case WM_RBUTTONDOWN
:
1825 case WM_LBUTTONDBLCLK
:
1826 case WM_MBUTTONDBLCLK
:
1827 case WM_RBUTTONDBLCLK
:
1830 case WM_MOUSEHWHEEL
:
1832 Result
= GuiConsoleHandleMouse(GuiData
, msg
, wParam
, lParam
);
1839 Result
= GuiConsoleHandleScroll(GuiData
, msg
, wParam
);
1843 case WM_NCRBUTTONDOWN
:
1845 DPRINT1("WM_NCRBUTTONDOWN\n");
1847 * HACK: !! Because, when we deal with WM_RBUTTON* and we do not
1848 * call after that DefWindowProc, on ReactOS, right-clicks on the
1849 * (non-client) application title-bar does not display the system
1850 * menu and does not trigger a WM_NCRBUTTONUP message too.
1851 * See: http://git.reactos.org/?p=reactos.git;a=blob;f=reactos/win32ss/user/user32/windows/defwnd.c;hb=332bc8f482f40fd05ab510f78276576719fbfba8#l1103
1852 * and line 1135 too.
1855 if (DefWindowProcW(hWnd
, WM_NCHITTEST
, 0, lParam
) == HTCAPTION
)
1857 /* Call DefWindowProcW with the WM_CONTEXTMENU message */
1858 msg
= WM_CONTEXTMENU
;
1863 // case WM_NCRBUTTONUP:
1864 // DPRINT1("WM_NCRBUTTONUP\n");
1867 case WM_CONTEXTMENU
:
1869 if (DefWindowProcW(hWnd
/*GuiData->hWindow*/, WM_NCHITTEST
, 0, lParam
) == HTCLIENT
)
1871 HMENU hMenu
= CreatePopupMenu();
1874 GuiConsoleAppendMenuItems(hMenu
, GuiConsoleEditMenuItems
);
1875 TrackPopupMenuEx(hMenu
,
1877 GET_X_LPARAM(lParam
),
1878 GET_Y_LPARAM(lParam
),
1893 HMENU hMenu
= (HMENU
)wParam
;
1896 /* Enable or disable the Close menu item */
1897 EnableMenuItem(hMenu
, SC_CLOSE
, MF_BYCOMMAND
|
1898 (GuiData
->IsCloseButtonEnabled
? MF_ENABLED
: MF_GRAYED
));
1900 /* Enable or disable the Copy and Paste items */
1901 EnableMenuItem(hMenu
, ID_SYSTEM_EDIT_COPY
, MF_BYCOMMAND
|
1902 ((Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) &&
1903 (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
) ? MF_ENABLED
: MF_GRAYED
));
1904 EnableMenuItem(hMenu
, ID_SYSTEM_EDIT_PASTE
, MF_BYCOMMAND
|
1905 (!(Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) &&
1906 IsClipboardFormatAvailable(CF_UNICODETEXT
) ? MF_ENABLED
: MF_GRAYED
));
1909 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1911 GuiSendMenuEvent(Console
, WM_INITMENU
);
1912 LeaveCriticalSection(&Console
->Lock
);
1919 if (HIWORD(wParam
) == 0xFFFF) // Allow all the menu flags
1921 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1923 GuiSendMenuEvent(Console
, WM_MENUSELECT
);
1924 LeaveCriticalSection(&Console
->Lock
);
1933 Result
= GuiConsoleHandleSysMenuCommand(GuiData
, wParam
, lParam
);
1940 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1942 BOOL SetFocus
= (msg
== WM_SETFOCUS
);
1945 er
.EventType
= FOCUS_EVENT
;
1946 er
.Event
.FocusEvent
.bSetFocus
= SetFocus
;
1947 ConioProcessInputEvent(Console
, &er
);
1950 DPRINT1("TODO: Create console caret\n");
1952 DPRINT1("TODO: Destroy console caret\n");
1954 LeaveCriticalSection(&Console
->Lock
);
1959 case WM_GETMINMAXINFO
:
1960 GuiConsoleGetMinMaxInfo(GuiData
, (PMINMAXINFO
)lParam
);
1964 GuiConsoleResize(GuiData
, wParam
, lParam
);
1967 case PM_RESIZE_TERMINAL
:
1969 /* Resize the window to the user's values */
1970 GuiData
->WindowSizeLock
= TRUE
;
1971 GuiConsoleResizeWindow(GuiData
);
1972 GuiData
->WindowSizeLock
= FALSE
;
1976 case PM_APPLY_CONSOLE_INFO
:
1978 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1980 GuiApplyUserSettings(GuiData
, (HANDLE
)wParam
, (BOOL
)lParam
);
1981 LeaveCriticalSection(&Console
->Lock
);
1986 case PM_CONSOLE_BEEP
:
1987 DPRINT1("Beep !!\n");
1991 // case PM_CONSOLE_SET_TITLE:
1992 // SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
1996 Result
= DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
2005 /******************************************************************************
2006 * GUI Terminal Initialization *
2007 ******************************************************************************/
2009 static LRESULT CALLBACK
2010 GuiConsoleNotifyWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
2020 SetWindowLongW(hWnd
, GWL_USERDATA
, 0);
2024 case PM_CREATE_CONSOLE
:
2026 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)lParam
;
2027 PCONSOLE Console
= GuiData
->Console
;
2029 NewWindow
= CreateWindowExW(WS_EX_CLIENTEDGE
,
2030 GUI_CONSOLE_WINDOW_CLASS
,
2031 Console
->Title
.Buffer
,
2032 WS_OVERLAPPEDWINDOW
| WS_HSCROLL
| WS_VSCROLL
,
2041 if (NULL
!= NewWindow
)
2043 ASSERT(NewWindow
== GuiData
->hWindow
);
2045 WindowCount
= GetWindowLongW(hWnd
, GWL_USERDATA
);
2047 SetWindowLongW(hWnd
, GWL_USERDATA
, WindowCount
);
2049 DPRINT("Set icons via PM_CREATE_CONSOLE\n");
2050 if (GuiData
->hIcon
== NULL
)
2052 DPRINT("Not really /o\\...\n");
2053 GuiData
->hIcon
= ghDefaultIcon
;
2054 GuiData
->hIconSm
= ghDefaultIconSm
;
2056 else if (GuiData
->hIcon
!= ghDefaultIcon
)
2058 DPRINT("Yes \\o/\n");
2059 SendMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
2060 SendMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
2063 /* Move and resize the window to the user's values */
2064 /* CAN WE DEADLOCK ?? */
2065 GuiConsoleMoveWindow(GuiData
);
2066 GuiData
->WindowSizeLock
= TRUE
;
2067 GuiConsoleResizeWindow(GuiData
);
2068 GuiData
->WindowSizeLock
= FALSE
;
2070 /* Switch to full-screen mode if necessary */
2071 if (GuiData
->GuiInfo
.FullScreen
) SwitchFullScreen(GuiData
, TRUE
);
2073 // ShowWindow(NewWindow, (int)wParam);
2074 ShowWindowAsync(NewWindow
, (int)wParam
);
2075 DPRINT("Window showed\n");
2078 return (LRESULT
)NewWindow
;
2081 case PM_DESTROY_CONSOLE
:
2083 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)lParam
;
2085 /* Exit the full screen mode if it was already set */
2086 // LeaveFullScreen(GuiData);
2089 * Window creation is done using a PostMessage(), so it's possible
2090 * that the window that we want to destroy doesn't exist yet.
2091 * So first empty the message queue.
2094 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
2096 TranslateMessage(&Msg);
2097 DispatchMessageW(&Msg);
2099 while (PeekMessageW(&Msg
, NULL
, 0, 0, PM_REMOVE
)) ;
2101 if (GuiData
->hWindow
!= NULL
) /* && DestroyWindow(GuiData->hWindow) */
2103 DestroyWindow(GuiData
->hWindow
);
2105 WindowCount
= GetWindowLongW(hWnd
, GWL_USERDATA
);
2107 SetWindowLongW(hWnd
, GWL_USERDATA
, WindowCount
);
2108 if (0 == WindowCount
)
2111 DestroyWindow(hWnd
);
2112 DPRINT("CONSRV: Going to quit the Gui Thread!!\n");
2121 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
2126 GuiConsoleGuiThread(PVOID Data
)
2129 PHANDLE GraphicsStartupEvent
= (PHANDLE
)Data
;
2132 * This thread dispatches all the console notifications to the notify window.
2133 * It is common for all the console windows.
2136 PrivateCsrssManualGuiCheck(+1);
2138 NotifyWnd
= CreateWindowW(L
"ConSrvCreateNotify",
2140 WS_OVERLAPPEDWINDOW
,
2149 if (NULL
== NotifyWnd
)
2151 PrivateCsrssManualGuiCheck(-1);
2152 SetEvent(*GraphicsStartupEvent
);
2156 SetEvent(*GraphicsStartupEvent
);
2158 while (GetMessageW(&msg
, NULL
, 0, 0))
2160 TranslateMessage(&msg
);
2161 DispatchMessageW(&msg
);
2164 DPRINT("CONSRV: Quit the Gui Thread!!\n");
2165 PrivateCsrssManualGuiCheck(-1);
2174 ATOM ConsoleClassAtom
;
2176 /* Exit if we were already initialized */
2177 // if (ConsInitialized) return TRUE;
2180 * Initialize and register the different window classes, if needed.
2182 if (!ConsInitialized
)
2184 /* Initialize the notification window class */
2185 wc
.cbSize
= sizeof(WNDCLASSEXW
);
2186 wc
.lpszClassName
= L
"ConSrvCreateNotify";
2187 wc
.lpfnWndProc
= GuiConsoleNotifyWndProc
;
2189 wc
.hInstance
= ConSrvDllInstance
;
2193 wc
.hbrBackground
= NULL
;
2194 wc
.lpszMenuName
= NULL
;
2197 if (RegisterClassExW(&wc
) == 0)
2199 DPRINT1("Failed to register GUI notify wndproc\n");
2203 /* Initialize the console window class */
2204 ghDefaultIcon
= LoadImageW(ConSrvDllInstance
,
2205 MAKEINTRESOURCEW(IDI_TERMINAL
),
2207 GetSystemMetrics(SM_CXICON
),
2208 GetSystemMetrics(SM_CYICON
),
2210 ghDefaultIconSm
= LoadImageW(ConSrvDllInstance
,
2211 MAKEINTRESOURCEW(IDI_TERMINAL
),
2213 GetSystemMetrics(SM_CXSMICON
),
2214 GetSystemMetrics(SM_CYSMICON
),
2216 ghDefaultCursor
= LoadCursorW(NULL
, IDC_ARROW
);
2217 wc
.cbSize
= sizeof(WNDCLASSEXW
);
2218 wc
.lpszClassName
= GUI_CONSOLE_WINDOW_CLASS
;
2219 wc
.lpfnWndProc
= GuiConsoleWndProc
;
2220 wc
.style
= CS_DBLCLKS
/* | CS_HREDRAW | CS_VREDRAW */;
2221 wc
.hInstance
= ConSrvDllInstance
;
2222 wc
.hIcon
= ghDefaultIcon
;
2223 wc
.hIconSm
= ghDefaultIconSm
;
2224 wc
.hCursor
= ghDefaultCursor
;
2225 wc
.hbrBackground
= (HBRUSH
)GetStockObject(BLACK_BRUSH
); // The color of a terminal when it is switch off.
2226 wc
.lpszMenuName
= NULL
;
2228 wc
.cbWndExtra
= GWLP_CONSOLEWND_ALLOC
;
2230 ConsoleClassAtom
= RegisterClassExW(&wc
);
2231 if (ConsoleClassAtom
== 0)
2233 DPRINT1("Failed to register GUI console wndproc\n");
2238 NtUserConsoleControl(GuiConsoleWndClassAtom
, &ConsoleClassAtom
, sizeof(ATOM
));
2241 ConsInitialized
= TRUE
;
2245 * Set-up the notification window
2247 if (NULL
== NotifyWnd
)
2249 HANDLE ThreadHandle
;
2250 HANDLE GraphicsStartupEvent
;
2252 GraphicsStartupEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
2253 if (NULL
== GraphicsStartupEvent
) return FALSE
;
2255 ThreadHandle
= CreateThread(NULL
,
2257 GuiConsoleGuiThread
,
2258 (PVOID
)&GraphicsStartupEvent
,
2261 if (NULL
== ThreadHandle
)
2263 CloseHandle(GraphicsStartupEvent
);
2264 DPRINT1("CONSRV: Failed to create graphics console thread. Expect problems\n");
2267 SetThreadPriority(ThreadHandle
, THREAD_PRIORITY_HIGHEST
);
2268 CloseHandle(ThreadHandle
);
2270 WaitForSingleObject(GraphicsStartupEvent
, INFINITE
);
2271 CloseHandle(GraphicsStartupEvent
);
2273 if (NULL
== NotifyWnd
)
2275 DPRINT1("CONSRV: Failed to create notification window.\n");
2280 // ConsInitialized = TRUE;
2287 /******************************************************************************
2288 * GUI Console Driver *
2289 ******************************************************************************/
2292 GuiDeinitFrontEnd(IN OUT PFRONTEND This
);
2295 GuiInitFrontEnd(IN OUT PFRONTEND This
,
2296 IN PCONSOLE Console
)
2298 PGUI_INIT_INFO GuiInitInfo
;
2299 PCONSOLE_INFO ConsoleInfo
;
2300 PCONSOLE_START_INFO ConsoleStartInfo
;
2302 PGUI_CONSOLE_DATA GuiData
;
2303 GUI_CONSOLE_INFO TermInfo
;
2306 LPWSTR IconPath
= NULL
;
2309 if (This
== NULL
|| Console
== NULL
|| This
->OldData
== NULL
)
2310 return STATUS_INVALID_PARAMETER
;
2312 ASSERT(This
->Console
== Console
);
2314 GuiInitInfo
= This
->OldData
;
2316 if (GuiInitInfo
->ConsoleInfo
== NULL
|| GuiInitInfo
->ConsoleStartInfo
== NULL
)
2317 return STATUS_INVALID_PARAMETER
;
2319 ConsoleInfo
= GuiInitInfo
->ConsoleInfo
;
2320 ConsoleStartInfo
= GuiInitInfo
->ConsoleStartInfo
;
2322 IconPath
= ConsoleStartInfo
->IconPath
;
2323 IconIndex
= ConsoleStartInfo
->IconIndex
;
2326 /* Terminal data allocation */
2327 GuiData
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_CONSOLE_DATA
));
2330 DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
2331 return STATUS_UNSUCCESSFUL
;
2333 /* HACK */ Console
->TermIFace
.Data
= (PVOID
)GuiData
; /* HACK */
2334 GuiData
->Console
= Console
;
2335 GuiData
->ActiveBuffer
= Console
->ActiveBuffer
;
2336 GuiData
->hWindow
= NULL
;
2338 /* The console can be resized */
2339 Console
->FixedSize
= FALSE
;
2341 InitializeCriticalSection(&GuiData
->Lock
);
2345 * Load terminal settings
2348 /* 1. Load the default settings */
2349 GuiConsoleGetDefaultSettings(&TermInfo
, GuiInitInfo
->ProcessId
);
2351 /* 3. Load the remaining console settings via the registry. */
2352 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
2354 /* Load the terminal infos from the registry. */
2355 GuiConsoleReadUserSettings(&TermInfo
,
2356 ConsoleInfo
->ConsoleTitle
,
2357 GuiInitInfo
->ProcessId
);
2360 * Now, update them with the properties the user might gave to us
2361 * via the STARTUPINFO structure before calling CreateProcess
2362 * (and which was transmitted via the ConsoleStartInfo structure).
2363 * We therefore overwrite the values read in the registry.
2365 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USESHOWWINDOW
)
2367 TermInfo
.ShowWindow
= ConsoleStartInfo
->wShowWindow
;
2369 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USEPOSITION
)
2371 TermInfo
.AutoPosition
= FALSE
;
2372 TermInfo
.WindowOrigin
.x
= ConsoleStartInfo
->dwWindowOrigin
.X
;
2373 TermInfo
.WindowOrigin
.y
= ConsoleStartInfo
->dwWindowOrigin
.Y
;
2375 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_RUNFULLSCREEN
)
2377 TermInfo
.FullScreen
= TRUE
;
2386 Length
= min(wcslen(TermInfo
.FaceName
) + 1, LF_FACESIZE
); // wcsnlen
2387 wcsncpy(GuiData
->GuiInfo
.FaceName
, TermInfo
.FaceName
, LF_FACESIZE
);
2388 GuiData
->GuiInfo
.FaceName
[Length
] = L
'\0';
2389 GuiData
->GuiInfo
.FontFamily
= TermInfo
.FontFamily
;
2390 GuiData
->GuiInfo
.FontSize
= TermInfo
.FontSize
;
2391 GuiData
->GuiInfo
.FontWeight
= TermInfo
.FontWeight
;
2392 GuiData
->GuiInfo
.UseRasterFonts
= TermInfo
.UseRasterFonts
;
2393 GuiData
->GuiInfo
.FullScreen
= TermInfo
.FullScreen
;
2394 GuiData
->GuiInfo
.ShowWindow
= TermInfo
.ShowWindow
;
2395 GuiData
->GuiInfo
.AutoPosition
= TermInfo
.AutoPosition
;
2396 GuiData
->GuiInfo
.WindowOrigin
= TermInfo
.WindowOrigin
;
2398 /* Initialize the icon handles to their default values */
2399 GuiData
->hIcon
= ghDefaultIcon
;
2400 GuiData
->hIconSm
= ghDefaultIconSm
;
2402 /* Get the associated icon, if any */
2403 if (IconPath
== NULL
|| IconPath
[0] == L
'\0')
2405 IconPath
= ConsoleStartInfo
->AppPath
;
2408 DPRINT("IconPath = %S ; IconIndex = %lu\n", (IconPath
? IconPath
: L
"n/a"), IconIndex
);
2409 if (IconPath
&& IconPath
[0] != L
'\0')
2411 HICON hIcon
= NULL
, hIconSm
= NULL
;
2412 PrivateExtractIconExW(IconPath
,
2417 DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon
, hIconSm
);
2420 DPRINT("Effectively set the icons\n");
2421 GuiData
->hIcon
= hIcon
;
2422 GuiData
->hIconSm
= hIconSm
;
2426 /* Original system palette */
2427 GuiData
->hSysPalette
= NULL
;
2429 /* Mouse is shown by default with its default cursor shape */
2430 GuiData
->hCursor
= ghDefaultCursor
;
2431 GuiData
->MouseCursorRefCount
= 0;
2433 /* A priori don't ignore mouse signals */
2434 GuiData
->IgnoreNextMouseSignal
= FALSE
;
2436 /* Close button and the corresponding system menu item are enabled by default */
2437 GuiData
->IsCloseButtonEnabled
= TRUE
;
2439 /* There is no user-reserved menu id range by default */
2440 GuiData
->cmdIdLow
= GuiData
->cmdIdHigh
= 0;
2443 * We need to wait until the GUI has been fully initialized
2444 * to retrieve custom settings i.e. WindowSize etc...
2445 * Ideally we could use SendNotifyMessage for this but its not
2448 GuiData
->hGuiInitEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
2450 DPRINT("GUI - Checkpoint\n");
2452 /* Create the terminal window */
2453 PostMessageW(NotifyWnd
, PM_CREATE_CONSOLE
, GuiData
->GuiInfo
.ShowWindow
, (LPARAM
)GuiData
);
2455 /* Wait until initialization has finished */
2456 WaitForSingleObject(GuiData
->hGuiInitEvent
, INFINITE
);
2457 DPRINT("OK we created the console window\n");
2458 CloseHandle(GuiData
->hGuiInitEvent
);
2459 GuiData
->hGuiInitEvent
= NULL
;
2461 /* Check whether we really succeeded in initializing the terminal window */
2462 if (GuiData
->hWindow
== NULL
)
2464 DPRINT("GuiInitConsole - We failed at creating a new terminal window\n");
2465 GuiDeinitFrontEnd(This
);
2466 return STATUS_UNSUCCESSFUL
;
2469 /* Finally, finish to initialize the frontend structure */
2470 This
->Data
= GuiData
;
2471 if (This
->OldData
) ConsoleFreeHeap(This
->OldData
);
2472 This
->OldData
= NULL
;
2474 return STATUS_SUCCESS
;
2478 GuiDeinitFrontEnd(IN OUT PFRONTEND This
)
2480 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2482 SendMessageW(NotifyWnd
, PM_DESTROY_CONSOLE
, 0, (LPARAM
)GuiData
);
2484 DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
2485 GuiData
->hIcon
, ghDefaultIcon
, GuiData
->hIconSm
, ghDefaultIconSm
);
2486 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
2488 DPRINT("Destroy hIcon\n");
2489 DestroyIcon(GuiData
->hIcon
);
2491 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
2493 DPRINT("Destroy hIconSm\n");
2494 DestroyIcon(GuiData
->hIconSm
);
2498 DeleteCriticalSection(&GuiData
->Lock
);
2499 ConsoleFreeHeap(GuiData
);
2501 DPRINT("Quit GuiDeinitFrontEnd\n");
2505 GuiDrawRegion(IN OUT PFRONTEND This
,
2508 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2511 SmallRectToRect(GuiData
, &RegionRect
, Region
);
2512 /* Do not erase the background: it speeds up redrawing and reduce flickering */
2513 InvalidateRect(GuiData
->hWindow
, &RegionRect
, FALSE
);
2517 GuiWriteStream(IN OUT PFRONTEND This
,
2525 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2526 PCONSOLE_SCREEN_BUFFER Buff
;
2527 SHORT CursorEndX
, CursorEndY
;
2530 if (NULL
== GuiData
|| NULL
== GuiData
->hWindow
) return;
2532 Buff
= GuiData
->ActiveBuffer
; // ConDrvGetActiveScreenBuffer(GuiData->Console);
2533 if (GetType(Buff
) != TEXTMODE_BUFFER
) return;
2535 if (0 != ScrolledLines
)
2537 ScrollRect
.left
= 0;
2539 ScrollRect
.right
= Buff
->ViewSize
.X
* GuiData
->CharWidth
;
2540 ScrollRect
.bottom
= Region
->Top
* GuiData
->CharHeight
;
2542 ScrollWindowEx(GuiData
->hWindow
,
2544 -(int)(ScrolledLines
* GuiData
->CharHeight
),
2552 GuiDrawRegion(This
, Region
);
2554 if (CursorStartX
< Region
->Left
|| Region
->Right
< CursorStartX
2555 || CursorStartY
< Region
->Top
|| Region
->Bottom
< CursorStartY
)
2557 GuiInvalidateCell(This
, CursorStartX
, CursorStartY
);
2560 CursorEndX
= Buff
->CursorPosition
.X
;
2561 CursorEndY
= Buff
->CursorPosition
.Y
;
2562 if ((CursorEndX
< Region
->Left
|| Region
->Right
< CursorEndX
2563 || CursorEndY
< Region
->Top
|| Region
->Bottom
< CursorEndY
)
2564 && (CursorEndX
!= CursorStartX
|| CursorEndY
!= CursorStartY
))
2566 GuiInvalidateCell(This
, CursorEndX
, CursorEndY
);
2569 // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
2570 // repaint the window without having it just freeze up and stay on the screen permanently.
2571 Buff
->CursorBlinkOn
= TRUE
;
2572 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
2576 GuiSetCursorInfo(IN OUT PFRONTEND This
,
2577 PCONSOLE_SCREEN_BUFFER Buff
)
2579 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2581 if (/*ConDrvGetActiveScreenBuffer(GuiData->Console)*/GuiData
->ActiveBuffer
== Buff
)
2583 GuiInvalidateCell(This
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
2590 GuiSetScreenInfo(IN OUT PFRONTEND This
,
2591 PCONSOLE_SCREEN_BUFFER Buff
,
2595 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2597 if (/*ConDrvGetActiveScreenBuffer(GuiData->Console)*/GuiData
->ActiveBuffer
== Buff
)
2599 /* Redraw char at old position (remove cursor) */
2600 GuiInvalidateCell(This
, OldCursorX
, OldCursorY
);
2601 /* Redraw char at new position (show cursor) */
2602 GuiInvalidateCell(This
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
2609 GuiResizeTerminal(IN OUT PFRONTEND This
)
2611 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2613 /* Resize the window to the user's values */
2614 // GuiData->WindowSizeLock = TRUE;
2615 // GuiConsoleResizeWindow(GuiData);
2616 // GuiData->WindowSizeLock = FALSE;
2617 // NOTE: This code ^^ causes deadlocks...
2619 PostMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
2623 GuiSetActiveScreenBuffer(IN OUT PFRONTEND This
)
2625 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2626 PCONSOLE_SCREEN_BUFFER ActiveBuffer
; // = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(GuiData->Console);
2630 EnterCriticalSection(&GuiData
->Lock
);
2631 GuiData
->WindowSizeLock
= TRUE
;
2633 InterlockedExchangePointer(&GuiData
->ActiveBuffer
,
2634 GuiData
->Console
->ActiveBuffer
);
2636 GuiData
->WindowSizeLock
= FALSE
;
2637 LeaveCriticalSection(&GuiData
->Lock
);
2639 ActiveBuffer
= GuiData
->ActiveBuffer
;
2641 /* Change the current palette */
2642 if (ActiveBuffer
->PaletteHandle
== NULL
)
2644 hPalette
= GuiData
->hSysPalette
;
2648 hPalette
= ActiveBuffer
->PaletteHandle
;
2651 DPRINT1("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette
);
2653 /* Get the Device Context of the console window */
2654 hDC
= GetDC(GuiData
->hWindow
);
2656 /* Set the new palette */
2657 SelectPalette(hDC
, hPalette
, FALSE
);
2659 /* Specify the use of the system palette */
2660 SetSystemPaletteUse(hDC
, ActiveBuffer
->PaletteUsage
);
2662 /* Realize the (logical) palette */
2663 RealizePalette(hDC
);
2665 /* Release the Device Context */
2666 ReleaseDC(GuiData
->hWindow
, hDC
);
2668 GuiResizeTerminal(This
);
2669 // ConioDrawConsole(Console);
2673 GuiReleaseScreenBuffer(IN OUT PFRONTEND This
,
2674 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer
)
2676 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2680 * If we were notified to release a screen buffer that is not actually
2681 * ours, then just ignore the notification...
2683 if (ScreenBuffer
!= GuiData
->ActiveBuffer
) return;
2686 * ... else, we must release our active buffer. Two cases are present:
2687 * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console
2688 * active screen buffer, then we can safely switch to it.
2689 * - If ScreenBuffer IS the console active screen buffer, we must release
2693 /* Get the Device Context of the console window */
2694 hDC
= GetDC(GuiData
->hWindow
);
2696 /* Release the old active palette and set the default one */
2697 if (GetCurrentObject(hDC
, OBJ_PAL
) == ScreenBuffer
->PaletteHandle
)
2699 /* Set the new palette */
2700 SelectPalette(hDC
, GuiData
->hSysPalette
, FALSE
);
2703 /* Release the Device Context */
2704 ReleaseDC(GuiData
->hWindow
, hDC
);
2706 /* Set the adequate active screen buffer */
2707 if (ScreenBuffer
!= GuiData
->Console
->ActiveBuffer
)
2709 GuiSetActiveScreenBuffer(This
);
2713 EnterCriticalSection(&GuiData
->Lock
);
2714 GuiData
->WindowSizeLock
= TRUE
;
2716 InterlockedExchangePointer(&GuiData
->ActiveBuffer
, NULL
);
2718 GuiData
->WindowSizeLock
= FALSE
;
2719 LeaveCriticalSection(&GuiData
->Lock
);
2724 GuiProcessKeyCallback(IN OUT PFRONTEND This
,
2728 UINT VirtualKeyCode
,
2731 if ((ShiftState
& (RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
) || KeyStateMenu
& 0x80) &&
2732 (VirtualKeyCode
== VK_ESCAPE
|| VirtualKeyCode
== VK_TAB
|| VirtualKeyCode
== VK_SPACE
))
2734 DefWindowProcW(msg
->hwnd
, msg
->message
, msg
->wParam
, msg
->lParam
);
2742 GuiSetMouseCursor(IN OUT PFRONTEND This
,
2746 GuiRefreshInternalInfo(IN OUT PFRONTEND This
)
2748 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2750 /* Update the console leader information held by the window */
2751 SetConsoleWndConsoleLeaderCID(GuiData
);
2755 * We reset the cursor here so that, when a console app quits, we reset
2756 * the cursor to the default one. It's quite a hack since it doesn't proceed
2757 * per - console process... This must be fixed.
2759 * See GuiInitConsole(...) for more information.
2762 /* Mouse is shown by default with its default cursor shape */
2763 GuiData
->MouseCursorRefCount
= 0; // Reinitialize the reference counter
2764 GuiSetMouseCursor(This
, NULL
);
2768 GuiChangeTitle(IN OUT PFRONTEND This
)
2770 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2771 // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
2772 SetWindowText(GuiData
->hWindow
, GuiData
->Console
->Title
.Buffer
);
2776 GuiChangeIcon(IN OUT PFRONTEND This
,
2779 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2780 HICON hIcon
, hIconSm
;
2782 if (hWindowIcon
== NULL
)
2784 hIcon
= ghDefaultIcon
;
2785 hIconSm
= ghDefaultIconSm
;
2789 hIcon
= CopyIcon(hWindowIcon
);
2790 hIconSm
= CopyIcon(hWindowIcon
);
2798 if (hIcon
!= GuiData
->hIcon
)
2800 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
2802 DestroyIcon(GuiData
->hIcon
);
2804 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
2806 DestroyIcon(GuiData
->hIconSm
);
2809 GuiData
->hIcon
= hIcon
;
2810 GuiData
->hIconSm
= hIconSm
;
2812 DPRINT("Set icons in GuiChangeIcon\n");
2813 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
2814 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
2821 GuiGetConsoleWindowHandle(IN OUT PFRONTEND This
)
2823 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2824 return GuiData
->hWindow
;
2828 GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This
,
2831 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2832 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
2835 UINT WidthUnit
, HeightUnit
;
2839 if (!SystemParametersInfoW(SPI_GETWORKAREA
, 0, &WorkArea
, 0))
2841 DPRINT1("SystemParametersInfoW failed - What to do ??\n");
2845 // ActiveBuffer = ConDrvGetActiveScreenBuffer(GuiData->Console);
2846 ActiveBuffer
= GuiData
->ActiveBuffer
;
2849 GetScreenBufferSizeUnits(ActiveBuffer
, GuiData
, &WidthUnit
, &HeightUnit
);
2853 /* Default: text mode */
2854 WidthUnit
= GuiData
->CharWidth
;
2855 HeightUnit
= GuiData
->CharHeight
;
2858 width
= WorkArea
.right
;
2859 height
= WorkArea
.bottom
;
2861 width
-= (2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
)));
2862 height
-= (2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
));
2864 if (width
< 0) width
= 0;
2865 if (height
< 0) height
= 0;
2867 pSize
->X
= (SHORT
)(width
/ (int)WidthUnit
) /* HACK */ + 2;
2868 pSize
->Y
= (SHORT
)(height
/ (int)HeightUnit
) /* HACK */ + 1;
2872 GuiSetPalette(IN OUT PFRONTEND This
,
2873 HPALETTE PaletteHandle
,
2876 BOOL Success
= TRUE
;
2877 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2878 // PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(GuiData->Console);
2880 HPALETTE OldPalette
;
2882 DPRINT1("GuiSetPalette checkpt 0\n");
2884 // if (GetType(ActiveBuffer) != GRAPHICS_BUFFER) return FALSE;
2885 if (PaletteHandle
== NULL
) return FALSE
;
2887 DPRINT1("GuiSetPalette checkpt 1\n");
2889 /* Get the Device Context of the console window */
2890 hDC
= GetDC(GuiData
->hWindow
);
2892 DPRINT1("GuiSetPalette calling SelectPalette(0x%p, 0x%p, FALSE)\n", hDC
, PaletteHandle
);
2894 /* Set the new palette */
2895 OldPalette
= SelectPalette(hDC
, PaletteHandle
, FALSE
);
2896 DPRINT1("OldPalette = 0x%p\n", OldPalette
);
2897 if (OldPalette
== NULL
)
2899 DPRINT1("SelectPalette failed\n");
2904 DPRINT1("GuiSetPalette checkpt 2\n");
2906 /* Specify the use of the system palette */
2907 SetSystemPaletteUse(hDC
, PaletteUsage
);
2909 /* Realize the (logical) palette */
2910 RealizePalette(hDC
);
2912 DPRINT1("GuiData->hSysPalette before == 0x%p\n", GuiData
->hSysPalette
);
2914 /* Save the original system palette handle */
2915 if (GuiData
->hSysPalette
== NULL
) GuiData
->hSysPalette
= OldPalette
;
2917 DPRINT1("GuiData->hSysPalette after == 0x%p\n", GuiData
->hSysPalette
);
2920 DPRINT1("GuiSetPalette Quit\n");
2921 /* Release the Device Context and return */
2922 ReleaseDC(GuiData
->hWindow
, hDC
);
2927 GuiGetDisplayMode(IN OUT PFRONTEND This
)
2929 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2930 ULONG DisplayMode
= 0;
2932 if (GuiData
->GuiInfo
.FullScreen
)
2933 DisplayMode
|= CONSOLE_FULLSCREEN_HARDWARE
; // CONSOLE_FULLSCREEN
2935 DisplayMode
|= CONSOLE_WINDOWED
;
2941 GuiSetDisplayMode(IN OUT PFRONTEND This
,
2944 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2947 if (NewMode
& ~(CONSOLE_FULLSCREEN_MODE
| CONSOLE_WINDOWED_MODE
))
2950 FullScreen
= ((NewMode
& CONSOLE_FULLSCREEN_MODE
) != 0);
2952 if (FullScreen
!= GuiData
->GuiInfo
.FullScreen
)
2954 SwitchFullScreen(GuiData
, FullScreen
);
2961 GuiShowMouseCursor(IN OUT PFRONTEND This
,
2964 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2966 /* Set the reference count */
2967 if (Show
) ++GuiData
->MouseCursorRefCount
;
2968 else --GuiData
->MouseCursorRefCount
;
2970 /* Effectively show (or hide) the cursor (use special values for (w|l)Param) */
2971 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
2973 return GuiData
->MouseCursorRefCount
;
2977 GuiSetMouseCursor(IN OUT PFRONTEND This
,
2980 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2983 * Set the cursor's handle. If the given handle is NULL,
2984 * then restore the default cursor.
2986 GuiData
->hCursor
= (hCursor
? hCursor
: ghDefaultCursor
);
2988 /* Effectively modify the shape of the cursor (use special values for (w|l)Param) */
2989 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
2995 GuiMenuControl(IN OUT PFRONTEND This
,
2999 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
3001 GuiData
->cmdIdLow
= cmdIdLow
;
3002 GuiData
->cmdIdHigh
= cmdIdHigh
;
3004 return GetSystemMenu(GuiData
->hWindow
, FALSE
);
3008 GuiSetMenuClose(IN OUT PFRONTEND This
,
3012 * NOTE: See http://www.mail-archive.com/harbour@harbour-project.org/msg27509.html
3013 * or http://harbour-devel.1590103.n2.nabble.com/Question-about-hb-gt-win-CtrlHandler-usage-td4670862i20.html
3014 * for more information.
3017 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
3018 HMENU hSysMenu
= GetSystemMenu(GuiData
->hWindow
, FALSE
);
3020 if (hSysMenu
== NULL
) return FALSE
;
3022 GuiData
->IsCloseButtonEnabled
= Enable
;
3023 EnableMenuItem(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
| (Enable
? MF_ENABLED
: MF_GRAYED
));
3028 static FRONTEND_VTBL GuiVtbl
=
3037 GuiSetActiveScreenBuffer
,
3038 GuiReleaseScreenBuffer
,
3039 GuiProcessKeyCallback
,
3040 GuiRefreshInternalInfo
,
3043 GuiGetConsoleWindowHandle
,
3044 GuiGetLargestConsoleWindowSize
,
3056 LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo
,
3057 IN OUT PCONSOLE_INFO ConsoleInfo
)
3059 #define PATH_SEPARATOR L'\\'
3061 BOOL RetVal
= FALSE
;
3062 HRESULT hRes
= S_OK
;
3063 LPWSTR LinkName
= NULL
;
3066 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
3069 ConsoleStartInfo
->IconPath
[0] = L
'\0';
3070 ConsoleStartInfo
->IconIndex
= 0;
3072 /* 1- Find the last path separator if any */
3073 LinkName
= wcsrchr(ConsoleStartInfo
->ConsoleTitle
, PATH_SEPARATOR
);
3074 if (LinkName
== NULL
)
3076 LinkName
= ConsoleStartInfo
->ConsoleTitle
;
3080 /* Skip the path separator */
3084 /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
3085 Length
= wcslen(LinkName
);
3086 if ( (Length
<= 4) || (wcsicmp(LinkName
+ (Length
- 4), L
".lnk") != 0) )
3089 /* 3- It may be a link. Try to retrieve some properties */
3090 hRes
= CoInitialize(NULL
);
3091 if (SUCCEEDED(hRes
))
3093 /* Get a pointer to the IShellLink interface */
3094 IShellLinkW
* pshl
= NULL
;
3095 hRes
= CoCreateInstance(&CLSID_ShellLink
,
3097 CLSCTX_INPROC_SERVER
,
3100 if (SUCCEEDED(hRes
))
3102 /* Get a pointer to the IPersistFile interface */
3103 IPersistFile
* ppf
= NULL
;
3104 hRes
= IPersistFile_QueryInterface(pshl
, &IID_IPersistFile
, (LPVOID
*)&ppf
);
3105 if (SUCCEEDED(hRes
))
3107 /* Load the shortcut */
3108 hRes
= IPersistFile_Load(ppf
, ConsoleStartInfo
->ConsoleTitle
, STGM_READ
);
3109 if (SUCCEEDED(hRes
))
3112 * Finally we can get the properties !
3113 * Update the old ones if needed.
3118 /* Reset the name of the console with the name of the shortcut */
3119 Length
= min(/*Length*/ Length
- 4, // 4 == len(".lnk")
3120 sizeof(ConsoleInfo
->ConsoleTitle
) / sizeof(ConsoleInfo
->ConsoleTitle
[0]) - 1);
3121 wcsncpy(ConsoleInfo
->ConsoleTitle
, LinkName
, Length
);
3122 ConsoleInfo
->ConsoleTitle
[Length
] = L
'\0';
3124 /* Get the window showing command */
3125 hRes
= IShellLinkW_GetShowCmd(pshl
, &ShowCmd
);
3126 if (SUCCEEDED(hRes
)) ConsoleStartInfo
->wShowWindow
= (WORD
)ShowCmd
;
3128 /* Get the hotkey */
3129 // hRes = pshl->GetHotkey(&ShowCmd);
3130 // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey;
3132 /* Get the icon location, if any */
3134 hRes
= IShellLinkW_GetIconLocation(pshl
,
3135 ConsoleStartInfo
->IconPath
,
3136 sizeof(ConsoleStartInfo
->IconPath
)/sizeof(ConsoleStartInfo
->IconPath
[0]) - 1, // == MAX_PATH
3137 &ConsoleStartInfo
->IconIndex
);
3138 if (!SUCCEEDED(hRes
))
3140 ConsoleStartInfo
->IconPath
[0] = L
'\0';
3141 ConsoleStartInfo
->IconIndex
= 0;
3144 // FIXME: Since we still don't load console properties from the shortcut,
3145 // return false. When this will be done, we will return true instead.
3148 IPersistFile_Release(ppf
);
3150 IShellLinkW_Release(pshl
);
3159 GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd
,
3160 IN OUT PCONSOLE_INFO ConsoleInfo
,
3161 IN OUT PVOID ExtraConsoleInfo
,
3164 PCONSOLE_START_INFO ConsoleStartInfo
= ExtraConsoleInfo
;
3165 PGUI_INIT_INFO GuiInitInfo
;
3167 if (FrontEnd
== NULL
|| ConsoleInfo
== NULL
|| ConsoleStartInfo
== NULL
)
3168 return STATUS_INVALID_PARAMETER
;
3170 /* Initialize GUI terminal emulator common functionalities */
3171 if (!GuiInit()) return STATUS_UNSUCCESSFUL
;
3174 * Load per-application terminal settings.
3176 * Check whether the process creating the console was launched via
3177 * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the
3178 * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too.
3180 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
)
3182 if (!LoadShellLinkConsoleInfo(ConsoleStartInfo
, ConsoleInfo
))
3184 ConsoleStartInfo
->dwStartupFlags
&= ~STARTF_TITLEISLINKNAME
;
3189 * Initialize a private initialization info structure for later use.
3190 * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd.
3192 GuiInitInfo
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_INIT_INFO
));
3193 if (GuiInitInfo
== NULL
) return STATUS_NO_MEMORY
;
3195 // HACK: We suppose that the pointers will be valid in GuiInitFrontEnd...
3196 GuiInitInfo
->ConsoleInfo
= ConsoleInfo
;
3197 GuiInitInfo
->ConsoleStartInfo
= ConsoleStartInfo
;
3198 GuiInitInfo
->ProcessId
= ProcessId
;
3200 /* Finally, initialize the frontend structure */
3201 FrontEnd
->Vtbl
= &GuiVtbl
;
3202 FrontEnd
->Data
= NULL
;
3203 FrontEnd
->OldData
= GuiInitInfo
;
3205 return STATUS_SUCCESS
;
3209 GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd
)
3211 if (FrontEnd
== NULL
) return STATUS_INVALID_PARAMETER
;
3213 if (FrontEnd
->Data
) GuiDeinitFrontEnd(FrontEnd
);
3214 if (FrontEnd
->OldData
) ConsoleFreeHeap(FrontEnd
->OldData
);
3216 return STATUS_SUCCESS
;