xref: /reactos/win32ss/user/winsrv/consrv/popup.c (revision 53221834)
1 /*
2  * LICENSE:         GPL - See COPYING in the top level directory
3  * PROJECT:         ReactOS Console Server DLL
4  * FILE:            win32ss/user/winsrv/consrv/popup.c
5  * PURPOSE:         Console popup windows
6  * PROGRAMMERS:     Hermes Belusca-Maito (hermes.belusca@sfr.fr)
7  *
8  * NOTE:            Strongly inspired by the DrawBox function
9  *                  from base/setup/usetup/interface/usetup.c, written by:
10  *                  Eric Kohl (revision 3753)
11  *                  Herv� Poussineau (revision 24718)
12  *                  and *UiDisplayMenu from FreeLdr.
13  */
14 
15 /* INCLUDES *******************************************************************/
16 
17 #include "consrv.h"
18 #include "popup.h"
19 
20 #define NDEBUG
21 #include <debug.h>
22 
23 
24 /* PRIVATE FUNCTIONS **********************************************************/
25 
26 NTSTATUS NTAPI
27 ConDrvFillConsoleOutput(IN PCONSOLE Console,
28                         IN PTEXTMODE_SCREEN_BUFFER Buffer,
29                         IN CODE_TYPE CodeType,
30                         IN CODE_ELEMENT Code,
31                         IN ULONG NumCodesToWrite,
32                         IN PCOORD WriteCoord,
33                         OUT PULONG NumCodesWritten OPTIONAL);
34 NTSTATUS NTAPI
35 ConDrvReadConsoleOutput(IN PCONSOLE Console,
36                         IN PTEXTMODE_SCREEN_BUFFER Buffer,
37                         IN BOOLEAN Unicode,
38                         OUT PCHAR_INFO CharInfo/*Buffer*/,
39                         IN OUT PSMALL_RECT ReadRegion);
40 NTSTATUS NTAPI
41 ConDrvWriteConsoleOutput(IN PCONSOLE Console,
42                          IN PTEXTMODE_SCREEN_BUFFER Buffer,
43                          IN BOOLEAN Unicode,
44                          IN PCHAR_INFO CharInfo/*Buffer*/,
45                          IN OUT PSMALL_RECT WriteRegion);
46 
47 
48 static VOID
49 DrawBox(PTEXTMODE_SCREEN_BUFFER Buffer,
50         IN SHORT xLeft,
51         IN SHORT yTop,
52         IN SHORT Width,
53         IN SHORT Height)
54 {
55     COORD coPos;
56     DWORD Written;
57     CODE_ELEMENT Code;
58 
59     /* Set screen attributes */
60     coPos.X = xLeft;
61     Code.Attribute = Buffer->PopupDefaultAttrib;
62     for (coPos.Y = yTop; coPos.Y < yTop + Height; coPos.Y++)
63     {
64         ConDrvFillConsoleOutput(Buffer->Header.Console,
65                                 Buffer,
66                                 CODE_ATTRIBUTE,
67                                 Code,
68                                 Width,
69                                 &coPos,
70                                 &Written);
71     }
72 
73     /* draw upper left corner */
74     coPos.X = xLeft;
75     coPos.Y = yTop;
76     Code.AsciiChar = 0xDA; // '+'
77     ConDrvFillConsoleOutput(Buffer->Header.Console,
78                             Buffer,
79                             CODE_ASCII,
80                             Code,
81                             1,
82                             &coPos,
83                             &Written);
84 
85     /* draw upper edge */
86     coPos.X = xLeft + 1;
87     coPos.Y = yTop;
88     Code.AsciiChar = 0xC4; // '-'
89     ConDrvFillConsoleOutput(Buffer->Header.Console,
90                             Buffer,
91                             CODE_ASCII,
92                             Code,
93                             Width - 2,
94                             &coPos,
95                             &Written);
96 
97     /* draw upper right corner */
98     coPos.X = xLeft + Width - 1;
99     coPos.Y = yTop;
100     Code.AsciiChar = 0xBF; // '+'
101     ConDrvFillConsoleOutput(Buffer->Header.Console,
102                             Buffer,
103                             CODE_ASCII,
104                             Code,
105                             1,
106                             &coPos,
107                             &Written);
108 
109     /* Draw right edge, inner space and left edge */
110     for (coPos.Y = yTop + 1; coPos.Y < yTop + Height - 1; coPos.Y++)
111     {
112         coPos.X = xLeft;
113         Code.AsciiChar = 0xB3; // '|'
114         ConDrvFillConsoleOutput(Buffer->Header.Console,
115                                 Buffer,
116                                 CODE_ASCII,
117                                 Code,
118                                 1,
119                                 &coPos,
120                                 &Written);
121 
122         coPos.X = xLeft + 1;
123         Code.AsciiChar = ' ';
124         ConDrvFillConsoleOutput(Buffer->Header.Console,
125                                 Buffer,
126                                 CODE_ASCII,
127                                 Code,
128                                 Width - 2,
129                                 &coPos,
130                                 &Written);
131 
132         coPos.X = xLeft + Width - 1;
133         Code.AsciiChar = 0xB3; // '|'
134         ConDrvFillConsoleOutput(Buffer->Header.Console,
135                                 Buffer,
136                                 CODE_ASCII,
137                                 Code,
138                                 1,
139                                 &coPos,
140                                 &Written);
141     }
142 
143     /* draw lower left corner */
144     coPos.X = xLeft;
145     coPos.Y = yTop + Height - 1;
146     Code.AsciiChar = 0xC0; // '+'
147     ConDrvFillConsoleOutput(Buffer->Header.Console,
148                             Buffer,
149                             CODE_ASCII,
150                             Code,
151                             1,
152                             &coPos,
153                             &Written);
154 
155     /* draw lower edge */
156     coPos.X = xLeft + 1;
157     coPos.Y = yTop + Height - 1;
158     Code.AsciiChar = 0xC4; // '-'
159     ConDrvFillConsoleOutput(Buffer->Header.Console,
160                             Buffer,
161                             CODE_ASCII,
162                             Code,
163                             Width - 2,
164                             &coPos,
165                             &Written);
166 
167     /* draw lower right corner */
168     coPos.X = xLeft + Width - 1;
169     coPos.Y = yTop + Height - 1;
170     Code.AsciiChar = 0xD9; // '+'
171     ConDrvFillConsoleOutput(Buffer->Header.Console,
172                             Buffer,
173                             CODE_ASCII,
174                             Code,
175                             1,
176                             &coPos,
177                             &Written);
178 }
179 
180 
181 /* PUBLIC FUNCTIONS ***********************************************************/
182 
183 PPOPUP_WINDOW
184 CreatePopupWindow(
185     IN PCONSRV_CONSOLE Console,
186     IN PCONSOLE_SCREEN_BUFFER ScreenBuffer,
187     IN SHORT xLeft,
188     IN SHORT yTop,
189     IN SHORT Width,
190     IN SHORT Height)
191 {
192     PTEXTMODE_SCREEN_BUFFER Buffer;
193     PPOPUP_WINDOW Popup;
194     SMALL_RECT Region;
195 
196     ASSERT((PCONSOLE)Console == ScreenBuffer->Header.Console);
197 
198     if (GetType(ScreenBuffer) != TEXTMODE_BUFFER)
199         return NULL;
200 
201     Buffer = (PTEXTMODE_SCREEN_BUFFER)ScreenBuffer;
202 
203     /* Create the popup window */
204     Popup = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(*Popup));
205     if (Popup == NULL) return NULL;
206 
207     Popup->ScreenBuffer = Buffer;
208     Popup->Origin.X = xLeft;
209     Popup->Origin.Y = yTop;
210     Popup->Size.X = Width;
211     Popup->Size.Y = Height;
212 
213     /* Save old contents */
214     Popup->OldContents = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
215                                           Popup->Size.X * Popup->Size.Y *
216                                             sizeof(*Popup->OldContents));
217     if (Popup->OldContents == NULL)
218     {
219         ConsoleFreeHeap(Popup);
220         return NULL;
221     }
222     Region.Left   = Popup->Origin.X;
223     Region.Top    = Popup->Origin.Y;
224     Region.Right  = Popup->Origin.X + Popup->Size.X - 1;
225     Region.Bottom = Popup->Origin.Y + Popup->Size.Y - 1;
226     ConDrvReadConsoleOutput(Buffer->Header.Console,
227                             Buffer,
228                             TRUE,
229                             Popup->OldContents,
230                             &Region);
231 
232     /* Draw it */
233     DrawBox(Buffer,
234             xLeft, yTop,
235             Width, Height);
236 
237     /* Add it into the list of popups */
238     InsertTailList(&Console->PopupWindows, &Popup->ListEntry);
239 
240     return Popup;
241 }
242 
243 VOID
244 DestroyPopupWindow(
245     IN PPOPUP_WINDOW Popup)
246 {
247     SMALL_RECT Region;
248 
249     if (Popup == NULL) return;
250 
251     /* Remove it from the list of popups */
252     RemoveEntryList(&Popup->ListEntry);
253 
254     /* Restore the old screen-buffer contents */
255     Region.Left   = Popup->Origin.X;
256     Region.Top    = Popup->Origin.Y;
257     Region.Right  = Popup->Origin.X + Popup->Size.X - 1;
258     Region.Bottom = Popup->Origin.Y + Popup->Size.Y - 1;
259     ConDrvWriteConsoleOutput(Popup->ScreenBuffer->Header.Console,
260                              Popup->ScreenBuffer,
261                              TRUE,
262                              Popup->OldContents,
263                              &Region);
264 
265     /* Free memory */
266     ConsoleFreeHeap(Popup->OldContents);
267     ConsoleFreeHeap(Popup);
268 }
269 
270 /* EOF */
271