4a5102f2584d91b0fcf51480e09828452ec6f5cb
[reactos.git] / reactos / win32ss / user / winsrv / consrv / frontends / gui / conwnd.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: frontends/gui/conwnd.c
5 * PURPOSE: GUI Console Window Class
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 #include <consrv.h>
15 #include <intrin.h>
16 #include <windowsx.h>
17
18 #define NDEBUG
19 #include <debug.h>
20
21 #include "guiterm.h"
22 #include "conwnd.h"
23 #include "resource.h"
24
25 /* GLOBALS ********************************************************************/
26
27 // #define PM_CREATE_CONSOLE (WM_APP + 1)
28 // #define PM_DESTROY_CONSOLE (WM_APP + 2)
29
30 // See guiterm.c
31 #define CONGUI_MIN_WIDTH 10
32 #define CONGUI_MIN_HEIGHT 10
33 #define CONGUI_UPDATE_TIME 0
34 #define CONGUI_UPDATE_TIMER 1
35
36 #define CURSOR_BLINK_TIME 500
37
38
39 /**************************************************************\
40 \** Define the Console Leader Process for the console window **/
41 #define GWLP_CONWND_ALLOC (2 * sizeof(LONG_PTR))
42 #define GWLP_CONSOLE_LEADER_PID 0
43 #define GWLP_CONSOLE_LEADER_TID 4
44
45 VOID
46 SetConWndConsoleLeaderCID(IN PGUI_CONSOLE_DATA GuiData)
47 {
48 PCONSOLE_PROCESS_DATA ProcessData;
49 CLIENT_ID ConsoleLeaderCID;
50
51 ProcessData = ConSrvGetConsoleLeaderProcess(GuiData->Console);
52 ConsoleLeaderCID = ProcessData->Process->ClientId;
53 SetWindowLongPtrW(GuiData->hWindow, GWLP_CONSOLE_LEADER_PID,
54 (LONG_PTR)(ConsoleLeaderCID.UniqueProcess));
55 SetWindowLongPtrW(GuiData->hWindow, GWLP_CONSOLE_LEADER_TID,
56 (LONG_PTR)(ConsoleLeaderCID.UniqueThread));
57 }
58 /**************************************************************/
59
60 HICON ghDefaultIcon = NULL;
61 HICON ghDefaultIconSm = NULL;
62 HCURSOR ghDefaultCursor = NULL;
63
64 typedef struct _GUICONSOLE_MENUITEM
65 {
66 UINT uID;
67 const struct _GUICONSOLE_MENUITEM *SubMenu;
68 WORD wCmdID;
69 } GUICONSOLE_MENUITEM, *PGUICONSOLE_MENUITEM;
70
71 static const GUICONSOLE_MENUITEM GuiConsoleEditMenuItems[] =
72 {
73 { IDS_MARK, NULL, ID_SYSTEM_EDIT_MARK },
74 { IDS_COPY, NULL, ID_SYSTEM_EDIT_COPY },
75 { IDS_PASTE, NULL, ID_SYSTEM_EDIT_PASTE },
76 { IDS_SELECTALL, NULL, ID_SYSTEM_EDIT_SELECTALL },
77 { IDS_SCROLL, NULL, ID_SYSTEM_EDIT_SCROLL },
78 { IDS_FIND, NULL, ID_SYSTEM_EDIT_FIND },
79
80 { 0, NULL, 0 } /* End of list */
81 };
82
83 static const GUICONSOLE_MENUITEM GuiConsoleMainMenuItems[] =
84 {
85 { IDS_EDIT, GuiConsoleEditMenuItems, 0 },
86 { IDS_DEFAULTS, NULL, ID_SYSTEM_DEFAULTS },
87 { IDS_PROPERTIES, NULL, ID_SYSTEM_PROPERTIES },
88
89 { 0, NULL, 0 } /* End of list */
90 };
91
92 /*
93 * Default 16-color palette for foreground and background
94 * (corresponding flags in comments).
95 */
96 const COLORREF s_Colors[16] =
97 {
98 RGB(0, 0, 0), // (Black)
99 RGB(0, 0, 128), // BLUE
100 RGB(0, 128, 0), // GREEN
101 RGB(0, 128, 128), // BLUE | GREEN
102 RGB(128, 0, 0), // RED
103 RGB(128, 0, 128), // BLUE | RED
104 RGB(128, 128, 0), // GREEN | RED
105 RGB(192, 192, 192), // BLUE | GREEN | RED
106
107 RGB(128, 128, 128), // (Grey) INTENSITY
108 RGB(0, 0, 255), // BLUE | INTENSITY
109 RGB(0, 255, 0), // GREEN | INTENSITY
110 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
111 RGB(255, 0, 0), // RED | INTENSITY
112 RGB(255, 0, 255), // BLUE | RED | INTENSITY
113 RGB(255, 255, 0), // GREEN | RED | INTENSITY
114 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
115 };
116
117 /* FUNCTIONS ******************************************************************/
118
119 static LRESULT CALLBACK
120 ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
121
122 BOOLEAN
123 RegisterConWndClass(IN HINSTANCE hInstance)
124 {
125 WNDCLASSEXW WndClass;
126 ATOM WndClassAtom;
127
128 ghDefaultIcon = LoadImageW(hInstance,
129 MAKEINTRESOURCEW(IDI_TERMINAL),
130 IMAGE_ICON,
131 GetSystemMetrics(SM_CXICON),
132 GetSystemMetrics(SM_CYICON),
133 LR_SHARED);
134 ghDefaultIconSm = LoadImageW(hInstance,
135 MAKEINTRESOURCEW(IDI_TERMINAL),
136 IMAGE_ICON,
137 GetSystemMetrics(SM_CXSMICON),
138 GetSystemMetrics(SM_CYSMICON),
139 LR_SHARED);
140 ghDefaultCursor = LoadCursorW(NULL, IDC_ARROW);
141
142 WndClass.cbSize = sizeof(WNDCLASSEXW);
143 WndClass.lpszClassName = GUI_CONWND_CLASS;
144 WndClass.lpfnWndProc = ConWndProc;
145 WndClass.style = CS_DBLCLKS /* | CS_HREDRAW | CS_VREDRAW */;
146 WndClass.hInstance = hInstance;
147 WndClass.hIcon = ghDefaultIcon;
148 WndClass.hIconSm = ghDefaultIconSm;
149 WndClass.hCursor = ghDefaultCursor;
150 WndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); // The color of a terminal when it is switched off.
151 WndClass.lpszMenuName = NULL;
152 WndClass.cbClsExtra = 0;
153 WndClass.cbWndExtra = GWLP_CONWND_ALLOC;
154
155 WndClassAtom = RegisterClassExW(&WndClass);
156 if (WndClassAtom == 0)
157 {
158 DPRINT1("Failed to register GUI console class\n");
159 }
160 else
161 {
162 NtUserConsoleControl(GuiConsoleWndClassAtom, &WndClassAtom, sizeof(ATOM));
163 }
164
165 return (WndClassAtom != 0);
166 }
167
168 BOOLEAN
169 UnRegisterConWndClass(HINSTANCE hInstance)
170 {
171 return !!UnregisterClassW(GUI_CONWND_CLASS, hInstance);
172 }
173
174
175
176 static VOID
177 GetScreenBufferSizeUnits(IN PCONSOLE_SCREEN_BUFFER Buffer,
178 IN PGUI_CONSOLE_DATA GuiData,
179 OUT PUINT WidthUnit,
180 OUT PUINT HeightUnit)
181 {
182 if (Buffer == NULL || GuiData == NULL ||
183 WidthUnit == NULL || HeightUnit == NULL)
184 {
185 return;
186 }
187
188 if (GetType(Buffer) == TEXTMODE_BUFFER)
189 {
190 *WidthUnit = GuiData->CharWidth ;
191 *HeightUnit = GuiData->CharHeight;
192 }
193 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
194 {
195 *WidthUnit = 1;
196 *HeightUnit = 1;
197 }
198 }
199
200 static VOID
201 AppendMenuItems(HMENU hMenu,
202 const GUICONSOLE_MENUITEM *Items)
203 {
204 UINT i = 0;
205 WCHAR szMenuString[255];
206 HMENU hSubMenu;
207
208 do
209 {
210 if (Items[i].uID != (UINT)-1)
211 {
212 if (LoadStringW(ConSrvDllInstance,
213 Items[i].uID,
214 szMenuString,
215 sizeof(szMenuString) / sizeof(szMenuString[0])) > 0)
216 {
217 if (Items[i].SubMenu != NULL)
218 {
219 hSubMenu = CreatePopupMenu();
220 if (hSubMenu != NULL)
221 {
222 AppendMenuItems(hSubMenu, Items[i].SubMenu);
223
224 if (!AppendMenuW(hMenu,
225 MF_STRING | MF_POPUP,
226 (UINT_PTR)hSubMenu,
227 szMenuString))
228 {
229 DestroyMenu(hSubMenu);
230 }
231 }
232 }
233 else
234 {
235 AppendMenuW(hMenu,
236 MF_STRING,
237 Items[i].wCmdID,
238 szMenuString);
239 }
240 }
241 }
242 else
243 {
244 AppendMenuW(hMenu,
245 MF_SEPARATOR,
246 0,
247 NULL);
248 }
249 i++;
250 } while (!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].wCmdID == 0));
251 }
252
253 //static
254 VOID
255 CreateSysMenu(HWND hWnd)
256 {
257 MENUITEMINFOW mii;
258 WCHAR szMenuStringBack[255];
259 WCHAR *ptrTab;
260 HMENU hMenu = GetSystemMenu(hWnd, FALSE);
261 if (hMenu != NULL)
262 {
263 mii.cbSize = sizeof(mii);
264 mii.fMask = MIIM_STRING;
265 mii.dwTypeData = szMenuStringBack;
266 mii.cch = sizeof(szMenuStringBack)/sizeof(WCHAR);
267
268 GetMenuItemInfoW(hMenu, SC_CLOSE, FALSE, &mii);
269
270 ptrTab = wcschr(szMenuStringBack, '\t');
271 if (ptrTab)
272 {
273 *ptrTab = '\0';
274 mii.cch = wcslen(szMenuStringBack);
275
276 SetMenuItemInfoW(hMenu, SC_CLOSE, FALSE, &mii);
277 }
278
279 AppendMenuItems(hMenu, GuiConsoleMainMenuItems);
280 DrawMenuBar(hWnd);
281 }
282 }
283
284 static VOID
285 SendMenuEvent(PCONSRV_CONSOLE Console, UINT CmdId)
286 {
287 INPUT_RECORD er;
288
289 DPRINT1("Menu item ID: %d\n", CmdId);
290
291 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
292
293 er.EventType = MENU_EVENT;
294 er.Event.MenuEvent.dwCommandId = CmdId;
295 ConioProcessInputEvent(Console, &er);
296
297 LeaveCriticalSection(&Console->Lock);
298 }
299
300 static VOID
301 Copy(PGUI_CONSOLE_DATA GuiData);
302 static VOID
303 Paste(PGUI_CONSOLE_DATA GuiData);
304 static VOID
305 UpdateSelection(PGUI_CONSOLE_DATA GuiData,
306 PCOORD SelectionAnchor OPTIONAL,
307 PCOORD coord);
308
309 static VOID
310 Mark(PGUI_CONSOLE_DATA GuiData)
311 {
312 PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
313
314 /* Clear the old selection */
315 GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
316
317 /* Restart a new selection */
318 GuiData->dwSelectionCursor = ActiveBuffer->ViewOrigin;
319 UpdateSelection(GuiData,
320 &GuiData->dwSelectionCursor,
321 &GuiData->dwSelectionCursor);
322 }
323
324 static VOID
325 SelectAll(PGUI_CONSOLE_DATA GuiData)
326 {
327 PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
328 COORD SelectionAnchor;
329
330 /* Clear the old selection */
331 GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
332
333 /*
334 * The selection area extends to the whole screen buffer's width.
335 */
336 SelectionAnchor.X = SelectionAnchor.Y = 0;
337 GuiData->dwSelectionCursor.X = ActiveBuffer->ScreenBufferSize.X - 1;
338
339 /*
340 * Determine whether the selection must extend to just some part
341 * (for text-mode screen buffers) or to all of the screen buffer's
342 * height (for graphics ones).
343 */
344 if (GetType(ActiveBuffer) == TEXTMODE_BUFFER)
345 {
346 /*
347 * We select all the characters from the first line
348 * to the line where the cursor is positioned.
349 */
350 GuiData->dwSelectionCursor.Y = ActiveBuffer->CursorPosition.Y;
351 }
352 else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
353 {
354 /*
355 * We select all the screen buffer area.
356 */
357 GuiData->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1;
358 }
359
360 /* Restart a new selection */
361 GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION;
362 UpdateSelection(GuiData, &SelectionAnchor, &GuiData->dwSelectionCursor);
363 }
364
365 static LRESULT
366 OnCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
367 {
368 LRESULT Ret = TRUE;
369 PCONSRV_CONSOLE Console = GuiData->Console;
370
371 /*
372 * In case the selected menu item belongs to the user-reserved menu id range,
373 * send to him a menu event and return directly. The user must handle those
374 * reserved menu commands...
375 */
376 if (GuiData->CmdIdLow <= (UINT)wParam && (UINT)wParam <= GuiData->CmdIdHigh)
377 {
378 SendMenuEvent(Console, (UINT)wParam);
379 goto Quit;
380 }
381
382 /* ... otherwise, perform actions. */
383 switch (wParam)
384 {
385 case ID_SYSTEM_EDIT_MARK:
386 Mark(GuiData);
387 break;
388
389 case ID_SYSTEM_EDIT_COPY:
390 Copy(GuiData);
391 break;
392
393 case ID_SYSTEM_EDIT_PASTE:
394 Paste(GuiData);
395 break;
396
397 case ID_SYSTEM_EDIT_SELECTALL:
398 SelectAll(GuiData);
399 break;
400
401 case ID_SYSTEM_EDIT_SCROLL:
402 DPRINT1("Scrolling is not handled yet\n");
403 break;
404
405 case ID_SYSTEM_EDIT_FIND:
406 DPRINT1("Finding is not handled yet\n");
407 break;
408
409 case ID_SYSTEM_DEFAULTS:
410 GuiConsoleShowConsoleProperties(GuiData, TRUE);
411 break;
412
413 case ID_SYSTEM_PROPERTIES:
414 GuiConsoleShowConsoleProperties(GuiData, FALSE);
415 break;
416
417 default:
418 Ret = FALSE;
419 break;
420 }
421
422 Quit:
423 if (!Ret)
424 Ret = DefWindowProcW(GuiData->hWindow, WM_SYSCOMMAND, wParam, lParam);
425
426 return Ret;
427 }
428
429 static PGUI_CONSOLE_DATA
430 GuiGetGuiData(HWND hWnd)
431 {
432 /* This function ensures that the console pointer is not NULL */
433 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
434 return ( ((GuiData == NULL) || (GuiData->hWindow == hWnd && GuiData->Console != NULL)) ? GuiData : NULL );
435 }
436
437 static VOID
438 ResizeConWnd(PGUI_CONSOLE_DATA GuiData, DWORD WidthUnit, DWORD HeightUnit)
439 {
440 PCONSOLE_SCREEN_BUFFER Buff = GuiData->ActiveBuffer;
441 SCROLLINFO sInfo;
442
443 DWORD Width, Height;
444
445 Width = Buff->ViewSize.X * WidthUnit +
446 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
447 Height = Buff->ViewSize.Y * HeightUnit +
448 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
449
450 /* Set scrollbar sizes */
451 sInfo.cbSize = sizeof(SCROLLINFO);
452 sInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
453 sInfo.nMin = 0;
454 if (Buff->ScreenBufferSize.Y > Buff->ViewSize.Y)
455 {
456 sInfo.nMax = Buff->ScreenBufferSize.Y - 1;
457 sInfo.nPage = Buff->ViewSize.Y;
458 sInfo.nPos = Buff->ViewOrigin.Y;
459 SetScrollInfo(GuiData->hWindow, SB_VERT, &sInfo, TRUE);
460 Width += GetSystemMetrics(SM_CXVSCROLL);
461 ShowScrollBar(GuiData->hWindow, SB_VERT, TRUE);
462 }
463 else
464 {
465 ShowScrollBar(GuiData->hWindow, SB_VERT, FALSE);
466 }
467
468 if (Buff->ScreenBufferSize.X > Buff->ViewSize.X)
469 {
470 sInfo.nMax = Buff->ScreenBufferSize.X - 1;
471 sInfo.nPage = Buff->ViewSize.X;
472 sInfo.nPos = Buff->ViewOrigin.X;
473 SetScrollInfo(GuiData->hWindow, SB_HORZ, &sInfo, TRUE);
474 Height += GetSystemMetrics(SM_CYHSCROLL);
475 ShowScrollBar(GuiData->hWindow, SB_HORZ, TRUE);
476 }
477 else
478 {
479 ShowScrollBar(GuiData->hWindow, SB_HORZ, FALSE);
480 }
481
482 /* Resize the window */
483 SetWindowPos(GuiData->hWindow, NULL, 0, 0, Width, Height,
484 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOCOPYBITS);
485 // NOTE: The SWP_NOCOPYBITS flag can be replaced by a subsequent call
486 // to: InvalidateRect(GuiData->hWindow, NULL, TRUE);
487 }
488
489
490 VOID
491 DeleteFonts(PGUI_CONSOLE_DATA GuiData)
492 {
493 ULONG i;
494 for (i = 0; i < sizeof(GuiData->Font) / sizeof(GuiData->Font[0]); ++i)
495 {
496 if (GuiData->Font[i] != NULL) DeleteObject(GuiData->Font[i]);
497 GuiData->Font[i] = NULL;
498 }
499 }
500
501 static HFONT
502 CreateDerivedFont(HFONT OrgFont,
503 // COORD FontSize,
504 ULONG FontWeight,
505 // BOOLEAN bItalic,
506 BOOLEAN bUnderline,
507 BOOLEAN bStrikeOut)
508 {
509 LOGFONT lf;
510
511 /* Initialize the LOGFONT structure */
512 RtlZeroMemory(&lf, sizeof(lf));
513
514 /* Retrieve the details of the current font */
515 if (GetObject(OrgFont, sizeof(lf), &lf) == 0)
516 return NULL;
517
518 /* Change the font attributes */
519 // lf.lfHeight = FontSize.Y;
520 // lf.lfWidth = FontSize.X;
521 lf.lfWeight = FontWeight;
522 // lf.lfItalic = bItalic;
523 lf.lfUnderline = bUnderline;
524 lf.lfStrikeOut = bStrikeOut;
525
526 /* Build a new font */
527 return CreateFontIndirect(&lf);
528 }
529
530 BOOL
531 InitFonts(PGUI_CONSOLE_DATA GuiData,
532 LPWSTR FaceName, // Points to a WCHAR array of LF_FACESIZE elements.
533 ULONG FontFamily,
534 COORD FontSize,
535 ULONG FontWeight)
536 {
537 HDC hDC;
538 HFONT OldFont, NewFont;
539 TEXTMETRICW Metrics;
540 SIZE CharSize;
541
542 hDC = GetDC(GuiData->hWindow);
543
544 /*
545 * Initialize a new NORMAL font and get its metrics.
546 */
547
548 FontSize.Y = FontSize.Y > 0 ? -MulDiv(FontSize.Y, GetDeviceCaps(hDC, LOGPIXELSY), 72)
549 : FontSize.Y;
550
551 NewFont = CreateFontW(FontSize.Y,
552 FontSize.X,
553 0,
554 TA_BASELINE,
555 FontWeight,
556 FALSE,
557 FALSE,
558 FALSE,
559 OEM_CHARSET,
560 OUT_DEFAULT_PRECIS,
561 CLIP_DEFAULT_PRECIS,
562 DEFAULT_QUALITY,
563 FIXED_PITCH | FontFamily,
564 FaceName);
565 if (NewFont == NULL)
566 {
567 DPRINT1("InitFonts: CreateFontW failed\n");
568 ReleaseDC(GuiData->hWindow, hDC);
569 return FALSE;
570 }
571
572 OldFont = SelectObject(hDC, NewFont);
573 if (OldFont == NULL)
574 {
575 DPRINT1("InitFonts: SelectObject failed\n");
576 ReleaseDC(GuiData->hWindow, hDC);
577 DeleteObject(NewFont);
578 return FALSE;
579 }
580
581 if (!GetTextMetricsW(hDC, &Metrics))
582 {
583 DPRINT1("InitFonts: GetTextMetrics failed\n");
584 SelectObject(hDC, OldFont);
585 ReleaseDC(GuiData->hWindow, hDC);
586 DeleteObject(NewFont);
587 return FALSE;
588 }
589 GuiData->CharWidth = Metrics.tmMaxCharWidth;
590 GuiData->CharHeight = Metrics.tmHeight + Metrics.tmExternalLeading;
591
592 /* Measure real char width more precisely if possible */
593 if (GetTextExtentPoint32W(hDC, L"R", 1, &CharSize))
594 GuiData->CharWidth = CharSize.cx;
595
596 SelectObject(hDC, OldFont);
597 ReleaseDC(GuiData->hWindow, hDC);
598
599 /*
600 * Initialization succeeded.
601 */
602 // Delete all the old fonts first.
603 DeleteFonts(GuiData);
604 GuiData->Font[FONT_NORMAL] = NewFont;
605
606 /*
607 * Now build the other fonts (bold, underlined, mixed).
608 */
609 GuiData->Font[FONT_BOLD] =
610 CreateDerivedFont(GuiData->Font[FONT_NORMAL],
611 FontWeight < FW_BOLD ? FW_BOLD : FontWeight,
612 FALSE,
613 FALSE);
614 GuiData->Font[FONT_UNDERLINE] =
615 CreateDerivedFont(GuiData->Font[FONT_NORMAL],
616 FontWeight,
617 TRUE,
618 FALSE);
619 GuiData->Font[FONT_BOLD | FONT_UNDERLINE] =
620 CreateDerivedFont(GuiData->Font[FONT_NORMAL],
621 FontWeight < FW_BOLD ? FW_BOLD : FontWeight,
622 TRUE,
623 FALSE);
624
625 /*
626 * Save the settings.
627 */
628 if (FaceName != GuiData->GuiInfo.FaceName)
629 {
630 SIZE_T Length = min(wcslen(FaceName) + 1, LF_FACESIZE); // wcsnlen
631 wcsncpy(GuiData->GuiInfo.FaceName, FaceName, LF_FACESIZE);
632 GuiData->GuiInfo.FaceName[Length] = L'\0'; // NULL-terminate
633 }
634 GuiData->GuiInfo.FontFamily = FontFamily;
635 GuiData->GuiInfo.FontSize = FontSize;
636 GuiData->GuiInfo.FontWeight = FontWeight;
637
638 return TRUE;
639 }
640
641
642 static BOOL
643 OnNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
644 {
645 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)Create->lpCreateParams;
646 PCONSRV_CONSOLE Console;
647
648 if (NULL == GuiData)
649 {
650 DPRINT1("GuiConsoleNcCreate: No GUI data\n");
651 return FALSE;
652 }
653
654 Console = GuiData->Console;
655
656 GuiData->hWindow = hWnd;
657
658 /* Initialize the fonts */
659 if (!InitFonts(GuiData,
660 GuiData->GuiInfo.FaceName,
661 GuiData->GuiInfo.FontFamily,
662 GuiData->GuiInfo.FontSize,
663 GuiData->GuiInfo.FontWeight))
664 {
665 DPRINT1("GuiConsoleNcCreate: InitFonts failed\n");
666 GuiData->hWindow = NULL;
667 SetEvent(GuiData->hGuiInitEvent);
668 return FALSE;
669 }
670
671 /* Initialize the terminal framebuffer */
672 GuiData->hMemDC = CreateCompatibleDC(NULL);
673 GuiData->hBitmap = NULL;
674 GuiData->hSysPalette = NULL; /* Original system palette */
675
676 /* Update the icons of the window */
677 if (GuiData->hIcon != ghDefaultIcon)
678 {
679 DefWindowProcW(GuiData->hWindow, WM_SETICON, ICON_BIG , (LPARAM)GuiData->hIcon );
680 DefWindowProcW(GuiData->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)GuiData->hIconSm);
681 }
682
683 // FIXME: Keep these instructions here ? ///////////////////////////////////
684 Console->ActiveBuffer->CursorBlinkOn = TRUE;
685 Console->ActiveBuffer->ForceCursorOff = FALSE;
686 ////////////////////////////////////////////////////////////////////////////
687
688 SetWindowLongPtrW(GuiData->hWindow, GWLP_USERDATA, (DWORD_PTR)GuiData);
689
690 SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
691 // FIXME: HACK: Potential HACK for CORE-8129; see revision 63595.
692 //CreateSysMenu(GuiData->hWindow);
693
694 DPRINT("OnNcCreate - setting start event\n");
695 SetEvent(GuiData->hGuiInitEvent);
696
697 return (BOOL)DefWindowProcW(GuiData->hWindow, WM_NCCREATE, 0, (LPARAM)Create);
698 }
699
700
701 BOOL
702 EnterFullScreen(PGUI_CONSOLE_DATA GuiData);
703 VOID
704 LeaveFullScreen(PGUI_CONSOLE_DATA GuiData);
705 VOID
706 SwitchFullScreen(PGUI_CONSOLE_DATA GuiData, BOOL FullScreen);
707 VOID
708 GuiConsoleSwitchFullScreen(PGUI_CONSOLE_DATA GuiData);
709
710 static VOID
711 OnActivate(PGUI_CONSOLE_DATA GuiData, WPARAM wParam)
712 {
713 WORD ActivationState = LOWORD(wParam);
714
715 DPRINT1("WM_ACTIVATE - ActivationState = %d\n");
716
717 if ( ActivationState == WA_ACTIVE ||
718 ActivationState == WA_CLICKACTIVE )
719 {
720 if (GuiData->GuiInfo.FullScreen)
721 {
722 EnterFullScreen(GuiData);
723 // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
724 // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
725 }
726 }
727 else // if (ActivationState == WA_INACTIVE)
728 {
729 if (GuiData->GuiInfo.FullScreen)
730 {
731 SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
732 LeaveFullScreen(GuiData);
733 // // PostMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
734 // SendMessageW(GuiData->hWindow, WM_SYSCOMMAND, SC_MINIMIZE, 0);
735 }
736 }
737
738 /*
739 * Ignore the next mouse signal when we are going to be enabled again via
740 * the mouse, in order to prevent, e.g. when we are in Edit mode, erroneous
741 * mouse actions from the user that could spoil text selection or copy/pastes.
742 */
743 if (ActivationState == WA_CLICKACTIVE)
744 GuiData->IgnoreNextMouseSignal = TRUE;
745 }
746
747 static VOID
748 OnFocus(PGUI_CONSOLE_DATA GuiData, BOOL SetFocus)
749 {
750 PCONSRV_CONSOLE Console = GuiData->Console;
751 INPUT_RECORD er;
752
753 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
754
755 er.EventType = FOCUS_EVENT;
756 er.Event.FocusEvent.bSetFocus = SetFocus;
757 ConioProcessInputEvent(Console, &er);
758
759 LeaveCriticalSection(&Console->Lock);
760
761 if (SetFocus)
762 DPRINT1("TODO: Create console caret\n");
763 else
764 DPRINT1("TODO: Destroy console caret\n");
765 }
766
767 static VOID
768 SmallRectToRect(PGUI_CONSOLE_DATA GuiData, PRECT Rect, PSMALL_RECT SmallRect)
769 {
770 PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer;
771 UINT WidthUnit, HeightUnit;
772
773 GetScreenBufferSizeUnits(Buffer, GuiData, &WidthUnit, &HeightUnit);
774
775 Rect->left = (SmallRect->Left - Buffer->ViewOrigin.X) * WidthUnit ;
776 Rect->top = (SmallRect->Top - Buffer->ViewOrigin.Y) * HeightUnit;
777 Rect->right = (SmallRect->Right + 1 - Buffer->ViewOrigin.X) * WidthUnit ;
778 Rect->bottom = (SmallRect->Bottom + 1 - Buffer->ViewOrigin.Y) * HeightUnit;
779 }
780
781 VOID
782 GetSelectionBeginEnd(PCOORD Begin, PCOORD End,
783 PCOORD SelectionAnchor,
784 PSMALL_RECT SmallRect)
785 {
786 if (Begin == NULL || End == NULL) return;
787
788 *Begin = *SelectionAnchor;
789 End->X = (SelectionAnchor->X == SmallRect->Left) ? SmallRect->Right
790 /* Case X != Left, must be == Right */ : SmallRect->Left;
791 End->Y = (SelectionAnchor->Y == SmallRect->Top ) ? SmallRect->Bottom
792 /* Case Y != Top, must be == Bottom */ : SmallRect->Top;
793
794 /* Exchange Begin / End if Begin > End lexicographically */
795 if (Begin->Y > End->Y || (Begin->Y == End->Y && Begin->X > End->X))
796 {
797 End->X = _InterlockedExchange16(&Begin->X, End->X);
798 End->Y = _InterlockedExchange16(&Begin->Y, End->Y);
799 }
800 }
801
802 static HRGN
803 CreateSelectionRgn(PGUI_CONSOLE_DATA GuiData,
804 BOOL LineSelection,
805 PCOORD SelectionAnchor,
806 PSMALL_RECT SmallRect)
807 {
808 if (!LineSelection)
809 {
810 RECT rect;
811 SmallRectToRect(GuiData, &rect, SmallRect);
812 return CreateRectRgnIndirect(&rect);
813 }
814 else
815 {
816 HRGN SelRgn;
817 COORD Begin, End;
818
819 GetSelectionBeginEnd(&Begin, &End, SelectionAnchor, SmallRect);
820
821 if (Begin.Y == End.Y)
822 {
823 SMALL_RECT sr;
824 RECT r ;
825
826 sr.Left = Begin.X;
827 sr.Top = Begin.Y;
828 sr.Right = End.X;
829 sr.Bottom = End.Y;
830
831 // Debug thingie to see whether I can put this corner case
832 // together with the previous one.
833 if (SmallRect->Left != sr.Left ||
834 SmallRect->Top != sr.Top ||
835 SmallRect->Right != sr.Right ||
836 SmallRect->Bottom != sr.Bottom)
837 {
838 DPRINT1("\n"
839 "SmallRect = (%d, %d, %d, %d)\n"
840 "sr = (%d, %d, %d, %d)\n"
841 "\n",
842 SmallRect->Left, SmallRect->Top, SmallRect->Right, SmallRect->Bottom,
843 sr.Left, sr.Top, sr.Right, sr.Bottom);
844 }
845
846 SmallRectToRect(GuiData, &r, &sr);
847 SelRgn = CreateRectRgnIndirect(&r);
848 }
849 else
850 {
851 PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
852
853 HRGN rg1, rg2, rg3;
854 SMALL_RECT sr1, sr2, sr3;
855 RECT r1 , r2 , r3 ;
856
857 sr1.Left = Begin.X;
858 sr1.Top = Begin.Y;
859 sr1.Right = ActiveBuffer->ScreenBufferSize.X - 1;
860 sr1.Bottom = Begin.Y;
861
862 sr2.Left = 0;
863 sr2.Top = Begin.Y + 1;
864 sr2.Right = ActiveBuffer->ScreenBufferSize.X - 1;
865 sr2.Bottom = End.Y - 1;
866
867 sr3.Left = 0;
868 sr3.Top = End.Y;
869 sr3.Right = End.X;
870 sr3.Bottom = End.Y;
871
872 SmallRectToRect(GuiData, &r1, &sr1);
873 SmallRectToRect(GuiData, &r2, &sr2);
874 SmallRectToRect(GuiData, &r3, &sr3);
875
876 rg1 = CreateRectRgnIndirect(&r1);
877 rg2 = CreateRectRgnIndirect(&r2);
878 rg3 = CreateRectRgnIndirect(&r3);
879
880 CombineRgn(rg1, rg1, rg2, RGN_XOR);
881 CombineRgn(rg1, rg1, rg3, RGN_XOR);
882 DeleteObject(rg3);
883 DeleteObject(rg2);
884
885 SelRgn = rg1;
886 }
887
888 return SelRgn;
889 }
890 }
891
892 static VOID
893 PaintSelectionRect(PGUI_CONSOLE_DATA GuiData, PPAINTSTRUCT pps)
894 {
895 HRGN rgnPaint = CreateRectRgnIndirect(&pps->rcPaint);
896 HRGN rgnSel = CreateSelectionRgn(GuiData, GuiData->LineSelection,
897 &GuiData->Selection.dwSelectionAnchor,
898 &GuiData->Selection.srSelection);
899
900 /* Invert the selection */
901
902 int ErrorCode = CombineRgn(rgnPaint, rgnPaint, rgnSel, RGN_AND);
903 if (ErrorCode != ERROR && ErrorCode != NULLREGION)
904 {
905 InvertRgn(pps->hdc, rgnPaint);
906 }
907
908 DeleteObject(rgnSel);
909 DeleteObject(rgnPaint);
910 }
911
912 static VOID
913 UpdateSelection(PGUI_CONSOLE_DATA GuiData,
914 PCOORD SelectionAnchor OPTIONAL,
915 PCOORD coord)
916 {
917 PCONSRV_CONSOLE Console = GuiData->Console;
918 HRGN oldRgn = CreateSelectionRgn(GuiData, GuiData->LineSelection,
919 &GuiData->Selection.dwSelectionAnchor,
920 &GuiData->Selection.srSelection);
921
922 /* Update the anchor if needed (use the old one if NULL) */
923 if (SelectionAnchor)
924 GuiData->Selection.dwSelectionAnchor = *SelectionAnchor;
925
926 if (coord != NULL)
927 {
928 SMALL_RECT rc;
929 HRGN newRgn;
930
931 /*
932 * Pressing the Control key while selecting text, allows us to enter
933 * into line-selection mode, the selection mode of *nix terminals.
934 */
935 BOOL OldLineSel = GuiData->LineSelection;
936 GuiData->LineSelection = !!(GetKeyState(VK_CONTROL) & 0x8000);
937
938 /* Exchange left/top with right/bottom if required */
939 rc.Left = min(GuiData->Selection.dwSelectionAnchor.X, coord->X);
940 rc.Top = min(GuiData->Selection.dwSelectionAnchor.Y, coord->Y);
941 rc.Right = max(GuiData->Selection.dwSelectionAnchor.X, coord->X);
942 rc.Bottom = max(GuiData->Selection.dwSelectionAnchor.Y, coord->Y);
943
944 newRgn = CreateSelectionRgn(GuiData, GuiData->LineSelection,
945 &GuiData->Selection.dwSelectionAnchor,
946 &rc);
947
948 if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
949 {
950 if (OldLineSel != GuiData->LineSelection ||
951 memcmp(&rc, &GuiData->Selection.srSelection, sizeof(SMALL_RECT)) != 0)
952 {
953 /* Calculate the region that needs to be updated */
954 if (oldRgn && newRgn && CombineRgn(newRgn, newRgn, oldRgn, RGN_XOR) != ERROR)
955 {
956 InvalidateRgn(GuiData->hWindow, newRgn, FALSE);
957 }
958 }
959 }
960 else
961 {
962 InvalidateRgn(GuiData->hWindow, newRgn, FALSE);
963 }
964
965 DeleteObject(newRgn);
966
967 GuiData->Selection.dwFlags |= CONSOLE_SELECTION_NOT_EMPTY;
968 GuiData->Selection.srSelection = rc;
969 GuiData->dwSelectionCursor = *coord;
970
971 if ((GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) == 0)
972 {
973 LPWSTR SelTypeStr = NULL , WindowTitle = NULL;
974 SIZE_T SelTypeStrLength = 0, Length = 0;
975
976 /* Clear the old selection */
977 if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
978 {
979 InvalidateRgn(GuiData->hWindow, oldRgn, FALSE);
980 }
981
982 /*
983 * When passing a zero-length buffer size, LoadString(...) returns
984 * a read-only pointer buffer to the program's resource string.
985 */
986 SelTypeStrLength =
987 LoadStringW(ConSrvDllInstance,
988 (GuiData->Selection.dwFlags & CONSOLE_MOUSE_SELECTION)
989 ? IDS_SELECT_TITLE : IDS_MARK_TITLE,
990 (LPWSTR)&SelTypeStr, 0);
991
992 /*
993 * Prepend the selection type string to the current console title
994 * if we succeeded in retrieving a valid localized string.
995 */
996 if (SelTypeStr)
997 {
998 // 3 for " - " and 1 for NULL
999 Length = Console->Title.Length + (SelTypeStrLength + 3 + 1) * sizeof(WCHAR);
1000 WindowTitle = ConsoleAllocHeap(0, Length);
1001
1002 wcsncpy(WindowTitle, SelTypeStr, SelTypeStrLength);
1003 WindowTitle[SelTypeStrLength] = L'\0';
1004 wcscat(WindowTitle, L" - ");
1005 wcscat(WindowTitle, Console->Title.Buffer);
1006
1007 SetWindowText(GuiData->hWindow, WindowTitle);
1008 ConsoleFreeHeap(WindowTitle);
1009 }
1010
1011 GuiData->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS;
1012 ConioPause(Console, PAUSED_FROM_SELECTION);
1013 }
1014 }
1015 else
1016 {
1017 /* Clear the selection */
1018 if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
1019 {
1020 InvalidateRgn(GuiData->hWindow, oldRgn, FALSE);
1021 }
1022
1023 GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
1024 ConioUnpause(Console, PAUSED_FROM_SELECTION);
1025
1026 /* Restore the console title */
1027 SetWindowText(GuiData->hWindow, Console->Title.Buffer);
1028 }
1029
1030 DeleteObject(oldRgn);
1031 }
1032
1033
1034 VOID
1035 GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
1036 PGUI_CONSOLE_DATA GuiData,
1037 PRECT rcView,
1038 PRECT rcFramebuffer);
1039 VOID
1040 GuiPaintGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer,
1041 PGUI_CONSOLE_DATA GuiData,
1042 PRECT rcView,
1043 PRECT rcFramebuffer);
1044
1045 static VOID
1046 OnPaint(PGUI_CONSOLE_DATA GuiData)
1047 {
1048 PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
1049 PAINTSTRUCT ps;
1050 RECT rcPaint;
1051
1052 BeginPaint(GuiData->hWindow, &ps);
1053 if (ps.hdc != NULL &&
1054 ps.rcPaint.left < ps.rcPaint.right &&
1055 ps.rcPaint.top < ps.rcPaint.bottom)
1056 {
1057 EnterCriticalSection(&GuiData->Lock);
1058
1059 /* Compose the current screen-buffer on-memory */
1060 if (GetType(ActiveBuffer) == TEXTMODE_BUFFER)
1061 {
1062 GuiPaintTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)ActiveBuffer,
1063 GuiData, &ps.rcPaint, &rcPaint);
1064 }
1065 else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */
1066 {
1067 GuiPaintGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)ActiveBuffer,
1068 GuiData, &ps.rcPaint, &rcPaint);
1069 }
1070
1071 /* Send it to screen */
1072 BitBlt(ps.hdc,
1073 ps.rcPaint.left,
1074 ps.rcPaint.top,
1075 rcPaint.right - rcPaint.left,
1076 rcPaint.bottom - rcPaint.top,
1077 GuiData->hMemDC,
1078 rcPaint.left,
1079 rcPaint.top,
1080 SRCCOPY);
1081
1082 /* Draw the selection region if needed */
1083 if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
1084 {
1085 PaintSelectionRect(GuiData, &ps);
1086 }
1087
1088 LeaveCriticalSection(&GuiData->Lock);
1089 }
1090 EndPaint(GuiData->hWindow, &ps);
1091
1092 return;
1093 }
1094
1095 static VOID
1096 OnPaletteChanged(PGUI_CONSOLE_DATA GuiData)
1097 {
1098 PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
1099
1100 // See WM_PALETTECHANGED message
1101 // if ((HWND)wParam == hWnd) break;
1102
1103 // if (GetType(ActiveBuffer) == GRAPHICS_BUFFER)
1104 if (ActiveBuffer->PaletteHandle)
1105 {
1106 DPRINT("WM_PALETTECHANGED changing palette\n");
1107
1108 /* Specify the use of the system palette for the framebuffer */
1109 SetSystemPaletteUse(GuiData->hMemDC, ActiveBuffer->PaletteUsage);
1110
1111 /* Realize the (logical) palette */
1112 RealizePalette(GuiData->hMemDC);
1113 }
1114 }
1115
1116 static BOOL
1117 IsSystemKey(WORD VirtualKeyCode)
1118 {
1119 switch (VirtualKeyCode)
1120 {
1121 /* From MSDN, "Virtual-Key Codes" */
1122 case VK_RETURN:
1123 case VK_SHIFT:
1124 case VK_CONTROL:
1125 case VK_MENU:
1126 case VK_PAUSE:
1127 case VK_CAPITAL:
1128 case VK_ESCAPE:
1129 case VK_LWIN:
1130 case VK_RWIN:
1131 case VK_NUMLOCK:
1132 case VK_SCROLL:
1133 return TRUE;
1134 default:
1135 return FALSE;
1136 }
1137 }
1138
1139 static VOID
1140 OnKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
1141 {
1142 PCONSRV_CONSOLE Console = GuiData->Console;
1143 PCONSOLE_SCREEN_BUFFER ActiveBuffer;
1144
1145 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
1146
1147 ActiveBuffer = GuiData->ActiveBuffer;
1148
1149 if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS)
1150 {
1151 WORD VirtualKeyCode = LOWORD(wParam);
1152
1153 if (msg != WM_KEYDOWN) goto Quit;
1154
1155 if (VirtualKeyCode == VK_RETURN)
1156 {
1157 /* Copy (and clear) selection if ENTER is pressed */
1158 Copy(GuiData);
1159 goto Quit;
1160 }
1161 else if ( VirtualKeyCode == VK_ESCAPE ||
1162 (VirtualKeyCode == 'C' && (GetKeyState(VK_CONTROL) & 0x8000)) )
1163 {
1164 /* Cancel selection if ESC or Ctrl-C are pressed */
1165 UpdateSelection(GuiData, NULL, NULL);
1166 goto Quit;
1167 }
1168
1169 if ((GuiData->Selection.dwFlags & CONSOLE_MOUSE_SELECTION) == 0)
1170 {
1171 /* Keyboard selection mode */
1172 BOOL Interpreted = FALSE;
1173 BOOL MajPressed = !!(GetKeyState(VK_SHIFT) & 0x8000);
1174
1175 switch (VirtualKeyCode)
1176 {
1177 case VK_LEFT:
1178 {
1179 Interpreted = TRUE;
1180 if (GuiData->dwSelectionCursor.X > 0)
1181 GuiData->dwSelectionCursor.X--;
1182
1183 break;
1184 }
1185
1186 case VK_RIGHT:
1187 {
1188 Interpreted = TRUE;
1189 if (GuiData->dwSelectionCursor.X < ActiveBuffer->ScreenBufferSize.X - 1)
1190 GuiData->dwSelectionCursor.X++;
1191
1192 break;
1193 }
1194
1195 case VK_UP:
1196 {
1197 Interpreted = TRUE;
1198 if (GuiData->dwSelectionCursor.Y > 0)
1199 GuiData->dwSelectionCursor.Y--;
1200
1201 break;
1202 }
1203
1204 case VK_DOWN:
1205 {
1206 Interpreted = TRUE;
1207 if (GuiData->dwSelectionCursor.Y < ActiveBuffer->ScreenBufferSize.Y - 1)
1208 GuiData->dwSelectionCursor.Y++;
1209
1210 break;
1211 }
1212
1213 case VK_HOME:
1214 {
1215 Interpreted = TRUE;
1216 GuiData->dwSelectionCursor.X = 0;
1217 GuiData->dwSelectionCursor.Y = 0;
1218 break;
1219 }
1220
1221 case VK_END:
1222 {
1223 Interpreted = TRUE;
1224 GuiData->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1;
1225 break;
1226 }
1227
1228 case VK_PRIOR:
1229 {
1230 Interpreted = TRUE;
1231 GuiData->dwSelectionCursor.Y -= ActiveBuffer->ViewSize.Y;
1232 if (GuiData->dwSelectionCursor.Y < 0)
1233 GuiData->dwSelectionCursor.Y = 0;
1234
1235 break;
1236 }
1237
1238 case VK_NEXT:
1239 {
1240 Interpreted = TRUE;
1241 GuiData->dwSelectionCursor.Y += ActiveBuffer->ViewSize.Y;
1242 if (GuiData->dwSelectionCursor.Y >= ActiveBuffer->ScreenBufferSize.Y)
1243 GuiData->dwSelectionCursor.Y = ActiveBuffer->ScreenBufferSize.Y - 1;
1244
1245 break;
1246 }
1247
1248 default:
1249 break;
1250 }
1251
1252 if (Interpreted)
1253 {
1254 UpdateSelection(GuiData,
1255 !MajPressed ? &GuiData->dwSelectionCursor : NULL,
1256 &GuiData->dwSelectionCursor);
1257 }
1258 else if (!IsSystemKey(VirtualKeyCode))
1259 {
1260 /* Emit an error beep sound */
1261 SendNotifyMessage(GuiData->hWindow, PM_CONSOLE_BEEP, 0, 0);
1262 }
1263
1264 goto Quit;
1265 }
1266 else
1267 {
1268 /* Mouse selection mode */
1269
1270 if (!IsSystemKey(VirtualKeyCode))
1271 {
1272 /* Clear the selection and send the key into the input buffer */
1273 UpdateSelection(GuiData, NULL, NULL);
1274 }
1275 else
1276 {
1277 goto Quit;
1278 }
1279 }
1280 }
1281
1282 if ((GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) == 0)
1283 {
1284 MSG Message;
1285
1286 Message.hwnd = GuiData->hWindow;
1287 Message.message = msg;
1288 Message.wParam = wParam;
1289 Message.lParam = lParam;
1290
1291 ConioProcessKey(Console, &Message);
1292 }
1293
1294 Quit:
1295 LeaveCriticalSection(&Console->Lock);
1296 }
1297
1298
1299 // FIXME: Remove after fixing OnTimer
1300 VOID
1301 InvalidateCell(PGUI_CONSOLE_DATA GuiData,
1302 SHORT x, SHORT y);
1303
1304 static VOID
1305 OnTimer(PGUI_CONSOLE_DATA GuiData)
1306 {
1307 PCONSRV_CONSOLE Console = GuiData->Console;
1308 PCONSOLE_SCREEN_BUFFER Buff;
1309
1310 SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CURSOR_BLINK_TIME, NULL);
1311
1312 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
1313
1314 Buff = GuiData->ActiveBuffer;
1315
1316 if (GetType(Buff) == TEXTMODE_BUFFER)
1317 {
1318 InvalidateCell(GuiData, Buff->CursorPosition.X, Buff->CursorPosition.Y);
1319 Buff->CursorBlinkOn = !Buff->CursorBlinkOn;
1320
1321 if ((GuiData->OldCursor.x != Buff->CursorPosition.X) ||
1322 (GuiData->OldCursor.y != Buff->CursorPosition.Y))
1323 {
1324 SCROLLINFO xScroll;
1325 int OldScrollX = -1, OldScrollY = -1;
1326 int NewScrollX = -1, NewScrollY = -1;
1327
1328 xScroll.cbSize = sizeof(SCROLLINFO);
1329 xScroll.fMask = SIF_POS;
1330 // Capture the original position of the scroll bars and save them.
1331 if (GetScrollInfo(GuiData->hWindow, SB_HORZ, &xScroll)) OldScrollX = xScroll.nPos;
1332 if (GetScrollInfo(GuiData->hWindow, SB_VERT, &xScroll)) OldScrollY = xScroll.nPos;
1333
1334 // If we successfully got the info for the horizontal scrollbar
1335 if (OldScrollX >= 0)
1336 {
1337 if ((Buff->CursorPosition.X < Buff->ViewOrigin.X) ||
1338 (Buff->CursorPosition.X >= (Buff->ViewOrigin.X + Buff->ViewSize.X)))
1339 {
1340 // Handle the horizontal scroll bar
1341 if (Buff->CursorPosition.X >= Buff->ViewSize.X)
1342 NewScrollX = Buff->CursorPosition.X - Buff->ViewSize.X + 1;
1343 else
1344 NewScrollX = 0;
1345 }
1346 else
1347 {
1348 NewScrollX = OldScrollX;
1349 }
1350 }
1351 // If we successfully got the info for the vertical scrollbar
1352 if (OldScrollY >= 0)
1353 {
1354 if ((Buff->CursorPosition.Y < Buff->ViewOrigin.Y) ||
1355 (Buff->CursorPosition.Y >= (Buff->ViewOrigin.Y + Buff->ViewSize.Y)))
1356 {
1357 // Handle the vertical scroll bar
1358 if (Buff->CursorPosition.Y >= Buff->ViewSize.Y)
1359 NewScrollY = Buff->CursorPosition.Y - Buff->ViewSize.Y + 1;
1360 else
1361 NewScrollY = 0;
1362 }
1363 else
1364 {
1365 NewScrollY = OldScrollY;
1366 }
1367 }
1368
1369 // Adjust scroll bars and refresh the window if the cursor has moved outside the visible area
1370 // NOTE: OldScroll# and NewScroll# will both be -1 (initial value) if the info for the respective scrollbar
1371 // was not obtained successfully in the previous steps. This means their difference is 0 (no scrolling)
1372 // and their associated scrollbar is left alone.
1373 if ((OldScrollX != NewScrollX) || (OldScrollY != NewScrollY))
1374 {
1375 Buff->ViewOrigin.X = NewScrollX;
1376 Buff->ViewOrigin.Y = NewScrollY;
1377 ScrollWindowEx(GuiData->hWindow,
1378 (OldScrollX - NewScrollX) * GuiData->CharWidth,
1379 (OldScrollY - NewScrollY) * GuiData->CharHeight,
1380 NULL,
1381 NULL,
1382 NULL,
1383 NULL,
1384 SW_INVALIDATE);
1385 if (NewScrollX >= 0)
1386 {
1387 xScroll.nPos = NewScrollX;
1388 SetScrollInfo(GuiData->hWindow, SB_HORZ, &xScroll, TRUE);
1389 }
1390 if (NewScrollY >= 0)
1391 {
1392 xScroll.nPos = NewScrollY;
1393 SetScrollInfo(GuiData->hWindow, SB_VERT, &xScroll, TRUE);
1394 }
1395 UpdateWindow(GuiData->hWindow);
1396 // InvalidateRect(GuiData->hWindow, NULL, FALSE);
1397 GuiData->OldCursor.x = Buff->CursorPosition.X;
1398 GuiData->OldCursor.y = Buff->CursorPosition.Y;
1399 }
1400 }
1401 }
1402 else /* if (GetType(Buff) == GRAPHICS_BUFFER) */
1403 {
1404 }
1405
1406 LeaveCriticalSection(&Console->Lock);
1407 }
1408
1409 static BOOL
1410 OnClose(PGUI_CONSOLE_DATA GuiData)
1411 {
1412 PCONSRV_CONSOLE Console = GuiData->Console;
1413
1414 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
1415 return TRUE;
1416
1417 // TODO: Prompt for termination ? (Warn the user about possible apps running in this console)
1418
1419 /*
1420 * FIXME: Windows will wait up to 5 seconds for the thread to exit.
1421 * We shouldn't wait here, though, since the console lock is entered.
1422 * A copy of the thread list probably needs to be made.
1423 */
1424 ConSrvConsoleProcessCtrlEvent(Console, 0, CTRL_CLOSE_EVENT);
1425
1426 LeaveCriticalSection(&Console->Lock);
1427 return FALSE;
1428 }
1429
1430 static LRESULT
1431 OnNcDestroy(HWND hWnd)
1432 {
1433 PGUI_CONSOLE_DATA GuiData = GuiGetGuiData(hWnd);
1434
1435 KillTimer(hWnd, CONGUI_UPDATE_TIMER);
1436 GetSystemMenu(hWnd, TRUE);
1437
1438 if (GuiData)
1439 {
1440 /* Free the terminal framebuffer */
1441 if (GuiData->hMemDC ) DeleteDC(GuiData->hMemDC);
1442 if (GuiData->hBitmap) DeleteObject(GuiData->hBitmap);
1443 // if (GuiData->hSysPalette) DeleteObject(GuiData->hSysPalette);
1444 DeleteFonts(GuiData);
1445 }
1446
1447 /* Free the GuiData registration */
1448 SetWindowLongPtrW(hWnd, GWLP_USERDATA, (DWORD_PTR)NULL);
1449
1450 return DefWindowProcW(hWnd, WM_NCDESTROY, 0, 0);
1451 }
1452
1453 static COORD
1454 PointToCoord(PGUI_CONSOLE_DATA GuiData, LPARAM lParam)
1455 {
1456 PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer;
1457 COORD Coord;
1458 UINT WidthUnit, HeightUnit;
1459
1460 GetScreenBufferSizeUnits(Buffer, GuiData, &WidthUnit, &HeightUnit);
1461
1462 Coord.X = Buffer->ViewOrigin.X + ((SHORT)LOWORD(lParam) / (int)WidthUnit );
1463 Coord.Y = Buffer->ViewOrigin.Y + ((SHORT)HIWORD(lParam) / (int)HeightUnit);
1464
1465 /* Clip coordinate to ensure it's inside buffer */
1466 if (Coord.X < 0)
1467 Coord.X = 0;
1468 else if (Coord.X >= Buffer->ScreenBufferSize.X)
1469 Coord.X = Buffer->ScreenBufferSize.X - 1;
1470
1471 if (Coord.Y < 0)
1472 Coord.Y = 0;
1473 else if (Coord.Y >= Buffer->ScreenBufferSize.Y)
1474 Coord.Y = Buffer->ScreenBufferSize.Y - 1;
1475
1476 return Coord;
1477 }
1478
1479 static LRESULT
1480 OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
1481 {
1482 BOOL Err = FALSE;
1483 PCONSRV_CONSOLE Console = GuiData->Console;
1484
1485 // FIXME: It's here that we need to check whether we has focus or not
1486 // and whether we are in edit mode or not, to know if we need to deal
1487 // with the mouse, or not.
1488
1489 if (GuiData->IgnoreNextMouseSignal)
1490 {
1491 if (msg != WM_LBUTTONDOWN &&
1492 msg != WM_MBUTTONDOWN &&
1493 msg != WM_RBUTTONDOWN)
1494 {
1495 /*
1496 * If this mouse signal is not a button-down action
1497 * then it is the last signal being ignored.
1498 */
1499 GuiData->IgnoreNextMouseSignal = FALSE;
1500 }
1501 else
1502 {
1503 /*
1504 * This mouse signal is a button-down action.
1505 * Ignore it and perform default action.
1506 */
1507 Err = TRUE;
1508 }
1509 goto Quit;
1510 }
1511
1512 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
1513 {
1514 Err = TRUE;
1515 goto Quit;
1516 }
1517
1518 if ( (GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) ||
1519 (Console->QuickEdit) )
1520 {
1521 switch (msg)
1522 {
1523 case WM_LBUTTONDOWN:
1524 {
1525 /* Clear the old selection */
1526 GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
1527
1528 /* Restart a new selection */
1529 GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
1530 SetCapture(GuiData->hWindow);
1531 GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
1532 UpdateSelection(GuiData,
1533 &GuiData->dwSelectionCursor,
1534 &GuiData->dwSelectionCursor);
1535
1536 break;
1537 }
1538
1539 case WM_LBUTTONUP:
1540 {
1541 if (!(GuiData->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
1542
1543 // GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
1544 GuiData->Selection.dwFlags &= ~CONSOLE_MOUSE_DOWN;
1545 // UpdateSelection(GuiData, NULL, &GuiData->dwSelectionCursor);
1546 ReleaseCapture();
1547
1548 break;
1549 }
1550
1551 case WM_LBUTTONDBLCLK:
1552 {
1553 PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer;
1554
1555 if (GetType(Buffer) == TEXTMODE_BUFFER)
1556 {
1557 #define IS_WORD_SEP(c) \
1558 ((c) == L'\0' || (c) == L' ' || (c) == L'\t' || (c) == L'\r' || (c) == L'\n')
1559
1560 PTEXTMODE_SCREEN_BUFFER TextBuffer = (PTEXTMODE_SCREEN_BUFFER)Buffer;
1561 COORD cL, cR;
1562 PCHAR_INFO ptrL, ptrR;
1563
1564 /* Starting point */
1565 cL = cR = PointToCoord(GuiData, lParam);
1566 ptrL = ptrR = ConioCoordToPointer(TextBuffer, cL.X, cL.Y);
1567
1568 /* Enlarge the selection by checking for whitespace */
1569 while ((0 < cL.X) && !IS_WORD_SEP(ptrL->Char.UnicodeChar)
1570 && !IS_WORD_SEP((ptrL-1)->Char.UnicodeChar))
1571 {
1572 --cL.X;
1573 --ptrL;
1574 }
1575 while ((cR.X < TextBuffer->ScreenBufferSize.X - 1) &&
1576 !IS_WORD_SEP(ptrR->Char.UnicodeChar) &&
1577 !IS_WORD_SEP((ptrR+1)->Char.UnicodeChar))
1578 {
1579 ++cR.X;
1580 ++ptrR;
1581 }
1582
1583 /*
1584 * Update the selection started with the single
1585 * left-click that preceded this double-click.
1586 */
1587 GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
1588 UpdateSelection(GuiData, &cL, &cR);
1589
1590 /* Ignore the next mouse move signal */
1591 GuiData->IgnoreNextMouseSignal = TRUE;
1592 }
1593
1594 break;
1595 }
1596
1597 case WM_RBUTTONDOWN:
1598 case WM_RBUTTONDBLCLK:
1599 {
1600 if (!(GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY))
1601 {
1602 Paste(GuiData);
1603 }
1604 else
1605 {
1606 Copy(GuiData);
1607 }
1608
1609 /* Ignore the next mouse move signal */
1610 GuiData->IgnoreNextMouseSignal = TRUE;
1611 break;
1612 }
1613
1614 case WM_MOUSEMOVE:
1615 {
1616 if (!(wParam & MK_LBUTTON)) break;
1617 if (!(GuiData->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
1618
1619 // TODO: Scroll buffer to bring SelectionCursor into view
1620 GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
1621 UpdateSelection(GuiData, NULL, &GuiData->dwSelectionCursor);
1622
1623 break;
1624 }
1625
1626 default:
1627 Err = FALSE; // TRUE;
1628 break;
1629 }
1630 }
1631 else if (Console->InputBuffer.Mode & ENABLE_MOUSE_INPUT)
1632 {
1633 INPUT_RECORD er;
1634 WORD wKeyState = GET_KEYSTATE_WPARAM(wParam);
1635 DWORD dwButtonState = 0;
1636 DWORD dwControlKeyState = 0;
1637 DWORD dwEventFlags = 0;
1638
1639 switch (msg)
1640 {
1641 case WM_LBUTTONDOWN:
1642 SetCapture(GuiData->hWindow);
1643 dwButtonState = FROM_LEFT_1ST_BUTTON_PRESSED;
1644 dwEventFlags = 0;
1645 break;
1646
1647 case WM_MBUTTONDOWN:
1648 SetCapture(GuiData->hWindow);
1649 dwButtonState = FROM_LEFT_2ND_BUTTON_PRESSED;
1650 dwEventFlags = 0;
1651 break;
1652
1653 case WM_RBUTTONDOWN:
1654 SetCapture(GuiData->hWindow);
1655 dwButtonState = RIGHTMOST_BUTTON_PRESSED;
1656 dwEventFlags = 0;
1657 break;
1658
1659 case WM_LBUTTONUP:
1660 ReleaseCapture();
1661 dwButtonState = 0;
1662 dwEventFlags = 0;
1663 break;
1664
1665 case WM_MBUTTONUP:
1666 ReleaseCapture();
1667 dwButtonState = 0;
1668 dwEventFlags = 0;
1669 break;
1670
1671 case WM_RBUTTONUP:
1672 ReleaseCapture();
1673 dwButtonState = 0;
1674 dwEventFlags = 0;
1675 break;
1676
1677 case WM_LBUTTONDBLCLK:
1678 dwButtonState = FROM_LEFT_1ST_BUTTON_PRESSED;
1679 dwEventFlags = DOUBLE_CLICK;
1680 break;
1681
1682 case WM_MBUTTONDBLCLK:
1683 dwButtonState = FROM_LEFT_2ND_BUTTON_PRESSED;
1684 dwEventFlags = DOUBLE_CLICK;
1685 break;
1686
1687 case WM_RBUTTONDBLCLK:
1688 dwButtonState = RIGHTMOST_BUTTON_PRESSED;
1689 dwEventFlags = DOUBLE_CLICK;
1690 break;
1691
1692 case WM_MOUSEMOVE:
1693 dwButtonState = 0;
1694 dwEventFlags = MOUSE_MOVED;
1695 break;
1696
1697 case WM_MOUSEWHEEL:
1698 dwButtonState = GET_WHEEL_DELTA_WPARAM(wParam) << 16;
1699 dwEventFlags = MOUSE_WHEELED;
1700 break;
1701
1702 case WM_MOUSEHWHEEL:
1703 dwButtonState = GET_WHEEL_DELTA_WPARAM(wParam) << 16;
1704 dwEventFlags = MOUSE_HWHEELED;
1705 break;
1706
1707 default:
1708 Err = TRUE;
1709 break;
1710 }
1711
1712 /*
1713 * HACK FOR CORE-8394: Ignore the next mouse move signal
1714 * just after mouse down click actions.
1715 */
1716 switch (msg)
1717 {
1718 case WM_LBUTTONDOWN:
1719 case WM_MBUTTONDOWN:
1720 case WM_RBUTTONDOWN:
1721 GuiData->IgnoreNextMouseSignal = TRUE;
1722 default:
1723 break;
1724 }
1725
1726 if (!Err)
1727 {
1728 if (wKeyState & MK_LBUTTON)
1729 dwButtonState |= FROM_LEFT_1ST_BUTTON_PRESSED;
1730 if (wKeyState & MK_MBUTTON)
1731 dwButtonState |= FROM_LEFT_2ND_BUTTON_PRESSED;
1732 if (wKeyState & MK_RBUTTON)
1733 dwButtonState |= RIGHTMOST_BUTTON_PRESSED;
1734
1735 if (GetKeyState(VK_RMENU) & 0x8000)
1736 dwControlKeyState |= RIGHT_ALT_PRESSED;
1737 if (GetKeyState(VK_LMENU) & 0x8000)
1738 dwControlKeyState |= LEFT_ALT_PRESSED;
1739 if (GetKeyState(VK_RCONTROL) & 0x8000)
1740 dwControlKeyState |= RIGHT_CTRL_PRESSED;
1741 if (GetKeyState(VK_LCONTROL) & 0x8000)
1742 dwControlKeyState |= LEFT_CTRL_PRESSED;
1743 if (GetKeyState(VK_SHIFT) & 0x8000)
1744 dwControlKeyState |= SHIFT_PRESSED;
1745 if (GetKeyState(VK_NUMLOCK) & 0x0001)
1746 dwControlKeyState |= NUMLOCK_ON;
1747 if (GetKeyState(VK_SCROLL) & 0x0001)
1748 dwControlKeyState |= SCROLLLOCK_ON;
1749 if (GetKeyState(VK_CAPITAL) & 0x0001)
1750 dwControlKeyState |= CAPSLOCK_ON;
1751 /* See WM_CHAR MSDN documentation for instance */
1752 if (lParam & 0x01000000)
1753 dwControlKeyState |= ENHANCED_KEY;
1754
1755 er.EventType = MOUSE_EVENT;
1756 er.Event.MouseEvent.dwMousePosition = PointToCoord(GuiData, lParam);
1757 er.Event.MouseEvent.dwButtonState = dwButtonState;
1758 er.Event.MouseEvent.dwControlKeyState = dwControlKeyState;
1759 er.Event.MouseEvent.dwEventFlags = dwEventFlags;
1760
1761 ConioProcessInputEvent(Console, &er);
1762 }
1763 }
1764 else
1765 {
1766 Err = TRUE;
1767 }
1768
1769 LeaveCriticalSection(&Console->Lock);
1770
1771 Quit:
1772 if (Err)
1773 return DefWindowProcW(GuiData->hWindow, msg, wParam, lParam);
1774 else
1775 return 0;
1776 }
1777
1778 VOID
1779 GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
1780 PGUI_CONSOLE_DATA GuiData);
1781 VOID
1782 GuiCopyFromGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer,
1783 PGUI_CONSOLE_DATA GuiData);
1784
1785 static VOID
1786 Copy(PGUI_CONSOLE_DATA GuiData)
1787 {
1788 if (OpenClipboard(GuiData->hWindow) == TRUE)
1789 {
1790 PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer;
1791
1792 if (GetType(Buffer) == TEXTMODE_BUFFER)
1793 {
1794 GuiCopyFromTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)Buffer, GuiData);
1795 }
1796 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
1797 {
1798 GuiCopyFromGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)Buffer, GuiData);
1799 }
1800
1801 CloseClipboard();
1802 }
1803
1804 /* Clear the selection */
1805 UpdateSelection(GuiData, NULL, NULL);
1806 }
1807
1808 VOID
1809 GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
1810 PGUI_CONSOLE_DATA GuiData);
1811 VOID
1812 GuiPasteToGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer,
1813 PGUI_CONSOLE_DATA GuiData);
1814
1815 static VOID
1816 Paste(PGUI_CONSOLE_DATA GuiData)
1817 {
1818 if (OpenClipboard(GuiData->hWindow) == TRUE)
1819 {
1820 PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer;
1821
1822 if (GetType(Buffer) == TEXTMODE_BUFFER)
1823 {
1824 GuiPasteToTextModeBuffer((PTEXTMODE_SCREEN_BUFFER)Buffer, GuiData);
1825 }
1826 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
1827 {
1828 GuiPasteToGraphicsBuffer((PGRAPHICS_SCREEN_BUFFER)Buffer, GuiData);
1829 }
1830
1831 CloseClipboard();
1832 }
1833 }
1834
1835 static VOID
1836 OnGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData, PMINMAXINFO minMaxInfo)
1837 {
1838 PCONSRV_CONSOLE Console = GuiData->Console;
1839 PCONSOLE_SCREEN_BUFFER ActiveBuffer;
1840 DWORD windx, windy;
1841 UINT WidthUnit, HeightUnit;
1842
1843 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
1844
1845 ActiveBuffer = GuiData->ActiveBuffer;
1846
1847 GetScreenBufferSizeUnits(ActiveBuffer, GuiData, &WidthUnit, &HeightUnit);
1848
1849 windx = CONGUI_MIN_WIDTH * WidthUnit + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
1850 windy = CONGUI_MIN_HEIGHT * HeightUnit + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
1851
1852 minMaxInfo->ptMinTrackSize.x = windx;
1853 minMaxInfo->ptMinTrackSize.y = windy;
1854
1855 windx = (ActiveBuffer->ScreenBufferSize.X) * WidthUnit + 2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE));
1856 windy = (ActiveBuffer->ScreenBufferSize.Y) * HeightUnit + 2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION);
1857
1858 if (ActiveBuffer->ViewSize.X < ActiveBuffer->ScreenBufferSize.X) windy += GetSystemMetrics(SM_CYHSCROLL); // window currently has a horizontal scrollbar
1859 if (ActiveBuffer->ViewSize.Y < ActiveBuffer->ScreenBufferSize.Y) windx += GetSystemMetrics(SM_CXVSCROLL); // window currently has a vertical scrollbar
1860
1861 minMaxInfo->ptMaxTrackSize.x = windx;
1862 minMaxInfo->ptMaxTrackSize.y = windy;
1863
1864 LeaveCriticalSection(&Console->Lock);
1865 }
1866
1867 static VOID
1868 OnSize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam)
1869 {
1870 PCONSRV_CONSOLE Console = GuiData->Console;
1871
1872 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return;
1873
1874 if ((GuiData->WindowSizeLock == FALSE) &&
1875 (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED || wParam == SIZE_MINIMIZED))
1876 {
1877 PCONSOLE_SCREEN_BUFFER Buff = GuiData->ActiveBuffer;
1878 DWORD windx, windy, charx, chary;
1879 UINT WidthUnit, HeightUnit;
1880
1881 GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit);
1882
1883 GuiData->WindowSizeLock = TRUE;
1884
1885 windx = LOWORD(lParam);
1886 windy = HIWORD(lParam);
1887
1888 // Compensate for existing scroll bars (because lParam values do not accommodate scroll bar)
1889 if (Buff->ViewSize.X < Buff->ScreenBufferSize.X) windy += GetSystemMetrics(SM_CYHSCROLL); // window currently has a horizontal scrollbar
1890 if (Buff->ViewSize.Y < Buff->ScreenBufferSize.Y) windx += GetSystemMetrics(SM_CXVSCROLL); // window currently has a vertical scrollbar
1891
1892 charx = windx / (int)WidthUnit ;
1893 chary = windy / (int)HeightUnit;
1894
1895 // Character alignment (round size up or down)
1896 if ((windx % WidthUnit ) >= (WidthUnit / 2)) ++charx;
1897 if ((windy % HeightUnit) >= (HeightUnit / 2)) ++chary;
1898
1899 // Compensate for added scroll bars in new window
1900 if (charx < Buff->ScreenBufferSize.X) windy -= GetSystemMetrics(SM_CYHSCROLL); // new window will have a horizontal scroll bar
1901 if (chary < Buff->ScreenBufferSize.Y) windx -= GetSystemMetrics(SM_CXVSCROLL); // new window will have a vertical scroll bar
1902
1903 charx = windx / (int)WidthUnit ;
1904 chary = windy / (int)HeightUnit;
1905
1906 // Character alignment (round size up or down)
1907 if ((windx % WidthUnit ) >= (WidthUnit / 2)) ++charx;
1908 if ((windy % HeightUnit) >= (HeightUnit / 2)) ++chary;
1909
1910 // Resize window
1911 if ((charx != Buff->ViewSize.X) || (chary != Buff->ViewSize.Y))
1912 {
1913 Buff->ViewSize.X = (charx <= Buff->ScreenBufferSize.X) ? charx : Buff->ScreenBufferSize.X;
1914 Buff->ViewSize.Y = (chary <= Buff->ScreenBufferSize.Y) ? chary : Buff->ScreenBufferSize.Y;
1915 }
1916
1917 ResizeConWnd(GuiData, WidthUnit, HeightUnit);
1918
1919 // Adjust the start of the visible area if we are attempting to show nonexistent areas
1920 if ((Buff->ScreenBufferSize.X - Buff->ViewOrigin.X) < Buff->ViewSize.X) Buff->ViewOrigin.X = Buff->ScreenBufferSize.X - Buff->ViewSize.X;
1921 if ((Buff->ScreenBufferSize.Y - Buff->ViewOrigin.Y) < Buff->ViewSize.Y) Buff->ViewOrigin.Y = Buff->ScreenBufferSize.Y - Buff->ViewSize.Y;
1922 InvalidateRect(GuiData->hWindow, NULL, TRUE);
1923
1924 GuiData->WindowSizeLock = FALSE;
1925 }
1926
1927 LeaveCriticalSection(&Console->Lock);
1928 }
1929
1930 static VOID
1931 OnMove(PGUI_CONSOLE_DATA GuiData)
1932 {
1933 RECT rcWnd;
1934
1935 // TODO: Simplify the code.
1936 // See: GuiConsoleNotifyWndProc() PM_CREATE_CONSOLE.
1937
1938 /* Retrieve our real position */
1939 GetWindowRect(GuiData->hWindow, &rcWnd);
1940 GuiData->GuiInfo.WindowOrigin.x = rcWnd.left;
1941 GuiData->GuiInfo.WindowOrigin.y = rcWnd.top;
1942 }
1943
1944 /*
1945 // HACK: This functionality is standard for general scrollbars. Don't add it by hand.
1946
1947 VOID
1948 GuiConsoleHandleScrollbarMenu(VOID)
1949 {
1950 HMENU hMenu;
1951
1952 hMenu = CreatePopupMenu();
1953 if (hMenu == NULL)
1954 {
1955 DPRINT("CreatePopupMenu failed\n");
1956 return;
1957 }
1958
1959 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLHERE);
1960 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1961 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLTOP);
1962 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLBOTTOM);
1963 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1964 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_UP);
1965 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLPAGE_DOWN);
1966 //InsertItem(hMenu, MFT_SEPARATOR, MIIM_FTYPE, 0, NULL, -1);
1967 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLUP);
1968 //InsertItem(hMenu, MIIM_STRING, MIIM_ID | MIIM_FTYPE | MIIM_STRING, 0, NULL, IDS_SCROLLDOWN);
1969 }
1970 */
1971
1972 static LRESULT
1973 OnScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam)
1974 {
1975 PCONSRV_CONSOLE Console = GuiData->Console;
1976 PCONSOLE_SCREEN_BUFFER Buff;
1977 SCROLLINFO sInfo;
1978 int fnBar;
1979 int old_pos, Maximum;
1980 PSHORT pShowXY;
1981
1982 if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return 0;
1983
1984 Buff = GuiData->ActiveBuffer;
1985
1986 if (uMsg == WM_HSCROLL)
1987 {
1988 fnBar = SB_HORZ;
1989 Maximum = Buff->ScreenBufferSize.X - Buff->ViewSize.X;
1990 pShowXY = &Buff->ViewOrigin.X;
1991 }
1992 else
1993 {
1994 fnBar = SB_VERT;
1995 Maximum = Buff->ScreenBufferSize.Y - Buff->ViewSize.Y;
1996 pShowXY = &Buff->ViewOrigin.Y;
1997 }
1998
1999 /* set scrollbar sizes */
2000 sInfo.cbSize = sizeof(SCROLLINFO);
2001 sInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE | SIF_TRACKPOS;
2002
2003 if (!GetScrollInfo(GuiData->hWindow, fnBar, &sInfo)) goto Quit;
2004
2005 old_pos = sInfo.nPos;
2006
2007 switch (LOWORD(wParam))
2008 {
2009 case SB_LINELEFT:
2010 sInfo.nPos -= 1;
2011 break;
2012
2013 case SB_LINERIGHT:
2014 sInfo.nPos += 1;
2015 break;
2016
2017 case SB_PAGELEFT:
2018 sInfo.nPos -= sInfo.nPage;
2019 break;
2020
2021 case SB_PAGERIGHT:
2022 sInfo.nPos += sInfo.nPage;
2023 break;
2024
2025 case SB_THUMBTRACK:
2026 sInfo.nPos = sInfo.nTrackPos;
2027 ConioPause(Console, PAUSED_FROM_SCROLLBAR);
2028 break;
2029
2030 case SB_THUMBPOSITION:
2031 ConioUnpause(Console, PAUSED_FROM_SCROLLBAR);
2032 break;
2033
2034 case SB_TOP:
2035 sInfo.nPos = sInfo.nMin;
2036 break;
2037
2038 case SB_BOTTOM:
2039 sInfo.nPos = sInfo.nMax;
2040 break;
2041
2042 default:
2043 break;
2044 }
2045
2046 sInfo.nPos = max(sInfo.nPos, 0);
2047 sInfo.nPos = min(sInfo.nPos, Maximum);
2048
2049 if (old_pos != sInfo.nPos)
2050 {
2051 USHORT OldX = Buff->ViewOrigin.X;
2052 USHORT OldY = Buff->ViewOrigin.Y;
2053 UINT WidthUnit, HeightUnit;
2054
2055 *pShowXY = sInfo.nPos;
2056
2057 GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit);
2058
2059 ScrollWindowEx(GuiData->hWindow,
2060 (OldX - Buff->ViewOrigin.X) * WidthUnit ,
2061 (OldY - Buff->ViewOrigin.Y) * HeightUnit,
2062 NULL,
2063 NULL,
2064 NULL,
2065 NULL,
2066 SW_INVALIDATE);
2067
2068 sInfo.fMask = SIF_POS;
2069 SetScrollInfo(GuiData->hWindow, fnBar, &sInfo, TRUE);
2070
2071 UpdateWindow(GuiData->hWindow);
2072 // InvalidateRect(GuiData->hWindow, NULL, FALSE);
2073 }
2074
2075 Quit:
2076 LeaveCriticalSection(&Console->Lock);
2077 return 0;
2078 }
2079
2080
2081 static LRESULT CALLBACK
2082 ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
2083 {
2084 LRESULT Result = 0;
2085 PGUI_CONSOLE_DATA GuiData = NULL;
2086 PCONSRV_CONSOLE Console = NULL;
2087
2088 /*
2089 * - If it's the first time we create a window for the terminal,
2090 * just initialize it and return.
2091 *
2092 * - If we are destroying the window, just do it and return.
2093 */
2094 if (msg == WM_NCCREATE)
2095 {
2096 return (LRESULT)OnNcCreate(hWnd, (LPCREATESTRUCTW)lParam);
2097 }
2098 else if (msg == WM_NCDESTROY)
2099 {
2100 return OnNcDestroy(hWnd);
2101 }
2102
2103 /*
2104 * Now the terminal window is initialized.
2105 * Get the terminal data via the window's data.
2106 * If there is no data, just go away.
2107 */
2108 GuiData = GuiGetGuiData(hWnd);
2109 if (GuiData == NULL) return DefWindowProcW(hWnd, msg, wParam, lParam);
2110
2111 // TEMPORARY HACK until all of the functions can deal with a NULL GuiData->ActiveBuffer ...
2112 if (GuiData->ActiveBuffer == NULL) return DefWindowProcW(hWnd, msg, wParam, lParam);
2113
2114 /*
2115 * Just retrieve a pointer to the console in case somebody needs it.
2116 * It is not NULL because it was checked in GuiGetGuiData.
2117 * Each helper function which needs the console has to validate and lock it.
2118 */
2119 Console = GuiData->Console;
2120
2121 /* We have a console, start message dispatching */
2122 switch (msg)
2123 {
2124 case WM_ACTIVATE:
2125 OnActivate(GuiData, wParam);
2126 break;
2127
2128 case WM_CLOSE:
2129 if (OnClose(GuiData)) goto Default;
2130 break;
2131
2132 case WM_PAINT:
2133 OnPaint(GuiData);
2134 break;
2135
2136 case WM_TIMER:
2137 OnTimer(GuiData);
2138 break;
2139
2140 case WM_PALETTECHANGED:
2141 {
2142 DPRINT("WM_PALETTECHANGED called\n");
2143
2144 /*
2145 * Protects against infinite loops:
2146 * "... A window that receives this message must not realize
2147 * its palette, unless it determines that wParam does not contain
2148 * its own window handle." (WM_PALETTECHANGED description - MSDN)
2149 *
2150 * This message is sent to all windows, including the one that
2151 * changed the system palette and caused this message to be sent.
2152 * The wParam of this message contains the handle of the window
2153 * that caused the system palette to change. To avoid an infinite
2154 * loop, care must be taken to check that the wParam of this message
2155 * does not match the window's handle.
2156 */
2157 if ((HWND)wParam == hWnd) break;
2158
2159 DPRINT("WM_PALETTECHANGED ok\n");
2160 OnPaletteChanged(GuiData);
2161 DPRINT("WM_PALETTECHANGED quit\n");
2162 break;
2163 }
2164
2165 case WM_KEYDOWN:
2166 case WM_KEYUP:
2167 case WM_CHAR:
2168 case WM_DEADCHAR:
2169 case WM_SYSKEYDOWN:
2170 case WM_SYSKEYUP:
2171 case WM_SYSCHAR:
2172 case WM_SYSDEADCHAR:
2173 {
2174 /* Detect Alt-Enter presses and switch back and forth to fullscreen mode */
2175 if (msg == WM_SYSKEYDOWN && (HIWORD(lParam) & KF_ALTDOWN) && wParam == VK_RETURN)
2176 {
2177 /* Switch only at first Alt-Enter press, and ignore subsequent key repetitions */
2178 if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) != KF_REPEAT)
2179 GuiConsoleSwitchFullScreen(GuiData);
2180
2181 break;
2182 }
2183 /* Detect Alt-Esc/Space/Tab presses defer to DefWindowProc */
2184 if ( (HIWORD(lParam) & KF_ALTDOWN) && (wParam == VK_ESCAPE || wParam == VK_SPACE || wParam == VK_TAB))
2185 {
2186 return DefWindowProcW(hWnd, msg, wParam, lParam);
2187 }
2188
2189 OnKey(GuiData, msg, wParam, lParam);
2190 break;
2191 }
2192
2193 case WM_SETCURSOR:
2194 {
2195 /*
2196 * The message was sent because we are manually triggering a change.
2197 * Check whether the mouse is indeed present on this console window
2198 * and take appropriate decisions.
2199 */
2200 if (wParam == -1 && lParam == -1)
2201 {
2202 POINT mouseCoords;
2203 HWND hWndHit;
2204
2205 /* Get the placement of the mouse */
2206 GetCursorPos(&mouseCoords);
2207
2208 /* On which window is placed the mouse ? */
2209 hWndHit = WindowFromPoint(mouseCoords);
2210
2211 /* It's our window. Perform the hit-test to be used later on. */
2212 if (hWndHit == hWnd)
2213 {
2214 wParam = (WPARAM)hWnd;
2215 lParam = DefWindowProcW(hWndHit, WM_NCHITTEST, 0,
2216 MAKELPARAM(mouseCoords.x, mouseCoords.y));
2217 }
2218 }
2219
2220 /* Set the mouse cursor only when we are in the client area */
2221 if ((HWND)wParam == hWnd && LOWORD(lParam) == HTCLIENT)
2222 {
2223 if (GuiData->MouseCursorRefCount >= 0)
2224 {
2225 /* Show the cursor */
2226 SetCursor(GuiData->hCursor);
2227 }
2228 else
2229 {
2230 /* Hide the cursor if the reference count is negative */
2231 SetCursor(NULL);
2232 }
2233 return TRUE;
2234 }
2235 else
2236 {
2237 goto Default;
2238 }
2239 }
2240
2241 case WM_LBUTTONDOWN:
2242 case WM_MBUTTONDOWN:
2243 case WM_RBUTTONDOWN:
2244 case WM_LBUTTONUP:
2245 case WM_MBUTTONUP:
2246 case WM_RBUTTONUP:
2247 case WM_LBUTTONDBLCLK:
2248 case WM_MBUTTONDBLCLK:
2249 case WM_RBUTTONDBLCLK:
2250 case WM_MOUSEMOVE:
2251 case WM_MOUSEWHEEL:
2252 case WM_MOUSEHWHEEL:
2253 {
2254 Result = OnMouse(GuiData, msg, wParam, lParam);
2255 break;
2256 }
2257
2258 case WM_HSCROLL:
2259 case WM_VSCROLL:
2260 {
2261 Result = OnScroll(GuiData, msg, wParam);
2262 break;
2263 }
2264
2265 case WM_CONTEXTMENU:
2266 {
2267 if (DefWindowProcW(hWnd /*GuiData->hWindow*/, WM_NCHITTEST, 0, lParam) == HTCLIENT)
2268 {
2269 HMENU hMenu = CreatePopupMenu();
2270 if (hMenu != NULL)
2271 {
2272 AppendMenuItems(hMenu, GuiConsoleEditMenuItems);
2273 TrackPopupMenuEx(hMenu,
2274 TPM_RIGHTBUTTON,
2275 GET_X_LPARAM(lParam),
2276 GET_Y_LPARAM(lParam),
2277 hWnd,
2278 NULL);
2279 DestroyMenu(hMenu);
2280 }
2281 break;
2282 }
2283 else
2284 {
2285 goto Default;
2286 }
2287 }
2288
2289 case WM_INITMENU:
2290 {
2291 HMENU hMenu = (HMENU)wParam;
2292 if (hMenu != NULL)
2293 {
2294 /* Enable or disable the Close menu item */
2295 EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND |
2296 (GuiData->IsCloseButtonEnabled ? MF_ENABLED : MF_GRAYED));
2297
2298 /* Enable or disable the Copy and Paste items */
2299 EnableMenuItem(hMenu, ID_SYSTEM_EDIT_COPY , MF_BYCOMMAND |
2300 ((GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) &&
2301 (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY) ? MF_ENABLED : MF_GRAYED));
2302 // FIXME: Following whether the active screen buffer is text-mode
2303 // or graphics-mode, search for CF_UNICODETEXT or CF_BITMAP formats.
2304 EnableMenuItem(hMenu, ID_SYSTEM_EDIT_PASTE, MF_BYCOMMAND |
2305 (!(GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) &&
2306 IsClipboardFormatAvailable(CF_UNICODETEXT) ? MF_ENABLED : MF_GRAYED));
2307 }
2308
2309 SendMenuEvent(Console, WM_INITMENU);
2310 break;
2311 }
2312
2313 case WM_MENUSELECT:
2314 {
2315 if (HIWORD(wParam) == 0xFFFF) // Allow all the menu flags
2316 {
2317 SendMenuEvent(Console, WM_MENUSELECT);
2318 }
2319 break;
2320 }
2321
2322 case WM_COMMAND:
2323 case WM_SYSCOMMAND:
2324 {
2325 Result = OnCommand(GuiData, wParam, lParam);
2326 break;
2327 }
2328
2329 case WM_SETFOCUS:
2330 case WM_KILLFOCUS:
2331 OnFocus(GuiData, (msg == WM_SETFOCUS));
2332 break;
2333
2334 case WM_GETMINMAXINFO:
2335 OnGetMinMaxInfo(GuiData, (PMINMAXINFO)lParam);
2336 break;
2337
2338 case WM_MOVE:
2339 OnMove(GuiData);
2340 break;
2341
2342 #if 0 // This code is here to prepare & control dynamic console SB resizing.
2343 case WM_SIZING:
2344 {
2345 PRECT dragRect = (PRECT)lParam;
2346 switch (wParam)
2347 {
2348 case WMSZ_LEFT:
2349 DPRINT1("WMSZ_LEFT\n");
2350 break;
2351 case WMSZ_RIGHT:
2352 DPRINT1("WMSZ_RIGHT\n");
2353 break;
2354 case WMSZ_TOP:
2355 DPRINT1("WMSZ_TOP\n");
2356 break;
2357 case WMSZ_TOPLEFT:
2358 DPRINT1("WMSZ_TOPLEFT\n");
2359 break;
2360 case WMSZ_TOPRIGHT:
2361 DPRINT1("WMSZ_TOPRIGHT\n");
2362 break;
2363 case WMSZ_BOTTOM:
2364 DPRINT1("WMSZ_BOTTOM\n");
2365 break;
2366 case WMSZ_BOTTOMLEFT:
2367 DPRINT1("WMSZ_BOTTOMLEFT\n");
2368 break;
2369 case WMSZ_BOTTOMRIGHT:
2370 DPRINT1("WMSZ_BOTTOMRIGHT\n");
2371 break;
2372 default:
2373 DPRINT1("wParam = %d\n", wParam);
2374 break;
2375 }
2376 DPRINT1("dragRect = {.left = %d ; .top = %d ; .right = %d ; .bottom = %d}\n",
2377 dragRect->left, dragRect->top, dragRect->right, dragRect->bottom);
2378 break;
2379 }
2380 #endif
2381
2382 case WM_SIZE:
2383 OnSize(GuiData, wParam, lParam);
2384 break;
2385
2386 case PM_RESIZE_TERMINAL:
2387 {
2388 PCONSOLE_SCREEN_BUFFER Buff = GuiData->ActiveBuffer;
2389 HDC hDC;
2390 HBITMAP hnew, hold;
2391
2392 DWORD Width, Height;
2393 UINT WidthUnit, HeightUnit;
2394
2395 GetScreenBufferSizeUnits(Buff, GuiData, &WidthUnit, &HeightUnit);
2396
2397 Width = Buff->ScreenBufferSize.X * WidthUnit ;
2398 Height = Buff->ScreenBufferSize.Y * HeightUnit;
2399
2400 /* Recreate the framebuffer */
2401 hDC = GetDC(GuiData->hWindow);
2402 hnew = CreateCompatibleBitmap(hDC, Width, Height);
2403 ReleaseDC(GuiData->hWindow, hDC);
2404 hold = SelectObject(GuiData->hMemDC, hnew);
2405 if (GuiData->hBitmap)
2406 {
2407 if (hold == GuiData->hBitmap) DeleteObject(GuiData->hBitmap);
2408 }
2409 GuiData->hBitmap = hnew;
2410
2411 /* Resize the window to the user's values */
2412 GuiData->WindowSizeLock = TRUE;
2413 ResizeConWnd(GuiData, WidthUnit, HeightUnit);
2414 GuiData->WindowSizeLock = FALSE;
2415 break;
2416 }
2417
2418 case PM_APPLY_CONSOLE_INFO:
2419 {
2420 GuiApplyUserSettings(GuiData, (HANDLE)wParam, (BOOL)lParam);
2421 break;
2422 }
2423
2424 /*
2425 * Undocumented message sent by Windows' console.dll for applying console info.
2426 * See http://www.catch22.net/sites/default/source/files/setconsoleinfo.c
2427 * and http://www.scn.rain.com/~neighorn/PDF/MSBugPaper.pdf
2428 * for more information.
2429 */
2430 case WM_SETCONSOLEINFO:
2431 {
2432 DPRINT1("WM_SETCONSOLEINFO message\n");
2433 GuiApplyWindowsConsoleSettings(GuiData, (HANDLE)wParam);
2434 break;
2435 }
2436
2437 case PM_CONSOLE_BEEP:
2438 DPRINT1("Beep\n");
2439 Beep(800, 200);
2440 break;
2441
2442 // case PM_CONSOLE_SET_TITLE:
2443 // SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
2444 // break;
2445
2446 default: Default:
2447 Result = DefWindowProcW(hWnd, msg, wParam, lParam);
2448 break;
2449 }
2450
2451 return Result;
2452 }
2453
2454 /* EOF */