[CONSRV]
[reactos.git] / reactos / win32ss / user / winsrv / consrv / frontends / gui / guiterm.c
1 /*
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
7 * Johannes Anderwald
8 * Jeffrey Morlan
9 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
10 */
11
12 /* INCLUDES *******************************************************************/
13
14 #define COBJMACROS
15
16 #include "consrv.h"
17 #include "include/conio.h"
18 #include "include/console.h"
19 #include "include/settings.h"
20 #include "conoutput.h"
21 #include "guiterm.h"
22 #include "guisettings.h"
23 #include "resource.h"
24
25 #include <windowsx.h>
26
27 #include <shlwapi.h>
28 #include <shlobj.h>
29
30 #define NDEBUG
31 #include <debug.h>
32
33 /* GUI Console Window Class name */
34 #define GUI_CONSOLE_WINDOW_CLASS L"ConsoleWindowClass"
35
36 #ifndef WM_APP
37 #define WM_APP 0x8000
38 #endif
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)
44
45
46 /* Not defined in any header file */
47 extern VOID NTAPI PrivateCsrssManualGuiCheck(LONG Check);
48 // See winsrv/usersrv/init.c line 234
49
50
51 /* GLOBALS ********************************************************************/
52
53 typedef struct _GUI_INIT_INFO
54 {
55 PCONSOLE_INFO ConsoleInfo;
56 PCONSOLE_START_INFO ConsoleStartInfo;
57 ULONG ProcessId;
58 } GUI_INIT_INFO, *PGUI_INIT_INFO;
59
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
65
66 #define SetConsoleWndConsoleLeaderCID(GuiData) \
67 do { \
68 PCONSOLE_PROCESS_DATA ProcessData; \
69 CLIENT_ID ConsoleLeaderCID; \
70 ProcessData = CONTAINING_RECORD((GuiData)->Console->ProcessList.Blink, \
71 CONSOLE_PROCESS_DATA, \
72 ConsoleLink); \
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 )); \
78 } while (0)
79 /**************************************************************/
80
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;
86
87 typedef struct _GUICONSOLE_MENUITEM
88 {
89 UINT uID;
90 const struct _GUICONSOLE_MENUITEM *SubMenu;
91 WORD wCmdID;
92 } GUICONSOLE_MENUITEM, *PGUICONSOLE_MENUITEM;
93
94 static const GUICONSOLE_MENUITEM GuiConsoleEditMenuItems[] =
95 {
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 },
102
103 { 0, NULL, 0 } /* End of list */
104 };
105
106 static const GUICONSOLE_MENUITEM GuiConsoleMainMenuItems[] =
107 {
108 { IDS_EDIT, GuiConsoleEditMenuItems, 0 },
109 { IDS_DEFAULTS, NULL, ID_SYSTEM_DEFAULTS },
110 { IDS_PROPERTIES, NULL, ID_SYSTEM_PROPERTIES },
111
112 { 0, NULL, 0 } /* End of list */
113 };
114
115 /*
116 * Default 16-color palette for foreground and background
117 * (corresponding flags in comments).
118 */
119 const COLORREF s_Colors[16] =
120 {
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
129
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
138 };
139
140 /* FUNCTIONS ******************************************************************/
141
142 static VOID
143 GetScreenBufferSizeUnits(IN PCONSOLE_SCREEN_BUFFER Buffer,
144 IN PGUI_CONSOLE_DATA GuiData,
145 OUT PUINT WidthUnit,
146 OUT PUINT HeightUnit)
147 {
148 if (Buffer == NULL || GuiData == NULL ||
149 WidthUnit == NULL || HeightUnit == NULL)
150 {
151 return;
152 }
153
154 if (GetType(Buffer) == TEXTMODE_BUFFER)
155 {
156 *WidthUnit = GuiData->CharWidth ;
157 *HeightUnit = GuiData->CharHeight;
158 }
159 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
160 {
161 *WidthUnit = 1;
162 *HeightUnit = 1;
163 }
164 }
165
166
167
168 static VOID
169 GuiConsoleAppendMenuItems(HMENU hMenu,
170 const GUICONSOLE_MENUITEM *Items)
171 {
172 UINT i = 0;
173 WCHAR szMenuString[255];
174 HMENU hSubMenu;
175
176 do
177 {
178 if (Items[i].uID != (UINT)-1)
179 {
180 if (LoadStringW(ConSrvDllInstance,
181 Items[i].uID,
182 szMenuString,
183 sizeof(szMenuString) / sizeof(szMenuString[0])) > 0)
184 {
185 if (Items[i].SubMenu != NULL)
186 {
187 hSubMenu = CreatePopupMenu();
188 if (hSubMenu != NULL)
189 {
190 GuiConsoleAppendMenuItems(hSubMenu,
191 Items[i].SubMenu);
192
193 if (!AppendMenuW(hMenu,
194 MF_STRING | MF_POPUP,
195 (UINT_PTR)hSubMenu,
196 szMenuString))
197 {
198 DestroyMenu(hSubMenu);
199 }
200 }
201 }
202 else
203 {
204 AppendMenuW(hMenu,
205 MF_STRING,
206 Items[i].wCmdID,
207 szMenuString);
208 }
209 }
210 }
211 else
212 {
213 AppendMenuW(hMenu,
214 MF_SEPARATOR,
215 0,
216 NULL);
217 }
218 i++;
219 } while (!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].wCmdID == 0));
220 }
221
222 static VOID
223 GuiConsoleCreateSysMenu(HWND hWnd)
224 {
225 HMENU hMenu = GetSystemMenu(hWnd, FALSE);
226 if (hMenu != NULL)
227 {
228 GuiConsoleAppendMenuItems(hMenu, GuiConsoleMainMenuItems);
229 DrawMenuBar(hWnd);
230 }
231 }
232
233 static VOID
234 GuiSendMenuEvent(PCONSOLE Console, UINT CmdId)
235 {
236 INPUT_RECORD er;
237
238 er.EventType = MENU_EVENT;
239 er.Event.MenuEvent.dwCommandId = CmdId;
240
241 ConioProcessInputEvent(Console, &er);
242 }
243
244 static VOID
245 GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData);
246 static VOID
247 GuiConsolePaste(PGUI_CONSOLE_DATA GuiData);
248 static VOID
249 GuiConsoleUpdateSelection(PCONSOLE Console, PCOORD coord);
250 static VOID NTAPI
251 GuiDrawRegion(IN OUT PFRONTEND This, SMALL_RECT* Region);
252 static VOID
253 GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData);
254
255
256 static LRESULT
257 GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
258 {
259 LRESULT Ret = TRUE;
260 PCONSOLE Console = GuiData->Console;
261 PCONSOLE_SCREEN_BUFFER ActiveBuffer;
262
263 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
264 {
265 Ret = FALSE;
266 goto Quit;
267 }
268 // ActiveBuffer = ConDrvGetActiveScreenBuffer(Console);
269 ActiveBuffer = GuiData->ActiveBuffer;
270
271 /*
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...
275 */
276 if (GuiData->cmdIdLow <= (UINT)wParam && (UINT)wParam <= GuiData->cmdIdHigh)
277 {
278 GuiSendMenuEvent(Console, (UINT)wParam);
279 goto Unlock_Quit;
280 }
281
282 /* ... otherwise, perform actions. */
283 switch (wParam)
284 {
285 case ID_SYSTEM_EDIT_MARK:
286 {
287 LPWSTR WindowTitle = NULL;
288 SIZE_T Length = 0;
289
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);
295
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);
302
303 break;
304 }
305
306 case ID_SYSTEM_EDIT_COPY:
307 GuiConsoleCopy(GuiData);
308 break;
309
310 case ID_SYSTEM_EDIT_PASTE:
311 GuiConsolePaste(GuiData);
312 break;
313
314 case ID_SYSTEM_EDIT_SELECTALL:
315 {
316 LPWSTR WindowTitle = NULL;
317 SIZE_T Length = 0;
318
319 /*
320 * The selection area extends to the whole screen buffer's width.
321 */
322 Console->Selection.dwSelectionAnchor.X = 0;
323 Console->Selection.dwSelectionAnchor.Y = 0;
324 Console->dwSelectionCursor.X = ActiveBuffer->ScreenBufferSize.X - 1;
325
326 /*
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).
330 */
331 if (GetType(ActiveBuffer) == TEXTMODE_BUFFER)
332 {
333 /*
334 * We select all the characters from the first line
335 * to the line where the cursor is positioned.
336 */
337 Console->dwSelectionCursor.Y = ActiveBuffer->CursorPosition.Y;
338 }
339 else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
340 {
341 /*
342 * We select all the screen buffer area.
343 */
344 Console->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1;
345 }
346
347 Console->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS | CONSOLE_MOUSE_SELECTION;
348 GuiConsoleUpdateSelection(Console, &Console->dwSelectionCursor);
349
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);
356
357 break;
358 }
359
360 case ID_SYSTEM_EDIT_SCROLL:
361 DPRINT1("Scrolling is not handled yet\n");
362 break;
363
364 case ID_SYSTEM_EDIT_FIND:
365 DPRINT1("Finding is not handled yet\n");
366 break;
367
368 case ID_SYSTEM_DEFAULTS:
369 GuiConsoleShowConsoleProperties(GuiData, TRUE);
370 break;
371
372 case ID_SYSTEM_PROPERTIES:
373 GuiConsoleShowConsoleProperties(GuiData, FALSE);
374 break;
375
376 default:
377 Ret = FALSE;
378 break;
379 }
380
381 Unlock_Quit:
382 LeaveCriticalSection(&Console->Lock);
383 Quit:
384 if (!Ret)
385 Ret = DefWindowProcW(GuiData->hWindow, WM_SYSCOMMAND, wParam, lParam);
386
387 return Ret;
388 }
389
390 static PGUI_CONSOLE_DATA
391 GuiGetGuiData(HWND hWnd)
392 {
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 );
396 }
397
398 VOID
399 GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData)
400 {
401 /* Move the window if needed (not positioned by the system) */
402 if (!GuiData->GuiInfo.AutoPosition)
403 {
404 SetWindowPos(GuiData->hWindow,
405 NULL,
406 GuiData->GuiInfo.WindowOrigin.x,
407 GuiData->GuiInfo.WindowOrigin.y,
408 0,
409 0,
410 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
411 }
412 }
413
414 static VOID
415 GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData)
416 {
417 // PCONSOLE Console = GuiData->Console;
418 PCONSOLE_SCREEN_BUFFER Buff = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(Console);
419 SCROLLINFO sInfo;
420
421 DWORD Width, Height;
422 UINT WidthUnit, HeightUnit;
423
424 GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit);
425
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);
430
431 /* Set scrollbar sizes */
432 sInfo.cbSize = sizeof(SCROLLINFO);
433 sInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
434 sInfo.nMin = 0;
435 if (Buff->ScreenBufferSize.Y > Buff->ViewSize.Y)
436 {
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);
443 }
444 else
445 {
446 ShowScrollBar(GuiData->hWindow, SB_VERT, FALSE);
447 }
448
449 if (Buff->ScreenBufferSize.X > Buff->ViewSize.X)
450 {
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);
457 }
458 else
459 {
460 ShowScrollBar(GuiData->hWindow, SB_HORZ, FALSE);
461 }
462
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);
468 }
469
470
471
472 static BOOL
473 EnterFullScreen(PGUI_CONSOLE_DATA GuiData)
474 {
475 DEVMODEW DevMode;
476
477 ZeroMemory(&DevMode, sizeof(DevMode));
478 DevMode.dmSize = sizeof(DevMode);
479
480 // DevMode.dmDisplayFixedOutput = DMDFO_CENTER; // DMDFO_STRETCH // DMDFO_DEFAULT
481 // DevMode.dmDisplayFlags = DMDISPLAYFLAGS_TEXTMODE;
482 DevMode.dmPelsWidth = 640; // GuiData->ActiveBuffer->ViewSize.X * GuiData->CharWidth;
483 DevMode.dmPelsHeight = 480; // GuiData->ActiveBuffer->ViewSize.Y * GuiData->CharHeight;
484 // DevMode.dmBitsPerPel = 32;
485 DevMode.dmFields = /* DM_DISPLAYFIXEDOUTPUT | DM_DISPLAYFLAGS | DM_BITSPERPEL | */ DM_PELSWIDTH | DM_PELSHEIGHT;
486
487 return (ChangeDisplaySettingsW(&DevMode, CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL);
488 }
489
490 static BOOL
491 LeaveFullScreen(PGUI_CONSOLE_DATA GuiData)
492 {
493 return (ChangeDisplaySettingsW(NULL, CDS_RESET) == DISP_CHANGE_SUCCESSFUL);
494 }
495
496 static VOID
497 GuiConsoleResize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam);
498
499 VOID
500 SwitchFullScreen(PGUI_CONSOLE_DATA GuiData, BOOL FullScreen)
501 {
502 PCONSOLE Console = GuiData->Console;
503
504 /*
505 * See:
506 * http://stackoverflow.com/questions/2382464/win32-full-screen-and-hiding-taskbar
507 * http://stackoverflow.com/questions/3549148/fullscreen-management-with-winapi
508 * http://blogs.msdn.com/b/oldnewthing/archive/2010/04/12/9994016.aspx
509 * http://blogs.msdn.com/b/oldnewthing/archive/2005/05/05/414910.aspx
510 * http://stackoverflow.com/questions/1400654/how-do-i-put-my-opengl-app-into-fullscreen-mode
511 * http://nehe.gamedev.net/tutorial/creating_an_opengl_window_win32/13001/
512 * http://www.reocities.com/pcgpe/dibs.html
513 */
514
515 if (FullScreen)
516 {
517 SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
518
519 /* Switch to full screen */
520 if (EnterFullScreen(GuiData))
521 {
522 /* Save the new state */
523 GuiData->GuiInfo.FullScreen = TRUE;
524 Console->FixedSize = TRUE;
525
526 GuiData->ActiveBuffer->OldViewSize = GuiData->ActiveBuffer->ViewSize;
527 // GuiData->ActiveBuffer->OldScreenBufferSize = GuiData->ActiveBuffer->ScreenBufferSize;
528
529 /* Save the old window styles */
530 GuiData->WndStyle = GetWindowLongPtr(GuiData->hWindow, GWL_STYLE );
531 GuiData->WndStyleEx = GetWindowLongPtr(GuiData->hWindow, GWL_EXSTYLE);
532
533 /* Change the window styles */
534 SetWindowLongPtr(GuiData->hWindow, GWL_STYLE,
535 WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
536 SetWindowLongPtr(GuiData->hWindow, GWL_EXSTYLE,
537 WS_EX_APPWINDOW);
538
539 /* Reposition the window to the upper-left corner */
540 SetWindowPos(GuiData->hWindow,
541 HWND_TOPMOST,
542 0, 0,
543 0, 0,
544 SWP_NOSIZE | SWP_FRAMECHANGED | SWP_SHOWWINDOW);
545 /* Make it the foreground window */
546 SetForegroundWindow(GuiData->hWindow);
547 /* Resize it */
548 // GuiConsoleResizeWindow(GuiData);
549 GuiConsoleResize(GuiData, SIZE_RESTORED, MAKELPARAM(640, 480));
550
551 PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
552 }
553 else
554 {
555 PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
556 }
557 }
558 else
559 {
560 SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
561
562 /* Restore windowing mode */
563 if (LeaveFullScreen(GuiData))
564 {
565 /* Save the new state */
566 GuiData->GuiInfo.FullScreen = FALSE;
567 Console->FixedSize = FALSE;
568
569 /*
570 * Restore possible saved dimensions
571 * of the active screen buffer view.
572 */
573 GuiData->ActiveBuffer->ViewSize = GuiData->ActiveBuffer->OldViewSize;
574 // GuiData->ActiveBuffer->ScreenBufferSize = GuiData->ActiveBuffer->OldScreenBufferSize;
575
576 /* Restore the window styles */
577 SetWindowLongPtr(GuiData->hWindow, GWL_STYLE,
578 GuiData->WndStyle);
579 SetWindowLongPtr(GuiData->hWindow, GWL_EXSTYLE,
580 GuiData->WndStyleEx);
581
582 /* Resize it */
583 GuiConsoleResizeWindow(GuiData);
584
585 // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
586 }
587 PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
588 }
589 }
590
591 static VOID
592 GuiConsoleSwitchFullScreen(PGUI_CONSOLE_DATA GuiData)
593 {
594 PCONSOLE Console = GuiData->Console;
595 BOOL FullScreen;
596
597 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
598
599 /* Switch to full-screen or to windowed mode */
600 FullScreen = !GuiData->GuiInfo.FullScreen;
601 DPRINT1("GuiConsoleSwitchFullScreen - Switch to %s ...\n",
602 (FullScreen ? "full-screen" : "windowed mode"));
603
604 SwitchFullScreen(GuiData, FullScreen);
605
606 LeaveCriticalSection(&Console->Lock);
607 }
608
609
610
611 static BOOL
612 GuiConsoleHandleNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
613 {
614 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)Create->lpCreateParams;
615 PCONSOLE Console;
616 HDC hDC;
617 HFONT OldFont;
618 TEXTMETRICW Metrics;
619 SIZE CharSize;
620
621 DPRINT("GuiConsoleHandleNcCreate\n");
622
623 if (NULL == GuiData)
624 {
625 DPRINT1("GuiConsoleNcCreate: No GUI data\n");
626 return FALSE;
627 }
628
629 Console = GuiData->Console;
630
631 GuiData->hWindow = hWnd;
632
633 GuiData->Font = CreateFontW(LOWORD(GuiData->GuiInfo.FontSize),
634 0, // HIWORD(GuiData->GuiInfo.FontSize),
635 0,
636 TA_BASELINE,
637 GuiData->GuiInfo.FontWeight,
638 FALSE,
639 FALSE,
640 FALSE,
641 OEM_CHARSET,
642 OUT_DEFAULT_PRECIS,
643 CLIP_DEFAULT_PRECIS,
644 NONANTIALIASED_QUALITY,
645 FIXED_PITCH | GuiData->GuiInfo.FontFamily /* FF_DONTCARE */,
646 GuiData->GuiInfo.FaceName);
647
648 if (NULL == GuiData->Font)
649 {
650 DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
651 GuiData->hWindow = NULL;
652 SetEvent(GuiData->hGuiInitEvent);
653 return FALSE;
654 }
655 hDC = GetDC(GuiData->hWindow);
656 if (NULL == hDC)
657 {
658 DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
659 DeleteObject(GuiData->Font);
660 GuiData->hWindow = NULL;
661 SetEvent(GuiData->hGuiInitEvent);
662 return FALSE;
663 }
664 OldFont = SelectObject(hDC, GuiData->Font);
665 if (NULL == OldFont)
666 {
667 DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
668 ReleaseDC(GuiData->hWindow, hDC);
669 DeleteObject(GuiData->Font);
670 GuiData->hWindow = NULL;
671 SetEvent(GuiData->hGuiInitEvent);
672 return FALSE;
673 }
674 if (!GetTextMetricsW(hDC, &Metrics))
675 {
676 DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
677 SelectObject(hDC, OldFont);
678 ReleaseDC(GuiData->hWindow, hDC);
679 DeleteObject(GuiData->Font);
680 GuiData->hWindow = NULL;
681 SetEvent(GuiData->hGuiInitEvent);
682 return FALSE;
683 }
684 GuiData->CharWidth = Metrics.tmMaxCharWidth;
685 GuiData->CharHeight = Metrics.tmHeight + Metrics.tmExternalLeading;
686
687 /* Measure real char width more precisely if possible. */
688 if (GetTextExtentPoint32W(hDC, L"R", 1, &CharSize))
689 GuiData->CharWidth = CharSize.cx;
690
691 SelectObject(hDC, OldFont);
692
693 ReleaseDC(GuiData->hWindow, hDC);
694
695 // FIXME: Keep these instructions here ? ///////////////////////////////////
696 Console->ActiveBuffer->CursorBlinkOn = TRUE;
697 Console->ActiveBuffer->ForceCursorOff = FALSE;
698 ////////////////////////////////////////////////////////////////////////////
699
700 SetWindowLongPtrW(GuiData->hWindow, GWLP_USERDATA, (DWORD_PTR)GuiData);
701
702 SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
703 GuiConsoleCreateSysMenu(GuiData->hWindow);
704
705 DPRINT("GuiConsoleHandleNcCreate - setting start event\n");
706 SetEvent(GuiData->hGuiInitEvent);
707
708 return (BOOL)DefWindowProcW(GuiData->hWindow, WM_NCCREATE, 0, (LPARAM)Create);
709 }
710
711 static VOID
712 SmallRectToRect(PGUI_CONSOLE_DATA GuiData, PRECT Rect, PSMALL_RECT SmallRect)
713 {
714 // PCONSOLE Console = GuiData->Console;
715 PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(Console);
716 UINT WidthUnit, HeightUnit;
717
718 GetScreenBufferSizeUnits(Buffer, GuiData, &WidthUnit, &HeightUnit);
719
720 Rect->left = (SmallRect->Left - Buffer->ViewOrigin.X) * WidthUnit ;
721 Rect->top = (SmallRect->Top - Buffer->ViewOrigin.Y) * HeightUnit;
722 Rect->right = (SmallRect->Right + 1 - Buffer->ViewOrigin.X) * WidthUnit ;
723 Rect->bottom = (SmallRect->Bottom + 1 - Buffer->ViewOrigin.Y) * HeightUnit;
724 }
725
726 static VOID
727 GuiConsoleUpdateSelection(PCONSOLE Console, PCOORD coord)
728 {
729 PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data;
730 RECT oldRect, newRect;
731
732 SmallRectToRect(GuiData, &oldRect, &Console->Selection.srSelection);
733
734 if (coord != NULL)
735 {
736 SMALL_RECT rc;
737 /* exchange left/top with right/bottom if required */
738 rc.Left = min(Console->Selection.dwSelectionAnchor.X, coord->X);
739 rc.Top = min(Console->Selection.dwSelectionAnchor.Y, coord->Y);
740 rc.Right = max(Console->Selection.dwSelectionAnchor.X, coord->X);
741 rc.Bottom = max(Console->Selection.dwSelectionAnchor.Y, coord->Y);
742
743 SmallRectToRect(GuiData, &newRect, &rc);
744
745 if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
746 {
747 if (memcmp(&rc, &Console->Selection.srSelection, sizeof(SMALL_RECT)) != 0)
748 {
749 HRGN rgn1, rgn2;
750
751 /* calculate the region that needs to be updated */
752 if ((rgn1 = CreateRectRgnIndirect(&oldRect)))
753 {
754 if ((rgn2 = CreateRectRgnIndirect(&newRect)))
755 {
756 if (CombineRgn(rgn1, rgn2, rgn1, RGN_XOR) != ERROR)
757 {
758 InvalidateRgn(GuiData->hWindow, rgn1, FALSE);
759 }
760 DeleteObject(rgn2);
761 }
762 DeleteObject(rgn1);
763 }
764 }
765 }
766 else
767 {
768 InvalidateRect(GuiData->hWindow, &newRect, FALSE);
769 }
770 Console->Selection.dwFlags |= CONSOLE_SELECTION_NOT_EMPTY;
771 Console->Selection.srSelection = rc;
772 Console->dwSelectionCursor = *coord;
773 ConioPause(Console, PAUSED_FROM_SELECTION);
774 }
775 else
776 {
777 /* clear the selection */
778 if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
779 {
780 InvalidateRect(GuiData->hWindow, &oldRect, FALSE);
781 }
782 Console->Selection.dwFlags = CONSOLE_NO_SELECTION;
783 ConioUnpause(Console, PAUSED_FROM_SELECTION);
784 }
785 }
786
787
788 VOID
789 GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
790 PGUI_CONSOLE_DATA GuiData,
791 HDC hDC,
792 PRECT rc);
793 VOID
794 GuiPaintGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer,
795 PGUI_CONSOLE_DATA GuiData,
796 HDC hDC,
797 PRECT rc);
798
799 static VOID
800 GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData)
801 {
802 BOOL Success = TRUE;
803 PCONSOLE Console = GuiData->Console;
804 PCONSOLE_SCREEN_BUFFER ActiveBuffer;
805 HDC hDC;
806 PAINTSTRUCT ps;
807
808 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
809 {
810 Success = FALSE;
811 goto Quit;
812 }
813 // ActiveBuffer = ConDrvGetActiveScreenBuffer(Console);
814 ActiveBuffer = GuiData->ActiveBuffer;
815
816 hDC = BeginPaint(GuiData->hWindow, &ps);
817 if (hDC != NULL &&
818 ps.rcPaint.left < ps.rcPaint.right &&
819 ps.rcPaint.top < ps.rcPaint.bottom)
820 {
821 EnterCriticalSection(&GuiData->Lock);
822
823 if (GetType(ActiveBuffer) == TEXTMODE_BUFFER)
824 {
825 GuiPaintTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)ActiveBuffer,
826 GuiData, hDC, &ps.rcPaint);
827 }
828 else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
829 {
830 GuiPaintGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)ActiveBuffer,
831 GuiData, hDC, &ps.rcPaint);
832 }
833
834 if (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
835 {
836 RECT rc;
837 SmallRectToRect(GuiData, &rc, &Console->Selection.srSelection);
838
839 /* invert the selection */
840 if (IntersectRect(&rc, &ps.rcPaint, &rc))
841 {
842 PatBlt(hDC,
843 rc.left,
844 rc.top,
845 rc.right - rc.left,
846 rc.bottom - rc.top,
847 DSTINVERT);
848 }
849 }
850
851 LeaveCriticalSection(&GuiData->Lock);
852 }
853 EndPaint(GuiData->hWindow, &ps);
854
855 Quit:
856 if (Success)
857 LeaveCriticalSection(&Console->Lock);
858 else
859 DefWindowProcW(GuiData->hWindow, WM_PAINT, 0, 0);
860
861 return;
862 }
863
864 static BOOL
865 IsSystemKey(WORD VirtualKeyCode)
866 {
867 switch (VirtualKeyCode)
868 {
869 /* From MSDN, "Virtual-Key Codes" */
870 case VK_RETURN:
871 case VK_SHIFT:
872 case VK_CONTROL:
873 case VK_MENU:
874 case VK_PAUSE:
875 case VK_CAPITAL:
876 case VK_ESCAPE:
877 case VK_LWIN:
878 case VK_RWIN:
879 case VK_NUMLOCK:
880 case VK_SCROLL:
881 return TRUE;
882 default:
883 return FALSE;
884 }
885 }
886
887 static VOID
888 GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
889 {
890 PCONSOLE Console = GuiData->Console;
891 PCONSOLE_SCREEN_BUFFER ActiveBuffer;
892
893 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
894
895 // ActiveBuffer = ConDrvGetActiveScreenBuffer(Console);
896 ActiveBuffer = GuiData->ActiveBuffer;
897
898 if (Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS)
899 {
900 WORD VirtualKeyCode = LOWORD(wParam);
901
902 if (msg != WM_KEYDOWN) goto Quit;
903
904 if (VirtualKeyCode == VK_RETURN)
905 {
906 /* Copy (and clear) selection if ENTER is pressed */
907 GuiConsoleCopy(GuiData);
908 goto Quit;
909 }
910 else if ( VirtualKeyCode == VK_ESCAPE ||
911 (VirtualKeyCode == 'C' && GetKeyState(VK_CONTROL) & 0x8000) )
912 {
913 /* Cancel selection if ESC or Ctrl-C are pressed */
914 GuiConsoleUpdateSelection(Console, NULL);
915 SetWindowText(GuiData->hWindow, Console->Title.Buffer);
916
917 goto Quit;
918 }
919
920 if ((Console->Selection.dwFlags & CONSOLE_MOUSE_SELECTION) == 0)
921 {
922 /* Keyboard selection mode */
923 BOOL Interpreted = FALSE;
924 BOOL MajPressed = (GetKeyState(VK_SHIFT) & 0x8000);
925
926 switch (VirtualKeyCode)
927 {
928 case VK_LEFT:
929 {
930 Interpreted = TRUE;
931 if (Console->dwSelectionCursor.X > 0)
932 Console->dwSelectionCursor.X--;
933
934 break;
935 }
936
937 case VK_RIGHT:
938 {
939 Interpreted = TRUE;
940 if (Console->dwSelectionCursor.X < ActiveBuffer->ScreenBufferSize.X - 1)
941 Console->dwSelectionCursor.X++;
942
943 break;
944 }
945
946 case VK_UP:
947 {
948 Interpreted = TRUE;
949 if (Console->dwSelectionCursor.Y > 0)
950 Console->dwSelectionCursor.Y--;
951
952 break;
953 }
954
955 case VK_DOWN:
956 {
957 Interpreted = TRUE;
958 if (Console->dwSelectionCursor.Y < ActiveBuffer->ScreenBufferSize.Y - 1)
959 Console->dwSelectionCursor.Y++;
960
961 break;
962 }
963
964 case VK_HOME:
965 {
966 Interpreted = TRUE;
967 Console->dwSelectionCursor.X = 0;
968 Console->dwSelectionCursor.Y = 0;
969 break;
970 }
971
972 case VK_END:
973 {
974 Interpreted = TRUE;
975 Console->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1;
976 break;
977 }
978
979 case VK_PRIOR:
980 {
981 Interpreted = TRUE;
982 Console->dwSelectionCursor.Y -= ActiveBuffer->ViewSize.Y;
983 if (Console->dwSelectionCursor.Y < 0)
984 Console->dwSelectionCursor.Y = 0;
985
986 break;
987 }
988
989 case VK_NEXT:
990 {
991 Interpreted = TRUE;
992 Console->dwSelectionCursor.Y += ActiveBuffer->ViewSize.Y;
993 if (Console->dwSelectionCursor.Y >= ActiveBuffer->ScreenBufferSize.Y)
994 Console->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1;
995
996 break;
997 }
998
999 default:
1000 break;
1001 }
1002
1003 if (Interpreted)
1004 {
1005 if (!MajPressed)
1006 Console->Selection.dwSelectionAnchor = Console->dwSelectionCursor;
1007
1008 GuiConsoleUpdateSelection(Console, &Console->dwSelectionCursor);
1009 }
1010 else if (!IsSystemKey(VirtualKeyCode))
1011 {
1012 /* Emit an error beep sound */
1013 SendNotifyMessage(GuiData->hWindow, PM_CONSOLE_BEEP, 0, 0);
1014 }
1015
1016 goto Quit;
1017 }
1018 else
1019 {
1020 /* Mouse selection mode */
1021
1022 if (!IsSystemKey(VirtualKeyCode))
1023 {
1024 /* Clear the selection and send the key into the input buffer */
1025 GuiConsoleUpdateSelection(Console, NULL);
1026 SetWindowText(GuiData->hWindow, Console->Title.Buffer);
1027 }
1028 else
1029 {
1030 goto Quit;
1031 }
1032 }
1033 }
1034
1035 if ((Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) == 0)
1036 {
1037 MSG Message;
1038
1039 Message.hwnd = GuiData->hWindow;
1040 Message.message = msg;
1041 Message.wParam = wParam;
1042 Message.lParam = lParam;
1043
1044 ConioProcessKey(Console, &Message);
1045 }
1046
1047 Quit:
1048 LeaveCriticalSection(&Console->Lock);
1049 }
1050
1051 static VOID
1052 GuiInvalidateCell(IN OUT PFRONTEND This, SHORT x, SHORT y)
1053 {
1054 SMALL_RECT CellRect = { x, y, x, y };
1055 GuiDrawRegion(This, &CellRect);
1056 }
1057
1058 static VOID
1059 GuiConsoleHandleTimer(PGUI_CONSOLE_DATA GuiData)
1060 {
1061 PCONSOLE Console = GuiData->Console;
1062 PCONSOLE_SCREEN_BUFFER Buff;
1063
1064 SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CURSOR_BLINK_TIME, NULL);
1065
1066 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
1067
1068 Buff = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(Console);
1069
1070 if (GetType(Buff) == TEXTMODE_BUFFER)
1071 {
1072 GuiInvalidateCell(&Console->TermIFace, Buff->CursorPosition.X, Buff->CursorPosition.Y);
1073 Buff->CursorBlinkOn = !Buff->CursorBlinkOn;
1074
1075 if ((GuiData->OldCursor.x != Buff->CursorPosition.X) || (GuiData->OldCursor.y != Buff->CursorPosition.Y))
1076 {
1077 SCROLLINFO xScroll;
1078 int OldScrollX = -1, OldScrollY = -1;
1079 int NewScrollX = -1, NewScrollY = -1;
1080
1081 xScroll.cbSize = sizeof(SCROLLINFO);
1082 xScroll.fMask = SIF_POS;
1083 // Capture the original position of the scroll bars and save them.
1084 if (GetScrollInfo(GuiData->hWindow, SB_HORZ, &xScroll)) OldScrollX = xScroll.nPos;
1085 if (GetScrollInfo(GuiData->hWindow, SB_VERT, &xScroll)) OldScrollY = xScroll.nPos;
1086
1087 // If we successfully got the info for the horizontal scrollbar
1088 if (OldScrollX >= 0)
1089 {
1090 if ((Buff->CursorPosition.X < Buff->ViewOrigin.X) || (Buff->CursorPosition.X >= (Buff->ViewOrigin.X + Buff->ViewSize.X)))
1091 {
1092 // Handle the horizontal scroll bar
1093 if (Buff->CursorPosition.X >= Buff->ViewSize.X) NewScrollX = Buff->CursorPosition.X - Buff->ViewSize.X + 1;
1094 else NewScrollX = 0;
1095 }
1096 else
1097 {
1098 NewScrollX = OldScrollX;
1099 }
1100 }
1101 // If we successfully got the info for the vertical scrollbar
1102 if (OldScrollY >= 0)
1103 {
1104 if ((Buff->CursorPosition.Y < Buff->ViewOrigin.Y) || (Buff->CursorPosition.Y >= (Buff->ViewOrigin.Y + Buff->ViewSize.Y)))
1105 {
1106 // Handle the vertical scroll bar
1107 if (Buff->CursorPosition.Y >= Buff->ViewSize.Y) NewScrollY = Buff->CursorPosition.Y - Buff->ViewSize.Y + 1;
1108 else NewScrollY = 0;
1109 }
1110 else
1111 {
1112 NewScrollY = OldScrollY;
1113 }
1114 }
1115
1116 // Adjust scroll bars and refresh the window if the cursor has moved outside the visible area
1117 // NOTE: OldScroll# and NewScroll# will both be -1 (initial value) if the info for the respective scrollbar
1118 // was not obtained successfully in the previous steps. This means their difference is 0 (no scrolling)
1119 // and their associated scrollbar is left alone.
1120 if ((OldScrollX != NewScrollX) || (OldScrollY != NewScrollY))
1121 {
1122 Buff->ViewOrigin.X = NewScrollX;
1123 Buff->ViewOrigin.Y = NewScrollY;
1124 ScrollWindowEx(GuiData->hWindow,
1125 (OldScrollX - NewScrollX) * GuiData->CharWidth,
1126 (OldScrollY - NewScrollY) * GuiData->CharHeight,
1127 NULL,
1128 NULL,
1129 NULL,
1130 NULL,
1131 SW_INVALIDATE);
1132 if (NewScrollX >= 0)
1133 {
1134 xScroll.nPos = NewScrollX;
1135 SetScrollInfo(GuiData->hWindow, SB_HORZ, &xScroll, TRUE);
1136 }
1137 if (NewScrollY >= 0)
1138 {
1139 xScroll.nPos = NewScrollY;
1140 SetScrollInfo(GuiData->hWindow, SB_VERT, &xScroll, TRUE);
1141 }
1142 UpdateWindow(GuiData->hWindow);
1143 GuiData->OldCursor.x = Buff->CursorPosition.X;
1144 GuiData->OldCursor.y = Buff->CursorPosition.Y;
1145 }
1146 }
1147 }
1148 else /* if (GetType(Buff) == GRAPHICS_BUFFER) */
1149 {
1150 }
1151
1152 LeaveCriticalSection(&Console->Lock);
1153 }
1154
1155 static BOOL
1156 GuiConsoleHandleClose(PGUI_CONSOLE_DATA GuiData)
1157 {
1158 PCONSOLE Console = GuiData->Console;
1159
1160 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
1161 return TRUE;
1162
1163 // TODO: Prompt for termination ? (Warn the user about possible apps running in this console)
1164
1165 /*
1166 * FIXME: Windows will wait up to 5 seconds for the thread to exit.
1167 * We shouldn't wait here, though, since the console lock is entered.
1168 * A copy of the thread list probably needs to be made.
1169 */
1170 ConDrvConsoleProcessCtrlEvent(Console, 0, CTRL_CLOSE_EVENT);
1171
1172 LeaveCriticalSection(&Console->Lock);
1173 return FALSE;
1174 }
1175
1176 static LRESULT
1177 GuiConsoleHandleNcDestroy(HWND hWnd)
1178 {
1179 KillTimer(hWnd, CONGUI_UPDATE_TIMER);
1180 GetSystemMenu(hWnd, TRUE);
1181
1182 /* Free the GuiData registration */
1183 SetWindowLongPtrW(hWnd, GWLP_USERDATA, (DWORD_PTR)NULL);
1184
1185 return DefWindowProcW(hWnd, WM_NCDESTROY, 0, 0);
1186 }
1187
1188 static COORD
1189 PointToCoord(PGUI_CONSOLE_DATA GuiData, LPARAM lParam)
1190 {
1191 // PCONSOLE Console = GuiData->Console;
1192 PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(Console);
1193 COORD Coord;
1194 UINT WidthUnit, HeightUnit;
1195
1196 GetScreenBufferSizeUnits(Buffer, GuiData, &WidthUnit, &HeightUnit);
1197
1198 Coord.X = Buffer->ViewOrigin.X + ((SHORT)LOWORD(lParam) / (int)WidthUnit );
1199 Coord.Y = Buffer->ViewOrigin.Y + ((SHORT)HIWORD(lParam) / (int)HeightUnit);
1200
1201 /* Clip coordinate to ensure it's inside buffer */
1202 if (Coord.X < 0)
1203 Coord.X = 0;
1204 else if (Coord.X >= Buffer->ScreenBufferSize.X)
1205 Coord.X = Buffer->ScreenBufferSize.X - 1;
1206
1207 if (Coord.Y < 0)
1208 Coord.Y = 0;
1209 else if (Coord.Y >= Buffer->ScreenBufferSize.Y)
1210 Coord.Y = Buffer->ScreenBufferSize.Y - 1;
1211
1212 return Coord;
1213 }
1214
1215 static LRESULT
1216 GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
1217 {
1218 BOOL Err = FALSE;
1219 PCONSOLE Console = GuiData->Console;
1220
1221 if (GuiData->IgnoreNextMouseSignal)
1222 {
1223 if (msg != WM_LBUTTONDOWN &&
1224 msg != WM_MBUTTONDOWN &&
1225 msg != WM_RBUTTONDOWN)
1226 {
1227 /*
1228 * If this mouse signal is not a button-down action,
1229 * then it is the last signal being ignored.
1230 */
1231 GuiData->IgnoreNextMouseSignal = FALSE;
1232 }
1233 else
1234 {
1235 /*
1236 * This mouse signal is a button-down action.
1237 * Ignore it and perform default action.
1238 */
1239 Err = TRUE;
1240 }
1241 goto Quit;
1242 }
1243
1244 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
1245 {
1246 Err = TRUE;
1247 goto Quit;
1248 }
1249
1250 if ( (Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) ||
1251 (Console->QuickEdit) )
1252 {
1253 switch (msg)
1254 {
1255 case WM_LBUTTONDOWN:
1256 {
1257 LPWSTR WindowTitle = NULL;
1258 SIZE_T Length = 0;
1259
1260 Console->Selection.dwSelectionAnchor = PointToCoord(GuiData, lParam);
1261 SetCapture(GuiData->hWindow);
1262 Console->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS | CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
1263 GuiConsoleUpdateSelection(Console, &Console->Selection.dwSelectionAnchor);
1264
1265 Length = Console->Title.Length + sizeof(L"Selection - ")/sizeof(WCHAR) + 1;
1266 WindowTitle = ConsoleAllocHeap(0, Length * sizeof(WCHAR));
1267 wcscpy(WindowTitle, L"Selection - ");
1268 wcscat(WindowTitle, Console->Title.Buffer);
1269 SetWindowText(GuiData->hWindow, WindowTitle);
1270 ConsoleFreeHeap(WindowTitle);
1271
1272 break;
1273 }
1274
1275 case WM_LBUTTONUP:
1276 {
1277 COORD c;
1278
1279 if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
1280
1281 c = PointToCoord(GuiData, lParam);
1282 Console->Selection.dwFlags &= ~CONSOLE_MOUSE_DOWN;
1283 GuiConsoleUpdateSelection(Console, &c);
1284 ReleaseCapture();
1285
1286 break;
1287 }
1288
1289 case WM_LBUTTONDBLCLK:
1290 {
1291 DPRINT1("Handle left-double-click for selecting a word\n");
1292 break;
1293 }
1294
1295 case WM_RBUTTONDOWN:
1296 case WM_RBUTTONDBLCLK:
1297 {
1298 if (!(Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY))
1299 {
1300 GuiConsolePaste(GuiData);
1301 }
1302 else
1303 {
1304 GuiConsoleCopy(GuiData);
1305 }
1306
1307 GuiData->IgnoreNextMouseSignal = TRUE;
1308 break;
1309 }
1310
1311 case WM_MOUSEMOVE:
1312 {
1313 COORD c;
1314
1315 if (!(wParam & MK_LBUTTON)) break;
1316 if (!(Console->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
1317
1318 c = PointToCoord(GuiData, lParam); /* TODO: Scroll buffer to bring c into view */
1319 GuiConsoleUpdateSelection(Console, &c);
1320
1321 break;
1322 }
1323
1324 default:
1325 Err = FALSE; // TRUE;
1326 break;
1327 }
1328 }
1329 else if (Console->InputBuffer.Mode & ENABLE_MOUSE_INPUT)
1330 {
1331 INPUT_RECORD er;
1332 WORD wKeyState = GET_KEYSTATE_WPARAM(wParam);
1333 DWORD dwButtonState = 0;
1334 DWORD dwControlKeyState = 0;
1335 DWORD dwEventFlags = 0;
1336
1337 switch (msg)
1338 {
1339 case WM_LBUTTONDOWN:
1340 SetCapture(GuiData->hWindow);
1341 dwButtonState = FROM_LEFT_1ST_BUTTON_PRESSED;
1342 dwEventFlags = 0;
1343 break;
1344
1345 case WM_MBUTTONDOWN:
1346 SetCapture(GuiData->hWindow);
1347 dwButtonState = FROM_LEFT_2ND_BUTTON_PRESSED;
1348 dwEventFlags = 0;
1349 break;
1350
1351 case WM_RBUTTONDOWN:
1352 SetCapture(GuiData->hWindow);
1353 dwButtonState = RIGHTMOST_BUTTON_PRESSED;
1354 dwEventFlags = 0;
1355 break;
1356
1357 case WM_LBUTTONUP:
1358 ReleaseCapture();
1359 dwButtonState = 0;
1360 dwEventFlags = 0;
1361 break;
1362
1363 case WM_MBUTTONUP:
1364 ReleaseCapture();
1365 dwButtonState = 0;
1366 dwEventFlags = 0;
1367 break;
1368
1369 case WM_RBUTTONUP:
1370 ReleaseCapture();
1371 dwButtonState = 0;
1372 dwEventFlags = 0;
1373 break;
1374
1375 case WM_LBUTTONDBLCLK:
1376 dwButtonState = FROM_LEFT_1ST_BUTTON_PRESSED;
1377 dwEventFlags = DOUBLE_CLICK;
1378 break;
1379
1380 case WM_MBUTTONDBLCLK:
1381 dwButtonState = FROM_LEFT_2ND_BUTTON_PRESSED;
1382 dwEventFlags = DOUBLE_CLICK;
1383 break;
1384
1385 case WM_RBUTTONDBLCLK:
1386 dwButtonState = RIGHTMOST_BUTTON_PRESSED;
1387 dwEventFlags = DOUBLE_CLICK;
1388 break;
1389
1390 case WM_MOUSEMOVE:
1391 dwButtonState = 0;
1392 dwEventFlags = MOUSE_MOVED;
1393 break;
1394
1395 case WM_MOUSEWHEEL:
1396 dwButtonState = GET_WHEEL_DELTA_WPARAM(wParam) << 16;
1397 dwEventFlags = MOUSE_WHEELED;
1398 break;
1399
1400 case WM_MOUSEHWHEEL:
1401 dwButtonState = GET_WHEEL_DELTA_WPARAM(wParam) << 16;
1402 dwEventFlags = MOUSE_HWHEELED;
1403 break;
1404
1405 default:
1406 Err = TRUE;
1407 break;
1408 }
1409
1410 if (!Err)
1411 {
1412 if (wKeyState & MK_LBUTTON)
1413 dwButtonState |= FROM_LEFT_1ST_BUTTON_PRESSED;
1414 if (wKeyState & MK_MBUTTON)
1415 dwButtonState |= FROM_LEFT_2ND_BUTTON_PRESSED;
1416 if (wKeyState & MK_RBUTTON)
1417 dwButtonState |= RIGHTMOST_BUTTON_PRESSED;
1418
1419 if (GetKeyState(VK_RMENU) & 0x8000)
1420 dwControlKeyState |= RIGHT_ALT_PRESSED;
1421 if (GetKeyState(VK_LMENU) & 0x8000)
1422 dwControlKeyState |= LEFT_ALT_PRESSED;
1423 if (GetKeyState(VK_RCONTROL) & 0x8000)
1424 dwControlKeyState |= RIGHT_CTRL_PRESSED;
1425 if (GetKeyState(VK_LCONTROL) & 0x8000)
1426 dwControlKeyState |= LEFT_CTRL_PRESSED;
1427 if (GetKeyState(VK_SHIFT) & 0x8000)
1428 dwControlKeyState |= SHIFT_PRESSED;
1429 if (GetKeyState(VK_NUMLOCK) & 0x0001)
1430 dwControlKeyState |= NUMLOCK_ON;
1431 if (GetKeyState(VK_SCROLL) & 0x0001)
1432 dwControlKeyState |= SCROLLLOCK_ON;
1433 if (GetKeyState(VK_CAPITAL) & 0x0001)
1434 dwControlKeyState |= CAPSLOCK_ON;
1435 /* See WM_CHAR MSDN documentation for instance */
1436 if (lParam & 0x01000000)
1437 dwControlKeyState |= ENHANCED_KEY;
1438
1439 er.EventType = MOUSE_EVENT;
1440 er.Event.MouseEvent.dwMousePosition = PointToCoord(GuiData, lParam);
1441 er.Event.MouseEvent.dwButtonState = dwButtonState;
1442 er.Event.MouseEvent.dwControlKeyState = dwControlKeyState;
1443 er.Event.MouseEvent.dwEventFlags = dwEventFlags;
1444
1445 ConioProcessInputEvent(Console, &er);
1446 }
1447 }
1448 else
1449 {
1450 Err = TRUE;
1451 }
1452
1453 LeaveCriticalSection(&Console->Lock);
1454
1455 Quit:
1456 if (Err)
1457 return DefWindowProcW(GuiData->hWindow, msg, wParam, lParam);
1458 else
1459 return 0;
1460 }
1461
1462 VOID GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer);
1463 VOID GuiCopyFromGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer);
1464
1465 static VOID
1466 GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData)
1467 {
1468 if (OpenClipboard(GuiData->hWindow) == TRUE)
1469 {
1470 PCONSOLE Console = GuiData->Console;
1471 PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(Console);
1472
1473 if (GetType(Buffer) == TEXTMODE_BUFFER)
1474 {
1475 GuiCopyFromTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)Buffer);
1476 }
1477 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
1478 {
1479 GuiCopyFromGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)Buffer);
1480 }
1481
1482 CloseClipboard();
1483
1484 /* Clear the selection */
1485 GuiConsoleUpdateSelection(Console, NULL);
1486 SetWindowText(GuiData->hWindow, Console->Title.Buffer);
1487 }
1488 }
1489
1490 VOID GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer);
1491 VOID GuiPasteToGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer);
1492
1493 static VOID
1494 GuiConsolePaste(PGUI_CONSOLE_DATA GuiData)
1495 {
1496 if (OpenClipboard(GuiData->hWindow) == TRUE)
1497 {
1498 // PCONSOLE Console = GuiData->Console;
1499 PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(Console);
1500
1501 if (GetType(Buffer) == TEXTMODE_BUFFER)
1502 {
1503 GuiPasteToTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)Buffer);
1504 }
1505 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
1506 {
1507 GuiPasteToGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)Buffer);
1508 }
1509
1510 CloseClipboard();
1511 }
1512 }
1513
1514 static VOID
1515 GuiConsoleGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData, PMINMAXINFO minMaxInfo)
1516 {
1517 PCONSOLE Console = GuiData->Console;
1518 PCONSOLE_SCREEN_BUFFER ActiveBuffer;
1519 DWORD windx, windy;
1520 UINT WidthUnit, HeightUnit;
1521
1522 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
1523
1524 // ActiveBuffer = ConDrvGetActiveScreenBuffer(Console);
1525 ActiveBuffer = GuiData->ActiveBuffer;
1526
1527 GetScreenBufferSizeUnits(ActiveBuffer, GuiData, &WidthUnit, &HeightUnit);
1528
1529 windx = CONGUI_MIN_WIDTH * WidthUnit + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
1530 windy = CONGUI_MIN_HEIGHT * HeightUnit + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
1531
1532 minMaxInfo->ptMinTrackSize.x = windx;
1533 minMaxInfo->ptMinTrackSize.y = windy;
1534
1535 windx = (ActiveBuffer->ScreenBufferSize.X) * WidthUnit + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
1536 windy = (ActiveBuffer->ScreenBufferSize.Y) * HeightUnit + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
1537
1538 if (ActiveBuffer->ViewSize.X < ActiveBuffer->ScreenBufferSize.X) windy += GetSystemMetrics(SM_CYHSCROLL); // window currently has a horizontal scrollbar
1539 if (ActiveBuffer->ViewSize.Y < ActiveBuffer->ScreenBufferSize.Y) windx += GetSystemMetrics(SM_CXVSCROLL); // window currently has a vertical scrollbar
1540
1541 minMaxInfo->ptMaxTrackSize.x = windx;
1542 minMaxInfo->ptMaxTrackSize.y = windy;
1543
1544 LeaveCriticalSection(&Console->Lock);
1545 }
1546
1547 static VOID
1548 GuiConsoleResize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
1549 {
1550 PCONSOLE Console = GuiData->Console;
1551
1552 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
1553
1554 if ((GuiData->WindowSizeLock == FALSE) &&
1555 (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED || wParam == SIZE_MINIMIZED))
1556 {
1557 PCONSOLE_SCREEN_BUFFER Buff = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(Console);
1558 DWORD windx, windy, charx, chary;
1559 UINT WidthUnit, HeightUnit;
1560
1561 GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit);
1562
1563 GuiData->WindowSizeLock = TRUE;
1564
1565 windx = LOWORD(lParam);
1566 windy = HIWORD(lParam);
1567
1568 // Compensate for existing scroll bars (because lParam values do not accommodate scroll bar)
1569 if (Buff->ViewSize.X < Buff->ScreenBufferSize.X) windy += GetSystemMetrics(SM_CYHSCROLL); // window currently has a horizontal scrollbar
1570 if (Buff->ViewSize.Y < Buff->ScreenBufferSize.Y) windx += GetSystemMetrics(SM_CXVSCROLL); // window currently has a vertical scrollbar
1571
1572 charx = windx / (int)WidthUnit ;
1573 chary = windy / (int)HeightUnit;
1574
1575 // Character alignment (round size up or down)
1576 if ((windx % WidthUnit ) >= (WidthUnit / 2)) ++charx;
1577 if ((windy % HeightUnit) >= (HeightUnit / 2)) ++chary;
1578
1579 // Compensate for added scroll bars in new window
1580 if (charx < Buff->ScreenBufferSize.X) windy -= GetSystemMetrics(SM_CYHSCROLL); // new window will have a horizontal scroll bar
1581 if (chary < Buff->ScreenBufferSize.Y) windx -= GetSystemMetrics(SM_CXVSCROLL); // new window will have a vertical scroll bar
1582
1583 charx = windx / (int)WidthUnit ;
1584 chary = windy / (int)HeightUnit;
1585
1586 // Character alignment (round size up or down)
1587 if ((windx % WidthUnit ) >= (WidthUnit / 2)) ++charx;
1588 if ((windy % HeightUnit) >= (HeightUnit / 2)) ++chary;
1589
1590 // Resize window
1591 if ((charx != Buff->ViewSize.X) || (chary != Buff->ViewSize.Y))
1592 {
1593 Buff->ViewSize.X = (charx <= Buff->ScreenBufferSize.X) ? charx : Buff->ScreenBufferSize.X;
1594 Buff->ViewSize.Y = (chary <= Buff->ScreenBufferSize.Y) ? chary : Buff->ScreenBufferSize.Y;
1595 }
1596
1597 GuiConsoleResizeWindow(GuiData);
1598
1599 // Adjust the start of the visible area if we are attempting to show nonexistent areas
1600 if ((Buff->ScreenBufferSize.X - Buff->ViewOrigin.X) < Buff->ViewSize.X) Buff->ViewOrigin.X = Buff->ScreenBufferSize.X - Buff->ViewSize.X;
1601 if ((Buff->ScreenBufferSize.Y - Buff->ViewOrigin.Y) < Buff->ViewSize.Y) Buff->ViewOrigin.Y = Buff->ScreenBufferSize.Y - Buff->ViewSize.Y;
1602 InvalidateRect(GuiData->hWindow, NULL, TRUE);
1603
1604 GuiData->WindowSizeLock = FALSE;
1605 }
1606
1607 LeaveCriticalSection(&Console->Lock);
1608 }
1609
1610 /*
1611 // HACK: This functionality is standard for general scrollbars. Don't add it by hand.
1612
1613 VOID
1614 FASTCALL
1615 GuiConsoleHandleScrollbarMenu(VOID)
1616 {
1617 HMENU hMenu;
1618
1619 hMenu = CreatePopupMenu();
1620 if (hMenu == NULL)
1621 {
1622 DPRINT("CreatePopupMenu failed\n");
1623 return;
1624 }
1625
1626 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLHERE);
1627 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1628 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLTOP);
1629 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLBOTTOM);
1630 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1631 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_UP);
1632 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_DOWN);
1633 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1634 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLUP);
1635 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLDOWN);
1636 }
1637 */
1638
1639 static LRESULT
1640 GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam)
1641 {
1642 PCONSOLE Console = GuiData->Console;
1643 PCONSOLE_SCREEN_BUFFER Buff;
1644 SCROLLINFO sInfo;
1645 int fnBar;
1646 int old_pos, Maximum;
1647 PSHORT pShowXY;
1648
1649 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return 0;
1650
1651 Buff = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(Console);
1652
1653 if (uMsg == WM_HSCROLL)
1654 {
1655 fnBar = SB_HORZ;
1656 Maximum = Buff->ScreenBufferSize.X - Buff->ViewSize.X;
1657 pShowXY = &Buff->ViewOrigin.X;
1658 }
1659 else
1660 {
1661 fnBar = SB_VERT;
1662 Maximum = Buff->ScreenBufferSize.Y - Buff->ViewSize.Y;
1663 pShowXY = &Buff->ViewOrigin.Y;
1664 }
1665
1666 /* set scrollbar sizes */
1667 sInfo.cbSize = sizeof(SCROLLINFO);
1668 sInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE | SIF_TRACKPOS;
1669
1670 if (!GetScrollInfo(GuiData->hWindow, fnBar, &sInfo)) goto Quit;
1671
1672 old_pos = sInfo.nPos;
1673
1674 switch (LOWORD(wParam))
1675 {
1676 case SB_LINELEFT:
1677 sInfo.nPos -= 1;
1678 break;
1679
1680 case SB_LINERIGHT:
1681 sInfo.nPos += 1;
1682 break;
1683
1684 case SB_PAGELEFT:
1685 sInfo.nPos -= sInfo.nPage;
1686 break;
1687
1688 case SB_PAGERIGHT:
1689 sInfo.nPos += sInfo.nPage;
1690 break;
1691
1692 case SB_THUMBTRACK:
1693 sInfo.nPos = sInfo.nTrackPos;
1694 ConioPause(Console, PAUSED_FROM_SCROLLBAR);
1695 break;
1696
1697 case SB_THUMBPOSITION:
1698 ConioUnpause(Console, PAUSED_FROM_SCROLLBAR);
1699 break;
1700
1701 case SB_TOP:
1702 sInfo.nPos = sInfo.nMin;
1703 break;
1704
1705 case SB_BOTTOM:
1706 sInfo.nPos = sInfo.nMax;
1707 break;
1708
1709 default:
1710 break;
1711 }
1712
1713 sInfo.nPos = max(sInfo.nPos, 0);
1714 sInfo.nPos = min(sInfo.nPos, Maximum);
1715
1716 if (old_pos != sInfo.nPos)
1717 {
1718 USHORT OldX = Buff->ViewOrigin.X;
1719 USHORT OldY = Buff->ViewOrigin.Y;
1720 UINT WidthUnit, HeightUnit;
1721
1722 *pShowXY = sInfo.nPos;
1723
1724 GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit);
1725
1726 ScrollWindowEx(GuiData->hWindow,
1727 (OldX - Buff->ViewOrigin.X) * WidthUnit ,
1728 (OldY - Buff->ViewOrigin.Y) * HeightUnit,
1729 NULL,
1730 NULL,
1731 NULL,
1732 NULL,
1733 SW_INVALIDATE);
1734
1735 sInfo.fMask = SIF_POS;
1736 SetScrollInfo(GuiData->hWindow, fnBar, &sInfo, TRUE);
1737
1738 UpdateWindow(GuiData->hWindow);
1739 }
1740
1741 Quit:
1742 LeaveCriticalSection(&Console->Lock);
1743 return 0;
1744 }
1745
1746 static LRESULT CALLBACK
1747 GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1748 {
1749 LRESULT Result = 0;
1750 PGUI_CONSOLE_DATA GuiData = NULL;
1751 PCONSOLE Console = NULL;
1752
1753 /*
1754 * - If it's the first time we create a window for the terminal,
1755 * just initialize it and return.
1756 *
1757 * - If we are destroying the window, just do it and return.
1758 */
1759 if (msg == WM_NCCREATE)
1760 {
1761 return (LRESULT)GuiConsoleHandleNcCreate(hWnd, (LPCREATESTRUCTW)lParam);
1762 }
1763 else if (msg == WM_NCDESTROY)
1764 {
1765 return GuiConsoleHandleNcDestroy(hWnd);
1766 }
1767
1768 /*
1769 * Now the terminal window is initialized.
1770 * Get the terminal data via the window's data.
1771 * If there is no data, just go away.
1772 */
1773 GuiData = GuiGetGuiData(hWnd);
1774 if (GuiData == NULL) return DefWindowProcW(hWnd, msg, wParam, lParam);
1775
1776 // TEMPORARY HACK until all of the functions can deal with a NULL GuiData->ActiveBuffer ...
1777 if (GuiData->ActiveBuffer == NULL) return DefWindowProcW(hWnd, msg, wParam, lParam);
1778
1779 /*
1780 * Just retrieve a pointer to the console in case somebody needs it.
1781 * It is not NULL because it was checked in GuiGetGuiData.
1782 * Each helper function which needs the console has to validate and lock it.
1783 */
1784 Console = GuiData->Console;
1785
1786 /* We have a console, start message dispatching */
1787 switch (msg)
1788 {
1789 case WM_ACTIVATE:
1790 {
1791 WORD ActivationState = LOWORD(wParam);
1792
1793 if ( ActivationState == WA_ACTIVE ||
1794 ActivationState == WA_CLICKACTIVE )
1795 {
1796 if (GuiData->GuiInfo.FullScreen)
1797 {
1798 EnterFullScreen(GuiData);
1799 // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
1800 // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
1801 }
1802 }
1803 else // if (ActivationState == WA_INACTIVE)
1804 {
1805 if (GuiData->GuiInfo.FullScreen)
1806 {
1807 SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
1808 LeaveFullScreen(GuiData);
1809 // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
1810 // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
1811 }
1812 }
1813
1814 if (ActivationState == WA_CLICKACTIVE) GuiData->IgnoreNextMouseSignal = TRUE;
1815
1816 break;
1817 }
1818
1819 case WM_CLOSE:
1820 if (GuiConsoleHandleClose(GuiData)) goto Default;
1821 break;
1822
1823 case WM_PAINT:
1824 GuiConsoleHandlePaint(GuiData);
1825 break;
1826
1827 case WM_PALETTECHANGED:
1828 {
1829 PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(GuiData->Console);
1830
1831 DPRINT1("WM_PALETTECHANGED called\n");
1832
1833 /*
1834 * Protects against infinite loops:
1835 * "... A window that receives this message must not realize
1836 * its palette, unless it determines that wParam does not contain
1837 * its own window handle." (WM_PALETTECHANGED description - MSDN)
1838 *
1839 * This message is sent to all windows, including the one that
1840 * changed the system palette and caused this message to be sent.
1841 * The wParam of this message contains the handle of the window
1842 * that caused the system palette to change. To avoid an infinite
1843 * loop, care must be taken to check that the wParam of this message
1844 * does not match the window's handle.
1845 */
1846 if ((HWND)wParam == hWnd) break;
1847
1848 DPRINT1("WM_PALETTECHANGED ok\n");
1849
1850 // if (GetType(ActiveBuffer) == GRAPHICS_BUFFER)
1851 if (ActiveBuffer->PaletteHandle)
1852 {
1853 /* Get the Device Context of the console window */
1854 HDC hDC = GetDC(GuiData->hWindow);
1855
1856 DPRINT1("WM_PALETTECHANGED changing palette\n");
1857
1858 /* Specify the use of the system palette */
1859 SetSystemPaletteUse(hDC, ActiveBuffer->PaletteUsage);
1860
1861 /* Realize the (logical) palette */
1862 RealizePalette(hDC);
1863
1864 /* Release the Device Context and return */
1865 ReleaseDC(GuiData->hWindow, hDC);
1866 }
1867
1868 DPRINT1("WM_PALETTECHANGED quit\n");
1869
1870 break;
1871 }
1872
1873 case WM_KEYDOWN:
1874 case WM_KEYUP:
1875 case WM_CHAR:
1876 case WM_DEADCHAR:
1877 case WM_SYSKEYDOWN:
1878 case WM_SYSKEYUP:
1879 case WM_SYSCHAR:
1880 case WM_SYSDEADCHAR:
1881 {
1882 /* Detect Alt-Enter presses and switch back and forth to fullscreen mode */
1883 if (msg == WM_SYSKEYDOWN && (HIWORD(lParam) & KF_ALTDOWN) && wParam == VK_RETURN)
1884 {
1885 /* Switch only at first Alt-Enter press, and ignore subsequent key repetitions */
1886 if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) != KF_REPEAT) GuiConsoleSwitchFullScreen(GuiData);
1887 break;
1888 }
1889
1890 GuiConsoleHandleKey(GuiData, msg, wParam, lParam);
1891 break;
1892 }
1893
1894 case WM_TIMER:
1895 GuiConsoleHandleTimer(GuiData);
1896 break;
1897
1898 case WM_SETCURSOR:
1899 {
1900 /*
1901 * The message was sent because we are manually triggering a change.
1902 * Check whether the mouse is indeed present on this console window
1903 * and take appropriate decisions.
1904 */
1905 if (wParam == -1 && lParam == -1)
1906 {
1907 POINT mouseCoords;
1908 HWND hWndHit;
1909
1910 /* Get the placement of the mouse */
1911 GetCursorPos(&mouseCoords);
1912
1913 /* On which window is placed the mouse ? */
1914 hWndHit = WindowFromPoint(mouseCoords);
1915
1916 /* It's our window. Perform the hit-test to be used later on. */
1917 if (hWndHit == hWnd)
1918 {
1919 wParam = (WPARAM)hWnd;
1920 lParam = DefWindowProcW(hWndHit, WM_NCHITTEST, 0,
1921 MAKELPARAM(mouseCoords.x, mouseCoords.y));
1922 }
1923 }
1924
1925 /* Set the mouse cursor only when we are in the client area */
1926 if ((HWND)wParam == hWnd && LOWORD(lParam) == HTCLIENT)
1927 {
1928 if (GuiData->MouseCursorRefCount >= 0)
1929 {
1930 /* Show the cursor */
1931 SetCursor(GuiData->hCursor);
1932 }
1933 else
1934 {
1935 /* Hide the cursor if the reference count is negative */
1936 SetCursor(NULL);
1937 }
1938 return TRUE;
1939 }
1940 else
1941 {
1942 goto Default;
1943 }
1944 }
1945
1946 case WM_LBUTTONDOWN:
1947 case WM_MBUTTONDOWN:
1948 case WM_RBUTTONDOWN:
1949 case WM_LBUTTONUP:
1950 case WM_MBUTTONUP:
1951 case WM_RBUTTONUP:
1952 case WM_LBUTTONDBLCLK:
1953 case WM_MBUTTONDBLCLK:
1954 case WM_RBUTTONDBLCLK:
1955 case WM_MOUSEMOVE:
1956 case WM_MOUSEWHEEL:
1957 case WM_MOUSEHWHEEL:
1958 {
1959 Result = GuiConsoleHandleMouse(GuiData, msg, wParam, lParam);
1960 break;
1961 }
1962
1963 case WM_HSCROLL:
1964 case WM_VSCROLL:
1965 {
1966 Result = GuiConsoleHandleScroll(GuiData, msg, wParam);
1967 break;
1968 }
1969
1970 case WM_NCRBUTTONDOWN:
1971 {
1972 DPRINT1("WM_NCRBUTTONDOWN\n");
1973 /*
1974 * HACK: !! Because, when we deal with WM_RBUTTON* and we do not
1975 * call after that DefWindowProc, on ReactOS, right-clicks on the
1976 * (non-client) application title-bar does not display the system
1977 * menu and does not trigger a WM_NCRBUTTONUP message too.
1978 * See: http://git.reactos.org/?p=reactos.git;a=blob;f=reactos/win32ss/user/user32/windows/defwnd.c;hb=332bc8f482f40fd05ab510f78276576719fbfba8#l1103
1979 * and line 1135 too.
1980 */
1981 #if 0
1982 if (DefWindowProcW(hWnd, WM_NCHITTEST, 0, lParam) == HTCAPTION)
1983 {
1984 /* Call DefWindowProcW with the WM_CONTEXTMENU message */
1985 msg = WM_CONTEXTMENU;
1986 }
1987 #endif
1988 goto Default;
1989 }
1990 // case WM_NCRBUTTONUP:
1991 // DPRINT1("WM_NCRBUTTONUP\n");
1992 // goto Default;
1993
1994 case WM_CONTEXTMENU:
1995 {
1996 if (DefWindowProcW(hWnd /*GuiData->hWindow*/, WM_NCHITTEST, 0, lParam) == HTCLIENT)
1997 {
1998 HMENU hMenu = CreatePopupMenu();
1999 if (hMenu != NULL)
2000 {
2001 GuiConsoleAppendMenuItems(hMenu, GuiConsoleEditMenuItems);
2002 TrackPopupMenuEx(hMenu,
2003 TPM_RIGHTBUTTON,
2004 GET_X_LPARAM(lParam),
2005 GET_Y_LPARAM(lParam),
2006 hWnd,
2007 NULL);
2008 DestroyMenu(hMenu);
2009 }
2010 break;
2011 }
2012 else
2013 {
2014 goto Default;
2015 }
2016 }
2017
2018 case WM_INITMENU:
2019 {
2020 HMENU hMenu = (HMENU)wParam;
2021 if (hMenu != NULL)
2022 {
2023 /* Enable or disable the Close menu item */
2024 EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND |
2025 (GuiData->IsCloseButtonEnabled ? MF_ENABLED : MF_GRAYED));
2026
2027 /* Enable or disable the Copy and Paste items */
2028 EnableMenuItem(hMenu, ID_SYSTEM_EDIT_COPY , MF_BYCOMMAND |
2029 ((Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) &&
2030 (Console->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY) ? MF_ENABLED : MF_GRAYED));
2031 EnableMenuItem(hMenu, ID_SYSTEM_EDIT_PASTE, MF_BYCOMMAND |
2032 (!(Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) &&
2033 IsClipboardFormatAvailable(CF_UNICODETEXT) ? MF_ENABLED : MF_GRAYED));
2034 }
2035
2036 if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
2037 {
2038 GuiSendMenuEvent(Console, WM_INITMENU);
2039 LeaveCriticalSection(&Console->Lock);
2040 }
2041 break;
2042 }
2043
2044 case WM_MENUSELECT:
2045 {
2046 if (HIWORD(wParam) == 0xFFFF) // Allow all the menu flags
2047 {
2048 if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
2049 {
2050 GuiSendMenuEvent(Console, WM_MENUSELECT);
2051 LeaveCriticalSection(&Console->Lock);
2052 }
2053 }
2054 break;
2055 }
2056
2057 case WM_COMMAND:
2058 case WM_SYSCOMMAND:
2059 {
2060 Result = GuiConsoleHandleSysMenuCommand(GuiData, wParam, lParam);
2061 break;
2062 }
2063
2064 case WM_SETFOCUS:
2065 case WM_KILLFOCUS:
2066 {
2067 if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
2068 {
2069 BOOL SetFocus = (msg == WM_SETFOCUS);
2070 INPUT_RECORD er;
2071
2072 er.EventType = FOCUS_EVENT;
2073 er.Event.FocusEvent.bSetFocus = SetFocus;
2074 ConioProcessInputEvent(Console, &er);
2075
2076 if (SetFocus)
2077 DPRINT1("TODO: Create console caret\n");
2078 else
2079 DPRINT1("TODO: Destroy console caret\n");
2080
2081 LeaveCriticalSection(&Console->Lock);
2082 }
2083 break;
2084 }
2085
2086 case WM_GETMINMAXINFO:
2087 GuiConsoleGetMinMaxInfo(GuiData, (PMINMAXINFO)lParam);
2088 break;
2089
2090 case WM_SIZE:
2091 GuiConsoleResize(GuiData, wParam, lParam);
2092 break;
2093
2094 case PM_RESIZE_TERMINAL:
2095 {
2096 /* Resize the window to the user's values */
2097 GuiData->WindowSizeLock = TRUE;
2098 GuiConsoleResizeWindow(GuiData);
2099 GuiData->WindowSizeLock = FALSE;
2100 break;
2101 }
2102
2103 case PM_APPLY_CONSOLE_INFO:
2104 {
2105 if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
2106 {
2107 GuiApplyUserSettings(GuiData, (HANDLE)wParam, (BOOL)lParam);
2108 LeaveCriticalSection(&Console->Lock);
2109 }
2110 break;
2111 }
2112
2113 case PM_CONSOLE_BEEP:
2114 DPRINT1("Beep !!\n");
2115 Beep(800, 200);
2116 break;
2117
2118 // case PM_CONSOLE_SET_TITLE:
2119 // SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
2120 // break;
2121
2122 default: Default:
2123 Result = DefWindowProcW(hWnd, msg, wParam, lParam);
2124 break;
2125 }
2126
2127 return Result;
2128 }
2129
2130
2131
2132 /******************************************************************************
2133 * GUI Terminal Initialization *
2134 ******************************************************************************/
2135
2136 static LRESULT CALLBACK
2137 GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
2138 {
2139 HWND NewWindow;
2140 LONG WindowCount;
2141 MSG Msg;
2142
2143 switch (msg)
2144 {
2145 case WM_CREATE:
2146 {
2147 SetWindowLongW(hWnd, GWL_USERDATA, 0);
2148 return 0;
2149 }
2150
2151 case PM_CREATE_CONSOLE:
2152 {
2153 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)lParam;
2154 PCONSOLE Console = GuiData->Console;
2155
2156 NewWindow = CreateWindowExW(WS_EX_CLIENTEDGE,
2157 GUI_CONSOLE_WINDOW_CLASS,
2158 Console->Title.Buffer,
2159 WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
2160 CW_USEDEFAULT,
2161 CW_USEDEFAULT,
2162 CW_USEDEFAULT,
2163 CW_USEDEFAULT,
2164 NULL,
2165 NULL,
2166 ConSrvDllInstance,
2167 (PVOID)GuiData);
2168 if (NULL != NewWindow)
2169 {
2170 ASSERT(NewWindow == GuiData->hWindow);
2171
2172 WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
2173 WindowCount++;
2174 SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
2175
2176 DPRINT("Set icons via PM_CREATE_CONSOLE\n");
2177 if (GuiData->hIcon == NULL)
2178 {
2179 DPRINT("Not really /o\\...\n");
2180 GuiData->hIcon = ghDefaultIcon;
2181 GuiData->hIconSm = ghDefaultIconSm;
2182 }
2183 else if (GuiData->hIcon != ghDefaultIcon)
2184 {
2185 DPRINT("Yes \\o/\n");
2186 SendMessageW(GuiData->hWindow, WM_SETICON, ICON_BIG, (LPARAM)GuiData->hIcon);
2187 SendMessageW(GuiData->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)GuiData->hIconSm);
2188 }
2189
2190 /* Move and resize the window to the user's values */
2191 /* CAN WE DEADLOCK ?? */
2192 GuiConsoleMoveWindow(GuiData);
2193 GuiData->WindowSizeLock = TRUE;
2194 GuiConsoleResizeWindow(GuiData);
2195 GuiData->WindowSizeLock = FALSE;
2196
2197 /* Switch to full-screen mode if necessary */
2198 if (GuiData->GuiInfo.FullScreen) SwitchFullScreen(GuiData, TRUE);
2199
2200 // ShowWindow(NewWindow, (int)wParam);
2201 ShowWindowAsync(NewWindow, (int)wParam);
2202 DPRINT("Window showed\n");
2203 }
2204
2205 return (LRESULT)NewWindow;
2206 }
2207
2208 case PM_DESTROY_CONSOLE:
2209 {
2210 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)lParam;
2211
2212 /* Exit the full screen mode if it was already set */
2213 // LeaveFullScreen(GuiData);
2214
2215 /*
2216 * Window creation is done using a PostMessage(), so it's possible
2217 * that the window that we want to destroy doesn't exist yet.
2218 * So first empty the message queue.
2219 */
2220 /*
2221 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
2222 {
2223 TranslateMessage(&Msg);
2224 DispatchMessageW(&Msg);
2225 }*/
2226 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE)) ;
2227
2228 if (GuiData->hWindow != NULL) /* && DestroyWindow(GuiData->hWindow) */
2229 {
2230 DestroyWindow(GuiData->hWindow);
2231
2232 WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
2233 WindowCount--;
2234 SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
2235 if (0 == WindowCount)
2236 {
2237 NotifyWnd = NULL;
2238 DestroyWindow(hWnd);
2239 DPRINT("CONSRV: Going to quit the Gui Thread!!\n");
2240 PostQuitMessage(0);
2241 }
2242 }
2243
2244 return 0;
2245 }
2246
2247 default:
2248 return DefWindowProcW(hWnd, msg, wParam, lParam);
2249 }
2250 }
2251
2252 static DWORD NTAPI
2253 GuiConsoleGuiThread(PVOID Data)
2254 {
2255 MSG msg;
2256 PHANDLE GraphicsStartupEvent = (PHANDLE)Data;
2257
2258 /*
2259 * This thread dispatches all the console notifications to the notify window.
2260 * It is common for all the console windows.
2261 */
2262
2263 PrivateCsrssManualGuiCheck(+1);
2264
2265 NotifyWnd = CreateWindowW(L"ConSrvCreateNotify",
2266 L"",
2267 WS_OVERLAPPEDWINDOW,
2268 CW_USEDEFAULT,
2269 CW_USEDEFAULT,
2270 CW_USEDEFAULT,
2271 CW_USEDEFAULT,
2272 NULL,
2273 NULL,
2274 ConSrvDllInstance,
2275 NULL);
2276 if (NULL == NotifyWnd)
2277 {
2278 PrivateCsrssManualGuiCheck(-1);
2279 SetEvent(*GraphicsStartupEvent);
2280 return 1;
2281 }
2282
2283 SetEvent(*GraphicsStartupEvent);
2284
2285 while (GetMessageW(&msg, NULL, 0, 0))
2286 {
2287 TranslateMessage(&msg);
2288 DispatchMessageW(&msg);
2289 }
2290
2291 DPRINT("CONSRV: Quit the Gui Thread!!\n");
2292 PrivateCsrssManualGuiCheck(-1);
2293
2294 return 1;
2295 }
2296
2297 static BOOL
2298 GuiInit(VOID)
2299 {
2300 WNDCLASSEXW wc;
2301 ATOM ConsoleClassAtom;
2302
2303 /* Exit if we were already initialized */
2304 // if (ConsInitialized) return TRUE;
2305
2306 /*
2307 * Initialize and register the different window classes, if needed.
2308 */
2309 if (!ConsInitialized)
2310 {
2311 /* Initialize the notification window class */
2312 wc.cbSize = sizeof(WNDCLASSEXW);
2313 wc.lpszClassName = L"ConSrvCreateNotify";
2314 wc.lpfnWndProc = GuiConsoleNotifyWndProc;
2315 wc.style = 0;
2316 wc.hInstance = ConSrvDllInstance;
2317 wc.hIcon = NULL;
2318 wc.hIconSm = NULL;
2319 wc.hCursor = NULL;
2320 wc.hbrBackground = NULL;
2321 wc.lpszMenuName = NULL;
2322 wc.cbClsExtra = 0;
2323 wc.cbWndExtra = 0;
2324 if (RegisterClassExW(&wc) == 0)
2325 {
2326 DPRINT1("Failed to register GUI notify wndproc\n");
2327 return FALSE;
2328 }
2329
2330 /* Initialize the console window class */
2331 ghDefaultIcon = LoadImageW(ConSrvDllInstance,
2332 MAKEINTRESOURCEW(IDI_TERMINAL),
2333 IMAGE_ICON,
2334 GetSystemMetrics(SM_CXICON),
2335 GetSystemMetrics(SM_CYICON),
2336 LR_SHARED);
2337 ghDefaultIconSm = LoadImageW(ConSrvDllInstance,
2338 MAKEINTRESOURCEW(IDI_TERMINAL),
2339 IMAGE_ICON,
2340 GetSystemMetrics(SM_CXSMICON),
2341 GetSystemMetrics(SM_CYSMICON),
2342 LR_SHARED);
2343 ghDefaultCursor = LoadCursorW(NULL, IDC_ARROW);
2344 wc.cbSize = sizeof(WNDCLASSEXW);
2345 wc.lpszClassName = GUI_CONSOLE_WINDOW_CLASS;
2346 wc.lpfnWndProc = GuiConsoleWndProc;
2347 wc.style = CS_DBLCLKS /* | CS_HREDRAW | CS_VREDRAW */;
2348 wc.hInstance = ConSrvDllInstance;
2349 wc.hIcon = ghDefaultIcon;
2350 wc.hIconSm = ghDefaultIconSm;
2351 wc.hCursor = ghDefaultCursor;
2352 wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); // The color of a terminal when it is switch off.
2353 wc.lpszMenuName = NULL;
2354 wc.cbClsExtra = 0;
2355 wc.cbWndExtra = GWLP_CONSOLEWND_ALLOC;
2356
2357 ConsoleClassAtom = RegisterClassExW(&wc);
2358 if (ConsoleClassAtom == 0)
2359 {
2360 DPRINT1("Failed to register GUI console wndproc\n");
2361 return FALSE;
2362 }
2363 else
2364 {
2365 NtUserConsoleControl(GuiConsoleWndClassAtom, &ConsoleClassAtom, sizeof(ATOM));
2366 }
2367
2368 ConsInitialized = TRUE;
2369 }
2370
2371 /*
2372 * Set-up the notification window
2373 */
2374 if (NULL == NotifyWnd)
2375 {
2376 HANDLE ThreadHandle;
2377 HANDLE GraphicsStartupEvent;
2378
2379 GraphicsStartupEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
2380 if (NULL == GraphicsStartupEvent) return FALSE;
2381
2382 ThreadHandle = CreateThread(NULL,
2383 0,
2384 GuiConsoleGuiThread,
2385 (PVOID)&GraphicsStartupEvent,
2386 0,
2387 NULL);
2388 if (NULL == ThreadHandle)
2389 {
2390 CloseHandle(GraphicsStartupEvent);
2391 DPRINT1("CONSRV: Failed to create graphics console thread. Expect problems\n");
2392 return FALSE;
2393 }
2394 SetThreadPriority(ThreadHandle, THREAD_PRIORITY_HIGHEST);
2395 CloseHandle(ThreadHandle);
2396
2397 WaitForSingleObject(GraphicsStartupEvent, INFINITE);
2398 CloseHandle(GraphicsStartupEvent);
2399
2400 if (NULL == NotifyWnd)
2401 {
2402 DPRINT1("CONSRV: Failed to create notification window.\n");
2403 return FALSE;
2404 }
2405 }
2406
2407 // ConsInitialized = TRUE;
2408
2409 return TRUE;
2410 }
2411
2412
2413
2414 /******************************************************************************
2415 * GUI Console Driver *
2416 ******************************************************************************/
2417
2418 static VOID NTAPI
2419 GuiDeinitFrontEnd(IN OUT PFRONTEND This);
2420
2421 NTSTATUS NTAPI
2422 GuiInitFrontEnd(IN OUT PFRONTEND This,
2423 IN PCONSOLE Console)
2424 {
2425 PGUI_INIT_INFO GuiInitInfo;
2426 PCONSOLE_INFO ConsoleInfo;
2427 PCONSOLE_START_INFO ConsoleStartInfo;
2428
2429 PGUI_CONSOLE_DATA GuiData;
2430 GUI_CONSOLE_INFO TermInfo;
2431
2432 SIZE_T Length = 0;
2433 LPWSTR IconPath = NULL;
2434 INT IconIndex = 0;
2435
2436 if (This == NULL || Console == NULL || This->OldData == NULL)
2437 return STATUS_INVALID_PARAMETER;
2438
2439 ASSERT(This->Console == Console);
2440
2441 GuiInitInfo = This->OldData;
2442
2443 if (GuiInitInfo->ConsoleInfo == NULL || GuiInitInfo->ConsoleStartInfo == NULL)
2444 return STATUS_INVALID_PARAMETER;
2445
2446 ConsoleInfo = GuiInitInfo->ConsoleInfo;
2447 ConsoleStartInfo = GuiInitInfo->ConsoleStartInfo;
2448
2449 IconPath = ConsoleStartInfo->IconPath;
2450 IconIndex = ConsoleStartInfo->IconIndex;
2451
2452
2453 /* Terminal data allocation */
2454 GuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(GUI_CONSOLE_DATA));
2455 if (!GuiData)
2456 {
2457 DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
2458 return STATUS_UNSUCCESSFUL;
2459 }
2460 /* HACK */ Console->TermIFace.Data = (PVOID)GuiData; /* HACK */
2461 GuiData->Console = Console;
2462 GuiData->ActiveBuffer = Console->ActiveBuffer;
2463 GuiData->hWindow = NULL;
2464
2465 /* The console can be resized */
2466 Console->FixedSize = FALSE;
2467
2468 InitializeCriticalSection(&GuiData->Lock);
2469
2470
2471 /*
2472 * Load terminal settings
2473 */
2474
2475 /* 1. Load the default settings */
2476 GuiConsoleGetDefaultSettings(&TermInfo, GuiInitInfo->ProcessId);
2477
2478 /* 3. Load the remaining console settings via the registry. */
2479 if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
2480 {
2481 /* Load the terminal infos from the registry. */
2482 GuiConsoleReadUserSettings(&TermInfo,
2483 ConsoleInfo->ConsoleTitle,
2484 GuiInitInfo->ProcessId);
2485
2486 /*
2487 * Now, update them with the properties the user might gave to us
2488 * via the STARTUPINFO structure before calling CreateProcess
2489 * (and which was transmitted via the ConsoleStartInfo structure).
2490 * We therefore overwrite the values read in the registry.
2491 */
2492 if (ConsoleStartInfo->dwStartupFlags & STARTF_USESHOWWINDOW)
2493 {
2494 TermInfo.ShowWindow = ConsoleStartInfo->wShowWindow;
2495 }
2496 if (ConsoleStartInfo->dwStartupFlags & STARTF_USEPOSITION)
2497 {
2498 TermInfo.AutoPosition = FALSE;
2499 TermInfo.WindowOrigin.x = ConsoleStartInfo->dwWindowOrigin.X;
2500 TermInfo.WindowOrigin.y = ConsoleStartInfo->dwWindowOrigin.Y;
2501 }
2502 if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)
2503 {
2504 TermInfo.FullScreen = TRUE;
2505 }
2506 }
2507
2508
2509 /*
2510 * Set up GUI data
2511 */
2512
2513 Length = min(wcslen(TermInfo.FaceName) + 1, LF_FACESIZE); // wcsnlen
2514 wcsncpy(GuiData->GuiInfo.FaceName, TermInfo.FaceName, LF_FACESIZE);
2515 GuiData->GuiInfo.FaceName[Length] = L'\0';
2516 GuiData->GuiInfo.FontFamily = TermInfo.FontFamily;
2517 GuiData->GuiInfo.FontSize = TermInfo.FontSize;
2518 GuiData->GuiInfo.FontWeight = TermInfo.FontWeight;
2519 GuiData->GuiInfo.UseRasterFonts = TermInfo.UseRasterFonts;
2520 GuiData->GuiInfo.FullScreen = TermInfo.FullScreen;
2521 GuiData->GuiInfo.ShowWindow = TermInfo.ShowWindow;
2522 GuiData->GuiInfo.AutoPosition = TermInfo.AutoPosition;
2523 GuiData->GuiInfo.WindowOrigin = TermInfo.WindowOrigin;
2524
2525 /* Initialize the icon handles to their default values */
2526 GuiData->hIcon = ghDefaultIcon;
2527 GuiData->hIconSm = ghDefaultIconSm;
2528
2529 /* Get the associated icon, if any */
2530 if (IconPath == NULL || IconPath[0] == L'\0')
2531 {
2532 IconPath = ConsoleStartInfo->AppPath;
2533 IconIndex = 0;
2534 }
2535 DPRINT("IconPath = %S ; IconIndex = %lu\n", (IconPath ? IconPath : L"n/a"), IconIndex);
2536 if (IconPath && IconPath[0] != L'\0')
2537 {
2538 HICON hIcon = NULL, hIconSm = NULL;
2539 PrivateExtractIconExW(IconPath,
2540 IconIndex,
2541 &hIcon,
2542 &hIconSm,
2543 1);
2544 DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon, hIconSm);
2545 if (hIcon != NULL)
2546 {
2547 DPRINT("Effectively set the icons\n");
2548 GuiData->hIcon = hIcon;
2549 GuiData->hIconSm = hIconSm;
2550 }
2551 }
2552
2553 /* Original system palette */
2554 GuiData->hSysPalette = NULL;
2555
2556 /* Mouse is shown by default with its default cursor shape */
2557 GuiData->hCursor = ghDefaultCursor;
2558 GuiData->MouseCursorRefCount = 0;
2559
2560 /* A priori don't ignore mouse signals */
2561 GuiData->IgnoreNextMouseSignal = FALSE;
2562
2563 /* Close button and the corresponding system menu item are enabled by default */
2564 GuiData->IsCloseButtonEnabled = TRUE;
2565
2566 /* There is no user-reserved menu id range by default */
2567 GuiData->cmdIdLow = GuiData->cmdIdHigh = 0;
2568
2569 /*
2570 * We need to wait until the GUI has been fully initialized
2571 * to retrieve custom settings i.e. WindowSize etc...
2572 * Ideally we could use SendNotifyMessage for this but its not
2573 * yet implemented.
2574 */
2575 GuiData->hGuiInitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
2576
2577 DPRINT("GUI - Checkpoint\n");
2578
2579 /* Create the terminal window */
2580 PostMessageW(NotifyWnd, PM_CREATE_CONSOLE, GuiData->GuiInfo.ShowWindow, (LPARAM)GuiData);
2581
2582 /* Wait until initialization has finished */
2583 WaitForSingleObject(GuiData->hGuiInitEvent, INFINITE);
2584 DPRINT("OK we created the console window\n");
2585 CloseHandle(GuiData->hGuiInitEvent);
2586 GuiData->hGuiInitEvent = NULL;
2587
2588 /* Check whether we really succeeded in initializing the terminal window */
2589 if (GuiData->hWindow == NULL)
2590 {
2591 DPRINT("GuiInitConsole - We failed at creating a new terminal window\n");
2592 GuiDeinitFrontEnd(This);
2593 return STATUS_UNSUCCESSFUL;
2594 }
2595
2596 /* Finally, finish to initialize the frontend structure */
2597 This->Data = GuiData;
2598 if (This->OldData) ConsoleFreeHeap(This->OldData);
2599 This->OldData = NULL;
2600
2601 return STATUS_SUCCESS;
2602 }
2603
2604 static VOID NTAPI
2605 GuiDeinitFrontEnd(IN OUT PFRONTEND This)
2606 {
2607 PGUI_CONSOLE_DATA GuiData = This->Data;
2608
2609 SendMessageW(NotifyWnd, PM_DESTROY_CONSOLE, 0, (LPARAM)GuiData);
2610
2611 DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
2612 GuiData->hIcon, ghDefaultIcon, GuiData->hIconSm, ghDefaultIconSm);
2613 if (GuiData->hIcon != NULL && GuiData->hIcon != ghDefaultIcon)
2614 {
2615 DPRINT("Destroy hIcon\n");
2616 DestroyIcon(GuiData->hIcon);
2617 }
2618 if (GuiData->hIconSm != NULL && GuiData->hIconSm != ghDefaultIconSm)
2619 {
2620 DPRINT("Destroy hIconSm\n");
2621 DestroyIcon(GuiData->hIconSm);
2622 }
2623
2624 This->Data = NULL;
2625 DeleteCriticalSection(&GuiData->Lock);
2626 ConsoleFreeHeap(GuiData);
2627
2628 DPRINT("Quit GuiDeinitFrontEnd\n");
2629 }
2630
2631 static VOID NTAPI
2632 GuiDrawRegion(IN OUT PFRONTEND This,
2633 SMALL_RECT* Region)
2634 {
2635 PGUI_CONSOLE_DATA GuiData = This->Data;
2636 RECT RegionRect;
2637
2638 SmallRectToRect(GuiData, &RegionRect, Region);
2639 /* Do not erase the background: it speeds up redrawing and reduce flickering */
2640 InvalidateRect(GuiData->hWindow, &RegionRect, FALSE);
2641 }
2642
2643 static VOID NTAPI
2644 GuiWriteStream(IN OUT PFRONTEND This,
2645 SMALL_RECT* Region,
2646 SHORT CursorStartX,
2647 SHORT CursorStartY,
2648 UINT ScrolledLines,
2649 PWCHAR Buffer,
2650 UINT Length)
2651 {
2652 PGUI_CONSOLE_DATA GuiData = This->Data;
2653 PCONSOLE_SCREEN_BUFFER Buff;
2654 SHORT CursorEndX, CursorEndY;
2655 RECT ScrollRect;
2656
2657 if (NULL == GuiData || NULL == GuiData->hWindow) return;
2658
2659 Buff = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(GuiData->Console);
2660 if (GetType(Buff) != TEXTMODE_BUFFER) return;
2661
2662 if (0 != ScrolledLines)
2663 {
2664 ScrollRect.left = 0;
2665 ScrollRect.top = 0;
2666 ScrollRect.right = Buff->ViewSize.X * GuiData->CharWidth;
2667 ScrollRect.bottom = Region->Top * GuiData->CharHeight;
2668
2669 ScrollWindowEx(GuiData->hWindow,
2670 0,
2671 -(int)(ScrolledLines * GuiData->CharHeight),
2672 &ScrollRect,
2673 NULL,
2674 NULL,
2675 NULL,
2676 SW_INVALIDATE);
2677 }
2678
2679 GuiDrawRegion(This, Region);
2680
2681 if (CursorStartX < Region->Left || Region->Right < CursorStartX
2682 || CursorStartY < Region->Top || Region->Bottom < CursorStartY)
2683 {
2684 GuiInvalidateCell(This, CursorStartX, CursorStartY);
2685 }
2686
2687 CursorEndX = Buff->CursorPosition.X;
2688 CursorEndY = Buff->CursorPosition.Y;
2689 if ((CursorEndX < Region->Left || Region->Right < CursorEndX
2690 || CursorEndY < Region->Top || Region->Bottom < CursorEndY)
2691 && (CursorEndX != CursorStartX || CursorEndY != CursorStartY))
2692 {
2693 GuiInvalidateCell(This, CursorEndX, CursorEndY);
2694 }
2695
2696 // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
2697 // repaint the window without having it just freeze up and stay on the screen permanently.
2698 Buff->CursorBlinkOn = TRUE;
2699 SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
2700 }
2701
2702 static BOOL NTAPI
2703 GuiSetCursorInfo(IN OUT PFRONTEND This,
2704 PCONSOLE_SCREEN_BUFFER Buff)
2705 {
2706 PGUI_CONSOLE_DATA GuiData = This->Data;
2707
2708 if (/*ConDrvGetActiveScreenBuffer(GuiData->Console)*/GuiData->ActiveBuffer == Buff)
2709 {
2710 GuiInvalidateCell(This, Buff->CursorPosition.X, Buff->CursorPosition.Y);
2711 }
2712
2713 return TRUE;
2714 }
2715
2716 static BOOL NTAPI
2717 GuiSetScreenInfo(IN OUT PFRONTEND This,
2718 PCONSOLE_SCREEN_BUFFER Buff,
2719 SHORT OldCursorX,
2720 SHORT OldCursorY)
2721 {
2722 PGUI_CONSOLE_DATA GuiData = This->Data;
2723
2724 if (/*ConDrvGetActiveScreenBuffer(GuiData->Console)*/GuiData->ActiveBuffer == Buff)
2725 {
2726 /* Redraw char at old position (remove cursor) */
2727 GuiInvalidateCell(This, OldCursorX, OldCursorY);
2728 /* Redraw char at new position (show cursor) */
2729 GuiInvalidateCell(This, Buff->CursorPosition.X, Buff->CursorPosition.Y);
2730 }
2731
2732 return TRUE;
2733 }
2734
2735 static VOID NTAPI
2736 GuiResizeTerminal(IN OUT PFRONTEND This)
2737 {
2738 PGUI_CONSOLE_DATA GuiData = This->Data;
2739
2740 /* Resize the window to the user's values */
2741 // GuiData->WindowSizeLock = TRUE;
2742 // GuiConsoleResizeWindow(GuiData);
2743 // GuiData->WindowSizeLock = FALSE;
2744 // NOTE: This code ^^ causes deadlocks...
2745
2746 PostMessageW(GuiData->hWindow, PM_RESIZE_TERMINAL, 0, 0);
2747 }
2748
2749 static VOID NTAPI
2750 GuiSetActiveScreenBuffer(IN OUT PFRONTEND This)
2751 {
2752 PGUI_CONSOLE_DATA GuiData = This->Data;
2753 PCONSOLE_SCREEN_BUFFER ActiveBuffer; // = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(GuiData->Console);
2754 HDC hDC;
2755 HPALETTE hPalette;
2756
2757 EnterCriticalSection(&GuiData->Lock);
2758 GuiData->WindowSizeLock = TRUE;
2759
2760 InterlockedExchangePointer(&GuiData->ActiveBuffer,
2761 GuiData->Console->ActiveBuffer);
2762
2763 GuiData->WindowSizeLock = FALSE;
2764 LeaveCriticalSection(&GuiData->Lock);
2765
2766 ActiveBuffer = GuiData->ActiveBuffer;
2767
2768 /* Change the current palette */
2769 if (ActiveBuffer->PaletteHandle == NULL)
2770 {
2771 hPalette = GuiData->hSysPalette;
2772 }
2773 else
2774 {
2775 hPalette = ActiveBuffer->PaletteHandle;
2776 }
2777
2778 DPRINT1("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette);
2779
2780 /* Get the Device Context of the console window */
2781 hDC = GetDC(GuiData->hWindow);
2782
2783 /* Set the new palette */
2784 SelectPalette(hDC, hPalette, FALSE);
2785
2786 /* Specify the use of the system palette */
2787 SetSystemPaletteUse(hDC, ActiveBuffer->PaletteUsage);
2788
2789 /* Realize the (logical) palette */
2790 RealizePalette(hDC);
2791
2792 /* Release the Device Context */
2793 ReleaseDC(GuiData->hWindow, hDC);
2794
2795 GuiResizeTerminal(This);
2796 // ConioDrawConsole(Console);
2797 }
2798
2799 static VOID NTAPI
2800 GuiReleaseScreenBuffer(IN OUT PFRONTEND This,
2801 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer)
2802 {
2803 PGUI_CONSOLE_DATA GuiData = This->Data;
2804 HDC hDC;
2805
2806 /*
2807 * If we were notified to release a screen buffer that is not actually
2808 * ours, then just ignore the notification...
2809 */
2810 if (ScreenBuffer != GuiData->ActiveBuffer) return;
2811
2812 /*
2813 * ... else, we must release our active buffer. Two cases are present:
2814 * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console
2815 * active screen buffer, then we can safely switch to it.
2816 * - If ScreenBuffer IS the console active screen buffer, we must release
2817 * it ONLY.
2818 */
2819
2820 /* Get the Device Context of the console window */
2821 hDC = GetDC(GuiData->hWindow);
2822
2823 /* Release the old active palette and set the default one */
2824 if (GetCurrentObject(hDC, OBJ_PAL) == ScreenBuffer->PaletteHandle)
2825 {
2826 /* Set the new palette */
2827 SelectPalette(hDC, GuiData->hSysPalette, FALSE);
2828 }
2829
2830 /* Release the Device Context */
2831 ReleaseDC(GuiData->hWindow, hDC);
2832
2833 /* Set the adequate active screen buffer */
2834 if (ScreenBuffer != GuiData->Console->ActiveBuffer)
2835 {
2836 GuiSetActiveScreenBuffer(This);
2837 }
2838 else
2839 {
2840 EnterCriticalSection(&GuiData->Lock);
2841 GuiData->WindowSizeLock = TRUE;
2842
2843 InterlockedExchangePointer(&GuiData->ActiveBuffer, NULL);
2844
2845 GuiData->WindowSizeLock = FALSE;
2846 LeaveCriticalSection(&GuiData->Lock);
2847 }
2848 }
2849
2850 static BOOL NTAPI
2851 GuiProcessKeyCallback(IN OUT PFRONTEND This,
2852 MSG* msg,
2853 BYTE KeyStateMenu,
2854 DWORD ShiftState,
2855 UINT VirtualKeyCode,
2856 BOOL Down)
2857 {
2858 if ((ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED) || KeyStateMenu & 0x80) &&
2859 (VirtualKeyCode == VK_ESCAPE || VirtualKeyCode == VK_TAB || VirtualKeyCode == VK_SPACE))
2860 {
2861 DefWindowProcW(msg->hwnd, msg->message, msg->wParam, msg->lParam);
2862 return TRUE;
2863 }
2864
2865 return FALSE;
2866 }
2867
2868 static BOOL NTAPI
2869 GuiSetMouseCursor(IN OUT PFRONTEND This,
2870 HCURSOR hCursor);
2871
2872 static VOID NTAPI
2873 GuiRefreshInternalInfo(IN OUT PFRONTEND This)
2874 {
2875 PGUI_CONSOLE_DATA GuiData = This->Data;
2876
2877 /* Update the console leader information held by the window */
2878 SetConsoleWndConsoleLeaderCID(GuiData);
2879
2880 /*
2881 * HACK:
2882 * We reset the cursor here so that, when a console app quits, we reset
2883 * the cursor to the default one. It's quite a hack since it doesn't proceed
2884 * per - console process... This must be fixed.
2885 *
2886 * See GuiInitConsole(...) for more information.
2887 */
2888
2889 /* Mouse is shown by default with its default cursor shape */
2890 GuiData->MouseCursorRefCount = 0; // Reinitialize the reference counter
2891 GuiSetMouseCursor(This, NULL);
2892 }
2893
2894 static VOID NTAPI
2895 GuiChangeTitle(IN OUT PFRONTEND This)
2896 {
2897 PGUI_CONSOLE_DATA GuiData = This->Data;
2898 // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
2899 SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
2900 }
2901
2902 static BOOL NTAPI
2903 GuiChangeIcon(IN OUT PFRONTEND This,
2904 HICON hWindowIcon)
2905 {
2906 PGUI_CONSOLE_DATA GuiData = This->Data;
2907 HICON hIcon, hIconSm;
2908
2909 if (hWindowIcon == NULL)
2910 {
2911 hIcon = ghDefaultIcon;
2912 hIconSm = ghDefaultIconSm;
2913 }
2914 else
2915 {
2916 hIcon = CopyIcon(hWindowIcon);
2917 hIconSm = CopyIcon(hWindowIcon);
2918 }
2919
2920 if (hIcon == NULL)
2921 {
2922 return FALSE;
2923 }
2924
2925 if (hIcon != GuiData->hIcon)
2926 {
2927 if (GuiData->hIcon != NULL && GuiData->hIcon != ghDefaultIcon)
2928 {
2929 DestroyIcon(GuiData->hIcon);
2930 }
2931 if (GuiData->hIconSm != NULL && GuiData->hIconSm != ghDefaultIconSm)
2932 {
2933 DestroyIcon(GuiData->hIconSm);
2934 }
2935
2936 GuiData->hIcon = hIcon;
2937 GuiData->hIconSm = hIconSm;
2938
2939 DPRINT("Set icons in GuiChangeIcon\n");
2940 PostMessageW(GuiData->hWindow, WM_SETICON, ICON_BIG, (LPARAM)GuiData->hIcon);
2941 PostMessageW(GuiData->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)GuiData->hIconSm);
2942 }
2943
2944 return TRUE;
2945 }
2946
2947 static HWND NTAPI
2948 GuiGetConsoleWindowHandle(IN OUT PFRONTEND This)
2949 {
2950 PGUI_CONSOLE_DATA GuiData = This->Data;
2951 return GuiData->hWindow;
2952 }
2953
2954 static VOID NTAPI
2955 GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This,
2956 PCOORD pSize)
2957 {
2958 PGUI_CONSOLE_DATA GuiData = This->Data;
2959 PCONSOLE_SCREEN_BUFFER ActiveBuffer;
2960 RECT WorkArea;
2961 LONG width, height;
2962 UINT WidthUnit, HeightUnit;
2963
2964 if (!pSize) return;
2965
2966 if (!SystemParametersInfoW(SPI_GETWORKAREA, 0, &WorkArea, 0))
2967 {
2968 DPRINT1("SystemParametersInfoW failed - What to do ??\n");
2969 return;
2970 }
2971
2972 // ActiveBuffer = ConDrvGetActiveScreenBuffer(GuiData->Console);
2973 ActiveBuffer = GuiData->ActiveBuffer;
2974 if (ActiveBuffer)
2975 {
2976 GetScreenBufferSizeUnits(ActiveBuffer, GuiData, &WidthUnit, &HeightUnit);
2977 }
2978 else
2979 {
2980 /* Default: text mode */
2981 WidthUnit = GuiData->CharWidth ;
2982 HeightUnit = GuiData->CharHeight;
2983 }
2984
2985 width = WorkArea.right;
2986 height = WorkArea.bottom;
2987
2988 width -= (2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE)));
2989 height -= (2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION));
2990
2991 if (width < 0) width = 0;
2992 if (height < 0) height = 0;
2993
2994 pSize->X = (SHORT)(width / (int)WidthUnit ) /* HACK */ + 2;
2995 pSize->Y = (SHORT)(height / (int)HeightUnit) /* HACK */ + 1;
2996 }
2997
2998 static BOOL NTAPI
2999 GuiSetPalette(IN OUT PFRONTEND This,
3000 HPALETTE PaletteHandle,
3001 UINT PaletteUsage)
3002 {
3003 BOOL Success = TRUE;
3004 PGUI_CONSOLE_DATA GuiData = This->Data;
3005 // PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer; // ConDrvGetActiveScreenBuffer(GuiData->Console);
3006 HDC hDC;
3007 HPALETTE OldPalette;
3008
3009 DPRINT1("GuiSetPalette checkpt 0\n");
3010
3011 // if (GetType(ActiveBuffer) != GRAPHICS_BUFFER) return FALSE;
3012 if (PaletteHandle == NULL) return FALSE;
3013
3014 DPRINT1("GuiSetPalette checkpt 1\n");
3015
3016 /* Get the Device Context of the console window */