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_CONWND_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 /* Clear the old selection */
281 // GuiConsoleUpdateSelection(Console, NULL);
282 Console
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
284 /* Restart a new selection */
285 Console
->dwSelectionCursor
.X
= ActiveBuffer
->ViewOrigin
.X
;
286 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->ViewOrigin
.Y
;
287 Console
->Selection
.dwSelectionAnchor
= Console
->dwSelectionCursor
;
288 GuiConsoleUpdateSelection(Console
, &Console
->Selection
.dwSelectionAnchor
);
293 case ID_SYSTEM_EDIT_COPY
:
294 GuiConsoleCopy(GuiData
);
297 case ID_SYSTEM_EDIT_PASTE
:
298 GuiConsolePaste(GuiData
);
301 case ID_SYSTEM_EDIT_SELECTALL
:
303 /* Clear the old selection */
304 // GuiConsoleUpdateSelection(Console, NULL);
305 Console
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
308 * The selection area extends to the whole screen buffer's width.
310 Console
->Selection
.dwSelectionAnchor
.X
= 0;
311 Console
->Selection
.dwSelectionAnchor
.Y
= 0;
312 Console
->dwSelectionCursor
.X
= ActiveBuffer
->ScreenBufferSize
.X
- 1;
315 * Determine whether the selection must extend to just some part
316 * (for text-mode screen buffers) or to all of the screen buffer's
317 * height (for graphics ones).
319 if (GetType(ActiveBuffer
) == TEXTMODE_BUFFER
)
322 * We select all the characters from the first line
323 * to the line where the cursor is positioned.
325 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->CursorPosition
.Y
;
327 else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
330 * We select all the screen buffer area.
332 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->ScreenBufferSize
.Y
- 1;
335 /* Restart a new selection */
336 Console
->Selection
.dwFlags
|= CONSOLE_MOUSE_SELECTION
;
337 GuiConsoleUpdateSelection(Console
, &Console
->dwSelectionCursor
);
342 case ID_SYSTEM_EDIT_SCROLL
:
343 DPRINT1("Scrolling is not handled yet\n");
346 case ID_SYSTEM_EDIT_FIND
:
347 DPRINT1("Finding is not handled yet\n");
350 case ID_SYSTEM_DEFAULTS
:
351 GuiConsoleShowConsoleProperties(GuiData
, TRUE
);
354 case ID_SYSTEM_PROPERTIES
:
355 GuiConsoleShowConsoleProperties(GuiData
, FALSE
);
364 LeaveCriticalSection(&Console
->Lock
);
367 Ret
= DefWindowProcW(GuiData
->hWindow
, WM_SYSCOMMAND
, wParam
, lParam
);
372 static PGUI_CONSOLE_DATA
373 GuiGetGuiData(HWND hWnd
)
375 /* This function ensures that the console pointer is not NULL */
376 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
377 return ( ((GuiData
== NULL
) || (GuiData
->hWindow
== hWnd
&& GuiData
->Console
!= NULL
)) ? GuiData
: NULL
);
381 GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData
)
383 /* Move the window if needed (not positioned by the system) */
384 if (!GuiData
->GuiInfo
.AutoPosition
)
386 SetWindowPos(GuiData
->hWindow
,
388 GuiData
->GuiInfo
.WindowOrigin
.x
,
389 GuiData
->GuiInfo
.WindowOrigin
.y
,
392 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
397 GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData
, DWORD WidthUnit
, DWORD HeightUnit
)
399 PCONSOLE_SCREEN_BUFFER Buff
= GuiData
->ActiveBuffer
;
404 Width
= Buff
->ViewSize
.X
* WidthUnit
+
405 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
406 Height
= Buff
->ViewSize
.Y
* HeightUnit
+
407 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
409 /* Set scrollbar sizes */
410 sInfo
.cbSize
= sizeof(SCROLLINFO
);
411 sInfo
.fMask
= SIF_RANGE
| SIF_PAGE
| SIF_POS
;
413 if (Buff
->ScreenBufferSize
.Y
> Buff
->ViewSize
.Y
)
415 sInfo
.nMax
= Buff
->ScreenBufferSize
.Y
- 1;
416 sInfo
.nPage
= Buff
->ViewSize
.Y
;
417 sInfo
.nPos
= Buff
->ViewOrigin
.Y
;
418 SetScrollInfo(GuiData
->hWindow
, SB_VERT
, &sInfo
, TRUE
);
419 Width
+= GetSystemMetrics(SM_CXVSCROLL
);
420 ShowScrollBar(GuiData
->hWindow
, SB_VERT
, TRUE
);
424 ShowScrollBar(GuiData
->hWindow
, SB_VERT
, FALSE
);
427 if (Buff
->ScreenBufferSize
.X
> Buff
->ViewSize
.X
)
429 sInfo
.nMax
= Buff
->ScreenBufferSize
.X
- 1;
430 sInfo
.nPage
= Buff
->ViewSize
.X
;
431 sInfo
.nPos
= Buff
->ViewOrigin
.X
;
432 SetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &sInfo
, TRUE
);
433 Height
+= GetSystemMetrics(SM_CYHSCROLL
);
434 ShowScrollBar(GuiData
->hWindow
, SB_HORZ
, TRUE
);
438 ShowScrollBar(GuiData
->hWindow
, SB_HORZ
, FALSE
);
441 /* Resize the window */
442 SetWindowPos(GuiData
->hWindow
, NULL
, 0, 0, Width
, Height
,
443 SWP_NOZORDER
| SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOCOPYBITS
);
444 // NOTE: The SWP_NOCOPYBITS flag can be replaced by a subsequent call
445 // to: InvalidateRect(GuiData->hWindow, NULL, TRUE);
449 GuiConsoleHandleNcCreate(HWND hWnd
, LPCREATESTRUCTW Create
)
451 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)Create
->lpCreateParams
;
458 DPRINT("GuiConsoleHandleNcCreate\n");
462 DPRINT1("GuiConsoleNcCreate: No GUI data\n");
466 Console
= GuiData
->Console
;
468 GuiData
->hWindow
= hWnd
;
470 GuiData
->Font
= CreateFontW(LOWORD(GuiData
->GuiInfo
.FontSize
),
471 0, // HIWORD(GuiData->GuiInfo.FontSize),
474 GuiData
->GuiInfo
.FontWeight
,
481 NONANTIALIASED_QUALITY
,
482 FIXED_PITCH
| GuiData
->GuiInfo
.FontFamily
/* FF_DONTCARE */,
483 GuiData
->GuiInfo
.FaceName
);
485 if (NULL
== GuiData
->Font
)
487 DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
488 GuiData
->hWindow
= NULL
;
489 SetEvent(GuiData
->hGuiInitEvent
);
492 hDC
= GetDC(GuiData
->hWindow
);
495 DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
496 DeleteObject(GuiData
->Font
);
497 GuiData
->hWindow
= NULL
;
498 SetEvent(GuiData
->hGuiInitEvent
);
501 OldFont
= SelectObject(hDC
, GuiData
->Font
);
504 DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
505 ReleaseDC(GuiData
->hWindow
, hDC
);
506 DeleteObject(GuiData
->Font
);
507 GuiData
->hWindow
= NULL
;
508 SetEvent(GuiData
->hGuiInitEvent
);
511 if (!GetTextMetricsW(hDC
, &Metrics
))
513 DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
514 SelectObject(hDC
, OldFont
);
515 ReleaseDC(GuiData
->hWindow
, hDC
);
516 DeleteObject(GuiData
->Font
);
517 GuiData
->hWindow
= NULL
;
518 SetEvent(GuiData
->hGuiInitEvent
);
521 GuiData
->CharWidth
= Metrics
.tmMaxCharWidth
;
522 GuiData
->CharHeight
= Metrics
.tmHeight
+ Metrics
.tmExternalLeading
;
524 /* Measure real char width more precisely if possible. */
525 if (GetTextExtentPoint32W(hDC
, L
"R", 1, &CharSize
))
526 GuiData
->CharWidth
= CharSize
.cx
;
528 SelectObject(hDC
, OldFont
);
530 ReleaseDC(GuiData
->hWindow
, hDC
);
532 /* Initialize the terminal framebuffer */
533 GuiData
->hMemDC
= CreateCompatibleDC(NULL
);
534 GuiData
->hBitmap
= NULL
;
535 GuiData
->hSysPalette
= NULL
; /* Original system palette */
537 // FIXME: Keep these instructions here ? ///////////////////////////////////
538 Console
->ActiveBuffer
->CursorBlinkOn
= TRUE
;
539 Console
->ActiveBuffer
->ForceCursorOff
= FALSE
;
540 ////////////////////////////////////////////////////////////////////////////
542 SetWindowLongPtrW(GuiData
->hWindow
, GWLP_USERDATA
, (DWORD_PTR
)GuiData
);
544 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
545 GuiConsoleCreateSysMenu(GuiData
->hWindow
);
547 DPRINT("GuiConsoleHandleNcCreate - setting start event\n");
548 SetEvent(GuiData
->hGuiInitEvent
);
550 return (BOOL
)DefWindowProcW(GuiData
->hWindow
, WM_NCCREATE
, 0, (LPARAM
)Create
);
554 SmallRectToRect(PGUI_CONSOLE_DATA GuiData
, PRECT Rect
, PSMALL_RECT SmallRect
)
556 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
557 UINT WidthUnit
, HeightUnit
;
559 GetScreenBufferSizeUnits(Buffer
, GuiData
, &WidthUnit
, &HeightUnit
);
561 Rect
->left
= (SmallRect
->Left
- Buffer
->ViewOrigin
.X
) * WidthUnit
;
562 Rect
->top
= (SmallRect
->Top
- Buffer
->ViewOrigin
.Y
) * HeightUnit
;
563 Rect
->right
= (SmallRect
->Right
+ 1 - Buffer
->ViewOrigin
.X
) * WidthUnit
;
564 Rect
->bottom
= (SmallRect
->Bottom
+ 1 - Buffer
->ViewOrigin
.Y
) * HeightUnit
;
568 GuiConsoleUpdateSelection(PCONSOLE Console
, PCOORD coord
)
570 PGUI_CONSOLE_DATA GuiData
= Console
->TermIFace
.Data
;
573 SmallRectToRect(GuiData
, &oldRect
, &Console
->Selection
.srSelection
);
580 /* Exchange left/top with right/bottom if required */
581 rc
.Left
= min(Console
->Selection
.dwSelectionAnchor
.X
, coord
->X
);
582 rc
.Top
= min(Console
->Selection
.dwSelectionAnchor
.Y
, coord
->Y
);
583 rc
.Right
= max(Console
->Selection
.dwSelectionAnchor
.X
, coord
->X
);
584 rc
.Bottom
= max(Console
->Selection
.dwSelectionAnchor
.Y
, coord
->Y
);
586 SmallRectToRect(GuiData
, &newRect
, &rc
);
588 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
590 if (memcmp(&rc
, &Console
->Selection
.srSelection
, sizeof(SMALL_RECT
)) != 0)
594 /* Calculate the region that needs to be updated */
595 if ((rgn1
= CreateRectRgnIndirect(&oldRect
)))
597 if ((rgn2
= CreateRectRgnIndirect(&newRect
)))
599 if (CombineRgn(rgn1
, rgn2
, rgn1
, RGN_XOR
) != ERROR
)
601 InvalidateRgn(GuiData
->hWindow
, rgn1
, FALSE
);
611 InvalidateRect(GuiData
->hWindow
, &newRect
, FALSE
);
614 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_NOT_EMPTY
;
615 Console
->Selection
.srSelection
= rc
;
616 Console
->dwSelectionCursor
= *coord
;
618 if ((Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) == 0)
620 LPWSTR SelectionType
, WindowTitle
= NULL
;
623 /* Clear the old selection */
624 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
626 InvalidateRect(GuiData
->hWindow
, &oldRect
, FALSE
);
629 if (Console
->Selection
.dwFlags
& CONSOLE_MOUSE_SELECTION
)
631 SelectionType
= L
"Selection - ";
635 SelectionType
= L
"Mark - ";
638 Length
= Console
->Title
.Length
+ wcslen(SelectionType
) + 1;
639 WindowTitle
= ConsoleAllocHeap(0, Length
* sizeof(WCHAR
));
640 wcscpy(WindowTitle
, SelectionType
);
641 wcscat(WindowTitle
, Console
->Title
.Buffer
);
642 SetWindowText(GuiData
->hWindow
, WindowTitle
);
643 ConsoleFreeHeap(WindowTitle
);
645 Console
->Selection
.dwFlags
|= CONSOLE_SELECTION_IN_PROGRESS
;
646 ConioPause(Console
, PAUSED_FROM_SELECTION
);
651 /* Clear the selection */
652 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
654 InvalidateRect(GuiData
->hWindow
, &oldRect
, FALSE
);
657 Console
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
658 ConioUnpause(Console
, PAUSED_FROM_SELECTION
);
660 SetWindowText(GuiData
->hWindow
, Console
->Title
.Buffer
);
666 GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
,
667 PGUI_CONSOLE_DATA GuiData
,
669 PRECT rcFramebuffer
);
671 GuiPaintGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
,
672 PGUI_CONSOLE_DATA GuiData
,
674 PRECT rcFramebuffer
);
677 GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData
)
680 PCONSOLE Console
= GuiData
->Console
;
681 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
685 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
690 ActiveBuffer
= GuiData
->ActiveBuffer
;
692 BeginPaint(GuiData
->hWindow
, &ps
);
693 if (ps
.hdc
!= NULL
&&
694 ps
.rcPaint
.left
< ps
.rcPaint
.right
&&
695 ps
.rcPaint
.top
< ps
.rcPaint
.bottom
)
697 EnterCriticalSection(&GuiData
->Lock
);
699 /* Compose the current screen-buffer on-memory */
700 if (GetType(ActiveBuffer
) == TEXTMODE_BUFFER
)
702 GuiPaintTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)ActiveBuffer
,
703 GuiData
, &ps
.rcPaint
, &rcPaint
);
705 else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
707 GuiPaintGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)ActiveBuffer
,
708 GuiData
, &ps
.rcPaint
, &rcPaint
);
711 /* Send it to screen */
715 rcPaint
.right
- rcPaint
.left
,
716 rcPaint
.bottom
- rcPaint
.top
,
722 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
)
724 SmallRectToRect(GuiData
, &rcPaint
, &Console
->Selection
.srSelection
);
726 /* Invert the selection */
727 if (IntersectRect(&rcPaint
, &ps
.rcPaint
, &rcPaint
))
729 InvertRect(ps
.hdc
, &rcPaint
);
733 LeaveCriticalSection(&GuiData
->Lock
);
735 EndPaint(GuiData
->hWindow
, &ps
);
739 LeaveCriticalSection(&Console
->Lock
);
741 DefWindowProcW(GuiData
->hWindow
, WM_PAINT
, 0, 0);
747 IsSystemKey(WORD VirtualKeyCode
)
749 switch (VirtualKeyCode
)
751 /* From MSDN, "Virtual-Key Codes" */
770 GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
772 PCONSOLE Console
= GuiData
->Console
;
773 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
775 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
777 ActiveBuffer
= GuiData
->ActiveBuffer
;
779 if (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
)
781 WORD VirtualKeyCode
= LOWORD(wParam
);
783 if (msg
!= WM_KEYDOWN
) goto Quit
;
785 if (VirtualKeyCode
== VK_RETURN
)
787 /* Copy (and clear) selection if ENTER is pressed */
788 GuiConsoleCopy(GuiData
);
791 else if ( VirtualKeyCode
== VK_ESCAPE
||
792 (VirtualKeyCode
== 'C' && GetKeyState(VK_CONTROL
) & 0x8000) )
794 /* Cancel selection if ESC or Ctrl-C are pressed */
795 GuiConsoleUpdateSelection(Console
, NULL
);
799 if ((Console
->Selection
.dwFlags
& CONSOLE_MOUSE_SELECTION
) == 0)
801 /* Keyboard selection mode */
802 BOOL Interpreted
= FALSE
;
803 BOOL MajPressed
= (GetKeyState(VK_SHIFT
) & 0x8000);
805 switch (VirtualKeyCode
)
810 if (Console
->dwSelectionCursor
.X
> 0)
811 Console
->dwSelectionCursor
.X
--;
819 if (Console
->dwSelectionCursor
.X
< ActiveBuffer
->ScreenBufferSize
.X
- 1)
820 Console
->dwSelectionCursor
.X
++;
828 if (Console
->dwSelectionCursor
.Y
> 0)
829 Console
->dwSelectionCursor
.Y
--;
837 if (Console
->dwSelectionCursor
.Y
< ActiveBuffer
->ScreenBufferSize
.Y
- 1)
838 Console
->dwSelectionCursor
.Y
++;
846 Console
->dwSelectionCursor
.X
= 0;
847 Console
->dwSelectionCursor
.Y
= 0;
854 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->ScreenBufferSize
.Y
- 1;
861 Console
->dwSelectionCursor
.Y
-= ActiveBuffer
->ViewSize
.Y
;
862 if (Console
->dwSelectionCursor
.Y
< 0)
863 Console
->dwSelectionCursor
.Y
= 0;
871 Console
->dwSelectionCursor
.Y
+= ActiveBuffer
->ViewSize
.Y
;
872 if (Console
->dwSelectionCursor
.Y
>= ActiveBuffer
->ScreenBufferSize
.Y
)
873 Console
->dwSelectionCursor
.Y
= ActiveBuffer
->ScreenBufferSize
.Y
- 1;
885 Console
->Selection
.dwSelectionAnchor
= Console
->dwSelectionCursor
;
887 GuiConsoleUpdateSelection(Console
, &Console
->dwSelectionCursor
);
889 else if (!IsSystemKey(VirtualKeyCode
))
891 /* Emit an error beep sound */
892 SendNotifyMessage(GuiData
->hWindow
, PM_CONSOLE_BEEP
, 0, 0);
899 /* Mouse selection mode */
901 if (!IsSystemKey(VirtualKeyCode
))
903 /* Clear the selection and send the key into the input buffer */
904 GuiConsoleUpdateSelection(Console
, NULL
);
913 if ((Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) == 0)
917 Message
.hwnd
= GuiData
->hWindow
;
918 Message
.message
= msg
;
919 Message
.wParam
= wParam
;
920 Message
.lParam
= lParam
;
922 ConioProcessKey(Console
, &Message
);
926 LeaveCriticalSection(&Console
->Lock
);
930 GuiInvalidateCell(IN OUT PFRONTEND This
, SHORT x
, SHORT y
)
932 SMALL_RECT CellRect
= { x
, y
, x
, y
};
933 GuiDrawRegion(This
, &CellRect
);
937 GuiConsoleHandleTimer(PGUI_CONSOLE_DATA GuiData
)
939 PCONSOLE Console
= GuiData
->Console
;
940 PCONSOLE_SCREEN_BUFFER Buff
;
942 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CURSOR_BLINK_TIME
, NULL
);
944 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
946 Buff
= GuiData
->ActiveBuffer
;
948 if (GetType(Buff
) == TEXTMODE_BUFFER
)
950 GuiInvalidateCell(&Console
->TermIFace
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
951 Buff
->CursorBlinkOn
= !Buff
->CursorBlinkOn
;
953 if ((GuiData
->OldCursor
.x
!= Buff
->CursorPosition
.X
) ||
954 (GuiData
->OldCursor
.y
!= Buff
->CursorPosition
.Y
))
957 int OldScrollX
= -1, OldScrollY
= -1;
958 int NewScrollX
= -1, NewScrollY
= -1;
960 xScroll
.cbSize
= sizeof(SCROLLINFO
);
961 xScroll
.fMask
= SIF_POS
;
962 // Capture the original position of the scroll bars and save them.
963 if (GetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &xScroll
)) OldScrollX
= xScroll
.nPos
;
964 if (GetScrollInfo(GuiData
->hWindow
, SB_VERT
, &xScroll
)) OldScrollY
= xScroll
.nPos
;
966 // If we successfully got the info for the horizontal scrollbar
969 if ((Buff
->CursorPosition
.X
< Buff
->ViewOrigin
.X
) ||
970 (Buff
->CursorPosition
.X
>= (Buff
->ViewOrigin
.X
+ Buff
->ViewSize
.X
)))
972 // Handle the horizontal scroll bar
973 if (Buff
->CursorPosition
.X
>= Buff
->ViewSize
.X
)
974 NewScrollX
= Buff
->CursorPosition
.X
- Buff
->ViewSize
.X
+ 1;
980 NewScrollX
= OldScrollX
;
983 // If we successfully got the info for the vertical scrollbar
986 if ((Buff
->CursorPosition
.Y
< Buff
->ViewOrigin
.Y
) ||
987 (Buff
->CursorPosition
.Y
>= (Buff
->ViewOrigin
.Y
+ Buff
->ViewSize
.Y
)))
989 // Handle the vertical scroll bar
990 if (Buff
->CursorPosition
.Y
>= Buff
->ViewSize
.Y
)
991 NewScrollY
= Buff
->CursorPosition
.Y
- Buff
->ViewSize
.Y
+ 1;
997 NewScrollY
= OldScrollY
;
1001 // Adjust scroll bars and refresh the window if the cursor has moved outside the visible area
1002 // NOTE: OldScroll# and NewScroll# will both be -1 (initial value) if the info for the respective scrollbar
1003 // was not obtained successfully in the previous steps. This means their difference is 0 (no scrolling)
1004 // and their associated scrollbar is left alone.
1005 if ((OldScrollX
!= NewScrollX
) || (OldScrollY
!= NewScrollY
))
1007 Buff
->ViewOrigin
.X
= NewScrollX
;
1008 Buff
->ViewOrigin
.Y
= NewScrollY
;
1009 ScrollWindowEx(GuiData
->hWindow
,
1010 (OldScrollX
- NewScrollX
) * GuiData
->CharWidth
,
1011 (OldScrollY
- NewScrollY
) * GuiData
->CharHeight
,
1017 if (NewScrollX
>= 0)
1019 xScroll
.nPos
= NewScrollX
;
1020 SetScrollInfo(GuiData
->hWindow
, SB_HORZ
, &xScroll
, TRUE
);
1022 if (NewScrollY
>= 0)
1024 xScroll
.nPos
= NewScrollY
;
1025 SetScrollInfo(GuiData
->hWindow
, SB_VERT
, &xScroll
, TRUE
);
1027 UpdateWindow(GuiData
->hWindow
);
1028 // InvalidateRect(GuiData->hWindow, NULL, FALSE);
1029 GuiData
->OldCursor
.x
= Buff
->CursorPosition
.X
;
1030 GuiData
->OldCursor
.y
= Buff
->CursorPosition
.Y
;
1034 else /* if (GetType(Buff) == GRAPHICS_BUFFER) */
1038 LeaveCriticalSection(&Console
->Lock
);
1042 GuiConsoleHandleClose(PGUI_CONSOLE_DATA GuiData
)
1044 PCONSOLE Console
= GuiData
->Console
;
1046 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1049 // TODO: Prompt for termination ? (Warn the user about possible apps running in this console)
1052 * FIXME: Windows will wait up to 5 seconds for the thread to exit.
1053 * We shouldn't wait here, though, since the console lock is entered.
1054 * A copy of the thread list probably needs to be made.
1056 ConDrvConsoleProcessCtrlEvent(Console
, 0, CTRL_CLOSE_EVENT
);
1058 LeaveCriticalSection(&Console
->Lock
);
1063 GuiConsoleHandleNcDestroy(HWND hWnd
)
1065 PGUI_CONSOLE_DATA GuiData
= GuiGetGuiData(hWnd
);
1067 KillTimer(hWnd
, CONGUI_UPDATE_TIMER
);
1068 GetSystemMenu(hWnd
, TRUE
);
1072 /* Free the terminal framebuffer */
1073 if (GuiData
->hMemDC
) DeleteDC(GuiData
->hMemDC
);
1074 if (GuiData
->hBitmap
) DeleteObject(GuiData
->hBitmap
);
1075 // if (GuiData->hSysPalette) DeleteObject(GuiData->hSysPalette);
1076 if (GuiData
->Font
) DeleteObject(GuiData
->Font
);
1079 /* Free the GuiData registration */
1080 SetWindowLongPtrW(hWnd
, GWLP_USERDATA
, (DWORD_PTR
)NULL
);
1082 return DefWindowProcW(hWnd
, WM_NCDESTROY
, 0, 0);
1086 PointToCoord(PGUI_CONSOLE_DATA GuiData
, LPARAM lParam
)
1088 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
1090 UINT WidthUnit
, HeightUnit
;
1092 GetScreenBufferSizeUnits(Buffer
, GuiData
, &WidthUnit
, &HeightUnit
);
1094 Coord
.X
= Buffer
->ViewOrigin
.X
+ ((SHORT
)LOWORD(lParam
) / (int)WidthUnit
);
1095 Coord
.Y
= Buffer
->ViewOrigin
.Y
+ ((SHORT
)HIWORD(lParam
) / (int)HeightUnit
);
1097 /* Clip coordinate to ensure it's inside buffer */
1100 else if (Coord
.X
>= Buffer
->ScreenBufferSize
.X
)
1101 Coord
.X
= Buffer
->ScreenBufferSize
.X
- 1;
1105 else if (Coord
.Y
>= Buffer
->ScreenBufferSize
.Y
)
1106 Coord
.Y
= Buffer
->ScreenBufferSize
.Y
- 1;
1112 GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1115 PCONSOLE Console
= GuiData
->Console
;
1117 if (GuiData
->IgnoreNextMouseSignal
)
1119 if (msg
!= WM_LBUTTONDOWN
&&
1120 msg
!= WM_MBUTTONDOWN
&&
1121 msg
!= WM_RBUTTONDOWN
&&
1122 msg
!= WM_MOUSEMOVE
)
1125 * If this mouse signal is not a button-down action or a move,
1126 * then it is the last signal being ignored.
1128 GuiData
->IgnoreNextMouseSignal
= FALSE
;
1133 * This mouse signal is a button-down action or a move.
1134 * Ignore it and perform default action.
1141 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
1147 if ( (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) ||
1148 (Console
->QuickEdit
) )
1152 case WM_LBUTTONDOWN
:
1154 /* Clear the old selection */
1155 // GuiConsoleUpdateSelection(Console, NULL);
1156 Console
->Selection
.dwFlags
= CONSOLE_NO_SELECTION
;
1158 /* Restart a new selection */
1159 Console
->Selection
.dwSelectionAnchor
= PointToCoord(GuiData
, lParam
);
1160 SetCapture(GuiData
->hWindow
);
1161 Console
->Selection
.dwFlags
|= CONSOLE_MOUSE_SELECTION
| CONSOLE_MOUSE_DOWN
;
1162 GuiConsoleUpdateSelection(Console
, &Console
->Selection
.dwSelectionAnchor
);
1171 if (!(Console
->Selection
.dwFlags
& CONSOLE_MOUSE_DOWN
)) break;
1173 // c = PointToCoord(GuiData, lParam);
1174 Console
->Selection
.dwFlags
&= ~CONSOLE_MOUSE_DOWN
;
1175 // GuiConsoleUpdateSelection(Console, &c);
1181 case WM_LBUTTONDBLCLK
:
1183 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
1185 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
1187 #ifdef IS_WHITESPACE
1188 #undef IS_WHITESPACE
1190 #define IS_WHITESPACE(c) \
1191 ((c) == L'\0' || (c) == L' ' || (c) == L'\t' || (c) == L'\r' || (c) == L'\n')
1193 PTEXTMODE_SCREEN_BUFFER TextBuffer
= (PTEXTMODE_SCREEN_BUFFER
)Buffer
;
1195 PCHAR_INFO ptrL
, ptrR
;
1197 /* Starting point */
1198 cL
= cR
= PointToCoord(GuiData
, lParam
);
1199 ptrL
= ptrR
= ConioCoordToPointer(TextBuffer
, cL
.X
, cL
.Y
);
1201 /* Enlarge the selection by checking for whitespace */
1202 while ((0 < cL
.X
) && !IS_WHITESPACE(ptrL
->Char
.UnicodeChar
)
1203 && !IS_WHITESPACE((ptrL
-1)->Char
.UnicodeChar
))
1208 while ((cR
.X
< TextBuffer
->ScreenBufferSize
.X
- 1) &&
1209 !IS_WHITESPACE(ptrR
->Char
.UnicodeChar
) &&
1210 !IS_WHITESPACE((ptrR
+1)->Char
.UnicodeChar
))
1217 * Update the selection started with the single
1218 * left-click that preceded this double-click.
1220 Console
->Selection
.dwSelectionAnchor
= cL
;
1221 Console
->dwSelectionCursor
= cR
;
1223 SetCapture(GuiData
->hWindow
);
1224 Console
->Selection
.dwFlags
|= CONSOLE_MOUSE_SELECTION
| CONSOLE_MOUSE_DOWN
;
1225 GuiConsoleUpdateSelection(Console
, &Console
->dwSelectionCursor
);
1227 /* Ignore the next mouse move signal */
1228 GuiData
->IgnoreNextMouseSignal
= TRUE
;
1234 case WM_RBUTTONDOWN
:
1235 case WM_RBUTTONDBLCLK
:
1237 if (!(Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
))
1239 GuiConsolePaste(GuiData
);
1243 GuiConsoleCopy(GuiData
);
1246 /* Ignore the next mouse move signal */
1247 GuiData
->IgnoreNextMouseSignal
= TRUE
;
1255 if (!(wParam
& MK_LBUTTON
)) break;
1256 if (!(Console
->Selection
.dwFlags
& CONSOLE_MOUSE_DOWN
)) break;
1258 c
= PointToCoord(GuiData
, lParam
); /* TODO: Scroll buffer to bring c into view */
1259 GuiConsoleUpdateSelection(Console
, &c
);
1265 Err
= FALSE
; // TRUE;
1269 else if (Console
->InputBuffer
.Mode
& ENABLE_MOUSE_INPUT
)
1272 WORD wKeyState
= GET_KEYSTATE_WPARAM(wParam
);
1273 DWORD dwButtonState
= 0;
1274 DWORD dwControlKeyState
= 0;
1275 DWORD dwEventFlags
= 0;
1279 case WM_LBUTTONDOWN
:
1280 SetCapture(GuiData
->hWindow
);
1281 dwButtonState
= FROM_LEFT_1ST_BUTTON_PRESSED
;
1285 case WM_MBUTTONDOWN
:
1286 SetCapture(GuiData
->hWindow
);
1287 dwButtonState
= FROM_LEFT_2ND_BUTTON_PRESSED
;
1291 case WM_RBUTTONDOWN
:
1292 SetCapture(GuiData
->hWindow
);
1293 dwButtonState
= RIGHTMOST_BUTTON_PRESSED
;
1315 case WM_LBUTTONDBLCLK
:
1316 dwButtonState
= FROM_LEFT_1ST_BUTTON_PRESSED
;
1317 dwEventFlags
= DOUBLE_CLICK
;
1320 case WM_MBUTTONDBLCLK
:
1321 dwButtonState
= FROM_LEFT_2ND_BUTTON_PRESSED
;
1322 dwEventFlags
= DOUBLE_CLICK
;
1325 case WM_RBUTTONDBLCLK
:
1326 dwButtonState
= RIGHTMOST_BUTTON_PRESSED
;
1327 dwEventFlags
= DOUBLE_CLICK
;
1332 dwEventFlags
= MOUSE_MOVED
;
1336 dwButtonState
= GET_WHEEL_DELTA_WPARAM(wParam
) << 16;
1337 dwEventFlags
= MOUSE_WHEELED
;
1340 case WM_MOUSEHWHEEL
:
1341 dwButtonState
= GET_WHEEL_DELTA_WPARAM(wParam
) << 16;
1342 dwEventFlags
= MOUSE_HWHEELED
;
1352 if (wKeyState
& MK_LBUTTON
)
1353 dwButtonState
|= FROM_LEFT_1ST_BUTTON_PRESSED
;
1354 if (wKeyState
& MK_MBUTTON
)
1355 dwButtonState
|= FROM_LEFT_2ND_BUTTON_PRESSED
;
1356 if (wKeyState
& MK_RBUTTON
)
1357 dwButtonState
|= RIGHTMOST_BUTTON_PRESSED
;
1359 if (GetKeyState(VK_RMENU
) & 0x8000)
1360 dwControlKeyState
|= RIGHT_ALT_PRESSED
;
1361 if (GetKeyState(VK_LMENU
) & 0x8000)
1362 dwControlKeyState
|= LEFT_ALT_PRESSED
;
1363 if (GetKeyState(VK_RCONTROL
) & 0x8000)
1364 dwControlKeyState
|= RIGHT_CTRL_PRESSED
;
1365 if (GetKeyState(VK_LCONTROL
) & 0x8000)
1366 dwControlKeyState
|= LEFT_CTRL_PRESSED
;
1367 if (GetKeyState(VK_SHIFT
) & 0x8000)
1368 dwControlKeyState
|= SHIFT_PRESSED
;
1369 if (GetKeyState(VK_NUMLOCK
) & 0x0001)
1370 dwControlKeyState
|= NUMLOCK_ON
;
1371 if (GetKeyState(VK_SCROLL
) & 0x0001)
1372 dwControlKeyState
|= SCROLLLOCK_ON
;
1373 if (GetKeyState(VK_CAPITAL
) & 0x0001)
1374 dwControlKeyState
|= CAPSLOCK_ON
;
1375 /* See WM_CHAR MSDN documentation for instance */
1376 if (lParam
& 0x01000000)
1377 dwControlKeyState
|= ENHANCED_KEY
;
1379 er
.EventType
= MOUSE_EVENT
;
1380 er
.Event
.MouseEvent
.dwMousePosition
= PointToCoord(GuiData
, lParam
);
1381 er
.Event
.MouseEvent
.dwButtonState
= dwButtonState
;
1382 er
.Event
.MouseEvent
.dwControlKeyState
= dwControlKeyState
;
1383 er
.Event
.MouseEvent
.dwEventFlags
= dwEventFlags
;
1385 ConioProcessInputEvent(Console
, &er
);
1393 LeaveCriticalSection(&Console
->Lock
);
1397 return DefWindowProcW(GuiData
->hWindow
, msg
, wParam
, lParam
);
1403 GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
,
1404 PGUI_CONSOLE_DATA GuiData
);
1406 GuiCopyFromGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
,
1407 PGUI_CONSOLE_DATA GuiData
);
1410 GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData
)
1412 PCONSOLE Console
= GuiData
->Console
;
1414 if (OpenClipboard(GuiData
->hWindow
) == TRUE
)
1416 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
1418 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
1420 GuiCopyFromTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)Buffer
, GuiData
);
1422 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
1424 GuiCopyFromGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)Buffer
, GuiData
);
1430 /* Clear the selection */
1431 GuiConsoleUpdateSelection(Console
, NULL
);
1435 GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
,
1436 PGUI_CONSOLE_DATA GuiData
);
1438 GuiPasteToGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer
,
1439 PGUI_CONSOLE_DATA GuiData
);
1442 GuiConsolePaste(PGUI_CONSOLE_DATA GuiData
)
1444 if (OpenClipboard(GuiData
->hWindow
) == TRUE
)
1446 PCONSOLE_SCREEN_BUFFER Buffer
= GuiData
->ActiveBuffer
;
1448 if (GetType(Buffer
) == TEXTMODE_BUFFER
)
1450 GuiPasteToTextModeBuffer((PTEXTMODE_SCREEN_BUFFER
)Buffer
, GuiData
);
1452 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
1454 GuiPasteToGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER
)Buffer
, GuiData
);
1462 GuiConsoleGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData
, PMINMAXINFO minMaxInfo
)
1464 PCONSOLE Console
= GuiData
->Console
;
1465 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
1467 UINT WidthUnit
, HeightUnit
;
1469 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
1471 ActiveBuffer
= GuiData
->ActiveBuffer
;
1473 GetScreenBufferSizeUnits(ActiveBuffer
, GuiData
, &WidthUnit
, &HeightUnit
);
1475 windx
= CONGUI_MIN_WIDTH
* WidthUnit
+ 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
1476 windy
= CONGUI_MIN_HEIGHT
* HeightUnit
+ 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
1478 minMaxInfo
->ptMinTrackSize
.x
= windx
;
1479 minMaxInfo
->ptMinTrackSize
.y
= windy
;
1481 windx
= (ActiveBuffer
->ScreenBufferSize
.X
) * WidthUnit
+ 2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
));
1482 windy
= (ActiveBuffer
->ScreenBufferSize
.Y
) * HeightUnit
+ 2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
);
1484 if (ActiveBuffer
->ViewSize
.X
< ActiveBuffer
->ScreenBufferSize
.X
) windy
+= GetSystemMetrics(SM_CYHSCROLL
); // window currently has a horizontal scrollbar
1485 if (ActiveBuffer
->ViewSize
.Y
< ActiveBuffer
->ScreenBufferSize
.Y
) windx
+= GetSystemMetrics(SM_CXVSCROLL
); // window currently has a vertical scrollbar
1487 minMaxInfo
->ptMaxTrackSize
.x
= windx
;
1488 minMaxInfo
->ptMaxTrackSize
.y
= windy
;
1490 LeaveCriticalSection(&Console
->Lock
);
1494 GuiConsoleResize(PGUI_CONSOLE_DATA GuiData
, WPARAM wParam
, LPARAM lParam
)
1496 PCONSOLE Console
= GuiData
->Console
;
1498 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
1500 if ((GuiData
->WindowSizeLock
== FALSE
) &&
1501 (wParam
== SIZE_RESTORED
|| wParam
== SIZE_MAXIMIZED
|| wParam
== SIZE_MINIMIZED
))
1503 PCONSOLE_SCREEN_BUFFER Buff
= GuiData
->ActiveBuffer
;
1504 DWORD windx
, windy
, charx
, chary
;
1505 UINT WidthUnit
, HeightUnit
;
1507 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
1509 GuiData
->WindowSizeLock
= TRUE
;
1511 windx
= LOWORD(lParam
);
1512 windy
= HIWORD(lParam
);
1514 // Compensate for existing scroll bars (because lParam values do not accommodate scroll bar)
1515 if (Buff
->ViewSize
.X
< Buff
->ScreenBufferSize
.X
) windy
+= GetSystemMetrics(SM_CYHSCROLL
); // window currently has a horizontal scrollbar
1516 if (Buff
->ViewSize
.Y
< Buff
->ScreenBufferSize
.Y
) windx
+= GetSystemMetrics(SM_CXVSCROLL
); // window currently has a vertical scrollbar
1518 charx
= windx
/ (int)WidthUnit
;
1519 chary
= windy
/ (int)HeightUnit
;
1521 // Character alignment (round size up or down)
1522 if ((windx
% WidthUnit
) >= (WidthUnit
/ 2)) ++charx
;
1523 if ((windy
% HeightUnit
) >= (HeightUnit
/ 2)) ++chary
;
1525 // Compensate for added scroll bars in new window
1526 if (charx
< Buff
->ScreenBufferSize
.X
) windy
-= GetSystemMetrics(SM_CYHSCROLL
); // new window will have a horizontal scroll bar
1527 if (chary
< Buff
->ScreenBufferSize
.Y
) windx
-= GetSystemMetrics(SM_CXVSCROLL
); // new window will have a vertical scroll bar
1529 charx
= windx
/ (int)WidthUnit
;
1530 chary
= windy
/ (int)HeightUnit
;
1532 // Character alignment (round size up or down)
1533 if ((windx
% WidthUnit
) >= (WidthUnit
/ 2)) ++charx
;
1534 if ((windy
% HeightUnit
) >= (HeightUnit
/ 2)) ++chary
;
1537 if ((charx
!= Buff
->ViewSize
.X
) || (chary
!= Buff
->ViewSize
.Y
))
1539 Buff
->ViewSize
.X
= (charx
<= Buff
->ScreenBufferSize
.X
) ? charx
: Buff
->ScreenBufferSize
.X
;
1540 Buff
->ViewSize
.Y
= (chary
<= Buff
->ScreenBufferSize
.Y
) ? chary
: Buff
->ScreenBufferSize
.Y
;
1543 GuiConsoleResizeWindow(GuiData
, WidthUnit
, HeightUnit
);
1545 // Adjust the start of the visible area if we are attempting to show nonexistent areas
1546 if ((Buff
->ScreenBufferSize
.X
- Buff
->ViewOrigin
.X
) < Buff
->ViewSize
.X
) Buff
->ViewOrigin
.X
= Buff
->ScreenBufferSize
.X
- Buff
->ViewSize
.X
;
1547 if ((Buff
->ScreenBufferSize
.Y
- Buff
->ViewOrigin
.Y
) < Buff
->ViewSize
.Y
) Buff
->ViewOrigin
.Y
= Buff
->ScreenBufferSize
.Y
- Buff
->ViewSize
.Y
;
1548 InvalidateRect(GuiData
->hWindow
, NULL
, TRUE
);
1550 GuiData
->WindowSizeLock
= FALSE
;
1553 LeaveCriticalSection(&Console
->Lock
);
1557 // HACK: This functionality is standard for general scrollbars. Don't add it by hand.
1561 GuiConsoleHandleScrollbarMenu(VOID)
1565 hMenu = CreatePopupMenu();
1568 DPRINT("CreatePopupMenu failed\n");
1572 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLHERE);
1573 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1574 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLTOP);
1575 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLBOTTOM);
1576 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1577 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_UP);
1578 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_DOWN);
1579 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1580 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLUP);
1581 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLDOWN);
1586 GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData
, UINT uMsg
, WPARAM wParam
)
1588 PCONSOLE Console
= GuiData
->Console
;
1589 PCONSOLE_SCREEN_BUFFER Buff
;
1592 int old_pos
, Maximum
;
1595 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return 0;
1597 Buff
= GuiData
->ActiveBuffer
;
1599 if (uMsg
== WM_HSCROLL
)
1602 Maximum
= Buff
->ScreenBufferSize
.X
- Buff
->ViewSize
.X
;
1603 pShowXY
= &Buff
->ViewOrigin
.X
;
1608 Maximum
= Buff
->ScreenBufferSize
.Y
- Buff
->ViewSize
.Y
;
1609 pShowXY
= &Buff
->ViewOrigin
.Y
;
1612 /* set scrollbar sizes */
1613 sInfo
.cbSize
= sizeof(SCROLLINFO
);
1614 sInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
| SIF_TRACKPOS
;
1616 if (!GetScrollInfo(GuiData
->hWindow
, fnBar
, &sInfo
)) goto Quit
;
1618 old_pos
= sInfo
.nPos
;
1620 switch (LOWORD(wParam
))
1631 sInfo
.nPos
-= sInfo
.nPage
;
1635 sInfo
.nPos
+= sInfo
.nPage
;
1639 sInfo
.nPos
= sInfo
.nTrackPos
;
1640 ConioPause(Console
, PAUSED_FROM_SCROLLBAR
);
1643 case SB_THUMBPOSITION
:
1644 ConioUnpause(Console
, PAUSED_FROM_SCROLLBAR
);
1648 sInfo
.nPos
= sInfo
.nMin
;
1652 sInfo
.nPos
= sInfo
.nMax
;
1659 sInfo
.nPos
= max(sInfo
.nPos
, 0);
1660 sInfo
.nPos
= min(sInfo
.nPos
, Maximum
);
1662 if (old_pos
!= sInfo
.nPos
)
1664 USHORT OldX
= Buff
->ViewOrigin
.X
;
1665 USHORT OldY
= Buff
->ViewOrigin
.Y
;
1666 UINT WidthUnit
, HeightUnit
;
1668 *pShowXY
= sInfo
.nPos
;
1670 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
1672 ScrollWindowEx(GuiData
->hWindow
,
1673 (OldX
- Buff
->ViewOrigin
.X
) * WidthUnit
,
1674 (OldY
- Buff
->ViewOrigin
.Y
) * HeightUnit
,
1681 sInfo
.fMask
= SIF_POS
;
1682 SetScrollInfo(GuiData
->hWindow
, fnBar
, &sInfo
, TRUE
);
1684 UpdateWindow(GuiData
->hWindow
);
1685 // InvalidateRect(GuiData->hWindow, NULL, FALSE);
1689 LeaveCriticalSection(&Console
->Lock
);
1695 EnterFullScreen(PGUI_CONSOLE_DATA GuiData
);
1697 LeaveFullScreen(PGUI_CONSOLE_DATA GuiData
);
1699 SwitchFullScreen(PGUI_CONSOLE_DATA GuiData
, BOOL FullScreen
);
1701 GuiConsoleSwitchFullScreen(PGUI_CONSOLE_DATA GuiData
);
1703 static LRESULT CALLBACK
1704 GuiConsoleWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1707 PGUI_CONSOLE_DATA GuiData
= NULL
;
1708 PCONSOLE Console
= NULL
;
1711 * - If it's the first time we create a window for the terminal,
1712 * just initialize it and return.
1714 * - If we are destroying the window, just do it and return.
1716 if (msg
== WM_NCCREATE
)
1718 return (LRESULT
)GuiConsoleHandleNcCreate(hWnd
, (LPCREATESTRUCTW
)lParam
);
1720 else if (msg
== WM_NCDESTROY
)
1722 return GuiConsoleHandleNcDestroy(hWnd
);
1726 * Now the terminal window is initialized.
1727 * Get the terminal data via the window's data.
1728 * If there is no data, just go away.
1730 GuiData
= GuiGetGuiData(hWnd
);
1731 if (GuiData
== NULL
) return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1733 // TEMPORARY HACK until all of the functions can deal with a NULL GuiData->ActiveBuffer ...
1734 if (GuiData
->ActiveBuffer
== NULL
) return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1737 * Just retrieve a pointer to the console in case somebody needs it.
1738 * It is not NULL because it was checked in GuiGetGuiData.
1739 * Each helper function which needs the console has to validate and lock it.
1741 Console
= GuiData
->Console
;
1743 /* We have a console, start message dispatching */
1748 WORD ActivationState
= LOWORD(wParam
);
1750 DPRINT1("WM_ACTIVATE - ActivationState = %d\n");
1752 if ( ActivationState
== WA_ACTIVE
||
1753 ActivationState
== WA_CLICKACTIVE
)
1755 if (GuiData
->GuiInfo
.FullScreen
)
1757 EnterFullScreen(GuiData
);
1758 // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
1759 // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
1762 else // if (ActivationState == WA_INACTIVE)
1764 if (GuiData
->GuiInfo
.FullScreen
)
1766 SendMessageW(GuiData
->hWindow
, WM_SYSCOMMAND
, SC_MINIMIZE
, 0);
1767 LeaveFullScreen(GuiData
);
1768 // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
1769 // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
1774 * When we are in QuickEdit mode, ignore the next mouse signal
1775 * when we are going to be enabled again via the mouse, in order
1776 * to prevent e.g. an erroneous right-click from the user which
1777 * would have as an effect to paste some unwanted text...
1779 if (Console
->QuickEdit
&& (ActivationState
== WA_CLICKACTIVE
))
1780 GuiData
->IgnoreNextMouseSignal
= TRUE
;
1786 if (GuiConsoleHandleClose(GuiData
)) goto Default
;
1790 GuiConsoleHandlePaint(GuiData
);
1794 GuiConsoleHandleTimer(GuiData
);
1797 case WM_PALETTECHANGED
:
1799 PCONSOLE_SCREEN_BUFFER ActiveBuffer
= GuiData
->ActiveBuffer
;
1801 DPRINT("WM_PALETTECHANGED called\n");
1804 * Protects against infinite loops:
1805 * "... A window that receives this message must not realize
1806 * its palette, unless it determines that wParam does not contain
1807 * its own window handle." (WM_PALETTECHANGED description - MSDN)
1809 * This message is sent to all windows, including the one that
1810 * changed the system palette and caused this message to be sent.
1811 * The wParam of this message contains the handle of the window
1812 * that caused the system palette to change. To avoid an infinite
1813 * loop, care must be taken to check that the wParam of this message
1814 * does not match the window's handle.
1816 if ((HWND
)wParam
== hWnd
) break;
1818 DPRINT("WM_PALETTECHANGED ok\n");
1820 // if (GetType(ActiveBuffer) == GRAPHICS_BUFFER)
1821 if (ActiveBuffer
->PaletteHandle
)
1823 DPRINT("WM_PALETTECHANGED changing palette\n");
1825 /* Specify the use of the system palette for the framebuffer */
1826 SetSystemPaletteUse(GuiData
->hMemDC
, ActiveBuffer
->PaletteUsage
);
1828 /* Realize the (logical) palette */
1829 RealizePalette(GuiData
->hMemDC
);
1832 DPRINT("WM_PALETTECHANGED quit\n");
1844 case WM_SYSDEADCHAR
:
1846 /* Detect Alt-Enter presses and switch back and forth to fullscreen mode */
1847 if (msg
== WM_SYSKEYDOWN
&& (HIWORD(lParam
) & KF_ALTDOWN
) && wParam
== VK_RETURN
)
1849 /* Switch only at first Alt-Enter press, and ignore subsequent key repetitions */
1850 if ((HIWORD(lParam
) & (KF_UP
| KF_REPEAT
)) != KF_REPEAT
)
1851 GuiConsoleSwitchFullScreen(GuiData
);
1856 GuiConsoleHandleKey(GuiData
, msg
, wParam
, lParam
);
1863 * The message was sent because we are manually triggering a change.
1864 * Check whether the mouse is indeed present on this console window
1865 * and take appropriate decisions.
1867 if (wParam
== -1 && lParam
== -1)
1872 /* Get the placement of the mouse */
1873 GetCursorPos(&mouseCoords
);
1875 /* On which window is placed the mouse ? */
1876 hWndHit
= WindowFromPoint(mouseCoords
);
1878 /* It's our window. Perform the hit-test to be used later on. */
1879 if (hWndHit
== hWnd
)
1881 wParam
= (WPARAM
)hWnd
;
1882 lParam
= DefWindowProcW(hWndHit
, WM_NCHITTEST
, 0,
1883 MAKELPARAM(mouseCoords
.x
, mouseCoords
.y
));
1887 /* Set the mouse cursor only when we are in the client area */
1888 if ((HWND
)wParam
== hWnd
&& LOWORD(lParam
) == HTCLIENT
)
1890 if (GuiData
->MouseCursorRefCount
>= 0)
1892 /* Show the cursor */
1893 SetCursor(GuiData
->hCursor
);
1897 /* Hide the cursor if the reference count is negative */
1908 case WM_LBUTTONDOWN
:
1909 case WM_MBUTTONDOWN
:
1910 case WM_RBUTTONDOWN
:
1914 case WM_LBUTTONDBLCLK
:
1915 case WM_MBUTTONDBLCLK
:
1916 case WM_RBUTTONDBLCLK
:
1919 case WM_MOUSEHWHEEL
:
1921 Result
= GuiConsoleHandleMouse(GuiData
, msg
, wParam
, lParam
);
1928 Result
= GuiConsoleHandleScroll(GuiData
, msg
, wParam
);
1932 case WM_NCRBUTTONDOWN
:
1934 DPRINT1("WM_NCRBUTTONDOWN\n");
1936 * HACK: !! Because, when we deal with WM_RBUTTON* and we do not
1937 * call after that DefWindowProc, on ReactOS, right-clicks on the
1938 * (non-client) application title-bar does not display the system
1939 * menu and does not trigger a WM_NCRBUTTONUP message too.
1940 * See: http://git.reactos.org/?p=reactos.git;a=blob;f=reactos/win32ss/user/user32/windows/defwnd.c;hb=332bc8f482f40fd05ab510f78276576719fbfba8#l1103
1941 * and line 1135 too.
1944 if (DefWindowProcW(hWnd
, WM_NCHITTEST
, 0, lParam
) == HTCAPTION
)
1946 /* Call DefWindowProcW with the WM_CONTEXTMENU message */
1947 msg
= WM_CONTEXTMENU
;
1952 // case WM_NCRBUTTONUP:
1953 // DPRINT1("WM_NCRBUTTONUP\n");
1956 case WM_CONTEXTMENU
:
1958 if (DefWindowProcW(hWnd
/*GuiData->hWindow*/, WM_NCHITTEST
, 0, lParam
) == HTCLIENT
)
1960 HMENU hMenu
= CreatePopupMenu();
1963 GuiConsoleAppendMenuItems(hMenu
, GuiConsoleEditMenuItems
);
1964 TrackPopupMenuEx(hMenu
,
1966 GET_X_LPARAM(lParam
),
1967 GET_Y_LPARAM(lParam
),
1982 HMENU hMenu
= (HMENU
)wParam
;
1985 /* Enable or disable the Close menu item */
1986 EnableMenuItem(hMenu
, SC_CLOSE
, MF_BYCOMMAND
|
1987 (GuiData
->IsCloseButtonEnabled
? MF_ENABLED
: MF_GRAYED
));
1989 /* Enable or disable the Copy and Paste items */
1990 EnableMenuItem(hMenu
, ID_SYSTEM_EDIT_COPY
, MF_BYCOMMAND
|
1991 ((Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) &&
1992 (Console
->Selection
.dwFlags
& CONSOLE_SELECTION_NOT_EMPTY
) ? MF_ENABLED
: MF_GRAYED
));
1993 // FIXME: Following whether the active screen buffer is text-mode
1994 // or graphics-mode, search for CF_UNICODETEXT or CF_BITMAP formats.
1995 EnableMenuItem(hMenu
, ID_SYSTEM_EDIT_PASTE
, MF_BYCOMMAND
|
1996 (!(Console
->Selection
.dwFlags
& CONSOLE_SELECTION_IN_PROGRESS
) &&
1997 IsClipboardFormatAvailable(CF_UNICODETEXT
) ? MF_ENABLED
: MF_GRAYED
));
2000 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
2002 GuiSendMenuEvent(Console
, WM_INITMENU
);
2003 LeaveCriticalSection(&Console
->Lock
);
2010 if (HIWORD(wParam
) == 0xFFFF) // Allow all the menu flags
2012 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
2014 GuiSendMenuEvent(Console
, WM_MENUSELECT
);
2015 LeaveCriticalSection(&Console
->Lock
);
2024 Result
= GuiConsoleHandleSysMenuCommand(GuiData
, wParam
, lParam
);
2031 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
2033 BOOL SetFocus
= (msg
== WM_SETFOCUS
);
2036 er
.EventType
= FOCUS_EVENT
;
2037 er
.Event
.FocusEvent
.bSetFocus
= SetFocus
;
2038 ConioProcessInputEvent(Console
, &er
);
2041 DPRINT1("TODO: Create console caret\n");
2043 DPRINT1("TODO: Destroy console caret\n");
2045 LeaveCriticalSection(&Console
->Lock
);
2050 case WM_GETMINMAXINFO
:
2051 GuiConsoleGetMinMaxInfo(GuiData
, (PMINMAXINFO
)lParam
);
2056 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
2058 // TODO: Simplify the code.
2059 // See: GuiConsoleNotifyWndProc() PM_CREATE_CONSOLE.
2063 /* Retrieve our real position */
2064 GetWindowRect(GuiData
->hWindow
, &rcWnd
);
2065 GuiData
->GuiInfo
.WindowOrigin
.x
= rcWnd
.left
;
2066 GuiData
->GuiInfo
.WindowOrigin
.y
= rcWnd
.top
;
2068 LeaveCriticalSection(&Console
->Lock
);
2074 GuiConsoleResize(GuiData
, wParam
, lParam
);
2077 case PM_RESIZE_TERMINAL
:
2079 PCONSOLE_SCREEN_BUFFER Buff
= GuiData
->ActiveBuffer
;
2083 DWORD Width
, Height
;
2084 UINT WidthUnit
, HeightUnit
;
2086 GetScreenBufferSizeUnits(Buff
, GuiData
, &WidthUnit
, &HeightUnit
);
2088 Width
= Buff
->ScreenBufferSize
.X
* WidthUnit
;
2089 Height
= Buff
->ScreenBufferSize
.Y
* HeightUnit
;
2091 /* Recreate the framebuffer */
2092 hDC
= GetDC(GuiData
->hWindow
);
2093 hnew
= CreateCompatibleBitmap(hDC
, Width
, Height
);
2094 ReleaseDC(GuiData
->hWindow
, hDC
);
2095 hold
= SelectObject(GuiData
->hMemDC
, hnew
);
2096 if (GuiData
->hBitmap
)
2098 if (hold
== GuiData
->hBitmap
) DeleteObject(GuiData
->hBitmap
);
2100 GuiData
->hBitmap
= hnew
;
2102 /* Resize the window to the user's values */
2103 GuiData
->WindowSizeLock
= TRUE
;
2104 GuiConsoleResizeWindow(GuiData
, WidthUnit
, HeightUnit
);
2105 GuiData
->WindowSizeLock
= FALSE
;
2109 case PM_APPLY_CONSOLE_INFO
:
2111 if (ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
2113 GuiApplyUserSettings(GuiData
, (HANDLE
)wParam
, (BOOL
)lParam
);
2114 LeaveCriticalSection(&Console
->Lock
);
2119 case PM_CONSOLE_BEEP
:
2120 DPRINT1("Beep !!\n");
2124 // case PM_CONSOLE_SET_TITLE:
2125 // SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
2129 Result
= DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
2138 /******************************************************************************
2139 * GUI Terminal Initialization *
2140 ******************************************************************************/
2142 static LRESULT CALLBACK
2143 GuiConsoleNotifyWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
2153 SetWindowLongW(hWnd
, GWL_USERDATA
, 0);
2157 case PM_CREATE_CONSOLE
:
2159 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)lParam
;
2160 PCONSOLE Console
= GuiData
->Console
;
2163 NewWindow
= CreateWindowExW(WS_EX_CLIENTEDGE
,
2165 Console
->Title
.Buffer
,
2166 WS_OVERLAPPEDWINDOW
| WS_HSCROLL
| WS_VSCROLL
,
2175 if (NULL
!= NewWindow
)
2177 ASSERT(NewWindow
== GuiData
->hWindow
);
2179 WindowCount
= GetWindowLongW(hWnd
, GWL_USERDATA
);
2181 SetWindowLongW(hWnd
, GWL_USERDATA
, WindowCount
);
2183 DPRINT("Set icons via PM_CREATE_CONSOLE\n");
2184 if (GuiData
->hIcon
== NULL
)
2186 DPRINT("Not really /o\\...\n");
2187 GuiData
->hIcon
= ghDefaultIcon
;
2188 GuiData
->hIconSm
= ghDefaultIconSm
;
2190 else if (GuiData
->hIcon
!= ghDefaultIcon
)
2192 DPRINT("Yes \\o/\n");
2193 SendMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
2194 SendMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
2197 /* Retrieve our real position */
2198 GetWindowRect(GuiData
->hWindow
, &rcWnd
);
2199 GuiData
->GuiInfo
.WindowOrigin
.x
= rcWnd
.left
;
2200 GuiData
->GuiInfo
.WindowOrigin
.y
= rcWnd
.top
;
2202 /* Move and resize the window to the user's values */
2203 /* CAN WE DEADLOCK ?? */
2204 GuiConsoleMoveWindow(GuiData
);
2205 SendMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
2207 /* Switch to full-screen mode if necessary */
2208 if (GuiData
->GuiInfo
.FullScreen
) SwitchFullScreen(GuiData
, TRUE
);
2210 // ShowWindow(NewWindow, (int)wParam);
2211 ShowWindowAsync(NewWindow
, (int)wParam
);
2212 DPRINT("Window showed\n");
2215 return (LRESULT
)NewWindow
;
2218 case PM_DESTROY_CONSOLE
:
2220 PGUI_CONSOLE_DATA GuiData
= (PGUI_CONSOLE_DATA
)lParam
;
2222 /* Exit the full screen mode if it was already set */
2223 // LeaveFullScreen(GuiData);
2226 * Window creation is done using a PostMessage(), so it's possible
2227 * that the window that we want to destroy doesn't exist yet.
2228 * So first empty the message queue.
2231 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
2233 TranslateMessage(&Msg);
2234 DispatchMessageW(&Msg);
2236 while (PeekMessageW(&Msg
, NULL
, 0, 0, PM_REMOVE
)) ;
2238 if (GuiData
->hWindow
!= NULL
) /* && DestroyWindow(GuiData->hWindow) */
2240 DestroyWindow(GuiData
->hWindow
);
2242 WindowCount
= GetWindowLongW(hWnd
, GWL_USERDATA
);
2244 SetWindowLongW(hWnd
, GWL_USERDATA
, WindowCount
);
2245 if (0 == WindowCount
)
2248 DestroyWindow(hWnd
);
2249 DPRINT("CONSRV: Going to quit the Gui Thread!!\n");
2258 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
2263 GuiConsoleGuiThread(PVOID Data
)
2266 PHANDLE GraphicsStartupEvent
= (PHANDLE
)Data
;
2269 * This thread dispatches all the console notifications to the notify window.
2270 * It is common for all the console windows.
2273 PrivateCsrssManualGuiCheck(+1);
2275 NotifyWnd
= CreateWindowW(L
"ConSrvCreateNotify",
2277 WS_OVERLAPPEDWINDOW
,
2286 if (NULL
== NotifyWnd
)
2288 PrivateCsrssManualGuiCheck(-1);
2289 SetEvent(*GraphicsStartupEvent
);
2293 SetEvent(*GraphicsStartupEvent
);
2295 while (GetMessageW(&msg
, NULL
, 0, 0))
2297 TranslateMessage(&msg
);
2298 DispatchMessageW(&msg
);
2301 DPRINT("CONSRV: Quit the Gui Thread!!\n");
2302 PrivateCsrssManualGuiCheck(-1);
2311 ATOM ConsoleClassAtom
;
2313 /* Exit if we were already initialized */
2314 // if (ConsInitialized) return TRUE;
2317 * Initialize and register the different window classes, if needed.
2319 if (!ConsInitialized
)
2321 /* Initialize the notification window class */
2322 wc
.cbSize
= sizeof(WNDCLASSEXW
);
2323 wc
.lpszClassName
= L
"ConSrvCreateNotify";
2324 wc
.lpfnWndProc
= GuiConsoleNotifyWndProc
;
2326 wc
.hInstance
= ConSrvDllInstance
;
2330 wc
.hbrBackground
= NULL
;
2331 wc
.lpszMenuName
= NULL
;
2334 if (RegisterClassExW(&wc
) == 0)
2336 DPRINT1("Failed to register GUI notify wndproc\n");
2340 /* Initialize the console window class */
2341 ghDefaultIcon
= LoadImageW(ConSrvDllInstance
,
2342 MAKEINTRESOURCEW(IDI_TERMINAL
),
2344 GetSystemMetrics(SM_CXICON
),
2345 GetSystemMetrics(SM_CYICON
),
2347 ghDefaultIconSm
= LoadImageW(ConSrvDllInstance
,
2348 MAKEINTRESOURCEW(IDI_TERMINAL
),
2350 GetSystemMetrics(SM_CXSMICON
),
2351 GetSystemMetrics(SM_CYSMICON
),
2353 ghDefaultCursor
= LoadCursorW(NULL
, IDC_ARROW
);
2354 wc
.cbSize
= sizeof(WNDCLASSEXW
);
2355 wc
.lpszClassName
= GUI_CONWND_CLASS
;
2356 wc
.lpfnWndProc
= GuiConsoleWndProc
;
2357 wc
.style
= CS_DBLCLKS
/* | CS_HREDRAW | CS_VREDRAW */;
2358 wc
.hInstance
= ConSrvDllInstance
;
2359 wc
.hIcon
= ghDefaultIcon
;
2360 wc
.hIconSm
= ghDefaultIconSm
;
2361 wc
.hCursor
= ghDefaultCursor
;
2362 wc
.hbrBackground
= (HBRUSH
)GetStockObject(BLACK_BRUSH
); // The color of a terminal when it is switch off.
2363 wc
.lpszMenuName
= NULL
;
2365 wc
.cbWndExtra
= GWLP_CONSOLEWND_ALLOC
;
2367 ConsoleClassAtom
= RegisterClassExW(&wc
);
2368 if (ConsoleClassAtom
== 0)
2370 DPRINT1("Failed to register GUI console wndproc\n");
2375 NtUserConsoleControl(GuiConsoleWndClassAtom
, &ConsoleClassAtom
, sizeof(ATOM
));
2378 ConsInitialized
= TRUE
;
2382 * Set-up the notification window
2384 if (NULL
== NotifyWnd
)
2386 HANDLE ThreadHandle
;
2387 HANDLE GraphicsStartupEvent
;
2389 GraphicsStartupEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
2390 if (NULL
== GraphicsStartupEvent
) return FALSE
;
2392 ThreadHandle
= CreateThread(NULL
,
2394 GuiConsoleGuiThread
,
2395 (PVOID
)&GraphicsStartupEvent
,
2398 if (NULL
== ThreadHandle
)
2400 CloseHandle(GraphicsStartupEvent
);
2401 DPRINT1("CONSRV: Failed to create graphics console thread. Expect problems\n");
2404 SetThreadPriority(ThreadHandle
, THREAD_PRIORITY_HIGHEST
);
2405 CloseHandle(ThreadHandle
);
2407 WaitForSingleObject(GraphicsStartupEvent
, INFINITE
);
2408 CloseHandle(GraphicsStartupEvent
);
2410 if (NULL
== NotifyWnd
)
2412 DPRINT1("CONSRV: Failed to create notification window.\n");
2417 // ConsInitialized = TRUE;
2424 /******************************************************************************
2425 * GUI Console Driver *
2426 ******************************************************************************/
2429 GuiDeinitFrontEnd(IN OUT PFRONTEND This
);
2432 GuiInitFrontEnd(IN OUT PFRONTEND This
,
2433 IN PCONSOLE Console
)
2435 PGUI_INIT_INFO GuiInitInfo
;
2436 PCONSOLE_INFO ConsoleInfo
;
2437 PCONSOLE_START_INFO ConsoleStartInfo
;
2439 PGUI_CONSOLE_DATA GuiData
;
2440 GUI_CONSOLE_INFO TermInfo
;
2443 LPWSTR IconPath
= NULL
;
2446 if (This
== NULL
|| Console
== NULL
|| This
->OldData
== NULL
)
2447 return STATUS_INVALID_PARAMETER
;
2449 ASSERT(This
->Console
== Console
);
2451 GuiInitInfo
= This
->OldData
;
2453 if (GuiInitInfo
->ConsoleInfo
== NULL
|| GuiInitInfo
->ConsoleStartInfo
== NULL
)
2454 return STATUS_INVALID_PARAMETER
;
2456 ConsoleInfo
= GuiInitInfo
->ConsoleInfo
;
2457 ConsoleStartInfo
= GuiInitInfo
->ConsoleStartInfo
;
2459 IconPath
= ConsoleStartInfo
->IconPath
;
2460 IconIndex
= ConsoleStartInfo
->IconIndex
;
2463 /* Terminal data allocation */
2464 GuiData
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_CONSOLE_DATA
));
2467 DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
2468 return STATUS_UNSUCCESSFUL
;
2470 /* HACK */ Console
->TermIFace
.Data
= (PVOID
)GuiData
; /* HACK */
2471 GuiData
->Console
= Console
;
2472 GuiData
->ActiveBuffer
= Console
->ActiveBuffer
;
2473 GuiData
->hWindow
= NULL
;
2475 /* The console can be resized */
2476 Console
->FixedSize
= FALSE
;
2478 InitializeCriticalSection(&GuiData
->Lock
);
2482 * Load terminal settings
2485 /* 1. Load the default settings */
2486 GuiConsoleGetDefaultSettings(&TermInfo
, GuiInitInfo
->ProcessId
);
2488 /* 3. Load the remaining console settings via the registry. */
2489 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
2491 /* Load the terminal infos from the registry. */
2492 GuiConsoleReadUserSettings(&TermInfo
,
2493 ConsoleInfo
->ConsoleTitle
,
2494 GuiInitInfo
->ProcessId
);
2497 * Now, update them with the properties the user might gave to us
2498 * via the STARTUPINFO structure before calling CreateProcess
2499 * (and which was transmitted via the ConsoleStartInfo structure).
2500 * We therefore overwrite the values read in the registry.
2502 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USESHOWWINDOW
)
2504 TermInfo
.ShowWindow
= ConsoleStartInfo
->wShowWindow
;
2506 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USEPOSITION
)
2508 TermInfo
.AutoPosition
= FALSE
;
2509 TermInfo
.WindowOrigin
.x
= ConsoleStartInfo
->dwWindowOrigin
.X
;
2510 TermInfo
.WindowOrigin
.y
= ConsoleStartInfo
->dwWindowOrigin
.Y
;
2512 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_RUNFULLSCREEN
)
2514 TermInfo
.FullScreen
= TRUE
;
2523 Length
= min(wcslen(TermInfo
.FaceName
) + 1, LF_FACESIZE
); // wcsnlen
2524 wcsncpy(GuiData
->GuiInfo
.FaceName
, TermInfo
.FaceName
, LF_FACESIZE
);
2525 GuiData
->GuiInfo
.FaceName
[Length
] = L
'\0';
2526 GuiData
->GuiInfo
.FontFamily
= TermInfo
.FontFamily
;
2527 GuiData
->GuiInfo
.FontSize
= TermInfo
.FontSize
;
2528 GuiData
->GuiInfo
.FontWeight
= TermInfo
.FontWeight
;
2529 GuiData
->GuiInfo
.UseRasterFonts
= TermInfo
.UseRasterFonts
;
2530 GuiData
->GuiInfo
.FullScreen
= TermInfo
.FullScreen
;
2531 GuiData
->GuiInfo
.ShowWindow
= TermInfo
.ShowWindow
;
2532 GuiData
->GuiInfo
.AutoPosition
= TermInfo
.AutoPosition
;
2533 GuiData
->GuiInfo
.WindowOrigin
= TermInfo
.WindowOrigin
;
2535 /* Initialize the icon handles to their default values */
2536 GuiData
->hIcon
= ghDefaultIcon
;
2537 GuiData
->hIconSm
= ghDefaultIconSm
;
2539 /* Get the associated icon, if any */
2540 if (IconPath
== NULL
|| IconPath
[0] == L
'\0')
2542 IconPath
= ConsoleStartInfo
->AppPath
;
2545 DPRINT("IconPath = %S ; IconIndex = %lu\n", (IconPath
? IconPath
: L
"n/a"), IconIndex
);
2546 if (IconPath
&& IconPath
[0] != L
'\0')
2548 HICON hIcon
= NULL
, hIconSm
= NULL
;
2549 PrivateExtractIconExW(IconPath
,
2554 DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon
, hIconSm
);
2557 DPRINT("Effectively set the icons\n");
2558 GuiData
->hIcon
= hIcon
;
2559 GuiData
->hIconSm
= hIconSm
;
2563 /* Mouse is shown by default with its default cursor shape */
2564 GuiData
->hCursor
= ghDefaultCursor
;
2565 GuiData
->MouseCursorRefCount
= 0;
2567 /* A priori don't ignore mouse signals */
2568 GuiData
->IgnoreNextMouseSignal
= FALSE
;
2570 /* Close button and the corresponding system menu item are enabled by default */
2571 GuiData
->IsCloseButtonEnabled
= TRUE
;
2573 /* There is no user-reserved menu id range by default */
2574 GuiData
->CmdIdLow
= GuiData
->CmdIdHigh
= 0;
2577 * We need to wait until the GUI has been fully initialized
2578 * to retrieve custom settings i.e. WindowSize etc...
2579 * Ideally we could use SendNotifyMessage for this but its not
2582 GuiData
->hGuiInitEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
2584 DPRINT("GUI - Checkpoint\n");
2586 /* Create the terminal window */
2587 PostMessageW(NotifyWnd
, PM_CREATE_CONSOLE
, GuiData
->GuiInfo
.ShowWindow
, (LPARAM
)GuiData
);
2589 /* Wait until initialization has finished */
2590 WaitForSingleObject(GuiData
->hGuiInitEvent
, INFINITE
);
2591 DPRINT("OK we created the console window\n");
2592 CloseHandle(GuiData
->hGuiInitEvent
);
2593 GuiData
->hGuiInitEvent
= NULL
;
2595 /* Check whether we really succeeded in initializing the terminal window */
2596 if (GuiData
->hWindow
== NULL
)
2598 DPRINT("GuiInitConsole - We failed at creating a new terminal window\n");
2599 GuiDeinitFrontEnd(This
);
2600 return STATUS_UNSUCCESSFUL
;
2603 /* Finally, finish to initialize the frontend structure */
2604 This
->Data
= GuiData
;
2605 if (This
->OldData
) ConsoleFreeHeap(This
->OldData
);
2606 This
->OldData
= NULL
;
2608 return STATUS_SUCCESS
;
2612 GuiDeinitFrontEnd(IN OUT PFRONTEND This
)
2614 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2616 SendMessageW(NotifyWnd
, PM_DESTROY_CONSOLE
, 0, (LPARAM
)GuiData
);
2618 DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
2619 GuiData
->hIcon
, ghDefaultIcon
, GuiData
->hIconSm
, ghDefaultIconSm
);
2620 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
2622 DPRINT("Destroy hIcon\n");
2623 DestroyIcon(GuiData
->hIcon
);
2625 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
2627 DPRINT("Destroy hIconSm\n");
2628 DestroyIcon(GuiData
->hIconSm
);
2632 DeleteCriticalSection(&GuiData
->Lock
);
2633 ConsoleFreeHeap(GuiData
);
2635 DPRINT("Quit GuiDeinitFrontEnd\n");
2639 GuiDrawRegion(IN OUT PFRONTEND This
,
2642 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2645 SmallRectToRect(GuiData
, &RegionRect
, Region
);
2646 /* Do not erase the background: it speeds up redrawing and reduce flickering */
2647 InvalidateRect(GuiData
->hWindow
, &RegionRect
, FALSE
);
2648 /**UpdateWindow(GuiData->hWindow);**/
2652 GuiWriteStream(IN OUT PFRONTEND This
,
2660 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2661 PCONSOLE_SCREEN_BUFFER Buff
;
2662 SHORT CursorEndX
, CursorEndY
;
2665 if (NULL
== GuiData
|| NULL
== GuiData
->hWindow
) return;
2667 Buff
= GuiData
->ActiveBuffer
;
2668 if (GetType(Buff
) != TEXTMODE_BUFFER
) return;
2670 if (0 != ScrolledLines
)
2672 ScrollRect
.left
= 0;
2674 ScrollRect
.right
= Buff
->ViewSize
.X
* GuiData
->CharWidth
;
2675 ScrollRect
.bottom
= Region
->Top
* GuiData
->CharHeight
;
2677 ScrollWindowEx(GuiData
->hWindow
,
2679 -(int)(ScrolledLines
* GuiData
->CharHeight
),
2687 GuiDrawRegion(This
, Region
);
2689 if (CursorStartX
< Region
->Left
|| Region
->Right
< CursorStartX
2690 || CursorStartY
< Region
->Top
|| Region
->Bottom
< CursorStartY
)
2692 GuiInvalidateCell(This
, CursorStartX
, CursorStartY
);
2695 CursorEndX
= Buff
->CursorPosition
.X
;
2696 CursorEndY
= Buff
->CursorPosition
.Y
;
2697 if ((CursorEndX
< Region
->Left
|| Region
->Right
< CursorEndX
2698 || CursorEndY
< Region
->Top
|| Region
->Bottom
< CursorEndY
)
2699 && (CursorEndX
!= CursorStartX
|| CursorEndY
!= CursorStartY
))
2701 GuiInvalidateCell(This
, CursorEndX
, CursorEndY
);
2704 // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
2705 // repaint the window without having it just freeze up and stay on the screen permanently.
2706 Buff
->CursorBlinkOn
= TRUE
;
2707 SetTimer(GuiData
->hWindow
, CONGUI_UPDATE_TIMER
, CONGUI_UPDATE_TIME
, NULL
);
2711 GuiSetCursorInfo(IN OUT PFRONTEND This
,
2712 PCONSOLE_SCREEN_BUFFER Buff
)
2714 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2716 if (GuiData
->ActiveBuffer
== Buff
)
2718 GuiInvalidateCell(This
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
2725 GuiSetScreenInfo(IN OUT PFRONTEND This
,
2726 PCONSOLE_SCREEN_BUFFER Buff
,
2730 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2732 if (GuiData
->ActiveBuffer
== Buff
)
2734 /* Redraw char at old position (remove cursor) */
2735 GuiInvalidateCell(This
, OldCursorX
, OldCursorY
);
2736 /* Redraw char at new position (show cursor) */
2737 GuiInvalidateCell(This
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
2744 GuiResizeTerminal(IN OUT PFRONTEND This
)
2746 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2748 /* Resize the window to the user's values */
2749 PostMessageW(GuiData
->hWindow
, PM_RESIZE_TERMINAL
, 0, 0);
2753 GuiSetActiveScreenBuffer(IN OUT PFRONTEND This
)
2755 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2756 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
2759 EnterCriticalSection(&GuiData
->Lock
);
2760 GuiData
->WindowSizeLock
= TRUE
;
2762 InterlockedExchangePointer(&GuiData
->ActiveBuffer
,
2763 ConDrvGetActiveScreenBuffer(GuiData
->Console
));
2765 GuiData
->WindowSizeLock
= FALSE
;
2766 LeaveCriticalSection(&GuiData
->Lock
);
2768 ActiveBuffer
= GuiData
->ActiveBuffer
;
2770 /* Change the current palette */
2771 if (ActiveBuffer
->PaletteHandle
== NULL
)
2773 hPalette
= GuiData
->hSysPalette
;
2777 hPalette
= ActiveBuffer
->PaletteHandle
;
2780 DPRINT1("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette
);
2782 /* Set the new palette for the framebuffer */
2783 SelectPalette(GuiData
->hMemDC
, hPalette
, FALSE
);
2785 /* Specify the use of the system palette for the framebuffer */
2786 SetSystemPaletteUse(GuiData
->hMemDC
, ActiveBuffer
->PaletteUsage
);
2788 /* Realize the (logical) palette */
2789 RealizePalette(GuiData
->hMemDC
);
2791 GuiResizeTerminal(This
);
2792 // ConioDrawConsole(Console);
2796 GuiReleaseScreenBuffer(IN OUT PFRONTEND This
,
2797 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer
)
2799 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2802 * If we were notified to release a screen buffer that is not actually
2803 * ours, then just ignore the notification...
2805 if (ScreenBuffer
!= GuiData
->ActiveBuffer
) return;
2808 * ... else, we must release our active buffer. Two cases are present:
2809 * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console
2810 * active screen buffer, then we can safely switch to it.
2811 * - If ScreenBuffer IS the console active screen buffer, we must release
2815 /* Release the old active palette and set the default one */
2816 if (GetCurrentObject(GuiData
->hMemDC
, OBJ_PAL
) == ScreenBuffer
->PaletteHandle
)
2818 /* Set the new palette */
2819 SelectPalette(GuiData
->hMemDC
, GuiData
->hSysPalette
, FALSE
);
2822 /* Set the adequate active screen buffer */
2823 if (ScreenBuffer
!= GuiData
->Console
->ActiveBuffer
)
2825 GuiSetActiveScreenBuffer(This
);
2829 EnterCriticalSection(&GuiData
->Lock
);
2830 GuiData
->WindowSizeLock
= TRUE
;
2832 InterlockedExchangePointer(&GuiData
->ActiveBuffer
, NULL
);
2834 GuiData
->WindowSizeLock
= FALSE
;
2835 LeaveCriticalSection(&GuiData
->Lock
);
2840 GuiProcessKeyCallback(IN OUT PFRONTEND This
,
2844 UINT VirtualKeyCode
,
2847 if ((ShiftState
& (RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
) || KeyStateMenu
& 0x80) &&
2848 (VirtualKeyCode
== VK_ESCAPE
|| VirtualKeyCode
== VK_TAB
|| VirtualKeyCode
== VK_SPACE
))
2850 DefWindowProcW(msg
->hwnd
, msg
->message
, msg
->wParam
, msg
->lParam
);
2858 GuiSetMouseCursor(IN OUT PFRONTEND This
,
2859 HCURSOR CursorHandle
);
2862 GuiRefreshInternalInfo(IN OUT PFRONTEND This
)
2864 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2866 /* Update the console leader information held by the window */
2867 SetConsoleWndConsoleLeaderCID(GuiData
);
2871 * We reset the cursor here so that, when a console app quits, we reset
2872 * the cursor to the default one. It's quite a hack since it doesn't proceed
2873 * per - console process... This must be fixed.
2875 * See GuiInitConsole(...) for more information.
2878 /* Mouse is shown by default with its default cursor shape */
2879 GuiData
->MouseCursorRefCount
= 0; // Reinitialize the reference counter
2880 GuiSetMouseCursor(This
, NULL
);
2884 GuiChangeTitle(IN OUT PFRONTEND This
)
2886 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2887 // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
2888 SetWindowText(GuiData
->hWindow
, GuiData
->Console
->Title
.Buffer
);
2892 GuiChangeIcon(IN OUT PFRONTEND This
,
2895 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2896 HICON hIcon
, hIconSm
;
2898 if (IconHandle
== NULL
)
2900 hIcon
= ghDefaultIcon
;
2901 hIconSm
= ghDefaultIconSm
;
2905 hIcon
= CopyIcon(IconHandle
);
2906 hIconSm
= CopyIcon(IconHandle
);
2914 if (hIcon
!= GuiData
->hIcon
)
2916 if (GuiData
->hIcon
!= NULL
&& GuiData
->hIcon
!= ghDefaultIcon
)
2918 DestroyIcon(GuiData
->hIcon
);
2920 if (GuiData
->hIconSm
!= NULL
&& GuiData
->hIconSm
!= ghDefaultIconSm
)
2922 DestroyIcon(GuiData
->hIconSm
);
2925 GuiData
->hIcon
= hIcon
;
2926 GuiData
->hIconSm
= hIconSm
;
2928 DPRINT("Set icons in GuiChangeIcon\n");
2929 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_BIG
, (LPARAM
)GuiData
->hIcon
);
2930 PostMessageW(GuiData
->hWindow
, WM_SETICON
, ICON_SMALL
, (LPARAM
)GuiData
->hIconSm
);
2937 GuiGetConsoleWindowHandle(IN OUT PFRONTEND This
)
2939 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2940 return GuiData
->hWindow
;
2944 GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This
,
2947 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2948 PCONSOLE_SCREEN_BUFFER ActiveBuffer
;
2951 UINT WidthUnit
, HeightUnit
;
2955 if (!SystemParametersInfoW(SPI_GETWORKAREA
, 0, &WorkArea
, 0))
2957 DPRINT1("SystemParametersInfoW failed - What to do ??\n");
2961 ActiveBuffer
= GuiData
->ActiveBuffer
;
2964 GetScreenBufferSizeUnits(ActiveBuffer
, GuiData
, &WidthUnit
, &HeightUnit
);
2968 /* Default: text mode */
2969 WidthUnit
= GuiData
->CharWidth
;
2970 HeightUnit
= GuiData
->CharHeight
;
2973 width
= WorkArea
.right
;
2974 height
= WorkArea
.bottom
;
2976 width
-= (2 * (GetSystemMetrics(SM_CXFRAME
) + GetSystemMetrics(SM_CXEDGE
)));
2977 height
-= (2 * (GetSystemMetrics(SM_CYFRAME
) + GetSystemMetrics(SM_CYEDGE
)) + GetSystemMetrics(SM_CYCAPTION
));
2979 if (width
< 0) width
= 0;
2980 if (height
< 0) height
= 0;
2982 pSize
->X
= (SHORT
)(width
/ (int)WidthUnit
) /* HACK */ + 2;
2983 pSize
->Y
= (SHORT
)(height
/ (int)HeightUnit
) /* HACK */ + 1;
2987 GuiSetPalette(IN OUT PFRONTEND This
,
2988 HPALETTE PaletteHandle
,
2991 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
2992 HPALETTE OldPalette
;
2994 // if (GetType(GuiData->ActiveBuffer) != GRAPHICS_BUFFER) return FALSE;
2995 if (PaletteHandle
== NULL
) return FALSE
;
2997 /* Set the new palette for the framebuffer */
2998 OldPalette
= SelectPalette(GuiData
->hMemDC
, PaletteHandle
, FALSE
);
2999 if (OldPalette
== NULL
) return FALSE
;
3001 /* Specify the use of the system palette for the framebuffer */
3002 SetSystemPaletteUse(GuiData
->hMemDC
, PaletteUsage
);
3004 /* Realize the (logical) palette */
3005 RealizePalette(GuiData
->hMemDC
);
3007 /* Save the original system palette handle */
3008 if (GuiData
->hSysPalette
== NULL
) GuiData
->hSysPalette
= OldPalette
;
3014 GuiGetDisplayMode(IN OUT PFRONTEND This
)
3016 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
3017 ULONG DisplayMode
= 0;
3019 if (GuiData
->GuiInfo
.FullScreen
)
3020 DisplayMode
|= CONSOLE_FULLSCREEN_HARDWARE
; // CONSOLE_FULLSCREEN
3022 DisplayMode
|= CONSOLE_WINDOWED
;
3028 GuiSetDisplayMode(IN OUT PFRONTEND This
,
3031 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
3034 if (NewMode
& ~(CONSOLE_FULLSCREEN_MODE
| CONSOLE_WINDOWED_MODE
))
3037 FullScreen
= ((NewMode
& CONSOLE_FULLSCREEN_MODE
) != 0);
3039 if (FullScreen
!= GuiData
->GuiInfo
.FullScreen
)
3041 SwitchFullScreen(GuiData
, FullScreen
);
3048 GuiShowMouseCursor(IN OUT PFRONTEND This
,
3051 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
3053 /* Set the reference count */
3054 if (Show
) ++GuiData
->MouseCursorRefCount
;
3055 else --GuiData
->MouseCursorRefCount
;
3057 /* Effectively show (or hide) the cursor (use special values for (w|l)Param) */
3058 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
3060 return GuiData
->MouseCursorRefCount
;
3064 GuiSetMouseCursor(IN OUT PFRONTEND This
,
3065 HCURSOR CursorHandle
)
3067 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
3070 * Set the cursor's handle. If the given handle is NULL,
3071 * then restore the default cursor.
3073 GuiData
->hCursor
= (CursorHandle
? CursorHandle
: ghDefaultCursor
);
3075 /* Effectively modify the shape of the cursor (use special values for (w|l)Param) */
3076 PostMessageW(GuiData
->hWindow
, WM_SETCURSOR
, -1, -1);
3082 GuiMenuControl(IN OUT PFRONTEND This
,
3086 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
3088 GuiData
->CmdIdLow
= CmdIdLow
;
3089 GuiData
->CmdIdHigh
= CmdIdHigh
;
3091 return GetSystemMenu(GuiData
->hWindow
, FALSE
);
3095 GuiSetMenuClose(IN OUT PFRONTEND This
,
3099 * NOTE: See http://www.mail-archive.com/harbour@harbour-project.org/msg27509.html
3100 * or http://harbour-devel.1590103.n2.nabble.com/Question-about-hb-gt-win-CtrlHandler-usage-td4670862i20.html
3101 * for more information.
3104 PGUI_CONSOLE_DATA GuiData
= This
->Data
;
3105 HMENU hSysMenu
= GetSystemMenu(GuiData
->hWindow
, FALSE
);
3107 if (hSysMenu
== NULL
) return FALSE
;
3109 GuiData
->IsCloseButtonEnabled
= Enable
;
3110 EnableMenuItem(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
| (Enable
? MF_ENABLED
: MF_GRAYED
));
3115 static FRONTEND_VTBL GuiVtbl
=
3124 GuiSetActiveScreenBuffer
,
3125 GuiReleaseScreenBuffer
,
3126 GuiProcessKeyCallback
,
3127 GuiRefreshInternalInfo
,
3130 GuiGetConsoleWindowHandle
,
3131 GuiGetLargestConsoleWindowSize
,
3143 LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo
,
3144 IN OUT PCONSOLE_INFO ConsoleInfo
)
3146 #define PATH_SEPARATOR L'\\'
3148 BOOL RetVal
= FALSE
;
3149 HRESULT hRes
= S_OK
;
3150 LPWSTR LinkName
= NULL
;
3153 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
3156 ConsoleStartInfo
->IconPath
[0] = L
'\0';
3157 ConsoleStartInfo
->IconIndex
= 0;
3159 /* 1- Find the last path separator if any */
3160 LinkName
= wcsrchr(ConsoleStartInfo
->ConsoleTitle
, PATH_SEPARATOR
);
3161 if (LinkName
== NULL
)
3163 LinkName
= ConsoleStartInfo
->ConsoleTitle
;
3167 /* Skip the path separator */
3171 /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
3172 Length
= wcslen(LinkName
);
3173 if ( (Length
<= 4) || (wcsicmp(LinkName
+ (Length
- 4), L
".lnk") != 0) )
3176 /* 3- It may be a link. Try to retrieve some properties */
3177 hRes
= CoInitialize(NULL
);
3178 if (SUCCEEDED(hRes
))
3180 /* Get a pointer to the IShellLink interface */
3181 IShellLinkW
* pshl
= NULL
;
3182 hRes
= CoCreateInstance(&CLSID_ShellLink
,
3184 CLSCTX_INPROC_SERVER
,
3187 if (SUCCEEDED(hRes
))
3189 /* Get a pointer to the IPersistFile interface */
3190 IPersistFile
* ppf
= NULL
;
3191 hRes
= IPersistFile_QueryInterface(pshl
, &IID_IPersistFile
, (LPVOID
*)&ppf
);
3192 if (SUCCEEDED(hRes
))
3194 /* Load the shortcut */
3195 hRes
= IPersistFile_Load(ppf
, ConsoleStartInfo
->ConsoleTitle
, STGM_READ
);
3196 if (SUCCEEDED(hRes
))
3199 * Finally we can get the properties !
3200 * Update the old ones if needed.
3205 /* Reset the name of the console with the name of the shortcut */
3206 Length
= min(/*Length*/ Length
- 4, // 4 == len(".lnk")
3207 sizeof(ConsoleInfo
->ConsoleTitle
) / sizeof(ConsoleInfo
->ConsoleTitle
[0]) - 1);
3208 wcsncpy(ConsoleInfo
->ConsoleTitle
, LinkName
, Length
);
3209 ConsoleInfo
->ConsoleTitle
[Length
] = L
'\0';
3211 /* Get the window showing command */
3212 hRes
= IShellLinkW_GetShowCmd(pshl
, &ShowCmd
);
3213 if (SUCCEEDED(hRes
)) ConsoleStartInfo
->wShowWindow
= (WORD
)ShowCmd
;
3215 /* Get the hotkey */
3216 // hRes = pshl->GetHotkey(&ShowCmd);
3217 // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey;
3219 /* Get the icon location, if any */
3221 hRes
= IShellLinkW_GetIconLocation(pshl
,
3222 ConsoleStartInfo
->IconPath
,
3223 sizeof(ConsoleStartInfo
->IconPath
)/sizeof(ConsoleStartInfo
->IconPath
[0]) - 1, // == MAX_PATH
3224 &ConsoleStartInfo
->IconIndex
);
3225 if (!SUCCEEDED(hRes
))
3227 ConsoleStartInfo
->IconPath
[0] = L
'\0';
3228 ConsoleStartInfo
->IconIndex
= 0;
3231 // FIXME: Since we still don't load console properties from the shortcut,
3232 // return false. When this will be done, we will return true instead.
3235 IPersistFile_Release(ppf
);
3237 IShellLinkW_Release(pshl
);
3246 GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd
,
3247 IN OUT PCONSOLE_INFO ConsoleInfo
,
3248 IN OUT PVOID ExtraConsoleInfo
,
3251 PCONSOLE_START_INFO ConsoleStartInfo
= ExtraConsoleInfo
;
3252 PGUI_INIT_INFO GuiInitInfo
;
3254 if (FrontEnd
== NULL
|| ConsoleInfo
== NULL
|| ConsoleStartInfo
== NULL
)
3255 return STATUS_INVALID_PARAMETER
;
3257 /* Initialize GUI terminal emulator common functionalities */
3258 if (!GuiInit()) return STATUS_UNSUCCESSFUL
;
3261 * Load per-application terminal settings.
3263 * Check whether the process creating the console was launched via
3264 * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the
3265 * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too.
3267 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
)
3269 if (!LoadShellLinkConsoleInfo(ConsoleStartInfo
, ConsoleInfo
))
3271 ConsoleStartInfo
->dwStartupFlags
&= ~STARTF_TITLEISLINKNAME
;
3276 * Initialize a private initialization info structure for later use.
3277 * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd.
3279 GuiInitInfo
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(GUI_INIT_INFO
));
3280 if (GuiInitInfo
== NULL
) return STATUS_NO_MEMORY
;
3282 // HACK: We suppose that the pointers will be valid in GuiInitFrontEnd...
3283 GuiInitInfo
->ConsoleInfo
= ConsoleInfo
;
3284 GuiInitInfo
->ConsoleStartInfo
= ConsoleStartInfo
;
3285 GuiInitInfo
->ProcessId
= ProcessId
;
3287 /* Finally, initialize the frontend structure */
3288 FrontEnd
->Vtbl
= &GuiVtbl
;
3289 FrontEnd
->Data
= NULL
;
3290 FrontEnd
->OldData
= GuiInitInfo
;
3292 return STATUS_SUCCESS
;
3296 GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd
)
3298 if (FrontEnd
== NULL
) return STATUS_INVALID_PARAMETER
;
3300 if (FrontEnd
->Data
) GuiDeinitFrontEnd(FrontEnd
);
3301 if (FrontEnd
->OldData
) ConsoleFreeHeap(FrontEnd
->OldData
);
3303 return STATUS_SUCCESS
;